[RFC PATCH 1/6] can: esd_402_pci: Add basic support for CAN-FD

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds the basic support for CAN-FD to the driver. This means
transmitting and receiving CAN-FD frames. TDC runs in automatic mode.

- Support only CAN-FD FPGA versions >= 0.72
- Refrain from providing do_set[_data]_bittiming callbacks.
- acc_set_bittiming() is now only called internally in acc_open().
- Rework acc_set_bittiming() (static, void, extended ctrlmode display
  in main stream, change data bit timing debug output)

Signed-off-by: Stefan Mätje <stefan.maetje@xxxxxx>
---
 drivers/net/can/esd/esd_402_pci-core.c |  37 +++-
 drivers/net/can/esd/esdacc.c           | 231 ++++++++++++++++++++++---
 drivers/net/can/esd/esdacc.h           |  43 ++++-
 3 files changed, 275 insertions(+), 36 deletions(-)

diff --git a/drivers/net/can/esd/esd_402_pci-core.c b/drivers/net/can/esd/esd_402_pci-core.c
index 5d6d2828cd04..0c0fc159a1cb 100644
--- a/drivers/net/can/esd/esd_402_pci-core.c
+++ b/drivers/net/can/esd/esd_402_pci-core.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh
- * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh
+ * Copyright (C) 2017 - 2024 Stefan Mätje, esd electronics gmbh
  */
 
 #include <linux/can/dev.h>
@@ -21,6 +21,7 @@
 #define ESD_PCI_DEVICE_ID_PCIE402 0x0402
 
 #define PCI402_FPGA_VER_MIN 0x003d
+#define PCI402_FPGA_VER_0_72 0x0048
 #define PCI402_MAX_CORES 6
 #define PCI402_BAR 0
 #define PCI402_IO_OV_OFFS 0
@@ -70,7 +71,7 @@ static const struct can_bittiming_const pci402_bittiming_const = {
 };
 
 /* Used if the esdACC FPGA is built as CAN-FD version. */
-static const struct can_bittiming_const pci402_bittiming_const_canfd = {
+static const struct can_bittiming_const pci402fd_nom_bittiming_const = {
 	.name = "esd_402fd",
 	.tseg1_min = 1,
 	.tseg1_max = 256,
@@ -78,7 +79,19 @@ static const struct can_bittiming_const pci402_bittiming_const_canfd = {
 	.tseg2_max = 128,
 	.sjw_max = 128,
 	.brp_min = 1,
-	.brp_max = 256,
+	.brp_max = 512,
+	.brp_inc = 1,
+};
+
+static const struct can_bittiming_const pci402fd_data_bittiming_const = {
+	.name = "esd_402fd",
+	.tseg1_min = 1,
+	.tseg1_max = 32,
+	.tseg2_min = 1,
+	.tseg2_max = 16,
+	.sjw_max = 16,
+	.brp_min = 1,
+	.brp_max = 512,
 	.brp_inc = 1,
 };
 
@@ -199,7 +212,13 @@ static int pci402_init_card(struct pci_dev *pdev)
 
 	if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) {
 		pci_warn(pdev,
-			 "esdACC with CAN-FD feature detected. This driver doesn't support CAN-FD yet.\n");
+			 "esdACC with CAN-FD feature detected. This driver partly implements CAN-FD.\n");
+		if (card->ov.version < PCI402_FPGA_VER_0_72) {
+			pci_err(pdev,
+				"esdACC CAN-FD below version 0x%.4x not supported, please update from 0x%.4x\n",
+				PCI402_FPGA_VER_0_72, card->ov.version);
+			return -EINVAL;
+		}
 	}
 
 #ifdef __LITTLE_ENDIAN
@@ -376,11 +395,13 @@ static int pci402_init_cores(struct pci_dev *pdev)
 			CAN_CTRLMODE_CC_LEN8_DLC;
 		if (card->ov.features & ACC_OV_REG_FEAT_MASK_DAR)
 			priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
