18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Xilinx CAN device driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 - 2014 Xilinx, Inc.
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 PetaLogix. All rights reserved.
68c2ecf20Sopenharmony_ci * Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Description:
98c2ecf20Sopenharmony_ci * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
208c2ecf20Sopenharmony_ci#include <linux/of.h>
218c2ecf20Sopenharmony_ci#include <linux/of_device.h>
228c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
238c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
248c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
258c2ecf20Sopenharmony_ci#include <linux/string.h>
268c2ecf20Sopenharmony_ci#include <linux/types.h>
278c2ecf20Sopenharmony_ci#include <linux/can/dev.h>
288c2ecf20Sopenharmony_ci#include <linux/can/error.h>
298c2ecf20Sopenharmony_ci#include <linux/can/led.h>
308c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define DRIVER_NAME	"xilinx_can"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* CAN registers set */
358c2ecf20Sopenharmony_cienum xcan_reg {
368c2ecf20Sopenharmony_ci	XCAN_SRR_OFFSET		= 0x00, /* Software reset */
378c2ecf20Sopenharmony_ci	XCAN_MSR_OFFSET		= 0x04, /* Mode select */
388c2ecf20Sopenharmony_ci	XCAN_BRPR_OFFSET	= 0x08, /* Baud rate prescaler */
398c2ecf20Sopenharmony_ci	XCAN_BTR_OFFSET		= 0x0C, /* Bit timing */
408c2ecf20Sopenharmony_ci	XCAN_ECR_OFFSET		= 0x10, /* Error counter */
418c2ecf20Sopenharmony_ci	XCAN_ESR_OFFSET		= 0x14, /* Error status */
428c2ecf20Sopenharmony_ci	XCAN_SR_OFFSET		= 0x18, /* Status */
438c2ecf20Sopenharmony_ci	XCAN_ISR_OFFSET		= 0x1C, /* Interrupt status */
448c2ecf20Sopenharmony_ci	XCAN_IER_OFFSET		= 0x20, /* Interrupt enable */
458c2ecf20Sopenharmony_ci	XCAN_ICR_OFFSET		= 0x24, /* Interrupt clear */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* not on CAN FD cores */
488c2ecf20Sopenharmony_ci	XCAN_TXFIFO_OFFSET	= 0x30, /* TX FIFO base */
498c2ecf20Sopenharmony_ci	XCAN_RXFIFO_OFFSET	= 0x50, /* RX FIFO base */
508c2ecf20Sopenharmony_ci	XCAN_AFR_OFFSET		= 0x60, /* Acceptance Filter */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* only on CAN FD cores */
538c2ecf20Sopenharmony_ci	XCAN_F_BRPR_OFFSET	= 0x088, /* Data Phase Baud Rate
548c2ecf20Sopenharmony_ci					  * Prescalar
558c2ecf20Sopenharmony_ci					  */
568c2ecf20Sopenharmony_ci	XCAN_F_BTR_OFFSET	= 0x08C, /* Data Phase Bit Timing */
578c2ecf20Sopenharmony_ci	XCAN_TRR_OFFSET		= 0x0090, /* TX Buffer Ready Request */
588c2ecf20Sopenharmony_ci	XCAN_AFR_EXT_OFFSET	= 0x00E0, /* Acceptance Filter */
598c2ecf20Sopenharmony_ci	XCAN_FSR_OFFSET		= 0x00E8, /* RX FIFO Status */
608c2ecf20Sopenharmony_ci	XCAN_TXMSG_BASE_OFFSET	= 0x0100, /* TX Message Space */
618c2ecf20Sopenharmony_ci	XCAN_RXMSG_BASE_OFFSET	= 0x1100, /* RX Message Space */
628c2ecf20Sopenharmony_ci	XCAN_RXMSG_2_BASE_OFFSET	= 0x2100, /* RX Message Space */
638c2ecf20Sopenharmony_ci	XCAN_AFR_2_MASK_OFFSET	= 0x0A00, /* Acceptance Filter MASK */
648c2ecf20Sopenharmony_ci	XCAN_AFR_2_ID_OFFSET	= 0x0A04, /* Acceptance Filter ID */
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define XCAN_FRAME_ID_OFFSET(frame_base)	((frame_base) + 0x00)
688c2ecf20Sopenharmony_ci#define XCAN_FRAME_DLC_OFFSET(frame_base)	((frame_base) + 0x04)
698c2ecf20Sopenharmony_ci#define XCAN_FRAME_DW1_OFFSET(frame_base)	((frame_base) + 0x08)
708c2ecf20Sopenharmony_ci#define XCAN_FRAME_DW2_OFFSET(frame_base)	((frame_base) + 0x0C)
718c2ecf20Sopenharmony_ci#define XCANFD_FRAME_DW_OFFSET(frame_base)	((frame_base) + 0x08)
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define XCAN_CANFD_FRAME_SIZE		0x48
748c2ecf20Sopenharmony_ci#define XCAN_TXMSG_FRAME_OFFSET(n)	(XCAN_TXMSG_BASE_OFFSET + \
758c2ecf20Sopenharmony_ci					 XCAN_CANFD_FRAME_SIZE * (n))
768c2ecf20Sopenharmony_ci#define XCAN_RXMSG_FRAME_OFFSET(n)	(XCAN_RXMSG_BASE_OFFSET + \
778c2ecf20Sopenharmony_ci					 XCAN_CANFD_FRAME_SIZE * (n))
788c2ecf20Sopenharmony_ci#define XCAN_RXMSG_2_FRAME_OFFSET(n)	(XCAN_RXMSG_2_BASE_OFFSET + \
798c2ecf20Sopenharmony_ci					 XCAN_CANFD_FRAME_SIZE * (n))
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* the single TX mailbox used by this driver on CAN FD HW */
828c2ecf20Sopenharmony_ci#define XCAN_TX_MAILBOX_IDX		0
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */
858c2ecf20Sopenharmony_ci#define XCAN_SRR_CEN_MASK		0x00000002 /* CAN enable */
868c2ecf20Sopenharmony_ci#define XCAN_SRR_RESET_MASK		0x00000001 /* Soft Reset the CAN core */
878c2ecf20Sopenharmony_ci#define XCAN_MSR_LBACK_MASK		0x00000002 /* Loop back mode select */
888c2ecf20Sopenharmony_ci#define XCAN_MSR_SLEEP_MASK		0x00000001 /* Sleep mode select */
898c2ecf20Sopenharmony_ci#define XCAN_BRPR_BRP_MASK		0x000000FF /* Baud rate prescaler */
908c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_MASK		0x00000180 /* Synchronous jump width */
918c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_MASK		0x00000070 /* Time segment 2 */
928c2ecf20Sopenharmony_ci#define XCAN_BTR_TS1_MASK		0x0000000F /* Time segment 1 */
938c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_MASK_CANFD		0x000F0000 /* Synchronous jump width */
948c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_MASK_CANFD		0x00000F00 /* Time segment 2 */
958c2ecf20Sopenharmony_ci#define XCAN_BTR_TS1_MASK_CANFD		0x0000003F /* Time segment 1 */
968c2ecf20Sopenharmony_ci#define XCAN_ECR_REC_MASK		0x0000FF00 /* Receive error counter */
978c2ecf20Sopenharmony_ci#define XCAN_ECR_TEC_MASK		0x000000FF /* Transmit error counter */
988c2ecf20Sopenharmony_ci#define XCAN_ESR_ACKER_MASK		0x00000010 /* ACK error */
998c2ecf20Sopenharmony_ci#define XCAN_ESR_BERR_MASK		0x00000008 /* Bit error */
1008c2ecf20Sopenharmony_ci#define XCAN_ESR_STER_MASK		0x00000004 /* Stuff error */
1018c2ecf20Sopenharmony_ci#define XCAN_ESR_FMER_MASK		0x00000002 /* Form error */
1028c2ecf20Sopenharmony_ci#define XCAN_ESR_CRCER_MASK		0x00000001 /* CRC error */
1038c2ecf20Sopenharmony_ci#define XCAN_SR_TXFLL_MASK		0x00000400 /* TX FIFO is full */
1048c2ecf20Sopenharmony_ci#define XCAN_SR_ESTAT_MASK		0x00000180 /* Error status */
1058c2ecf20Sopenharmony_ci#define XCAN_SR_ERRWRN_MASK		0x00000040 /* Error warning */
1068c2ecf20Sopenharmony_ci#define XCAN_SR_NORMAL_MASK		0x00000008 /* Normal mode */
1078c2ecf20Sopenharmony_ci#define XCAN_SR_LBACK_MASK		0x00000002 /* Loop back mode */
1088c2ecf20Sopenharmony_ci#define XCAN_SR_CONFIG_MASK		0x00000001 /* Configuration mode */
1098c2ecf20Sopenharmony_ci#define XCAN_IXR_RXMNF_MASK		0x00020000 /* RX match not finished */
1108c2ecf20Sopenharmony_ci#define XCAN_IXR_TXFEMP_MASK		0x00004000 /* TX FIFO Empty */
1118c2ecf20Sopenharmony_ci#define XCAN_IXR_WKUP_MASK		0x00000800 /* Wake up interrupt */
1128c2ecf20Sopenharmony_ci#define XCAN_IXR_SLP_MASK		0x00000400 /* Sleep interrupt */
1138c2ecf20Sopenharmony_ci#define XCAN_IXR_BSOFF_MASK		0x00000200 /* Bus off interrupt */
1148c2ecf20Sopenharmony_ci#define XCAN_IXR_ERROR_MASK		0x00000100 /* Error interrupt */
1158c2ecf20Sopenharmony_ci#define XCAN_IXR_RXNEMP_MASK		0x00000080 /* RX FIFO NotEmpty intr */
1168c2ecf20Sopenharmony_ci#define XCAN_IXR_RXOFLW_MASK		0x00000040 /* RX FIFO Overflow intr */
1178c2ecf20Sopenharmony_ci#define XCAN_IXR_RXOK_MASK		0x00000010 /* Message received intr */
1188c2ecf20Sopenharmony_ci#define XCAN_IXR_TXFLL_MASK		0x00000004 /* Tx FIFO Full intr */
1198c2ecf20Sopenharmony_ci#define XCAN_IXR_TXOK_MASK		0x00000002 /* TX successful intr */
1208c2ecf20Sopenharmony_ci#define XCAN_IXR_ARBLST_MASK		0x00000001 /* Arbitration lost intr */
1218c2ecf20Sopenharmony_ci#define XCAN_IDR_ID1_MASK		0xFFE00000 /* Standard msg identifier */
1228c2ecf20Sopenharmony_ci#define XCAN_IDR_SRR_MASK		0x00100000 /* Substitute remote TXreq */
1238c2ecf20Sopenharmony_ci#define XCAN_IDR_IDE_MASK		0x00080000 /* Identifier extension */
1248c2ecf20Sopenharmony_ci#define XCAN_IDR_ID2_MASK		0x0007FFFE /* Extended message ident */
1258c2ecf20Sopenharmony_ci#define XCAN_IDR_RTR_MASK		0x00000001 /* Remote TX request */
1268c2ecf20Sopenharmony_ci#define XCAN_DLCR_DLC_MASK		0xF0000000 /* Data length code */
1278c2ecf20Sopenharmony_ci#define XCAN_FSR_FL_MASK		0x00003F00 /* RX Fill Level */
1288c2ecf20Sopenharmony_ci#define XCAN_2_FSR_FL_MASK		0x00007F00 /* RX Fill Level */
1298c2ecf20Sopenharmony_ci#define XCAN_FSR_IRI_MASK		0x00000080 /* RX Increment Read Index */
1308c2ecf20Sopenharmony_ci#define XCAN_FSR_RI_MASK		0x0000001F /* RX Read Index */
1318c2ecf20Sopenharmony_ci#define XCAN_2_FSR_RI_MASK		0x0000003F /* RX Read Index */
1328c2ecf20Sopenharmony_ci#define XCAN_DLCR_EDL_MASK		0x08000000 /* EDL Mask in DLC */
1338c2ecf20Sopenharmony_ci#define XCAN_DLCR_BRS_MASK		0x04000000 /* BRS Mask in DLC */
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
1368c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_SHIFT		7  /* Synchronous jump width */
1378c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_SHIFT		4  /* Time segment 2 */
1388c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_SHIFT_CANFD	16 /* Synchronous jump width */
1398c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_SHIFT_CANFD	8  /* Time segment 2 */
1408c2ecf20Sopenharmony_ci#define XCAN_IDR_ID1_SHIFT		21 /* Standard Messg Identifier */
1418c2ecf20Sopenharmony_ci#define XCAN_IDR_ID2_SHIFT		1  /* Extended Message Identifier */
1428c2ecf20Sopenharmony_ci#define XCAN_DLCR_DLC_SHIFT		28 /* Data length code */
1438c2ecf20Sopenharmony_ci#define XCAN_ESR_REC_SHIFT		8  /* Rx Error Count */
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* CAN frame length constants */
1468c2ecf20Sopenharmony_ci#define XCAN_FRAME_MAX_DATA_LEN		8
1478c2ecf20Sopenharmony_ci#define XCANFD_DW_BYTES			4
1488c2ecf20Sopenharmony_ci#define XCAN_TIMEOUT			(1 * HZ)
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* TX-FIFO-empty interrupt available */
1518c2ecf20Sopenharmony_ci#define XCAN_FLAG_TXFEMP	0x0001
1528c2ecf20Sopenharmony_ci/* RX Match Not Finished interrupt available */
1538c2ecf20Sopenharmony_ci#define XCAN_FLAG_RXMNF		0x0002
1548c2ecf20Sopenharmony_ci/* Extended acceptance filters with control at 0xE0 */
1558c2ecf20Sopenharmony_ci#define XCAN_FLAG_EXT_FILTERS	0x0004
1568c2ecf20Sopenharmony_ci/* TX mailboxes instead of TX FIFO */
1578c2ecf20Sopenharmony_ci#define XCAN_FLAG_TX_MAILBOXES	0x0008
1588c2ecf20Sopenharmony_ci/* RX FIFO with each buffer in separate registers at 0x1100
1598c2ecf20Sopenharmony_ci * instead of the regular FIFO at 0x50
1608c2ecf20Sopenharmony_ci */
1618c2ecf20Sopenharmony_ci#define XCAN_FLAG_RX_FIFO_MULTI	0x0010
1628c2ecf20Sopenharmony_ci#define XCAN_FLAG_CANFD_2	0x0020
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cienum xcan_ip_type {
1658c2ecf20Sopenharmony_ci	XAXI_CAN = 0,
1668c2ecf20Sopenharmony_ci	XZYNQ_CANPS,
1678c2ecf20Sopenharmony_ci	XAXI_CANFD,
1688c2ecf20Sopenharmony_ci	XAXI_CANFD_2_0,
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistruct xcan_devtype_data {
1728c2ecf20Sopenharmony_ci	enum xcan_ip_type cantype;
1738c2ecf20Sopenharmony_ci	unsigned int flags;
1748c2ecf20Sopenharmony_ci	const struct can_bittiming_const *bittiming_const;
1758c2ecf20Sopenharmony_ci	const char *bus_clk_name;
1768c2ecf20Sopenharmony_ci	unsigned int btr_ts2_shift;
1778c2ecf20Sopenharmony_ci	unsigned int btr_sjw_shift;
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/**
1818c2ecf20Sopenharmony_ci * struct xcan_priv - This definition define CAN driver instance
1828c2ecf20Sopenharmony_ci * @can:			CAN private data structure.
1838c2ecf20Sopenharmony_ci * @tx_lock:			Lock for synchronizing TX interrupt handling
1848c2ecf20Sopenharmony_ci * @tx_head:			Tx CAN packets ready to send on the queue
1858c2ecf20Sopenharmony_ci * @tx_tail:			Tx CAN packets successfully sended on the queue
1868c2ecf20Sopenharmony_ci * @tx_max:			Maximum number packets the driver can send
1878c2ecf20Sopenharmony_ci * @napi:			NAPI structure
1888c2ecf20Sopenharmony_ci * @read_reg:			For reading data from CAN registers
1898c2ecf20Sopenharmony_ci * @write_reg:			For writing data to CAN registers
1908c2ecf20Sopenharmony_ci * @dev:			Network device data structure
1918c2ecf20Sopenharmony_ci * @reg_base:			Ioremapped address to registers
1928c2ecf20Sopenharmony_ci * @irq_flags:			For request_irq()
1938c2ecf20Sopenharmony_ci * @bus_clk:			Pointer to struct clk
1948c2ecf20Sopenharmony_ci * @can_clk:			Pointer to struct clk
1958c2ecf20Sopenharmony_ci * @devtype:			Device type specific constants
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_cistruct xcan_priv {
1988c2ecf20Sopenharmony_ci	struct can_priv can;
1998c2ecf20Sopenharmony_ci	spinlock_t tx_lock; /* Lock for synchronizing TX interrupt handling */
2008c2ecf20Sopenharmony_ci	unsigned int tx_head;
2018c2ecf20Sopenharmony_ci	unsigned int tx_tail;
2028c2ecf20Sopenharmony_ci	unsigned int tx_max;
2038c2ecf20Sopenharmony_ci	struct napi_struct napi;
2048c2ecf20Sopenharmony_ci	u32 (*read_reg)(const struct xcan_priv *priv, enum xcan_reg reg);
2058c2ecf20Sopenharmony_ci	void (*write_reg)(const struct xcan_priv *priv, enum xcan_reg reg,
2068c2ecf20Sopenharmony_ci			  u32 val);
2078c2ecf20Sopenharmony_ci	struct device *dev;
2088c2ecf20Sopenharmony_ci	void __iomem *reg_base;
2098c2ecf20Sopenharmony_ci	unsigned long irq_flags;
2108c2ecf20Sopenharmony_ci	struct clk *bus_clk;
2118c2ecf20Sopenharmony_ci	struct clk *can_clk;
2128c2ecf20Sopenharmony_ci	struct xcan_devtype_data devtype;
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* CAN Bittiming constants as per Xilinx CAN specs */
2168c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const = {
2178c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
2188c2ecf20Sopenharmony_ci	.tseg1_min = 1,
2198c2ecf20Sopenharmony_ci	.tseg1_max = 16,
2208c2ecf20Sopenharmony_ci	.tseg2_min = 1,
2218c2ecf20Sopenharmony_ci	.tseg2_max = 8,
2228c2ecf20Sopenharmony_ci	.sjw_max = 4,
2238c2ecf20Sopenharmony_ci	.brp_min = 1,
2248c2ecf20Sopenharmony_ci	.brp_max = 256,
2258c2ecf20Sopenharmony_ci	.brp_inc = 1,
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/* AXI CANFD Arbitration Bittiming constants as per AXI CANFD 1.0 spec */
2298c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const_canfd = {
2308c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
2318c2ecf20Sopenharmony_ci	.tseg1_min = 1,
2328c2ecf20Sopenharmony_ci	.tseg1_max = 64,
2338c2ecf20Sopenharmony_ci	.tseg2_min = 1,
2348c2ecf20Sopenharmony_ci	.tseg2_max = 16,
2358c2ecf20Sopenharmony_ci	.sjw_max = 16,
2368c2ecf20Sopenharmony_ci	.brp_min = 1,
2378c2ecf20Sopenharmony_ci	.brp_max = 256,
2388c2ecf20Sopenharmony_ci	.brp_inc = 1,
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */
2428c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_data_bittiming_const_canfd = {
2438c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
2448c2ecf20Sopenharmony_ci	.tseg1_min = 1,
2458c2ecf20Sopenharmony_ci	.tseg1_max = 16,
2468c2ecf20Sopenharmony_ci	.tseg2_min = 1,
2478c2ecf20Sopenharmony_ci	.tseg2_max = 8,
2488c2ecf20Sopenharmony_ci	.sjw_max = 8,
2498c2ecf20Sopenharmony_ci	.brp_min = 1,
2508c2ecf20Sopenharmony_ci	.brp_max = 256,
2518c2ecf20Sopenharmony_ci	.brp_inc = 1,
2528c2ecf20Sopenharmony_ci};
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/* AXI CANFD 2.0 Arbitration Bittiming constants as per AXI CANFD 2.0 spec */
2558c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
2568c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
2578c2ecf20Sopenharmony_ci	.tseg1_min = 1,
2588c2ecf20Sopenharmony_ci	.tseg1_max = 256,
2598c2ecf20Sopenharmony_ci	.tseg2_min = 1,
2608c2ecf20Sopenharmony_ci	.tseg2_max = 128,
2618c2ecf20Sopenharmony_ci	.sjw_max = 128,
2628c2ecf20Sopenharmony_ci	.brp_min = 1,
2638c2ecf20Sopenharmony_ci	.brp_max = 256,
2648c2ecf20Sopenharmony_ci	.brp_inc = 1,
2658c2ecf20Sopenharmony_ci};
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */
2688c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
2698c2ecf20Sopenharmony_ci	.name = DRIVER_NAME,
2708c2ecf20Sopenharmony_ci	.tseg1_min = 1,
2718c2ecf20Sopenharmony_ci	.tseg1_max = 32,
2728c2ecf20Sopenharmony_ci	.tseg2_min = 1,
2738c2ecf20Sopenharmony_ci	.tseg2_max = 16,
2748c2ecf20Sopenharmony_ci	.sjw_max = 16,
2758c2ecf20Sopenharmony_ci	.brp_min = 1,
2768c2ecf20Sopenharmony_ci	.brp_max = 256,
2778c2ecf20Sopenharmony_ci	.brp_inc = 1,
2788c2ecf20Sopenharmony_ci};
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/**
2818c2ecf20Sopenharmony_ci * xcan_write_reg_le - Write a value to the device register little endian
2828c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
2838c2ecf20Sopenharmony_ci * @reg:	Register offset
2848c2ecf20Sopenharmony_ci * @val:	Value to write at the Register offset
2858c2ecf20Sopenharmony_ci *
2868c2ecf20Sopenharmony_ci * Write data to the paricular CAN register
2878c2ecf20Sopenharmony_ci */
2888c2ecf20Sopenharmony_cistatic void xcan_write_reg_le(const struct xcan_priv *priv, enum xcan_reg reg,
2898c2ecf20Sopenharmony_ci			      u32 val)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	iowrite32(val, priv->reg_base + reg);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/**
2958c2ecf20Sopenharmony_ci * xcan_read_reg_le - Read a value from the device register little endian
2968c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
2978c2ecf20Sopenharmony_ci * @reg:	Register offset
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * Read data from the particular CAN register
3008c2ecf20Sopenharmony_ci * Return: value read from the CAN register
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_cistatic u32 xcan_read_reg_le(const struct xcan_priv *priv, enum xcan_reg reg)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	return ioread32(priv->reg_base + reg);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/**
3088c2ecf20Sopenharmony_ci * xcan_write_reg_be - Write a value to the device register big endian
3098c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
3108c2ecf20Sopenharmony_ci * @reg:	Register offset
3118c2ecf20Sopenharmony_ci * @val:	Value to write at the Register offset
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * Write data to the paricular CAN register
3148c2ecf20Sopenharmony_ci */
3158c2ecf20Sopenharmony_cistatic void xcan_write_reg_be(const struct xcan_priv *priv, enum xcan_reg reg,
3168c2ecf20Sopenharmony_ci			      u32 val)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	iowrite32be(val, priv->reg_base + reg);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/**
3228c2ecf20Sopenharmony_ci * xcan_read_reg_be - Read a value from the device register big endian
3238c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
3248c2ecf20Sopenharmony_ci * @reg:	Register offset
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci * Read data from the particular CAN register
3278c2ecf20Sopenharmony_ci * Return: value read from the CAN register
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_cistatic u32 xcan_read_reg_be(const struct xcan_priv *priv, enum xcan_reg reg)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	return ioread32be(priv->reg_base + reg);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/**
3358c2ecf20Sopenharmony_ci * xcan_rx_int_mask - Get the mask for the receive interrupt
3368c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
3378c2ecf20Sopenharmony_ci *
3388c2ecf20Sopenharmony_ci * Return: The receive interrupt mask used by the driver on this HW
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic u32 xcan_rx_int_mask(const struct xcan_priv *priv)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	/* RXNEMP is better suited for our use case as it cannot be cleared
3438c2ecf20Sopenharmony_ci	 * while the FIFO is non-empty, but CAN FD HW does not have it
3448c2ecf20Sopenharmony_ci	 */
3458c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI)
3468c2ecf20Sopenharmony_ci		return XCAN_IXR_RXOK_MASK;
3478c2ecf20Sopenharmony_ci	else
3488c2ecf20Sopenharmony_ci		return XCAN_IXR_RXNEMP_MASK;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/**
3528c2ecf20Sopenharmony_ci * set_reset_mode - Resets the CAN device mode
3538c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * This is the driver reset mode routine.The driver
3568c2ecf20Sopenharmony_ci * enters into configuration mode.
3578c2ecf20Sopenharmony_ci *
3588c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
3598c2ecf20Sopenharmony_ci */
3608c2ecf20Sopenharmony_cistatic int set_reset_mode(struct net_device *ndev)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
3638c2ecf20Sopenharmony_ci	unsigned long timeout;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	timeout = jiffies + XCAN_TIMEOUT;
3688c2ecf20Sopenharmony_ci	while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) {
3698c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
3708c2ecf20Sopenharmony_ci			netdev_warn(ndev, "timed out for config mode\n");
3718c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci		usleep_range(500, 10000);
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* reset clears FIFOs */
3778c2ecf20Sopenharmony_ci	priv->tx_head = 0;
3788c2ecf20Sopenharmony_ci	priv->tx_tail = 0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci/**
3848c2ecf20Sopenharmony_ci * xcan_set_bittiming - CAN set bit timing routine
3858c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
3868c2ecf20Sopenharmony_ci *
3878c2ecf20Sopenharmony_ci * This is the driver set bittiming  routine.
3888c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_cistatic int xcan_set_bittiming(struct net_device *ndev)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
3938c2ecf20Sopenharmony_ci	struct can_bittiming *bt = &priv->can.bittiming;
3948c2ecf20Sopenharmony_ci	struct can_bittiming *dbt = &priv->can.data_bittiming;
3958c2ecf20Sopenharmony_ci	u32 btr0, btr1;
3968c2ecf20Sopenharmony_ci	u32 is_config_mode;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* Check whether Xilinx CAN is in configuration mode.
3998c2ecf20Sopenharmony_ci	 * It cannot set bit timing if Xilinx CAN is not in configuration mode.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) &
4028c2ecf20Sopenharmony_ci				XCAN_SR_CONFIG_MASK;
4038c2ecf20Sopenharmony_ci	if (!is_config_mode) {
4048c2ecf20Sopenharmony_ci		netdev_alert(ndev,
4058c2ecf20Sopenharmony_ci			     "BUG! Cannot set bittiming - CAN is not in config mode\n");
4068c2ecf20Sopenharmony_ci		return -EPERM;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Setting Baud Rate prescalar value in BRPR Register */
4108c2ecf20Sopenharmony_ci	btr0 = (bt->brp - 1);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Setting Time Segment 1 in BTR Register */
4138c2ecf20Sopenharmony_ci	btr1 = (bt->prop_seg + bt->phase_seg1 - 1);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Setting Time Segment 2 in BTR Register */
4168c2ecf20Sopenharmony_ci	btr1 |= (bt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* Setting Synchronous jump width in BTR Register */
4198c2ecf20Sopenharmony_ci	btr1 |= (bt->sjw - 1) << priv->devtype.btr_sjw_shift;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0);
4228c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_BTR_OFFSET, btr1);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (priv->devtype.cantype == XAXI_CANFD ||
4258c2ecf20Sopenharmony_ci	    priv->devtype.cantype == XAXI_CANFD_2_0) {
4268c2ecf20Sopenharmony_ci		/* Setting Baud Rate prescalar value in F_BRPR Register */
4278c2ecf20Sopenharmony_ci		btr0 = dbt->brp - 1;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		/* Setting Time Segment 1 in BTR Register */
4308c2ecf20Sopenharmony_ci		btr1 = dbt->prop_seg + dbt->phase_seg1 - 1;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		/* Setting Time Segment 2 in BTR Register */
4338c2ecf20Sopenharmony_ci		btr1 |= (dbt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		/* Setting Synchronous jump width in BTR Register */
4368c2ecf20Sopenharmony_ci		btr1 |= (dbt->sjw - 1) << priv->devtype.btr_sjw_shift;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_F_BRPR_OFFSET, btr0);
4398c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_F_BTR_OFFSET, btr1);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n",
4438c2ecf20Sopenharmony_ci		   priv->read_reg(priv, XCAN_BRPR_OFFSET),
4448c2ecf20Sopenharmony_ci		   priv->read_reg(priv, XCAN_BTR_OFFSET));
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return 0;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci/**
4508c2ecf20Sopenharmony_ci * xcan_chip_start - This the drivers start routine
4518c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
4528c2ecf20Sopenharmony_ci *
4538c2ecf20Sopenharmony_ci * This is the drivers start routine.
4548c2ecf20Sopenharmony_ci * Based on the State of the CAN device it puts
4558c2ecf20Sopenharmony_ci * the CAN device into a proper mode.
4568c2ecf20Sopenharmony_ci *
4578c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
4588c2ecf20Sopenharmony_ci */
4598c2ecf20Sopenharmony_cistatic int xcan_chip_start(struct net_device *ndev)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
4628c2ecf20Sopenharmony_ci	u32 reg_msr;
4638c2ecf20Sopenharmony_ci	int err;
4648c2ecf20Sopenharmony_ci	u32 ier;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* Check if it is in reset mode */
4678c2ecf20Sopenharmony_ci	err = set_reset_mode(ndev);
4688c2ecf20Sopenharmony_ci	if (err < 0)
4698c2ecf20Sopenharmony_ci		return err;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	err = xcan_set_bittiming(ndev);
4728c2ecf20Sopenharmony_ci	if (err < 0)
4738c2ecf20Sopenharmony_ci		return err;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* Enable interrupts
4768c2ecf20Sopenharmony_ci	 *
4778c2ecf20Sopenharmony_ci	 * We enable the ERROR interrupt even with
4788c2ecf20Sopenharmony_ci	 * CAN_CTRLMODE_BERR_REPORTING disabled as there is no
4798c2ecf20Sopenharmony_ci	 * dedicated interrupt for a state change to
4808c2ecf20Sopenharmony_ci	 * ERROR_WARNING/ERROR_PASSIVE.
4818c2ecf20Sopenharmony_ci	 */
4828c2ecf20Sopenharmony_ci	ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |
4838c2ecf20Sopenharmony_ci		XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK |
4848c2ecf20Sopenharmony_ci		XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
4858c2ecf20Sopenharmony_ci		XCAN_IXR_ARBLST_MASK | xcan_rx_int_mask(priv);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_RXMNF)
4888c2ecf20Sopenharmony_ci		ier |= XCAN_IXR_RXMNF_MASK;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_IER_OFFSET, ier);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* Check whether it is loopback mode or normal mode  */
4938c2ecf20Sopenharmony_ci	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
4948c2ecf20Sopenharmony_ci		reg_msr = XCAN_MSR_LBACK_MASK;
4958c2ecf20Sopenharmony_ci	else
4968c2ecf20Sopenharmony_ci		reg_msr = 0x0;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* enable the first extended filter, if any, as cores with extended
4998c2ecf20Sopenharmony_ci	 * filtering default to non-receipt if all filters are disabled
5008c2ecf20Sopenharmony_ci	 */
5018c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_EXT_FILTERS)
5028c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_AFR_EXT_OFFSET, 0x00000001);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr);
5058c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	netdev_dbg(ndev, "status:#x%08x\n",
5088c2ecf20Sopenharmony_ci		   priv->read_reg(priv, XCAN_SR_OFFSET));
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	priv->can.state = CAN_STATE_ERROR_ACTIVE;
5118c2ecf20Sopenharmony_ci	return 0;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci/**
5158c2ecf20Sopenharmony_ci * xcan_do_set_mode - This sets the mode of the driver
5168c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
5178c2ecf20Sopenharmony_ci * @mode:	Tells the mode of the driver
5188c2ecf20Sopenharmony_ci *
5198c2ecf20Sopenharmony_ci * This check the drivers state and calls the
5208c2ecf20Sopenharmony_ci * the corresponding modes to set.
5218c2ecf20Sopenharmony_ci *
5228c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
5238c2ecf20Sopenharmony_ci */
5248c2ecf20Sopenharmony_cistatic int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	int ret;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	switch (mode) {
5298c2ecf20Sopenharmony_ci	case CAN_MODE_START:
5308c2ecf20Sopenharmony_ci		ret = xcan_chip_start(ndev);
5318c2ecf20Sopenharmony_ci		if (ret < 0) {
5328c2ecf20Sopenharmony_ci			netdev_err(ndev, "xcan_chip_start failed!\n");
5338c2ecf20Sopenharmony_ci			return ret;
5348c2ecf20Sopenharmony_ci		}
5358c2ecf20Sopenharmony_ci		netif_wake_queue(ndev);
5368c2ecf20Sopenharmony_ci		break;
5378c2ecf20Sopenharmony_ci	default:
5388c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
5398c2ecf20Sopenharmony_ci		break;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return ret;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci/**
5468c2ecf20Sopenharmony_ci * xcan_write_frame - Write a frame to HW
5478c2ecf20Sopenharmony_ci * @ndev:		Pointer to net_device structure
5488c2ecf20Sopenharmony_ci * @skb:		sk_buff pointer that contains data to be Txed
5498c2ecf20Sopenharmony_ci * @frame_offset:	Register offset to write the frame to
5508c2ecf20Sopenharmony_ci */
5518c2ecf20Sopenharmony_cistatic void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb,
5528c2ecf20Sopenharmony_ci			     int frame_offset)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	u32 id, dlc, data[2] = {0, 0};
5558c2ecf20Sopenharmony_ci	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
5568c2ecf20Sopenharmony_ci	u32 ramoff, dwindex = 0, i;
5578c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Watch carefully on the bit sequence */
5608c2ecf20Sopenharmony_ci	if (cf->can_id & CAN_EFF_FLAG) {
5618c2ecf20Sopenharmony_ci		/* Extended CAN ID format */
5628c2ecf20Sopenharmony_ci		id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) &
5638c2ecf20Sopenharmony_ci			XCAN_IDR_ID2_MASK;
5648c2ecf20Sopenharmony_ci		id |= (((cf->can_id & CAN_EFF_MASK) >>
5658c2ecf20Sopenharmony_ci			(CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)) <<
5668c2ecf20Sopenharmony_ci			XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		/* The substibute remote TX request bit should be "1"
5698c2ecf20Sopenharmony_ci		 * for extended frames as in the Xilinx CAN datasheet
5708c2ecf20Sopenharmony_ci		 */
5718c2ecf20Sopenharmony_ci		id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		if (cf->can_id & CAN_RTR_FLAG)
5748c2ecf20Sopenharmony_ci			/* Extended frames remote TX request */
5758c2ecf20Sopenharmony_ci			id |= XCAN_IDR_RTR_MASK;
5768c2ecf20Sopenharmony_ci	} else {
5778c2ecf20Sopenharmony_ci		/* Standard CAN ID format */
5788c2ecf20Sopenharmony_ci		id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) &
5798c2ecf20Sopenharmony_ci			XCAN_IDR_ID1_MASK;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		if (cf->can_id & CAN_RTR_FLAG)
5828c2ecf20Sopenharmony_ci			/* Standard frames remote TX request */
5838c2ecf20Sopenharmony_ci			id |= XCAN_IDR_SRR_MASK;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	dlc = can_len2dlc(cf->len) << XCAN_DLCR_DLC_SHIFT;
5878c2ecf20Sopenharmony_ci	if (can_is_canfd_skb(skb)) {
5888c2ecf20Sopenharmony_ci		if (cf->flags & CANFD_BRS)
5898c2ecf20Sopenharmony_ci			dlc |= XCAN_DLCR_BRS_MASK;
5908c2ecf20Sopenharmony_ci		dlc |= XCAN_DLCR_EDL_MASK;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) &&
5948c2ecf20Sopenharmony_ci	    (priv->devtype.flags & XCAN_FLAG_TXFEMP))
5958c2ecf20Sopenharmony_ci		can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max);
5968c2ecf20Sopenharmony_ci	else
5978c2ecf20Sopenharmony_ci		can_put_echo_skb(skb, ndev, 0);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	priv->tx_head++;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id);
6028c2ecf20Sopenharmony_ci	/* If the CAN frame is RTR frame this write triggers transmission
6038c2ecf20Sopenharmony_ci	 * (not on CAN FD)
6048c2ecf20Sopenharmony_ci	 */
6058c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_offset), dlc);
6068c2ecf20Sopenharmony_ci	if (priv->devtype.cantype == XAXI_CANFD ||
6078c2ecf20Sopenharmony_ci	    priv->devtype.cantype == XAXI_CANFD_2_0) {
6088c2ecf20Sopenharmony_ci		for (i = 0; i < cf->len; i += 4) {
6098c2ecf20Sopenharmony_ci			ramoff = XCANFD_FRAME_DW_OFFSET(frame_offset) +
6108c2ecf20Sopenharmony_ci					(dwindex * XCANFD_DW_BYTES);
6118c2ecf20Sopenharmony_ci			priv->write_reg(priv, ramoff,
6128c2ecf20Sopenharmony_ci					be32_to_cpup((__be32 *)(cf->data + i)));
6138c2ecf20Sopenharmony_ci			dwindex++;
6148c2ecf20Sopenharmony_ci		}
6158c2ecf20Sopenharmony_ci	} else {
6168c2ecf20Sopenharmony_ci		if (cf->len > 0)
6178c2ecf20Sopenharmony_ci			data[0] = be32_to_cpup((__be32 *)(cf->data + 0));
6188c2ecf20Sopenharmony_ci		if (cf->len > 4)
6198c2ecf20Sopenharmony_ci			data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		if (!(cf->can_id & CAN_RTR_FLAG)) {
6228c2ecf20Sopenharmony_ci			priv->write_reg(priv,
6238c2ecf20Sopenharmony_ci					XCAN_FRAME_DW1_OFFSET(frame_offset),
6248c2ecf20Sopenharmony_ci					data[0]);
6258c2ecf20Sopenharmony_ci			/* If the CAN frame is Standard/Extended frame this
6268c2ecf20Sopenharmony_ci			 * write triggers transmission (not on CAN FD)
6278c2ecf20Sopenharmony_ci			 */
6288c2ecf20Sopenharmony_ci			priv->write_reg(priv,
6298c2ecf20Sopenharmony_ci					XCAN_FRAME_DW2_OFFSET(frame_offset),
6308c2ecf20Sopenharmony_ci					data[1]);
6318c2ecf20Sopenharmony_ci		}
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/**
6368c2ecf20Sopenharmony_ci * xcan_start_xmit_fifo - Starts the transmission (FIFO mode)
6378c2ecf20Sopenharmony_ci * @skb:	sk_buff pointer that contains data to be Txed
6388c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * Return: 0 on success, -ENOSPC if FIFO is full.
6418c2ecf20Sopenharmony_ci */
6428c2ecf20Sopenharmony_cistatic int xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
6458c2ecf20Sopenharmony_ci	unsigned long flags;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/* Check if the TX buffer is full */
6488c2ecf20Sopenharmony_ci	if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) &
6498c2ecf20Sopenharmony_ci			XCAN_SR_TXFLL_MASK))
6508c2ecf20Sopenharmony_ci		return -ENOSPC;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->tx_lock, flags);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	xcan_write_frame(ndev, skb, XCAN_TXFIFO_OFFSET);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */
6578c2ecf20Sopenharmony_ci	if (priv->tx_max > 1)
6588c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* Check if the TX buffer is full */
6618c2ecf20Sopenharmony_ci	if ((priv->tx_head - priv->tx_tail) == priv->tx_max)
6628c2ecf20Sopenharmony_ci		netif_stop_queue(ndev);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->tx_lock, flags);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci * xcan_start_xmit_mailbox - Starts the transmission (mailbox mode)
6718c2ecf20Sopenharmony_ci * @skb:	sk_buff pointer that contains data to be Txed
6728c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * Return: 0 on success, -ENOSPC if there is no space
6758c2ecf20Sopenharmony_ci */
6768c2ecf20Sopenharmony_cistatic int xcan_start_xmit_mailbox(struct sk_buff *skb, struct net_device *ndev)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
6798c2ecf20Sopenharmony_ci	unsigned long flags;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (unlikely(priv->read_reg(priv, XCAN_TRR_OFFSET) &
6828c2ecf20Sopenharmony_ci		     BIT(XCAN_TX_MAILBOX_IDX)))
6838c2ecf20Sopenharmony_ci		return -ENOSPC;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->tx_lock, flags);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	xcan_write_frame(ndev, skb,
6888c2ecf20Sopenharmony_ci			 XCAN_TXMSG_FRAME_OFFSET(XCAN_TX_MAILBOX_IDX));
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	/* Mark buffer as ready for transmit */
6918c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_TRR_OFFSET, BIT(XCAN_TX_MAILBOX_IDX));
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	netif_stop_queue(ndev);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->tx_lock, flags);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return 0;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/**
7018c2ecf20Sopenharmony_ci * xcan_start_xmit - Starts the transmission
7028c2ecf20Sopenharmony_ci * @skb:	sk_buff pointer that contains data to be Txed
7038c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
7048c2ecf20Sopenharmony_ci *
7058c2ecf20Sopenharmony_ci * This function is invoked from upper layers to initiate transmission.
7068c2ecf20Sopenharmony_ci *
7078c2ecf20Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full
7088c2ecf20Sopenharmony_ci */
7098c2ecf20Sopenharmony_cistatic netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
7128c2ecf20Sopenharmony_ci	int ret;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (can_dropped_invalid_skb(ndev, skb))
7158c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES)
7188c2ecf20Sopenharmony_ci		ret = xcan_start_xmit_mailbox(skb, ndev);
7198c2ecf20Sopenharmony_ci	else
7208c2ecf20Sopenharmony_ci		ret = xcan_start_xmit_fifo(skb, ndev);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (ret < 0) {
7238c2ecf20Sopenharmony_ci		netdev_err(ndev, "BUG!, TX full when queue awake!\n");
7248c2ecf20Sopenharmony_ci		netif_stop_queue(ndev);
7258c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci/**
7328c2ecf20Sopenharmony_ci * xcan_rx -  Is called from CAN isr to complete the received
7338c2ecf20Sopenharmony_ci *		frame  processing
7348c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
7358c2ecf20Sopenharmony_ci * @frame_base:	Register offset to the frame to be read
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * This function is invoked from the CAN isr(poll) to process the Rx frames. It
7388c2ecf20Sopenharmony_ci * does minimal processing and invokes "netif_receive_skb" to complete further
7398c2ecf20Sopenharmony_ci * processing.
7408c2ecf20Sopenharmony_ci * Return: 1 on success and 0 on failure.
7418c2ecf20Sopenharmony_ci */
7428c2ecf20Sopenharmony_cistatic int xcan_rx(struct net_device *ndev, int frame_base)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
7458c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
7468c2ecf20Sopenharmony_ci	struct can_frame *cf;
7478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7488c2ecf20Sopenharmony_ci	u32 id_xcan, dlc, data[2] = {0, 0};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	skb = alloc_can_skb(ndev, &cf);
7518c2ecf20Sopenharmony_ci	if (unlikely(!skb)) {
7528c2ecf20Sopenharmony_ci		stats->rx_dropped++;
7538c2ecf20Sopenharmony_ci		return 0;
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* Read a frame from Xilinx zynq CANPS */
7578c2ecf20Sopenharmony_ci	id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base));
7588c2ecf20Sopenharmony_ci	dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)) >>
7598c2ecf20Sopenharmony_ci				   XCAN_DLCR_DLC_SHIFT;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/* Change Xilinx CAN data length format to socketCAN data format */
7628c2ecf20Sopenharmony_ci	cf->can_dlc = get_can_dlc(dlc);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* Change Xilinx CAN ID format to socketCAN ID format */
7658c2ecf20Sopenharmony_ci	if (id_xcan & XCAN_IDR_IDE_MASK) {
7668c2ecf20Sopenharmony_ci		/* The received frame is an Extended format frame */
7678c2ecf20Sopenharmony_ci		cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
7688c2ecf20Sopenharmony_ci		cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
7698c2ecf20Sopenharmony_ci				XCAN_IDR_ID2_SHIFT;
7708c2ecf20Sopenharmony_ci		cf->can_id |= CAN_EFF_FLAG;
7718c2ecf20Sopenharmony_ci		if (id_xcan & XCAN_IDR_RTR_MASK)
7728c2ecf20Sopenharmony_ci			cf->can_id |= CAN_RTR_FLAG;
7738c2ecf20Sopenharmony_ci	} else {
7748c2ecf20Sopenharmony_ci		/* The received frame is a standard format frame */
7758c2ecf20Sopenharmony_ci		cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
7768c2ecf20Sopenharmony_ci				XCAN_IDR_ID1_SHIFT;
7778c2ecf20Sopenharmony_ci		if (id_xcan & XCAN_IDR_SRR_MASK)
7788c2ecf20Sopenharmony_ci			cf->can_id |= CAN_RTR_FLAG;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* DW1/DW2 must always be read to remove message from RXFIFO */
7828c2ecf20Sopenharmony_ci	data[0] = priv->read_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_base));
7838c2ecf20Sopenharmony_ci	data[1] = priv->read_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_base));
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	if (!(cf->can_id & CAN_RTR_FLAG)) {
7868c2ecf20Sopenharmony_ci		/* Change Xilinx CAN data format to socketCAN data format */
7878c2ecf20Sopenharmony_ci		if (cf->can_dlc > 0)
7888c2ecf20Sopenharmony_ci			*(__be32 *)(cf->data) = cpu_to_be32(data[0]);
7898c2ecf20Sopenharmony_ci		if (cf->can_dlc > 4)
7908c2ecf20Sopenharmony_ci			*(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]);
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	stats->rx_bytes += cf->can_dlc;
7948c2ecf20Sopenharmony_ci	stats->rx_packets++;
7958c2ecf20Sopenharmony_ci	netif_receive_skb(skb);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	return 1;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci/**
8018c2ecf20Sopenharmony_ci * xcanfd_rx -  Is called from CAN isr to complete the received
8028c2ecf20Sopenharmony_ci *		frame  processing
8038c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
8048c2ecf20Sopenharmony_ci * @frame_base:	Register offset to the frame to be read
8058c2ecf20Sopenharmony_ci *
8068c2ecf20Sopenharmony_ci * This function is invoked from the CAN isr(poll) to process the Rx frames. It
8078c2ecf20Sopenharmony_ci * does minimal processing and invokes "netif_receive_skb" to complete further
8088c2ecf20Sopenharmony_ci * processing.
8098c2ecf20Sopenharmony_ci * Return: 1 on success and 0 on failure.
8108c2ecf20Sopenharmony_ci */
8118c2ecf20Sopenharmony_cistatic int xcanfd_rx(struct net_device *ndev, int frame_base)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
8148c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
8158c2ecf20Sopenharmony_ci	struct canfd_frame *cf;
8168c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8178c2ecf20Sopenharmony_ci	u32 id_xcan, dlc, data[2] = {0, 0}, dwindex = 0, i, dw_offset;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base));
8208c2ecf20Sopenharmony_ci	dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base));
8218c2ecf20Sopenharmony_ci	if (dlc & XCAN_DLCR_EDL_MASK)
8228c2ecf20Sopenharmony_ci		skb = alloc_canfd_skb(ndev, &cf);
8238c2ecf20Sopenharmony_ci	else
8248c2ecf20Sopenharmony_ci		skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (unlikely(!skb)) {
8278c2ecf20Sopenharmony_ci		stats->rx_dropped++;
8288c2ecf20Sopenharmony_ci		return 0;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* Change Xilinx CANFD data length format to socketCAN data
8328c2ecf20Sopenharmony_ci	 * format
8338c2ecf20Sopenharmony_ci	 */
8348c2ecf20Sopenharmony_ci	if (dlc & XCAN_DLCR_EDL_MASK)
8358c2ecf20Sopenharmony_ci		cf->len = can_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >>
8368c2ecf20Sopenharmony_ci				  XCAN_DLCR_DLC_SHIFT);
8378c2ecf20Sopenharmony_ci	else
8388c2ecf20Sopenharmony_ci		cf->len = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >>
8398c2ecf20Sopenharmony_ci					  XCAN_DLCR_DLC_SHIFT);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* Change Xilinx CAN ID format to socketCAN ID format */
8428c2ecf20Sopenharmony_ci	if (id_xcan & XCAN_IDR_IDE_MASK) {
8438c2ecf20Sopenharmony_ci		/* The received frame is an Extended format frame */
8448c2ecf20Sopenharmony_ci		cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
8458c2ecf20Sopenharmony_ci		cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
8468c2ecf20Sopenharmony_ci				XCAN_IDR_ID2_SHIFT;
8478c2ecf20Sopenharmony_ci		cf->can_id |= CAN_EFF_FLAG;
8488c2ecf20Sopenharmony_ci		if (id_xcan & XCAN_IDR_RTR_MASK)
8498c2ecf20Sopenharmony_ci			cf->can_id |= CAN_RTR_FLAG;
8508c2ecf20Sopenharmony_ci	} else {
8518c2ecf20Sopenharmony_ci		/* The received frame is a standard format frame */
8528c2ecf20Sopenharmony_ci		cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
8538c2ecf20Sopenharmony_ci				XCAN_IDR_ID1_SHIFT;
8548c2ecf20Sopenharmony_ci		if (!(dlc & XCAN_DLCR_EDL_MASK) && (id_xcan &
8558c2ecf20Sopenharmony_ci					XCAN_IDR_SRR_MASK))
8568c2ecf20Sopenharmony_ci			cf->can_id |= CAN_RTR_FLAG;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	/* Check the frame received is FD or not*/
8608c2ecf20Sopenharmony_ci	if (dlc & XCAN_DLCR_EDL_MASK) {
8618c2ecf20Sopenharmony_ci		for (i = 0; i < cf->len; i += 4) {
8628c2ecf20Sopenharmony_ci			dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base) +
8638c2ecf20Sopenharmony_ci					(dwindex * XCANFD_DW_BYTES);
8648c2ecf20Sopenharmony_ci			data[0] = priv->read_reg(priv, dw_offset);
8658c2ecf20Sopenharmony_ci			*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
8668c2ecf20Sopenharmony_ci			dwindex++;
8678c2ecf20Sopenharmony_ci		}
8688c2ecf20Sopenharmony_ci	} else {
8698c2ecf20Sopenharmony_ci		for (i = 0; i < cf->len; i += 4) {
8708c2ecf20Sopenharmony_ci			dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base);
8718c2ecf20Sopenharmony_ci			data[0] = priv->read_reg(priv, dw_offset + i);
8728c2ecf20Sopenharmony_ci			*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci	stats->rx_bytes += cf->len;
8768c2ecf20Sopenharmony_ci	stats->rx_packets++;
8778c2ecf20Sopenharmony_ci	netif_receive_skb(skb);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	return 1;
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci/**
8838c2ecf20Sopenharmony_ci * xcan_current_error_state - Get current error state from HW
8848c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
8858c2ecf20Sopenharmony_ci *
8868c2ecf20Sopenharmony_ci * Checks the current CAN error state from the HW. Note that this
8878c2ecf20Sopenharmony_ci * only checks for ERROR_PASSIVE and ERROR_WARNING.
8888c2ecf20Sopenharmony_ci *
8898c2ecf20Sopenharmony_ci * Return:
8908c2ecf20Sopenharmony_ci * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE
8918c2ecf20Sopenharmony_ci * otherwise.
8928c2ecf20Sopenharmony_ci */
8938c2ecf20Sopenharmony_cistatic enum can_state xcan_current_error_state(struct net_device *ndev)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
8968c2ecf20Sopenharmony_ci	u32 status = priv->read_reg(priv, XCAN_SR_OFFSET);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK)
8998c2ecf20Sopenharmony_ci		return CAN_STATE_ERROR_PASSIVE;
9008c2ecf20Sopenharmony_ci	else if (status & XCAN_SR_ERRWRN_MASK)
9018c2ecf20Sopenharmony_ci		return CAN_STATE_ERROR_WARNING;
9028c2ecf20Sopenharmony_ci	else
9038c2ecf20Sopenharmony_ci		return CAN_STATE_ERROR_ACTIVE;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/**
9078c2ecf20Sopenharmony_ci * xcan_set_error_state - Set new CAN error state
9088c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
9098c2ecf20Sopenharmony_ci * @new_state:	The new CAN state to be set
9108c2ecf20Sopenharmony_ci * @cf:		Error frame to be populated or NULL
9118c2ecf20Sopenharmony_ci *
9128c2ecf20Sopenharmony_ci * Set new CAN error state for the device, updating statistics and
9138c2ecf20Sopenharmony_ci * populating the error frame if given.
9148c2ecf20Sopenharmony_ci */
9158c2ecf20Sopenharmony_cistatic void xcan_set_error_state(struct net_device *ndev,
9168c2ecf20Sopenharmony_ci				 enum can_state new_state,
9178c2ecf20Sopenharmony_ci				 struct can_frame *cf)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
9208c2ecf20Sopenharmony_ci	u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET);
9218c2ecf20Sopenharmony_ci	u32 txerr = ecr & XCAN_ECR_TEC_MASK;
9228c2ecf20Sopenharmony_ci	u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT;
9238c2ecf20Sopenharmony_ci	enum can_state tx_state = txerr >= rxerr ? new_state : 0;
9248c2ecf20Sopenharmony_ci	enum can_state rx_state = txerr <= rxerr ? new_state : 0;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* non-ERROR states are handled elsewhere */
9278c2ecf20Sopenharmony_ci	if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE))
9288c2ecf20Sopenharmony_ci		return;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	can_change_state(ndev, cf, tx_state, rx_state);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	if (cf) {
9338c2ecf20Sopenharmony_ci		cf->data[6] = txerr;
9348c2ecf20Sopenharmony_ci		cf->data[7] = rxerr;
9358c2ecf20Sopenharmony_ci	}
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci/**
9398c2ecf20Sopenharmony_ci * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX
9408c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
9418c2ecf20Sopenharmony_ci *
9428c2ecf20Sopenharmony_ci * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if
9438c2ecf20Sopenharmony_ci * the performed RX/TX has caused it to drop to a lesser state and set
9448c2ecf20Sopenharmony_ci * the interface state accordingly.
9458c2ecf20Sopenharmony_ci */
9468c2ecf20Sopenharmony_cistatic void xcan_update_error_state_after_rxtx(struct net_device *ndev)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
9498c2ecf20Sopenharmony_ci	enum can_state old_state = priv->can.state;
9508c2ecf20Sopenharmony_ci	enum can_state new_state;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/* changing error state due to successful frame RX/TX can only
9538c2ecf20Sopenharmony_ci	 * occur from these states
9548c2ecf20Sopenharmony_ci	 */
9558c2ecf20Sopenharmony_ci	if (old_state != CAN_STATE_ERROR_WARNING &&
9568c2ecf20Sopenharmony_ci	    old_state != CAN_STATE_ERROR_PASSIVE)
9578c2ecf20Sopenharmony_ci		return;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	new_state = xcan_current_error_state(ndev);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (new_state != old_state) {
9628c2ecf20Sopenharmony_ci		struct sk_buff *skb;
9638c2ecf20Sopenharmony_ci		struct can_frame *cf;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		skb = alloc_can_err_skb(ndev, &cf);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		if (skb) {
9708c2ecf20Sopenharmony_ci			struct net_device_stats *stats = &ndev->stats;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci			stats->rx_packets++;
9738c2ecf20Sopenharmony_ci			stats->rx_bytes += cf->can_dlc;
9748c2ecf20Sopenharmony_ci			netif_rx(skb);
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci/**
9808c2ecf20Sopenharmony_ci * xcan_err_interrupt - error frame Isr
9818c2ecf20Sopenharmony_ci * @ndev:	net_device pointer
9828c2ecf20Sopenharmony_ci * @isr:	interrupt status register value
9838c2ecf20Sopenharmony_ci *
9848c2ecf20Sopenharmony_ci * This is the CAN error interrupt and it will
9858c2ecf20Sopenharmony_ci * check the the type of error and forward the error
9868c2ecf20Sopenharmony_ci * frame to upper layers.
9878c2ecf20Sopenharmony_ci */
9888c2ecf20Sopenharmony_cistatic void xcan_err_interrupt(struct net_device *ndev, u32 isr)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
9918c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
9928c2ecf20Sopenharmony_ci	struct can_frame cf = { };
9938c2ecf20Sopenharmony_ci	u32 err_status;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
9968c2ecf20Sopenharmony_ci	priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_BSOFF_MASK) {
9998c2ecf20Sopenharmony_ci		priv->can.state = CAN_STATE_BUS_OFF;
10008c2ecf20Sopenharmony_ci		priv->can.can_stats.bus_off++;
10018c2ecf20Sopenharmony_ci		/* Leave device in Config Mode in bus-off state */
10028c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
10038c2ecf20Sopenharmony_ci		can_bus_off(ndev);
10048c2ecf20Sopenharmony_ci		cf.can_id |= CAN_ERR_BUSOFF;
10058c2ecf20Sopenharmony_ci	} else {
10068c2ecf20Sopenharmony_ci		enum can_state new_state = xcan_current_error_state(ndev);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		if (new_state != priv->can.state)
10098c2ecf20Sopenharmony_ci			xcan_set_error_state(ndev, new_state, &cf);
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* Check for Arbitration lost interrupt */
10138c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_ARBLST_MASK) {
10148c2ecf20Sopenharmony_ci		priv->can.can_stats.arbitration_lost++;
10158c2ecf20Sopenharmony_ci		cf.can_id |= CAN_ERR_LOSTARB;
10168c2ecf20Sopenharmony_ci		cf.data[0] = CAN_ERR_LOSTARB_UNSPEC;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	/* Check for RX FIFO Overflow interrupt */
10208c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_RXOFLW_MASK) {
10218c2ecf20Sopenharmony_ci		stats->rx_over_errors++;
10228c2ecf20Sopenharmony_ci		stats->rx_errors++;
10238c2ecf20Sopenharmony_ci		cf.can_id |= CAN_ERR_CRTL;
10248c2ecf20Sopenharmony_ci		cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	/* Check for RX Match Not Finished interrupt */
10288c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_RXMNF_MASK) {
10298c2ecf20Sopenharmony_ci		stats->rx_dropped++;
10308c2ecf20Sopenharmony_ci		stats->rx_errors++;
10318c2ecf20Sopenharmony_ci		netdev_err(ndev, "RX match not finished, frame discarded\n");
10328c2ecf20Sopenharmony_ci		cf.can_id |= CAN_ERR_CRTL;
10338c2ecf20Sopenharmony_ci		cf.data[1] |= CAN_ERR_CRTL_UNSPEC;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	/* Check for error interrupt */
10378c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_ERROR_MASK) {
10388c2ecf20Sopenharmony_ci		bool berr_reporting = false;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
10418c2ecf20Sopenharmony_ci			berr_reporting = true;
10428c2ecf20Sopenharmony_ci			cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
10438c2ecf20Sopenharmony_ci		}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		/* Check for Ack error interrupt */
10468c2ecf20Sopenharmony_ci		if (err_status & XCAN_ESR_ACKER_MASK) {
10478c2ecf20Sopenharmony_ci			stats->tx_errors++;
10488c2ecf20Sopenharmony_ci			if (berr_reporting) {
10498c2ecf20Sopenharmony_ci				cf.can_id |= CAN_ERR_ACK;
10508c2ecf20Sopenharmony_ci				cf.data[3] = CAN_ERR_PROT_LOC_ACK;
10518c2ecf20Sopenharmony_ci			}
10528c2ecf20Sopenharmony_ci		}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci		/* Check for Bit error interrupt */
10558c2ecf20Sopenharmony_ci		if (err_status & XCAN_ESR_BERR_MASK) {
10568c2ecf20Sopenharmony_ci			stats->tx_errors++;
10578c2ecf20Sopenharmony_ci			if (berr_reporting) {
10588c2ecf20Sopenharmony_ci				cf.can_id |= CAN_ERR_PROT;
10598c2ecf20Sopenharmony_ci				cf.data[2] = CAN_ERR_PROT_BIT;
10608c2ecf20Sopenharmony_ci			}
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		/* Check for Stuff error interrupt */
10648c2ecf20Sopenharmony_ci		if (err_status & XCAN_ESR_STER_MASK) {
10658c2ecf20Sopenharmony_ci			stats->rx_errors++;
10668c2ecf20Sopenharmony_ci			if (berr_reporting) {
10678c2ecf20Sopenharmony_ci				cf.can_id |= CAN_ERR_PROT;
10688c2ecf20Sopenharmony_ci				cf.data[2] = CAN_ERR_PROT_STUFF;
10698c2ecf20Sopenharmony_ci			}
10708c2ecf20Sopenharmony_ci		}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci		/* Check for Form error interrupt */
10738c2ecf20Sopenharmony_ci		if (err_status & XCAN_ESR_FMER_MASK) {
10748c2ecf20Sopenharmony_ci			stats->rx_errors++;
10758c2ecf20Sopenharmony_ci			if (berr_reporting) {
10768c2ecf20Sopenharmony_ci				cf.can_id |= CAN_ERR_PROT;
10778c2ecf20Sopenharmony_ci				cf.data[2] = CAN_ERR_PROT_FORM;
10788c2ecf20Sopenharmony_ci			}
10798c2ecf20Sopenharmony_ci		}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci		/* Check for CRC error interrupt */
10828c2ecf20Sopenharmony_ci		if (err_status & XCAN_ESR_CRCER_MASK) {
10838c2ecf20Sopenharmony_ci			stats->rx_errors++;
10848c2ecf20Sopenharmony_ci			if (berr_reporting) {
10858c2ecf20Sopenharmony_ci				cf.can_id |= CAN_ERR_PROT;
10868c2ecf20Sopenharmony_ci				cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
10878c2ecf20Sopenharmony_ci			}
10888c2ecf20Sopenharmony_ci		}
10898c2ecf20Sopenharmony_ci		priv->can.can_stats.bus_error++;
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	if (cf.can_id) {
10938c2ecf20Sopenharmony_ci		struct can_frame *skb_cf;
10948c2ecf20Sopenharmony_ci		struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		if (skb) {
10978c2ecf20Sopenharmony_ci			skb_cf->can_id |= cf.can_id;
10988c2ecf20Sopenharmony_ci			memcpy(skb_cf->data, cf.data, CAN_ERR_DLC);
10998c2ecf20Sopenharmony_ci			stats->rx_packets++;
11008c2ecf20Sopenharmony_ci			stats->rx_bytes += CAN_ERR_DLC;
11018c2ecf20Sopenharmony_ci			netif_rx(skb);
11028c2ecf20Sopenharmony_ci		}
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	netdev_dbg(ndev, "%s: error status register:0x%x\n",
11068c2ecf20Sopenharmony_ci		   __func__, priv->read_reg(priv, XCAN_ESR_OFFSET));
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci/**
11108c2ecf20Sopenharmony_ci * xcan_state_interrupt - It will check the state of the CAN device
11118c2ecf20Sopenharmony_ci * @ndev:	net_device pointer
11128c2ecf20Sopenharmony_ci * @isr:	interrupt status register value
11138c2ecf20Sopenharmony_ci *
11148c2ecf20Sopenharmony_ci * This will checks the state of the CAN device
11158c2ecf20Sopenharmony_ci * and puts the device into appropriate state.
11168c2ecf20Sopenharmony_ci */
11178c2ecf20Sopenharmony_cistatic void xcan_state_interrupt(struct net_device *ndev, u32 isr)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* Check for Sleep interrupt if set put CAN device in sleep state */
11228c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_SLP_MASK)
11238c2ecf20Sopenharmony_ci		priv->can.state = CAN_STATE_SLEEPING;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	/* Check for Wake up interrupt if set put CAN device in Active state */
11268c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_WKUP_MASK)
11278c2ecf20Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_ACTIVE;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci/**
11318c2ecf20Sopenharmony_ci * xcan_rx_fifo_get_next_frame - Get register offset of next RX frame
11328c2ecf20Sopenharmony_ci * @priv:	Driver private data structure
11338c2ecf20Sopenharmony_ci *
11348c2ecf20Sopenharmony_ci * Return: Register offset of the next frame in RX FIFO.
11358c2ecf20Sopenharmony_ci */
11368c2ecf20Sopenharmony_cistatic int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	int offset;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) {
11418c2ecf20Sopenharmony_ci		u32 fsr, mask;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci		/* clear RXOK before the is-empty check so that any newly
11448c2ecf20Sopenharmony_ci		 * received frame will reassert it without a race
11458c2ecf20Sopenharmony_ci		 */
11468c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXOK_MASK);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci		fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci		/* check if RX FIFO is empty */
11518c2ecf20Sopenharmony_ci		if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
11528c2ecf20Sopenharmony_ci			mask = XCAN_2_FSR_FL_MASK;
11538c2ecf20Sopenharmony_ci		else
11548c2ecf20Sopenharmony_ci			mask = XCAN_FSR_FL_MASK;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		if (!(fsr & mask))
11578c2ecf20Sopenharmony_ci			return -ENOENT;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci		if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
11608c2ecf20Sopenharmony_ci			offset =
11618c2ecf20Sopenharmony_ci			  XCAN_RXMSG_2_FRAME_OFFSET(fsr & XCAN_2_FSR_RI_MASK);
11628c2ecf20Sopenharmony_ci		else
11638c2ecf20Sopenharmony_ci			offset =
11648c2ecf20Sopenharmony_ci			  XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	} else {
11678c2ecf20Sopenharmony_ci		/* check if RX FIFO is empty */
11688c2ecf20Sopenharmony_ci		if (!(priv->read_reg(priv, XCAN_ISR_OFFSET) &
11698c2ecf20Sopenharmony_ci		      XCAN_IXR_RXNEMP_MASK))
11708c2ecf20Sopenharmony_ci			return -ENOENT;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci		/* frames are read from a static offset */
11738c2ecf20Sopenharmony_ci		offset = XCAN_RXFIFO_OFFSET;
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	return offset;
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci/**
11808c2ecf20Sopenharmony_ci * xcan_rx_poll - Poll routine for rx packets (NAPI)
11818c2ecf20Sopenharmony_ci * @napi:	napi structure pointer
11828c2ecf20Sopenharmony_ci * @quota:	Max number of rx packets to be processed.
11838c2ecf20Sopenharmony_ci *
11848c2ecf20Sopenharmony_ci * This is the poll routine for rx part.
11858c2ecf20Sopenharmony_ci * It will process the packets maximux quota value.
11868c2ecf20Sopenharmony_ci *
11878c2ecf20Sopenharmony_ci * Return: number of packets received
11888c2ecf20Sopenharmony_ci */
11898c2ecf20Sopenharmony_cistatic int xcan_rx_poll(struct napi_struct *napi, int quota)
11908c2ecf20Sopenharmony_ci{
11918c2ecf20Sopenharmony_ci	struct net_device *ndev = napi->dev;
11928c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
11938c2ecf20Sopenharmony_ci	u32 ier;
11948c2ecf20Sopenharmony_ci	int work_done = 0;
11958c2ecf20Sopenharmony_ci	int frame_offset;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	while ((frame_offset = xcan_rx_fifo_get_next_frame(priv)) >= 0 &&
11988c2ecf20Sopenharmony_ci	       (work_done < quota)) {
11998c2ecf20Sopenharmony_ci		if (xcan_rx_int_mask(priv) & XCAN_IXR_RXOK_MASK)
12008c2ecf20Sopenharmony_ci			work_done += xcanfd_rx(ndev, frame_offset);
12018c2ecf20Sopenharmony_ci		else
12028c2ecf20Sopenharmony_ci			work_done += xcan_rx(ndev, frame_offset);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI)
12058c2ecf20Sopenharmony_ci			/* increment read index */
12068c2ecf20Sopenharmony_ci			priv->write_reg(priv, XCAN_FSR_OFFSET,
12078c2ecf20Sopenharmony_ci					XCAN_FSR_IRI_MASK);
12088c2ecf20Sopenharmony_ci		else
12098c2ecf20Sopenharmony_ci			/* clear rx-not-empty (will actually clear only if
12108c2ecf20Sopenharmony_ci			 * empty)
12118c2ecf20Sopenharmony_ci			 */
12128c2ecf20Sopenharmony_ci			priv->write_reg(priv, XCAN_ICR_OFFSET,
12138c2ecf20Sopenharmony_ci					XCAN_IXR_RXNEMP_MASK);
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (work_done) {
12178c2ecf20Sopenharmony_ci		can_led_event(ndev, CAN_LED_EVENT_RX);
12188c2ecf20Sopenharmony_ci		xcan_update_error_state_after_rxtx(ndev);
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (work_done < quota) {
12228c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
12238c2ecf20Sopenharmony_ci		ier = priv->read_reg(priv, XCAN_IER_OFFSET);
12248c2ecf20Sopenharmony_ci		ier |= xcan_rx_int_mask(priv);
12258c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_IER_OFFSET, ier);
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci	return work_done;
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci/**
12318c2ecf20Sopenharmony_ci * xcan_tx_interrupt - Tx Done Isr
12328c2ecf20Sopenharmony_ci * @ndev:	net_device pointer
12338c2ecf20Sopenharmony_ci * @isr:	Interrupt status register value
12348c2ecf20Sopenharmony_ci */
12358c2ecf20Sopenharmony_cistatic void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
12368c2ecf20Sopenharmony_ci{
12378c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
12388c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
12398c2ecf20Sopenharmony_ci	unsigned int frames_in_fifo;
12408c2ecf20Sopenharmony_ci	int frames_sent = 1; /* TXOK => at least 1 frame was sent */
12418c2ecf20Sopenharmony_ci	unsigned long flags;
12428c2ecf20Sopenharmony_ci	int retries = 0;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	/* Synchronize with xmit as we need to know the exact number
12458c2ecf20Sopenharmony_ci	 * of frames in the FIFO to stay in sync due to the TXFEMP
12468c2ecf20Sopenharmony_ci	 * handling.
12478c2ecf20Sopenharmony_ci	 * This also prevents a race between netif_wake_queue() and
12488c2ecf20Sopenharmony_ci	 * netif_stop_queue().
12498c2ecf20Sopenharmony_ci	 */
12508c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->tx_lock, flags);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	frames_in_fifo = priv->tx_head - priv->tx_tail;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(frames_in_fifo == 0)) {
12558c2ecf20Sopenharmony_ci		/* clear TXOK anyway to avoid getting back here */
12568c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
12578c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->tx_lock, flags);
12588c2ecf20Sopenharmony_ci		return;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	/* Check if 2 frames were sent (TXOK only means that at least 1
12628c2ecf20Sopenharmony_ci	 * frame was sent).
12638c2ecf20Sopenharmony_ci	 */
12648c2ecf20Sopenharmony_ci	if (frames_in_fifo > 1) {
12658c2ecf20Sopenharmony_ci		WARN_ON(frames_in_fifo > priv->tx_max);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci		/* Synchronize TXOK and isr so that after the loop:
12688c2ecf20Sopenharmony_ci		 * (1) isr variable is up-to-date at least up to TXOK clear
12698c2ecf20Sopenharmony_ci		 *     time. This avoids us clearing a TXOK of a second frame
12708c2ecf20Sopenharmony_ci		 *     but not noticing that the FIFO is now empty and thus
12718c2ecf20Sopenharmony_ci		 *     marking only a single frame as sent.
12728c2ecf20Sopenharmony_ci		 * (2) No TXOK is left. Having one could mean leaving a
12738c2ecf20Sopenharmony_ci		 *     stray TXOK as we might process the associated frame
12748c2ecf20Sopenharmony_ci		 *     via TXFEMP handling as we read TXFEMP *after* TXOK
12758c2ecf20Sopenharmony_ci		 *     clear to satisfy (1).
12768c2ecf20Sopenharmony_ci		 */
12778c2ecf20Sopenharmony_ci		while ((isr & XCAN_IXR_TXOK_MASK) &&
12788c2ecf20Sopenharmony_ci		       !WARN_ON(++retries == 100)) {
12798c2ecf20Sopenharmony_ci			priv->write_reg(priv, XCAN_ICR_OFFSET,
12808c2ecf20Sopenharmony_ci					XCAN_IXR_TXOK_MASK);
12818c2ecf20Sopenharmony_ci			isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
12828c2ecf20Sopenharmony_ci		}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci		if (isr & XCAN_IXR_TXFEMP_MASK) {
12858c2ecf20Sopenharmony_ci			/* nothing in FIFO anymore */
12868c2ecf20Sopenharmony_ci			frames_sent = frames_in_fifo;
12878c2ecf20Sopenharmony_ci		}
12888c2ecf20Sopenharmony_ci	} else {
12898c2ecf20Sopenharmony_ci		/* single frame in fifo, just clear TXOK */
12908c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	while (frames_sent--) {
12948c2ecf20Sopenharmony_ci		stats->tx_bytes += can_get_echo_skb(ndev, priv->tx_tail %
12958c2ecf20Sopenharmony_ci						    priv->tx_max);
12968c2ecf20Sopenharmony_ci		priv->tx_tail++;
12978c2ecf20Sopenharmony_ci		stats->tx_packets++;
12988c2ecf20Sopenharmony_ci	}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	netif_wake_queue(ndev);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->tx_lock, flags);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	can_led_event(ndev, CAN_LED_EVENT_TX);
13058c2ecf20Sopenharmony_ci	xcan_update_error_state_after_rxtx(ndev);
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci/**
13098c2ecf20Sopenharmony_ci * xcan_interrupt - CAN Isr
13108c2ecf20Sopenharmony_ci * @irq:	irq number
13118c2ecf20Sopenharmony_ci * @dev_id:	device id pointer
13128c2ecf20Sopenharmony_ci *
13138c2ecf20Sopenharmony_ci * This is the xilinx CAN Isr. It checks for the type of interrupt
13148c2ecf20Sopenharmony_ci * and invokes the corresponding ISR.
13158c2ecf20Sopenharmony_ci *
13168c2ecf20Sopenharmony_ci * Return:
13178c2ecf20Sopenharmony_ci * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
13188c2ecf20Sopenharmony_ci */
13198c2ecf20Sopenharmony_cistatic irqreturn_t xcan_interrupt(int irq, void *dev_id)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	struct net_device *ndev = (struct net_device *)dev_id;
13228c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
13238c2ecf20Sopenharmony_ci	u32 isr, ier;
13248c2ecf20Sopenharmony_ci	u32 isr_errors;
13258c2ecf20Sopenharmony_ci	u32 rx_int_mask = xcan_rx_int_mask(priv);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* Get the interrupt status from Xilinx CAN */
13288c2ecf20Sopenharmony_ci	isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
13298c2ecf20Sopenharmony_ci	if (!isr)
13308c2ecf20Sopenharmony_ci		return IRQ_NONE;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	/* Check for the type of interrupt and Processing it */
13338c2ecf20Sopenharmony_ci	if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) {
13348c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK |
13358c2ecf20Sopenharmony_ci				XCAN_IXR_WKUP_MASK));
13368c2ecf20Sopenharmony_ci		xcan_state_interrupt(ndev, isr);
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	/* Check for Tx interrupt and Processing it */
13408c2ecf20Sopenharmony_ci	if (isr & XCAN_IXR_TXOK_MASK)
13418c2ecf20Sopenharmony_ci		xcan_tx_interrupt(ndev, isr);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* Check for the type of error interrupt and Processing it */
13448c2ecf20Sopenharmony_ci	isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
13458c2ecf20Sopenharmony_ci			    XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK |
13468c2ecf20Sopenharmony_ci			    XCAN_IXR_RXMNF_MASK);
13478c2ecf20Sopenharmony_ci	if (isr_errors) {
13488c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors);
13498c2ecf20Sopenharmony_ci		xcan_err_interrupt(ndev, isr);
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	/* Check for the type of receive interrupt and Processing it */
13538c2ecf20Sopenharmony_ci	if (isr & rx_int_mask) {
13548c2ecf20Sopenharmony_ci		ier = priv->read_reg(priv, XCAN_IER_OFFSET);
13558c2ecf20Sopenharmony_ci		ier &= ~rx_int_mask;
13568c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_IER_OFFSET, ier);
13578c2ecf20Sopenharmony_ci		napi_schedule(&priv->napi);
13588c2ecf20Sopenharmony_ci	}
13598c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci/**
13638c2ecf20Sopenharmony_ci * xcan_chip_stop - Driver stop routine
13648c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
13658c2ecf20Sopenharmony_ci *
13668c2ecf20Sopenharmony_ci * This is the drivers stop routine. It will disable the
13678c2ecf20Sopenharmony_ci * interrupts and put the device into configuration mode.
13688c2ecf20Sopenharmony_ci */
13698c2ecf20Sopenharmony_cistatic void xcan_chip_stop(struct net_device *ndev)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
13728c2ecf20Sopenharmony_ci	int ret;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/* Disable interrupts and leave the can in configuration mode */
13758c2ecf20Sopenharmony_ci	ret = set_reset_mode(ndev);
13768c2ecf20Sopenharmony_ci	if (ret < 0)
13778c2ecf20Sopenharmony_ci		netdev_dbg(ndev, "set_reset_mode() Failed\n");
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	priv->can.state = CAN_STATE_STOPPED;
13808c2ecf20Sopenharmony_ci}
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci/**
13838c2ecf20Sopenharmony_ci * xcan_open - Driver open routine
13848c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
13858c2ecf20Sopenharmony_ci *
13868c2ecf20Sopenharmony_ci * This is the driver open routine.
13878c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
13888c2ecf20Sopenharmony_ci */
13898c2ecf20Sopenharmony_cistatic int xcan_open(struct net_device *ndev)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
13928c2ecf20Sopenharmony_ci	int ret;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(priv->dev);
13958c2ecf20Sopenharmony_ci	if (ret < 0) {
13968c2ecf20Sopenharmony_ci		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
13978c2ecf20Sopenharmony_ci			   __func__, ret);
13988c2ecf20Sopenharmony_ci		goto err;
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags,
14028c2ecf20Sopenharmony_ci			  ndev->name, ndev);
14038c2ecf20Sopenharmony_ci	if (ret < 0) {
14048c2ecf20Sopenharmony_ci		netdev_err(ndev, "irq allocation for CAN failed\n");
14058c2ecf20Sopenharmony_ci		goto err;
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/* Set chip into reset mode */
14098c2ecf20Sopenharmony_ci	ret = set_reset_mode(ndev);
14108c2ecf20Sopenharmony_ci	if (ret < 0) {
14118c2ecf20Sopenharmony_ci		netdev_err(ndev, "mode resetting failed!\n");
14128c2ecf20Sopenharmony_ci		goto err_irq;
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* Common open */
14168c2ecf20Sopenharmony_ci	ret = open_candev(ndev);
14178c2ecf20Sopenharmony_ci	if (ret)
14188c2ecf20Sopenharmony_ci		goto err_irq;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	ret = xcan_chip_start(ndev);
14218c2ecf20Sopenharmony_ci	if (ret < 0) {
14228c2ecf20Sopenharmony_ci		netdev_err(ndev, "xcan_chip_start failed!\n");
14238c2ecf20Sopenharmony_ci		goto err_candev;
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	can_led_event(ndev, CAN_LED_EVENT_OPEN);
14278c2ecf20Sopenharmony_ci	napi_enable(&priv->napi);
14288c2ecf20Sopenharmony_ci	netif_start_queue(ndev);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	return 0;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cierr_candev:
14338c2ecf20Sopenharmony_ci	close_candev(ndev);
14348c2ecf20Sopenharmony_cierr_irq:
14358c2ecf20Sopenharmony_ci	free_irq(ndev->irq, ndev);
14368c2ecf20Sopenharmony_cierr:
14378c2ecf20Sopenharmony_ci	pm_runtime_put(priv->dev);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	return ret;
14408c2ecf20Sopenharmony_ci}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci/**
14438c2ecf20Sopenharmony_ci * xcan_close - Driver close routine
14448c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
14458c2ecf20Sopenharmony_ci *
14468c2ecf20Sopenharmony_ci * Return: 0 always
14478c2ecf20Sopenharmony_ci */
14488c2ecf20Sopenharmony_cistatic int xcan_close(struct net_device *ndev)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	netif_stop_queue(ndev);
14538c2ecf20Sopenharmony_ci	napi_disable(&priv->napi);
14548c2ecf20Sopenharmony_ci	xcan_chip_stop(ndev);
14558c2ecf20Sopenharmony_ci	free_irq(ndev->irq, ndev);
14568c2ecf20Sopenharmony_ci	close_candev(ndev);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	can_led_event(ndev, CAN_LED_EVENT_STOP);
14598c2ecf20Sopenharmony_ci	pm_runtime_put(priv->dev);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	return 0;
14628c2ecf20Sopenharmony_ci}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci/**
14658c2ecf20Sopenharmony_ci * xcan_get_berr_counter - error counter routine
14668c2ecf20Sopenharmony_ci * @ndev:	Pointer to net_device structure
14678c2ecf20Sopenharmony_ci * @bec:	Pointer to can_berr_counter structure
14688c2ecf20Sopenharmony_ci *
14698c2ecf20Sopenharmony_ci * This is the driver error counter routine.
14708c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
14718c2ecf20Sopenharmony_ci */
14728c2ecf20Sopenharmony_cistatic int xcan_get_berr_counter(const struct net_device *ndev,
14738c2ecf20Sopenharmony_ci				 struct can_berr_counter *bec)
14748c2ecf20Sopenharmony_ci{
14758c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
14768c2ecf20Sopenharmony_ci	int ret;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(priv->dev);
14798c2ecf20Sopenharmony_ci	if (ret < 0) {
14808c2ecf20Sopenharmony_ci		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
14818c2ecf20Sopenharmony_ci			   __func__, ret);
14828c2ecf20Sopenharmony_ci		pm_runtime_put(priv->dev);
14838c2ecf20Sopenharmony_ci		return ret;
14848c2ecf20Sopenharmony_ci	}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK;
14878c2ecf20Sopenharmony_ci	bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) &
14888c2ecf20Sopenharmony_ci			XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	pm_runtime_put(priv->dev);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	return 0;
14938c2ecf20Sopenharmony_ci}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_cistatic const struct net_device_ops xcan_netdev_ops = {
14968c2ecf20Sopenharmony_ci	.ndo_open	= xcan_open,
14978c2ecf20Sopenharmony_ci	.ndo_stop	= xcan_close,
14988c2ecf20Sopenharmony_ci	.ndo_start_xmit	= xcan_start_xmit,
14998c2ecf20Sopenharmony_ci	.ndo_change_mtu	= can_change_mtu,
15008c2ecf20Sopenharmony_ci};
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci/**
15038c2ecf20Sopenharmony_ci * xcan_suspend - Suspend method for the driver
15048c2ecf20Sopenharmony_ci * @dev:	Address of the device structure
15058c2ecf20Sopenharmony_ci *
15068c2ecf20Sopenharmony_ci * Put the driver into low power mode.
15078c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
15088c2ecf20Sopenharmony_ci */
15098c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_suspend(struct device *dev)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	if (netif_running(ndev)) {
15148c2ecf20Sopenharmony_ci		netif_stop_queue(ndev);
15158c2ecf20Sopenharmony_ci		netif_device_detach(ndev);
15168c2ecf20Sopenharmony_ci		xcan_chip_stop(ndev);
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	return pm_runtime_force_suspend(dev);
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci/**
15238c2ecf20Sopenharmony_ci * xcan_resume - Resume from suspend
15248c2ecf20Sopenharmony_ci * @dev:	Address of the device structure
15258c2ecf20Sopenharmony_ci *
15268c2ecf20Sopenharmony_ci * Resume operation after suspend.
15278c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
15288c2ecf20Sopenharmony_ci */
15298c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_resume(struct device *dev)
15308c2ecf20Sopenharmony_ci{
15318c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
15328c2ecf20Sopenharmony_ci	int ret;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	ret = pm_runtime_force_resume(dev);
15358c2ecf20Sopenharmony_ci	if (ret) {
15368c2ecf20Sopenharmony_ci		dev_err(dev, "pm_runtime_force_resume failed on resume\n");
15378c2ecf20Sopenharmony_ci		return ret;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if (netif_running(ndev)) {
15418c2ecf20Sopenharmony_ci		ret = xcan_chip_start(ndev);
15428c2ecf20Sopenharmony_ci		if (ret) {
15438c2ecf20Sopenharmony_ci			dev_err(dev, "xcan_chip_start failed on resume\n");
15448c2ecf20Sopenharmony_ci			return ret;
15458c2ecf20Sopenharmony_ci		}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci		netif_device_attach(ndev);
15488c2ecf20Sopenharmony_ci		netif_start_queue(ndev);
15498c2ecf20Sopenharmony_ci	}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	return 0;
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci/**
15558c2ecf20Sopenharmony_ci * xcan_runtime_suspend - Runtime suspend method for the driver
15568c2ecf20Sopenharmony_ci * @dev:	Address of the device structure
15578c2ecf20Sopenharmony_ci *
15588c2ecf20Sopenharmony_ci * Put the driver into low power mode.
15598c2ecf20Sopenharmony_ci * Return: 0 always
15608c2ecf20Sopenharmony_ci */
15618c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_runtime_suspend(struct device *dev)
15628c2ecf20Sopenharmony_ci{
15638c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
15648c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->bus_clk);
15678c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->can_clk);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	return 0;
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci/**
15738c2ecf20Sopenharmony_ci * xcan_runtime_resume - Runtime resume from suspend
15748c2ecf20Sopenharmony_ci * @dev:	Address of the device structure
15758c2ecf20Sopenharmony_ci *
15768c2ecf20Sopenharmony_ci * Resume operation after suspend.
15778c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
15788c2ecf20Sopenharmony_ci */
15798c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_runtime_resume(struct device *dev)
15808c2ecf20Sopenharmony_ci{
15818c2ecf20Sopenharmony_ci	struct net_device *ndev = dev_get_drvdata(dev);
15828c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
15838c2ecf20Sopenharmony_ci	int ret;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->bus_clk);
15868c2ecf20Sopenharmony_ci	if (ret) {
15878c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot enable clock.\n");
15888c2ecf20Sopenharmony_ci		return ret;
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->can_clk);
15918c2ecf20Sopenharmony_ci	if (ret) {
15928c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot enable clock.\n");
15938c2ecf20Sopenharmony_ci		clk_disable_unprepare(priv->bus_clk);
15948c2ecf20Sopenharmony_ci		return ret;
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	return 0;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic const struct dev_pm_ops xcan_dev_pm_ops = {
16018c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(xcan_suspend, xcan_resume)
16028c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL)
16038c2ecf20Sopenharmony_ci};
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_zynq_data = {
16068c2ecf20Sopenharmony_ci	.cantype = XZYNQ_CANPS,
16078c2ecf20Sopenharmony_ci	.flags = XCAN_FLAG_TXFEMP,
16088c2ecf20Sopenharmony_ci	.bittiming_const = &xcan_bittiming_const,
16098c2ecf20Sopenharmony_ci	.btr_ts2_shift = XCAN_BTR_TS2_SHIFT,
16108c2ecf20Sopenharmony_ci	.btr_sjw_shift = XCAN_BTR_SJW_SHIFT,
16118c2ecf20Sopenharmony_ci	.bus_clk_name = "pclk",
16128c2ecf20Sopenharmony_ci};
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_axi_data = {
16158c2ecf20Sopenharmony_ci	.cantype = XAXI_CAN,
16168c2ecf20Sopenharmony_ci	.bittiming_const = &xcan_bittiming_const,
16178c2ecf20Sopenharmony_ci	.btr_ts2_shift = XCAN_BTR_TS2_SHIFT,
16188c2ecf20Sopenharmony_ci	.btr_sjw_shift = XCAN_BTR_SJW_SHIFT,
16198c2ecf20Sopenharmony_ci	.bus_clk_name = "s_axi_aclk",
16208c2ecf20Sopenharmony_ci};
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_canfd_data = {
16238c2ecf20Sopenharmony_ci	.cantype = XAXI_CANFD,
16248c2ecf20Sopenharmony_ci	.flags = XCAN_FLAG_EXT_FILTERS |
16258c2ecf20Sopenharmony_ci		 XCAN_FLAG_RXMNF |
16268c2ecf20Sopenharmony_ci		 XCAN_FLAG_TX_MAILBOXES |
16278c2ecf20Sopenharmony_ci		 XCAN_FLAG_RX_FIFO_MULTI,
16288c2ecf20Sopenharmony_ci	.bittiming_const = &xcan_bittiming_const_canfd,
16298c2ecf20Sopenharmony_ci	.btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD,
16308c2ecf20Sopenharmony_ci	.btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD,
16318c2ecf20Sopenharmony_ci	.bus_clk_name = "s_axi_aclk",
16328c2ecf20Sopenharmony_ci};
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_canfd2_data = {
16358c2ecf20Sopenharmony_ci	.cantype = XAXI_CANFD_2_0,
16368c2ecf20Sopenharmony_ci	.flags = XCAN_FLAG_EXT_FILTERS |
16378c2ecf20Sopenharmony_ci		 XCAN_FLAG_RXMNF |
16388c2ecf20Sopenharmony_ci		 XCAN_FLAG_TX_MAILBOXES |
16398c2ecf20Sopenharmony_ci		 XCAN_FLAG_CANFD_2 |
16408c2ecf20Sopenharmony_ci		 XCAN_FLAG_RX_FIFO_MULTI,
16418c2ecf20Sopenharmony_ci	.bittiming_const = &xcan_bittiming_const_canfd2,
16428c2ecf20Sopenharmony_ci	.btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD,
16438c2ecf20Sopenharmony_ci	.btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD,
16448c2ecf20Sopenharmony_ci	.bus_clk_name = "s_axi_aclk",
16458c2ecf20Sopenharmony_ci};
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci/* Match table for OF platform binding */
16488c2ecf20Sopenharmony_cistatic const struct of_device_id xcan_of_match[] = {
16498c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data },
16508c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data },
16518c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,canfd-1.0", .data = &xcan_canfd_data },
16528c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,canfd-2.0", .data = &xcan_canfd2_data },
16538c2ecf20Sopenharmony_ci	{ /* end of list */ },
16548c2ecf20Sopenharmony_ci};
16558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xcan_of_match);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci/**
16588c2ecf20Sopenharmony_ci * xcan_probe - Platform registration call
16598c2ecf20Sopenharmony_ci * @pdev:	Handle to the platform device structure
16608c2ecf20Sopenharmony_ci *
16618c2ecf20Sopenharmony_ci * This function does all the memory allocation and registration for the CAN
16628c2ecf20Sopenharmony_ci * device.
16638c2ecf20Sopenharmony_ci *
16648c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error
16658c2ecf20Sopenharmony_ci */
16668c2ecf20Sopenharmony_cistatic int xcan_probe(struct platform_device *pdev)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	struct net_device *ndev;
16698c2ecf20Sopenharmony_ci	struct xcan_priv *priv;
16708c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
16718c2ecf20Sopenharmony_ci	const struct xcan_devtype_data *devtype = &xcan_axi_data;
16728c2ecf20Sopenharmony_ci	void __iomem *addr;
16738c2ecf20Sopenharmony_ci	int ret;
16748c2ecf20Sopenharmony_ci	int rx_max, tx_max;
16758c2ecf20Sopenharmony_ci	u32 hw_tx_max = 0, hw_rx_max = 0;
16768c2ecf20Sopenharmony_ci	const char *hw_tx_max_property;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	/* Get the virtual base address for the device */
16798c2ecf20Sopenharmony_ci	addr = devm_platform_ioremap_resource(pdev, 0);
16808c2ecf20Sopenharmony_ci	if (IS_ERR(addr)) {
16818c2ecf20Sopenharmony_ci		ret = PTR_ERR(addr);
16828c2ecf20Sopenharmony_ci		goto err;
16838c2ecf20Sopenharmony_ci	}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	of_id = of_match_device(xcan_of_match, &pdev->dev);
16868c2ecf20Sopenharmony_ci	if (of_id && of_id->data)
16878c2ecf20Sopenharmony_ci		devtype = of_id->data;
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	hw_tx_max_property = devtype->flags & XCAN_FLAG_TX_MAILBOXES ?
16908c2ecf20Sopenharmony_ci			     "tx-mailbox-count" : "tx-fifo-depth";
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	ret = of_property_read_u32(pdev->dev.of_node, hw_tx_max_property,
16938c2ecf20Sopenharmony_ci				   &hw_tx_max);
16948c2ecf20Sopenharmony_ci	if (ret < 0) {
16958c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing %s property\n",
16968c2ecf20Sopenharmony_ci			hw_tx_max_property);
16978c2ecf20Sopenharmony_ci		goto err;
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
17018c2ecf20Sopenharmony_ci				   &hw_rx_max);
17028c2ecf20Sopenharmony_ci	if (ret < 0) {
17038c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
17048c2ecf20Sopenharmony_ci			"missing rx-fifo-depth property (mailbox mode is not supported)\n");
17058c2ecf20Sopenharmony_ci		goto err;
17068c2ecf20Sopenharmony_ci	}
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/* With TX FIFO:
17098c2ecf20Sopenharmony_ci	 *
17108c2ecf20Sopenharmony_ci	 * There is no way to directly figure out how many frames have been
17118c2ecf20Sopenharmony_ci	 * sent when the TXOK interrupt is processed. If TXFEMP
17128c2ecf20Sopenharmony_ci	 * is supported, we can have 2 frames in the FIFO and use TXFEMP
17138c2ecf20Sopenharmony_ci	 * to determine if 1 or 2 frames have been sent.
17148c2ecf20Sopenharmony_ci	 * Theoretically we should be able to use TXFWMEMP to determine up
17158c2ecf20Sopenharmony_ci	 * to 3 frames, but it seems that after putting a second frame in the
17168c2ecf20Sopenharmony_ci	 * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less
17178c2ecf20Sopenharmony_ci	 * than 2 frames in FIFO) is set anyway with no TXOK (a frame was
17188c2ecf20Sopenharmony_ci	 * sent), which is not a sensible state - possibly TXFWMEMP is not
17198c2ecf20Sopenharmony_ci	 * completely synchronized with the rest of the bits?
17208c2ecf20Sopenharmony_ci	 *
17218c2ecf20Sopenharmony_ci	 * With TX mailboxes:
17228c2ecf20Sopenharmony_ci	 *
17238c2ecf20Sopenharmony_ci	 * HW sends frames in CAN ID priority order. To preserve FIFO ordering
17248c2ecf20Sopenharmony_ci	 * we submit frames one at a time.
17258c2ecf20Sopenharmony_ci	 */
17268c2ecf20Sopenharmony_ci	if (!(devtype->flags & XCAN_FLAG_TX_MAILBOXES) &&
17278c2ecf20Sopenharmony_ci	    (devtype->flags & XCAN_FLAG_TXFEMP))
17288c2ecf20Sopenharmony_ci		tx_max = min(hw_tx_max, 2U);
17298c2ecf20Sopenharmony_ci	else
17308c2ecf20Sopenharmony_ci		tx_max = 1;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	rx_max = hw_rx_max;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	/* Create a CAN device instance */
17358c2ecf20Sopenharmony_ci	ndev = alloc_candev(sizeof(struct xcan_priv), tx_max);
17368c2ecf20Sopenharmony_ci	if (!ndev)
17378c2ecf20Sopenharmony_ci		return -ENOMEM;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	priv = netdev_priv(ndev);
17408c2ecf20Sopenharmony_ci	priv->dev = &pdev->dev;
17418c2ecf20Sopenharmony_ci	priv->can.bittiming_const = devtype->bittiming_const;
17428c2ecf20Sopenharmony_ci	priv->can.do_set_mode = xcan_do_set_mode;
17438c2ecf20Sopenharmony_ci	priv->can.do_get_berr_counter = xcan_get_berr_counter;
17448c2ecf20Sopenharmony_ci	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
17458c2ecf20Sopenharmony_ci					CAN_CTRLMODE_BERR_REPORTING;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	if (devtype->cantype == XAXI_CANFD)
17488c2ecf20Sopenharmony_ci		priv->can.data_bittiming_const =
17498c2ecf20Sopenharmony_ci			&xcan_data_bittiming_const_canfd;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (devtype->cantype == XAXI_CANFD_2_0)
17528c2ecf20Sopenharmony_ci		priv->can.data_bittiming_const =
17538c2ecf20Sopenharmony_ci			&xcan_data_bittiming_const_canfd2;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	if (devtype->cantype == XAXI_CANFD ||
17568c2ecf20Sopenharmony_ci	    devtype->cantype == XAXI_CANFD_2_0)
17578c2ecf20Sopenharmony_ci		priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	priv->reg_base = addr;
17608c2ecf20Sopenharmony_ci	priv->tx_max = tx_max;
17618c2ecf20Sopenharmony_ci	priv->devtype = *devtype;
17628c2ecf20Sopenharmony_ci	spin_lock_init(&priv->tx_lock);
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	/* Get IRQ for the device */
17658c2ecf20Sopenharmony_ci	ret = platform_get_irq(pdev, 0);
17668c2ecf20Sopenharmony_ci	if (ret < 0)
17678c2ecf20Sopenharmony_ci		goto err_free;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	ndev->irq = ret;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	ndev->flags |= IFF_ECHO;	/* We support local echo */
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
17748c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(ndev, &pdev->dev);
17758c2ecf20Sopenharmony_ci	ndev->netdev_ops = &xcan_netdev_ops;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	/* Getting the CAN can_clk info */
17788c2ecf20Sopenharmony_ci	priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
17798c2ecf20Sopenharmony_ci	if (IS_ERR(priv->can_clk)) {
17808c2ecf20Sopenharmony_ci		if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER)
17818c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "Device clock not found.\n");
17828c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->can_clk);
17838c2ecf20Sopenharmony_ci		goto err_free;
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
17878c2ecf20Sopenharmony_ci	if (IS_ERR(priv->bus_clk)) {
17888c2ecf20Sopenharmony_ci		if (PTR_ERR(priv->bus_clk) != -EPROBE_DEFER)
17898c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "bus clock not found\n");
17908c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->bus_clk);
17918c2ecf20Sopenharmony_ci		goto err_free;
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	priv->write_reg = xcan_write_reg_le;
17958c2ecf20Sopenharmony_ci	priv->read_reg = xcan_read_reg_le;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
17988c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(&pdev->dev);
17998c2ecf20Sopenharmony_ci	if (ret < 0) {
18008c2ecf20Sopenharmony_ci		netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
18018c2ecf20Sopenharmony_ci			   __func__, ret);
18028c2ecf20Sopenharmony_ci		goto err_disableclks;
18038c2ecf20Sopenharmony_ci	}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) {
18068c2ecf20Sopenharmony_ci		priv->write_reg = xcan_write_reg_be;
18078c2ecf20Sopenharmony_ci		priv->read_reg = xcan_read_reg_be;
18088c2ecf20Sopenharmony_ci	}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	priv->can.clock.freq = clk_get_rate(priv->can_clk);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	netif_napi_add(ndev, &priv->napi, xcan_rx_poll, rx_max);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	ret = register_candev(ndev);
18158c2ecf20Sopenharmony_ci	if (ret) {
18168c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret);
18178c2ecf20Sopenharmony_ci		goto err_disableclks;
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	devm_can_led_init(ndev);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	pm_runtime_put(&pdev->dev);
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	if (priv->devtype.flags & XCAN_FLAG_CANFD_2) {
18258c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_AFR_2_ID_OFFSET, 0x00000000);
18268c2ecf20Sopenharmony_ci		priv->write_reg(priv, XCAN_AFR_2_MASK_OFFSET, 0x00000000);
18278c2ecf20Sopenharmony_ci	}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx buffers: actual %d, using %d\n",
18308c2ecf20Sopenharmony_ci		   priv->reg_base, ndev->irq, priv->can.clock.freq,
18318c2ecf20Sopenharmony_ci		   hw_tx_max, priv->tx_max);
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	return 0;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cierr_disableclks:
18368c2ecf20Sopenharmony_ci	pm_runtime_put(priv->dev);
18378c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
18388c2ecf20Sopenharmony_cierr_free:
18398c2ecf20Sopenharmony_ci	free_candev(ndev);
18408c2ecf20Sopenharmony_cierr:
18418c2ecf20Sopenharmony_ci	return ret;
18428c2ecf20Sopenharmony_ci}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci/**
18458c2ecf20Sopenharmony_ci * xcan_remove - Unregister the device after releasing the resources
18468c2ecf20Sopenharmony_ci * @pdev:	Handle to the platform device structure
18478c2ecf20Sopenharmony_ci *
18488c2ecf20Sopenharmony_ci * This function frees all the resources allocated to the device.
18498c2ecf20Sopenharmony_ci * Return: 0 always
18508c2ecf20Sopenharmony_ci */
18518c2ecf20Sopenharmony_cistatic int xcan_remove(struct platform_device *pdev)
18528c2ecf20Sopenharmony_ci{
18538c2ecf20Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
18548c2ecf20Sopenharmony_ci	struct xcan_priv *priv = netdev_priv(ndev);
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	unregister_candev(ndev);
18578c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
18588c2ecf20Sopenharmony_ci	netif_napi_del(&priv->napi);
18598c2ecf20Sopenharmony_ci	free_candev(ndev);
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	return 0;
18628c2ecf20Sopenharmony_ci}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_cistatic struct platform_driver xcan_driver = {
18658c2ecf20Sopenharmony_ci	.probe = xcan_probe,
18668c2ecf20Sopenharmony_ci	.remove	= xcan_remove,
18678c2ecf20Sopenharmony_ci	.driver	= {
18688c2ecf20Sopenharmony_ci		.name = DRIVER_NAME,
18698c2ecf20Sopenharmony_ci		.pm = &xcan_dev_pm_ops,
18708c2ecf20Sopenharmony_ci		.of_match_table	= xcan_of_match,
18718c2ecf20Sopenharmony_ci	},
18728c2ecf20Sopenharmony_ci};
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_cimodule_platform_driver(xcan_driver);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
18778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xilinx Inc");
18788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx CAN interface");
1879