devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements
@ 2025-12-23 10:55 Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy

This patch series updates the GRCAN driver to support the GRCANFD core
from the GRLIB IP core library.

In addition to GRCANFD support, the updates include enhancements for
compatibility with NOEL-V (RISC-V) systems, such as matching drivers
using the 'compatible' identifier and adding support for reading clock
frequency via the common clock framework where available. The series
also includes improvements like functions for configuring
nominal bit-timing and optimizations for DMA operations.

This series also updates the driver documentation and bindings.
The old text binding is converted to YAML, a new vendor prefix
is added to reflect the updated ownership and an entry for the
driver is added to the MAINTAINERS file.

Arun Muthusamy (3):
  dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding
    from txt to YAML
  MAINTAINERS: Add maintainers for GRCAN CAN network driver
  can: grcan: Add CANFD support alongside legacy CAN

Daniel Hellstrom (6):
  can: grcan: Add clock handling
  can: grcan: add FD capability detection and nominal bit-timing
  can: grcan: optimize DMA by 32-bit accesses
  can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit
  can: grcan: Add saving and restoring of CAN FD baud-rate registers
  can: grcan: Reserve space between cap and next register to align with
    address layout

Ludwig Rydberg (1):
  dt-bindings: Add vendor prefix for Frontgrade Gaisler AB

Changes in v2:
- bindings: Updated commit message to explain the removal of freq
  and systemid in the new binding.
- can: S-o-b is placed last in commit messages.
- can: Add values are directly added to the struct can_bittiming_const.
- can: Replaced custom bit shifting with FIELD_PREP and GENMASK for clarity.
- can: Drop do_set_bittiming() callback
- can: Remove forward declarations, unnecessary parentheses, redundant comments
  and unnecessary debug printouts.
- can: Refactored variable declarations to follow the reverse-xmas-tree style.
- can: Adjust line breaks according to new character limits
- can: Eliminating unnecessary defines
- can: Enhance code efficiency with memcpy, use standard API to fetch device specific data and
  error handling.
- Link to v1: https://lore.kernel.org/all/20251118092115.3455-1-arun.muthusamy@gaisler.com

 .../bindings/net/can/gaisler,grcan.yaml       |  62 +++
 .../devicetree/bindings/net/can/grcan.txt     |  28 -
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |   8 +
 drivers/net/can/Kconfig                       |   6 +-
 drivers/net/can/grcan.c                       | 508 +++++++++++++-----
 6 files changed, 437 insertions(+), 177 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
 delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt


base-commit: 4001bda0cc911fcdd3dde36963a17f4eac173d7d
--
2.51.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
@ 2025-12-23 10:55 ` Arun Muthusamy
  2025-12-27 12:31   ` Krzysztof Kozlowski
  2025-12-23 10:55 ` [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML Arun Muthusamy
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Ludwig Rydberg,
	Arun Muthusamy

From: Ludwig Rydberg <ludwig.rydberg@gaisler.com>

Frontgrade Gaisler AB provides IP cores and supporting development tools
for embedded processors based on the SPARC and RISC-V architectures.
Some essential products are the LEON and NOEL synthesizable processor
models together with a complete development environment and a library of
IP cores (GRLIB).

The company specializes in digital hardware design (ASIC/FPGA) for both
commercial and aerospace applications.

Web site: https://www.gaisler.com/

Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 424aa7b911a7..4e1b4eeff9ff 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -594,6 +594,8 @@ patternProperties:
     description: Fujitsu Ltd.
   "^fxtec,.*":
     description: FX Technology Ltd.
+  "^gaisler,.*":
+    description: Frontgrade Gaisler AB
   "^galaxycore,.*":
     description: GalaxyCore Inc.
   "^gameforce,.*":
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
@ 2025-12-23 10:55 ` Arun Muthusamy
  2025-12-24  2:29   ` kernel test robot
  2025-12-30  2:19   ` Rob Herring
  2025-12-23 10:55 ` [PATCH v2 03/10] MAINTAINERS: Add maintainers for GRCAN CAN network driver Arun Muthusamy
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy

Migrate device tree bindings for Gaisler GRCAN, GRHCAN
and GRCANFD CAN controllers from a text format to YAML format.

Additional changes:
  - Remove stale systemid property
    removed in commit 1e93ed26acf0 ("can: grcan: grcan_probe():
    fix broken system id check for errata workaround needs")
  - Make freq optional
  - Add clocks
  - Add compatible
  - Add example

Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 .../bindings/net/can/gaisler,grcan.yaml       | 62 +++++++++++++++++++
 .../devicetree/bindings/net/can/grcan.txt     | 28 ---------
 2 files changed, 62 insertions(+), 28 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
 delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt

diff --git a/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml b/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
new file mode 100644
index 000000000000..8fea97c7319a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/can/gaisler,grcan.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aeroflex Gaisler GRCAN, GRHCAN and GRCANFD CAN controllers.
+
+description: |
+  GRCAN, GRCANFD, GRHCAN controllers are available in the GRLIB VHDL
+  IP core library.
+  For further information look in the documentation for the GRLIB IP library:
+  https://download.gaisler.com/products/GRLIB/doc/grip.pdf
+
+maintainers:
+  - Arun Muthusamy <arun.muthusamy@gaisler.com>
+  - Andreas Larsson <andreas@gaisler.com>
+
+allOf:
+  - $ref: can-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - gaisler,grcan
+      - gaisler,grcanfd
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  freq:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Frequency of the external oscillator clock in Hz (the frequency of the
+      AMBA bus in the ordinary case).
+      This property should be used by systems where the common clock
+      framework is not supported.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    can@ff400000 {
+        compatible = "gaisler,grcanfd";
+        clocks = <&sysclock>;
+        reg = <0xff400000 0x400>;
+        interrupt-parent = <&plic0>;
+        interrupts = <6>;
+    };
diff --git a/Documentation/devicetree/bindings/net/can/grcan.txt b/Documentation/devicetree/bindings/net/can/grcan.txt
deleted file mode 100644
index 34ef3498f887..000000000000
--- a/Documentation/devicetree/bindings/net/can/grcan.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-Aeroflex Gaisler GRCAN and GRHCAN CAN controllers.
-
-The GRCAN and CRHCAN CAN controllers are available in the GRLIB VHDL IP core
-library.
-
-Note: These properties are built from the AMBA plug&play in a Leon SPARC system
-(the ordinary environment for GRCAN and GRHCAN). There are no dts files for
-sparc.
-
-Required properties:
-
-- name : Should be "GAISLER_GRCAN", "01_03d", "GAISLER_GRHCAN" or "01_034"
-
-- reg : Address and length of the register set for the device
-
-- freq : Frequency of the external oscillator clock in Hz (the frequency of
-	the amba bus in the ordinary case)
-
-- interrupts : Interrupt number for this device
-
-Optional properties:
-
-- systemid : If not present or if the value of the least significant 16 bits
-	of this 32-bit property is smaller than GRCAN_TXBUG_SAFE_GRLIB_VERSION
-	a bug workaround is activated.
-
-For further information look in the documentation for the GLIB IP core library:
-http://www.gaisler.com/products/grlib/grip.pdf
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 03/10] MAINTAINERS: Add maintainers for GRCAN CAN network driver
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML Arun Muthusamy
@ 2025-12-23 10:55 ` Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 04/10] can: grcan: Add clock handling Arun Muthusamy
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy

Add Arun Muthusamy and Andreas Larsson as maintainers for
the GRCAN CAN network driver, This entry ensures clear
communication channels for maintaining the Documentation
and driver code associated with GRCAN.

Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0dc4aa37d903..14ddd48e063f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10706,6 +10706,14 @@ F:	drivers/gpio/gpiolib-cdev.c
 F:	include/uapi/linux/gpio.h
 F:	tools/gpio/
 
+GRCAN CAN NETWORK DRIVER
+M:	Andreas Larsson <andreas@gaisler.com>
+M:	Arun Muthusamy <arun.muthusamy@gaisler.com>
+L:	linux-can@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
+F:	drivers/net/can/grcan.c
+
 GRETH 10/100/1G Ethernet MAC device driver
 M:	Andreas Larsson <andreas@gaisler.com>
 L:	netdev@vger.kernel.org
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 04/10] can: grcan: Add clock handling
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (2 preceding siblings ...)
  2025-12-23 10:55 ` [PATCH v2 03/10] MAINTAINERS: Add maintainers for GRCAN CAN network driver Arun Muthusamy
@ 2025-12-23 10:55 ` Arun Muthusamy
  2025-12-23 10:55 ` [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

Add clock handling and add error messages for missing 'freq' DT property.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 3b1b09943436..538a9b4f82ab 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -34,7 +34,7 @@
 #include <linux/spinlock.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
-
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 
 #define DRV_NAME	"grcan"
@@ -1644,6 +1644,7 @@ static int grcan_probe(struct platform_device *ofdev)
 {
 	struct device_node *np = ofdev->dev.of_node;
 	struct device_node *sysid_parent;
+	struct clk *clk;
 	u32 sysid, ambafreq;
 	int irq, err;
 	void __iomem *base;
@@ -1663,8 +1664,20 @@ static int grcan_probe(struct platform_device *ofdev)
 
 	err = of_property_read_u32(np, "freq", &ambafreq);
 	if (err) {
-		dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n");
-		goto exit_error;
+		clk = devm_clk_get(&ofdev->dev, NULL);
+		if (IS_ERR(clk)) {
+			dev_err_probe(&ofdev->dev, PTR_ERR(clk),
+				      "Failed both to get \"freq\" property and clock for fallback\n");
+			err = PTR_ERR(clk);
+			goto exit_error;
+		}
+		if (clk) {
+			ambafreq = clk_get_rate(clk);
+			if (!ambafreq) {
+				dev_err(&ofdev->dev, "Invalid or Uninitialized clock\n");
+				return -EINVAL;
+			}
+		}
 	}
 
 	base = devm_platform_ioremap_resource(ofdev, 0);
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (3 preceding siblings ...)
  2025-12-23 10:55 ` [PATCH v2 04/10] can: grcan: Add clock handling Arun Muthusamy