-		if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD)
-			priv->can.bittiming_const = &pci402_bittiming_const_canfd;
-		else
+		if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) {
+			priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+			priv->can.bittiming_const = &pci402fd_nom_bittiming_const;
+			priv->can.data_bittiming_const = &pci402fd_data_bittiming_const;
+		} else {
 			priv->can.bittiming_const = &pci402_bittiming_const;
-		priv->can.do_set_bittiming = acc_set_bittiming;
+		}
 		priv->can.do_set_mode = acc_set_mode;
 		priv->can.do_get_berr_counter = acc_get_berr_counter;
 
diff --git a/drivers/net/can/esd/esdacc.c b/drivers/net/can/esd/esdacc.c
index c80032bc1a52..faad38e23251 100644
--- a/drivers/net/can/esd/esdacc.c
+++ b/drivers/net/can/esd/esdacc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh
- * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh
+ * Copyright (C) 2017 - 2024 Stefan Mätje, esd electronics gmbh
  */
 
 #include "esdacc.h"
@@ -18,9 +18,19 @@
 #define ACC_DLC_DLC_MASK GENMASK(3, 0)
 #define ACC_DLC_RTR_FLAG BIT(4)
 #define ACC_DLC_SSTX_FLAG BIT(24)	/* Single Shot TX */
-
-/* esdACC DLC in struct acc_bmmsg_rxtxdone::acc_dlc.len only! */
-#define ACC_DLC_TXD_FLAG BIT(5)
+#define ACC_DLC_BRS_FLAG BIT(29)	/* enable Bit Rate Switch */
+#define ACC_DLC_EDL_FLAG BIT(30)	/* enable Extended Data Length = FD frame */
+
+/* Copy of esdACC DLC register in bus master messages only */
+/* struct acc_bmmsg_rxtxdone::acc_dlc.len and acc_bmmsg_fddata::acc_dlc_len */
+#define ACC_DLC_LEN_DLC_MASK GENMASK(3, 0)
+#define ACC_DLC_LEN_TXD_FLAG BIT(5)
+#define ACC_DLC_LEN_SR_FLAG BIT(6)
+#define ACC_DLC_LEN_TXTS_FLAG BIT(7)
+/* struct acc_bmmsg_rxtxdone::acc_dlc.fdf */
+#define ACC_DLC_FDF_ESI_FLAG BIT(28 - 24)
+#define ACC_DLC_FDF_BRS_FLAG BIT(29 - 24)	/* enable Bit Rate Switch */
+#define ACC_DLC_FDF_EDL_FLAG BIT(30 - 24)	/* enable Extended Data Length = FD frame */
 
 /* ecc value of esdACC equals SJA1000's ECC register */
 #define ACC_ECC_SEG 0x1f
@@ -44,6 +54,8 @@
  */
 #define ACC_BM_IRQ_UNMASK_ALL 0x55555555U
 
