Commit e37425c2 authored by Florinel Iordache's avatar Florinel Iordache Committed by David S. Miller

fsl/fman: implement several errata workarounds

Implemented workarounds for the following dTSEC Erratum:
A002, A004, A0012, A0014, A004839 on several operations
that involve MAC CFG register changes: adjust link,
rx pause frames, modify MAC address.
Signed-off-by: default avatarFlorinel Iordache <florinel.iordache@nxp.com>
Acked-by: default avatarMadalin Bucur <madalin.bucur@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 720a8478
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
#define DTSEC_ECNTRL_R100M 0x00000008 #define DTSEC_ECNTRL_R100M 0x00000008
#define DTSEC_ECNTRL_QSGMIIM 0x00000001 #define DTSEC_ECNTRL_QSGMIIM 0x00000001
#define DTSEC_TCTRL_GTS 0x00000020 #define TCTRL_GTS 0x00000020
#define RCTRL_PAL_MASK 0x001f0000 #define RCTRL_PAL_MASK 0x001f0000
#define RCTRL_PAL_SHIFT 16 #define RCTRL_PAL_SHIFT 16
...@@ -863,6 +863,52 @@ int dtsec_cfg_pad_and_crc(struct fman_mac *dtsec, bool new_val) ...@@ -863,6 +863,52 @@ int dtsec_cfg_pad_and_crc(struct fman_mac *dtsec, bool new_val)
return 0; return 0;
} }
static void graceful_start(struct fman_mac *dtsec, enum comm_mode mode)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
if (mode & COMM_MODE_TX)
iowrite32be(ioread32be(&regs->tctrl) &
~TCTRL_GTS, &regs->tctrl);
if (mode & COMM_MODE_RX)
iowrite32be(ioread32be(&regs->rctrl) &
~RCTRL_GRS, &regs->rctrl);
}
static void graceful_stop(struct fman_mac *dtsec, enum comm_mode mode)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
u32 tmp;
/* Graceful stop - Assert the graceful Rx stop bit */
if (mode & COMM_MODE_RX) {
tmp = ioread32be(&regs->rctrl) | RCTRL_GRS;
iowrite32be(tmp, &regs->rctrl);
if (dtsec->fm_rev_info.major == 2) {
/* Workaround for dTSEC Errata A002 */
usleep_range(100, 200);
} else {
/* Workaround for dTSEC Errata A004839 */
usleep_range(10, 50);
}
}
/* Graceful stop - Assert the graceful Tx stop bit */
if (mode & COMM_MODE_TX) {
if (dtsec->fm_rev_info.major == 2) {
/* dTSEC Errata A004: Do not use TCTRL[GTS]=1 */
pr_debug("GTS not supported due to DTSEC_A004 Errata.\n");
} else {
tmp = ioread32be(&regs->tctrl) | TCTRL_GTS;
iowrite32be(tmp, &regs->tctrl);
/* Workaround for dTSEC Errata A0012, A0014 */
usleep_range(10, 50);
}
}
}
int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode) int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode)
{ {
struct dtsec_regs __iomem *regs = dtsec->regs; struct dtsec_regs __iomem *regs = dtsec->regs;
...@@ -880,13 +926,8 @@ int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode) ...@@ -880,13 +926,8 @@ int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode)
iowrite32be(tmp, &regs->maccfg1); iowrite32be(tmp, &regs->maccfg1);
/* Graceful start - clear the graceful receive stop bit */ /* Graceful start - clear the graceful Rx/Tx stop bit */
if (mode & COMM_MODE_TX) graceful_start(dtsec, mode);
iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS,
&regs->tctrl);
if (mode & COMM_MODE_RX)
iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS,
&regs->rctrl);
return 0; return 0;
} }
...@@ -899,23 +940,8 @@ int dtsec_disable(struct fman_mac *dtsec, enum comm_mode mode) ...@@ -899,23 +940,8 @@ int dtsec_disable(struct fman_mac *dtsec, enum comm_mode mode)
if (!is_init_done(dtsec->dtsec_drv_param)) if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL; return -EINVAL;
/* Gracefull stop - Assert the graceful transmit stop bit */ /* Graceful stop - Assert the graceful Rx/Tx stop bit */
if (mode & COMM_MODE_RX) { graceful_stop(dtsec, mode);
tmp = ioread32be(&regs->rctrl) | RCTRL_GRS;
iowrite32be(tmp, &regs->rctrl);
if (dtsec->fm_rev_info.major == 2)
usleep_range(100, 200);
else
udelay(10);
}
if (mode & COMM_MODE_TX) {
if (dtsec->fm_rev_info.major == 2)
pr_debug("GTS not supported due to DTSEC_A004 errata.\n");
else
pr_debug("GTS not supported due to DTSEC_A0014 errata.\n");
}
tmp = ioread32be(&regs->maccfg1); tmp = ioread32be(&regs->maccfg1);
if (mode & COMM_MODE_RX) if (mode & COMM_MODE_RX)
...@@ -933,11 +959,19 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, ...@@ -933,11 +959,19 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
u16 pause_time, u16 __maybe_unused thresh_time) u16 pause_time, u16 __maybe_unused thresh_time)
{ {
struct dtsec_regs __iomem *regs = dtsec->regs; struct dtsec_regs __iomem *regs = dtsec->regs;
enum comm_mode mode = COMM_MODE_NONE;
u32 ptv = 0; u32 ptv = 0;
if (!is_init_done(dtsec->dtsec_drv_param)) if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL; return -EINVAL;
if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
mode |= COMM_MODE_RX;
if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
mode |= COMM_MODE_TX;
graceful_stop(dtsec, mode);
if (pause_time) { if (pause_time) {
/* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */ /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) { if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
...@@ -958,17 +992,27 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec, ...@@ -958,17 +992,27 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW, iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
&regs->maccfg1); &regs->maccfg1);
graceful_start(dtsec, mode);
return 0; return 0;
} }
int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en) int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
{ {
struct dtsec_regs __iomem *regs = dtsec->regs; struct dtsec_regs __iomem *regs = dtsec->regs;
enum comm_mode mode = COMM_MODE_NONE;
u32 tmp; u32 tmp;
if (!is_init_done(dtsec->dtsec_drv_param)) if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL; return -EINVAL;
if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
mode |= COMM_MODE_RX;
if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
mode |= COMM_MODE_TX;
graceful_stop(dtsec, mode);
tmp = ioread32be(&regs->maccfg1); tmp = ioread32be(&regs->maccfg1);
if (en) if (en)
tmp |= MACCFG1_RX_FLOW; tmp |= MACCFG1_RX_FLOW;
...@@ -976,20 +1020,34 @@ int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en) ...@@ -976,20 +1020,34 @@ int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
tmp &= ~MACCFG1_RX_FLOW; tmp &= ~MACCFG1_RX_FLOW;
iowrite32be(tmp, &regs->maccfg1); iowrite32be(tmp, &regs->maccfg1);
graceful_start(dtsec, mode);
return 0; return 0;
} }
int dtsec_modify_mac_address(struct fman_mac *dtsec, enet_addr_t *enet_addr) int dtsec_modify_mac_address(struct fman_mac *dtsec, enet_addr_t *enet_addr)
{ {
struct dtsec_regs __iomem *regs = dtsec->regs;
enum comm_mode mode = COMM_MODE_NONE;
if (!is_init_done(dtsec->dtsec_drv_param)) if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL; return -EINVAL;
if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
mode |= COMM_MODE_RX;
if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
mode |= COMM_MODE_TX;
graceful_stop(dtsec, mode);
/* Initialize MAC Station Address registers (1 & 2) /* Initialize MAC Station Address registers (1 & 2)
* Station address have to be swapped (big endian to little endian * Station address have to be swapped (big endian to little endian
*/ */
dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr); dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr);
set_mac_address(dtsec->regs, (u8 *)(*enet_addr)); set_mac_address(dtsec->regs, (u8 *)(*enet_addr));
graceful_start(dtsec, mode);
return 0; return 0;
} }
...@@ -1162,11 +1220,19 @@ int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val) ...@@ -1162,11 +1220,19 @@ int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val)
int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed) int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
{ {
struct dtsec_regs __iomem *regs = dtsec->regs; struct dtsec_regs __iomem *regs = dtsec->regs;
enum comm_mode mode = COMM_MODE_NONE;
u32 tmp; u32 tmp;
if (!is_init_done(dtsec->dtsec_drv_param)) if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL; return -EINVAL;
if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
mode |= COMM_MODE_RX;
if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
mode |= COMM_MODE_TX;
graceful_stop(dtsec, mode);
tmp = ioread32be(&regs->maccfg2); tmp = ioread32be(&regs->maccfg2);
/* Full Duplex */ /* Full Duplex */
...@@ -1186,6 +1252,8 @@ int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed) ...@@ -1186,6 +1252,8 @@ int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
tmp &= ~DTSEC_ECNTRL_R100M; tmp &= ~DTSEC_ECNTRL_R100M;
iowrite32be(tmp, &regs->ecntrl); iowrite32be(tmp, &regs->ecntrl);
graceful_start(dtsec, mode);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment