From nobody Fri Dec 19 07:19:54 2025 Received: from mail-m12799.qiye.163.com (mail-m12799.qiye.163.com [115.236.127.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9CB9313E02E; Tue, 17 Dec 2024 02:44:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.127.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734403479; cv=none; b=b6Ed4tftU4Lgo2AgD4EX7zheQoch9hgqKUwqGAxU2sHxGtsGjMrOq0sj2iZw6naRq+ymPYMoXGmRleH7kv01yJjUeEr4hHdTMLCJV/dVuYd/mW8xeSm2K6QuEVGyms+r45ZO61dPY94W3Kg6DA8oFceAI9chvhepqe7yoJAiVxg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734403479; c=relaxed/simple; bh=GpBJKPe4BpW+37iPRlFFC7tTRgmaEt2bPiG7zAwLwrU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SK9rq03BDP0pGGNzZ9TXsnbVqI9e/TZQUGN53Y8ex1OSHh0TrWF6o5RntB4wUfLA+B0p4O6QmtF89nbAkpV+sWchpMSjonUYYOWyunDc3eyqOJLQ1ew7upyff+PH8KYyqPviGjRvlZEraca4vN3Q97WOj61FKf5dtFPnVMEK1b0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rock-chips.com; spf=pass smtp.mailfrom=rock-chips.com; dkim=pass (1024-bit key) header.d=rock-chips.com header.i=@rock-chips.com header.b=azx7fMPD; arc=none smtp.client-ip=115.236.127.99 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rock-chips.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rock-chips.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=rock-chips.com header.i=@rock-chips.com header.b="azx7fMPD" Received: from rockchip.. (unknown [58.22.7.114]) by smtp.qiye.163.com (Hmail) with ESMTP id 5ec156b5; Tue, 17 Dec 2024 10:39:20 +0800 (GMT+08:00) From: Elaine Zhang To: zhangqing@rock-chips.com, mkl@pengutronix.de, kernel@pengutronix.de, mailhol.vincent@wanadoo.fr, heiko@sntech.de, cl@rock-chips.com, kever.yang@rock-chips.com Cc: linux-can@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH 1/2] net: can: rockchip: add can for RK3576 Soc Date: Tue, 17 Dec 2024 10:39:07 +0800 Message-Id: <20241217023908.1292999-2-zhangqing@rock-chips.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241217023908.1292999-1-zhangqing@rock-chips.com> References: <20241217023908.1292999-1-zhangqing@rock-chips.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFDSUNOT01LS0k3V1ktWUFJV1kPCRoVCBIfWUFZQxgZS1ZPQxpKGEIYQkxCHkNWFRQJFh oXVRMBExYaEhckFA4PWVdZGBILWUFZTkNVSUlVTFVKSk9ZV1kWGg8SFR0UWUFZT0tIVUpLSUhCSE NVSktLVUpCS0tZBg++ X-HM-Tid: 0a93d27bfbc403a3kunm5ec156b5 X-HM-MType: 1 X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6MTo6OBw4IzIQNh8JIxQWUT8R EwMwFBpVSlVKTEhPT0tISk1JTElOVTMWGhIXVQETGhUcChIVHDsJFBgQVhgTEgsIVRgUFkVZV1kS C1lBWU5DVUlJVUxVSkpPWVdZCAFZQU9LT0xDNwY+ DKIM-Signature: a=rsa-sha256; b=azx7fMPDXIziAlna74NjoYfUCaP4OlVl9zpgBfIGrCnJDMNAiQaiDAiSOB37MV3kHZfRshSMN7VKtv6GiBSwFZcFxtHQM+kFOHmJibvF/mo5OoL1GAbY0tAPiFVNTlXKnmNCWXaxQmu4Ji576XhDcHQlaGzpKJJICWxTsxEjLLI=; c=relaxed/relaxed; s=default; d=rock-chips.com; v=1; bh=+RMCZ32UVDPZmcPliHegw6GzYj0kHvPAL0Oysy8tf8I=; h=date:mime-version:subject:message-id:from; Content-Type: text/plain; charset="utf-8" Is new controller: Support CAN and CANFD protocol. Support DMA. Signed-off-by: Elaine Zhang --- drivers/net/can/rockchip/Kconfig | 10 + drivers/net/can/rockchip/Makefile | 1 + drivers/net/can/rockchip/rk3576_canfd.c | 1349 +++++++++++++++++++++++ 3 files changed, 1360 insertions(+) create mode 100644 drivers/net/can/rockchip/rk3576_canfd.c diff --git a/drivers/net/can/rockchip/Kconfig b/drivers/net/can/rockchip/Kc= onfig index d203c530551f..78c2990e374e 100644 --- a/drivers/net/can/rockchip/Kconfig +++ b/drivers/net/can/rockchip/Kconfig @@ -8,3 +8,13 @@ config CAN_ROCKCHIP_CANFD help Say Y here if you want to use CAN-FD controller found on Rockchip SoCs. + +config CANFD_RK3576 + tristate "RK3576 CANFD controller" + depends on OF + depends on ARCH_ROCKCHIP || COMPILE_TEST + help + Say Y here if you want to use CANFD controller found on RK3576 SoCs. + + To compile this driver as a module, choose M here: the module will + be called rk3576_canfd. diff --git a/drivers/net/can/rockchip/Makefile b/drivers/net/can/rockchip/M= akefile index 3760d3e1baa3..151f9e0ee6aa 100644 --- a/drivers/net/can/rockchip/Makefile +++ b/drivers/net/can/rockchip/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 =20 obj-$(CONFIG_CAN_ROCKCHIP_CANFD) +=3D rockchip_canfd.o +obj-$(CONFIG_CANFD_RK3576) +=3D rk3576_canfd.o =20 rockchip_canfd-objs :=3D rockchip_canfd-objs +=3D rockchip_canfd-core.o diff --git a/drivers/net/can/rockchip/rk3576_canfd.c b/drivers/net/can/rock= chip/rk3576_canfd.c new file mode 100644 index 000000000000..663f6e3a68ab --- /dev/null +++ b/drivers/net/can/rockchip/rk3576_canfd.c @@ -0,0 +1,1349 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * Rk3576 CANFD driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* registers definition */ +enum rk3576_canfd_reg { + CANFD_MODE =3D 0x00, + CANFD_CMD =3D 0x04, + CANFD_STATE =3D 0x08, + CANFD_INT =3D 0x0c, + CANFD_INT_MASK =3D 0x10, + CANFD_NBTP =3D 0x100, + CANFD_DBTP =3D 0x104, + CANFD_TDCR =3D 0x108, + CANFD_BRS_CFG =3D 0x10c, + CANFD_DMA_CTRL =3D 0x11c, + CANFD_TXFIC =3D 0x200, + CANFD_TXID =3D 0x204, + CANFD_TXDAT0 =3D 0x208, + CANFD_TXDAT1 =3D 0x20c, + CANFD_TXDAT2 =3D 0x210, + CANFD_TXDAT3 =3D 0x214, + CANFD_TXDAT4 =3D 0x218, + CANFD_TXDAT5 =3D 0x21c, + CANFD_TXDAT6 =3D 0x220, + CANFD_TXDAT7 =3D 0x224, + CANFD_TXDAT8 =3D 0x228, + CANFD_TXDAT9 =3D 0x22c, + CANFD_TXDAT10 =3D 0x230, + CANFD_TXDAT11 =3D 0x234, + CANFD_TXDAT12 =3D 0x238, + CANFD_TXDAT13 =3D 0x23c, + CANFD_TXDAT14 =3D 0x240, + CANFD_TXDAT15 =3D 0x244, + CANFD_RXFIC =3D 0x300, + CANFD_RXID =3D 0x304, + CANFD_RXTS =3D 0x308, + CANFD_RXDAT0 =3D 0x30c, + CANFD_RXDAT1 =3D 0x310, + CANFD_RXDAT2 =3D 0x314, + CANFD_RXDAT3 =3D 0x318, + CANFD_RXDAT4 =3D 0x31c, + CANFD_RXDAT5 =3D 0x320, + CANFD_RXDAT6 =3D 0x324, + CANFD_RXDAT7 =3D 0x328, + CANFD_RXDAT8 =3D 0x32c, + CANFD_RXDAT9 =3D 0x330, + CANFD_RXDAT10 =3D 0x334, + CANFD_RXDAT11 =3D 0x338, + CANFD_RXDAT12 =3D 0x33c, + CANFD_RXDAT13 =3D 0x340, + CANFD_RXDAT14 =3D 0x344, + CANFD_RXDAT15 =3D 0x348, + CANFD_RXFRD =3D 0x400, + CANFD_STR_CTL =3D 0x600, + CANFD_STR_STATE =3D 0x604, + CANFD_STR_TIMEOUT =3D 0x608, + CANFD_STR_WTM =3D 0x60c, + CANFD_EXTM_START_ADDR =3D 0x610, + CANFD_EXTM_SIZE =3D 0x614, + CANFD_EXTM_WADDR =3D 0x618, + CANFD_EXTM_RADDR =3D 0x61c, + CANFD_EXTM_AHB_TXTHR =3D 0x620, + CANFD_EXTM_LEFT_CNT =3D 0x624, + CANFD_ATF0 =3D 0x700, + CANFD_ATF1 =3D 0x704, + CANFD_ATF2 =3D 0x708, + CANFD_ATF3 =3D 0x70c, + CANFD_ATF4 =3D 0x710, + CANFD_ATFM0 =3D 0x714, + CANFD_ATFM1 =3D 0x718, + CANFD_ATFM2 =3D 0x71c, + CANFD_ATFM3 =3D 0x720, + CANFD_ATFM4 =3D 0x724, + CANFD_ATF_DLC =3D 0x728, + CANFD_ATF_CTL =3D 0x72c, + CANFD_SPACE_CTRL =3D 0x800, + CANFD_AUTO_RETX_CFG =3D 0x808, + CANFD_AUTO_RETX_STATE0 =3D 0x80c, + CANFD_AUTO_RETX_STATE1 =3D 0x810, + CANFD_OLF_CFG =3D 0x814, + CANFD_RXINT_CTRL =3D 0x818, + CANFD_RXINT_TIMEOUT =3D 0x81c, + CANFD_OTHER_CFG =3D 0x820, + CANFD_WAVE_FILTER_CFG =3D 0x824, + CANFD_RBC_CFG =3D 0x828, + CANFD_TXCRC_CFG =3D 0x82c, + CANFD_BUSOFFRCY_CFG =3D 0x830, + CANFD_BUSOFF_RCY_THR =3D 0x834, + CANFD_ERROR_CODE =3D 0x900, + CANFD_ERROR_MASK =3D 0x904, + CANFD_RXERRORCNT =3D 0x910, + CANFD_TXERRORCNT =3D 0x914, + CANFD_RX_RXSRAM_RDATA =3D 0xc00, + CANFD_RTL_VERSION =3D 0xf0c, +}; + +#define DATE_LENGTH_12_BYTE (0x9) +#define DATE_LENGTH_16_BYTE (0xa) +#define DATE_LENGTH_20_BYTE (0xb) +#define DATE_LENGTH_24_BYTE (0xc) +#define DATE_LENGTH_32_BYTE (0xd) +#define DATE_LENGTH_48_BYTE (0xe) +#define DATE_LENGTH_64_BYTE (0xf) + +#define CANFD_TX0_REQ BIT(0) +#define CANFD_TX1_REQ BIT(1) +#define CANFD_TX_REQ_FULL ((CANFD_TX0_REQ) | (CANFD_TX1_REQ)) + +#define MODE_PASS_ERR BIT(10) +#define MODE_DIS_PEE BIT(9) +#define MODE_RETT BIT(8) +#define MODE_AUTO_BUS_ON BIT(7) +#define MODE_COVER BIT(6) +#define MODE_RXSTX BIT(5) +#define MODE_LBACK BIT(4) +#define MODE_SILENT BIT(3) +#define MODE_SELF_TEST BIT(2) +#define MODE_SLEEP BIT(1) +#define RESET_MODE 0 +#define WORK_MODE BIT(0) + +#define RETX_TIME_LIMIT_CNT 0x12c /* 300 */ +#define RETX_TIME_LIMIT_SHIFT 3 +#define RETX_LIMIT_EN BIT(1) +#define AUTO_RETX_EN BIT(0) + +#define ERR_WARNING_STATE BIT(3) +#define BUS_OFF_STATE BIT(4) + +#define RX_FINISH_INT BIT(0) +#define TX_FINISH_INT BIT(1) +#define ERR_WARN_INT BIT(2) +#define RX_BUF_OV_INT BIT(3) +#define PASSIVE_ERR_INT BIT(4) +#define TX_LOSTARB_INT BIT(5) +#define BUS_ERR_INT BIT(6) +#define RX_STR_FULL_INT BIT(7) +#define RX_STR_OV_INT BIT(8) +#define BUS_OFF_INT BIT(9) +#define BUS_OFF_RECOVERY_INT BIT(10) +#define WAKEUP_INT BIT(11) +#define AUTO_RETX_FAIL_INT BIT(12) +#define MFI_INT BIT(13) +#define MFI_TIMEOUT BIT(14) +#define RX_STR_TIMEOUT_INT BIT(15) +#define BUSINT_INT BIT(16) +#define ISM_WTM_INT BIT(17) +#define ESM_WTM_INT BIT(18) +#define BUSOFF_RCY_INT BIT(19) + +#define INT_ENABLE BIT(0) + +#define ERR_PHASE BIT(28) +#define ARB_PHASE 0 +#define DATA_PHASE 1 +#define ERR_TYPE_MASK GENMASK(27, 25) +#define ERR_TYPE_SHIFT 25 +#define BIT_ERROR 0 +#define BIT_STUFF_ERROR 1 +#define FORM_ERROR 2 +#define ACK_ERROR 3 +#define CRC_ERROR 4 +#define TRANSMIT_ACK_EOF BIT(24) +#define TRANSMIT_CRC BIT(23) +#define TRANSMIT_STUFF_COUNT BIT(22) +#define TRANSMIT_DATA BIT(21) +#define TRANSMIT_SOF_DLC BIT(20) +#define TRANSMIT_IDLE BIT(19) +#define RECEIVE_ERROR BIT(18) +#define RECEIVE_OVERLOAD BIT(17) +#define RECEIVE_SPACE BIT(16) +#define RECEIVE_EOF BIT(15) +#define RECEIVE_ACK_LIM BIT(14) +#define RECEIVE_ACK_SLOT BIT(13) +#define RECEIVE_CRC_LIM BIT(12) +#define RECEIVE_CRC BIT(11) +#define RECEIVE_STUFF_COUNT BIT(10) +#define RECEIVE_DATA BIT(9) +#define RECEIVE_DLC BIT(8) +#define RECEIVE_BRS_ESI BIT(7) +#define RECEIVE_RES BIT(6) +#define RECEIVE_FDF BIT(5) +#define RECEIVE_ID2_RTR BIT(4) +#define RECEIVE_SOF_IDE BIT(3) +#define RECEIVE_BUS_IDLE BIT(2) +#define RECEIVE_BUS_INT BIT(1) +#define RECEIVE_STOP BIT(0) + +/* Nominal Bit Timing & Prescaler Register (NBTP) */ +#define NBTP_MODE_3_SAMPLES BIT(31) +#define NBTP_NSJW_SHIFT 24 +#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT) +#define NBTP_NBRP_SHIFT 16 +#define NBTP_NBRP_MASK (0xff << NBTP_NBRP_SHIFT) +#define NBTP_NTSEG2_SHIFT 8 +#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT) +#define NBTP_NTSEG1_SHIFT 0 +#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT) + +/* Data Bit Timing & Prescaler Register (DBTP) */ +#define DBTP_BRS_TSEG1_SHIFT 24 +#define DBTP_BRS_TSEG1_MASK (0xff << DBTP_BRS_TSEG1_SHIFT) +#define DBTP_BRS_MODE BIT(23) +#define DBTP_MODE_3_SAMPLES BIT(21) +#define DBTP_DSJW_SHIFT 17 +#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) +#define DBTP_DBRP_SHIFT 9 +#define DBTP_DBRP_MASK (0xff << DBTP_DBRP_SHIFT) +#define DBTP_DTSEG2_SHIFT 5 +#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT) +#define DBTP_DTSEG1_SHIFT 0 +#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT) + +/* Transmitter Delay Compensation Register (TDCR) */ +#define TDCR_TDCO_SHIFT 1 +#define TDCR_TDCO_MASK (0x3f << TDCR_TDCO_SHIFT) +#define TDCR_TDC_ENABLE BIT(0) + +#define RX_DMA_ENABLE BIT(9) + +#define TX_FD_ENABLE BIT(5) +#define TX_FD_BRS_ENABLE BIT(4) + +#define TX_FORMAT_SHIFT 7 +#define TX_FORMAT_MASK (0x1 << TX_FORMAT_SHIFT) +#define TX_RTR_SHIFT 6 +#define TX_RTR_MASK (0x1 << TX_RTR_SHIFT) +#define TX_FDF_SHIFT 5 +#define TX_FDF_MASK (0x1 << TX_FDF_SHIFT) +#define TX_BRS_SHIFT 4 +#define TX_BRS_MASK (0x1 << TX_BRS_SHIFT) +#define TX_DLC_SHIFT 0 +#define TX_DLC_MASK (0xF << TX_DLC_SHIFT) + +#define RX_FORMAT_SHIFT 23 +#define RX_FORMAT_MASK (0x1 << RX_FORMAT_SHIFT) +#define RX_RTR_SHIFT 22 +#define RX_RTR_MASK (0x1 << RX_RTR_SHIFT) +#define RX_FDF_SHIFT 21 +#define RX_FDF_MASK (0x1 << RX_FDF_SHIFT) +#define RX_BRS_SHIFT 20 +#define RX_BRS_MASK (0x1 << RX_BRS_SHIFT) +#define RX_DLC_SHIFT 24 +#define RX_DLC_MASK (0xF << RX_DLC_SHIFT) +#define RX_ISM_LEN_SHIFT 8 +#define RX_ISM_LEN_MASK (0xF << RX_ISM_LEN_SHIFT) + +#define BUFFER_MODE_ENABLE BIT(0) +#define EXT_STORAGE_MODE BIT(1) +#define ISM_SEL_SHIFT 2 +#define ISM_SEL_MASK (0x3 << ISM_SEL_SHIFT) +#define RX_STORAGE_RESET BIT(4) +#define ESM_SEL_SHIFT 6 +#define ESM_SEL_MASK (0x3 << ESM_SEL_SHIFT) +#define STORAGE_TIMEOUT_MODE BIT(8) + +#define INTM_CNT_SHIFT 17 +#define INTM_CNT_MASK (0x1ff << INTM_CNT_SHIFT) +#define INTM_LEFT_CNT_SHIFT 8 +#define INTM_LEFT_CNT_MASK (0x1ff << INTM_LEFT_CNT_SHIFT) +#define EXTM_FULL BIT(3) +#define EXTM_EMPTY BIT(2) +#define INTM_FULL BIT(1) +#define INTM_EMPTY BIT(0) + +#define EXTTM_LEFT_CNT_SHIFT 0 +#define EXTTM_LEFT_CNT_MASK (0x3fffff << EXTTM_LEFT_CNT_SHIFT) + +#define ISM_WATERMASK_CAN 0x6c /* word */ +#define ISM_WATERMASK_CANFD 0x6c /* word */ +#define ESM_WATERMASK (0x50 << 8) /* word */ + +#define BUSOFF_RCY_MODE_EN BIT(8) +#define BUSOFF_RCY_TIME_CLR BIT(9) +#define BUSOFF_RCY_CNT_FAST 4 +#define BUSOFF_RCY_CNT_SLOW 5 +#define BUSOFF_RCY_TIME_FAST 0x3d0900 /* 40ms : cnt * (1 / can_clk) */ +#define BUSOFF_RCY_TIME_SLOW 0x1312d00 /* 200ms : cnt * (1 / can_clk) */ + +#define ATF_MASK BIT(31) +#define ATF_RTR_EN BIT(30) +#define ATF_RTR BIT(29) + +#define ATF_DLC_MODE BIT(5) +#define ATF_DLC_EN BIT(4) +#define ATF_DLC_SHIFT 0 +#define ATF_DLC_MASK (0xf << ATF_DLC_SHIFT) + +#define ATF_DIS(n) BIT(n) + +#define ACK_ERROR_MASK BIT(4) +#define FORM_ERROR_MASK BIT(3) +#define CRC_ERROR_MASK BIT(2) +#define STUFF_ERROR_MASK BIT(1) +#define BIT_ERROR_MASK BIT(0) + +#define SRAM_MAX_DEPTH 256 /* word */ +#define EXT_MEM_SIZE 0x2000 /* 8KByte */ + +#define CANFD_FILTER_MASK 0x1fffffff + +#define CANFD_FIFO_CNT_MASK 0xff + +#define CANBUSOFF_RCY_SLOW 200 /* ms */ +#define CANBUSOFF_RCY_FAST 30 /* ms */ + +#define DRV_NAME "rk3576_canfd" + +enum rk3576_canfd_atf_mode { + CANFD_ATF_MASK_MODE =3D 0, + CANFD_ATF_LIST_MODE, +}; + +enum rk3576_canfd_storage_mode { + CANFD_DATA_FLEXIBLE =3D 0, + CANFD_DATA_CAN_FIXED, + CANFD_DATA_CANFD_FIXED, +}; + +/* rk3576_canfd private data structure */ + +struct rk3576_canfd { + struct can_priv can; + struct device *dev; + struct napi_struct napi; + struct clk_bulk_data *clks; + int num_clks; + struct reset_control *reset; + void __iomem *base; + u32 irqstatus; + unsigned long mode; + int rx_fifo_shift; + u32 rx_fifo_mask; + int rx_fifo_depth; + int rx_max_data; + bool use_dma; + u32 dma_size; + int quota; + struct dma_chan *rxchan; + u32 *rxbuf; + dma_addr_t rx_dma_src_addr; + dma_addr_t rx_dma_dst_addr; +}; + +static inline u32 rk3576_canfd_read(const struct rk3576_canfd *priv, + enum rk3576_canfd_reg reg) +{ + return readl(priv->base + reg); +} + +static inline void rk3576_canfd_write(const struct rk3576_canfd *priv, + enum rk3576_canfd_reg reg, u32 val) +{ + writel(val, priv->base + reg); +} + +static const struct can_bittiming_const rk3576_canfd_bittiming_const =3D { + .name =3D DRV_NAME, + .tseg1_min =3D 1, + .tseg1_max =3D 128, + .tseg2_min =3D 1, + .tseg2_max =3D 128, + .sjw_max =3D 128, + .brp_min =3D 1, + .brp_max =3D 256, + .brp_inc =3D 2, +}; + +static const struct can_bittiming_const rk3576_canfd_data_bittiming_const = =3D { + .name =3D DRV_NAME, + .tseg1_min =3D 1, + .tseg1_max =3D 32, + .tseg2_min =3D 1, + .tseg2_max =3D 16, + .sjw_max =3D 16, + .brp_min =3D 1, + .brp_max =3D 256, + .brp_inc =3D 2, +}; + +static int set_reset_mode(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + + reset_control_assert(rcan->reset); + udelay(2); + reset_control_deassert(rcan->reset); + + rk3576_canfd_write(rcan, CANFD_MODE, 0); + + netdev_dbg(ndev, "%s MODE=3D0x%08x\n", __func__, + rk3576_canfd_read(rcan, CANFD_MODE)); + + return 0; +} + +static int set_normal_mode(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + u32 val; + + val =3D rk3576_canfd_read(rcan, CANFD_MODE); + val |=3D WORK_MODE; + rk3576_canfd_write(rcan, CANFD_MODE, val); + + netdev_dbg(ndev, "%s MODE=3D0x%08x\n", __func__, + rk3576_canfd_read(rcan, CANFD_MODE)); + return 0; +} + +/* bittiming is called in reset_mode only */ +static int rk3576_canfd_set_bittiming(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + const struct can_bittiming *bt =3D &rcan->can.bittiming; + const struct can_bittiming *dbt =3D &rcan->can.data_bittiming; + u16 brp, sjw, tseg1, tseg2; + u32 reg_btp; + + brp =3D (bt->brp >> 1) - 1; + sjw =3D bt->sjw - 1; + tseg1 =3D bt->prop_seg + bt->phase_seg1 - 1; + tseg2 =3D bt->phase_seg2 - 1; + reg_btp =3D (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) | + (tseg1 << NBTP_NTSEG1_SHIFT) | + (tseg2 << NBTP_NTSEG2_SHIFT); + + if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + reg_btp |=3D NBTP_MODE_3_SAMPLES; + + rk3576_canfd_write(rcan, CANFD_NBTP, reg_btp); + + if (rcan->can.ctrlmode & CAN_CTRLMODE_FD) { + reg_btp =3D 0; + brp =3D (dbt->brp >> 1) - 1; + sjw =3D dbt->sjw - 1; + tseg1 =3D dbt->prop_seg + dbt->phase_seg1 - 1; + tseg2 =3D dbt->phase_seg2 - 1; + if (sjw < 2) + sjw =3D 2; + + if (dbt->bitrate > 2200000) { + u32 tdco; + + /* Equation based on Bosch's ROCKCHIP_CANFD User Manual's + * Transmitter Delay Compensation Section + */ + tdco =3D ((1 + 1 + tseg1) * (brp + 1)) - 2; + /* Max valid TDCO value is 63 */ + if (tdco > 63) + tdco =3D 63; + rk3576_canfd_write(rcan, CANFD_TDCR, + (tdco << TDCR_TDCO_SHIFT) | + TDCR_TDC_ENABLE); + } else { + rk3576_canfd_write(rcan, CANFD_TDCR, 0); + } + + reg_btp |=3D (brp << DBTP_DBRP_SHIFT) | + (sjw << DBTP_DSJW_SHIFT) | + (tseg1 << DBTP_DTSEG1_SHIFT) | + (tseg2 << DBTP_DTSEG2_SHIFT) | + DBTP_BRS_MODE | + ((tseg1 / 2) << DBTP_BRS_TSEG1_SHIFT); + + if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + reg_btp |=3D DBTP_MODE_3_SAMPLES; + + rk3576_canfd_write(rcan, CANFD_DBTP, reg_btp); + } + + netdev_dbg(ndev, "%s NBTP=3D0x%08x, DBTP=3D0x%08x, TDCR=3D0x%08x\n", __fu= nc__, + rk3576_canfd_read(rcan, CANFD_NBTP), + rk3576_canfd_read(rcan, CANFD_DBTP), + rk3576_canfd_read(rcan, CANFD_TDCR)); + return 0; +} + +static int rk3576_canfd_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + int err; + + err =3D pm_runtime_get_sync(rcan->dev); + if (err < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, err); + return err; + } + + bec->rxerr =3D rk3576_canfd_read(rcan, CANFD_RXERRORCNT); + bec->txerr =3D rk3576_canfd_read(rcan, CANFD_TXERRORCNT); + + pm_runtime_put(rcan->dev); + + netdev_dbg(ndev, "%s RX_ERR_CNT=3D0x%08x, TX_ERR_CNT=3D0x%08x\n", __func_= _, + rk3576_canfd_read(rcan, CANFD_RXERRORCNT), + rk3576_canfd_read(rcan, CANFD_TXERRORCNT)); + + return 0; +} + +static int rk3576_canfd_atf_config(const struct net_device *ndev, int mode) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + u32 id[10] =3D {0}; + u32 dlc =3D 0, dlc_over =3D 0; + + switch (mode) { + case CANFD_ATF_MASK_MODE: + rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); + rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); + rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); + rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); + rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); + rk3576_canfd_write(rcan, CANFD_ATFM0, 0x7fff); + rk3576_canfd_write(rcan, CANFD_ATFM1, 0x7fff); + rk3576_canfd_write(rcan, CANFD_ATFM2, 0x7fff); + rk3576_canfd_write(rcan, CANFD_ATFM3, 0x7fff); + rk3576_canfd_write(rcan, CANFD_ATFM4, 0x7fff); + break; + case CANFD_ATF_LIST_MODE: + rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); + rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); + rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); + rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); + rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); + rk3576_canfd_write(rcan, CANFD_ATFM0, id[5] | (1 << 31)); + rk3576_canfd_write(rcan, CANFD_ATFM1, id[6] | (1 << 31)); + rk3576_canfd_write(rcan, CANFD_ATFM2, id[7] | (1 << 31)); + rk3576_canfd_write(rcan, CANFD_ATFM3, id[8] | (1 << 31)); + rk3576_canfd_write(rcan, CANFD_ATFM4, id[9] | (1 << 31)); + break; + default: + rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0xffff); + return -EINVAL; + } + + if (dlc) { + if (dlc_over) + rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4)); + else + rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4) | (1 << 5)); + } + rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0); + + return 0; +} + +static int rk3576_canfd_start(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + u32 val, ism =3D 0, water =3D 0; + + /* we need to enter the reset mode */ + set_reset_mode(ndev); + + rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_canfd_atf_config(ndev, CANFD_ATF_MASK_MODE); + + /* set mode */ + val =3D rk3576_canfd_read(rcan, CANFD_MODE); + + if (rcan->rx_max_data > 4) { + ism =3D CANFD_DATA_CANFD_FIXED; + water =3D ISM_WATERMASK_CANFD; + } else { + ism =3D CANFD_DATA_CAN_FIXED; + water =3D ISM_WATERMASK_CAN; + } + + /* internal sram mode */ + rk3576_canfd_write(rcan, CANFD_STR_CTL, + (ism << ISM_SEL_SHIFT) | STORAGE_TIMEOUT_MODE); + rk3576_canfd_write(rcan, CANFD_STR_WTM, water); + + /* Loopback Mode */ + if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { + val |=3D MODE_LBACK; + rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + } else if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { + val |=3D MODE_SILENT; + rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + } else { + rk3576_canfd_write(rcan, CANFD_ERROR_MASK, 0); + } + + rk3576_canfd_write(rcan, CANFD_AUTO_RETX_CFG, + AUTO_RETX_EN | RETX_LIMIT_EN | + (RETX_TIME_LIMIT_CNT << RETX_TIME_LIMIT_SHIFT)); + + rk3576_canfd_write(rcan, CANFD_MODE, val); + if (rcan->use_dma) + rk3576_canfd_write(rcan, CANFD_DMA_CTRL, RX_DMA_ENABLE); + + rk3576_canfd_write(rcan, CANFD_BRS_CFG, 0x7); + + rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_MODE_EN | BUSOFF= _RCY_CNT_FAST); + rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_FAST); + + rk3576_canfd_set_bittiming(ndev); + + set_normal_mode(ndev); + + rcan->can.state =3D CAN_STATE_ERROR_ACTIVE; + + netdev_dbg(ndev, "%s MODE=3D0x%08x, INT_MASK=3D0x%08x\n", __func__, + rk3576_canfd_read(rcan, CANFD_MODE), + rk3576_canfd_read(rcan, CANFD_INT_MASK)); + + return 0; +} + +static int rk3576_canfd_stop(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + + rcan->can.state =3D CAN_STATE_STOPPED; + /* we need to enter reset mode */ + set_reset_mode(ndev); + + /* disable all interrupts */ + rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffffffff); + + netdev_dbg(ndev, "%s MODE=3D0x%08x, INT_MASK=3D0x%08x\n", __func__, + rk3576_canfd_read(rcan, CANFD_MODE), + rk3576_canfd_read(rcan, CANFD_INT_MASK)); + return 0; +} + +static int rk3576_canfd_set_mode(struct net_device *ndev, + enum can_mode mode) +{ + int err; + + switch (mode) { + case CAN_MODE_START: + err =3D rk3576_canfd_start(ndev); + if (err) { + netdev_err(ndev, "starting CANFD controller failed!\n"); + return err; + } + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* transmit a CANFD message + * message layout in the sk_buff should be like this: + * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 + * [ can_id ] [flags] [len] [can data (up to 8 bytes] + */ +static netdev_tx_t rk3576_canfd_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + struct canfd_frame *cf =3D (struct canfd_frame *)skb->data; + u32 id, dlc; + u32 cmd =3D CANFD_TX0_REQ; + int i; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + + netif_stop_queue(ndev); + + if (rk3576_canfd_read(rcan, CANFD_CMD) & CANFD_TX0_REQ) + cmd =3D CANFD_TX1_REQ; + + /* Watch carefully on the bit sequence */ + if (cf->can_id & CAN_EFF_FLAG) { + /* Extended CANFD ID format */ + id =3D cf->can_id & CAN_EFF_MASK; + dlc =3D can_fd_len2dlc(cf->len) & TX_DLC_MASK; + dlc |=3D TX_FORMAT_MASK; + + /* Extended frames remote TX request */ + if (cf->can_id & CAN_RTR_FLAG) + dlc |=3D TX_RTR_MASK; + } else { + /* Standard CANFD ID format */ + id =3D cf->can_id & CAN_SFF_MASK; + dlc =3D can_fd_len2dlc(cf->len) & TX_DLC_MASK; + + /* Standard frames remote TX request */ + if (cf->can_id & CAN_RTR_FLAG) + dlc |=3D TX_RTR_MASK; + } + + if ((rcan->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { + dlc |=3D TX_FD_ENABLE; + if (cf->flags & CANFD_BRS) + dlc |=3D TX_FD_BRS_ENABLE; + } + + rk3576_canfd_write(rcan, CANFD_TXID, id); + rk3576_canfd_write(rcan, CANFD_TXFIC, dlc); + + for (i =3D 0; i < cf->len; i +=3D 4) + rk3576_canfd_write(rcan, CANFD_TXDAT0 + i, + *(u32 *)(cf->data + i)); + + can_put_echo_skb(skb, ndev, 0, 0); + + rk3576_canfd_write(rcan, CANFD_CMD, cmd); + + return NETDEV_TX_OK; +} + +static int rk3576_canfd_rx(struct net_device *ndev, u32 addr) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + struct net_device_stats *stats =3D &ndev->stats; + struct canfd_frame *cf; + struct sk_buff *skb; + u32 id_rk3576_canfd, dlc; + int i =3D 0; + u32 __maybe_unused ts, ret; + u32 data[16] =3D {0}; + + if (rcan->use_dma) { + dlc =3D readl(rcan->rxbuf + addr * rcan->rx_max_data); + id_rk3576_canfd =3D readl(rcan->rxbuf + 1 + addr * rcan->rx_max_data); + for (i =3D 0; i < (rcan->rx_max_data - 2); i++) + data[i] =3D readl(rcan->rxbuf + 2 + i + addr * rcan->rx_max_data); + } else { + dlc =3D rk3576_canfd_read(rcan, addr); + id_rk3576_canfd =3D rk3576_canfd_read(rcan, addr); + for (i =3D 0; i < (rcan->rx_max_data - 2); i++) + data[i] =3D rk3576_canfd_read(rcan, addr); + } + + /* create zero'ed CANFD frame buffer */ + if (dlc & RX_FDF_MASK) + skb =3D alloc_canfd_skb(ndev, &cf); + else + skb =3D alloc_can_skb(ndev, (struct can_frame **)&cf); + if (!skb) { + stats->rx_dropped++; + return 1; + } + + /* Change CANFD data length format to SocketCAN data format */ + if (dlc & RX_FDF_MASK) + cf->len =3D can_fd_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); + else + cf->len =3D can_cc_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); + + /* Change CANFD ID format to SocketCAN ID format */ + if (dlc & RX_FORMAT_MASK) { + /* The received frame is an Extended format frame */ + cf->can_id =3D id_rk3576_canfd; + cf->can_id |=3D CAN_EFF_FLAG; + if (dlc & RX_RTR_MASK) + cf->can_id |=3D CAN_RTR_FLAG; + } else { + /* The received frame is a standard format frame */ + cf->can_id =3D id_rk3576_canfd; + if (dlc & RX_RTR_MASK) + cf->can_id |=3D CAN_RTR_FLAG; + } + + if (dlc & RX_BRS_MASK) + cf->flags |=3D CANFD_BRS; + + if (!(cf->can_id & CAN_RTR_FLAG)) { + /* Change CANFD data format to SocketCAN data format */ + for (i =3D 0; i < cf->len; i +=3D 4) + *(u32 *)(cf->data + i) =3D data[i / 4]; + } + + stats->rx_packets++; + stats->rx_bytes +=3D cf->len; + netif_rx(skb); + + return 1; +} + +/* rk3576_canfd_rx_poll - Poll routine for rx packets (NAPI) + * @napi: napi structure pointer + * @quota: Max number of rx packets to be processed. + * + * This is the poll routine for rx part. + * It will process the packets maximux quota value. + * + * Return: number of packets received + */ +static int rk3576_canfd_rx_poll(struct napi_struct *napi, int quota) +{ + struct net_device *ndev =3D napi->dev; + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + int work_done =3D 0, cnt =3D 0; + + if (rcan->use_dma) { + while (work_done < rcan->quota) + work_done +=3D rk3576_canfd_rx(ndev, work_done); + + if (work_done <=3D rcan->rx_fifo_depth) { + napi_complete_done(napi, work_done); + rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + } + } else { + quota =3D (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask= ) >> + rcan->rx_fifo_shift; + quota =3D quota / rcan->rx_max_data; + cnt =3D (rk3576_canfd_read(rcan, CANFD_STR_STATE) & INTM_CNT_MASK) >> IN= TM_CNT_SHIFT; + if (quota !=3D cnt) + quota =3D ((rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_ma= sk) >> + rcan->rx_fifo_shift) / rcan->rx_max_data; + + while (work_done < quota) + work_done +=3D rk3576_canfd_rx(ndev, CANFD_RXFRD); + + if (work_done <=3D rcan->rx_fifo_depth) { + napi_complete_done(napi, work_done); + rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + } + } + return work_done; +} + +static void rk3576_canfd_rx_dma_callback(void *data) +{ + struct rk3576_canfd *rcan =3D data; + + napi_schedule(&rcan->napi); +} + +static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) +{ + struct dma_async_tx_descriptor *rxdesc =3D NULL; + int quota =3D 0, cnt =3D 0; + + quota =3D (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask)= >> + rcan->rx_fifo_shift; + quota =3D quota / rcan->rx_max_data; + cnt =3D (rk3576_canfd_read(rcan, CANFD_STR_STATE) & INTM_CNT_MASK) >> INT= M_CNT_SHIFT; + + if (quota !=3D cnt) + quota =3D ((rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mas= k) >> + rcan->rx_fifo_shift) / rcan->rx_max_data; + + rcan->quota =3D quota; + if (rcan->quota =3D=3D 0) + return 1; + + rxdesc =3D dmaengine_prep_slave_single(rcan->rxchan, rcan->rx_dma_dst_add= r, + rcan->dma_size * rcan->quota, DMA_DEV_TO_MEM, 0); + if (!rxdesc) + return -EBUSY; + + rxdesc->callback =3D rk3576_canfd_rx_dma_callback; + rxdesc->callback_param =3D rcan; + + dmaengine_submit(rxdesc); + dma_async_issue_pending(rcan->rxchan); + return 1; +} + +static int rk3576_canfd_err(struct net_device *ndev, u32 isr) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + struct net_device_stats *stats =3D &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + unsigned int rxerr, txerr; + u32 sta_reg; + + skb =3D alloc_can_err_skb(ndev, &cf); + + rxerr =3D rk3576_canfd_read(rcan, CANFD_RXERRORCNT); + txerr =3D rk3576_canfd_read(rcan, CANFD_TXERRORCNT); + sta_reg =3D rk3576_canfd_read(rcan, CANFD_STATE); + + if (skb) { + cf->data[6] =3D txerr; + cf->data[7] =3D rxerr; + } + + if (isr & BUS_OFF_INT) { + rcan->can.state =3D CAN_STATE_BUS_OFF; + rcan->can.can_stats.bus_off++; + cf->can_id |=3D CAN_ERR_BUSOFF; + } else if (isr & PASSIVE_ERR_INT) { + rcan->can.can_stats.error_passive++; + rcan->can.state =3D CAN_STATE_ERROR_PASSIVE; + /* error passive state */ + cf->can_id |=3D CAN_ERR_CRTL; + cf->data[1] =3D (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + cf->data[6] =3D txerr; + cf->data[7] =3D rxerr; + } + if (sta_reg & ERR_WARNING_STATE) { + rcan->can.can_stats.error_warning++; + rcan->can.state =3D CAN_STATE_ERROR_WARNING; + /* error warning state */ + if (likely(skb)) { + cf->can_id |=3D CAN_ERR_CRTL; + cf->data[1] =3D (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + cf->data[6] =3D txerr; + cf->data[7] =3D rxerr; + } + } + + if (isr & BUSOFF_RCY_INT) { + rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffff); + rk3576_canfd_write(rcan, CANFD_INT, isr); + napi_schedule(&rcan->napi); + rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_TIME_CLR); + rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_SLOW); + rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, + BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_SLOW); + rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + netif_stop_queue(ndev); + can_free_echo_skb(ndev, 0, NULL); + netif_start_queue(ndev); + } + stats->rx_packets++; + stats->rx_bytes +=3D cf->can_dlc; + netif_rx(skb); + + return 0; +} + +static irqreturn_t rk3576_canfd_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev =3D (struct net_device *)dev_id; + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + struct net_device_stats *stats =3D &ndev->stats; + u32 err_int =3D ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | + BUS_ERR_INT | BUS_OFF_INT | BUSOFF_RCY_INT | + BUS_OFF_RECOVERY_INT | RX_STR_FULL_INT; + u32 isr; + + isr =3D rk3576_canfd_read(rcan, CANFD_INT); + if ((isr & RX_STR_TIMEOUT_INT) || (isr & ISM_WTM_INT) || (isr & RX_STR_FU= LL_INT)) { + rk3576_canfd_write(rcan, CANFD_INT_MASK, + ISM_WTM_INT | RX_STR_TIMEOUT_INT | + RX_FINISH_INT); + if (rcan->use_dma) + rk3576_canfd_rx_dma(rcan); + else + napi_schedule(&rcan->napi); + } + + if (isr & TX_FINISH_INT) { + rk3576_canfd_write(rcan, CANFD_CMD, 0); + stats->tx_bytes +=3D can_get_echo_skb(ndev, 0, NULL); + stats->tx_packets++; + netif_wake_queue(ndev); + } + + if (isr & err_int) { + /* error interrupt */ + if (rk3576_canfd_err(ndev, isr)) + netdev_err(ndev, "can't allocate buffer - clearing pending interrupts\n= "); + } + + rk3576_canfd_write(rcan, CANFD_INT, isr); + return IRQ_HANDLED; +} + +static int rk3576_canfd_open(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + int err; + + /* common open */ + err =3D open_candev(ndev); + if (err) + return err; + + err =3D pm_runtime_get_sync(rcan->dev); + if (err < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, err); + goto exit; + } + + err =3D rk3576_canfd_start(ndev); + if (err) { + netdev_err(ndev, "could not start CANFD peripheral\n"); + goto exit_can_start; + } + + napi_enable(&rcan->napi); + netif_start_queue(ndev); + + netdev_dbg(ndev, "%s\n", __func__); + return 0; + +exit_can_start: + pm_runtime_put(rcan->dev); +exit: + close_candev(ndev); + return err; +} + +static int rk3576_canfd_close(struct net_device *ndev) +{ + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + + netif_stop_queue(ndev); + napi_disable(&rcan->napi); + rk3576_canfd_stop(ndev); + close_candev(ndev); + pm_runtime_put(rcan->dev); + + netdev_dbg(ndev, "%s\n", __func__); + return 0; +} + +static const struct net_device_ops rk3576_canfd_netdev_ops =3D { + .ndo_open =3D rk3576_canfd_open, + .ndo_stop =3D rk3576_canfd_close, + .ndo_start_xmit =3D rk3576_canfd_start_xmit, + .ndo_change_mtu =3D can_change_mtu, +}; + +/** + * rk3576_canfd_suspend - Suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused rk3576_canfd_suspend(struct device *dev) +{ + struct net_device *ndev =3D dev_get_drvdata(dev); + + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + rk3576_canfd_stop(ndev); + } + + return pm_runtime_force_suspend(dev); +} + +/** + * rk3576_canfd_resume - Resume from suspend + * @dev: Address of the device structure + * + * Resume operation after suspend. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused rk3576_canfd_resume(struct device *dev) +{ + struct net_device *ndev =3D dev_get_drvdata(dev); + int ret; + + ret =3D pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "pm_runtime_force_resume failed on resume\n"); + return ret; + } + + if (netif_running(ndev)) { + ret =3D rk3576_canfd_start(ndev); + if (ret) { + dev_err(dev, "rk3576_canfd_chip_start failed on resume\n"); + return ret; + } + + netif_device_attach(ndev); + netif_start_queue(ndev); + } + + return 0; +} + +/** + * rk3576_canfd_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 always + */ +static int __maybe_unused rk3576_canfd_runtime_suspend(struct device *dev) +{ + struct net_device *ndev =3D dev_get_drvdata(dev); + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + + clk_bulk_disable_unprepare(rcan->num_clks, rcan->clks); + + return 0; +} + +/** + * rk3576_canfd_runtime_resume - Runtime resume from suspend + * @dev: Address of the device structure + * + * Resume operation after suspend. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused rk3576_canfd_runtime_resume(struct device *dev) +{ + struct net_device *ndev =3D dev_get_drvdata(dev); + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + int ret; + + ret =3D clk_bulk_prepare_enable(rcan->num_clks, rcan->clks); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops rk3576_canfd_dev_pm_ops =3D { + SET_SYSTEM_SLEEP_PM_OPS(rk3576_canfd_suspend, rk3576_canfd_resume) + SET_RUNTIME_PM_OPS(rk3576_canfd_runtime_suspend, + rk3576_canfd_runtime_resume, NULL) +}; + +static const struct of_device_id rk3576_canfd_of_match[] =3D { + { + .compatible =3D "rockchip,rk3576-canfd", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, rk3576_canfd_of_match); + +static void rk3576_canfd_dma_init(struct rk3576_canfd *rcan) +{ + struct dma_slave_config rxconf =3D { + .direction =3D DMA_DEV_TO_MEM, + .src_addr =3D rcan->rx_dma_src_addr, + .src_addr_width =3D 4, + .dst_addr_width =3D 4, + .src_maxburst =3D 16, + }; + + rcan->rxbuf =3D dma_alloc_coherent(rcan->dev, rcan->dma_size * rcan->rx_f= ifo_depth, + &rcan->rx_dma_dst_addr, GFP_KERNEL); + if (!rcan->rxbuf) { + rcan->use_dma =3D 0; + return; + } + dmaengine_slave_config(rcan->rxchan, &rxconf); +} + +static int rk3576_canfd_probe(struct platform_device *pdev) +{ + struct net_device *ndev; + struct rk3576_canfd *rcan; + struct resource *res; + void __iomem *addr; + int err, irq; + u32 val =3D 0; + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "could not get a valid irq\n"); + return -ENODEV; + } + + res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr =3D devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(addr)) + return -EBUSY; + + ndev =3D alloc_candev(sizeof(struct rk3576_canfd), 1); + if (!ndev) { + dev_err(&pdev->dev, "could not allocate memory for CANFD device\n"); + return -ENOMEM; + } + rcan =3D netdev_priv(ndev); + + /* register interrupt handler */ + err =3D devm_request_irq(&pdev->dev, irq, rk3576_canfd_interrupt, + 0, ndev->name, ndev); + if (err) { + dev_err(&pdev->dev, "request_irq err: %d\n", err); + return err; + } + + rcan->reset =3D devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(rcan->reset)) { + if (PTR_ERR(rcan->reset) !=3D -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to get canfd reset lines\n"); + return PTR_ERR(rcan->reset); + } + rcan->num_clks =3D devm_clk_bulk_get_all(&pdev->dev, &rcan->clks); + if (rcan->num_clks < 1) + return -ENODEV; + + rcan->mode =3D (unsigned long)of_device_get_match_data(&pdev->dev); + + rcan->base =3D addr; + rcan->can.clock.freq =3D clk_get_rate(rcan->clks[0].clk); + rcan->dev =3D &pdev->dev; + rcan->can.state =3D CAN_STATE_STOPPED; + + rcan->can.bittiming_const =3D &rk3576_canfd_bittiming_const; + rcan->can.data_bittiming_const =3D &rk3576_canfd_data_bittiming_const; + rcan->can.do_set_mode =3D rk3576_canfd_set_mode; + rcan->can.do_get_berr_counter =3D rk3576_canfd_get_berr_counter; + rcan->can.do_set_bittiming =3D rk3576_canfd_set_bittiming; + rcan->can.do_set_data_bittiming =3D rk3576_canfd_set_bittiming; + rcan->can.ctrlmode =3D CAN_CTRLMODE_FD; + /* IFI CANFD can do both Bosch FD and ISO FD */ + rcan->can.ctrlmode_supported =3D CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_FD; + + rcan->rx_fifo_shift =3D INTM_LEFT_CNT_SHIFT; + rcan->rx_fifo_mask =3D INTM_LEFT_CNT_MASK; + + /* rx-max-data only 4 Words or 18 words are supported */ + if (device_property_read_u32_array(&pdev->dev, "rockchip,rx-max-data", &v= al, 1)) + rcan->rx_max_data =3D 18; + else + rcan->rx_max_data =3D val; + + if (rcan->rx_max_data !=3D 4 && rcan->rx_max_data !=3D 18) { + rcan->rx_max_data =3D 18; + dev_warn(&pdev->dev, "rx_max_data is invalid, set to 18 words!\n"); + } + rcan->rx_fifo_depth =3D SRAM_MAX_DEPTH / rcan->rx_max_data; + + rcan->rxchan =3D dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR(rcan->rxchan)) { + dev_warn(&pdev->dev, "Failed to request rxchan\n"); + rcan->rxchan =3D NULL; + rcan->use_dma =3D 0; + } else { + rcan->rx_dma_src_addr =3D res->start + CANFD_RXFRD; + rcan->dma_size =3D rcan->rx_max_data * 4; + rcan->use_dma =3D 1; + } + if (rcan->use_dma) + rk3576_canfd_dma_init(rcan); + + ndev->netdev_ops =3D &rk3576_canfd_netdev_ops; + ndev->irq =3D irq; + ndev->flags |=3D IFF_ECHO; + + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + + pm_runtime_enable(&pdev->dev); + err =3D pm_runtime_get_sync(&pdev->dev); + if (err < 0) { + dev_err(&pdev->dev, "%s: pm_runtime_get failed(%d)\n", + __func__, err); + goto err_pmdisable; + } + netif_napi_add(ndev, &rcan->napi, rk3576_canfd_rx_poll); + err =3D register_candev(ndev); + if (err) { + dev_err(&pdev->dev, "registering %s failed (err=3D%d)\n", + DRV_NAME, err); + goto err_disableclks; + } + dev_info(&pdev->dev, "CAN info: use_dma =3D %d, rx_max_data =3D %d, fifo_= depth =3D %d\n", + rcan->use_dma, rcan->rx_max_data, rcan->rx_fifo_depth); + return 0; + +err_disableclks: + pm_runtime_put(&pdev->dev); +err_pmdisable: + if (rcan->rxbuf) { + dma_free_coherent(rcan->dev, rcan->dma_size * rcan->rx_fifo_depth, rcan-= >rxbuf, + rcan->rx_dma_dst_addr); + rcan->rxbuf =3D NULL; + } + if (rcan->rxchan) + dma_release_channel(rcan->rxchan); + pm_runtime_disable(&pdev->dev); + free_candev(ndev); + + return err; +} + +static void rk3576_canfd_remove(struct platform_device *pdev) +{ + struct net_device *ndev =3D platform_get_drvdata(pdev); + struct rk3576_canfd *rcan =3D netdev_priv(ndev); + + if (rcan->rxbuf) { + dma_free_coherent(rcan->dev, rcan->dma_size * rcan->rx_fifo_depth, rcan-= >rxbuf, + rcan->rx_dma_dst_addr); + rcan->rxbuf =3D NULL; + } + + if (rcan->rxchan) + dma_release_channel(rcan->rxchan); + + unregister_netdev(ndev); + pm_runtime_disable(&pdev->dev); + netif_napi_del(&rcan->napi); + free_candev(ndev); +} + +static struct platform_driver rk3576_canfd_driver =3D { + .driver =3D { + .name =3D DRV_NAME, + .pm =3D &rk3576_canfd_dev_pm_ops, + .of_match_table =3D rk3576_canfd_of_match, + }, + .probe =3D rk3576_canfd_probe, + .remove =3D rk3576_canfd_remove, +}; +module_platform_driver(rk3576_canfd_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Elaine Zhang "); +MODULE_DESCRIPTION("RK3576 CANFD Drivers"); --=20 2.34.1 From nobody Fri Dec 19 07:19:54 2025 Received: from mail-m11879.qiye.163.com (mail-m11879.qiye.163.com [115.236.118.79]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D620A15A85A; Tue, 17 Dec 2024 02:44:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.118.79 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734403482; cv=none; b=Og1wsaE3j3RrYoD0LKei37MWMBieedLLSRGeTO0l7ExQZJkrS2nAE2S9XZ/vgb5tDx2Lt6eMPGx3Z4BGkxi1tnQVUGpqO0pj4zDPK3B5zu0/PSoo5fUwYmJO9mvxZuSPItvsbULzmmDjc3AQ0evI3V+8iwCQ0XN+bldOO6simKc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734403482; c=relaxed/simple; bh=9n/zI/O7haEMeDpiOaVz2plrsy4gpJ2Kt2kHVN/A0qc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=tEXwy8k3/rIiSplxpIXLix1hvyl0i+c3AJBQJPVUGgCxk7BTM5bhmJUAmIx7PTj5t6kjIxHrOuaCd/0bfKprRvkU7E5/tUSnGCS9qh3OZ8zGOHjJBDfGXpmv6jhkPzoZBEV5X1AkNlwMW3piGyTC7MkW6biT3ePhNWAq4qZ5vGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rock-chips.com; spf=pass smtp.mailfrom=rock-chips.com; dkim=pass (1024-bit key) header.d=rock-chips.com header.i=@rock-chips.com header.b=WRSzkUcL; arc=none smtp.client-ip=115.236.118.79 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rock-chips.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rock-chips.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=rock-chips.com header.i=@rock-chips.com header.b="WRSzkUcL" Received: from rockchip.. (unknown [58.22.7.114]) by smtp.qiye.163.com (Hmail) with ESMTP id 5ec156bf; Tue, 17 Dec 2024 10:39:22 +0800 (GMT+08:00) From: Elaine Zhang To: zhangqing@rock-chips.com, mkl@pengutronix.de, kernel@pengutronix.de, mailhol.vincent@wanadoo.fr, heiko@sntech.de, cl@rock-chips.com, kever.yang@rock-chips.com Cc: linux-can@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH 2/2] arm64: dts: rockchip: rk3576: add can dts nodes Date: Tue, 17 Dec 2024 10:39:08 +0800 Message-Id: <20241217023908.1292999-3-zhangqing@rock-chips.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241217023908.1292999-1-zhangqing@rock-chips.com> References: <20241217023908.1292999-1-zhangqing@rock-chips.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFDSUNOT01LS0k3V1ktWUFJV1kPCRoVCBIfWUFZGh9JTFYfSkJLTEsfGkpOTUtWFRQJFh oXVRMBExYaEhckFA4PWVdZGBILWUFZTkNVSUlVTFVKSk9ZV1kWGg8SFR0UWUFZT0tIVUpLSUhCSE NVSktLVUpCS0tZBg++ X-HM-Tid: 0a93d27c02cf03a3kunm5ec156bf X-HM-MType: 1 X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6Ny46Dio5LTILTR84IwoSUT0N DDNPCwFVSlVKTEhPT0tISk1IQklIVTMWGhIXVQETGhUcChIVHDsJFBgQVhgTEgsIVRgUFkVZV1kS C1lBWU5DVUlJVUxVSkpPWVdZCAFZQUpPQko3Bg++ DKIM-Signature: a=rsa-sha256; b=WRSzkUcLFHUQwjHZ9FgA80+ljrbvUmQfByWfj/cQfxVhXpURm/hQJeGmnGypOut36OH8y8qHTwwEjeLSvTU+CTNOKRmb0jl/cvYNDFZrNHQLgbLkj/dx8SY3bsndragufi3Nr1KyrcOxLCSuVKdBzM4vjLxNjGVwzaC0/WtgM8c=; c=relaxed/relaxed; s=default; d=rock-chips.com; v=1; bh=mbc4XvnMPoqYWmjqlM+MGD27w/PMpYBtQHdgk1ZuX98=; h=date:mime-version:subject:message-id:from; Content-Type: text/plain; charset="utf-8" Signed-off-by: Elaine Zhang --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts= /rockchip/rk3576.dtsi index 436232ffe4d1..82fdfd4720ec 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -1195,6 +1195,32 @@ dmac2: dma-controller@2abd0000 { #dma-cells =3D <1>; }; =20 + can0: can@2ac00000 { + compatible =3D "rockchip,rk3576-canfd"; + reg =3D <0x0 0x2ac00000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&cru CLK_CAN0>, <&cru HCLK_CAN0>; + clock-names =3D "baudclk", "apb_pclk"; + resets =3D <&cru SRST_CAN0>, <&cru SRST_H_CAN0>; + reset-names =3D "can", "can-apb"; + dmas =3D <&dmac0 20>; + dma-names =3D "rx"; + status =3D "disabled"; + }; +=09 + can1: can@2ac10000 { + compatible =3D "rockchip,rk3576-canfd"; + reg =3D <0x0 0x2ac10000 0x0 0x1000>; + interrupts =3D ; + clocks =3D <&cru CLK_CAN1>, <&cru HCLK_CAN1>; + clock-names =3D "baudclk", "apb_pclk"; + resets =3D <&cru SRST_CAN1>, <&cru SRST_H_CAN1>; + reset-names =3D "can", "can-apb"; + dmas =3D <&dmac1 21>; + dma-names =3D "rx"; + status =3D "disabled"; + }; + i2c1: i2c@2ac40000 { compatible =3D "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; reg =3D <0x0 0x2ac40000 0x0 0x1000>; --=20 2.34.1