+static void acc_set_bittiming(struct net_device *netdev);
+
 static void acc_resetmode_enter(struct acc_core *core)
 {
 	acc_set_bits(core, ACC_CORE_OF_CTRL,
@@ -62,18 +74,56 @@ static void acc_resetmode_leave(struct acc_core *core)
 	acc_resetmode_entered(core);
 }
 
+#define ACC_TXQ_WRITE32(core, data, ridx)				\
+	acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_ ## ridx, ((const u32 *)data)[ridx])
+
 static void acc_txq_put(struct acc_core *core, u32 acc_id, u32 acc_dlc,
 			const void *data)
 {
-	acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
-			   *((const u32 *)(data + 4)));
-	acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_0,
-			   *((const u32 *)data));
+	if (acc_dlc & ACC_DLC_EDL_FLAG) {
+		switch (acc_dlc & ACC_DLC_DLC_MASK) {
+		case 15:
+			ACC_TXQ_WRITE32(core, data, 15);
+			ACC_TXQ_WRITE32(core, data, 14);
+			ACC_TXQ_WRITE32(core, data, 13);
+			ACC_TXQ_WRITE32(core, data, 12);
+			fallthrough;
+		case 14:
+			ACC_TXQ_WRITE32(core, data, 11);
+			ACC_TXQ_WRITE32(core, data, 10);
+			ACC_TXQ_WRITE32(core, data, 9);
+			ACC_TXQ_WRITE32(core, data, 8);
+			fallthrough;
+		case 13:
+			ACC_TXQ_WRITE32(core, data, 7);
+			ACC_TXQ_WRITE32(core, data, 6);
+			fallthrough;
+		case 12:
+			ACC_TXQ_WRITE32(core, data, 5);
+			fallthrough;
+		case 11:
+			ACC_TXQ_WRITE32(core, data, 4);
+			fallthrough;
+		case 10:
+			ACC_TXQ_WRITE32(core, data, 3);
+			fallthrough;
+		case 9:
+			ACC_TXQ_WRITE32(core, data, 2);
+			fallthrough;
+		default:
+			break;
+		}
+	}
+	ACC_TXQ_WRITE32(core, data, 1);
+	ACC_TXQ_WRITE32(core, data, 0);
+
 	acc_write32(core, ACC_CORE_OF_TXFIFO_DLC, acc_dlc);
 	/* CAN id must be written at last. This write starts TX. */
 	acc_write32(core, ACC_CORE_OF_TXFIFO_ID, acc_id);
 }
 
+#undef ACC_TXQ_WRITE32
+
 static u8 acc_tx_fifo_next(struct acc_core *core, u8 tx_fifo_idx)
 {
 	++tx_fifo_idx;
@@ -190,6 +240,8 @@ int acc_open(struct net_device *netdev)
 	if (err)
 		return err;
 
+	acc_set_bittiming(netdev);
+
 	ctrl = ACC_REG_CTRL_MASK_IE_RXTX |
 		ACC_REG_CTRL_MASK_IE_TXERROR |
 		ACC_REG_CTRL_MASK_IE_ERRWARN |
@@ -274,9 +326,20 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (fifo_usage == core->tx_fifo_size - 2)
 		netif_stop_queue(netdev);
 
-	acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
-	if (cf->can_id & CAN_RTR_FLAG)
-		acc_dlc |= ACC_DLC_RTR_FLAG;
+	if (can_is_canfd_skb(skb)) {
+		struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+		acc_dlc = can_fd_len2dlc(cfd->len);
+		acc_dlc |= ACC_DLC_EDL_FLAG;
+
+		if (cfd->flags & CANFD_BRS)
+			acc_dlc |= ACC_DLC_BRS_FLAG;
+	} else {
+		acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
+		if (cf->can_id & CAN_RTR_FLAG)
+			acc_dlc |= ACC_DLC_RTR_FLAG;
+	}
+
 	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
 		acc_dlc |= ACC_DLC_SSTX_FLAG;
 
@@ -355,17 +418,22 @@ int acc_set_mode(struct net_device *netdev, enum can_mode mode)
 	return 0;
 }
 
