Hi Marc,
This patch set intends to enable CANFD bitrate switch and ISO FD mode
support.
You may need to firstly review the patch set([PATCH 0/3] can: flexcan:
add imx8qm support).
I noticed that you have been reviewing my patches recetnly, please feel
free to let me know if you want me to rebase the patch about CANFD and
that may easy your patch review.
Thanks a lot.
Joakim Zhang.
Dong Aisheng (1):
can: flexcan: add CANFD BRS support and improve bittiming setting
Joakim Zhang (1):
can: flexcan: add ISO CAN FD feature support
drivers/net/can/flexcan.c | 116 ++++++++++++++++++++++++++++++--------
1 file changed, 94 insertions(+), 22 deletions(-)
--
2.17.1
From: Dong Aisheng <[email protected]>
This patch intends to add CANFD BitRate Switch(BRS) support. Bit timing
must be 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 <[email protected]>
Signed-off-by: Dong Aisheng <[email protected]>
---
drivers/net/can/flexcan.c | 107 ++++++++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 21 deletions(-)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f997f07b6cf9..4ba35f9eb515 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -137,6 +137,14 @@
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) & 0x1f) << 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_MBDSR3(x) (((x) & 0x3) << 25)
#define FLEXCAN_FDCTRL_MBDSR2(x) (((x) & 0x3) << 22)
@@ -243,7 +251,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
@@ -363,6 +372,18 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
.brp_inc = 1,
};
+static const struct can_bittiming_const flexcan_fd_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 64,
+ .tseg2_min = 1,
+ .tseg2_max = 32,
+ .sjw_max = 32,
+ .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 = 1,
@@ -653,9 +674,13 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
if (cf->can_id & CAN_RTR_FLAG)
ctrl |= FLEXCAN_MB_CNT_RTR;
- if (can_is_canfd_skb(skb))
+ if (can_is_canfd_skb(skb)) {
ctrl |= FLEXCAN_MB_CNT_EDL;
+ if (cf->flags & CANFD_BRS)
+ ctrl |= FLEXCAN_MB_CNT_BRS;
+ }
+
for (i = 0; i < cf->len; i += sizeof(u32)) {
data = be32_to_cpup((__be32 *)&cf->data[i]);
priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
@@ -834,6 +859,9 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
cf->len = can_dlc2len((reg_ctrl >> 16) & 0x0F);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+ cf->flags |= CANFD_BRS;
} else {
cf->len = get_can_dlc((reg_ctrl >> 16) & 0x0F);
@@ -1013,21 +1041,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
u32 reg;
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)
@@ -1039,17 +1053,60 @@ static void flexcan_set_bittiming(struct net_device *dev)
priv->write(reg, ®s->ctrl);
if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ reg = 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, ®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);
+
reg = 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, ®s->fdcbt);
- }
- /* print chip status */
- netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
- priv->read(®s->mcr), priv->read(®s->ctrl));
+ if (bt->brp != dbt->brp)
+ netdev_warn(dev, "PRESDIV not the same, may risk transfer errors\n");
+
+ 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
@@ -1172,6 +1229,13 @@ static int flexcan_chip_start(struct net_device *dev)
priv->write(reg_mcr | FLEXCAN_MCR_FDEN, ®s->mcr);
}
+ if ((priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) &&
+ !(priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
+ netdev_err(dev, "fd mode must be enabled\n");
+ err = -EOPNOTSUPP;
+ goto out_chip_disable;
+ }
+
if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
reg_ctrl2 = priv->read(®s->ctrl2);
reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS;
@@ -1666,6 +1730,7 @@ static int flexcan_probe(struct platform_device *pdev)
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
priv->offload.is_canfd = true;
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, "canfd mode can't work on fifo mode\n");
--
2.17.1
ISO CAN FD is introduced to increase the failture detection capability
than non-ISO CAN FD. The non-ISO CAN FD is still supported by FlexCAN so
that it can be used mainly during an intermediate phase, for evaluation
and development purposes.
Therefore, it is strongly recommended to configure FlexCAN to the ISO
CAN FD protocol by setting the ISOCANFDEN field in the CTRL2 register.
Test Command:
ISO FD MODE:
ip link set can0 type can bitrate 1000000 dbitrate 4000000 fd on
fd-non-iso off
non-ISO FD MODE:
ip link set can0 type can bitrate 1000000 dbitrate 4000000 fd on
fd-non-iso on
NOTE: if you only set "fd on", driver will use ISO FD MODE by default.
Signed-off-by: Joakim Zhang <[email protected]>
---
drivers/net/can/flexcan.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 4ba35f9eb515..25e077a68db9 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -91,6 +91,7 @@
#define FLEXCAN_CTRL2_MRP BIT(18)
#define FLEXCAN_CTRL2_RRS BIT(17)
#define FLEXCAN_CTRL2_EACEN BIT(16)
+#define FLEXCAN_CTRL2_ISOCANFDEN BIT(12)
/* FLEXCAN memory error control register (MECR) bits */
#define FLEXCAN_MECR_ECRWRDIS BIT(31)
@@ -1227,6 +1228,12 @@ static int flexcan_chip_start(struct net_device *dev)
priv->write(reg_fdctrl, ®s->fdctrl);
reg_mcr = priv->read(®s->mcr);
priv->write(reg_mcr | FLEXCAN_MCR_FDEN, ®s->mcr);
+
+ reg_ctrl2 = flexcan_read(®s->ctrl2);
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
+ flexcan_write(reg_ctrl2 | FLEXCAN_CTRL2_ISOCANFDEN, ®s->ctrl2);
+ else
+ flexcan_write(reg_ctrl2 & ~FLEXCAN_CTRL2_ISOCANFDEN, ®s->ctrl2);
}
if ((priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) &&
@@ -1729,7 +1736,7 @@ static int flexcan_probe(struct platform_device *pdev)
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
priv->offload.is_canfd = true;
- priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO;
priv->can.bittiming_const = &flexcan_fd_bittiming_const;
priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
} else {
--
2.17.1