@ 2025-12-23 10:55 ` Arun Muthusamy
  2025-12-23 20:51   ` Vincent Mailhol
  2025-12-23 10:56 ` [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:55 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

Add capability for the driver to detect CAN FD support
and adjust accordingly. Introduce structures and functions
for setting nominal bit-timing for standard CAN and CAN FD.
The `grcan_hwcap` structure defines hardware capabilities like
CAN FD support and baud-rate options. Additionally, improved
device tree compatibility by updating the `of_device_id` table
for better matching of GRCAN and GRCANFD devices. Also update
Kconfig to mention GRCANFD support.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/Kconfig |   6 +-
 drivers/net/can/grcan.c | 208 ++++++++++++++++++++++++++++------------
 2 files changed, 151 insertions(+), 63 deletions(-)

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index d43d56694667..816b6e71a990 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -133,10 +133,12 @@ config CAN_FLEXCAN
 	  Say Y here if you want to support for Freescale FlexCAN.
 
 config CAN_GRCAN
-	tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
+	tristate "Aeroflex Gaisler GRCAN, GRCANFD and GRHCAN CAN devices"
 	depends on OF && HAS_DMA && HAS_IOMEM
 	help
-	  Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
+	  Say Y here if you want to use Aeroflex Gaisler GRCAN or GRCANFD
+	  or GRHCAN.
+
 	  Note that the driver supports little endian, even though little
 	  endian syntheses of the cores would need some modifications on
 	  the hardware level to work.
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 538a9b4f82ab..cac85fbe6acf 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -33,9 +33,11 @@
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
+#include <linux/bitfield.h>
 
 #define DRV_NAME	"grcan"
 
@@ -50,7 +52,11 @@ struct grcan_registers {
 	u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
 	u32 smask;	/* 0x18 - CanMASK */
 	u32 scode;	/* 0x1c - CanCODE */
-	u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)];
+	u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
+	u32 nbtr;	/* 0x40 */
+	u32 fdbtr;	/* 0x44 */
+	u32 tdelay;	/* 0x48 */
+	u32 __reserved2_[GRCAN_RESERVE_SIZE(0x48, 0x100)];
 	u32 pimsr;	/* 0x100 */
 	u32 pimr;	/* 0x104 */
 	u32 pisr;	/* 0x108 */
@@ -93,16 +99,6 @@ struct grcan_registers {
 	(GRCAN_CONF_BPR | GRCAN_CONF_RSJ | GRCAN_CONF_PS1		\
 	 | GRCAN_CONF_PS2 | GRCAN_CONF_SCALER)
 
-#define GRCAN_CONF_RSJ_MIN	1
-#define GRCAN_CONF_RSJ_MAX	4
-#define GRCAN_CONF_PS1_MIN	1
-#define GRCAN_CONF_PS1_MAX	15
-#define GRCAN_CONF_PS2_MIN	2
-#define GRCAN_CONF_PS2_MAX	8
-#define GRCAN_CONF_SCALER_MIN	0
-#define GRCAN_CONF_SCALER_MAX	255
-#define GRCAN_CONF_SCALER_INC	1
-
 #define GRCAN_CONF_BPR_BIT	8
 #define GRCAN_CONF_RSJ_BIT	12
 #define GRCAN_CONF_PS1_BIT	20
@@ -212,6 +208,39 @@ struct grcan_registers {
 #error "Invalid default buffer size"
 #endif
 
+#define GRCANFD_NBTR_SCALER     GENMASK(23, 16)
+#define GRCANFD_NBTR_PS1        GENMASK(17, 10)
+#define GRCANFD_NBTR_PS2        GENMASK(9, 5)
+#define GRCANFD_NBTR_SJW        GENMASK(4, 0)
+#define GRCANFD_NBTR_TIMING						\
+	(GRCANFD_NBTR_SCALER | GRCANFD_NBTR_PS1 | GRCANFD_NBTR_PS2 |	\
+	 GRCANFD_NBTR_SJW)
+
+#define GRCANFD_FDBTR_SCALER 0x00ff0000
+#define GRCANFD_FDBTR_PS1 0x00003c00
+#define GRCANFD_FDBTR_PS2 0x000001e0
+#define GRCANFD_FDBTR_SJW 0x0000000f
+#define GRCANFD_FDBTR_TIMING						\
+	(GRCANFD_FDBTR_SCALER | GRCANFD_FDBTR_PS1 | GRCANFD_FDBTR_PS2 |	\
+	 GRCANFD_FDBTR_SJW)
+
+#define GRCANFD_FDBTR_SCALER_BIT 16
+#define GRCANFD_FDBTR_PS1_BIT 10
+#define GRCANFD_FDBTR_PS2_BIT 5
+#define GRCANFD_FDBTR_SJW_BIT 0
+
+/* Hardware capabilities */
+struct grcan_hwcap {
+	/* CAN-FD capable, indicates GRCANFD IP.
+	 * The GRCANFD has different baud-rate registers and extended DMA
+	 * format to also describe FD-frames.
+	 */
+	const struct can_bittiming_const *bt_const;
+	int (*set_bittiming)(struct net_device *dev);
+	bool txbug_possible;
+	bool fd;
+};
+
 struct grcan_dma_buffer {
 	size_t size;
 	void *buf;
@@ -254,6 +283,7 @@ struct grcan_priv {
 	struct napi_struct napi;
 
 	struct grcan_registers __iomem *regs;	/* ioremap'ed registers */
+	const struct grcan_hwcap *hwcap;
 	struct grcan_device_config config;
 	struct grcan_dma dma;
 
@@ -304,6 +334,7 @@ struct grcan_priv {
 	 */
 	bool resetting;
 	bool closing;
+
 };
 
 /* Wait time for a short wait for ongoing to clear */
@@ -392,55 +423,79 @@ static struct grcan_device_config grcan_module_config =
 
 static const struct can_bittiming_const grcan_bittiming_const = {
 	.name		= DRV_NAME,
-	.tseg1_min	= GRCAN_CONF_PS1_MIN + 1,
-	.tseg1_max	= GRCAN_CONF_PS1_MAX + 1,
-	.tseg2_min	= GRCAN_CONF_PS2_MIN,
-	.tseg2_max	= GRCAN_CONF_PS2_MAX,
-	.sjw_max	= GRCAN_CONF_RSJ_MAX,
-	.brp_min	= GRCAN_CONF_SCALER_MIN + 1,
-	.brp_max	= GRCAN_CONF_SCALER_MAX + 1,
-	.brp_inc	= GRCAN_CONF_SCALER_INC,
+	.tseg1_min	= 2,
+	.tseg1_max	= 16,
+	.tseg2_min	= 2,
+	.tseg2_max	= 8,
+	.sjw_max	= 4,
+	.brp_min	= 1,
+	.brp_max	= 256,
+	.brp_inc	= 1,
+};
+
+/* GRCANFD nominal boundaries for baud-rate parameters */
+static const struct can_bittiming_const grcanfd_bittiming_const = {
+	.name		= DRV_NAME,
+	.tseg1_min	= 2,
+	.tseg1_max	= 63,
+	.tseg2_min	= 2,
+	.tseg2_max	= 16,
+	.sjw_max	= 16,
+	.brp_min	= 1,
+	.brp_max	= 256,
+	.brp_inc	= 1,
 };
 
 static int grcan_set_bittiming(struct net_device *dev)
 {
 	struct grcan_priv *priv = netdev_priv(dev);
-	struct grcan_registers __iomem *regs = priv->regs;
-	struct can_bittiming *bt = &priv->can.bittiming;
-	u32 timing = 0;
+	struct grcan_registers __iomem *regs;
 	int bpr, rsj, ps1, ps2, scaler;
+	struct can_bittiming *bt;
+	u32 timing = 0;
 
-	/* Should never happen - function will not be called when
-	 * device is up
-	 */
-	if (grcan_read_bits(&regs->ctrl, GRCAN_CTRL_ENABLE))
-		return -EBUSY;
+	regs = priv->regs;
+	bt = &priv->can.bittiming;
 
 	bpr = 0; /* Note bpr and brp are different concepts */
 	rsj = bt->sjw;
 	ps1 = (bt->prop_seg + bt->phase_seg1) - 1; /* tseg1 - 1 */
 	ps2 = bt->phase_seg2;
-	scaler = (bt->brp - 1);
-	netdev_dbg(dev, "Request for BPR=%d, RSJ=%d, PS1=%d, PS2=%d, SCALER=%d",
-		   bpr, rsj, ps1, ps2, scaler);
-	if (!(ps1 > ps2)) {
-		netdev_err(dev, "PS1 > PS2 must hold: PS1=%d, PS2=%d\n",
-			   ps1, ps2);
-		return -EINVAL;
-	}
-	if (!(ps2 >= rsj)) {
-		netdev_err(dev, "PS2 >= RSJ must hold: PS2=%d, RSJ=%d\n",
-			   ps2, rsj);
-		return -EINVAL;
-	}
+	scaler = bt->brp - 1;
+
+	timing |= FIELD_PREP(GRCAN_CONF_BPR, bpr);
+	timing |= FIELD_PREP(GRCAN_CONF_RSJ, rsj);
+	timing |= FIELD_PREP(GRCAN_CONF_PS1, ps1);
+	timing |= FIELD_PREP(GRCAN_CONF_PS2, ps2);
+	timing |= FIELD_PREP(GRCAN_CONF_SCALER, scaler);
+	netdev_dbg(dev, "setting timing=0x%x\n", timing);
+	grcan_write_bits(&regs->conf, timing, GRCAN_CONF_TIMING);
+
+	return 0;
+}
+
+static int grcanfd_set_bittiming(struct net_device *dev)
+{
+	struct grcan_priv *priv = netdev_priv(dev);
+	struct grcan_registers __iomem *regs;
+	int sjw, ps1, ps2, scaler;
+	struct can_bittiming *bt;
+	u32 timing = 0;
+
+	regs = priv->regs;
+	bt = &priv->can.bittiming;
+
+	sjw = bt->sjw;
+	ps1 = (bt->prop_seg + bt->phase_seg1);
+	ps2 = bt->phase_seg2;
+	scaler = bt->brp - 1;
 
-	timing |= (bpr << GRCAN_CONF_BPR_BIT) & GRCAN_CONF_BPR;
-	timing |= (rsj << GRCAN_CONF_RSJ_BIT) & GRCAN_CONF_RSJ;
-	timing |= (ps1 << GRCAN_CONF_PS1_BIT) & GRCAN_CONF_PS1;
-	timing |= (ps2 << GRCAN_CONF_PS2_BIT) & GRCAN_CONF_PS2;
-	timing |= (scaler << GRCAN_CONF_SCALER_BIT) & GRCAN_CONF_SCALER;
+	timing |= FIELD_PREP(GRCANFD_NBTR_SJW, sjw);
+	timing |= FIELD_PREP(GRCANFD_NBTR_PS1, ps1);
+	timing |= FIELD_PREP(GRCANFD_NBTR_PS2, ps2);
+	timing |= FIELD_PREP(GRCANFD_NBTR_SCALER, scaler);
 	netdev_info(dev, "setting timing=0x%x\n", timing);
-	grcan_write_bits(&regs->conf, timing, GRCAN_CONF_TIMING);
+	grcan_write_bits(&regs->nbtr, timing, GRCANFD_NBTR_TIMING);
 
 	return 0;
 }
@@ -1569,7 +1624,8 @@ static const struct ethtool_ops grcan_ethtool_ops = {
 
 static int grcan_setup_netdev(struct platform_device *ofdev,
 			      void __iomem *base,
-			      int irq, u32 ambafreq, bool txbug)
+			      int irq, u32 ambafreq, bool txbug,
+			      const struct grcan_hwcap *hwcap)
 {
 	struct net_device *dev;
 	struct grcan_priv *priv;
@@ -1592,14 +1648,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
 	priv->dev = dev;
 	priv->ofdev_dev = &ofdev->dev;
 	priv->regs = base;
-	priv->can.bittiming_const = &grcan_bittiming_const;
-	priv->can.do_set_bittiming = grcan_set_bittiming;
+	priv->can.bittiming_const = hwcap->bt_const;
 	priv->can.do_set_mode = grcan_set_mode;
 	priv->can.do_get_berr_counter = grcan_get_berr_counter;
 	priv->can.clock.freq = ambafreq;
 	priv->can.ctrlmode_supported =
 		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
 	priv->need_txbug_workaround = txbug;
+	priv->hwcap = hwcap;
 
 	/* Discover if triple sampling is supported by hardware */
 	regs = priv->regs;
@@ -1644,22 +1700,33 @@ static int grcan_probe(struct platform_device *ofdev)
 {
 	struct device_node *np = ofdev->dev.of_node;
 	struct device_node *sysid_parent;
+	const struct grcan_hwcap *hwcap;
 	struct clk *clk;
 	u32 sysid, ambafreq;
 	int irq, err;
 	void __iomem *base;
 	bool txbug = true;
 
+	hwcap = device_get_match_data(&ofdev->dev);
+	if (!hwcap) {
+		dev_err(&ofdev->dev, "Platform data not provided!\n");
+		return -ENODEV;
+	}
+
 	/* Compare GRLIB version number with the first that does not
 	 * have the tx bug (see start_xmit)
 	 */
-	sysid_parent = of_find_node_by_path("/ambapp0");
-	if (sysid_parent) {
-		err = of_property_read_u32(sysid_parent, "systemid", &sysid);
-		if (!err && ((sysid & GRLIB_VERSION_MASK) >=
-			     GRCAN_TXBUG_SAFE_GRLIB_VERSION))
-			txbug = false;
-		of_node_put(sysid_parent);
+	if (!hwcap->txbug_possible) {
+		txbug = false;
+	} else {
+		sysid_parent = of_find_node_by_path("/ambapp0");
+		if (sysid_parent) {
+			err = of_property_read_u32(sysid_parent, "systemid", &sysid);
+			if (!err && ((sysid & GRLIB_VERSION_MASK) >=
+				     GRCAN_TXBUG_SAFE_GRLIB_VERSION))
+				txbug = false;
+			of_node_put(sysid_parent);
+		}
 	}
 
 	err = of_property_read_u32(np, "freq", &ambafreq);
@@ -1695,7 +1762,7 @@ static int grcan_probe(struct platform_device *ofdev)
 
 	grcan_sanitize_module_config(ofdev);
 
-	err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug);
+	err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug, hwcap);
 	if (err)
 		goto exit_dispose_irq;
 
@@ -1722,11 +1789,30 @@ static void grcan_remove(struct platform_device *ofdev)
 	free_candev(dev);
 }
 
+static const struct grcan_hwcap grcan_hwcap = {
+	.fd = false,
+	.txbug_possible = true,
+	.bt_const = &grcan_bittiming_const,
+	.set_bittiming = grcan_set_bittiming,
+};
+
+static const struct grcan_hwcap grcanfd_hwcap = {
+	.fd = true,
+	.txbug_possible = false,
+	.bt_const = &grcanfd_bittiming_const,
+	.set_bittiming = grcanfd_set_bittiming,
+};
+
 static const struct of_device_id grcan_match[] = {
-	{.name = "GAISLER_GRCAN"},
-	{.name = "01_03d"},
-	{.name = "GAISLER_GRHCAN"},
-	{.name = "01_034"},
+	{.name = "GAISLER_GRCAN", .data = &grcan_hwcap},
+	{.name = "01_03d", .data = &grcan_hwcap},
+	{.name = "GAISLER_GRHCAN", .data = &grcan_hwcap},
+	{.name = "01_034", .data = &grcan_hwcap},
+	{.compatible = "gaisler,grcan", .data = &grcan_hwcap},
+	/* GRCANFD */
+	{.compatible = "gaisler,grcanfd", .data = &grcanfd_hwcap},
+	{.name = "GAISLER_GRCANFD", .data = &grcanfd_hwcap},
+	{.name = "01_0B5", .data = &grcanfd_hwcap},
 	{},
 };
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (4 preceding siblings ...)
  2025-12-23 10:55 ` [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
@ 2025-12-23 10:56 ` Arun Muthusamy
  2025-12-23 20:40   ` Vincent Mailhol
  2025-12-23 10:56 ` [PATCH v2 07/10] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit Arun Muthusamy
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:56 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

Optimizes DMA transfers in the GRCAN driver by reorganizing
data handling to use 32-bit accesses instead of individual
byte accesses.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index cac85fbe6acf..8a6c59473cf4 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1218,7 +1218,7 @@ static int grcan_receive(struct net_device *dev, int budget)
 	struct sk_buff *skb;
 	u32 wr, rd, startrd;
 	u32 *slot;
-	u32 i, rtr, eff, j, shift;
+	u32 rtr, eff;
 	int work_done = 0;
 
 	rd = grcan_read_reg(&regs->rxrd);
@@ -1254,10 +1254,10 @@ static int grcan_receive(struct net_device *dev, int budget)
 		if (rtr) {
 			cf->can_id |= CAN_RTR_FLAG;
 		} else {
-			for (i = 0; i < cf->len; i++) {
-				j = GRCAN_MSG_DATA_SLOT_INDEX(i);
-				shift = GRCAN_MSG_DATA_SHIFT(i);
-				cf->data[i] = (u8)(slot[j] >> shift);
+			if (cf->can_dlc > 0) {
+				memcpy(cf->data, &slot[2], sizeof(u32));
+				if (cf->can_dlc > 4)
+					memcpy(cf->data + 4, &slot[3], sizeof(u32));
 			}
 
 			stats->rx_bytes += cf->len;
@@ -1397,8 +1397,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 	u32 id, txwr, txrd, space, txctrl;
 	int slotindex;
 	u32 *slot;
-	u32 i, rtr, eff, dlc, tmp, err;
-	int j, shift;
+	u32 rtr, eff, dlc, tmp, err;
 	unsigned long flags;
 	u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
 
@@ -1451,10 +1450,11 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 	slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
 	slot[2] = 0;
 	slot[3] = 0;
-	for (i = 0; i < dlc; i++) {
-		j = GRCAN_MSG_DATA_SLOT_INDEX(i);
-		shift = GRCAN_MSG_DATA_SHIFT(i);
-		slot[j] |= cf->data[i] << shift;
+	if (dlc > 0) {
+		memcpy(&slot[2], cf->data, sizeof(u32));
+		slot[2] = *(u32 *)(cf->data);
+		if (dlc > 4)
+			memcpy(&slot[3], cf->data + 4, sizeof(u32));
 	}
 
 	/* Checking that channel has not been disabled. These cases
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 07/10] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (5 preceding siblings ...)
  2025-12-23 10:56 ` [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
@ 2025-12-23 10:56 ` Arun Muthusamy
  2025-12-23 10:56 ` [PATCH v2 08/10] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:56 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

Sets the DMA mask for GRCAN and GRCANFD devices to 32-bit.
Setting the DMA mask and coherent DMA mask to 32-bit ensures proper
memory addressing during DMA operations

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 8a6c59473cf4..cdb9498cf783 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1753,6 +1753,13 @@ static int grcan_probe(struct platform_device *ofdev)
 		goto exit_error;
 	}
 
+	/* On 64-bit systems.. GRCAN and GRCANFD can only address 32-bit */
+	err = dma_set_mask_and_coherent(&ofdev->dev, DMA_BIT_MASK(32));
+	if (err) {
+		dev_err_probe(&ofdev->dev, err, "No usable DMA configuration.\n");
+		goto exit_error;
+	}
+
 	irq = irq_of_parse_and_map(np, GRCAN_IRQIX_IRQ);
 	if (!irq) {
 		dev_err(&ofdev->dev, "no irq found\n");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 08/10] can: grcan: Add saving and restoring of CAN FD baud-rate registers
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (6 preceding siblings ...)
  2025-12-23 10:56 ` [PATCH v2 07/10] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit Arun Muthusamy
@ 2025-12-23 10:56 ` Arun Muthusamy
  2025-12-23 10:56 ` [PATCH v2 09/10] can: grcan: Reserve space between cap and next register to align with address layout Arun Muthusamy
  2025-12-23 10:56 ` [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN Arun Muthusamy
  9 siblings, 0 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:56 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

While reset the GRCAN baud-rates are preserved, since GRCANFD has the
baud-rate in different registers we need to add saving of those
registers too.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index cdb9498cf783..dc14b3145e73 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -520,15 +520,27 @@ static void grcan_reset(struct net_device *dev)
 	struct grcan_priv *priv = netdev_priv(dev);
 	struct grcan_registers __iomem *regs = priv->regs;
 	u32 config = grcan_read_reg(&regs->conf);
+	u32 nbtr, fdbtr;
+
+	if (priv->hwcap->fd) {
+		nbtr = grcan_read_reg(&regs->nbtr);
+		fdbtr = grcan_read_reg(&regs->fdbtr);
+	}
 
 	grcan_set_bits(&regs->ctrl, GRCAN_CTRL_RESET);
 	grcan_write_reg(&regs->conf, config);
+	if (priv->hwcap->fd) {
+		grcan_write_reg(&regs->nbtr, nbtr);
+		grcan_write_reg(&regs->fdbtr, fdbtr);
+	}
 
 	priv->eskbp = grcan_read_reg(&regs->txrd);
 	priv->can.state = CAN_STATE_STOPPED;
 
 	/* Turn off hardware filtering - regs->rxcode set to 0 by reset */
 	grcan_write_reg(&regs->rxmask, 0);
+
+	priv->hwcap->set_bittiming(dev);
 }
 
 /* stop device without changing any configurations */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 09/10] can: grcan: Reserve space between cap and next register to align with address layout
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (7 preceding siblings ...)
  2025-12-23 10:56 ` [PATCH v2 08/10] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
@ 2025-12-23 10:56 ` Arun Muthusamy
  2025-12-23 10:56 ` [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN Arun Muthusamy
  9 siblings, 0 replies; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:56 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
	Arun Muthusamy

From: Daniel Hellstrom <daniel@gaisler.com>

Reserves space between the capability register and the next register
within the GRCAN driver to align with the hardware address layout.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index dc14b3145e73..bf1c503d575d 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -49,7 +49,8 @@ struct grcan_registers {
 	u32 conf;	/* 0x00 */
 	u32 stat;	/* 0x04 */
 	u32 ctrl;	/* 0x08 */
-	u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
+	u32 cap;	/* 0x0c */
+	u32 __reserved1[GRCAN_RESERVE_SIZE(0x0c, 0x18)];
 	u32 smask;	/* 0x18 - CanMASK */
 	u32 scode;	/* 0x1c - CanCODE */
 	u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN
  2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
                   ` (8 preceding siblings ...)
  2025-12-23 10:56 ` [PATCH v2 09/10] can: grcan: Reserve space between cap and next register to align with address layout Arun Muthusamy
@ 2025-12-23 10:56 ` Arun Muthusamy
  2025-12-23 21:09   ` Vincent Mailhol
  9 siblings, 1 reply; 17+ messages in thread
From: Arun Muthusamy @ 2025-12-23 10:56 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy

Include CANFD support with the legacy CAN support, enabling
support for extended data payloads up to 64 bytes, higher bit rates,
handle canecho frames.

Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
 drivers/net/can/grcan.c | 259 +++++++++++++++++++++++++++-------------
 1 file changed, 177 insertions(+), 82 deletions(-)

diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index bf1c503d575d..3d5b4c7e58bc 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -174,6 +174,7 @@ struct grcan_registers {
 #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
 
 #define GRCAN_MSG_SIZE		16
+#define GRCAN_CLASSIC_DATA_SIZE 8
 
 #define GRCAN_MSG_IDE		0x80000000
 #define GRCAN_MSG_RTR		0x40000000
@@ -230,6 +231,12 @@ struct grcan_registers {
 #define GRCANFD_FDBTR_PS2_BIT 5
 #define GRCANFD_FDBTR_SJW_BIT 0
 
+#define GRCAN_TX_BRS  BIT(25)
+#define GRCAN_TX_FDF  BIT(26)
+
+#define GRCAN_RX_BRS  BIT(25)
+#define GRCAN_RX_FDF  BIT(26)
+
 /* Hardware capabilities */
 struct grcan_hwcap {
 	/* CAN-FD capable, indicates GRCANFD IP.
@@ -290,6 +297,13 @@ struct grcan_priv {
 
 	struct sk_buff **echo_skb;	/* We allocate this on our own */
 
+	/*
+	 * Since the CAN FD frame has a variable length, this variable is used
+	 * to keep track of the index of the CAN echo skb (socket buffer) frame.
+	 * It's important for ensuring that we correctly manage the echo skb.
+	 */
+	u32 echo_skb_idx;
+
 	/* The echo skb pointer, pointing into echo_skb and indicating which
 	 * frames can be echoed back. See the "Notes on the tx cyclic buffer
 	 * handling"-comment for grcan_start_xmit for more details.
@@ -570,7 +584,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
 	struct grcan_registers __iomem *regs = priv->regs;
 	struct grcan_dma *dma = &priv->dma;
 	struct net_device_stats *stats = &dev->stats;
-	int i, work_done;
+	int work_done;
 
 	/* Updates to priv->eskbp and wake-ups of the queue needs to
 	 * be atomic towards the reads of priv->eskbp and shut-downs
@@ -581,19 +595,22 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
 	for (work_done = 0; work_done < budget || budget < 0; work_done++) {
 		if (priv->eskbp == txrd)
 			break;
-		i = priv->eskbp / GRCAN_MSG_SIZE;
-		if (echo) {
-			/* Normal echo of messages */
-			stats->tx_packets++;
-			stats->tx_bytes += can_get_echo_skb(dev, i, NULL);
-		} else {
-			/* For cleanup of untransmitted messages */
-			can_free_echo_skb(dev, i, NULL);
-		}
 
 		priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
 					     dma->tx.size);
 		txrd = grcan_read_reg(&regs->txrd);
+
+		/* Grab the packet once the  packet is send or free untransmitted packet*/
+		if (priv->eskbp == txrd) {
+			if (echo) {
+				/* Normal echo of messages */
+				stats->tx_packets++;
+				stats->tx_bytes += can_get_echo_skb(dev, priv->echo_skb_idx, NULL);
+			} else {
+				/* For cleanup of untransmitted messages */
+				can_free_echo_skb(dev, priv->echo_skb_idx, NULL);
+			}
+		}
 	}
 	return work_done;
 }
@@ -676,10 +693,8 @@ static void grcan_err(struct net_device *dev, u32 sources, u32 status)
 	    (status & GRCAN_STAT_ERRCTR_RELATED)) {
 		enum can_state state = priv->can.state;
 		enum can_state oldstate = state;
-		u32 txerr = (status & GRCAN_STAT_TXERRCNT)
-			>> GRCAN_STAT_TXERRCNT_BIT;
-		u32 rxerr = (status & GRCAN_STAT_RXERRCNT)
-			>> GRCAN_STAT_RXERRCNT_BIT;
+		u32 txerr = (status & GRCAN_STAT_TXERRCNT) >> GRCAN_STAT_TXERRCNT_BIT;
+		u32 rxerr = (status & GRCAN_STAT_RXERRCNT) >> GRCAN_STAT_RXERRCNT_BIT;
 
 		/* Figure out current state */
 		if (status & GRCAN_STAT_OFF) {
@@ -1101,6 +1116,7 @@ static int grcan_set_mode(struct net_device *dev, enum can_mode mode)
 			if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
 				netif_wake_queue(dev);
 		}
+		priv->echo_skb_idx = 0;
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return err;
 	}
@@ -1150,7 +1166,6 @@ static int grcan_open(struct net_device *dev)
 		netif_start_queue(dev);
 	priv->resetting = false;
 	priv->closing = false;
-
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -1221,20 +1236,31 @@ static void grcan_transmit_catch_up(struct net_device *dev)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+static int grcan_numbds(int len)
+{
+	if (len <= GRCAN_CLASSIC_DATA_SIZE)
+		return 1;
+	return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
+}
+
 static int grcan_receive(struct net_device *dev, int budget)
 {
+	struct net_device_stats *stats = &dev->stats;
 	struct grcan_priv *priv = netdev_priv(dev);
-	struct grcan_registers __iomem *regs = priv->regs;
+	struct grcan_registers __iomem *regs;
 	struct grcan_dma *dma = &priv->dma;
-	struct net_device_stats *stats = &dev->stats;
-	struct can_frame *cf;
+	u32 bds, copy_len, payload_offset;
+	u32 wr, rd, dlc, startrd;
+	struct canfd_frame *cf;
+	int i, work_done = 0;
 	struct sk_buff *skb;
-	u32 wr, rd, startrd;
-	u32 *slot;
 	u32 rtr, eff;
-	int work_done = 0;
+	u32 *slot;
+	u8 *data;
 
+	regs = priv->regs;
 	rd = grcan_read_reg(&regs->rxrd);
+
 	startrd = rd;
 	for (work_done = 0; work_done < budget; work_done++) {
 		/* Check for packet to receive */
@@ -1242,44 +1268,70 @@ static int grcan_receive(struct net_device *dev, int budget)
 		if (rd == wr)
 			break;
 
-		/* Take care of packet */
-		skb = alloc_can_skb(dev, &cf);
-		if (skb == NULL) {
+		slot = dma->rx.buf + rd;
+
+		if (slot[1] & GRCAN_RX_FDF)
+			skb = alloc_canfd_skb(dev, &cf);
+		else
+			skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf);
+
+		if (unlikely(!skb)) {
 			netdev_err(dev,
 				   "dropping frame: skb allocation failed\n");
 			stats->rx_dropped++;
 			continue;
 		}
 
-		slot = dma->rx.buf + rd;
-		eff = slot[0] & GRCAN_MSG_IDE;
-		rtr = slot[0] & GRCAN_MSG_RTR;
-		if (eff) {
-			cf->can_id = ((slot[0] & GRCAN_MSG_EID)
-				      >> GRCAN_MSG_EID_BIT);
-			cf->can_id |= CAN_EFF_FLAG;
-		} else {
-			cf->can_id = ((slot[0] & GRCAN_MSG_BID)
-				      >> GRCAN_MSG_BID_BIT);
-		}
-		cf->len = can_cc_dlc2len((slot[1] & GRCAN_MSG_DLC)
-					  >> GRCAN_MSG_DLC_BIT);
-		if (rtr) {
-			cf->can_id |= CAN_RTR_FLAG;
-		} else {
-			if (cf->can_dlc > 0) {
-				memcpy(cf->data, &slot[2], sizeof(u32));
-				if (cf->can_dlc > 4)
-					memcpy(cf->data + 4, &slot[3], sizeof(u32));
+		dlc = (slot[1] & GRCAN_MSG_DLC) >> GRCAN_MSG_DLC_BIT;
+		if (slot[1] & GRCAN_RX_FDF)
+			cf->len = can_fd_dlc2len(dlc);
+		else
+			cf->len = can_cc_dlc2len(dlc);
+
+		bds = grcan_numbds(cf->len);
+		payload_offset = 0;
+		data = cf->data;
+
+		for (i = 0; i < bds; i++) {
+			slot = dma->rx.buf + rd;
+
+			if (i == 0) {
+				eff = slot[0] & GRCAN_MSG_IDE;
+				rtr = slot[0] & GRCAN_MSG_RTR;
+				if (eff) {
+					cf->can_id = ((slot[0] & GRCAN_MSG_EID)
+						>> GRCAN_MSG_EID_BIT);
+					cf->can_id |= CAN_EFF_FLAG;
+				} else {
+					cf->can_id = ((slot[0] & GRCAN_MSG_BID)
+						>> GRCAN_MSG_BID_BIT);
+				}
+				if (rtr)
+					cf->can_id |= CAN_RTR_FLAG;
+
+				dlc = (slot[1] & GRCAN_MSG_DLC) >> GRCAN_MSG_DLC_BIT;
+				if (slot[1] & GRCAN_RX_FDF)
+					cf->len = can_fd_dlc2len(dlc);
+				else
+					cf->len = can_cc_dlc2len(dlc);
+
+				copy_len = min(cf->len, GRCAN_CLASSIC_DATA_SIZE);
+				memcpy(data, &slot[2], copy_len);
+				payload_offset += copy_len;
+			} else {
+				copy_len =  min(cf->len - payload_offset, GRCAN_MSG_SIZE);
+				memcpy(data + payload_offset, slot, copy_len);
+				payload_offset += copy_len;
 			}
-
-			stats->rx_bytes += cf->len;
+			rd += GRCAN_MSG_SIZE;
+			if (rd >= dma->tx.size)
+				rd -= dma->tx.size;
 		}
-		stats->rx_packets++;
 
+		/* Update statistics and read pointer */
+		stats->rx_packets++;
+		stats->rx_bytes += cf->len;
 		netif_receive_skb(skb);
-
-		rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
 	}
 
 	/* Make sure everything is read before allowing hardware to
@@ -1404,15 +1456,22 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 				    struct net_device *dev)
 {
 	struct grcan_priv *priv = netdev_priv(dev);
-	struct grcan_registers __iomem *regs = priv->regs;
+	struct grcan_registers __iomem *regs;
+	u32 eff, rtr, dlc, tmp, err, can_id;
 	struct grcan_dma *dma = &priv->dma;
-	struct can_frame *cf = (struct can_frame *)skb->data;
+	u32 bds, copy_len, payload_offset;
 	u32 id, txwr, txrd, space, txctrl;
-	int slotindex;
-	u32 *slot;
-	u32 rtr, eff, dlc, tmp, err;
+	struct canfd_frame *cfd;
+	struct can_frame *cf;
 	unsigned long flags;
-	u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
+	u32 oneshotmode;
+	u8 *payload;
+	u32 *slot;
+	u8 len;
+	int i;
+
+	regs = priv->regs;
+	oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
 
 	if (can_dev_dropped_skb(dev, skb))
 		return NETDEV_TX_OK;
@@ -1423,6 +1482,20 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
 		return NETDEV_TX_BUSY;
 
+	if (can_is_canfd_skb(skb)) {
+		cfd = (struct canfd_frame *)skb->data;
+		len = cfd->len;
+		dlc = can_fd_len2dlc(cfd->len);
+		can_id = cfd->can_id;
+		payload = cfd->data;
+	} else {
+		cf = (struct can_frame *)skb->data;
+		len = cf->len;
+		dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
+		can_id = cf->can_id;
+		payload = cf->data;
+	}
+
 	/* Reads of priv->eskbp and shut-downs of the queue needs to
 	 * be atomic towards the updates to priv->eskbp and wake-ups
 	 * of the queue in the interrupt handler.
@@ -1431,9 +1504,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 
 	txwr = grcan_read_reg(&regs->txwr);
 	space = grcan_txspace(dma->tx.size, txwr, priv->eskbp);
-
-	slotindex = txwr / GRCAN_MSG_SIZE;
-	slot = dma->tx.buf + txwr;
+	bds = grcan_numbds(len);
 
 	if (unlikely(space == 1))
 		netif_stop_queue(dev);
@@ -1449,25 +1520,38 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 		return NETDEV_TX_BUSY;
 	}
 
-	/* Convert and write CAN message to DMA buffer */
-	eff = cf->can_id & CAN_EFF_FLAG;
-	rtr = cf->can_id & CAN_RTR_FLAG;
-	id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
-	dlc = cf->len;
-	if (eff)
-		tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
-	else
-		tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
-	slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
-
-	slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
-	slot[2] = 0;
-	slot[3] = 0;
-	if (dlc > 0) {
-		memcpy(&slot[2], cf->data, sizeof(u32));
-		slot[2] = *(u32 *)(cf->data);
-		if (dlc > 4)
-			memcpy(&slot[3], cf->data + 4, sizeof(u32));
+	payload_offset = 0;
+	for (i = 0; i < bds; i++) {
+		slot = dma->tx.buf + txwr;
+		memset(slot, 0, GRCAN_MSG_SIZE);
+
+		if (i == 0) {
+			eff = can_id & CAN_EFF_FLAG;
+			rtr = can_id & CAN_RTR_FLAG;
+			id = can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
+			if (eff)
+				tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
+			else
+				tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
+			slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
+			slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
+			if (can_is_canfd_skb(skb)) {
+				slot[1] |= GRCAN_TX_FDF;
+				if (cfd->flags & CANFD_BRS)
+					slot[1] |= GRCAN_TX_BRS;
+			}
+
+			copy_len = min(len, 8);
+			memcpy(&slot[2], payload, copy_len);
+			payload_offset += copy_len;
+		} else {
+			copy_len =  min(len - payload_offset, GRCAN_MSG_SIZE);
+			memcpy(slot, payload + payload_offset, copy_len);
+			payload_offset += copy_len;
+		}
+		txwr += GRCAN_MSG_SIZE;
+		if (txwr >= dma->tx.size)
+			txwr -= dma->tx.size;
 	}
 
 	/* Checking that channel has not been disabled. These cases
@@ -1502,7 +1586,14 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 	 * can_put_echo_skb would be an error unless other measures are
 	 * taken.
 	 */
-	can_put_echo_skb(skb, dev, slotindex, 0);
+
+	can_put_echo_skb(skb, dev, priv->echo_skb_idx, 0);
+
+	/* Move to the next index in the echo skb buffer */
+	priv->echo_skb_idx = (priv->echo_skb_idx + 1) % priv->can.echo_skb_max;
+
+	if (priv->can.echo_skb[priv->echo_skb_idx])
+		netif_stop_queue(dev);
 
 	/* Make sure everything is written before allowing hardware to
 	 * read from the memory
@@ -1510,8 +1601,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
 	wmb();
 
 	/* Update write pointer to start transmission */
-	grcan_write_reg(&regs->txwr,
-			grcan_ring_add(txwr, GRCAN_MSG_SIZE, dma->tx.size));
+	grcan_write_reg(&regs->txwr, txwr);
 
 	return NETDEV_TX_OK;
 }
@@ -1662,11 +1752,16 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
 	priv->ofdev_dev = &ofdev->dev;
 	priv->regs = base;
 	priv->can.bittiming_const = hwcap->bt_const;
+	priv->can.fd.data_bittiming_const = hwcap->bt_const;
 	priv->can.do_set_mode = grcan_set_mode;
 	priv->can.do_get_berr_counter = grcan_get_berr_counter;
 	priv->can.clock.freq = ambafreq;
-	priv->can.ctrlmode_supported =
-		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
+	if (hwcap->fd)
+		priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_FD;
+	else
+		priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			CAN_CTRLMODE_ONE_SHOT;
 	priv->need_txbug_workaround = txbug;
 	priv->hwcap = hwcap;
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses
  2025-12-23 10:56 ` [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
@ 2025-12-23 20:40   ` Vincent Mailhol
  0 siblings, 0 replies; 17+ messages in thread
From: Vincent Mailhol @ 2025-12-23 20:40 UTC (permalink / raw)
  To: Arun Muthusamy, robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom

On 23/12/2025 at 11:56, Arun Muthusamy wrote:
> From: Daniel Hellstrom <daniel@gaisler.com>
> 
> Optimizes DMA transfers in the GRCAN driver by reorganizing
> data handling to use 32-bit accesses instead of individual
> byte accesses.
> 
> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
>  drivers/net/can/grcan.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index cac85fbe6acf..8a6c59473cf4 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -1218,7 +1218,7 @@ static int grcan_receive(struct net_device *dev, int budget)
>  	struct sk_buff *skb;
>  	u32 wr, rd, startrd;
>  	u32 *slot;
> -	u32 i, rtr, eff, j, shift;
> +	u32 rtr, eff;
>  	int work_done = 0;
>  
>  	rd = grcan_read_reg(&regs->rxrd);
> @@ -1254,10 +1254,10 @@ static int grcan_receive(struct net_device *dev, int budget)
>  		if (rtr) {
>  			cf->can_id |= CAN_RTR_FLAG;
>  		} else {
> -			for (i = 0; i < cf->len; i++) {
> -				j = GRCAN_MSG_DATA_SLOT_INDEX(i);
> -				shift = GRCAN_MSG_DATA_SHIFT(i);
> -				cf->data[i] = (u8)(slot[j] >> shift);
> +			if (cf->can_dlc > 0) {
> +				memcpy(cf->data, &slot[2], sizeof(u32));
> +				if (cf->can_dlc > 4)
> +					memcpy(cf->data + 4, &slot[3], sizeof(u32));
>  			}

Nitpick: you may instead do:

	if (cf->can_dlc > 0)
		memcpy(cf->data, &slot[2], sizeof(u32));
	if (cf->can_dlc > 4)
		memcpy(cf->data + 4, &slot[3], sizeof(u32));

and let the compiler take care of the optimization for you ;)

>  
>  			stats->rx_bytes += cf->len;
> @@ -1397,8 +1397,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  	u32 id, txwr, txrd, space, txctrl;
>  	int slotindex;
>  	u32 *slot;
> -	u32 i, rtr, eff, dlc, tmp, err;
> -	int j, shift;
> +	u32 rtr, eff, dlc, tmp, err;
>  	unsigned long flags;
>  	u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
>  
> @@ -1451,10 +1450,11 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  	slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
>  	slot[2] = 0;
>  	slot[3] = 0;
> -	for (i = 0; i < dlc; i++) {
> -		j = GRCAN_MSG_DATA_SLOT_INDEX(i);
> -		shift = GRCAN_MSG_DATA_SHIFT(i);
> -		slot[j] |= cf->data[i] << shift;
> +	if (dlc > 0) {
> +		memcpy(&slot[2], cf->data, sizeof(u32));
> +		slot[2] = *(u32 *)(cf->data);

Why do you have both the memcpy() and the "slot[2] =" assignment?

> +		if (dlc > 4)
> +			memcpy(&slot[3], cf->data + 4, sizeof(u32));
>  	}
>  
>  	/* Checking that channel has not been disabled. These cases

Don't forget also to remove the unused macros.


Yours sincerely,
Vincent Mailhol


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing
  2025-12-23 10:55 ` [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
@ 2025-12-23 20:51   ` Vincent Mailhol
  0 siblings, 0 replies; 17+ messages in thread
From: Vincent Mailhol @ 2025-12-23 20:51 UTC (permalink / raw)
  To: Arun Muthusamy, robh, krzk+dt, conor+dt, mkl
  Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom

On 23/12/2025 at 11:55, Arun Muthusamy wrote:
> From: Daniel Hellstrom <daniel@gaisler.com>
> 
> Add capability for the driver to detect CAN FD support
> and adjust accordingly. Introduce structures and functions
> for setting nominal bit-timing for standard CAN and CAN FD.
> The `grcan_hwcap` structure defines hardware capabilities like
> CAN FD support and baud-rate options. Additionally, improved
> device tree compatibility by updating the `of_device_id` table
> for better matching of GRCAN and GRCANFD devices. Also update
> Kconfig to mention GRCANFD support.

Your patch is doing a lot of things. Can you split it in smaller
changes? More specifically try to not mix together the refactors
with the introduction of new code.

> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
>  drivers/net/can/Kconfig |   6 +-
>  drivers/net/can/grcan.c | 208 ++++++++++++++++++++++++++++------------
>  2 files changed, 151 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index d43d56694667..816b6e71a990 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -133,10 +133,12 @@ config CAN_FLEXCAN
>  	  Say Y here if you want to support for Freescale FlexCAN.
>  
>  config CAN_GRCAN
> -	tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
> +	tristate "Aeroflex Gaisler GRCAN, GRCANFD and GRHCAN CAN devices"

Nitpick: try a more compact approach:

  tristate "Aeroflex Gaisler GRCAN(FD) and GRHCAN devices"

>  	depends on OF && HAS_DMA && HAS_IOMEM
>  	help
> -	  Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
> +	  Say Y here if you want to use Aeroflex Gaisler GRCAN or GRCANFD
> +	  or GRHCAN.
> +

OK to be more verbose here ;)

>  	  Note that the driver supports little endian, even though little
>  	  endian syntheses of the cores would need some modifications on
>  	  the hardware level to work.
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index 538a9b4f82ab..cac85fbe6acf 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -33,9 +33,11 @@
>  #include <linux/platform_device.h>
>  #include <linux/spinlock.h>
>  #include <linux/of.h>
> +#include <linux/of_device.h>
>  #include <linux/of_irq.h>
>  #include <linux/clk.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/bitfield.h>
>  
>  #define DRV_NAME	"grcan"
>  
> @@ -50,7 +52,11 @@ struct grcan_registers {
>  	u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
>  	u32 smask;	/* 0x18 - CanMASK */
>  	u32 scode;	/* 0x1c - CanCODE */
> -	u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)];
> +	u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
> +	u32 nbtr;	/* 0x40 */
> +	u32 fdbtr;	/* 0x44 */
> +	u32 tdelay;	/* 0x48 */
> +	u32 __reserved2_[GRCAN_RESERVE_SIZE(0x48, 0x100)];
>  	u32 pimsr;	/* 0x100 */
>  	u32 pimr;	/* 0x104 */
>  	u32 pisr;	/* 0x108 */
> @@ -93,16 +99,6 @@ struct grcan_registers {
>  	(GRCAN_CONF_BPR | GRCAN_CONF_RSJ | GRCAN_CONF_PS1		\
>  	 | GRCAN_CONF_PS2 | GRCAN_CONF_SCALER)
>  
> -#define GRCAN_CONF_RSJ_MIN	1
> -#define GRCAN_CONF_RSJ_MAX	4
> -#define GRCAN_CONF_PS1_MIN	1
> -#define GRCAN_CONF_PS1_MAX	15
> -#define GRCAN_CONF_PS2_MIN	2
> -#define GRCAN_CONF_PS2_MAX	8
> -#define GRCAN_CONF_SCALER_MIN	0
> -#define GRCAN_CONF_SCALER_MAX	255
> -#define GRCAN_CONF_SCALER_INC	1
> -
>  #define GRCAN_CONF_BPR_BIT	8
>  #define GRCAN_CONF_RSJ_BIT	12
>  #define GRCAN_CONF_PS1_BIT	20
> @@ -212,6 +208,39 @@ struct grcan_registers {
>  #error "Invalid default buffer size"
>  #endif
>  
> +#define GRCANFD_NBTR_SCALER     GENMASK(23, 16)
> +#define GRCANFD_NBTR_PS1        GENMASK(17, 10)
> +#define GRCANFD_NBTR_PS2        GENMASK(9, 5)
> +#define GRCANFD_NBTR_SJW        GENMASK(4, 0)
> +#define GRCANFD_NBTR_TIMING						\
> +	(GRCANFD_NBTR_SCALER | GRCANFD_NBTR_PS1 | GRCANFD_NBTR_PS2 |	\
> +	 GRCANFD_NBTR_SJW)
> +
> +#define GRCANFD_FDBTR_SCALER 0x00ff0000
> +#define GRCANFD_FDBTR_PS1 0x00003c00
> +#define GRCANFD_FDBTR_PS2 0x000001e0
> +#define GRCANFD_FDBTR_SJW 0x0000000f
> +#define GRCANFD_FDBTR_TIMING						\
> +	(GRCANFD_FDBTR_SCALER | GRCANFD_FDBTR_PS1 | GRCANFD_FDBTR_PS2 |	\
> +	 GRCANFD_FDBTR_SJW)
> +
> +#define GRCANFD_FDBTR_SCALER_BIT 16
> +#define GRCANFD_FDBTR_PS1_BIT 10
> +#define GRCANFD_FDBTR_PS2_BIT 5
> +#define GRCANFD_FDBTR_SJW_BIT 0
> +
> +/* Hardware capabilities */
> +struct grcan_hwcap {
> +	/* CAN-FD capable, indicates GRCANFD IP.
> +	 * The GRCANFD has different baud-rate registers and extended DMA
> +	 * format to also describe FD-frames.
> +	 */
> +	const struct can_bittiming_const *bt_const;
> +	int (*set_bittiming)(struct net_device *dev);
> +	bool txbug_possible;
> +	bool fd;
> +};
> +
>  struct grcan_dma_buffer {
>  	size_t size;
>  	void *buf;
> @@ -254,6 +283,7 @@ struct grcan_priv {
>  	struct napi_struct napi;
>  
>  	struct grcan_registers __iomem *regs;	/* ioremap'ed registers */
> +	const struct grcan_hwcap *hwcap;
>  	struct grcan_device_config config;
>  	struct grcan_dma dma;
>  
> @@ -304,6 +334,7 @@ struct grcan_priv {
>  	 */
>  	bool resetting;
>  	bool closing;
> +
>  };
>  
>  /* Wait time for a short wait for ongoing to clear */
> @@ -392,55 +423,79 @@ static struct grcan_device_config grcan_module_config =
>  
>  static const struct can_bittiming_const grcan_bittiming_const = {
>  	.name		= DRV_NAME,
> -	.tseg1_min	= GRCAN_CONF_PS1_MIN + 1,
> -	.tseg1_max	= GRCAN_CONF_PS1_MAX + 1,
> -	.tseg2_min	= GRCAN_CONF_PS2_MIN,
> -	.tseg2_max	= GRCAN_CONF_PS2_MAX,
> -	.sjw_max	= GRCAN_CONF_RSJ_MAX,
> -	.brp_min	= GRCAN_CONF_SCALER_MIN + 1,
> -	.brp_max	= GRCAN_CONF_SCALER_MAX + 1,
> -	.brp_inc	= GRCAN_CONF_SCALER_INC,
> +	.tseg1_min	= 2,
> +	.tseg1_max	= 16,
> +	.tseg2_min	= 2,
> +	.tseg2_max	= 8,
> +	.sjw_max	= 4,
> +	.brp_min	= 1,
> +	.brp_max	= 256,
> +	.brp_inc	= 1,

For example, removing those macros and replacing them by literal
values is not related to adding FD capabilities.

This should go to a preparation clean-up patch.

> +};
> +
> +/* GRCANFD nominal boundaries for baud-rate parameters */
> +static const struct can_bittiming_const grcanfd_bittiming_const = {
> +	.name		= DRV_NAME,
> +	.tseg1_min	= 2,
> +	.tseg1_max	= 63,
> +	.tseg2_min	= 2,
> +	.tseg2_max	= 16,
> +	.sjw_max	= 16,
> +	.brp_min	= 1,
> +	.brp_max	= 256,
> +	.brp_inc	= 1,
>  };
>  
>  static int grcan_set_bittiming(struct net_device *dev)
>  {
>  	struct grcan_priv *priv = netdev_priv(dev);
> -	struct grcan_registers __iomem *regs = priv->regs;
> -	struct can_bittiming *bt = &priv->can.bittiming;
> -	u32 timing = 0;
> +	struct grcan_registers __iomem *regs;
>  	int bpr, rsj, ps1, ps2, scaler;
> +	struct can_bittiming *bt;
> +	u32 timing = 0;
>  
> -	/* Should never happen - function will not be called when
> -	 * device is up
> -	 */
> -	if (grcan_read_bits(&regs->ctrl, GRCAN_CTRL_ENABLE))
> -		return -EBUSY;
> +	regs = priv->regs;
> +	bt = &priv->can.bittiming;
>  
>  	bpr = 0; /* Note bpr and brp are different concepts */
>  	rsj = bt->sjw;
>  	ps1 = (bt->prop_seg + bt->phase_seg1) - 1; /* tseg1 - 1 */
>  	ps2 = bt->phase_seg2;
> -	scaler = (bt->brp - 1);
> -	netdev_dbg(dev, "Request for BPR=%d, RSJ=%d, PS1=%d, PS2=%d, SCALER=%d",
> -		   bpr, rsj, ps1, ps2, scaler);
> -	if (!(ps1 > ps2)) {
> -		netdev_err(dev, "PS1 > PS2 must hold: PS1=%d, PS2=%d\n",
> -			   ps1, ps2);
> -		return -EINVAL;
> -	}
> -	if (!(ps2 >= rsj)) {
> -		netdev_err(dev, "PS2 >= RSJ must hold: PS2=%d, RSJ=%d\n",
> -			   ps2, rsj);
> -		return -EINVAL;
> -	}
> +	scaler = bt->brp - 1;
> +
> +	timing |= FIELD_PREP(GRCAN_CONF_BPR, bpr);
> +	timing |= FIELD_PREP(GRCAN_CONF_RSJ, rsj);
> +	timing |= FIELD_PREP(GRCAN_CONF_PS1, ps1);
> +	timing |= FIELD_PREP(GRCAN_CONF_PS2, ps2);
> +	timing |= FIELD_PREP(GRCAN_CONF_SCALER, scaler);
> +	netdev_dbg(dev, "setting timing=0x%x\n", timing);
> +	grcan_write_bits(&regs->conf, timing, GRCAN_CONF_TIMING);
> +
> +	return 0;
> +}
> +
> +static int grcanfd_set_bittiming(struct net_device *dev)
> +{
> +	struct grcan_priv *priv = netdev_priv(dev);
> +	struct grcan_registers __iomem *regs;
> +	int sjw, ps1, ps2, scaler;
> +	struct can_bittiming *bt;
> +	u32 timing = 0;
> +
> +	regs = priv->regs;
> +	bt = &priv->can.bittiming;
> +
> +	sjw = bt->sjw;
> +	ps1 = (bt->prop_seg + bt->phase_seg1);
> +	ps2 = bt->phase_seg2;
> +	scaler = bt->brp - 1;
>  
> -	timing |= (bpr << GRCAN_CONF_BPR_BIT) & GRCAN_CONF_BPR;
> -	timing |= (rsj << GRCAN_CONF_RSJ_BIT) & GRCAN_CONF_RSJ;
> -	timing |= (ps1 << GRCAN_CONF_PS1_BIT) & GRCAN_CONF_PS1;
> -	timing |= (ps2 << GRCAN_CONF_PS2_BIT) & GRCAN_CONF_PS2;
> -	timing |= (scaler << GRCAN_CONF_SCALER_BIT) & GRCAN_CONF_SCALER;
> +	timing |= FIELD_PREP(GRCANFD_NBTR_SJW, sjw);
> +	timing |= FIELD_PREP(GRCANFD_NBTR_PS1, ps1);
> +	timing |= FIELD_PREP(GRCANFD_NBTR_PS2, ps2);
> +	timing |= FIELD_PREP(GRCANFD_NBTR_SCALER, scaler);
>  	netdev_info(dev, "setting timing=0x%x\n", timing);
> -	grcan_write_bits(&regs->conf, timing, GRCAN_CONF_TIMING);
> +	grcan_write_bits(&regs->nbtr, timing, GRCANFD_NBTR_TIMING);

Same here. That's another preparation patch.

>  	return 0;
>  }
> @@ -1569,7 +1624,8 @@ static const struct ethtool_ops grcan_ethtool_ops = {
>  
>  static int grcan_setup_netdev(struct platform_device *ofdev,
>  			      void __iomem *base,
> -			      int irq, u32 ambafreq, bool txbug)
> +			      int irq, u32 ambafreq, bool txbug,
> +			      const struct grcan_hwcap *hwcap)
>  {
>  	struct net_device *dev;
>  	struct grcan_priv *priv;
> @@ -1592,14 +1648,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
>  	priv->dev = dev;
>  	priv->ofdev_dev = &ofdev->dev;
>  	priv->regs = base;
> -	priv->can.bittiming_const = &grcan_bittiming_const;
> -	priv->can.do_set_bittiming = grcan_set_bittiming;
> +	priv->can.bittiming_const = hwcap->bt_const;
>  	priv->can.do_set_mode = grcan_set_mode;
>  	priv->can.do_get_berr_counter = grcan_get_berr_counter;
>  	priv->can.clock.freq = ambafreq;
>  	priv->can.ctrlmode_supported =
>  		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
>  	priv->need_txbug_workaround = txbug;
> +	priv->hwcap = hwcap;
>  
>  	/* Discover if triple sampling is supported by hardware */
>  	regs = priv->regs;
> @@ -1644,22 +1700,33 @@ static int grcan_probe(struct platform_device *ofdev)
>  {
>  	struct device_node *np = ofdev->dev.of_node;
>  	struct device_node *sysid_parent;
> +	const struct grcan_hwcap *hwcap;
>  	struct clk *clk;
>  	u32 sysid, ambafreq;
>  	int irq, err;
>  	void __iomem *base;
>  	bool txbug = true;
>  
> +	hwcap = device_get_match_data(&ofdev->dev);
> +	if (!hwcap) {
> +		dev_err(&ofdev->dev, "Platform data not provided!\n");
> +		return -ENODEV;
> +	}
> +
>  	/* Compare GRLIB version number with the first that does not
>  	 * have the tx bug (see start_xmit)
>  	 */
> -	sysid_parent = of_find_node_by_path("/ambapp0");
> -	if (sysid_parent) {
> -		err = of_property_read_u32(sysid_parent, "systemid", &sysid);
> -		if (!err && ((sysid & GRLIB_VERSION_MASK) >=
> -			     GRCAN_TXBUG_SAFE_GRLIB_VERSION))
> -			txbug = false;
> -		of_node_put(sysid_parent);
> +	if (!hwcap->txbug_possible) {
> +		txbug = false;
> +	} else {
> +		sysid_parent = of_find_node_by_path("/ambapp0");
> +		if (sysid_parent) {
> +			err = of_property_read_u32(sysid_parent, "systemid", &sysid);
> +			if (!err && ((sysid & GRLIB_VERSION_MASK) >=
> +				     GRCAN_TXBUG_SAFE_GRLIB_VERSION))
> +				txbug = false;
> +			of_node_put(sysid_parent);
> +		}
>  	}
>  
>  	err = of_property_read_u32(np, "freq", &ambafreq);
> @@ -1695,7 +1762,7 @@ static int grcan_probe(struct platform_device *ofdev)
>  
>  	grcan_sanitize_module_config(ofdev);
>  
> -	err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug);
> +	err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug, hwcap);
>  	if (err)
>  		goto exit_dispose_irq;
>  
> @@ -1722,11 +1789,30 @@ static void grcan_remove(struct platform_device *ofdev)
>  	free_candev(dev);
>  }
>  
> +static const struct grcan_hwcap grcan_hwcap = {
> +	.fd = false,
> +	.txbug_possible = true,
> +	.bt_const = &grcan_bittiming_const,
> +	.set_bittiming = grcan_set_bittiming,
> +};
> +
> +static const struct grcan_hwcap grcanfd_hwcap = {
> +	.fd = true,
> +	.txbug_possible = false,
> +	.bt_const = &grcanfd_bittiming_const,
> +	.set_bittiming = grcanfd_set_bittiming,
> +};
> +
>  static const struct of_device_id grcan_match[] = {
> -	{.name = "GAISLER_GRCAN"},
> -	{.name = "01_03d"},
> -	{.name = "GAISLER_GRHCAN"},
> -	{.name = "01_034"},
> +	{.name = "GAISLER_GRCAN", .data = &grcan_hwcap},
> +	{.name = "01_03d", .data = &grcan_hwcap},
> +	{.name = "GAISLER_GRHCAN", .data = &grcan_hwcap},
> +	{.name = "01_034", .data = &grcan_hwcap},
> +	{.compatible = "gaisler,grcan", .data = &grcan_hwcap},
> +	/* GRCANFD */
> +	{.compatible = "gaisler,grcanfd", .data = &grcanfd_hwcap},
> +	{.name = "GAISLER_GRCANFD", .data = &grcanfd_hwcap},
> +	{.name = "01_0B5", .data = &grcanfd_hwcap},
>  	{},
>  };
>  


Yours sincerely,
Vincent Mailhol

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN
  2025-12-23 10:56 ` [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN Arun Muthusamy
@ 2025-12-23 21:09   ` Vincent Mailhol
  0 siblings, 0 replies; 17+ messages in thread
From: Vincent Mailhol @ 2025-12-23 21:09 UTC (permalink / raw)
  To: Arun Muthusamy, robh, krzk+dt, conor+dt, mkl
  Cc: devicetree, linux-kernel, linux-can

On 23/12/2025 at 11:56, Arun Muthusamy wrote:
> Include CANFD support with the legacy CAN support, enabling
> support for extended data payloads up to 64 bytes, higher bit rates,
> handle canecho frames.

The patch mixes code refactor with introduction of new feature. I am
only a partial review for now, waiting for a proper split to do the
full review.

> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
>  drivers/net/can/grcan.c | 259 +++++++++++++++++++++++++++-------------
>  1 file changed, 177 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index bf1c503d575d..3d5b4c7e58bc 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -174,6 +174,7 @@ struct grcan_registers {
>  #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
>  
>  #define GRCAN_MSG_SIZE		16
> +#define GRCAN_CLASSIC_DATA_SIZE 8
>  
>  #define GRCAN_MSG_IDE		0x80000000
>  #define GRCAN_MSG_RTR		0x40000000
> @@ -230,6 +231,12 @@ struct grcan_registers {
>  #define GRCANFD_FDBTR_PS2_BIT 5
>  #define GRCANFD_FDBTR_SJW_BIT 0
>  
> +#define GRCAN_TX_BRS  BIT(25)
> +#define GRCAN_TX_FDF  BIT(26)
> +
> +#define GRCAN_RX_BRS  BIT(25)
> +#define GRCAN_RX_FDF  BIT(26)
> +
>  /* Hardware capabilities */
>  struct grcan_hwcap {
>  	/* CAN-FD capable, indicates GRCANFD IP.
> @@ -290,6 +297,13 @@ struct grcan_priv {
>  
>  	struct sk_buff **echo_skb;	/* We allocate this on our own */
>  
> +	/*
> +	 * Since the CAN FD frame has a variable length, this variable is used
> +	 * to keep track of the index of the CAN echo skb (socket buffer) frame.
> +	 * It's important for ensuring that we correctly manage the echo skb.
> +	 */
> +	u32 echo_skb_idx;
> +
>  	/* The echo skb pointer, pointing into echo_skb and indicating which
>  	 * frames can be echoed back. See the "Notes on the tx cyclic buffer
>  	 * handling"-comment for grcan_start_xmit for more details.
> @@ -570,7 +584,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
>  	struct grcan_registers __iomem *regs = priv->regs;
>  	struct grcan_dma *dma = &priv->dma;
>  	struct net_device_stats *stats = &dev->stats;
> -	int i, work_done;
> +	int work_done;
>  
>  	/* Updates to priv->eskbp and wake-ups of the queue needs to
>  	 * be atomic towards the reads of priv->eskbp and shut-downs
> @@ -581,19 +595,22 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
>  	for (work_done = 0; work_done < budget || budget < 0; work_done++) {
>  		if (priv->eskbp == txrd)
>  			break;
> -		i = priv->eskbp / GRCAN_MSG_SIZE;
> -		if (echo) {
> -			/* Normal echo of messages */
> -			stats->tx_packets++;
> -			stats->tx_bytes += can_get_echo_skb(dev, i, NULL);
> -		} else {
> -			/* For cleanup of untransmitted messages */
> -			can_free_echo_skb(dev, i, NULL);
> -		}
>  
>  		priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
>  					     dma->tx.size);
>  		txrd = grcan_read_reg(&regs->txrd);
> +
> +		/* Grab the packet once the  packet is send or free untransmitted packet*/
> +		if (priv->eskbp == txrd) {
> +			if (echo) {
> +				/* Normal echo of messages */
> +				stats->tx_packets++;
> +				stats->tx_bytes += can_get_echo_skb(dev, priv->echo_skb_idx, NULL);
> +			} else {
> +				/* For cleanup of untransmitted messages */
> +				can_free_echo_skb(dev, priv->echo_skb_idx, NULL);
> +			}
> +		}
>  	}
>  	return work_done;
>  }
> @@ -676,10 +693,8 @@ static void grcan_err(struct net_device *dev, u32 sources, u32 status)
>  	    (status & GRCAN_STAT_ERRCTR_RELATED)) {
>  		enum can_state state = priv->can.state;
>  		enum can_state oldstate = state;
> -		u32 txerr = (status & GRCAN_STAT_TXERRCNT)
> -			>> GRCAN_STAT_TXERRCNT_BIT;
> -		u32 rxerr = (status & GRCAN_STAT_RXERRCNT)
> -			>> GRCAN_STAT_RXERRCNT_BIT;
> +		u32 txerr = (status & GRCAN_STAT_TXERRCNT) >> GRCAN_STAT_TXERRCNT_BIT;
> +		u32 rxerr = (status & GRCAN_STAT_RXERRCNT) >> GRCAN_STAT_RXERRCNT_BIT;

Do not add random code refactors to your patch. If you want to change
those lines, put it in a separate patch.

>  		/* Figure out current state */
>  		if (status & GRCAN_STAT_OFF) {
> @@ -1101,6 +1116,7 @@ static int grcan_set_mode(struct net_device *dev, enum can_mode mode)
>  			if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
>  				netif_wake_queue(dev);
>  		}
> +		priv->echo_skb_idx = 0;
>  		spin_unlock_irqrestore(&priv->lock, flags);
>  		return err;
>  	}
> @@ -1150,7 +1166,6 @@ static int grcan_open(struct net_device *dev)
>  		netif_start_queue(dev);
>  	priv->resetting = false;
>  	priv->closing = false;
> -
>  	spin_unlock_irqrestore(&priv->lock, flags);
>  
>  	return 0;
> @@ -1221,20 +1236,31 @@ static void grcan_transmit_catch_up(struct net_device *dev)
>  	spin_unlock_irqrestore(&priv->lock, flags);
>  }
>  
> +static int grcan_numbds(int len)
> +{
> +	if (len <= GRCAN_CLASSIC_DATA_SIZE)
> +		return 1;
> +	return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> +}
> +
>  static int grcan_receive(struct net_device *dev, int budget)
>  {
> +	struct net_device_stats *stats = &dev->stats;
>  	struct grcan_priv *priv = netdev_priv(dev);
> -	struct grcan_registers __iomem *regs = priv->regs;
> +	struct grcan_registers __iomem *regs;
>  	struct grcan_dma *dma = &priv->dma;
> -	struct net_device_stats *stats = &dev->stats;
> -	struct can_frame *cf;
> +	u32 bds, copy_len, payload_offset;
> +	u32 wr, rd, dlc, startrd;
> +	struct canfd_frame *cf;
> +	int i, work_done = 0;
>  	struct sk_buff *skb;
> -	u32 wr, rd, startrd;
> -	u32 *slot;
>  	u32 rtr, eff;
> -	int work_done = 0;
> +	u32 *slot;
> +	u8 *data;
>  
> +	regs = priv->regs;
>  	rd = grcan_read_reg(&regs->rxrd);
> +
>  	startrd = rd;
>  	for (work_done = 0; work_done < budget; work_done++) {
>  		/* Check for packet to receive */
> @@ -1242,44 +1268,70 @@ static int grcan_receive(struct net_device *dev, int budget)
>  		if (rd == wr)
>  			break;
>  
> -		/* Take care of packet */
> -		skb = alloc_can_skb(dev, &cf);
> -		if (skb == NULL) {
> +		slot = dma->rx.buf + rd;
> +
> +		if (slot[1] & GRCAN_RX_FDF)
> +			skb = alloc_canfd_skb(dev, &cf);
> +		else
> +			skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf);
> +
> +		if (unlikely(!skb)) {
>  			netdev_err(dev,
>  				   "dropping frame: skb allocation failed\n");
>  			stats->rx_dropped++;
>  			continue;
>  		}
>  
> -		slot = dma->rx.buf + rd;
> -		eff = slot[0] & GRCAN_MSG_IDE;
> -		rtr = slot[0] & GRCAN_MSG_RTR;
> -		if (eff) {
> -			cf->can_id = ((slot[0] & GRCAN_MSG_EID)
> -				      >> GRCAN_MSG_EID_BIT);
> -			cf->can_id |= CAN_EFF_FLAG;
> -		} else {
> -			cf->can_id = ((slot[0] & GRCAN_MSG_BID)
> -				      >> GRCAN_MSG_BID_BIT);
> -		}
> -		cf->len = can_cc_dlc2len((slot[1] & GRCAN_MSG_DLC)
> -					  >> GRCAN_MSG_DLC_BIT);
> -		if (rtr) {
> -			cf->can_id |= CAN_RTR_FLAG;
> -		} else {
> -			if (cf->can_dlc > 0) {
> -				memcpy(cf->data, &slot[2], sizeof(u32));
> -				if (cf->can_dlc > 4)
> -					memcpy(cf->data + 4, &slot[3], sizeof(u32));
> +		dlc = (slot[1] & GRCAN_MSG_DLC) >> GRCAN_MSG_DLC_BIT;
> +		if (slot[1] & GRCAN_RX_FDF)
> +			cf->len = can_fd_dlc2len(dlc);
> +		else
> +			cf->len = can_cc_dlc2len(dlc);
> +
> +		bds = grcan_numbds(cf->len);
> +		payload_offset = 0;
> +		data = cf->data;
> +
> +		for (i = 0; i < bds; i++) {
> +			slot = dma->rx.buf + rd;
> +
> +			if (i == 0) {
> +				eff = slot[0] & GRCAN_MSG_IDE;
> +				rtr = slot[0] & GRCAN_MSG_RTR;
> +				if (eff) {
> +					cf->can_id = ((slot[0] & GRCAN_MSG_EID)
> +						>> GRCAN_MSG_EID_BIT);

Use FIELD_GET() here. Add the required GRCAN_MSG_EID_MASK macro in a
dedicated clean-up patch.

> +					cf->can_id |= CAN_EFF_FLAG;
> +				} else {
> +					cf->can_id = ((slot[0] & GRCAN_MSG_BID)
> +						>> GRCAN_MSG_BID_BIT);
> +				}
> +				if (rtr)
> +					cf->can_id |= CAN_RTR_FLAG;
> +
> +				dlc = (slot[1] & GRCAN_MSG_DLC) >> GRCAN_MSG_DLC_BIT;

Same.

> +				if (slot[1] & GRCAN_RX_FDF)
> +					cf->len = can_fd_dlc2len(dlc);
> +				else
> +					cf->len = can_cc_dlc2len(dlc);
> +
> +				copy_len = min(cf->len, GRCAN_CLASSIC_DATA_SIZE);
> +				memcpy(data, &slot[2], copy_len);
> +				payload_offset += copy_len;
> +			} else {
> +				copy_len =  min(cf->len - payload_offset, GRCAN_MSG_SIZE);
> +				memcpy(data + payload_offset, slot, copy_len);
> +				payload_offset += copy_len;
>  			}
> -
> -			stats->rx_bytes += cf->len;
> +			rd += GRCAN_MSG_SIZE;
> +			if (rd >= dma->tx.size)
> +				rd -= dma->tx.size;
>  		}
> -		stats->rx_packets++;
>  
> +		/* Update statistics and read pointer */
> +		stats->rx_packets++;
> +		stats->rx_bytes += cf->len;
>  		netif_receive_skb(skb);
> -
> -		rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
>  	}
>  
>  	/* Make sure everything is read before allowing hardware to
> @@ -1404,15 +1456,22 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  				    struct net_device *dev)
>  {
>  	struct grcan_priv *priv = netdev_priv(dev);
> -	struct grcan_registers __iomem *regs = priv->regs;
> +	struct grcan_registers __iomem *regs;
> +	u32 eff, rtr, dlc, tmp, err, can_id;
>  	struct grcan_dma *dma = &priv->dma;
> -	struct can_frame *cf = (struct can_frame *)skb->data;
> +	u32 bds, copy_len, payload_offset;
>  	u32 id, txwr, txrd, space, txctrl;
> -	int slotindex;
> -	u32 *slot;
> -	u32 rtr, eff, dlc, tmp, err;
> +	struct canfd_frame *cfd;
> +	struct can_frame *cf;
>  	unsigned long flags;
> -	u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
> +	u32 oneshotmode;
> +	u8 *payload;
> +	u32 *slot;
> +	u8 len;
> +	int i;
> +
> +	regs = priv->regs;
> +	oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
>  
>  	if (can_dev_dropped_skb(dev, skb))
>  		return NETDEV_TX_OK;
> @@ -1423,6 +1482,20 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
>  		return NETDEV_TX_BUSY;
>  
> +	if (can_is_canfd_skb(skb)) {
> +		cfd = (struct canfd_frame *)skb->data;
> +		len = cfd->len;
> +		dlc = can_fd_len2dlc(cfd->len);
> +		can_id = cfd->can_id;
> +		payload = cfd->data;
> +	} else {
> +		cf = (struct can_frame *)skb->data;
> +		len = cf->len;
> +		dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
> +		can_id = cf->can_id;
> +		payload = cf->data;
> +	}

struct canfd_frame and struct can_frame share the same layout so try
to factorize what can be factorized, that is to say, everything except
of the dlc assignment.

>  	/* Reads of priv->eskbp and shut-downs of the queue needs to
>  	 * be atomic towards the updates to priv->eskbp and wake-ups
>  	 * of the queue in the interrupt handler.
> @@ -1431,9 +1504,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  
>  	txwr = grcan_read_reg(&regs->txwr);
>  	space = grcan_txspace(dma->tx.size, txwr, priv->eskbp);
> -
> -	slotindex = txwr / GRCAN_MSG_SIZE;
> -	slot = dma->tx.buf + txwr;
> +	bds = grcan_numbds(len);
>  
>  	if (unlikely(space == 1))
>  		netif_stop_queue(dev);
> @@ -1449,25 +1520,38 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  		return NETDEV_TX_BUSY;
>  	}
>  
> -	/* Convert and write CAN message to DMA buffer */
> -	eff = cf->can_id & CAN_EFF_FLAG;
> -	rtr = cf->can_id & CAN_RTR_FLAG;
> -	id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
> -	dlc = cf->len;
> -	if (eff)
> -		tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
> -	else
> -		tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
> -	slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
> -
> -	slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
> -	slot[2] = 0;
> -	slot[3] = 0;
> -	if (dlc > 0) {
> -		memcpy(&slot[2], cf->data, sizeof(u32));
> -		slot[2] = *(u32 *)(cf->data);
> -		if (dlc > 4)
> -			memcpy(&slot[3], cf->data + 4, sizeof(u32));
> +	payload_offset = 0;
> +	for (i = 0; i < bds; i++) {
> +		slot = dma->tx.buf + txwr;
> +		memset(slot, 0, GRCAN_MSG_SIZE);
> +
> +		if (i == 0) {
> +			eff = can_id & CAN_EFF_FLAG;
> +			rtr = can_id & CAN_RTR_FLAG;
> +			id = can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
> +			if (eff)
> +				tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
> +			else
> +				tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
> +			slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
> +			slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
> +			if (can_is_canfd_skb(skb)) {
> +				slot[1] |= GRCAN_TX_FDF;
> +				if (cfd->flags & CANFD_BRS)
> +					slot[1] |= GRCAN_TX_BRS;
> +			}
> +
> +			copy_len = min(len, 8);
> +			memcpy(&slot[2], payload, copy_len);
> +			payload_offset += copy_len;
> +		} else {
> +			copy_len =  min(len - payload_offset, GRCAN_MSG_SIZE);
> +			memcpy(slot, payload + payload_offset, copy_len);
> +			payload_offset += copy_len;
> +		}
> +		txwr += GRCAN_MSG_SIZE;
> +		if (txwr >= dma->tx.size)
> +			txwr -= dma->tx.size;
>  	}
>  
>  	/* Checking that channel has not been disabled. These cases
> @@ -1502,7 +1586,14 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  	 * can_put_echo_skb would be an error unless other measures are
>  	 * taken.
>  	 */
> -	can_put_echo_skb(skb, dev, slotindex, 0);
> +
> +	can_put_echo_skb(skb, dev, priv->echo_skb_idx, 0);
> +
> +	/* Move to the next index in the echo skb buffer */
> +	priv->echo_skb_idx = (priv->echo_skb_idx + 1) % priv->can.echo_skb_max;
> +
> +	if (priv->can.echo_skb[priv->echo_skb_idx])
> +		netif_stop_queue(dev);
>  
>  	/* Make sure everything is written before allowing hardware to
>  	 * read from the memory
> @@ -1510,8 +1601,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>  	wmb();
>  
>  	/* Update write pointer to start transmission */
> -	grcan_write_reg(&regs->txwr,
> -			grcan_ring_add(txwr, GRCAN_MSG_SIZE, dma->tx.size));
> +	grcan_write_reg(&regs->txwr, txwr);
>  
>  	return NETDEV_TX_OK;
>  }
> @@ -1662,11 +1752,16 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
>  	priv->ofdev_dev = &ofdev->dev;
>  	priv->regs = base;
>  	priv->can.bittiming_const = hwcap->bt_const;
> +	priv->can.fd.data_bittiming_const = hwcap->bt_const;
>  	priv->can.do_set_mode = grcan_set_mode;
>  	priv->can.do_get_berr_counter = grcan_get_berr_counter;
>  	priv->can.clock.freq = ambafreq;
> -	priv->can.ctrlmode_supported =
> -		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
> +	if (hwcap->fd)
> +		priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
> +			CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_FD;
> +	else
> +		priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
> +			CAN_CTRLMODE_ONE_SHOT;

Do it like this:

	priv->can.ctrlmode_supported =
		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
	if (hwcap->fd)
		priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;

>  	priv->need_txbug_workaround = txbug;
>  	priv->hwcap = hwcap;
>  

Yours sincerely,
Vincent Mailhol

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML
  2025-12-23 10:55 ` [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML Arun Muthusamy
@ 2025-12-24  2:29   ` kernel test robot
  2025-12-30  2:19   ` Rob Herring
  1 sibling, 0 replies; 17+ messages in thread
From: kernel test robot @ 2025-12-24  2:29 UTC (permalink / raw)
  To: Arun Muthusamy, robh, krzk+dt, conor+dt, mkl, mailhol
  Cc: oe-kbuild-all, devicetree, linux-kernel, linux-can,
	Arun Muthusamy

Hi Arun,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 4001bda0cc911fcdd3dde36963a17f4eac173d7d]

url:    https://github.com/intel-lab-lkp/linux/commits/Arun-Muthusamy/dt-bindings-Add-vendor-prefix-for-Frontgrade-Gaisler-AB/20251223-190933
base:   4001bda0cc911fcdd3dde36963a17f4eac173d7d
patch link:    https://lore.kernel.org/r/20251223105604.12675-3-arun.muthusamy%40gaisler.com
patch subject: [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML
reproduce: (https://download.01.org/0day-ci/archive/20251224/202512240358.V4rXhlja-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512240358.V4rXhlja-lkp@intel.com/

All warnings (new ones prefixed by >>):

   Warning: MAINTAINERS references a file that doesn't exist: Documentation/sphinx/parse-headers.pl
   Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
   Warning: arch/powerpc/sysdev/mpic.c references a file that doesn't exist: Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
   Warning: arch/riscv/kernel/kexec_image.c references a file that doesn't exist: Documentation/riscv/boot-image-header.rst
   Warning: drivers/clocksource/timer-armada-370-xp.c references a file that doesn't exist: Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
>> Warning: drivers/net/can/grcan.c references a file that doesn't exist: Documentation/devicetree/bindings/net/can/grcan.txt
   Warning: include/rv/da_monitor.h references a file that doesn't exist: Documentation/trace/rv/da_monitor_synthesis.rst
   Warning: rust/kernel/sync/atomic/ordering.rs references a file that doesn't exist: srctree/tools/memory-model/Documentation/explanation.txt
   Using alabaster theme
   ERROR: Cannot find file ./include/linux/pci.h
   WARNING: No kernel-doc for file ./include/linux/pci.h

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB
  2025-12-23 10:55 ` [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
@ 2025-12-27 12:31   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 17+ messages in thread
From: Krzysztof Kozlowski @ 2025-12-27 12:31 UTC (permalink / raw)
  To: Arun Muthusamy
  Cc: robh, krzk+dt, conor+dt, mkl, mailhol, devicetree, linux-kernel,
	linux-can, Ludwig Rydberg

On Tue, Dec 23, 2025 at 11:55:55AM +0100, Arun Muthusamy wrote:
> From: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
> 
> Frontgrade Gaisler AB provides IP cores and supporting development tools
> for embedded processors based on the SPARC and RISC-V architectures.
> Some essential products are the LEON and NOEL synthesizable processor
> models together with a complete development environment and a library of
> IP cores (GRLIB).
> 
> The company specializes in digital hardware design (ASIC/FPGA) for both
> commercial and aerospace applications.
> 
> Web site: https://www.gaisler.com/
> 
> Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML
  2025-12-23 10:55 ` [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML Arun Muthusamy
  2025-12-24  2:29   ` kernel test robot
@ 2025-12-30  2:19   ` Rob Herring
  1 sibling, 0 replies; 17+ messages in thread
From: Rob Herring @ 2025-12-30  2:19 UTC (permalink / raw)
  To: Arun Muthusamy
  Cc: krzk+dt, conor+dt, mkl, mailhol, devicetree, linux-kernel,
	linux-can

On Tue, Dec 23, 2025 at 11:55:56AM +0100, Arun Muthusamy wrote:
> Migrate device tree bindings for Gaisler GRCAN, GRHCAN
> and GRCANFD CAN controllers from a text format to YAML format.

A more concise subject would be:

net: can: Convert gaisler,grcan to DT schema

Otherwise,

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>

> 
> Additional changes:
>   - Remove stale systemid property
>     removed in commit 1e93ed26acf0 ("can: grcan: grcan_probe():
>     fix broken system id check for errata workaround needs")
>   - Make freq optional
>   - Add clocks
>   - Add compatible
>   - Add example
> 
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
>  .../bindings/net/can/gaisler,grcan.yaml       | 62 +++++++++++++++++++
>  .../devicetree/bindings/net/can/grcan.txt     | 28 ---------
>  2 files changed, 62 insertions(+), 28 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
>  delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2025-12-30  2:19 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-23 10:55 [PATCH v2 00/10] can: grcan: Enhance driver with CANFD Support and Improvements Arun Muthusamy
2025-12-23 10:55 ` [PATCH v2 01/10] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
2025-12-27 12:31   ` Krzysztof Kozlowski
2025-12-23 10:55 ` [PATCH v2 02/10] dt-bindings: net: can: grcan: Convert GRCAN CAN controllers binding from txt to YAML Arun Muthusamy
2025-12-24  2:29   ` kernel test robot
2025-12-30  2:19   ` Rob Herring
2025-12-23 10:55 ` [PATCH v2 03/10] MAINTAINERS: Add maintainers for GRCAN CAN network driver Arun Muthusamy
2025-12-23 10:55 ` [PATCH v2 04/10] can: grcan: Add clock handling Arun Muthusamy
2025-12-23 10:55 ` [PATCH v2 05/10] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
2025-12-23 20:51   ` Vincent Mailhol
2025-12-23 10:56 ` [PATCH v2 06/10] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
2025-12-23 20:40   ` Vincent Mailhol
2025-12-23 10:56 ` [PATCH v2 07/10] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit Arun Muthusamy
2025-12-23 10:56 ` [PATCH v2 08/10] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
2025-12-23 10:56 ` [PATCH v2 09/10] can: grcan: Reserve space between cap and next register to align with address layout Arun Muthusamy
2025-12-23 10:56 ` [PATCH v2 10/10] can: grcan: Add CANFD support alongside legacy CAN Arun Muthusamy
2025-12-23 21:09   ` Vincent Mailhol

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).