diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/net/can/flexcan/flexcan-core.c (renamed from drivers/net/can/flexcan.c) | 234 |
1 files changed, 90 insertions, 144 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan/flexcan-core.c index 12b60ad95b02..0bff1884d5cc 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -15,7 +15,6 @@ #include <linux/can/dev.h> #include <linux/can/error.h> #include <linux/can/led.h> -#include <linux/can/rx-offload.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/firmware/imx/sci.h> @@ -33,6 +32,8 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include "flexcan.h" + #define DRV_NAME "flexcan" /* 8 for RX fifo and 2 error handling */ @@ -173,9 +174,9 @@ /* FLEXCAN interrupt flag register (IFLAG) bits */ /* Errata ERR005829 step7: Reserve first valid MB */ -#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 -#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 -#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) +#define FLEXCAN_TX_MB_RESERVED_RX_FIFO 8 +#define FLEXCAN_TX_MB_RESERVED_RX_MAILBOX 0 +#define FLEXCAN_RX_MB_RX_MAILBOX_FIRST (FLEXCAN_TX_MB_RESERVED_RX_MAILBOX + 1) #define FLEXCAN_IFLAG_MB(x) BIT_ULL(x) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) @@ -206,53 +207,6 @@ #define FLEXCAN_TIMEOUT_US (250) -/* FLEXCAN hardware feature flags - * - * Below is some version info we got: - * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode MB - * Filter? connected? Passive detection ption in MB Supported? - * MCF5441X FlexCAN2 ? no yes no no yes no 16 - * MX25 FlexCAN2 03.00.00.00 no no no no no no 64 - * MX28 FlexCAN2 03.00.04.00 yes yes no no no no 64 - * MX35 FlexCAN2 03.00.00.00 no no no no no no 64 - * MX53 FlexCAN2 03.00.00.00 yes no no no no no 64 - * MX6s FlexCAN3 10.00.12.00 yes yes no no yes no 64 - * MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes 64 - * MX8MP FlexCAN3 03.00.17.01 yes yes no yes yes yes 64 - * VF610 FlexCAN3 ? no yes no yes yes? no 64 - * LS1021A FlexCAN2 03.00.04.00 no yes no no yes no 64 - * LX2160A FlexCAN3 03.00.23.00 no yes no yes yes yes 64 - * - * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. - */ - -/* [TR]WRN_INT not connected */ -#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) - /* Disable RX FIFO Global mask */ -#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) -/* Enable EACEN and RRS bit in ctrl2 */ -#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) -/* Disable non-correctable errors interrupt and freeze mode */ -#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) -/* Use timestamp based offloading */ -#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) -/* No interrupt for error passive */ -#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) -/* default to BE register access */ -#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) -/* Setup stop mode with GPR to support wakeup */ -#define FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR BIT(8) -/* Support CAN-FD mode */ -#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9) -/* support memory detection and correction */ -#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10) -/* Setup stop mode with SCU firmware to support wakeup */ -#define FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW BIT(11) -/* Setup 3 separate interrupts, main, boff and err */ -#define FLEXCAN_QUIRK_NR_IRQ_3 BIT(12) -/* Setup 16 mailboxes */ -#define FLEXCAN_QUIRK_NR_MB_16 BIT(13) - /* Structure of the message buffer */ struct flexcan_mb { u32 can_ctrl; @@ -339,106 +293,80 @@ struct flexcan_regs { static_assert(sizeof(struct flexcan_regs) == 0x4 * 18 + 0xfb8); -struct flexcan_devtype_data { - u32 quirks; /* quirks needed for different IP cores */ -}; - -struct flexcan_stop_mode { - struct regmap *gpr; - u8 req_gpr; - u8 req_bit; -}; - -struct flexcan_priv { - struct can_priv can; - struct can_rx_offload offload; - struct device *dev; - - struct flexcan_regs __iomem *regs; - struct flexcan_mb __iomem *tx_mb; - struct flexcan_mb __iomem *tx_mb_reserved; - u8 tx_mb_idx; - u8 mb_count; - u8 mb_size; - u8 clk_src; /* clock source of CAN Protocol Engine */ - u8 scu_idx; - - u64 rx_mask; - u64 tx_mask; - u32 reg_ctrl_default; - - struct clk *clk_ipg; - struct clk *clk_per; - const struct flexcan_devtype_data *devtype_data; - struct regulator *reg_xceiver; - struct flexcan_stop_mode stm; - - int irq_boff; - int irq_err; - - /* IPC handle when setup stop mode by System Controller firmware(scfw) */ - struct imx_sc_ipc *sc_ipc_handle; - - /* Read and Write APIs */ - u32 (*read)(void __iomem *addr); - void (*write)(u32 val, void __iomem *addr); -}; - static const struct flexcan_devtype_data fsl_mcf5441x_devtype_data = { .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16, + FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16 | + FLEXCAN_QUIRK_SUPPPORT_RX_FIFO, }; static const struct flexcan_devtype_data fsl_p1010_devtype_data = { .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE | FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN, + FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_FIFO, }; static const struct flexcan_devtype_data fsl_imx25_devtype_data = { .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE | - FLEXCAN_QUIRK_BROKEN_PERR_STATE, + FLEXCAN_QUIRK_BROKEN_PERR_STATE | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_FIFO, }; static const struct flexcan_devtype_data fsl_imx28_devtype_data = { - .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE, + .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_FIFO, }; static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR, + FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_BROKEN_PERR_STATE | + FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW, + FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_BROKEN_PERR_STATE | + FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static struct flexcan_devtype_data fsl_imx8mp_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR | - FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC, + FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static const struct flexcan_devtype_data fsl_vf610_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | - FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_ECC, + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | + FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_ECC | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, + FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_SUPPORT_FD | - FLEXCAN_QUIRK_SUPPORT_ECC, + FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_SUPPORT_FD | + FLEXCAN_QUIRK_SUPPORT_ECC | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR, }; static const struct can_bittiming_const flexcan_bittiming_const = { @@ -600,7 +528,7 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) priv->write(reg_mcr, ®s->mcr); /* enable stop request */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { ret = flexcan_stop_mode_enable_scfw(priv, true); if (ret < 0) return ret; @@ -619,7 +547,7 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) int ret; /* remove stop request */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { ret = flexcan_stop_mode_enable_scfw(priv, false); if (ret < 0) return ret; @@ -1022,7 +950,7 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, mb = flexcan_get_mb(priv, n); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) { u32 code; do { @@ -1087,7 +1015,7 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, } mark_as_read: - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), ®s->iflag1); else priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1); @@ -1113,7 +1041,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) enum can_state last_state = priv->can.state; /* reception interrupt */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) { u64 reg_iflag_rx; int ret; @@ -1173,7 +1101,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* state change interrupt or broken error state quirk fix is enabled */ if ((reg_esr & FLEXCAN_ESR_ERR_STATE) || - (priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE | + (priv->devtype_data.quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE | FLEXCAN_QUIRK_BROKEN_PERR_STATE))) flexcan_irq_state(dev, reg_esr); @@ -1195,11 +1123,11 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) * (1): enabled if FLEXCAN_QUIRK_BROKEN_WERR_STATE is enabled */ if ((last_state != priv->can.state) && - (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_PERR_STATE) && + (priv->devtype_data.quirks & FLEXCAN_QUIRK_BROKEN_PERR_STATE) && !(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) { switch (priv->can.state) { case CAN_STATE_ERROR_ACTIVE: - if (priv->devtype_data->quirks & + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE) flexcan_error_irq_enable(priv); else @@ -1423,26 +1351,26 @@ static int flexcan_rx_offload_setup(struct net_device *dev) else priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_MB_16) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_MB_16) priv->mb_count = 16; else priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) + (sizeof(priv->regs->mb[1]) / priv->mb_size); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) priv->tx_mb_reserved = - flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP); + flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_RX_MAILBOX); else priv->tx_mb_reserved = - flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO); + flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_RX_FIFO); priv->tx_mb_idx = priv->mb_count - 1; priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); priv->offload.mailbox_read = flexcan_mailbox_read; - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { - priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) { + priv->offload.mb_first = FLEXCAN_RX_MB_RX_MAILBOX_FIRST; priv->offload.mb_last = priv->mb_count - 2; priv->rx_mask = GENMASK_ULL(priv->offload.mb_last, @@ -1506,7 +1434,7 @@ static int flexcan_chip_start(struct net_device *dev) if (err) goto out_chip_disable; - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_ECC) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SUPPORT_ECC) flexcan_ram_init(dev); flexcan_set_bittiming(dev); @@ -1532,10 +1460,10 @@ static int flexcan_chip_start(struct net_device *dev) /* MCR * * FIFO: - * - disable for timestamp mode + * - disable for mailbox mode * - enable for FIFO mode */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) reg_mcr &= ~FLEXCAN_MCR_FEN; else reg_mcr |= FLEXCAN_MCR_FEN; @@ -1586,7 +1514,7 @@ static int flexcan_chip_start(struct net_device *dev) * on most Flexcan cores, too. Otherwise we don't get * any error warning or passive interrupts. */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE || + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE || priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; else @@ -1599,7 +1527,7 @@ static int flexcan_chip_start(struct net_device *dev) netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); priv->write(reg_ctrl, ®s->ctrl); - if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) { + if ((priv->devtype_data.quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) { reg_ctrl2 = priv->read(®s->ctrl2); reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS; priv->write(reg_ctrl2, ®s->ctrl2); @@ -1631,7 +1559,7 @@ static int flexcan_chip_start(struct net_device *dev) priv->write(reg_fdctrl, ®s->fdctrl); } - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) { 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, @@ -1639,7 +1567,7 @@ static int flexcan_chip_start(struct net_device *dev) } } else { /* clear and invalidate unused mailboxes first */ - for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i < priv->mb_count; i++) { + for (i = FLEXCAN_TX_MB_RESERVED_RX_FIFO; i < priv->mb_count; i++) { mb = flexcan_get_mb(priv, i); priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, &mb->can_ctrl); @@ -1659,7 +1587,7 @@ static int flexcan_chip_start(struct net_device *dev) priv->write(0x0, ®s->rx14mask); priv->write(0x0, ®s->rx15mask); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_DISABLE_RXFG) priv->write(0x0, ®s->rxfgmask); /* clear acceptance filters */ @@ -1673,7 +1601,7 @@ static int flexcan_chip_start(struct net_device *dev) * This also works around errata e5295 which generates false * positive memory errors and put the device in freeze mode. */ - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_DISABLE_MECR) { /* Follow the protocol as described in "Detection * and Correction of Memory Errors" to write to * MECR register (step 1 - 5) @@ -1799,7 +1727,7 @@ static int flexcan_open(struct net_device *dev) if (err) goto out_can_rx_offload_disable; - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) { err = request_irq(priv->irq_boff, flexcan_irq, IRQF_SHARED, dev->name, dev); if (err) @@ -1845,7 +1773,7 @@ static int flexcan_close(struct net_device *dev) netif_stop_queue(dev); flexcan_chip_interrupts_disable(dev); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) { free_irq(priv->irq_err, dev); free_irq(priv->irq_boff, dev); } @@ -2051,9 +1979,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) priv = netdev_priv(dev); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) ret = flexcan_setup_stop_mode_scfw(pdev); - else if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) + else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) ret = flexcan_setup_stop_mode_gpr(pdev); else /* return 0 directly if doesn't support stop mode feature */ @@ -2164,8 +2092,25 @@ static int flexcan_probe(struct platform_device *pdev) return -ENODEV; if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) && - !(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) { - dev_err(&pdev->dev, "CAN-FD mode doesn't work with FIFO mode!\n"); + !((devtype_data->quirks & + (FLEXCAN_QUIRK_USE_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR | + FLEXCAN_QUIRK_SUPPPORT_RX_FIFO)) == + (FLEXCAN_QUIRK_USE_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR))) { + dev_err(&pdev->dev, "CAN-FD mode doesn't work in RX-FIFO mode!\n"); + return -EINVAL; + } + + if ((devtype_data->quirks & + (FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX | + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR)) == + FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR) { + dev_err(&pdev->dev, + "Quirks (0x%08x) inconsistent: RX_MAILBOX_RX supported but not RX_MAILBOX\n", + devtype_data->quirks); return -EINVAL; } @@ -2177,13 +2122,15 @@ static int flexcan_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &flexcan_netdev_ops; + flexcan_set_ethtool_ops(dev); dev->irq = irq; dev->flags |= IFF_ECHO; priv = netdev_priv(dev); + priv->devtype_data = *devtype_data; if (of_property_read_bool(pdev->dev.of_node, "big-endian") || - devtype_data->quirks & FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN) { + priv->devtype_data.quirks & FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN) { priv->read = flexcan_read_be; priv->write = flexcan_write_be; } else { @@ -2202,10 +2149,9 @@ static int flexcan_probe(struct platform_device *pdev) priv->clk_ipg = clk_ipg; priv->clk_per = clk_per; priv->clk_src = clk_src; - priv->devtype_data = devtype_data; priv->reg_xceiver = reg_xceiver; - if (devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) { priv->irq_boff = platform_get_irq(pdev, 1); if (priv->irq_boff <= 0) { err = -ENODEV; @@ -2218,7 +2164,7 @@ static int flexcan_probe(struct platform_device *pdev) } } - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) { + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SUPPORT_FD) { priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO; priv->can.bittiming_const = &flexcan_fd_bittiming_const; |