diff options
-rw-r--r-- | drivers/net/can/rcar/rcar_canfd.c | 228 |
1 files changed, 156 insertions, 72 deletions
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 7f10213738e5..1e559c0ff038 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -191,9 +191,19 @@ /* 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) @@ -425,19 +435,10 @@ #define RCANFD_C_RPGACC(r) (0x1900 + (0x04 * (r))) /* R-Car Gen4 Classical and CAN FD mode specific register map */ -#define RCANFD_GEN4_FDCFG(m) (0x1404 + (0x20 * (m))) - #define RCANFD_GEN4_GAFL_OFFSET (0x1800) /* CAN FD mode specific register map */ -/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */ -#define RCANFD_F_DCFG(gpriv, m) ((gpriv)->info->regs->f_dcfg + (0x20 * (m))) -#define RCANFD_F_CFDCFG(m) (0x0504 + (0x20 * (m))) -#define RCANFD_F_CFDCTR(m) (0x0508 + (0x20 * (m))) -#define RCANFD_F_CFDSTS(m) (0x050c + (0x20 * (m))) -#define RCANFD_F_CFDCRC(m) (0x0510 + (0x20 * (m))) - /* RSCFDnCFDGAFLXXXj offset */ #define RCANFD_F_GAFL_OFFSET (0x1000) @@ -510,7 +511,7 @@ struct rcar_canfd_regs { u16 cfcc; /* Common FIFO Configuration/Control Register */ u16 cfsts; /* Common FIFO Status Register */ u16 cfpctr; /* Common FIFO Pointer Control Register */ - u16 f_dcfg; /* Global FD Configuration Register */ + u16 coffset; /* Channel Data Bitrate Configuration Register */ u16 rfoffset; /* Receive FIFO buffer access ID register */ u16 cfoffset; /* Transmit/receive FIFO buffer access ID register */ }; @@ -529,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; @@ -636,12 +638,31 @@ 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, .cfsts = 0x0178, .cfpctr = 0x01d8, - .f_dcfg = 0x0500, + .coffset = 0x0500, .rfoffset = 0x3000, .cfoffset = 0x3400, }; @@ -651,7 +672,7 @@ static const struct rcar_canfd_regs rcar_gen4_regs = { .cfcc = 0x0120, .cfsts = 0x01e0, .cfpctr = 0x0240, - .f_dcfg = 0x1400, + .coffset = 0x1400, .rfoffset = 0x6000, .cfoffset = 0x6400, }; @@ -681,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, @@ -697,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, @@ -713,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, @@ -729,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, @@ -781,23 +806,54 @@ static void rcar_canfd_update_bit(void __iomem *base, u32 reg, static void rcar_canfd_get_data(struct rcar_canfd_channel *priv, struct canfd_frame *cf, u32 off) { + u32 *data = (u32 *)cf->data; u32 i, lwords; lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); for (i = 0; i < lwords; i++) - *((u32 *)cf->data + i) = - rcar_canfd_read(priv->base, off + i * sizeof(u32)); + data[i] = rcar_canfd_read(priv->base, off + i * sizeof(u32)); } static void rcar_canfd_put_data(struct rcar_canfd_channel *priv, struct canfd_frame *cf, u32 off) { + const u32 *data = (u32 *)cf->data; u32 i, lwords; lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); for (i = 0; i < lwords; i++) - rcar_canfd_write(priv->base, off + i * sizeof(u32), - *((u32 *)cf->data + i)); + rcar_canfd_write(priv->base, off + i * sizeof(u32), data[i]); +} + +/* RSCFDnCFDCmXXX -> rcar_canfd_f_xxx(gpriv, ch) */ +static inline unsigned int rcar_canfd_f_dcfg(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + return gpriv->info->regs->coffset + 0x00 + 0x20 * ch; +} + +static inline unsigned int rcar_canfd_f_cfdcfg(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + return gpriv->info->regs->coffset + 0x04 + 0x20 * ch; +} + +static inline unsigned int rcar_canfd_f_cfdctr(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + return gpriv->info->regs->coffset + 0x08 + 0x20 * ch; +} + +static inline unsigned int rcar_canfd_f_cfdsts(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + return gpriv->info->regs->coffset + 0x0c + 0x20 * ch; +} + +static inline unsigned int rcar_canfd_f_cfdcrc(struct rcar_canfd_global *gpriv, + unsigned int ch) +{ + return gpriv->info->regs->coffset + 0x10 + 0x20 * ch; } static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) @@ -808,8 +864,8 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) can_free_echo_skb(ndev, i, NULL); } -static void rcar_canfd_setrnc(struct rcar_canfd_global *gpriv, unsigned int ch, - unsigned int num_rules) +static void rcar_canfd_set_rnc(struct rcar_canfd_global *gpriv, unsigned int ch, + unsigned int num_rules) { unsigned int rnc_stride = 32 / gpriv->info->rnc_field_width; unsigned int shift = 32 - (ch % rnc_stride + 1) * gpriv->info->rnc_field_width; @@ -827,8 +883,8 @@ static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv) for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) - rcar_canfd_set_bit(gpriv->base, RCANFD_GEN4_FDCFG(ch), - val); + rcar_canfd_set_bit(gpriv->base, + rcar_canfd_f_cfdcfg(gpriv, ch), val); } else { if (gpriv->fdmode) rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG, @@ -841,6 +897,7 @@ static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv) static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) { + struct device *dev = &gpriv->pdev->dev; u32 sts, ch; int err; @@ -850,7 +907,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, !(sts & RCANFD_GSTS_GRAMINIT), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, "global raminit failed\n"); + dev_dbg(dev, "global raminit failed\n"); return err; } @@ -863,7 +920,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, (sts & RCANFD_GSTS_GRSTSTS), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, "global reset failed\n"); + dev_dbg(dev, "global reset failed\n"); return err; } @@ -887,8 +944,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) (sts & RCANFD_CSTS_CRSTSTS), 2, 500000); if (err) { - dev_dbg(&gpriv->pdev->dev, - "channel %u reset failed\n", ch); + dev_dbg(dev, "channel %u reset failed\n", ch); return err; } } @@ -938,7 +994,7 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv, RCANFD_GAFLECTR_AFLDAE)); /* Write number of rules for channel */ - rcar_canfd_setrnc(gpriv, ch, num_rules); + rcar_canfd_set_rnc(gpriv, ch, num_rules); if (gpriv->info->shared_can_regs) offset = RCANFD_GEN4_GAFL_OFFSET; else if (gpriv->fdmode) @@ -1436,14 +1492,17 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void rcar_canfd_set_bittiming(struct net_device *dev) +static void rcar_canfd_set_bittiming(struct net_device *ndev) { - struct rcar_canfd_channel *priv = netdev_priv(dev); + 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 */ @@ -1452,46 +1511,43 @@ static void rcar_canfd_set_bittiming(struct net_device *dev) tseg1 = bt->prop_seg + bt->phase_seg1 - 1; tseg2 = bt->phase_seg2 - 1; - if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { - /* CAN FD only mode */ + if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) { cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) | RCANFD_NCFG_NBRP(brp) | RCANFD_NCFG_NSJW(gpriv, sjw) | RCANFD_NCFG_NTSEG2(gpriv, tseg2)); + } else { + cfg = (RCANFD_CFG_TSEG1(tseg1) | RCANFD_CFG_BRP(brp) | + RCANFD_CFG_SJW(sjw) | RCANFD_CFG_TSEG2(tseg2)); + } - rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); - - /* Data bit timing settings */ - brp = dbt->brp - 1; - sjw = dbt->sjw - 1; - tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; - tseg2 = dbt->phase_seg2 - 1; - - cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) | - RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2)); + rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - rcar_canfd_write(priv->base, RCANFD_F_DCFG(gpriv, ch), cfg); - netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); - } else { - /* Classical CAN only mode */ - if (gpriv->info->shared_can_regs) { - cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) | - RCANFD_NCFG_NBRP(brp) | - RCANFD_NCFG_NSJW(gpriv, sjw) | - RCANFD_NCFG_NTSEG2(gpriv, tseg2)); - } else { - cfg = (RCANFD_CFG_TSEG1(tseg1) | - RCANFD_CFG_BRP(brp) | - RCANFD_CFG_SJW(sjw) | - RCANFD_CFG_TSEG2(tseg2)); - } + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) + return; - rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg); - netdev_dbg(priv->ndev, - "rate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n", - brp, sjw, tseg1, tseg2); + /* Data bit timing settings */ + brp = dbt->brp - 1; + sjw = dbt->sjw - 1; + tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; + tseg2 = dbt->phase_seg2 - 1; + + cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) | + 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) @@ -1691,7 +1747,8 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb, static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) { - struct net_device_stats *stats = &priv->ndev->stats; + struct net_device *ndev = priv->ndev; + struct net_device_stats *stats = &ndev->stats; struct rcar_canfd_global *gpriv = priv->gpriv; struct canfd_frame *cf; struct sk_buff *skb; @@ -1707,14 +1764,13 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && sts & RCANFD_RFFDSTS_RFFDF) - skb = alloc_canfd_skb(priv->ndev, &cf); + skb = alloc_canfd_skb(ndev, &cf); else - skb = alloc_can_skb(priv->ndev, - (struct can_frame **)&cf); + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); } else { id = rcar_canfd_read(priv->base, RCANFD_C_RFID(ridx)); dlc = rcar_canfd_read(priv->base, RCANFD_C_RFPTR(ridx)); - skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cf); + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); } if (!skb) { @@ -1735,7 +1791,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv) if (sts & RCANFD_RFFDSTS_RFESI) { cf->flags |= CANFD_ESI; - netdev_dbg(priv->ndev, "ESI Error\n"); + netdev_dbg(ndev, "ESI Error\n"); } if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) { @@ -1802,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; @@ -1818,10 +1897,10 @@ static int rcar_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode) } } -static int rcar_canfd_get_berr_counter(const struct net_device *dev, +static int rcar_canfd_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { - struct rcar_canfd_channel *priv = netdev_priv(dev); + struct rcar_canfd_channel *priv = netdev_priv(ndev); u32 val, ch = priv->channel; /* Peripheral clock is already enabled in probe */ @@ -1924,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; |