* [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
^ 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
^ 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
^ permalink raw reply related [flat|nested] 6+ messages in thread