can: flexcan: add Transceiver Delay Compensation support
authorJoakim Zhang <qiangqing.zhang@nxp.com>
Fri, 12 Jul 2019 08:02:56 +0000 (08:02 +0000)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 22 Sep 2020 14:55:34 +0000 (16:55 +0200)
The CAN-FD protocol allows the transmission and reception of data at a
higher bit rate than the nominal rate used in the arbitration phase when
the message's BRS bit is set.

The TDC mechanism is effective only during the data phase of FD frames
having BRS bit set. It has no effect either on non-FD frames, or on FD
frames transmitted at normal bit rate.

Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Link: https://lore.kernel.org/r/20190712075926.7357-7-qiangqing.zhang@nxp.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/flexcan.c

index fc0e9d5fd02b66bd864a5279cb0225dff0c1f2e6..fc98b5d521f205a5ff3c47a7131f5a2dd4407c69 100644 (file)
 #define FLEXCAN_FDCTRL_MBDSR_12                0x1
 #define FLEXCAN_FDCTRL_MBDSR_32                0x2
 #define FLEXCAN_FDCTRL_MBDSR_64                0x3
+#define FLEXCAN_FDCTRL_TDCEN           BIT(15)
+#define FLEXCAN_FDCTRL_TDCFAIL         BIT(14)
+#define FLEXCAN_FDCTRL_TDCOFF          GENMASK(12, 8)
+#define FLEXCAN_FDCTRL_TDCVAL          GENMASK(5, 0)
 
 /* FLEXCAN FD Bit Timing register (FDCBT) bits */
 #define FLEXCAN_FDCBT_FPRESDIV_MASK    GENMASK(29, 20)
@@ -1220,11 +1224,24 @@ static void flexcan_set_bittiming_cbt(const struct net_device *dev)
 
        /* FDCTRL */
        reg_fdctrl = priv->read(&regs->fdctrl);
-       reg_fdctrl &= ~FLEXCAN_FDCTRL_FDRATE;
+       reg_fdctrl &= ~(FLEXCAN_FDCTRL_FDRATE |
+                       FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, 0x1f));
 
-       if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+       if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
                reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
 
+               if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+                       /* TDC must be disabled for Loop Back mode */
+                       reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN;
+               } else {
+                       reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN |
+                               FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF,
+                                          ((dbt->phase_seg1 - 1) +
+                                           dbt->prop_seg + 2) *
+                                          ((dbt->brp - 1 ) + 1));
+               }
+       }
+
        netdev_dbg(dev, "writing fdctrl=0x%08x\n", reg_fdctrl);
        priv->write(reg_fdctrl, &regs->fdctrl);