Commit 0517961c authored by Pankaj Bansal's avatar Pankaj Bansal Committed by Marc Kleine-Budde

can: flexcan: Add provision for variable payload size

Till now the flexcan module supported 8 byte payload size as per CAN 2.0
specifications. But now upcoming flexcan module in NXP LX2160A SOC
supports CAN FD protocol too. The Message buffers need to be configured
to have payload size 64 bytes.

Therefore, added provision in the driver for payload size to be 64 bytes.
Signed-off-by: default avatarPankaj Bansal <pankaj.bansal@nxp.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 5156c7b1
...@@ -140,9 +140,7 @@ ...@@ -140,9 +140,7 @@
/* Errata ERR005829 step7: Reserve first valid MB */ /* Errata ERR005829 step7: Reserve first valid MB */
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
#define FLEXCAN_TX_MB 63
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST (FLEXCAN_TX_MB - 1)
#define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f) #define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f)
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
...@@ -198,7 +196,7 @@ ...@@ -198,7 +196,7 @@
struct flexcan_mb { struct flexcan_mb {
u32 can_ctrl; u32 can_ctrl;
u32 can_id; u32 can_id;
u32 data[2]; u32 data[];
}; };
/* Structure of the hardware registers */ /* Structure of the hardware registers */
...@@ -227,7 +225,7 @@ struct flexcan_regs { ...@@ -227,7 +225,7 @@ struct flexcan_regs {
u32 rxfgmask; /* 0x48 */ u32 rxfgmask; /* 0x48 */
u32 rxfir; /* 0x4c */ u32 rxfir; /* 0x4c */
u32 _reserved3[12]; /* 0x50 */ u32 _reserved3[12]; /* 0x50 */
struct flexcan_mb mb[64]; /* 0x80 */ u8 mb[1024]; /* 0x80 */
/* FIFO-mode: /* FIFO-mode:
* MB * MB
* 0x080...0x08f 0 RX message buffer * 0x080...0x08f 0 RX message buffer
...@@ -270,7 +268,11 @@ struct flexcan_priv { ...@@ -270,7 +268,11 @@ struct flexcan_priv {
struct can_rx_offload offload; struct can_rx_offload offload;
struct flexcan_regs __iomem *regs; struct flexcan_regs __iomem *regs;
struct flexcan_mb __iomem *tx_mb;
struct flexcan_mb __iomem *tx_mb_reserved; struct flexcan_mb __iomem *tx_mb_reserved;
u8 tx_mb_idx;
u8 mb_count;
u8 mb_size;
u32 reg_ctrl_default; u32 reg_ctrl_default;
u32 reg_imask1_default; u32 reg_imask1_default;
u32 reg_imask2_default; u32 reg_imask2_default;
...@@ -364,6 +366,16 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr) ...@@ -364,6 +366,16 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr)
iowrite32(val, addr); iowrite32(val, addr);
} }
static struct flexcan_mb __iomem *flexcan_get_mb(const struct flexcan_priv *priv,
u8 mb_index)
{
if (WARN_ON(mb_index >= priv->mb_count))
return NULL;
return (struct flexcan_mb __iomem *)
(&priv->regs->mb[priv->mb_size * mb_index]);
}
static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
{ {
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
...@@ -569,11 +581,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev, ...@@ -569,11 +581,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
const struct flexcan_priv *priv = netdev_priv(dev); const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
struct can_frame *cf = (struct can_frame *)skb->data; struct can_frame *cf = (struct can_frame *)skb->data;
u32 can_id; u32 can_id;
u32 data; u32 data;
u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16); u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
int i;
if (can_dropped_invalid_skb(dev, skb)) if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -590,19 +602,15 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de ...@@ -590,19 +602,15 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
ctrl |= FLEXCAN_MB_CNT_RTR; ctrl |= FLEXCAN_MB_CNT_RTR;
if (cf->can_dlc > 0) { for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
data = be32_to_cpup((__be32 *)&cf->data[0]); data = be32_to_cpup((__be32 *)&cf->data[i]);
priv->write(data, &regs->mb[FLEXCAN_TX_MB].data[0]); priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
}
if (cf->can_dlc > 4) {
data = be32_to_cpup((__be32 *)&cf->data[4]);
priv->write(data, &regs->mb[FLEXCAN_TX_MB].data[1]);
} }
can_put_echo_skb(skb, dev, 0); can_put_echo_skb(skb, dev, 0);
priv->write(can_id, &regs->mb[FLEXCAN_TX_MB].can_id); priv->write(can_id, &priv->tx_mb->can_id);
priv->write(ctrl, &regs->mb[FLEXCAN_TX_MB].can_ctrl); priv->write(ctrl, &priv->tx_mb->can_ctrl);
/* Errata ERR005829 step8: /* Errata ERR005829 step8:
* Write twice INACTIVE(0x8) code to first MB. * Write twice INACTIVE(0x8) code to first MB.
...@@ -729,8 +737,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, ...@@ -729,8 +737,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
{ {
struct flexcan_priv *priv = rx_offload_to_priv(offload); struct flexcan_priv *priv = rx_offload_to_priv(offload);
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
struct flexcan_mb __iomem *mb = &regs->mb[n]; struct flexcan_mb __iomem *mb;
u32 reg_ctrl, reg_id, reg_iflag1; u32 reg_ctrl, reg_id, reg_iflag1;
int i;
mb = flexcan_get_mb(priv, n);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
u32 code; u32 code;
...@@ -771,8 +782,10 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, ...@@ -771,8 +782,10 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
cf->can_id |= CAN_RTR_FLAG; cf->can_id |= CAN_RTR_FLAG;
cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf); cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
*(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0])); for (i = 0; i < cf->can_dlc; i += sizeof(u32)) {
*(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1])); __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)]));
*(__be32 *)(cf->data + i) = data;
}
/* mark as read */ /* mark as read */
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
...@@ -801,7 +814,7 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) ...@@ -801,7 +814,7 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
u32 iflag1, iflag2; u32 iflag1, iflag2;
iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default & iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
~FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default; iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
return (u64)iflag2 << 32 | iflag1; return (u64)iflag2 << 32 | iflag1;
...@@ -851,8 +864,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -851,8 +864,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
reg_iflag2 = priv->read(&regs->iflag2); reg_iflag2 = priv->read(&regs->iflag2);
/* transmission complete interrupt */ /* transmission complete interrupt */
if (reg_iflag2 & FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB)) { if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
u32 reg_ctrl = priv->read(&regs->mb[FLEXCAN_TX_MB].can_ctrl); u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload, stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload,
...@@ -862,8 +875,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -862,8 +875,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
/* after sending a RTR frame MB is in RX mode */ /* after sending a RTR frame MB is in RX mode */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->mb[FLEXCAN_TX_MB].can_ctrl); &priv->tx_mb->can_ctrl);
priv->write(FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB), &regs->iflag2); priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -976,6 +989,7 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -976,6 +989,7 @@ static int flexcan_chip_start(struct net_device *dev)
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
int err, i; int err, i;
struct flexcan_mb __iomem *mb;
/* enable module */ /* enable module */
err = flexcan_chip_enable(priv); err = flexcan_chip_enable(priv);
...@@ -1003,7 +1017,7 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1003,7 +1017,7 @@ static int flexcan_chip_start(struct net_device *dev)
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV | reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | FLEXCAN_MCR_IDAM_C |
FLEXCAN_MCR_MAXMB(FLEXCAN_TX_MB); FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
/* MCR /* MCR
* *
...@@ -1077,14 +1091,16 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1077,14 +1091,16 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) { for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) {
mb = flexcan_get_mb(priv, i);
priv->write(FLEXCAN_MB_CODE_RX_EMPTY, priv->write(FLEXCAN_MB_CODE_RX_EMPTY,
&regs->mb[i].can_ctrl); &mb->can_ctrl);
} }
} else { } else {
/* clear and invalidate unused mailboxes first */ /* clear and invalidate unused mailboxes first */
for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= ARRAY_SIZE(regs->mb); i++) { for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= priv->mb_count; i++) {
mb = flexcan_get_mb(priv, i);
priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
&regs->mb[i].can_ctrl); &mb->can_ctrl);
} }
} }
...@@ -1094,7 +1110,7 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1094,7 +1110,7 @@ static int flexcan_chip_start(struct net_device *dev)
/* mark TX mailbox as INACTIVE */ /* mark TX mailbox as INACTIVE */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&regs->mb[FLEXCAN_TX_MB].can_ctrl); &priv->tx_mb->can_ctrl);
/* acceptance mask/acceptance code (accept everything) */ /* acceptance mask/acceptance code (accept everything) */
priv->write(0x0, &regs->rxgmask); priv->write(0x0, &regs->rxgmask);
...@@ -1105,7 +1121,7 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1105,7 +1121,7 @@ static int flexcan_chip_start(struct net_device *dev)
priv->write(0x0, &regs->rxfgmask); priv->write(0x0, &regs->rxfgmask);
/* clear acceptance filters */ /* clear acceptance filters */
for (i = 0; i < ARRAY_SIZE(regs->mb); i++) for (i = 0; i < priv->mb_count; i++)
priv->write(0, &regs->rximr[i]); priv->write(0, &regs->rximr[i]);
/* On Vybrid, disable memory error detection interrupts /* On Vybrid, disable memory error detection interrupts
...@@ -1188,7 +1204,6 @@ static void flexcan_chip_stop(struct net_device *dev) ...@@ -1188,7 +1204,6 @@ static void flexcan_chip_stop(struct net_device *dev)
static int flexcan_open(struct net_device *dev) static int flexcan_open(struct net_device *dev)
{ {
struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
int err; int err;
err = clk_prepare_enable(priv->clk_ipg); err = clk_prepare_enable(priv->clk_ipg);
...@@ -1207,13 +1222,20 @@ static int flexcan_open(struct net_device *dev) ...@@ -1207,13 +1222,20 @@ static int flexcan_open(struct net_device *dev)
if (err) if (err)
goto out_close; goto out_close;
priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
priv->mb_count = sizeof(priv->regs->mb) / priv->mb_size;
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
priv->tx_mb_reserved = &regs->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP]; priv->tx_mb_reserved =
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP);
else else
priv->tx_mb_reserved = &regs->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO]; priv->tx_mb_reserved =
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
priv->tx_mb_idx = priv->mb_count - 1;
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
priv->reg_imask1_default = 0; priv->reg_imask1_default = 0;
priv->reg_imask2_default = FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
priv->offload.mailbox_read = flexcan_mailbox_read; priv->offload.mailbox_read = flexcan_mailbox_read;
...@@ -1221,7 +1243,7 @@ static int flexcan_open(struct net_device *dev) ...@@ -1221,7 +1243,7 @@ static int flexcan_open(struct net_device *dev)
u64 imask; u64 imask;
priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
priv->offload.mb_last = FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST; priv->offload.mb_last = priv->mb_count - 2;
imask = GENMASK_ULL(priv->offload.mb_last, imask = GENMASK_ULL(priv->offload.mb_last,
priv->offload.mb_first); priv->offload.mb_first);
......
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