* [PATCH v8 0/4] rockchip: add can for RK3576 Soc
@ 2025-10-29 3:22 Elaine Zhang
2025-10-29 3:22 ` [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller Elaine Zhang
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Elaine Zhang @ 2025-10-29 3:22 UTC (permalink / raw)
To: zhangqing, mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt,
heiko, cl
Cc: linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
rk3576 can is a new controller,new register layout and Bit position
definition:
Support CAN protocol.
Support Dma.
There are major differences from the previous rk3568.
All errata on the rk3568 have been fixed and redesigned.
RK3576 CANFD requires authorization and permission. The software
code is not open by default and needs to be authorized separately.
Change in V8:
[PATCH v8 1/4]: Drop CANFD, correction format warning.
[PATCH v8 2/4]: Drop fifo_setup of rkcanfd_devtype_data.
[PATCH v8 3/4]: Drop CANFD.
[PATCH v8 4/4]: Drop CANFD.
Change in V7:
[PATCH v7 1/4]: Correction format warning.
[PATCH v7 2/4]: No change.
[PATCH v7 3/4]: Correct the writing of some registers and
correct the annotations.
[PATCH v7 4/4]: Optimize the structure parameters and
ensure error handling.
Change in V6:
[PATCH v6 1/4]: Fix dma is support only for rk3576.
[PATCH v6 2/4]: Fix the compilation warning.
[PATCH v6 3/4]: Fix the compilation warning.
[PATCH v6 4/4]: Fix the compilation warning.
Change in V5:
[PATCH v5 1/4]: Add rk3576 canfd to rockchip,rk3568v2-canfd.yaml, remove
rockchip,rk3576-canfd.yaml
[PATCH v5 2/4]: Encapsulate some hardware operation functions into
rkcanfd_devtype_data to provide differentiated
implementations for different models
(such as RK3568v2/v3)..
[PATCH v5 3/4]: Add rk3576 canfd,fix the register naming rule,
Delete the variables used by rockchip itself.
[PATCH v5 4/4]: Fix .h sorting.
Change in V4:
[PATCH v4 1/3]: Correct the format and add explanations.
[PATCH v4 2/3]: No change.
[PATCH v4 3/3]: No change.
Change in V3:
[PATCH v3 1/3]: Add documentation for the rk3576 CAN-FD.
[PATCH v3 2/3]: Adjust the differentiated code section and
add dma function.
[PATCH v3 3/3]: Remove dma, no use dma by default.
Change in V2:
[PATCH v2 1/2]: remove rk3576_canfd.c, use the rockchip_canfd driver
[PATCH v2 2/2]: code style.
Elaine Zhang (4):
dt-bindings: can: rockchip_canfd: add rk3576 CAN controller
net: can: rockchip: Refactor the rkcanfd_devtype_data structure
net: can: rockchip: add can for RK3576 Soc
net: can: rockchip: support dma for rk3576 rx
.../net/can/rockchip,rk3568v2-canfd.yaml | 52 +-
.../net/can/rockchip/rockchip_canfd-core.c | 581 ++++++++++++++++--
drivers/net/can/rockchip/rockchip_canfd-rx.c | 212 +++++++
drivers/net/can/rockchip/rockchip_canfd-tx.c | 20 +
drivers/net/can/rockchip/rockchip_canfd.h | 277 +++++++++
5 files changed, 1094 insertions(+), 48 deletions(-)
--
2.34.1
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller
2025-10-29 3:22 [PATCH v8 0/4] rockchip: add can for RK3576 Soc Elaine Zhang
@ 2025-10-29 3:22 ` Elaine Zhang
2025-10-29 17:48 ` Conor Dooley
2025-10-29 3:23 ` [PATCH v8 2/4] net: can: rockchip: Refactor the rkcanfd_devtype_data structure Elaine Zhang
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Elaine Zhang @ 2025-10-29 3:22 UTC (permalink / raw)
To: zhangqing, mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt,
heiko, cl
Cc: linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
Add documentation for the rockchip rk3576 CAN controller.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
.../net/can/rockchip,rk3568v2-canfd.yaml | 52 +++++++++++++++++--
1 file changed, 48 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
index a077c0330013..30782218728e 100644
--- a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
+++ b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
@@ -10,13 +10,12 @@ title:
maintainers:
- Marc Kleine-Budde <mkl@pengutronix.de>
-allOf:
- - $ref: can-controller.yaml#
-
properties:
compatible:
oneOf:
- - const: rockchip,rk3568v2-canfd
+ - enum:
+ - rockchip,rk3568v2-canfd
+ - rockchip,rk3576-can
- items:
- const: rockchip,rk3568v3-canfd
- const: rockchip,rk3568v2-canfd
@@ -43,6 +42,33 @@ properties:
- const: core
- const: apb
+ dmas:
+ maxItems: 1
+
+ dma-names:
+ items:
+ - const: rx
+
+allOf:
+ - $ref: can-controller.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3576-can
+ then:
+ properties:
+ dmas:
+ minItems: 1
+ maxItems: 2
+ dma-names:
+ minItems: 1
+ maxItems: 2
+ else:
+ properties:
+ dmas: false
+ dma-names: false
+
required:
- compatible
- reg
@@ -72,3 +98,21 @@ examples:
reset-names = "core", "apb";
};
};
+
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ can@2ac00000 {
+ compatible = "rockchip,rk3576-can";
+ reg = <0x0 0x2ac00000 0x0 0x1000>;
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru CLK_CAN0>, <&cru PCLK_CAN0>;
+ clock-names = "baud", "pclk";
+ resets = <&cru SRST_CAN0>, <&cru SRST_P_CAN0>;
+ reset-names = "core", "apb";
+ dmas = <&dmac0 20>;
+ dma-names = "rx";
+ };
+ };
--
2.34.1
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v8 2/4] net: can: rockchip: Refactor the rkcanfd_devtype_data structure
2025-10-29 3:22 [PATCH v8 0/4] rockchip: add can for RK3576 Soc Elaine Zhang
2025-10-29 3:22 ` [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller Elaine Zhang
@ 2025-10-29 3:23 ` Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 3/4] net: can: rockchip: add can for RK3576 Soc Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 4/4] net: can: rockchip: support dma for rk3576 rx Elaine Zhang
3 siblings, 0 replies; 6+ messages in thread
From: Elaine Zhang @ 2025-10-29 3:23 UTC (permalink / raw)
To: zhangqing, mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt,
heiko, cl
Cc: linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
Add new function pointer:
Encapsulate some hardware operation functions into
rkcanfd_devtype_data to provide differentiated implementations for
different models (such as RK3568v2/v3).
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
.../net/can/rockchip/rockchip_canfd-core.c | 100 ++++++++++--------
drivers/net/can/rockchip/rockchip_canfd.h | 10 ++
2 files changed, 68 insertions(+), 42 deletions(-)
diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c
index 046f0a0ae4d4..761cb36148ff 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-core.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-core.c
@@ -24,32 +24,6 @@
#include "rockchip_canfd.h"
-static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v2 = {
- .model = RKCANFD_MODEL_RK3568V2,
- .quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
- RKCANFD_QUIRK_RK3568_ERRATUM_3 | RKCANFD_QUIRK_RK3568_ERRATUM_4 |
- RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_6 |
- RKCANFD_QUIRK_RK3568_ERRATUM_7 | RKCANFD_QUIRK_RK3568_ERRATUM_8 |
- RKCANFD_QUIRK_RK3568_ERRATUM_9 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
- RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
- RKCANFD_QUIRK_CANFD_BROKEN,
-};
-
-/* The rk3568 CAN-FD errata sheet as of Tue 07 Nov 2023 11:25:31 +08:00
- * states that only the rk3568v2 is affected by erratum 5, but tests
- * with the rk3568v2 and rk3568v3 show that the RX_FIFO_CNT is
- * sometimes too high. In contrast to the errata sheet mark rk3568v3
- * as effected by erratum 5, too.
- */
-static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = {
- .model = RKCANFD_MODEL_RK3568V3,
- .quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
- RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_7 |
- RKCANFD_QUIRK_RK3568_ERRATUM_8 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
- RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
- RKCANFD_QUIRK_CANFD_BROKEN,
-};
-
static const char *__rkcanfd_get_model_str(enum rkcanfd_model model)
{
switch (model) {
@@ -212,7 +186,7 @@ static int rkcanfd_get_berr_counter(const struct net_device *ndev,
if (err)
return err;
- rkcanfd_get_berr_counter_corrected(priv, bec);
+ priv->devtype_data.get_berr_counter(priv, bec);
pm_runtime_put(ndev->dev.parent);
@@ -302,7 +276,7 @@ static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
rkcanfd_set_bittiming(priv);
- rkcanfd_chip_interrupts_disable(priv);
+ priv->devtype_data.interrupts_disable(priv);
rkcanfd_chip_set_work_mode(priv);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -316,7 +290,7 @@ static void __rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state
priv->can.state = state;
rkcanfd_chip_set_reset_mode(priv);
- rkcanfd_chip_interrupts_disable(priv);
+ priv->devtype_data.interrupts_disable(priv);
}
static void rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state state)
@@ -342,8 +316,8 @@ static int rkcanfd_set_mode(struct net_device *ndev,
switch (mode) {
case CAN_MODE_START:
- rkcanfd_chip_start(priv);
- rkcanfd_chip_interrupts_enable(priv);
+ priv->devtype_data.chip_start(priv);
+ priv->devtype_data.interrupts_enable(priv);
netif_wake_queue(ndev);
break;
@@ -537,7 +511,7 @@ static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
if (cf) {
struct can_berr_counter bec;
- rkcanfd_get_berr_counter_corrected(priv, &bec);
+ priv->devtype_data.get_berr_counter(priv, &bec);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT;
cf->data[6] = bec.txerr;
cf->data[7] = bec.rxerr;
@@ -567,7 +541,7 @@ static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
u32 timestamp;
int err;
- rkcanfd_get_berr_counter_corrected(priv, &bec);
+ priv->devtype_data.get_berr_counter(priv, &bec);
can_state_get_by_berr_counter(ndev, &bec, &tx_state, &rx_state);
new_state = max(tx_state, rx_state);
@@ -581,7 +555,7 @@ static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
can_change_state(ndev, cf, tx_state, rx_state);
if (new_state == CAN_STATE_BUS_OFF) {
- rkcanfd_chip_stop(priv, CAN_STATE_BUS_OFF);
+ priv->devtype_data.chip_stop(priv, CAN_STATE_BUS_OFF);
can_bus_off(ndev);
}
@@ -620,7 +594,7 @@ rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
if (!skb)
return 0;
- rkcanfd_get_berr_counter_corrected(priv, &bec);
+ priv->devtype_data.get_berr_counter(priv, &bec);
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
@@ -719,21 +693,21 @@ static int rkcanfd_open(struct net_device *ndev)
if (err)
goto out_close_candev;
- rkcanfd_chip_start(priv);
+ priv->devtype_data.chip_start(priv);
can_rx_offload_enable(&priv->offload);
- err = request_irq(ndev->irq, rkcanfd_irq, IRQF_SHARED, ndev->name, priv);
+ err = request_irq(ndev->irq, priv->devtype_data.irq, IRQF_SHARED, ndev->name, priv);
if (err)
goto out_rkcanfd_chip_stop;
- rkcanfd_chip_interrupts_enable(priv);
+ priv->devtype_data.interrupts_enable(priv);
netif_start_queue(ndev);
return 0;
out_rkcanfd_chip_stop:
- rkcanfd_chip_stop_sync(priv, CAN_STATE_STOPPED);
+ priv->devtype_data.chip_stop_sync(priv, CAN_STATE_STOPPED);
pm_runtime_put(ndev->dev.parent);
out_close_candev:
close_candev(ndev);
@@ -746,10 +720,10 @@ static int rkcanfd_stop(struct net_device *ndev)
netif_stop_queue(ndev);
- rkcanfd_chip_interrupts_disable(priv);
+ priv->devtype_data.interrupts_disable(priv);
free_irq(ndev->irq, priv);
can_rx_offload_disable(&priv->offload);
- rkcanfd_chip_stop_sync(priv, CAN_STATE_STOPPED);
+ priv->devtype_data.chip_stop_sync(priv, CAN_STATE_STOPPED);
close_candev(ndev);
pm_runtime_put(ndev->dev.parent);
@@ -818,7 +792,7 @@ static int rkcanfd_register(struct rkcanfd_priv *priv)
if (err)
goto out_pm_runtime_put_sync;
- rkcanfd_register_done(priv);
+ priv->devtype_data.register_done(priv);
pm_runtime_put(ndev->dev.parent);
@@ -840,6 +814,48 @@ static inline void rkcanfd_unregister(struct rkcanfd_priv *priv)
pm_runtime_disable(ndev->dev.parent);
}
+static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v2 = {
+ .model = RKCANFD_MODEL_RK3568V2,
+ .quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_3 | RKCANFD_QUIRK_RK3568_ERRATUM_4 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_6 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_7 | RKCANFD_QUIRK_RK3568_ERRATUM_8 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_9 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
+ RKCANFD_QUIRK_CANFD_BROKEN,
+ .get_berr_counter = rkcanfd_get_berr_counter_corrected,
+ .interrupts_enable = rkcanfd_chip_interrupts_enable,
+ .interrupts_disable = rkcanfd_chip_interrupts_disable,
+ .chip_start = rkcanfd_chip_start,
+ .chip_stop = rkcanfd_chip_stop,
+ .chip_stop_sync = rkcanfd_chip_stop_sync,
+ .irq = rkcanfd_irq,
+ .register_done = rkcanfd_register_done,
+};
+
+/* The rk3568 CAN-FD errata sheet as of Tue 07 Nov 2023 11:25:31 +08:00
+ * states that only the rk3568v2 is affected by erratum 5, but tests
+ * with the rk3568v2 and rk3568v3 show that the RX_FIFO_CNT is
+ * sometimes too high. In contrast to the errata sheet mark rk3568v3
+ * as effected by erratum 5, too.
+ */
+static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = {
+ .model = RKCANFD_MODEL_RK3568V3,
+ .quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_7 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_8 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
+ RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
+ RKCANFD_QUIRK_CANFD_BROKEN,
+ .get_berr_counter = rkcanfd_get_berr_counter_corrected,
+ .interrupts_enable = rkcanfd_chip_interrupts_enable,
+ .interrupts_disable = rkcanfd_chip_interrupts_disable,
+ .chip_start = rkcanfd_chip_start,
+ .chip_stop = rkcanfd_chip_stop,
+ .chip_stop_sync = rkcanfd_chip_stop_sync,
+ .irq = rkcanfd_irq,
+ .register_done = rkcanfd_register_done,
+};
+
static const struct of_device_id rkcanfd_of_match[] = {
{
.compatible = "rockchip,rk3568v2-canfd",
diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h
index 93131c7d7f54..72f26b96add0 100644
--- a/drivers/net/can/rockchip/rockchip_canfd.h
+++ b/drivers/net/can/rockchip/rockchip_canfd.h
@@ -436,9 +436,19 @@ enum rkcanfd_model {
RKCANFD_MODEL_RK3568V3 = 0x35683,
};
+struct rkcanfd_priv;
+
struct rkcanfd_devtype_data {
enum rkcanfd_model model;
u32 quirks;
+ void (*get_berr_counter)(struct rkcanfd_priv *priv, struct can_berr_counter *bec);
+ void (*interrupts_enable)(const struct rkcanfd_priv *priv);
+ void (*interrupts_disable)(const struct rkcanfd_priv *priv);
+ void (*chip_start)(struct rkcanfd_priv *priv);
+ void (*chip_stop)(struct rkcanfd_priv *priv, const enum can_state state);
+ void (*chip_stop_sync)(struct rkcanfd_priv *priv, const enum can_state state);
+ irqreturn_t (*irq)(int irq, void *dev_id);
+ void (*register_done)(const struct rkcanfd_priv *priv);
};
struct rkcanfd_fifo_header {
--
2.34.1
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v8 3/4] net: can: rockchip: add can for RK3576 Soc
2025-10-29 3:22 [PATCH v8 0/4] rockchip: add can for RK3576 Soc Elaine Zhang
2025-10-29 3:22 ` [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 2/4] net: can: rockchip: Refactor the rkcanfd_devtype_data structure Elaine Zhang
@ 2025-10-29 3:23 ` Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 4/4] net: can: rockchip: support dma for rk3576 rx Elaine Zhang
3 siblings, 0 replies; 6+ messages in thread
From: Elaine Zhang @ 2025-10-29 3:23 UTC (permalink / raw)
To: zhangqing, mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt,
heiko, cl
Cc: linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
Is new controller, new register layout and Bit position definition:
Support CAN protocol, ISO 11898-1
Support transmit or receive error count
Support acceptance filter, more functional
Support interrupt and all interrupt can be masked
Support error code check
Support self test\silent\loop-back mode
Support auto retransmission mode
Support auto bus on after bus-off state
Support 2 transmit buffers
Support Internal Storage Mode
Support DMA
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
.../net/can/rockchip/rockchip_canfd-core.c | 419 ++++++++++++++++++
drivers/net/can/rockchip/rockchip_canfd-rx.c | 103 +++++
drivers/net/can/rockchip/rockchip_canfd-tx.c | 20 +
drivers/net/can/rockchip/rockchip_canfd.h | 258 +++++++++++
4 files changed, 800 insertions(+)
diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c
index 761cb36148ff..58fffcf97b20 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-core.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-core.c
@@ -31,6 +31,8 @@ static const char *__rkcanfd_get_model_str(enum rkcanfd_model model)
return "rk3568v2";
case RKCANFD_MODEL_RK3568V3:
return "rk3568v3";
+ case RKCAN_MODEL_RK3576:
+ return "rk3576";
}
return "<unknown>";
@@ -176,6 +178,27 @@ static void rkcanfd_get_berr_counter_corrected(struct rkcanfd_priv *priv,
!!(reg_state & RKCANFD_REG_STATE_ERROR_WARNING_STATE));
}
+static void rk3576can_get_berr_counter_corrected(struct rkcanfd_priv *priv,
+ struct can_berr_counter *bec)
+{
+ struct can_berr_counter bec_raw;
+ u32 reg_state;
+
+ bec->rxerr = rkcanfd_read(priv, RK3576CAN_REG_RXERRORCNT);
+ bec->txerr = rkcanfd_read(priv, RK3576CAN_REG_TXERRORCNT);
+ bec_raw = *bec;
+
+ priv->bec = *bec;
+
+ reg_state = rkcanfd_read(priv, RKCANFD_REG_STATE);
+ netdev_vdbg(priv->ndev,
+ "%s: Raw/Cor: txerr=%3u/%3u rxerr=%3u/%3u Bus Off=%u Warning=%u\n",
+ __func__,
+ bec_raw.txerr, bec->txerr, bec_raw.rxerr, bec->rxerr,
+ !!(reg_state & RK3576CAN_REG_STATE_BUS_OFF_STATE),
+ !!(reg_state & RK3576CAN_REG_STATE_ERROR_WARNING_STATE));
+}
+
static int rkcanfd_get_berr_counter(const struct net_device *ndev,
struct can_berr_counter *bec)
{
@@ -206,6 +229,11 @@ static void rkcanfd_chip_interrupts_disable(const struct rkcanfd_priv *priv)
rkcanfd_write(priv, RKCANFD_REG_INT_MASK, RKCANFD_REG_INT_ALL);
}
+static void rk3576can_chip_interrupts_disable(const struct rkcanfd_priv *priv)
+{
+ rkcanfd_write(priv, RK3576CAN_REG_INT_MASK, RK3576CAN_REG_INT_ALL);
+}
+
static void rkcanfd_chip_fifo_setup(struct rkcanfd_priv *priv)
{
u32 reg;
@@ -220,6 +248,48 @@ static void rkcanfd_chip_fifo_setup(struct rkcanfd_priv *priv)
netdev_reset_queue(priv->ndev);
}
+static void rk3576can_chip_fifo_setup(struct rkcanfd_priv *priv)
+{
+ u32 reg_ism, reg_water;
+
+ reg_ism = FIELD_PREP(RK3576CAN_REG_STR_CTL_ISM_SEL,
+ RK3576CAN_REG_STR_CTL_ISM_SEL_CANFD_FIXED) |
+ RK3576CAN_REG_STR_CTL_STORAGE_TIMEOUT_MODE;
+ reg_water = RK3576CAN_ISM_WATERMASK_CANFD;
+
+ /* internal sram mode */
+ rkcanfd_write(priv, RK3576CAN_REG_STR_CTL, reg_ism);
+ rkcanfd_write(priv, RK3576CAN_REG_STR_WTM, reg_water);
+ WRITE_ONCE(priv->tx_head, 0);
+ WRITE_ONCE(priv->tx_tail, 0);
+ netdev_reset_queue(priv->ndev);
+}
+
+static void rk3576can_atf_config(struct rkcanfd_priv *priv, int mode)
+{
+ int i;
+
+ switch (mode) {
+ case RK3576CAN_REG_ATFM_MASK_SEL_MASK_MODE:
+ for (i = 0; i < 5; i++) {
+ rkcanfd_write(priv, RK3576CAN_REG_ATF(i), 0);
+ rkcanfd_write(priv, RK3576CAN_REG_ATFM(i), RK3576CAN_REG_ATFM_ID);
+ }
+ break;
+ case RK3576CAN_REG_ATFM_MASK_SEL_LIST_MODE:
+ for (i = 0; i < 5; i++) {
+ rkcanfd_write(priv, RK3576CAN_REG_ATF(i), 0);
+ rkcanfd_write(priv, RK3576CAN_REG_ATFM(i), RK3576CAN_REG_ATFM_MASK_SEL);
+ }
+ break;
+ default:
+ rkcanfd_write(priv, RK3576CAN_REG_ATF_CTL, RK3576CAN_REG_ATF_CTL_ATF_DIS_ALL);
+ return;
+ }
+
+ rkcanfd_write(priv, RK3576CAN_REG_ATF_CTL, 0);
+}
+
static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
{
u32 reg;
@@ -285,6 +355,61 @@ static void rkcanfd_chip_start(struct rkcanfd_priv *priv)
rkcanfd_read(priv, RKCANFD_REG_MODE));
}
+static void rk3576can_chip_start(struct rkcanfd_priv *priv)
+
+{
+ u32 reg;
+
+ rkcanfd_chip_set_reset_mode(priv);
+
+ /* Receiving Filter: accept all */
+ rk3576can_atf_config(priv, RK3576CAN_REG_ATFM_MASK_SEL_MASK_MODE);
+
+ /* enable:
+ * - WORK_MODE: transition from reset to working mode
+ */
+ reg = rkcanfd_read(priv, RKCANFD_REG_MODE);
+ priv->reg_mode_default = reg | RKCANFD_REG_MODE_WORK_MODE;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ priv->reg_mode_default |= RKCANFD_REG_MODE_LBACK_MODE;
+ rkcanfd_write(priv, RK3576CAN_REG_ERROR_MASK,
+ RK3576CAN_REG_ERROR_MASK_ACK_ERROR);
+ }
+
+ /* mask, i.e. ignore:
+ * - RX_FINISH_INT - Rx finish interrupt
+ */
+ priv->reg_int_mask_default = RK3576CAN_REG_INT_RX_FINISH_INT;
+
+ /* Do not mask the bus error interrupt if the bus error
+ * reporting is requested.
+ */
+ if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+ priv->reg_int_mask_default |= RKCANFD_REG_INT_ERROR_INT;
+
+ memset(&priv->bec, 0x0, sizeof(priv->bec));
+
+ rk3576can_chip_fifo_setup(priv);
+
+ rkcanfd_write(priv, RK3576CAN_REG_AUTO_RETX_CFG,
+ RK3576CAN_REG_AUTO_RETX_CFG_AUTO_RETX_EN);
+
+ rkcanfd_write(priv, RK3576CAN_REG_BRS_CFG,
+ RK3576CAN_REG_BRS_CFG_BRS_NEGSYNC_EN |
+ RK3576CAN_REG_BRS_CFG_BRS_POSSYNC_EN);
+
+ rkcanfd_set_bittiming(priv);
+
+ priv->devtype_data.interrupts_disable(priv);
+ rkcanfd_chip_set_work_mode(priv);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ netdev_dbg(priv->ndev, "%s: reg_mode=0x%08x\n", __func__,
+ rkcanfd_read(priv, RKCANFD_REG_MODE));
+}
+
static void __rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state state)
{
priv->can.state = state;
@@ -301,6 +426,13 @@ static void rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state st
__rkcanfd_chip_stop(priv, state);
}
+static void rk3576can_chip_stop(struct rkcanfd_priv *priv, const enum can_state state)
+{
+ priv->can.state = state;
+
+ __rkcanfd_chip_stop(priv, state);
+}
+
static void rkcanfd_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_state state)
{
priv->can.state = state;
@@ -309,6 +441,13 @@ static void rkcanfd_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_sta
__rkcanfd_chip_stop(priv, state);
}
+static void rk3576can_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_state state)
+{
+ priv->can.state = state;
+
+ __rkcanfd_chip_stop(priv, state);
+}
+
static int rkcanfd_set_mode(struct net_device *ndev,
enum can_mode mode)
{
@@ -364,6 +503,9 @@ static const char *rkcanfd_get_error_type_str(unsigned int type)
#define RKCAN_ERROR_CODE(reg_ec, code) \
((reg_ec) & RKCANFD_REG_ERROR_CODE_##code ? __stringify(code) " " : "")
+#define RK3576CAN_ERROR_CODE(reg_ec, code) \
+ ((reg_ec) & RK3576CAN_REG_ERROR_CODE_##code ? __stringify(code) " " : "")
+
static void
rkcanfd_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
const u32 reg_ec)
@@ -493,6 +635,128 @@ rkcanfd_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
}
}
+static void
+rk3576can_handle_error_int_reg_ec(struct rkcanfd_priv *priv, struct can_frame *cf,
+ const u32 reg_ec)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ unsigned int type;
+ u32 reg_state, reg_cmd;
+
+ type = FIELD_GET(RK3576CAN_REG_ERROR_CODE_TYPE, reg_ec);
+ reg_cmd = rkcanfd_read(priv, RK3576CAN_REG_CMD);
+ reg_state = rkcanfd_read(priv, RK3576CAN_REG_STATE);
+
+ netdev_dbg(priv->ndev, "%s Error in %s %s Phase: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s(0x%08x) CMD=%u RX=%u TX=%u Error-Warning=%u Bus-Off=%u\n",
+ rkcanfd_get_error_type_str(type),
+ reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX ? "RX" : "TX",
+ reg_ec & RK3576CAN_REG_ERROR_CODE_PHASE ? "Data" : "Arbitration",
+ RK3576CAN_ERROR_CODE(reg_ec, TX_ACK_EOF),
+ RK3576CAN_ERROR_CODE(reg_ec, TX_CRC),
+ RK3576CAN_ERROR_CODE(reg_ec, TX_STUFF_COUNT),
+ RK3576CAN_ERROR_CODE(reg_ec, TX_DATA),
+ RK3576CAN_ERROR_CODE(reg_ec, TX_SOF_DLC),
+ RK3576CAN_ERROR_CODE(reg_ec, TX_IDLE),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_ERROR),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_OVERLOAD),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_SPACE),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_EOF),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_ACK_LIM),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_ACK),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_CRC_LIM),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_CRC),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_STUFF_COUNT),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_DATA),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_DLC),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_BRS_ESI),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_RES),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_FDF),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_ID2_RTR),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_SOF_IDE),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_BUS_IDLE),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_BUS_INT),
+ RK3576CAN_ERROR_CODE(reg_ec, RX_STOP),
+ reg_ec, reg_cmd,
+ !!(reg_state & RK3576CAN_REG_STATE_RX_PERIOD),
+ !!(reg_state & RK3576CAN_REG_STATE_TX_PERIOD),
+ !!(reg_state & RK3576CAN_REG_STATE_ERROR_WARNING_STATE),
+ !!(reg_state & RK3576CAN_REG_STATE_BUS_OFF_STATE));
+
+ priv->can.can_stats.bus_error++;
+
+ if (reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX)
+ stats->rx_errors++;
+ else
+ stats->tx_errors++;
+
+ if (!cf)
+ return;
+
+ if (reg_ec & RK3576CAN_REG_ERROR_CODE_DIRECTION_RX) {
+ if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_SOF_IDE)
+ cf->data[3] = CAN_ERR_PROT_LOC_SOF;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ID2_RTR)
+ cf->data[3] = CAN_ERR_PROT_LOC_RTR;
+ /* RKCANFD_REG_ERROR_CODE_RX_FDF */
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_RES)
+ cf->data[3] = CAN_ERR_PROT_LOC_RES0;
+ /* RKCANFD_REG_ERROR_CODE_RX_BRS_ESI */
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_DLC)
+ cf->data[3] = CAN_ERR_PROT_LOC_DLC;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_DATA)
+ cf->data[3] = CAN_ERR_PROT_LOC_DATA;
+ /* RKCANFD_REG_ERROR_CODE_RX_STUFF_COUNT */
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_CRC)
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_CRC_LIM)
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ACK)
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_ACK_LIM)
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_EOF)
+ cf->data[3] = CAN_ERR_PROT_LOC_EOF;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_RX_SPACE)
+ cf->data[3] = CAN_ERR_PROT_LOC_EOF;
+ } else {
+ cf->data[2] |= CAN_ERR_PROT_TX;
+
+ if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_SOF_DLC)
+ cf->data[3] = CAN_ERR_PROT_LOC_SOF;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_DATA)
+ cf->data[3] = CAN_ERR_PROT_LOC_DATA;
+ /* RKCANFD_REG_ERROR_CODE_TX_STUFF_COUNT */
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_CRC)
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+ else if (reg_ec & RK3576CAN_REG_ERROR_CODE_TX_ACK_EOF)
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
+ }
+
+ switch (reg_ec & RK3576CAN_REG_ERROR_CODE_TYPE) {
+ case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
+ RK3576CAN_REG_ERROR_CODE_TYPE_BIT):
+
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ break;
+ case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
+ RK3576CAN_REG_ERROR_CODE_TYPE_STUFF):
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
+ RK3576CAN_REG_ERROR_CODE_TYPE_FORM):
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
+ RK3576CAN_REG_ERROR_CODE_TYPE_ACK):
+ cf->can_id |= CAN_ERR_ACK;
+ break;
+ case FIELD_PREP_CONST(RK3576CAN_REG_ERROR_CODE_TYPE,
+ RK3576CAN_REG_ERROR_CODE_TYPE_CRC):
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+ break;
+ }
+}
+
static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
@@ -530,6 +794,41 @@ static int rkcanfd_handle_error_int(struct rkcanfd_priv *priv)
return 0;
}
+static int rkcanfd_handle_rk3576_error_int(struct rkcanfd_priv *priv)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ struct can_frame *cf = NULL;
+ u32 reg_ec;
+ struct sk_buff *skb;
+ int err;
+
+ reg_ec = rkcanfd_read(priv, RK3576CAN_REG_ERROR_CODE);
+ if (!reg_ec)
+ return 0;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
+ skb = alloc_can_err_skb(priv->ndev, &cf);
+ if (cf) {
+ struct can_berr_counter bec;
+
+ priv->devtype_data.get_berr_counter(priv, &bec);
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ }
+ }
+
+ rk3576can_handle_error_int_reg_ec(priv, cf, reg_ec);
+ if (!cf)
+ return 0;
+
+ err = can_rx_offload_queue_tail(&priv->offload, skb);
+ if (err)
+ stats->rx_fifo_errors++;
+
+ return 0;
+}
+
static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
@@ -575,6 +874,50 @@ static int rkcanfd_handle_state_error_int(struct rkcanfd_priv *priv)
return 0;
}
+static int rkcanfd_handle_rk3576_state_error_int(struct rkcanfd_priv *priv)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ enum can_state new_state, rx_state, tx_state;
+ struct net_device *ndev = priv->ndev;
+ struct can_berr_counter bec;
+ struct can_frame *cf = NULL;
+ struct sk_buff *skb;
+ int err;
+
+ priv->devtype_data.get_berr_counter(priv, &bec);
+ can_state_get_by_berr_counter(ndev, &bec, &tx_state, &rx_state);
+
+ new_state = max(tx_state, rx_state);
+ if (new_state == priv->can.state)
+ return 0;
+
+ /* The skb allocation might fail, but can_change_state()
+ * handles cf == NULL.
+ */
+ skb = alloc_can_err_skb(priv->ndev, &cf);
+ can_change_state(ndev, cf, tx_state, rx_state);
+
+ if (new_state == CAN_STATE_BUS_OFF) {
+ priv->devtype_data.chip_stop(priv, CAN_STATE_BUS_OFF);
+ can_bus_off(ndev);
+ }
+
+ if (!skb)
+ return 0;
+
+ if (new_state != CAN_STATE_BUS_OFF) {
+ cf->can_id |= CAN_ERR_CNT;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ }
+
+ err = can_rx_offload_queue_tail(&priv->offload, skb);
+ if (err)
+ stats->rx_fifo_errors++;
+
+ return 0;
+}
+
static int
rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
{
@@ -621,6 +964,55 @@ rkcanfd_handle_rx_fifo_overflow_int(struct rkcanfd_priv *priv)
err; \
})
+static irqreturn_t rk3576can_irq(int irq, void *dev_id)
+{
+ struct rkcanfd_priv *priv = dev_id;
+ u32 reg_int_unmasked, reg_int;
+
+ reg_int_unmasked = rkcanfd_read(priv, RK3576CAN_REG_INT);
+ reg_int = reg_int_unmasked & ~priv->reg_int_mask_default;
+
+ if (!reg_int)
+ return IRQ_NONE;
+
+ rkcanfd_write(priv, RK3576CAN_REG_INT, reg_int);
+
+ if (reg_int & (RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT |
+ RK3576CAN_REG_INT_ISM_WTM_INT |
+ RK3576CAN_REG_INT_RX_FIFO_FULL_INT)) {
+ rkcanfd_write(priv, RK3576CAN_REG_INT_MASK,
+ priv->reg_int_mask_default | RK3576CAN_REG_INT_ISM_WTM_INT |
+ RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT |
+ RK3576CAN_REG_INT_RX_FINISH_INT);
+ rkcanfd_handle(priv, rk3576_rx_int);
+ }
+
+ if (reg_int & RK3576CAN_REG_INT_TX_FINISH_INT)
+ rkcanfd_handle(priv, rk3576_tx_int);
+
+ if (reg_int & RK3576CAN_REG_INT_ERROR_INT)
+ rkcanfd_handle(priv, rk3576_error_int);
+
+ if (reg_int & (RK3576CAN_REG_INT_BUS_OFF_INT |
+ RK3576CAN_REG_INT_PASSIVE_ERROR_INT |
+ RK3576CAN_REG_INT_ERROR_WARNING_INT) ||
+ priv->can.state > CAN_STATE_ERROR_ACTIVE)
+ rkcanfd_handle(priv, rk3576_state_error_int);
+
+ if (reg_int & RK3576CAN_REG_INT_WAKEUP_INT)
+ netdev_info(priv->ndev, "%s: WAKEUP_INT\n", __func__);
+
+ if (reg_int & RK3576CAN_REG_INT_BUS_OFF_RECOVERY_INT)
+ netdev_info(priv->ndev, "%s: BUS_OFF_RECOVERY_INT\n", __func__);
+
+ if (reg_int & RK3576CAN_REG_INT_OVERLOAD_INT)
+ netdev_info(priv->ndev, "%s: OVERLOAD_INT\n", __func__);
+
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t rkcanfd_irq(int irq, void *dev_id)
{
struct rkcanfd_priv *priv = dev_id;
@@ -775,6 +1167,16 @@ static void rkcanfd_register_done(const struct rkcanfd_priv *priv)
RKCANFD_ERRATUM_5_SYSCLOCK_HZ_MIN / MEGA);
}
+static void rk3576can_register_done(const struct rkcanfd_priv *priv)
+{
+ u32 dev_id;
+
+ dev_id = rkcanfd_read(priv, RK3576CAN_REG_RTL_VERSION);
+ netdev_info(priv->ndev,
+ "Rockchip-CANFD %s rev%u.\n",
+ rkcanfd_get_model_str(priv), dev_id);
+}
+
static int rkcanfd_register(struct rkcanfd_priv *priv)
{
struct net_device *ndev = priv->ndev;
@@ -856,6 +1258,20 @@ static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = {
.register_done = rkcanfd_register_done,
};
+/* The rk3576 CAN-FD */
+static const struct rkcanfd_devtype_data rkcan_devtype_data_rk3576 = {
+ .model = RKCAN_MODEL_RK3576,
+ .quirks = RKCANFD_QUIRK_CANFD_BROKEN,
+ .get_berr_counter = rk3576can_get_berr_counter_corrected,
+ .interrupts_enable = rkcanfd_chip_interrupts_enable,
+ .interrupts_disable = rk3576can_chip_interrupts_disable,
+ .chip_start = rk3576can_chip_start,
+ .chip_stop = rk3576can_chip_stop,
+ .chip_stop_sync = rk3576can_chip_stop_sync,
+ .irq = rk3576can_irq,
+ .register_done = rk3576can_register_done,
+};
+
static const struct of_device_id rkcanfd_of_match[] = {
{
.compatible = "rockchip,rk3568v2-canfd",
@@ -863,6 +1279,9 @@ static const struct of_device_id rkcanfd_of_match[] = {
}, {
.compatible = "rockchip,rk3568v3-canfd",
.data = &rkcanfd_devtype_data_rk3568v3,
+ }, {
+ .compatible = "rockchip,rk3576-can",
+ .data = &rkcan_devtype_data_rk3576,
}, {
/* sentinel */
},
diff --git a/drivers/net/can/rockchip/rockchip_canfd-rx.c b/drivers/net/can/rockchip/rockchip_canfd-rx.c
index 475c0409e215..6bc4b0185502 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-rx.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-rx.c
@@ -91,6 +91,47 @@ rkcanfd_fifo_header_to_cfd_header(const struct rkcanfd_priv *priv,
return len + cfd->len;
}
+static unsigned int
+rk3576can_fifo_header_to_cfd_header(const struct rkcanfd_priv *priv,
+ const struct rk3576can_fifo_header *header,
+ struct canfd_frame *cfd)
+{
+ unsigned int len = sizeof(*cfd) - sizeof(cfd->data);
+ u8 dlc;
+
+ if (header->frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FRAME_FORMAT)
+ cfd->can_id = FIELD_GET(RKCANFD_REG_FD_ID_EFF, header->id) |
+ CAN_EFF_FLAG;
+ else
+ cfd->can_id = FIELD_GET(RKCANFD_REG_FD_ID_SFF, header->id);
+
+ dlc = FIELD_GET(RK3576CAN_REG_RXFRD_FRAMEINFO_DATA_LENGTH,
+ header->frameinfo);
+
+ /* CAN-FD */
+ if (header->frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FDF) {
+ cfd->len = can_fd_dlc2len(dlc);
+
+ /* The cfd is not allocated by alloc_canfd_skb(), so
+ * set CANFD_FDF here.
+ */
+ cfd->flags |= CANFD_FDF;
+
+ if (header->frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_BRS)
+ cfd->flags |= CANFD_BRS;
+ } else {
+ cfd->len = can_cc_dlc2len(dlc);
+
+ if (header->frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_RTR) {
+ cfd->can_id |= CAN_RTR_FLAG;
+
+ return len;
+ }
+ }
+
+ return len + cfd->len;
+}
+
static int rkcanfd_rxstx_filter(struct rkcanfd_priv *priv,
const struct canfd_frame *cfd_rx, const u32 ts,
bool *tx_done)
@@ -198,6 +239,44 @@ rkcanfd_fifo_header_empty(const struct rkcanfd_fifo_header *header)
header->frameinfo == header->ts;
}
+static int rk3576can_handle_rx_int_one(struct rkcanfd_priv *priv)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ struct canfd_frame cfd[1] = { }, *skb_cfd;
+ struct rk3576can_fifo_header header[1] = { };
+ struct sk_buff *skb;
+ unsigned int len;
+ int err;
+
+ /* read header into separate struct and convert it later */
+ rkcanfd_read_rep(priv, RKCANFD_REG_RX_FIFO_RDATA,
+ header, sizeof(*header));
+ /* read data directly into cfd */
+ rkcanfd_read_rep(priv, RKCANFD_REG_RX_FIFO_RDATA,
+ cfd->data, sizeof(cfd->data));
+
+ len = rk3576can_fifo_header_to_cfd_header(priv, header, cfd);
+
+ if (header->frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FDF)
+ skb = alloc_canfd_skb(priv->ndev, &skb_cfd);
+ else
+ skb = alloc_can_skb(priv->ndev, (struct can_frame **)&skb_cfd);
+
+ if (!skb) {
+ stats->rx_dropped++;
+
+ return 0;
+ }
+
+ memcpy(skb_cfd, cfd, len);
+
+ err = can_rx_offload_queue_tail(&priv->offload, skb);
+ if (err)
+ stats->rx_fifo_errors++;
+
+ return 0;
+}
+
static int rkcanfd_handle_rx_int_one(struct rkcanfd_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
@@ -284,6 +363,15 @@ rkcanfd_rx_fifo_get_len(const struct rkcanfd_priv *priv)
return FIELD_GET(RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT, reg);
}
+static inline unsigned int
+rk3576can_rx_fifo_get_len(const struct rkcanfd_priv *priv)
+{
+ const u32 reg = rkcanfd_read(priv, RK3576CAN_REG_STR_STATE);
+ int val = FIELD_GET(RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT, reg);
+
+ return DIV_ROUND_UP(val, RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
+}
+
int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv)
{
unsigned int len;
@@ -297,3 +385,18 @@ int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv)
return 0;
}
+
+int rkcanfd_handle_rk3576_rx_int(struct rkcanfd_priv *priv)
+{
+ unsigned int len;
+ int err;
+
+ while ((len = rk3576can_rx_fifo_get_len(priv))) {
+ err = rk3576can_handle_rx_int_one(priv);
+ if (err)
+ return err;
+ }
+ rkcanfd_write(priv, RK3576CAN_REG_INT_MASK, priv->reg_int_mask_default);
+ return 0;
+}
+
diff --git a/drivers/net/can/rockchip/rockchip_canfd-tx.c b/drivers/net/can/rockchip/rockchip_canfd-tx.c
index 12200dcfd338..de2f673c31ed 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-tx.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-tx.c
@@ -165,3 +165,23 @@ void rkcanfd_handle_tx_done_one(struct rkcanfd_priv *priv, const u32 ts,
frame_len_p);
stats->tx_packets++;
}
+
+int rkcanfd_handle_rk3576_tx_int(struct rkcanfd_priv *priv)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ unsigned int tx_tail;
+ unsigned int frame_len = 0;
+
+ tx_tail = rkcanfd_get_tx_tail(priv);
+
+ stats->tx_bytes +=
+ can_rx_offload_get_echo_skb_queue_tail(&priv->offload,
+ tx_tail, &frame_len);
+ stats->tx_packets++;
+ WRITE_ONCE(priv->tx_tail, priv->tx_tail + 1);
+ netif_subqueue_completed_wake(priv->ndev, 0, 1, frame_len,
+ rkcanfd_get_effective_tx_free(priv),
+ RKCANFD_TX_START_THRESHOLD);
+ return 0;
+}
+
diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h
index 72f26b96add0..77c673cfea3b 100644
--- a/drivers/net/can/rockchip/rockchip_canfd.h
+++ b/drivers/net/can/rockchip/rockchip_canfd.h
@@ -287,6 +287,256 @@
#define RKCANFD_REG_RX_FIFO_RDATA 0x400
#define RKCANFD_REG_TXE_FIFO_RDATA 0x500
+#define RK3576CAN_REG_MODE 0x000
+#define RK3576CAN_REG_CMD 0x004
+
+#define RK3576CAN_REG_STATE 0x008
+#define RK3576CAN_REG_STATE_SLEEP_STATE BIT(5)
+#define RK3576CAN_REG_STATE_BUS_OFF_STATE BIT(4)
+#define RK3576CAN_REG_STATE_ERROR_WARNING_STATE BIT(3)
+#define RK3576CAN_REG_STATE_TX_PERIOD BIT(2)
+#define RK3576CAN_REG_STATE_RX_PERIOD BIT(1)
+#define RK3576CAN_REG_STATE_TX_BUFFER_FULL BIT(0)
+
+#define RK3576CAN_REG_INT 0x00c
+#define RK3576CAN_REG_INT_BUSOFF_RCY_INT BIT(19)
+#define RK3576CAN_REG_INT_ESM_WTM_INT BIT(18)
+#define RK3576CAN_REG_INT_ISM_WTM_INT BIT(17)
+#define RK3576CAN_REG_INT_BUSINT_INT BIT(16)
+#define RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT BIT(15)
+#define RK3576CAN_REG_INT_MFI_TIMEOUT_INT BIT(14)
+#define RK3576CAN_REG_INT_MFI_INT BIT(13)
+#define RK3576CAN_REG_INT_AUTO_RETX_FAIL_INT BIT(12)
+#define RK3576CAN_REG_INT_WAKEUP_INT BIT(11)
+#define RK3576CAN_REG_INT_BUS_OFF_RECOVERY_INT BIT(10)
+#define RK3576CAN_REG_INT_BUS_OFF_INT BIT(9)
+#define RK3576CAN_REG_INT_RX_FIFO_OVERFLOW_INT BIT(8)
+#define RK3576CAN_REG_INT_RX_FIFO_FULL_INT BIT(7)
+#define RK3576CAN_REG_INT_ERROR_INT BIT(6)
+#define RK3576CAN_REG_INT_TX_ARBIT_FAIL_INT BIT(5)
+#define RK3576CAN_REG_INT_PASSIVE_ERROR_INT BIT(4)
+#define RK3576CAN_REG_INT_OVERLOAD_INT BIT(3)
+#define RK3576CAN_REG_INT_ERROR_WARNING_INT BIT(2)
+#define RK3576CAN_REG_INT_TX_FINISH_INT BIT(1)
+#define RK3576CAN_REG_INT_RX_FINISH_INT BIT(0)
+
+#define RK3576CAN_REG_INT_ALL \
+ (RK3576CAN_REG_INT_BUSOFF_RCY_INT | \
+ RK3576CAN_REG_INT_ESM_WTM_INT | \
+ RK3576CAN_REG_INT_ISM_WTM_INT | \
+ RK3576CAN_REG_INT_BUSINT_INT | \
+ RK3576CAN_REG_INT_RXSTR_TIMEOUT_INT | \
+ RK3576CAN_REG_INT_MFI_TIMEOUT_INT | \
+ RK3576CAN_REG_INT_MFI_INT | \
+ RK3576CAN_REG_INT_AUTO_RETX_FAIL_INT | \
+ RK3576CAN_REG_INT_WAKEUP_INT | \
+ RK3576CAN_REG_INT_BUS_OFF_RECOVERY_INT | \
+ RK3576CAN_REG_INT_BUS_OFF_INT | \
+ RK3576CAN_REG_INT_RX_FIFO_OVERFLOW_INT | \
+ RK3576CAN_REG_INT_RX_FIFO_FULL_INT | \
+ RK3576CAN_REG_INT_ERROR_INT | \
+ RK3576CAN_REG_INT_TX_ARBIT_FAIL_INT | \
+ RK3576CAN_REG_INT_PASSIVE_ERROR_INT | \
+ RK3576CAN_REG_INT_OVERLOAD_INT | \
+ RK3576CAN_REG_INT_ERROR_WARNING_INT | \
+ RK3576CAN_REG_INT_TX_FINISH_INT | \
+ RK3576CAN_REG_INT_RX_FINISH_INT)
+
+#define RK3576CAN_REG_INT_ALL_ERROR \
+ (RK3576CAN_REG_INT_BUS_OFF_INT | \
+ RK3576CAN_REG_INT_ERROR_INT | \
+ RK3576CAN_REG_INT_PASSIVE_ERROR_INT | \
+ RK3576CAN_REG_INT_ERROR_WARNING_INT)
+
+#define RK3576CAN_REG_INT_MASK 0x010
+
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING 0x100
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING_SAMPLE_MODE BIT(31)
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING_SJW GENMASK(30, 24)
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING_BRP GENMASK(23, 16)
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING_TSEG2 GENMASK(14, 8)
+#define RK3576CAN_REG_FD_NOMINAL_BITTIMING_TSEG1 GENMASK(7, 0)
+
+#define RK3576CAN_REG_FD_DATA_BITTIMING 0x104
+#define RK3576CAN_REG_FD_DATA_BITTIMING_BRS_TSEG1 GENMASK(31, 24)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_BRS_MODE BIT(23)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_ACKSLOT_SYNC_DIS BIT(22)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_SJW GENMASK(20, 17)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_BRP GENMASK(16, 9)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_TSEG2 GENMASK(8, 5)
+#define RK3576CAN_REG_FD_DATA_BITTIMING_TSEG1 GENMASK(4, 0)
+
+#define RK3576CAN_REG_TRANSMIT_DELAY_COMPENSATION 0x108
+#define RK3576CAN_REG_TRANSMIT_DELAY_COMPENSATION_TDC_OFFSET GENMASK(6, 1)
+#define RK3576CAN_REG_TRANSMIT_DELAY_COMPENSATION_TDC_ENABLE BIT(0)
+
+#define RK3576CAN_REG_BRS_CFG 0x10c
+#define RK3576CAN_REG_BRS_CFG_TRIPLE_SYNC_MODE BIT(31)
+#define RK3576CAN_REG_BRS_CFG_SP2_DTSEG1 GENMASK(30, 26)
+#define RK3576CAN_REG_BRS_CFG_SP2_NTSEG1 GENMASK(25, 18)
+#define RK3576CAN_REG_BRS_CFG_SP1_DTSEG1 GENMASK(17, 13)
+#define RK3576CAN_REG_BRS_CFG_SP1_NTSEG1 GENMASK(12, 5)
+#define RK3576CAN_REG_BRS_CFG_RESYNC_MODE BIT(3)
+#define RK3576CAN_REG_BRS_CFG_BRS_POSSYNC_EN BIT(1)
+#define RK3576CAN_REG_BRS_CFG_BRS_NEGSYNC_EN BIT(0)
+
+#define RK3576CAN_REG_LOOP_CNT 0x110
+
+#define RK3576CAN_REG_DMA_CTRL 0x11c
+#define RK3576CAN_REG_DMA_CTRL_DMA_RX_EN BIT(9)
+#define RK3576CAN_REG_DMA_CTRL_DMA_THR GENMASK(8, 0)
+
+#define RK3576CAN_REG_FD_TXFRAMEINFO 0x200
+
+#define RK3576CAN_REG_FD_TXID 0x204
+#define RK3576CAN_REG_FD_ID_EFF GENMASK(28, 0)
+#define RK3576CAN_REG_FD_ID_SFF GENMASK(11, 0)
+
+#define RK3576CAN_REG_FD_TXDATA0 0x208
+#define RK3576CAN_REG_FD_TXDATA1 0x20c
+#define RK3576CAN_REG_FD_TXDATA2 0x210
+#define RK3576CAN_REG_FD_TXDATA3 0x214
+#define RK3576CAN_REG_FD_TXDATA4 0x218
+#define RK3576CAN_REG_FD_TXDATA5 0x21c
+#define RK3576CAN_REG_FD_TXDATA6 0x220
+#define RK3576CAN_REG_FD_TXDATA7 0x224
+#define RK3576CAN_REG_FD_TXDATA8 0x228
+#define RK3576CAN_REG_FD_TXDATA9 0x22c
+#define RK3576CAN_REG_FD_TXDATA10 0x230
+#define RK3576CAN_REG_FD_TXDATA11 0x234
+#define RK3576CAN_REG_FD_TXDATA12 0x238
+#define RK3576CAN_REG_FD_TXDATA13 0x23c
+#define RK3576CAN_REG_FD_TXDATA14 0x240
+#define RK3576CAN_REG_FD_TXDATA15 0x244
+
+#define RK3576CAN_REG_RXFRD 0x400
+#define RK3576CAN_REG_RXFRD_FRAMEINFO_FRAME_FORMAT BIT(23)
+#define RK3576CAN_REG_RXFRD_FRAMEINFO_RTR BIT(22)
+#define RK3576CAN_REG_RXFRD_FRAMEINFO_FDF BIT(21)
+#define RK3576CAN_REG_RXFRD_FRAMEINFO_BRS BIT(20)
+#define RK3576CAN_REG_RXFRD_FRAMEINFO_DATA_LENGTH GENMASK(27, 24)
+
+#define RK3576CAN_REG_STR_CTL 0x600
+#define RK3576CAN_REG_STR_CTL_STORAGE_TIMEOUT_MODE BIT(8)
+#define RK3576CAN_REG_STR_CTL_ESM_SEL_MASK GENMASK(7, 6)
+#define RK3576CAN_REG_STR_CTL_RX_STORAGE_RESET BIT(4)
+#define RK3576CAN_REG_STR_CTL_ISM_SEL GENMASK(3, 2)
+#define RK3576CAN_REG_STR_CTL_ISM_SEL_FLEXIBLE 0x0
+#define RK3576CAN_REG_STR_CTL_ISM_SEL_CAN_FIXED 0x1
+#define RK3576CAN_REG_STR_CTL_ISM_SEL_CANFD_FIXED 0x2
+#define RK3576CAN_REG_STR_CTL_EXT_STORAGE_MODE BIT(1)
+#define RK3576CAN_REG_STR_CTL_BUFFER_MODE_ENABLE BIT(0)
+
+#define RK3576CAN_REG_STR_STATE 0x604
+#define RK3576CAN_REG_STR_STATE_INTM_FRAME_CNT GENMASK(25, 17)
+#define RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT GENMASK(16, 8)
+#define RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT 18
+#define RK3576CAN_REG_STR_STATE_EXTM_FULL BIT(3)
+#define RK3576CAN_REG_STR_STATE_EXTM_EMPTY BIT(2)
+#define RK3576CAN_REG_STR_STATE_INTM_FULL BIT(1)
+#define RK3576CAN_REG_STR_STATE_INTM_EMPTY BIT(0)
+
+#define RK3576CAN_REG_STR_TIMEOUT 0x608
+
+#define RK3576CAN_REG_STR_WTM 0x60c
+#define RK3576CAN_REG_ATF(n) (0x700 + ((n) << 2))
+#define RK3576CAN_REG_ATFM(n) (0x714 + ((n) << 2))
+#define RK3576CAN_REG_ATFM_MASK_SEL BIT(31)
+#define RK3576CAN_REG_ATFM_RTR_EN BIT(30)
+#define RK3576CAN_REG_ATFM_RTR BIT(29)
+#define RK3576CAN_REG_ATFM_MASK_SEL_MASK_MODE 0x0
+#define RK3576CAN_REG_ATFM_MASK_SEL_LIST_MODE 0x1
+#define RK3576CAN_REG_ATFM_ID GENMASK(28, 0)
+
+#define RK3576CAN_REG_ATF_DLC 0x728
+#define RK3576CAN_REG_ATF_DLC_ATF_DLC_MODE BIT(5)
+#define RK3576CAN_REG_ATF_DLC_ATF_DLC_EN BIT(4)
+#define RK3576CAN_REG_ATF_DLC_ATF_DLC GENMASK(3, 0)
+
+#define RK3576CAN_REG_ATF_CTL 0x72c
+#define RK3576CAN_REG_ATF_CTL_ATF_DIS(n) BIT(n)
+#define RK3576CAN_REG_ATF_CTL_ATF_DIS_ALL GENMASK(15, 0)
+
+#define RK3576CAN_REG_SPACE_CTRL 0x800
+
+#define RK3576CAN_REG_AUTO_RETX_CFG 0x808
+#define RK3576CAN_REG_AUTO_RETX_CFG_RETX_TIME_LIMIT GENMASK(18, 3)
+#define RK3576CAN_REG_AUTO_RETX_CFG_RETX_LIMIT_EN BIT(1)
+#define RK3576CAN_REG_AUTO_RETX_CFG_AUTO_RETX_EN BIT(0)
+
+#define RK3576CAN_REG_AUTO_RETX_STATE0 0x80c
+#define RK3576CAN_REG_AUTO_RETX_STATE0_AUTO_RETX_CNT GENMASK(15, 0)
+
+#define RK3576CAN_REG_AUTO_RETX_STATE1 0x810
+#define RK3576CAN_REG_OLF_CFG 0x814
+#define RK3576CAN_REG_RXINT_CTRL 0x818
+#define RK3576CAN_REG_RXINT_TIMEOUT 0x81c
+#define RK3576CAN_REG_OTHER_CFG 0x820
+#define RK3576CAN_REG_WAVE_FILTER_CFG 0x824
+#define RK3576CAN_REG_RBC_CFG 0x828
+#define RK3576CAN_REG_TXCRC_CFG 0x82c
+
+#define RK3576CAN_REG_BUSOFFRCY_CFG 0x830
+#define RK3576CAN_REG_BUSOFF_RCY_THR 0x834
+
+#define RK3576CAN_REG_ERROR_CODE 0x900
+#define RK3576CAN_REG_ERROR_MASK 0x904
+#define RK3576CAN_REG_ERROR_MASK_ACK_ERROR BIT(4)
+#define RK3576CAN_REG_ERROR_MASK_FORM_ERROR BIT(3)
+#define RK3576CAN_REG_ERROR_MASK_CRC_ERROR BIT(2)
+#define RK3576CAN_REG_ERROR_MASK_STUFF_ERROR BIT(1)
+#define RK3576CAN_REG_ERROR_MASK_BIT_ERROR BIT(0)
+
+#define RK3576CAN_REG_RXERRORCNT 0x910
+#define RK3576CAN_REG_TXERRORCNT 0x914
+#define RK3576CAN_REG_RX_RXSRAM_RDATA 0xc00
+#define RK3576CAN_REG_RTL_VERSION 0xf0c
+
+#define RK3576CAN_REG_ERROR_CODE_PHASE BIT(29)
+#define RK3576CAN_REG_ERROR_CODE_TYPE GENMASK(28, 26)
+#define RK3576CAN_REG_ERROR_CODE_TYPE_BIT 0x0
+#define RK3576CAN_REG_ERROR_CODE_TYPE_STUFF 0x1
+#define RK3576CAN_REG_ERROR_CODE_TYPE_FORM 0x2
+#define RK3576CAN_REG_ERROR_CODE_TYPE_ACK 0x3
+#define RK3576CAN_REG_ERROR_CODE_TYPE_CRC 0x4
+#define RK3576CAN_REG_ERROR_CODE_DIRECTION_RX BIT(25)
+#define RK3576CAN_REG_ERROR_CODE_TX GENMASK(24, 19)
+#define RK3576CAN_REG_ERROR_CODE_TX_ACK_EOF BIT(24)
+#define RK3576CAN_REG_ERROR_CODE_TX_CRC BIT(23)
+#define RK3576CAN_REG_ERROR_CODE_TX_STUFF_COUNT BIT(22)
+#define RK3576CAN_REG_ERROR_CODE_TX_DATA BIT(21)
+#define RK3576CAN_REG_ERROR_CODE_TX_SOF_DLC BIT(20)
+#define RK3576CAN_REG_ERROR_CODE_TX_IDLE BIT(19)
+#define RK3576CAN_REG_ERROR_CODE_RX GENMASK(18, 0)
+#define RK3576CAN_REG_ERROR_CODE_RX_ERROR BIT(18)
+#define RK3576CAN_REG_ERROR_CODE_RX_OVERLOAD BIT(17)
+#define RK3576CAN_REG_ERROR_CODE_RX_SPACE BIT(16)
+#define RK3576CAN_REG_ERROR_CODE_RX_EOF BIT(15)
+#define RK3576CAN_REG_ERROR_CODE_RX_ACK_LIM BIT(14)
+#define RK3576CAN_REG_ERROR_CODE_RX_ACK BIT(13)
+#define RK3576CAN_REG_ERROR_CODE_RX_CRC_LIM BIT(12)
+#define RK3576CAN_REG_ERROR_CODE_RX_CRC BIT(11)
+#define RK3576CAN_REG_ERROR_CODE_RX_STUFF_COUNT BIT(10)
+#define RK3576CAN_REG_ERROR_CODE_RX_DATA BIT(9)
+#define RK3576CAN_REG_ERROR_CODE_RX_DLC BIT(8)
+#define RK3576CAN_REG_ERROR_CODE_RX_BRS_ESI BIT(7)
+#define RK3576CAN_REG_ERROR_CODE_RX_RES BIT(6)
+#define RK3576CAN_REG_ERROR_CODE_RX_FDF BIT(5)
+#define RK3576CAN_REG_ERROR_CODE_RX_ID2_RTR BIT(4)
+#define RK3576CAN_REG_ERROR_CODE_RX_SOF_IDE BIT(3)
+#define RK3576CAN_REG_ERROR_CODE_RX_BUS_IDLE BIT(2)
+#define RK3576CAN_REG_ERROR_CODE_RX_BUS_INT BIT(1)
+#define RK3576CAN_REG_ERROR_CODE_RX_STOP BIT(0)
+
+#define RK3576CAN_ISM_WATERMASK_CAN 0x6c /* word */
+#define RK3576CAN_ISM_WATERMASK_CANFD 0x6c /* word */
+
+#define RK3576CAN_SRAM_MAX_DEPTH 256 /* word */
+
+#define RK3576CAN_CANFD_FILTER GENMASK(28, 0)
+
+#define RK3576CAN_CANFD_FIFO_CNT GENMASK(7, 0)
+
#define DEVICE_NAME "rockchip_canfd"
#define RKCANFD_NAPI_WEIGHT 32
#define RKCANFD_TXFIFO_DEPTH 2
@@ -434,6 +684,7 @@
enum rkcanfd_model {
RKCANFD_MODEL_RK3568V2 = 0x35682,
RKCANFD_MODEL_RK3568V3 = 0x35683,
+ RKCAN_MODEL_RK3576 = 0x3576,
};
struct rkcanfd_priv;
@@ -457,6 +708,11 @@ struct rkcanfd_fifo_header {
u32 ts;
};
+struct rk3576can_fifo_header {
+ u32 frameinfo;
+ u32 id;
+};
+
struct rkcanfd_stats {
struct u64_stats_sync syncp;
@@ -546,6 +802,8 @@ rkcanfd_get_tx_free(const struct rkcanfd_priv *priv)
void rkcanfd_ethtool_init(struct rkcanfd_priv *priv);
int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv);
+int rkcanfd_handle_rk3576_tx_int(struct rkcanfd_priv *priv);
+int rkcanfd_handle_rk3576_rx_int(struct rkcanfd_priv *priv);
void rkcanfd_skb_set_timestamp(const struct rkcanfd_priv *priv,
struct sk_buff *skb, const u32 timestamp);
--
2.34.1
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v8 4/4] net: can: rockchip: support dma for rk3576 rx
2025-10-29 3:22 [PATCH v8 0/4] rockchip: add can for RK3576 Soc Elaine Zhang
` (2 preceding siblings ...)
2025-10-29 3:23 ` [PATCH v8 3/4] net: can: rockchip: add can for RK3576 Soc Elaine Zhang
@ 2025-10-29 3:23 ` Elaine Zhang
3 siblings, 0 replies; 6+ messages in thread
From: Elaine Zhang @ 2025-10-29 3:23 UTC (permalink / raw)
To: zhangqing, mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt,
heiko, cl
Cc: linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
The new can controller of rk3576 supports rx dma.
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
.../net/can/rockchip/rockchip_canfd-core.c | 62 +++++++++-
drivers/net/can/rockchip/rockchip_canfd-rx.c | 109 ++++++++++++++++++
drivers/net/can/rockchip/rockchip_canfd.h | 9 ++
3 files changed, 178 insertions(+), 2 deletions(-)
diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c
index 58fffcf97b20..8284bf05efba 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-core.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-core.c
@@ -399,6 +399,9 @@ static void rk3576can_chip_start(struct rkcanfd_priv *priv)
RK3576CAN_REG_BRS_CFG_BRS_NEGSYNC_EN |
RK3576CAN_REG_BRS_CFG_BRS_POSSYNC_EN);
+ if (priv->dma_thr)
+ rkcanfd_write(priv, RK3576CAN_REG_DMA_CTRL,
+ RK3576CAN_REG_DMA_CTRL_DMA_RX_EN | priv->dma_thr);
rkcanfd_set_bittiming(priv);
priv->devtype_data.interrupts_disable(priv);
@@ -1288,10 +1291,34 @@ static const struct of_device_id rkcanfd_of_match[] = {
};
MODULE_DEVICE_TABLE(of, rkcanfd_of_match);
+static int rk3576_canfd_dma_init(struct rkcanfd_priv *priv, struct resource *res)
+{
+ struct dma_slave_config rxconf = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr = res->start + RK3576CAN_REG_RXFRD,
+ .src_addr_width = 4,
+ .dst_addr_width = 4,
+ .src_maxburst = 9,
+ };
+
+ priv->dma_thr = rxconf.src_maxburst - 1;
+ priv->dma_size = RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT * 4;
+ priv->rxbuf = dma_alloc_coherent(priv->ndev->dev.parent,
+ priv->dma_size * RK3576CAN_SRAM_MAX_FIFO_CNT,
+ &priv->rx_dma_dst_addr, GFP_KERNEL);
+ if (!priv->rxbuf) {
+ priv->rxbuf = NULL;
+ return -ENOMEM;
+ }
+ dmaengine_slave_config(priv->rxchan, &rxconf);
+ return 0;
+}
+
static int rkcanfd_probe(struct platform_device *pdev)
{
struct rkcanfd_priv *priv;
struct net_device *ndev;
+ struct resource *res;
const void *match;
int err;
@@ -1313,7 +1340,7 @@ static int rkcanfd_probe(struct platform_device *pdev)
goto out_free_candev;
}
- priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->regs)) {
err = PTR_ERR(priv->regs);
goto out_free_candev;
@@ -1348,10 +1375,22 @@ static int rkcanfd_probe(struct platform_device *pdev)
priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
}
+ priv->rxchan = dma_request_chan(&pdev->dev, "rx");
+ if (IS_ERR(priv->rxchan)) {
+ netdev_warn(priv->ndev,
+ "Failed to request RX-DMA channel: %pe, continuing without DMA",
+ priv->rxchan);
+ priv->rxchan = NULL;
+ } else {
+ err = rk3576_canfd_dma_init(priv, res);
+ if (err)
+ goto out_can_dma_rx_chan_del;
+ }
+
err = can_rx_offload_add_manual(ndev, &priv->offload,
RKCANFD_NAPI_WEIGHT);
if (err)
- goto out_free_candev;
+ goto out_can_dma_rx_chan_del;
err = rkcanfd_register(priv);
if (err)
@@ -1361,6 +1400,15 @@ static int rkcanfd_probe(struct platform_device *pdev)
out_can_rx_offload_del:
can_rx_offload_del(&priv->offload);
+out_can_dma_rx_chan_del:
+ if (priv->rxbuf) {
+ dma_free_coherent(priv->ndev->dev.parent,
+ priv->dma_size * RK3576CAN_SRAM_MAX_FIFO_CNT,
+ priv->rxbuf, priv->rx_dma_dst_addr);
+ priv->rxbuf = NULL;
+ }
+ if (priv->rxchan)
+ dma_release_channel(priv->rxchan);
out_free_candev:
free_candev(ndev);
@@ -1372,6 +1420,16 @@ static void rkcanfd_remove(struct platform_device *pdev)
struct rkcanfd_priv *priv = platform_get_drvdata(pdev);
struct net_device *ndev = priv->ndev;
+ if (priv->rxbuf) {
+ dma_free_coherent(priv->ndev->dev.parent,
+ priv->dma_size * RK3576CAN_SRAM_MAX_FIFO_CNT,
+ priv->rxbuf, priv->rx_dma_dst_addr);
+ priv->rxbuf = NULL;
+ }
+
+ if (priv->rxchan)
+ dma_release_channel(priv->rxchan);
+
rkcanfd_unregister(priv);
can_rx_offload_del(&priv->offload);
free_candev(ndev);
diff --git a/drivers/net/can/rockchip/rockchip_canfd-rx.c b/drivers/net/can/rockchip/rockchip_canfd-rx.c
index 6bc4b0185502..e478b2b482c1 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-rx.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-rx.c
@@ -277,6 +277,71 @@ static int rk3576can_handle_rx_int_one(struct rkcanfd_priv *priv)
return 0;
}
+static int rk3576can_handle_rx_dma(struct rkcanfd_priv *priv, u32 addr)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ struct canfd_frame *skb_cfd;
+ struct sk_buff *skb;
+ u32 frameinfo, id, data[16] = {0};
+ u8 dlc;
+ int i;
+
+ frameinfo = *(u32 *)(priv->rxbuf + addr * RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
+ id = *(u32 *)(priv->rxbuf + 1 + addr * RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
+ for (i = 0; i < (RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT - 2); i++)
+ data[i] = *(u32 *)(priv->rxbuf + 2 + i +
+ addr * RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
+
+ if (frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FDF)
+ skb = alloc_canfd_skb(priv->ndev, &skb_cfd);
+ else
+ skb = alloc_can_skb(priv->ndev, (struct can_frame **)&skb_cfd);
+
+ if (!skb) {
+ stats->rx_dropped++;
+
+ return 0;
+ }
+
+ if (frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FRAME_FORMAT)
+ skb_cfd->can_id = FIELD_GET(RKCANFD_REG_FD_ID_EFF, id) |
+ CAN_EFF_FLAG;
+ else
+ skb_cfd->can_id = FIELD_GET(RKCANFD_REG_FD_ID_SFF, id);
+
+ dlc = FIELD_GET(RK3576CAN_REG_RXFRD_FRAMEINFO_DATA_LENGTH,
+ frameinfo);
+
+ /* CAN-FD */
+ if (frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_FDF) {
+ skb_cfd->len = can_fd_dlc2len(dlc);
+
+ /* The cfd is not allocated by alloc_canfd_skb(), so
+ * set CANFD_FDF here.
+ */
+ skb_cfd->flags |= CANFD_FDF;
+
+ if (frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_BRS)
+ skb_cfd->flags |= CANFD_BRS;
+ } else {
+ skb_cfd->len = can_cc_dlc2len(dlc);
+
+ if (frameinfo & RK3576CAN_REG_RXFRD_FRAMEINFO_RTR)
+ skb_cfd->can_id |= CAN_RTR_FLAG;
+ }
+ if (!(skb_cfd->can_id & CAN_RTR_FLAG)) {
+ /* Change CANFD data format to SocketCAN data format */
+ for (i = 0; i < skb_cfd->len; i += 4)
+ *(u32 *)(skb_cfd->data + i) = data[i / 4];
+ }
+
+ stats->rx_packets++;
+ stats->rx_bytes += skb_cfd->len;
+ netif_rx(skb);
+
+ return 0;
+}
+
static int rkcanfd_handle_rx_int_one(struct rkcanfd_priv *priv)
{
struct net_device_stats *stats = &priv->ndev->stats;
@@ -372,6 +437,43 @@ rk3576can_rx_fifo_get_len(const struct rkcanfd_priv *priv)
return DIV_ROUND_UP(val, RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
}
+static void rk3576_can_rx_dma_callback(void *data)
+{
+ struct rkcanfd_priv *priv = data;
+ int i;
+
+ for (i = 0; i < priv->quota; i++)
+ rk3576can_handle_rx_dma(priv, i);
+
+ rkcanfd_write(priv, RK3576CAN_REG_INT_MASK, priv->reg_int_mask_default);
+}
+
+static int rk3576_can_rx_dma(struct rkcanfd_priv *priv)
+{
+ struct dma_async_tx_descriptor *rxdesc = NULL;
+ const u32 reg = rkcanfd_read(priv, RK3576CAN_REG_STR_STATE);
+ int quota = FIELD_GET(RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT, reg);
+
+ quota = DIV_ROUND_UP(quota, RK3576CAN_REG_STR_STATE_INTM_LEFT_CNT_UNIT);
+ priv->quota = quota;
+ if (priv->quota == 0) {
+ rkcanfd_write(priv, RK3576CAN_REG_INT_MASK, priv->reg_int_mask_default);
+ return 0;
+ }
+
+ rxdesc = dmaengine_prep_slave_single(priv->rxchan, priv->rx_dma_dst_addr,
+ priv->dma_size * priv->quota, DMA_DEV_TO_MEM, 0);
+ if (!rxdesc)
+ return -ENOMSG;
+
+ rxdesc->callback = rk3576_can_rx_dma_callback;
+ rxdesc->callback_param = priv;
+
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(priv->rxchan);
+ return 0;
+}
+
int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv)
{
unsigned int len;
@@ -391,6 +493,13 @@ int rkcanfd_handle_rk3576_rx_int(struct rkcanfd_priv *priv)
unsigned int len;
int err;
+ if (priv->rxchan) {
+ err = rk3576_can_rx_dma(priv);
+ if (err)
+ return err;
+ else
+ return 0;
+ }
while ((len = rk3576can_rx_fifo_get_len(priv))) {
err = rk3576can_handle_rx_int_one(priv);
if (err)
diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h
index 77c673cfea3b..bdd01150d920 100644
--- a/drivers/net/can/rockchip/rockchip_canfd.h
+++ b/drivers/net/can/rockchip/rockchip_canfd.h
@@ -11,6 +11,8 @@
#include <linux/can/dev.h>
#include <linux/can/rx-offload.h>
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/io.h>
#include <linux/netdevice.h>
#include <linux/reset.h>
@@ -532,6 +534,7 @@
#define RK3576CAN_ISM_WATERMASK_CANFD 0x6c /* word */
#define RK3576CAN_SRAM_MAX_DEPTH 256 /* word */
+#define RK3576CAN_SRAM_MAX_FIFO_CNT (RK3576CAN_SRAM_MAX_DEPTH / 18)
#define RK3576CAN_CANFD_FILTER GENMASK(28, 0)
@@ -748,6 +751,12 @@ struct rkcanfd_priv {
struct reset_control *reset;
struct clk_bulk_data *clks;
int clks_num;
+ u32 dma_size;
+ u32 dma_thr;
+ int quota;
+ struct dma_chan *rxchan;
+ u32 *rxbuf;
+ dma_addr_t rx_dma_dst_addr;
};
static inline u32
--
2.34.1
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller
2025-10-29 3:22 ` [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller Elaine Zhang
@ 2025-10-29 17:48 ` Conor Dooley
0 siblings, 0 replies; 6+ messages in thread
From: Conor Dooley @ 2025-10-29 17:48 UTC (permalink / raw)
To: Elaine Zhang
Cc: mkl, kernel, mailhol.vincent, robh, krzk+dt, conor+dt, heiko, cl,
linux-can, linux-arm-kernel, linux-rockchip, linux-kernel,
devicetree
[-- Attachment #1.1: Type: text/plain, Size: 2683 bytes --]
On Wed, Oct 29, 2025 at 11:22:59AM +0800, Elaine Zhang wrote:
> Add documentation for the rockchip rk3576 CAN controller.
>
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> ---
> .../net/can/rockchip,rk3568v2-canfd.yaml | 52 +++++++++++++++++--
> 1 file changed, 48 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
> index a077c0330013..30782218728e 100644
> --- a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
> +++ b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml
> @@ -10,13 +10,12 @@ title:
> maintainers:
> - Marc Kleine-Budde <mkl@pengutronix.de>
>
> -allOf:
> - - $ref: can-controller.yaml#
> -
> properties:
> compatible:
> oneOf:
> - - const: rockchip,rk3568v2-canfd
> + - enum:
> + - rockchip,rk3568v2-canfd
> + - rockchip,rk3576-can
> - items:
> - const: rockchip,rk3568v3-canfd
> - const: rockchip,rk3568v2-canfd
> @@ -43,6 +42,33 @@ properties:
> - const: core
> - const: apb
>
> + dmas:
> + maxItems: 1
> +
> + dma-names:
> + items:
> + - const: rx
> +
> +allOf:
> + - $ref: can-controller.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: rockchip,rk3576-can
> + then:
> + properties:
> + dmas:
> + minItems: 1
> + maxItems: 2
> + dma-names:
> + minItems: 1
> + maxItems: 2
This looks wrong. You have one dma, but you're setting maxItems to 2.
Seems fine otherwise.
pw-bot: changes-requested
Cheers,
Conor.
> + else:
> + properties:
> + dmas: false
> + dma-names: false
> +
> required:
> - compatible
> - reg
> @@ -72,3 +98,21 @@ examples:
> reset-names = "core", "apb";
> };
> };
> +
> + - |
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + can@2ac00000 {
> + compatible = "rockchip,rk3576-can";
> + reg = <0x0 0x2ac00000 0x0 0x1000>;
> + interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&cru CLK_CAN0>, <&cru PCLK_CAN0>;
> + clock-names = "baud", "pclk";
> + resets = <&cru SRST_CAN0>, <&cru SRST_P_CAN0>;
> + reset-names = "core", "apb";
> + dmas = <&dmac0 20>;
> + dma-names = "rx";
> + };
> + };
> --
> 2.34.1
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 170 bytes --]
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-10-29 17:48 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-29 3:22 [PATCH v8 0/4] rockchip: add can for RK3576 Soc Elaine Zhang
2025-10-29 3:22 ` [PATCH v8 1/4] dt-bindings: can: rockchip_canfd: add rk3576 CAN controller Elaine Zhang
2025-10-29 17:48 ` Conor Dooley
2025-10-29 3:23 ` [PATCH v8 2/4] net: can: rockchip: Refactor the rkcanfd_devtype_data structure Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 3/4] net: can: rockchip: add can for RK3576 Soc Elaine Zhang
2025-10-29 3:23 ` [PATCH v8 4/4] net: can: rockchip: support dma for rk3576 rx Elaine Zhang
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).