Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+93 −25
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@
#define DTSEC_ECNTRL_R100M		0x00000008
#define DTSEC_ECNTRL_QSGMIIM		0x00000001

#define DTSEC_TCTRL_GTS			0x00000020
#define TCTRL_GTS			0x00000020

#define RCTRL_PAL_MASK			0x001f0000
#define RCTRL_PAL_SHIFT			16
@@ -863,6 +863,52 @@ int dtsec_cfg_pad_and_crc(struct fman_mac *dtsec, bool new_val)
	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)
{
	struct dtsec_regs __iomem *regs = dtsec->regs;
@@ -880,13 +926,8 @@ int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode)

	iowrite32be(tmp, &regs->maccfg1);

	/* Graceful start - clear the graceful receive stop bit */
	if (mode & COMM_MODE_TX)
		iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS,
			    &regs->tctrl);
	if (mode & COMM_MODE_RX)
		iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS,
			    &regs->rctrl);
	/* Graceful start - clear the graceful Rx/Tx stop bit */
	graceful_start(dtsec, mode);

	return 0;
}
@@ -899,23 +940,8 @@ int dtsec_disable(struct fman_mac *dtsec, enum comm_mode mode)
	if (!is_init_done(dtsec->dtsec_drv_param))
		return -EINVAL;

	/* Gracefull stop - Assert the graceful transmit stop bit */
	if (mode & COMM_MODE_RX) {
		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");
	}
	/* Graceful stop - Assert the graceful Rx/Tx stop bit */
	graceful_stop(dtsec, mode);

	tmp = ioread32be(&regs->maccfg1);
	if (mode & COMM_MODE_RX)
@@ -933,11 +959,19 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
			      u16 pause_time, u16 __maybe_unused thresh_time)
{
	struct dtsec_regs __iomem *regs = dtsec->regs;
	enum comm_mode mode = COMM_MODE_NONE;
	u32 ptv = 0;

	if (!is_init_done(dtsec->dtsec_drv_param))
		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) {
		/* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
		if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
@@ -958,17 +992,27 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
		iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
			    &regs->maccfg1);

	graceful_start(dtsec, mode);

	return 0;
}

int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
{
	struct dtsec_regs __iomem *regs = dtsec->regs;
	enum comm_mode mode = COMM_MODE_NONE;
	u32 tmp;

	if (!is_init_done(dtsec->dtsec_drv_param))
		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);
	if (en)
		tmp |= MACCFG1_RX_FLOW;
@@ -976,20 +1020,34 @@ int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
		tmp &= ~MACCFG1_RX_FLOW;
	iowrite32be(tmp, &regs->maccfg1);

	graceful_start(dtsec, mode);

	return 0;
}

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))
		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)
	 * Station address have to be swapped (big endian to little endian
	 */
	dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr);
	set_mac_address(dtsec->regs, (u8 *)(*enet_addr));

	graceful_start(dtsec, mode);

	return 0;
}

@@ -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)
{
	struct dtsec_regs __iomem *regs = dtsec->regs;
	enum comm_mode mode = COMM_MODE_NONE;
	u32 tmp;

	if (!is_init_done(dtsec->dtsec_drv_param))
		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);

	/* Full Duplex */
@@ -1186,6 +1252,8 @@ int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
		tmp &= ~DTSEC_ECNTRL_R100M;
	iowrite32be(tmp, &regs->ecntrl);

	graceful_start(dtsec, mode);

	return 0;
}