The new version of flexcan support CAN FD mode. The salient features of this version are: - Full implementation of the CAN with Flexible Data Rate (CAN FD) protocol specification and CAN protocol specification, Version 2.0 B • Standard data frames • Extended data frames • Zero to sixty four bytes data length • Programmable bit rate • Content-related addressing - Flexible mailboxes configurable to store 0 to 8, 16, 32 or 64 bytes data length - Compliant with the ISO 11898-1 standard - Transceiver Delay Compensation feature when transmitting CAN FD messages at faster data rates Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx> --- Notes: V2: - Fix the overflow when setting CAN bittimings in CBT and FDCBT Registers drivers/net/can/flexcan.c | 264 +++++++++++++++++++++++++++++++----- 1 file changed, 227 insertions(+), 37 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 26e65d3d1c3a..37d4fe6533e8 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -52,6 +52,7 @@ #define FLEXCAN_MCR_IRMQ BIT(16) #define FLEXCAN_MCR_LPRIO_EN BIT(13) #define FLEXCAN_MCR_AEN BIT(12) +#define FLEXCAN_MCR_FDEN BIT(11) /* MCR_MAXMB: maximum used MBs is MAXMB + 1 */ #define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f) #define FLEXCAN_MCR_IDAM_A (0x0 << 8) @@ -137,6 +138,29 @@ FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \ FLEXCAN_ESR_WAK_INT) +/* FLEXCAN CAN Bit Timing Register (CBT) bits */ +#define FLEXCAN_CBT_BTF BIT(31) +#define FLEXCAN_CBT_EPRESDIV(x) (((x) & 0x3ff) << 21) +#define FLEXCAN_CBT_ERJW(x) (((x) & 0x0f) << 16) +#define FLEXCAN_CBT_EPROPSEG(x) (((x) & 0x3f) << 10) +#define FLEXCAN_CBT_EPSEG1(x) (((x) & 0x1f) << 5) +#define FLEXCAN_CBT_EPSEG2(x) ((x) & 0x1f) + +/* FLEXCAN CAN FD control Register (FDCTRL) bits */ +#define FLEXCAN_FDCTRL_FDRATE BIT(31) +#define FLEXCAN_FDCTRL_MBDSR1(x) (((x) & 0x03) << 19) +#define FLEXCAN_FDCTRL_MBDSR0(x) (((x) & 0x03) << 16) +#define FLEXCAN_FDCTRL_TDCEN BIT(15) +#define FLEXCAN_FDCTRL_TDCFAIL BIT(14) +#define FLEXCAN_FDCTRL_TDCOFF(x) (((x) & 0x1f) << 8) + +/* FLEXCAN CAN FD Bit Timing Register (FDCBT) bits */ +#define FLEXCAN_FDCBT_FPRESDIV(x) (((x) & 0x3ff) << 20) +#define FLEXCAN_FDCBT_FRJW(x) (((x) & 0x03) << 16) +#define FLEXCAN_FDCBT_FPROPSEG(x) (((x) & 0x1f) << 10) +#define FLEXCAN_FDCBT_FPSEG1(x) (((x) & 0x07) << 5) +#define FLEXCAN_FDCBT_FPSEG2(x) ((x) & 0x07) + /* FLEXCAN interrupt flag register (IFLAG) bits */ /* Errata ERR005829 step7: Reserve first valid MB */ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 @@ -161,6 +185,9 @@ #define FLEXCAN_MB_CODE_TX_DATA (0xc << 24) #define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24) +#define FLEXCAN_MB_CNT_EDL BIT(31) +#define FLEXCAN_MB_CNT_BRS BIT(30) +#define FLEXCAN_MB_CNT_ESI BIT(29) #define FLEXCAN_MB_CNT_SRR BIT(22) #define FLEXCAN_MB_CNT_IDE BIT(21) #define FLEXCAN_MB_CNT_RTR BIT(20) @@ -172,15 +199,16 @@ /* FLEXCAN hardware feature flags * * Below is some version info we got: - * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR re- - * Filter? connected? Passive detection ception in MB - * MX25 FlexCAN2 03.00.00.00 no no no no no - * MX28 FlexCAN2 03.00.04.00 yes yes no no no - * MX35 FlexCAN2 03.00.00.00 no no no no no - * MX53 FlexCAN2 03.00.00.00 yes no no no no - * MX6s FlexCAN3 10.00.12.00 yes yes no no yes - * VF610 FlexCAN3 ? no yes no yes yes? - * LS1021A FlexCAN2 03.00.04.00 no yes no no yes + * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode + * Filter? connected? Passive detection ption in MB Supported? + * MX25 FlexCAN2 03.00.00.00 no no no no no no + * MX28 FlexCAN2 03.00.04.00 yes yes no no no no + * MX35 FlexCAN2 03.00.00.00 no no no no no no + * MX53 FlexCAN2 03.00.00.00 yes no no no no no + * MX6s FlexCAN3 10.00.12.00 yes yes no no yes no + * VF610 FlexCAN3 ? no yes no yes yes? no + * LS1021A FlexCAN2 03.00.04.00 no yes no no yes no + * LX2160A FlexCAN3 03.00.23.00 no yes no no yes yes * * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. */ @@ -192,6 +220,7 @@ #define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */ #define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) /* default to BE register access */ #define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) /* Setup stop mode to support wakeup */ +#define FLEXCAN_QUIRK_USE_FD BIT(9) /* Structure of the message buffer */ struct flexcan_mb { @@ -225,7 +254,8 @@ struct flexcan_regs { u32 crcr; /* 0x44 */ u32 rxfgmask; /* 0x48 */ u32 rxfir; /* 0x4c */ - u32 _reserved3[12]; /* 0x50 */ + u32 cbt; /* 0x50 */ + u32 _reserved3[11]; /* 0x54 */ u8 mb[2][512]; /* 0x80 */ /* FIFO-mode: * MB @@ -250,6 +280,10 @@ struct flexcan_regs { u32 rerrdr; /* 0xaf4 */ u32 rerrsynr; /* 0xaf8 */ u32 errsr; /* 0xafc */ + u32 _reserved7[64]; /* 0xb00 */ + u32 fdctrl; /* 0xc00 */ + u32 fdcbt; /* 0xc04 */ + u32 fdcrc; /* 0xc08 */ }; struct flexcan_devtype_data { @@ -324,6 +358,12 @@ static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = { FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, }; +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_USE_FD, +}; + static const struct can_bittiming_const flexcan_bittiming_const = { .name = DRV_NAME, .tseg1_min = 4, @@ -336,6 +376,30 @@ static const struct can_bittiming_const flexcan_bittiming_const = { .brp_inc = 1, }; +static const struct can_bittiming_const extended_flexcan_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = 2, + .tseg1_max = 96, + .tseg2_min = 2, + .tseg2_max = 32, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, +}; + +static const struct can_bittiming_const flexcan_data_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = 2, + .tseg1_max = 39, + .tseg2_min = 2, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, +}; + /* FlexCAN module is essentially modelled as a little-endian IP in most * SoCs, i.e the registers as well as the message buffer areas are * implemented in a little-endian fashion. @@ -626,8 +690,16 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de can_id = (cfd->can_id & CAN_SFF_MASK) << 18; } - if (!can_is_canfd_skb(skb) && (cfd->can_id & CAN_RTR_FLAG)) - ctrl |= FLEXCAN_MB_CNT_RTR; + if (can_is_canfd_skb(skb)) { + ctrl |= FLEXCAN_MB_CNT_EDL; + if (cfd->flags & CANFD_BRS) + ctrl |= FLEXCAN_MB_CNT_BRS; + if (cfd->flags & CANFD_ESI) + ctrl |= FLEXCAN_MB_CNT_ESI; + } else { + if (cfd->can_id & CAN_RTR_FLAG) + ctrl |= FLEXCAN_MB_CNT_RTR; + } for (i = 0; i < can_len2dlc(cfd->len); i += sizeof(u32)) { data = be32_to_cpup((__be32 *)&cfd->data[i]); @@ -981,36 +1053,131 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) static void flexcan_set_bittiming(struct net_device *dev) { - const struct flexcan_priv *priv = netdev_priv(dev); - const struct can_bittiming *bt = &priv->can.bittiming; + struct flexcan_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + struct can_bittiming *data_bt = &priv->can.data_bittiming; struct flexcan_regs __iomem *regs = priv->regs; - u32 reg; + u32 reg_ctrl, reg_mcr, reg_cbt, reg_fdcbt, reg_fdctrl; - reg = priv->read(®s->ctrl); - reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) | - FLEXCAN_CTRL_RJW(0x3) | - FLEXCAN_CTRL_PSEG1(0x7) | - FLEXCAN_CTRL_PSEG2(0x7) | - FLEXCAN_CTRL_PROPSEG(0x7) | - FLEXCAN_CTRL_LPB | - FLEXCAN_CTRL_SMP | - FLEXCAN_CTRL_LOM); - - reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) | - FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) | - FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) | - FLEXCAN_CTRL_RJW(bt->sjw - 1) | - FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1); + reg_mcr = priv->read(®s->mcr); + reg_ctrl = priv->read(®s->ctrl); + + reg_ctrl &= ~(FLEXCAN_CTRL_LPB | + FLEXCAN_CTRL_SMP | + FLEXCAN_CTRL_LOM); if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) - reg |= FLEXCAN_CTRL_LPB; + reg_ctrl |= FLEXCAN_CTRL_LPB; if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) - reg |= FLEXCAN_CTRL_LOM; + reg_ctrl |= FLEXCAN_CTRL_LOM; if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) - reg |= FLEXCAN_CTRL_SMP; + reg_ctrl |= FLEXCAN_CTRL_SMP; + + if (reg_mcr & FLEXCAN_MCR_FDEN) { + reg_cbt = priv->read(®s->cbt); + reg_fdcbt = priv->read(®s->fdcbt); + reg_fdctrl = priv->read(®s->fdctrl); + + reg_cbt |= FLEXCAN_CBT_BTF; + reg_cbt &= ~(FLEXCAN_CBT_EPRESDIV(0x3ff) | + FLEXCAN_CBT_ERJW(0x0f) | + FLEXCAN_CBT_EPROPSEG(0x3f) | + FLEXCAN_CBT_EPSEG1(0x1f) | + FLEXCAN_CBT_EPSEG2(0x1f)); + + /* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit long. + * The can_calc_bittiming tries to divide the tseg1 equally + * between phase_seg1 and prop_seg, which may not fit in CBT + * register. Therefore, if phase_seg1 is more than possible + * value, increase prop_seg and decrease phase_seg1 + */ + if (bt->phase_seg1 > 0x20) { + bt->prop_seg += (bt->phase_seg1 - 0x20); + bt->phase_seg1 = 0x20; + } - netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); - priv->write(reg, ®s->ctrl); + reg_cbt |= FLEXCAN_CBT_EPRESDIV(bt->brp - 1) | + FLEXCAN_CBT_ERJW(bt->sjw - 1) | + FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) | + FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) | + FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1); + + reg_fdcbt &= ~(FLEXCAN_FDCBT_FPRESDIV(0x3ff) | + FLEXCAN_FDCBT_FRJW(0x03) | + FLEXCAN_CBT_EPROPSEG(0x1f) | + FLEXCAN_FDCBT_FPSEG1(0x07) | + FLEXCAN_FDCBT_FPSEG2(0x07)); + + /* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is 5 bit long. + * The can_calc_bittiming tries to divide the tseg1 equally + * between phase_seg1 and prop_seg, which may not fit in FDCBT + * register. Therefore, if phase_seg1 is more than possible + * value, increase prop_seg and decrease phase_seg1 + */ + if (data_bt->phase_seg1 > 0x8) { + data_bt->prop_seg += (data_bt->phase_seg1 - 0x8); + data_bt->phase_seg1 = 0x8; + } + + reg_fdcbt |= FLEXCAN_FDCBT_FPRESDIV(data_bt->brp - 1) | + FLEXCAN_FDCBT_FRJW(data_bt->sjw - 1) | + FLEXCAN_FDCBT_FPROPSEG(data_bt->prop_seg) | + FLEXCAN_FDCBT_FPSEG1(data_bt->phase_seg1 - 1) | + FLEXCAN_FDCBT_FPSEG2(data_bt->phase_seg2 - 1); + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { + u32 tdcoff; + /* No TDC is needed for data bit rates up to 2.5 MBit/s + * refer https://www.can-cia.org/fileadmin/resources/documents/proceedings/2013_hartwich_v2.pdf + */ + if (reg_ctrl & FLEXCAN_CTRL_LPB || + data_bt->bitrate <= 2500000) + reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN; + else + reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN; + + reg_fdctrl |= (FLEXCAN_FDCTRL_FDRATE | + FLEXCAN_FDCTRL_TDCFAIL); + + /* offset should be within the can FD bit timings */ + tdcoff = (data_bt->phase_seg1 + data_bt->prop_seg) * + data_bt->brp; + + reg_fdctrl |= FLEXCAN_FDCTRL_TDCOFF(tdcoff); + reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR0(3) | + FLEXCAN_FDCTRL_MBDSR1(3); + + if (data_bt->brp != bt->brp) + netdev_warn(dev, "Warning!! data brp = %d and brp = %d don't match.\n" + "flexcan may not work. consider using different bitrate or data bitrate\n", + data_bt->brp, bt->brp); + } else { + reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR0(0) | + FLEXCAN_FDCTRL_MBDSR1(0); + reg_fdctrl &= ~FLEXCAN_FDCTRL_FDRATE; + } + netdev_dbg(dev, "writing fdctrl=0x%08x", reg_fdctrl); + netdev_dbg(dev, "writing cbt=0x%08x\n", reg_cbt); + netdev_dbg(dev, "writing fdcbt=0x%08x\n", reg_fdcbt); + priv->write(reg_fdctrl, ®s->fdctrl); + priv->write(reg_cbt, ®s->cbt); + priv->write(reg_fdcbt, ®s->fdcbt); + } else { + reg_ctrl &= ~(FLEXCAN_CTRL_PRESDIV(0xff) | + FLEXCAN_CTRL_RJW(0x3) | + FLEXCAN_CTRL_PSEG1(0x7) | + FLEXCAN_CTRL_PSEG2(0x7) | + FLEXCAN_CTRL_PROPSEG(0x7)); + + reg_ctrl |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) | + FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) | + FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) | + FLEXCAN_CTRL_RJW(bt->sjw - 1) | + FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1); + } + + netdev_dbg(dev, "writing ctrl=0x%08x\n", reg_ctrl); + priv->write(reg_ctrl, ®s->ctrl); /* print chip status */ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, @@ -1049,6 +1216,7 @@ static int flexcan_chip_start(struct net_device *dev) * enable individual RX masking * choose format C * set max mailbox number + * enable FD mode */ reg_mcr = priv->read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); @@ -1083,6 +1251,8 @@ static int flexcan_chip_start(struct net_device *dev) reg_mcr &= ~FLEXCAN_MCR_SRX_DIS; else reg_mcr |= FLEXCAN_MCR_SRX_DIS; + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_FD) + reg_mcr |= FLEXCAN_MCR_FDEN; netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); priv->write(reg_mcr, ®s->mcr); @@ -1257,7 +1427,14 @@ static int flexcan_open(struct net_device *dev) if (err) goto out_close; - priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { + priv->offload.fd_enable = true; + priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN; + } else { + priv->offload.fd_enable = false; + priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; + } + priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) + (sizeof(priv->regs->mb[1]) / priv->mb_size); @@ -1272,7 +1449,6 @@ static int flexcan_open(struct net_device *dev) priv->reg_imask_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); - priv->offload.fd_enable = false; priv->offload.mailbox_read = flexcan_mailbox_read; if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { @@ -1495,6 +1671,7 @@ static const struct of_device_id flexcan_of_match[] = { { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, }, { .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, }, + { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, flexcan_of_match); @@ -1588,6 +1765,13 @@ static int flexcan_probe(struct platform_device *pdev) priv->write = flexcan_write_le; } + if ((devtype_data->quirks & FLEXCAN_QUIRK_USE_FD) && + !(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) { + dev_err(&pdev->dev, "can't use FIFO with FD mode\n"); + err = -ENODEV; + goto failed_register; + } + priv->dev = &pdev->dev; priv->can.clock.freq = clock_freq; priv->can.bittiming_const = &flexcan_bittiming_const; @@ -1603,6 +1787,12 @@ static int flexcan_probe(struct platform_device *pdev) priv->devtype_data = devtype_data; priv->reg_xceiver = reg_xceiver; + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_FD) { + priv->can.bittiming_const = &extended_flexcan_bittiming_const; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; + priv->can.data_bittiming_const = &flexcan_data_bittiming_const; + } + pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); -- 2.17.1