diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch b/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch deleted file mode 100644 index ee0dbd179e..0000000000 --- a/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 2aea13a107090d05e968d7d2aa3f72380a3f1b4c Mon Sep 17 00:00:00 2001 -From: Joakim Zhang <qiangqing.zhang@nxp.com> -Date: Fri, 12 Jul 2019 08:02:44 +0000 -Subject: [PATCH] can: flexcan: add CAN FD mode support - -This patch intends to add CAN FD mode support in driver, it means that -payload size can extend up to 64 bytes. - -Bit timing always set in CBT register other than CTRL1 register when -CANFD supports BRS, it will extend the range of all CAN bit timing -variables (PRESDIV, PROPSEG, PSEG1, PSEG2 and RJW), which will improve -the bit timing accuracy. - -Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com> -Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> ---- - drivers/net/can/flexcan.c | 247 ++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 218 insertions(+), 29 deletions(-) - ---- 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,26 @@ - FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \ - FLEXCAN_ESR_WAK_INT) - -+/* FLEXCAN 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 FD control register (FDCTRL) bits */ -+#define FLEXCAN_FDCTRL_FDRATE BIT(31) -+#define FLEXCAN_FDCTRL_MBDSR1(x) (((x) & 0x3) << 19) -+#define FLEXCAN_FDCTRL_MBDSR0(x) (((x) & 0x3) << 16) -+ -+/* FLEXCAN FD Bit Timing register (FDCBT) bits */ -+#define FLEXCAN_FDCBT_FPRESDIV(x) (((x) & 0x3ff) << 20) -+#define FLEXCAN_FDCBT_FRJW(x) (((x) & 0x07) << 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 +182,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) -@@ -192,6 +216,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_TIMESTAMP_SUPPORT_FD BIT(9) /* Use timestamp then support can fd mode */ - - /* Structure of the message buffer */ - struct flexcan_mb { -@@ -225,7 +250,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 +276,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 { -@@ -336,6 +366,30 @@ static const struct can_bittiming_const - .brp_inc = 1, - }; - -+static const struct can_bittiming_const flexcan_fd_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_fd_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. -@@ -638,7 +692,7 @@ static netdev_tx_t flexcan_start_xmit(st - struct canfd_frame *cfd = (struct canfd_frame *)skb->data; - u32 can_id; - u32 data; -- u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cfd->len << 16); -+ u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16); - int i; - - if (can_dropped_invalid_skb(dev, skb)) -@@ -656,6 +710,9 @@ static netdev_tx_t flexcan_start_xmit(st - if (cfd->can_id & CAN_RTR_FLAG) - ctrl |= FLEXCAN_MB_CNT_RTR; - -+ if (can_is_canfd_skb(skb)) -+ ctrl |= FLEXCAN_MB_CNT_EDL; -+ - for (i = 0; i < cfd->len; i += sizeof(u32)) { - data = be32_to_cpup((__be32 *)&cfd->data[i]); - priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]); -@@ -866,7 +923,10 @@ static struct sk_buff *flexcan_mailbox_r - reg_ctrl = priv->read(&mb->can_ctrl); - } - -- skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd); -+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL) -+ skb = alloc_canfd_skb(offload->dev, &cfd); -+ else -+ skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd); - if (unlikely(!skb)) { - skb = ERR_PTR(-ENOMEM); - goto mark_as_read; -@@ -881,9 +941,17 @@ static struct sk_buff *flexcan_mailbox_r - else - cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK; - -- if (reg_ctrl & FLEXCAN_MB_CNT_RTR) -- cfd->can_id |= CAN_RTR_FLAG; -- cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf); -+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL) { -+ cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf)); -+ } else { -+ cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf); -+ -+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR) -+ cfd->can_id |= CAN_RTR_FLAG; -+ } -+ -+ if (reg_ctrl & FLEXCAN_MB_CNT_ESI) -+ cfd->flags |= CANFD_ESI; - - for (i = 0; i < cfd->len; i += sizeof(u32)) { - __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)])); -@@ -1028,27 +1096,14 @@ static irqreturn_t flexcan_irq(int irq, - - 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 *dbt = &priv->can.data_bittiming; - struct flexcan_regs __iomem *regs = priv->regs; -- u32 reg; -+ u32 reg, reg_cbt, reg_fdcbt; - - 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 &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM); - if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) - reg |= FLEXCAN_CTRL_LPB; - if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) -@@ -1059,9 +1114,102 @@ static void flexcan_set_bittiming(struct - netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); - priv->write(reg, ®s->ctrl); - -- /* print chip status */ -- netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, -- priv->read(®s->mcr), priv->read(®s->ctrl)); -+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { -+ reg_cbt = priv->read(®s->cbt); -+ reg_cbt &= ~(FLEXCAN_CBT_EPRESDIV(0x3ff) | -+ FLEXCAN_CBT_EPSEG1(0x1f) | -+ FLEXCAN_CBT_EPSEG2(0x1f) | -+ FLEXCAN_CBT_ERJW(0x1f) | -+ FLEXCAN_CBT_EPROPSEG(0x3f) | -+ FLEXCAN_CBT_BTF); -+ -+ /* 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; -+ } -+ -+ reg_cbt = FLEXCAN_CBT_EPRESDIV(bt->brp - 1) | -+ FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) | -+ FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1) | -+ FLEXCAN_CBT_ERJW(bt->sjw - 1) | -+ FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) | -+ FLEXCAN_CBT_BTF; -+ priv->write(reg_cbt, ®s->cbt); -+ -+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n", -+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1, -+ bt->sjw - 1, bt->prop_seg - 1); -+ -+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { -+ reg_fdcbt = priv->read(®s->fdcbt); -+ reg_fdcbt &= ~(FLEXCAN_FDCBT_FPRESDIV(0x3ff) | -+ FLEXCAN_FDCBT_FPSEG1(0x07) | -+ FLEXCAN_FDCBT_FPSEG2(0x07) | -+ FLEXCAN_FDCBT_FRJW(0x07) | -+ FLEXCAN_FDCBT_FPROPSEG(0x1f)); -+ -+ /* 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 (dbt->phase_seg1 > 0x8) { -+ dbt->prop_seg += (dbt->phase_seg1 - 0x8); -+ dbt->phase_seg1 = 0x8; -+ } -+ -+ reg_fdcbt = FLEXCAN_FDCBT_FPRESDIV(dbt->brp - 1) | -+ FLEXCAN_FDCBT_FPSEG1(dbt->phase_seg1 - 1) | -+ FLEXCAN_FDCBT_FPSEG2(dbt->phase_seg2 - 1) | -+ FLEXCAN_FDCBT_FRJW(dbt->sjw - 1) | -+ FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg); -+ priv->write(reg_fdcbt, ®s->fdcbt); -+ -+ if (bt->brp != dbt->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", -+ dbt->brp, bt->brp); -+ -+ netdev_dbg(dev, "fdbt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n", -+ dbt->brp - 1, dbt->phase_seg1 - 1, dbt->phase_seg2 - 1, -+ dbt->sjw - 1, dbt->prop_seg); -+ -+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n", -+ __func__, priv->read(®s->mcr), -+ priv->read(®s->ctrl), -+ priv->read(®s->cbt), -+ priv->read(®s->fdcbt)); -+ } -+ } else { -+ 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)); -+ -+ 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); -+ priv->write(reg, ®s->ctrl); -+ -+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n", -+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1, -+ bt->sjw - 1, bt->prop_seg - 1); -+ -+ /* print chip status */ -+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, -+ priv->read(®s->mcr), priv->read(®s->ctrl)); -+ } - } - - /* flexcan_chip_start -@@ -1073,7 +1221,7 @@ static int flexcan_chip_start(struct net - { - struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->regs; -- u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; -+ u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr, reg_fdctrl; - u64 reg_imask; - int err, i; - struct flexcan_mb __iomem *mb; -@@ -1172,6 +1320,26 @@ static int flexcan_chip_start(struct net - netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); - priv->write(reg_ctrl, ®s->ctrl); - -+ /* FDCTRL */ -+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { -+ reg_fdctrl = priv->read(®s->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE; -+ reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3)); -+ reg_mcr = priv->read(®s->mcr) & ~FLEXCAN_MCR_FDEN; -+ -+ /* support BRS when set CAN FD mode -+ * 64 bytes payload per MB and 7 MBs per RAM block by default -+ * enable CAN FD mode -+ */ -+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { -+ reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE; -+ reg_fdctrl |= FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3); -+ reg_mcr |= FLEXCAN_MCR_FDEN; -+ } -+ -+ priv->write(reg_fdctrl, ®s->fdctrl); -+ priv->write(reg_mcr, ®s->mcr); -+ } -+ - if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) { - reg_ctrl2 = priv->read(®s->ctrl2); - reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS; -@@ -1312,6 +1480,12 @@ static int flexcan_open(struct net_devic - struct flexcan_priv *priv = netdev_priv(dev); - int err; - -+ if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) && -+ (priv->can.ctrlmode & CAN_CTRLMODE_FD)) { -+ netdev_err(dev, "three samples mode and fd mode can't be used together\n"); -+ return -EINVAL; -+ } -+ - err = pm_runtime_get_sync(priv->dev); - if (err < 0) { - pm_runtime_put_noidle(priv->dev); -@@ -1330,7 +1504,10 @@ static int flexcan_open(struct net_devic - if (err) - goto out_transceiver_disable; - -- priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; -+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) -+ priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN; -+ else -+ 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); - -@@ -1682,6 +1859,18 @@ static int flexcan_probe(struct platform - priv->devtype_data = devtype_data; - priv->reg_xceiver = reg_xceiver; - -+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) { -+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { -+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; -+ priv->can.bittiming_const = &flexcan_fd_bittiming_const; -+ priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const; -+ } else { -+ dev_err(&pdev->dev, "can fd mode can't work on fifo mode\n"); -+ err = -EINVAL; -+ goto failed_register; -+ } -+ } -+ - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); |