diff options
Diffstat (limited to '')
| -rw-r--r-- | drivers/net/can/flexcan.c | 62 | 
1 files changed, 53 insertions, 9 deletions
| diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index f425ec2c7839..6586309329e6 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -62,7 +62,7 @@  #define FLEXCAN_MCR_BCC			BIT(16)  #define FLEXCAN_MCR_LPRIO_EN		BIT(13)  #define FLEXCAN_MCR_AEN			BIT(12) -#define FLEXCAN_MCR_MAXMB(x)		((x) & 0x1f) +#define FLEXCAN_MCR_MAXMB(x)		((x) & 0x7f)  #define FLEXCAN_MCR_IDAM_A		(0 << 8)  #define FLEXCAN_MCR_IDAM_B		(1 << 8)  #define FLEXCAN_MCR_IDAM_C		(2 << 8) @@ -125,7 +125,9 @@  	 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)  /* FLEXCAN interrupt flag register (IFLAG) bits */ -#define FLEXCAN_TX_BUF_ID		8 +/* Errata ERR005829 step7: Reserve first valid MB */ +#define FLEXCAN_TX_BUF_RESERVED		8 +#define FLEXCAN_TX_BUF_ID		9  #define FLEXCAN_IFLAG_BUF(x)		BIT(x)  #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7)  #define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6) @@ -136,6 +138,17 @@  /* FLEXCAN message buffers */  #define FLEXCAN_MB_CNT_CODE(x)		(((x) & 0xf) << 24) +#define FLEXCAN_MB_CODE_RX_INACTIVE	(0x0 << 24) +#define FLEXCAN_MB_CODE_RX_EMPTY	(0x4 << 24) +#define FLEXCAN_MB_CODE_RX_FULL		(0x2 << 24) +#define FLEXCAN_MB_CODE_RX_OVERRRUN	(0x6 << 24) +#define FLEXCAN_MB_CODE_RX_RANSWER	(0xa << 24) + +#define FLEXCAN_MB_CODE_TX_INACTIVE	(0x8 << 24) +#define FLEXCAN_MB_CODE_TX_ABORT	(0x9 << 24) +#define FLEXCAN_MB_CODE_TX_DATA		(0xc << 24) +#define FLEXCAN_MB_CODE_TX_TANSWER	(0xe << 24) +  #define FLEXCAN_MB_CNT_SRR		BIT(22)  #define FLEXCAN_MB_CNT_IDE		BIT(21)  #define FLEXCAN_MB_CNT_RTR		BIT(20) @@ -298,7 +311,7 @@ static int flexcan_chip_enable(struct flexcan_priv *priv)  	flexcan_write(reg, ®s->mcr);  	while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) -		usleep_range(10, 20); +		udelay(10);  	if (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)  		return -ETIMEDOUT; @@ -317,7 +330,7 @@ static int flexcan_chip_disable(struct flexcan_priv *priv)  	flexcan_write(reg, ®s->mcr);  	while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) -		usleep_range(10, 20); +		udelay(10);  	if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK))  		return -ETIMEDOUT; @@ -336,7 +349,7 @@ static int flexcan_chip_freeze(struct flexcan_priv *priv)  	flexcan_write(reg, ®s->mcr);  	while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) -		usleep_range(100, 200); +		udelay(100);  	if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK))  		return -ETIMEDOUT; @@ -355,7 +368,7 @@ static int flexcan_chip_unfreeze(struct flexcan_priv *priv)  	flexcan_write(reg, ®s->mcr);  	while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) -		usleep_range(10, 20); +		udelay(10);  	if (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)  		return -ETIMEDOUT; @@ -370,7 +383,7 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv)  	flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr);  	while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST)) -		usleep_range(10, 20); +		udelay(10);  	if (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST)  		return -ETIMEDOUT; @@ -428,6 +441,14 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)  	flexcan_write(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id);  	flexcan_write(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); +	/* Errata ERR005829 step8: +	 * Write twice INACTIVE(0x8) code to first MB. +	 */ +	flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, +		      ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); +	flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, +		      ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); +  	return NETDEV_TX_OK;  } @@ -549,6 +570,13 @@ static void do_state(struct net_device *dev,  	/* process state changes depending on the new state */  	switch (new_state) { +	case CAN_STATE_ERROR_WARNING: +		netdev_dbg(dev, "Error Warning\n"); +		cf->can_id |= CAN_ERR_CRTL; +		cf->data[1] = (bec.txerr > bec.rxerr) ? +			CAN_ERR_CRTL_TX_WARNING : +			CAN_ERR_CRTL_RX_WARNING; +		break;  	case CAN_STATE_ERROR_ACTIVE:  		netdev_dbg(dev, "Error Active\n");  		cf->can_id |= CAN_ERR_PROT; @@ -737,6 +765,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)  		stats->tx_bytes += can_get_echo_skb(dev, 0);  		stats->tx_packets++;  		can_led_event(dev, CAN_LED_EVENT_TX); +		/* after sending a RTR frame mailbox is in RX mode */ +		flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, +			      ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);  		flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1);  		netif_wake_queue(dev);  	} @@ -794,6 +825,7 @@ static int flexcan_chip_start(struct net_device *dev)  	struct flexcan_regs __iomem *regs = priv->base;  	int err;  	u32 reg_mcr, reg_ctrl; +	int i;  	/* enable module */  	err = flexcan_chip_enable(priv); @@ -852,14 +884,26 @@ static int flexcan_chip_start(struct net_device *dev)  	if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||  	    priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)  		reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; +	else +		reg_ctrl &= ~FLEXCAN_CTRL_ERR_MSK;  	/* save for later use */  	priv->reg_ctrl_default = reg_ctrl;  	netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);  	flexcan_write(reg_ctrl, ®s->ctrl); -	/* Abort any pending TX, mark Mailbox as INACTIVE */ -	flexcan_write(FLEXCAN_MB_CNT_CODE(0x4), +	/* clear and invalidate all mailboxes first */ +	for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->cantxfg); i++) { +		flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE, +			      ®s->cantxfg[i].can_ctrl); +	} + +	/* Errata ERR005829: mark first TX mailbox as INACTIVE */ +	flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE, +		      ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl); + +	/* mark TX mailbox as INACTIVE */ +	flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,  		      ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);  	/* acceptance mask/acceptance code (accept everything) */ | 
