> -----Original Message----- > From: linux-can-owner@xxxxxxxxxxxxxxx <linux-can-owner@xxxxxxxxxxxxxxx> > On Behalf Of Pankaj Bansal > Sent: 2019年5月28日 17:55 > To: Wolfgang Grandegger <wg@xxxxxxxxxxxxxx>; Marc Kleine-Budde > <mkl@xxxxxxxxxxxxxx> > Cc: linux-can@xxxxxxxxxxxxxxx > Subject: [PATCH v2 4/4] net: can: flexcan: can FD Format (FDF) changes > > 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://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.c > an-cia.org%2Ffileadmin%2Fresources%2Fdocuments%2Fproceedings%2F2013 > _hartwich_v2.pdf&data=02%7C01%7Cqiangqing.zhang%40nxp.com%7C0 > 70afb27ad23478de53508d6e352a25f%7C686ea1d3bc2b4c6fa92cd99c5c301 > 635%7C0%7C0%7C636946341388299767&sdata=4gHJvh9QZuIhE7TGvx > arFejLAEWvNLqdq8aUlHxoDcQ%3D&reserved=0 > + */ > + 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; [Joakim Zhang] One more caught, should this be tdcoff = (data_bt->phase_seg1 + data_bt->prop_seg + 1 ) * 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