aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/802-can-0019-can-flexcan-add-CAN-FD-mode-support.patch
diff options
context:
space:
mode:
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.patch397
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(&regs->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, &regs->ctrl);
-
-- /* print chip status */
-- netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
-- priv->read(&regs->mcr), priv->read(&regs->ctrl));
-+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
-+ reg_cbt = priv->read(&regs->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, &regs->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(&regs->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, &regs->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(&regs->mcr),
-+ priv->read(&regs->ctrl),
-+ priv->read(&regs->cbt),
-+ priv->read(&regs->fdcbt));
-+ }
-+ } else {
-+ reg = priv->read(&regs->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, &regs->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(&regs->mcr), priv->read(&regs->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, &regs->ctrl);
-
-+ /* FDCTRL */
-+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
-+ reg_fdctrl = priv->read(&regs->fdctrl) & ~FLEXCAN_FDCTRL_FDRATE;
-+ reg_fdctrl &= ~(FLEXCAN_FDCTRL_MBDSR1(0x3) | FLEXCAN_FDCTRL_MBDSR0(0x3));
-+ reg_mcr = priv->read(&regs->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, &regs->fdctrl);
-+ priv->write(reg_mcr, &regs->mcr);
-+ }
-+
- if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
- reg_ctrl2 = priv->read(&regs->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);