]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
can: rcar_canfd: Add support for Transceiver Delay Compensation
authorGeert Uytterhoeven <geert+renesas@glider.be>
Wed, 11 Jun 2025 15:37:39 +0000 (17:37 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 13 Jun 2025 07:34:09 +0000 (09:34 +0200)
The Renesas CAN-FD hardware block supports configuring Transceiver Delay
Compensation, and reading back the Transceiver Delay Compensation
Result, which is needed to support high transfer rates like 8 Mbps.
The Secondary Sample Point is either the measured delay plus the
configured offset, or just the configured offset.

Fix the existing RCANFD_FDCFG_TDCO() macro for the intended use case
(writing instead of reading the field).  Add register definition bits
for the Channel n CAN-FD Status Register.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://patch.msgid.link/69db727d5f728d679ba691d20854e7d963d0f323.1749655315.git.geert+renesas@glider.be
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/rcar/rcar_canfd.c

index 3340ae75bbecdb5b74e111926d83670dcc24be39..1e559c0ff0389a5bb73f47529fa399fc23929d9e 100644 (file)
 /* RSCFDnCFDCmFDCFG */
 #define RCANFD_GEN4_FDCFG_CLOE         BIT(30)
 #define RCANFD_GEN4_FDCFG_FDOE         BIT(28)
+#define RCANFD_FDCFG_TDCO              GENMASK(23, 16)
 #define RCANFD_FDCFG_TDCE              BIT(9)
 #define RCANFD_FDCFG_TDCOC             BIT(8)
-#define RCANFD_FDCFG_TDCO(x)           (((x) & 0x7f) >> 16)
+
+/* RSCFDnCFDCmFDSTS */
+#define RCANFD_FDSTS_SOC               GENMASK(31, 24)
+#define RCANFD_FDSTS_EOC               GENMASK(23, 16)
+#define RCANFD_GEN4_FDSTS_TDCVF                BIT(15)
+#define RCANFD_GEN4_FDSTS_PNSTS                GENMASK(13, 12)
+#define RCANFD_FDSTS_SOCO              BIT(9)
+#define RCANFD_FDSTS_EOCO              BIT(8)
+#define RCANFD_FDSTS_TDCVF             BIT(7)
+#define RCANFD_FDSTS_TDCR              GENMASK(7, 0)
 
 /* RSCFDnCFDRFCCx */
 #define RCANFD_RFCC_RFIM               BIT(12)
@@ -520,6 +530,7 @@ struct rcar_canfd_shift_data {
 struct rcar_canfd_hw_info {
        const struct can_bittiming_const *nom_bittiming;
        const struct can_bittiming_const *data_bittiming;
+       const struct can_tdc_const *tdc_const;
        const struct rcar_canfd_regs *regs;
        const struct rcar_canfd_shift_data *sh;
        u8 rnc_field_width;
@@ -627,6 +638,25 @@ static const struct can_bittiming_const rcar_canfd_bittiming_const = {
        .brp_inc = 1,
 };
 
+/* CAN FD Transmission Delay Compensation constants */
+static const struct can_tdc_const rcar_canfd_gen3_tdc_const = {
+       .tdcv_min = 1,
+       .tdcv_max = 128,
+       .tdco_min = 1,
+       .tdco_max = 128,
+       .tdcf_min = 0,  /* Filter window not supported */
+       .tdcf_max = 0,
+};
+
+static const struct can_tdc_const rcar_canfd_gen4_tdc_const = {
+       .tdcv_min = 1,
+       .tdcv_max = 256,
+       .tdco_min = 1,
+       .tdco_max = 256,
+       .tdcf_min = 0,  /* Filter window not supported */
+       .tdcf_max = 0,
+};
+
 static const struct rcar_canfd_regs rcar_gen3_regs = {
        .rfcc = 0x00b8,
        .cfcc = 0x0118,
@@ -672,6 +702,7 @@ static const struct rcar_canfd_shift_data rcar_gen4_shift_data = {
 static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
        .nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const,
        .data_bittiming = &rcar_canfd_gen3_data_bittiming_const,
+       .tdc_const = &rcar_canfd_gen3_tdc_const,
        .regs = &rcar_gen3_regs,
        .sh = &rcar_gen3_shift_data,
        .rnc_field_width = 8,
@@ -688,6 +719,7 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
 static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
        .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
        .data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
+       .tdc_const = &rcar_canfd_gen4_tdc_const,
        .regs = &rcar_gen4_regs,
        .sh = &rcar_gen4_shift_data,
        .rnc_field_width = 16,
@@ -704,6 +736,7 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
 static const struct rcar_canfd_hw_info rzg2l_hw_info = {
        .nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const,
        .data_bittiming = &rcar_canfd_gen3_data_bittiming_const,
+       .tdc_const = &rcar_canfd_gen3_tdc_const,
        .regs = &rcar_gen3_regs,
        .sh = &rcar_gen3_shift_data,
        .rnc_field_width = 8,
@@ -720,6 +753,7 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
 static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
        .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
        .data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
+       .tdc_const = &rcar_canfd_gen4_tdc_const,
        .regs = &rcar_gen4_regs,
        .sh = &rcar_gen4_shift_data,
        .rnc_field_width = 16,
@@ -1460,12 +1494,15 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
 
 static void rcar_canfd_set_bittiming(struct net_device *ndev)
 {
+       u32 mask = RCANFD_FDCFG_TDCO | RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC;
        struct rcar_canfd_channel *priv = netdev_priv(ndev);
        struct rcar_canfd_global *gpriv = priv->gpriv;
        const struct can_bittiming *bt = &priv->can.bittiming;
        const struct can_bittiming *dbt = &priv->can.fd.data_bittiming;
+       const struct can_tdc_const *tdc_const = priv->can.fd.tdc_const;
+       const struct can_tdc *tdc = &priv->can.fd.tdc;
+       u32 cfg, tdcmode = 0, tdco = 0;
        u16 brp, sjw, tseg1, tseg2;
-       u32 cfg;
        u32 ch = priv->channel;
 
        /* Nominal bit timing settings */
@@ -1497,6 +1534,20 @@ static void rcar_canfd_set_bittiming(struct net_device *ndev)
               RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
 
        rcar_canfd_write(priv->base, rcar_canfd_f_dcfg(gpriv, ch), cfg);
+
+       /* Transceiver Delay Compensation */
+       if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_AUTO) {
+               /* TDC enabled, measured + offset */
+               tdcmode = RCANFD_FDCFG_TDCE;
+               tdco = tdc->tdco - 1;
+       } else if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_MANUAL) {
+               /* TDC enabled, offset only */
+               tdcmode = RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC;
+               tdco = min(tdc->tdcv + tdc->tdco, tdc_const->tdco_max) - 1;
+       }
+
+       rcar_canfd_update_bit(gpriv->base, rcar_canfd_f_cfdcfg(gpriv, ch), mask,
+                             tdcmode | FIELD_PREP(RCANFD_FDCFG_TDCO, tdco));
 }
 
 static int rcar_canfd_start(struct net_device *ndev)
@@ -1807,6 +1858,29 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota)
        return num_pkts;
 }
 
+static unsigned int rcar_canfd_get_tdcr(struct rcar_canfd_global *gpriv,
+                                       unsigned int ch)
+{
+       u32 sts = rcar_canfd_read(gpriv->base, rcar_canfd_f_cfdsts(gpriv, ch));
+       u32 tdcr = FIELD_GET(RCANFD_FDSTS_TDCR, sts);
+
+       return tdcr & (gpriv->info->tdc_const->tdcv_max - 1);
+}
+
+static int rcar_canfd_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
+{
+       struct rcar_canfd_channel *priv = netdev_priv(ndev);
+       u32 tdco = priv->can.fd.tdc.tdco;
+       u32 tdcr;
+
+       /* Transceiver Delay Compensation Result */
+       tdcr = rcar_canfd_get_tdcr(priv->gpriv, priv->channel) + 1;
+
+       *tdcv = tdcr < tdco ? 0 : tdcr - tdco;
+
+       return 0;
+}
+
 static int rcar_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode)
 {
        int err;
@@ -1929,12 +2003,17 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
        if (gpriv->fdmode) {
                priv->can.bittiming_const = gpriv->info->nom_bittiming;
                priv->can.fd.data_bittiming_const = gpriv->info->data_bittiming;
+               priv->can.fd.tdc_const = gpriv->info->tdc_const;
 
                /* Controller starts in CAN FD only mode */
                err = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
                if (err)
                        goto fail;
-               priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+
+               priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |
+                                              CAN_CTRLMODE_TDC_AUTO |
+                                              CAN_CTRLMODE_TDC_MANUAL;
+               priv->can.fd.do_get_auto_tdcv = rcar_canfd_get_auto_tdcv;
        } else {
                /* Controller starts in Classical CAN only mode */
                priv->can.bittiming_const = &rcar_canfd_bittiming_const;