-int acc_set_bittiming(struct net_device *netdev)
+static void acc_set_bittiming(struct net_device *netdev)
 {
 	struct acc_net_priv *priv = netdev_priv(netdev);
 	const struct can_bittiming *bt = &priv->can.bittiming;
+	const struct can_bittiming *dbt = &priv->can.data_bittiming;
 	u32 brp;
 	u32 btr;
 
+	netdev_dbg(netdev, "ctrlmode 0x%03X, FD=%d, TDC=%c\n",
+		   priv->can.ctrlmode, !!(priv->can.ctrlmode & CAN_CTRLMODE_FD),
+		   "OAM?"[FIELD_GET(CAN_CTRLMODE_TDC_MASK, priv->can.ctrlmode)]);
+
 	if (priv->ov->features & ACC_OV_REG_FEAT_MASK_CANFD) {
 		u32 fbtr = 0;
 
-		netdev_dbg(netdev, "bit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n",
+		netdev_dbg(netdev, "nbit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n",
 			   bt->brp, bt->prop_seg,
 			   bt->phase_seg1, bt->phase_seg2, bt->sjw);
 
@@ -379,6 +447,19 @@ int acc_set_bittiming(struct net_device *netdev)
 		acc_write32(priv->core, ACC_CORE_OF_BRP, brp);
 		acc_write32(priv->core, ACC_CORE_OF_BTR, btr);
 
+		netdev_dbg(netdev, "dbit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n",
+			   dbt->brp, dbt->prop_seg,
+			   dbt->phase_seg1, dbt->phase_seg2, dbt->sjw);
+
+		if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+			fbtr = FIELD_PREP(ACC_REG_FBTR_FD_MASK_TSEG1,
+					  dbt->phase_seg1 + dbt->prop_seg - 1);
+			fbtr |= FIELD_PREP(ACC_REG_FBTR_FD_MASK_TSEG2, dbt->phase_seg2 - 1);
+			fbtr |= FIELD_PREP(ACC_REG_FBTR_FD_MASK_SJW, dbt->sjw - 1);
+		}
+		/* Write ACC_CORE_OF_FBTR last. */
+		acc_write32(priv->core, ACC_CORE_OF_FBTR, fbtr);
+
 		netdev_dbg(netdev, "esdACC: BRP %u, NBTR 0x%08x, DBTR 0x%08x",
 			   brp, btr, fbtr);
 	} else {
@@ -398,8 +479,6 @@ int acc_set_bittiming(struct net_device *netdev)
 
 		netdev_dbg(netdev, "esdACC: BRP %u, BTR 0x%08x", brp, btr);
 	}
-
-	return 0;
 }
 
 static void handle_core_msg_rxtxdone(struct acc_core *core,
@@ -409,7 +488,7 @@ static void handle_core_msg_rxtxdone(struct acc_core *core,
 	struct net_device_stats *stats = &core->netdev->stats;
 	struct sk_buff *skb;
 
-	if (msg->acc_dlc.len & ACC_DLC_TXD_FLAG) {
+	if (msg->acc_dlc.len & ACC_DLC_LEN_TXD_FLAG) {
 		u8 tx_fifo_tail = core->tx_fifo_tail;
 
 		if (core->tx_fifo_head == tx_fifo_tail) {
@@ -434,9 +513,17 @@ static void handle_core_msg_rxtxdone(struct acc_core *core,
 		netif_wake_queue(core->netdev);
 
 	} else {
+		struct canfd_frame *cfd;
 		struct can_frame *cf;
+		u8 len;
+
+		if (msg->acc_dlc.fdf & ACC_DLC_FDF_EDL_FLAG) {
+			skb = alloc_canfd_skb(core->netdev, &cfd);
+			cf = (struct can_frame *)cfd;
+		} else {
+			skb = alloc_can_skb(core->netdev, &cf);
+		}
 
-		skb = alloc_can_skb(core->netdev, &cf);
 		if (!skb) {
 			stats->rx_dropped++;
 			return;
@@ -446,15 +533,36 @@ static void handle_core_msg_rxtxdone(struct acc_core *core,
 		if (msg->id & ACC_ID_EFF_FLAG)
 			cf->can_id |= CAN_EFF_FLAG;
 
-		can_frame_set_cc_len(cf, msg->acc_dlc.len & ACC_DLC_DLC_MASK,
-				     priv->can.ctrlmode);
+		if (msg->acc_dlc.fdf & ACC_DLC_FDF_EDL_FLAG) {
+			/* can_fd_dlc2len() masks its argument with 0x0F == ACC_DLC_LEN_DLC_MASK */
+			cfd->len = can_fd_dlc2len(msg->acc_dlc.len);
+
+			if (msg->acc_dlc.fdf & ACC_DLC_FDF_BRS_FLAG)
+				cfd->flags |= CANFD_BRS;
+			if (msg->acc_dlc.fdf & ACC_DLC_FDF_ESI_FLAG)
+				cfd->flags |= CANFD_ESI;
 
-		if (msg->acc_dlc.len & ACC_DLC_RTR_FLAG) {
-			cf->can_id |= CAN_RTR_FLAG;
+			len = cfd->len;
+			stats->rx_bytes += len;
+
+			if (len > CAN_MAX_DLEN) {
+				/* Fetch data buffered from struct acc_bmmsg_fddata messages. */
+				memcpy(cfd->data + CAN_MAX_DLEN, core->fdd, len - CAN_MAX_DLEN);
+				len = CAN_MAX_DLEN;
+			}
 		} else {
-			memcpy(cf->data, msg->data, cf->len);
-			stats->rx_bytes += cf->len;
+			can_frame_set_cc_len(cf, msg->acc_dlc.len & ACC_DLC_DLC_MASK,
+					     priv->can.ctrlmode);
+
+			if (msg->acc_dlc.len & ACC_DLC_RTR_FLAG) {
+				cf->can_id |= CAN_RTR_FLAG;
+				len = 0U;
+			} else {
+				len = cf->len;
+				stats->rx_bytes += len;
+			}
 		}
+		memcpy(cf->data, msg->data, len);
 		stats->rx_packets++;
 
 		skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts);
@@ -637,6 +745,75 @@ handle_core_msg_errstatechange(struct acc_core *core,
 	}
 }
 
+/* Reassemble split CAN-FD data into buffer at struct acc_core::fdd
+ *
+ * The bus master engine splits CAN-FD frames into multiple bus master
+ * messages depending on the data length.
+ *
+ * - three messages for frames with data lengths 48 & 64:
+ *	BM_MSG_ID_FDDATA0
+ *	BM_MSG_ID_FDDATA1
+ *	BM_MSG_ID_RXTXDONE
+ *
+ * - two messages for frames with data lengths of 12, 16, 20, 24 and 32
+ *	BM_MSG_ID_FDDATA0
+ *	BM_MSG_ID_RXTXDONE
+ *
+ * For shorter frames no message with id BM_MSG_ID_FDDATA[01] is created.
+ *
+ * During the handling of the message with id BM_MSG_ID_RXTXDONE the
+ * reassembled CAN-FD data are transferred to struct canfd_frame as
+ * needed. The first up to eight data bytes are always taken from the
+ * BM_MSG_ID_RXTXDONE message.
+ *
+ * Newer FPGA images provide some length information in the struct
+ * acc_bmmsg_fddata::acc_dlc_len member to announce the amount of real
+ * data.
+ * Older FPGA versions don't provide any data length information and
+ * set acc_bmmsg_fddata::acc_dlc_len to zero. In this case the full
+ * data length of ACC_FDD_SLICE_SIZE is copied.
+ *
+ * This function uses the information in acc_bmmsg_fddata::acc_dlc_len
+ * to copy less data.
+ */
+static void handle_core_msg_fddata(struct acc_core *core,
+				   const struct acc_bmmsg_fddata *msg)
+{
+	/* Copy length table indexed by DLC value and BM_MSG_ID_FDDATA[0|1] message type.
+	 * Entries with 0U are never selected.
+	 */
+	static const u8 cp_len_tbl[16][2] = {
+		{ ACC_FDD_SLICE_SIZE, ACC_FDD_SLICE_SIZE },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 0U, 0U },
+		{ 12U - CAN_MAX_DLEN, 0U },
+		{ 16U - CAN_MAX_DLEN, 0U },
+		{ 20U - CAN_MAX_DLEN, 0U },
+		{ 24U - CAN_MAX_DLEN, 0U },
+		{ 32U - CAN_MAX_DLEN, 0U },
+		{ ACC_FDD_SLICE_SIZE, 48U - ACC_FDD_SLICE_SIZE - CAN_MAX_DLEN },
+		{ ACC_FDD_SLICE_SIZE, 64U - ACC_FDD_SLICE_SIZE - CAN_MAX_DLEN },
+	};
+	int msg_type;
+	u8 cp_len;
+	u8 *dst;
+
+	if (msg->acc_dlc_len & ACC_DLC_LEN_TXD_FLAG)
+		return;
+
+	msg_type = msg->msg_id - BM_MSG_ID_FDDATA0;
+	dst = core->fdd + (msg_type * ACC_FDD_SLICE_SIZE);
+	cp_len = cp_len_tbl[msg->acc_dlc_len & ACC_DLC_LEN_DLC_MASK][msg_type];
+
+	memcpy(dst, msg->fdd.ui8, cp_len);
+}
+
 static void handle_core_interrupt(struct acc_core *core)
 {
 	u32 msg_fifo_head = core->bmfifo.local_irq_cnt & 0xff;
@@ -668,8 +845,14 @@ static void handle_core_interrupt(struct acc_core *core)
 						       &msg->errstatechange);
 			break;
 
+		case BM_MSG_ID_FDDATA0:
+		case BM_MSG_ID_FDDATA1:
+			handle_core_msg_fddata(core, &msg->fddata);
+			break;
+
 		default:
-			/* Ignore all other BM messages (like the CAN-FD messages) */
+			/* Ignore all other BM messages */
+			netdev_dbg(core->netdev, "WARN: BM MSG 0x%x ignored\n", msg->msg_id);
 			break;
 		}
 
diff --git a/drivers/net/can/esd/esdacc.h b/drivers/net/can/esd/esdacc.h
index 6b7ebd8c91b2..fdbb017b80a9 100644
--- a/drivers/net/can/esd/esdacc.h
+++ b/drivers/net/can/esd/esdacc.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh
- * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh
+ * Copyright (C) 2017 - 2024 Stefan Mätje, esd electronics gmbh
  */
 
 #include <linux/bits.h>
@@ -67,6 +67,21 @@
 #define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8
 #define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc
 
+#define ACC_CORE_OF_TXFIFO_DATA_2 0x0108
+#define ACC_CORE_OF_TXFIFO_DATA_3 0x010c
+#define ACC_CORE_OF_TXFIFO_DATA_4 0x0110
+#define ACC_CORE_OF_TXFIFO_DATA_5 0x0114
+#define ACC_CORE_OF_TXFIFO_DATA_6 0x0118
+#define ACC_CORE_OF_TXFIFO_DATA_7 0x011c
+#define ACC_CORE_OF_TXFIFO_DATA_8 0x0120
+#define ACC_CORE_OF_TXFIFO_DATA_9 0x0124
+#define ACC_CORE_OF_TXFIFO_DATA_10 0x0128
+#define ACC_CORE_OF_TXFIFO_DATA_11 0x012c
+#define ACC_CORE_OF_TXFIFO_DATA_12 0x0130
+#define ACC_CORE_OF_TXFIFO_DATA_13 0x0134
+#define ACC_CORE_OF_TXFIFO_DATA_14 0x0138
+#define ACC_CORE_OF_TXFIFO_DATA_15 0x013c
+
 /* CTRL register layout */
 #define ACC_REG_CTRL_MASK_RESETMODE BIT(0)
 #define ACC_REG_CTRL_MASK_LOM BIT(1)
@@ -90,16 +105,21 @@
 #define ACC_REG_BTR_CL_MASK_TSEG2 GENMASK(18, 16)
 #define ACC_REG_BTR_CL_MASK_SJW GENMASK(25, 24)
 
-/* BRP and BTR register layout for CAN-FD version */
+/* BRP and (F)BTR register layout for CAN-FD version */
 #define ACC_REG_BRP_FD_MASK_BRP GENMASK(7, 0)
 #define ACC_REG_BTR_FD_MASK_TSEG1 GENMASK(7, 0)
 #define ACC_REG_BTR_FD_MASK_TSEG2 GENMASK(22, 16)
 #define ACC_REG_BTR_FD_MASK_SJW GENMASK(30, 24)
+#define ACC_REG_FBTR_FD_MASK_TSEG1 GENMASK(4, 0)
+#define ACC_REG_FBTR_FD_MASK_TSEG2 GENMASK(19, 16)
+#define ACC_REG_FBTR_FD_MASK_SJW GENMASK(27, 24)
 
 /* 256 BM_MSGs of 32 byte size */
 #define ACC_CORE_DMAMSG_SIZE 32U
 #define ACC_CORE_DMABUF_SIZE (256U * ACC_CORE_DMAMSG_SIZE)
 
+#define ACC_FDD_SLICE_SIZE ((CANFD_MAX_DLEN - CAN_MAX_DLEN) / 2)
+
 enum acc_bmmsg_id {
 	BM_MSG_ID_RXTXDONE = 0x01,
 	BM_MSG_ID_TXABORT = 0x02,
@@ -110,6 +130,8 @@ enum acc_bmmsg_id {
 	BM_MSG_ID_TIMESLICE = 0x07,
 	BM_MSG_ID_HWTIMER = 0x08,
 	BM_MSG_ID_HOTPLUG = 0x09,
+	BM_MSG_ID_FDDATA0 = 0x0a,
+	BM_MSG_ID_FDDATA1 = 0x0b,
 };
 
 /* The struct acc_bmmsg_* structure declarations that follow here provide
@@ -137,7 +159,7 @@ struct acc_bmmsg_rxtxdone {
 		u8 len;
 		u8 txdfifo_idx;
 		u8 zeroes8;
-		u8 reserved;
+		u8 fdf;
 	} acc_dlc;
 	u8 data[CAN_MAX_DLEN];
 	/* Time stamps in struct acc_ov::timestamp_frequency ticks. */
@@ -214,6 +236,17 @@ struct acc_bmmsg_hotplug {
 	u32 reserved2[7];
 };
 
+struct acc_bmmsg_fddata {
+	u8 msg_id;
+	u8 reserved1[1];
+	u8 acc_dlc_len;
+	u8 reserved2[1];
+	union {
+		u8 ui8[ACC_FDD_SLICE_SIZE];
+		u32 ui32[ACC_FDD_SLICE_SIZE / sizeof(u32)];
+	} fdd;
+};
+
 union acc_bmmsg {
 	u8 msg_id;
 	struct acc_bmmsg_rxtxdone rxtxdone;
@@ -223,6 +256,7 @@ union acc_bmmsg {
 	struct acc_bmmsg_errstatechange errstatechange;
 	struct acc_bmmsg_timeslice timeslice;
 	struct acc_bmmsg_hwtimer hwtimer;
+	struct acc_bmmsg_fddata fddata;
 };
 
 /* Check size of union acc_bmmsg to be of expected size. */
@@ -246,6 +280,8 @@ struct acc_core {
 	u8 tx_fifo_size;
 	u8 tx_fifo_head;
 	u8 tx_fifo_tail;
+	u8 reserved;
+	u8 fdd[CANFD_MAX_DLEN - CAN_MAX_DLEN];
 };
 
 struct acc_ov {
@@ -354,5 +390,4 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev);
 int acc_get_berr_counter(const struct net_device *netdev,
 			 struct can_berr_counter *bec);
 int acc_set_mode(struct net_device *netdev, enum can_mode mode);
-int acc_set_bittiming(struct net_device *netdev);
 irqreturn_t acc_card_interrupt(struct acc_ov *ov, struct acc_core *cores);
-- 
2.34.1





[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux