xref: /openbmc/linux/drivers/net/can/m_can/m_can.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
1f524f829SDan Murphy // SPDX-License-Identifier: GPL-2.0
2f524f829SDan Murphy // CAN bus driver for Bosch M_CAN controller
3f524f829SDan Murphy // Copyright (C) 2014 Freescale Semiconductor, Inc.
4f524f829SDan Murphy //      Dong Aisheng <b29396@freescale.com>
5f524f829SDan Murphy // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
6f524f829SDan Murphy 
7f524f829SDan Murphy /* Bosch M_CAN user manual can be obtained from:
84c832b38SMarc Kleine-Budde  * https://github.com/linux-can/can-doc/tree/master/m_can
9e0d1f481SDong Aisheng  */
10e0d1f481SDong Aisheng 
1117447f08STorin Cooper-Bennun #include <linux/bitfield.h>
1209451f24SVivek Yadav #include <linux/can/dev.h>
13409c188cSVincent Mailhol #include <linux/ethtool.h>
14b382380cSJudith Mendez #include <linux/hrtimer.h>
15e0d1f481SDong Aisheng #include <linux/interrupt.h>
16e0d1f481SDong Aisheng #include <linux/io.h>
1709451f24SVivek Yadav #include <linux/iopoll.h>
18e0d1f481SDong Aisheng #include <linux/kernel.h>
19e0d1f481SDong Aisheng #include <linux/module.h>
20e0d1f481SDong Aisheng #include <linux/netdevice.h>
21e0d1f481SDong Aisheng #include <linux/of.h>
2209451f24SVivek Yadav #include <linux/phy/phy.h>
2309451f24SVivek Yadav #include <linux/pinctrl/consumer.h>
24e0d1f481SDong Aisheng #include <linux/platform_device.h>
25cdf8259dSFaiz Abbas #include <linux/pm_runtime.h>
26e0d1f481SDong Aisheng 
27f524f829SDan Murphy #include "m_can.h"
28e0d1f481SDong Aisheng 
29e0d1f481SDong Aisheng /* registers definition */
30e0d1f481SDong Aisheng enum m_can_reg {
31e0d1f481SDong Aisheng 	M_CAN_CREL	= 0x0,
32e0d1f481SDong Aisheng 	M_CAN_ENDN	= 0x4,
33e0d1f481SDong Aisheng 	M_CAN_CUST	= 0x8,
345e1bd15aSMario Huettel 	M_CAN_DBTP	= 0xc,
35e0d1f481SDong Aisheng 	M_CAN_TEST	= 0x10,
36e0d1f481SDong Aisheng 	M_CAN_RWD	= 0x14,
37e0d1f481SDong Aisheng 	M_CAN_CCCR	= 0x18,
385e1bd15aSMario Huettel 	M_CAN_NBTP	= 0x1c,
39e0d1f481SDong Aisheng 	M_CAN_TSCC	= 0x20,
40e0d1f481SDong Aisheng 	M_CAN_TSCV	= 0x24,
41e0d1f481SDong Aisheng 	M_CAN_TOCC	= 0x28,
42e0d1f481SDong Aisheng 	M_CAN_TOCV	= 0x2c,
43e0d1f481SDong Aisheng 	M_CAN_ECR	= 0x40,
44e0d1f481SDong Aisheng 	M_CAN_PSR	= 0x44,
455e1bd15aSMario Huettel 	/* TDCR Register only available for version >=3.1.x */
465e1bd15aSMario Huettel 	M_CAN_TDCR	= 0x48,
47e0d1f481SDong Aisheng 	M_CAN_IR	= 0x50,
48e0d1f481SDong Aisheng 	M_CAN_IE	= 0x54,
49e0d1f481SDong Aisheng 	M_CAN_ILS	= 0x58,
50e0d1f481SDong Aisheng 	M_CAN_ILE	= 0x5c,
51e0d1f481SDong Aisheng 	M_CAN_GFC	= 0x80,
52e0d1f481SDong Aisheng 	M_CAN_SIDFC	= 0x84,
53e0d1f481SDong Aisheng 	M_CAN_XIDFC	= 0x88,
54e0d1f481SDong Aisheng 	M_CAN_XIDAM	= 0x90,
55e0d1f481SDong Aisheng 	M_CAN_HPMS	= 0x94,
56e0d1f481SDong Aisheng 	M_CAN_NDAT1	= 0x98,
57e0d1f481SDong Aisheng 	M_CAN_NDAT2	= 0x9c,
58e0d1f481SDong Aisheng 	M_CAN_RXF0C	= 0xa0,
59e0d1f481SDong Aisheng 	M_CAN_RXF0S	= 0xa4,
60e0d1f481SDong Aisheng 	M_CAN_RXF0A	= 0xa8,
61e0d1f481SDong Aisheng 	M_CAN_RXBC	= 0xac,
62e0d1f481SDong Aisheng 	M_CAN_RXF1C	= 0xb0,
63e0d1f481SDong Aisheng 	M_CAN_RXF1S	= 0xb4,
64e0d1f481SDong Aisheng 	M_CAN_RXF1A	= 0xb8,
65e0d1f481SDong Aisheng 	M_CAN_RXESC	= 0xbc,
66e0d1f481SDong Aisheng 	M_CAN_TXBC	= 0xc0,
67e0d1f481SDong Aisheng 	M_CAN_TXFQS	= 0xc4,
68e0d1f481SDong Aisheng 	M_CAN_TXESC	= 0xc8,
69e0d1f481SDong Aisheng 	M_CAN_TXBRP	= 0xcc,
70e0d1f481SDong Aisheng 	M_CAN_TXBAR	= 0xd0,
71e0d1f481SDong Aisheng 	M_CAN_TXBCR	= 0xd4,
72e0d1f481SDong Aisheng 	M_CAN_TXBTO	= 0xd8,
73e0d1f481SDong Aisheng 	M_CAN_TXBCF	= 0xdc,
74e0d1f481SDong Aisheng 	M_CAN_TXBTIE	= 0xe0,
75e0d1f481SDong Aisheng 	M_CAN_TXBCIE	= 0xe4,
76e0d1f481SDong Aisheng 	M_CAN_TXEFC	= 0xf0,
77e0d1f481SDong Aisheng 	M_CAN_TXEFS	= 0xf4,
78e0d1f481SDong Aisheng 	M_CAN_TXEFA	= 0xf8,
79e0d1f481SDong Aisheng };
80e0d1f481SDong Aisheng 
81f524f829SDan Murphy /* message ram configuration data length */
82f524f829SDan Murphy #define MRAM_CFG_LEN	8
83e0d1f481SDong Aisheng 
84b03cfc5bSMario Huettel /* Core Release Register (CREL) */
8520779943STorin Cooper-Bennun #define CREL_REL_MASK		GENMASK(31, 28)
8620779943STorin Cooper-Bennun #define CREL_STEP_MASK		GENMASK(27, 24)
8720779943STorin Cooper-Bennun #define CREL_SUBSTEP_MASK	GENMASK(23, 20)
88b03cfc5bSMario Huettel 
895e1bd15aSMario Huettel /* Data Bit Timing & Prescaler Register (DBTP) */
905e1bd15aSMario Huettel #define DBTP_TDC		BIT(23)
9120779943STorin Cooper-Bennun #define DBTP_DBRP_MASK		GENMASK(20, 16)
9220779943STorin Cooper-Bennun #define DBTP_DTSEG1_MASK	GENMASK(12, 8)
9320779943STorin Cooper-Bennun #define DBTP_DTSEG2_MASK	GENMASK(7, 4)
9420779943STorin Cooper-Bennun #define DBTP_DSJW_MASK		GENMASK(3, 0)
9580646733SDong Aisheng 
96e759c626SFranklin S Cooper Jr /* Transmitter Delay Compensation Register (TDCR) */
9720779943STorin Cooper-Bennun #define TDCR_TDCO_MASK		GENMASK(14, 8)
9820779943STorin Cooper-Bennun #define TDCR_TDCF_MASK		GENMASK(6, 0)
99e759c626SFranklin S Cooper Jr 
100e0d1f481SDong Aisheng /* Test Register (TEST) */
101e0d1f481SDong Aisheng #define TEST_LBCK		BIT(4)
102e0d1f481SDong Aisheng 
103e0d1f481SDong Aisheng /* CC Control Register (CCCR) */
1045e1bd15aSMario Huettel #define CCCR_TXP		BIT(14)
10580646733SDong Aisheng #define CCCR_TEST		BIT(7)
106fb7d6a81SPankaj Sharma #define CCCR_DAR		BIT(6)
107e0d1f481SDong Aisheng #define CCCR_MON		BIT(5)
1085e1bd15aSMario Huettel #define CCCR_CSR		BIT(4)
1095e1bd15aSMario Huettel #define CCCR_CSA		BIT(3)
1105e1bd15aSMario Huettel #define CCCR_ASM		BIT(2)
111e0d1f481SDong Aisheng #define CCCR_CCE		BIT(1)
112e0d1f481SDong Aisheng #define CCCR_INIT		BIT(0)
11338395f30STorin Cooper-Bennun /* for version 3.0.x */
11438395f30STorin Cooper-Bennun #define CCCR_CMR_MASK		GENMASK(11, 10)
11538395f30STorin Cooper-Bennun #define CCCR_CMR_CANFD		0x1
11638395f30STorin Cooper-Bennun #define CCCR_CMR_CANFD_BRS	0x2
11738395f30STorin Cooper-Bennun #define CCCR_CMR_CAN		0x3
11838395f30STorin Cooper-Bennun #define CCCR_CME_MASK		GENMASK(9, 8)
11938395f30STorin Cooper-Bennun #define CCCR_CME_CAN		0
12038395f30STorin Cooper-Bennun #define CCCR_CME_CANFD		0x1
12138395f30STorin Cooper-Bennun #define CCCR_CME_CANFD_BRS	0x2
1225e1bd15aSMario Huettel /* for version >=3.1.x */
1235e1bd15aSMario Huettel #define CCCR_EFBI		BIT(13)
1245e1bd15aSMario Huettel #define CCCR_PXHD		BIT(12)
1255e1bd15aSMario Huettel #define CCCR_BRSE		BIT(9)
1265e1bd15aSMario Huettel #define CCCR_FDOE		BIT(8)
12738395f30STorin Cooper-Bennun /* for version >=3.2.x */
1285e1bd15aSMario Huettel #define CCCR_NISO		BIT(15)
12938395f30STorin Cooper-Bennun /* for version >=3.3.x */
13038395f30STorin Cooper-Bennun #define CCCR_WMM		BIT(11)
13138395f30STorin Cooper-Bennun #define CCCR_UTSU		BIT(10)
132e0d1f481SDong Aisheng 
1335e1bd15aSMario Huettel /* Nominal Bit Timing & Prescaler Register (NBTP) */
13420779943STorin Cooper-Bennun #define NBTP_NSJW_MASK		GENMASK(31, 25)
13520779943STorin Cooper-Bennun #define NBTP_NBRP_MASK		GENMASK(24, 16)
13620779943STorin Cooper-Bennun #define NBTP_NTSEG1_MASK	GENMASK(15, 8)
13720779943STorin Cooper-Bennun #define NBTP_NTSEG2_MASK	GENMASK(6, 0)
138e0d1f481SDong Aisheng 
13917447f08STorin Cooper-Bennun /* Timestamp Counter Configuration Register (TSCC) */
14017447f08STorin Cooper-Bennun #define TSCC_TCP_MASK		GENMASK(19, 16)
14117447f08STorin Cooper-Bennun #define TSCC_TSS_MASK		GENMASK(1, 0)
14217447f08STorin Cooper-Bennun #define TSCC_TSS_DISABLE	0x0
14317447f08STorin Cooper-Bennun #define TSCC_TSS_INTERNAL	0x1
14417447f08STorin Cooper-Bennun #define TSCC_TSS_EXTERNAL	0x2
14517447f08STorin Cooper-Bennun 
14617447f08STorin Cooper-Bennun /* Timestamp Counter Value Register (TSCV) */
14717447f08STorin Cooper-Bennun #define TSCV_TSC_MASK		GENMASK(15, 0)
14817447f08STorin Cooper-Bennun 
149e0d1f481SDong Aisheng /* Error Counter Register (ECR) */
150e0d1f481SDong Aisheng #define ECR_RP			BIT(15)
15120779943STorin Cooper-Bennun #define ECR_REC_MASK		GENMASK(14, 8)
15220779943STorin Cooper-Bennun #define ECR_TEC_MASK		GENMASK(7, 0)
153e0d1f481SDong Aisheng 
154e0d1f481SDong Aisheng /* Protocol Status Register (PSR) */
155e0d1f481SDong Aisheng #define PSR_BO		BIT(7)
156e0d1f481SDong Aisheng #define PSR_EW		BIT(6)
157e0d1f481SDong Aisheng #define PSR_EP		BIT(5)
15820779943STorin Cooper-Bennun #define PSR_LEC_MASK	GENMASK(2, 0)
159f5071d9eSVivek Yadav #define PSR_DLEC_MASK	GENMASK(10, 8)
160e0d1f481SDong Aisheng 
161e0d1f481SDong Aisheng /* Interrupt Register (IR) */
162e0d1f481SDong Aisheng #define IR_ALL_INT	0xffffffff
1635e1bd15aSMario Huettel 
1645e1bd15aSMario Huettel /* Renamed bits for versions > 3.1.x */
1655e1bd15aSMario Huettel #define IR_ARA		BIT(29)
1665e1bd15aSMario Huettel #define IR_PED		BIT(28)
1675e1bd15aSMario Huettel #define IR_PEA		BIT(27)
1685e1bd15aSMario Huettel 
1695e1bd15aSMario Huettel /* Bits for version 3.0.x */
170e0d1f481SDong Aisheng #define IR_STE		BIT(31)
171e0d1f481SDong Aisheng #define IR_FOE		BIT(30)
172e0d1f481SDong Aisheng #define IR_ACKE		BIT(29)
173e0d1f481SDong Aisheng #define IR_BE		BIT(28)
174e0d1f481SDong Aisheng #define IR_CRCE		BIT(27)
175e0d1f481SDong Aisheng #define IR_WDI		BIT(26)
176e0d1f481SDong Aisheng #define IR_BO		BIT(25)
177e0d1f481SDong Aisheng #define IR_EW		BIT(24)
178e0d1f481SDong Aisheng #define IR_EP		BIT(23)
179e0d1f481SDong Aisheng #define IR_ELO		BIT(22)
180e0d1f481SDong Aisheng #define IR_BEU		BIT(21)
181e0d1f481SDong Aisheng #define IR_BEC		BIT(20)
182e0d1f481SDong Aisheng #define IR_DRX		BIT(19)
183e0d1f481SDong Aisheng #define IR_TOO		BIT(18)
184e0d1f481SDong Aisheng #define IR_MRAF		BIT(17)
185e0d1f481SDong Aisheng #define IR_TSW		BIT(16)
186e0d1f481SDong Aisheng #define IR_TEFL		BIT(15)
187e0d1f481SDong Aisheng #define IR_TEFF		BIT(14)
188e0d1f481SDong Aisheng #define IR_TEFW		BIT(13)
189e0d1f481SDong Aisheng #define IR_TEFN		BIT(12)
190e0d1f481SDong Aisheng #define IR_TFE		BIT(11)
191e0d1f481SDong Aisheng #define IR_TCF		BIT(10)
192e0d1f481SDong Aisheng #define IR_TC		BIT(9)
193e0d1f481SDong Aisheng #define IR_HPM		BIT(8)
194e0d1f481SDong Aisheng #define IR_RF1L		BIT(7)
195e0d1f481SDong Aisheng #define IR_RF1F		BIT(6)
196e0d1f481SDong Aisheng #define IR_RF1W		BIT(5)
197e0d1f481SDong Aisheng #define IR_RF1N		BIT(4)
198e0d1f481SDong Aisheng #define IR_RF0L		BIT(3)
199e0d1f481SDong Aisheng #define IR_RF0F		BIT(2)
200e0d1f481SDong Aisheng #define IR_RF0W		BIT(1)
201e0d1f481SDong Aisheng #define IR_RF0N		BIT(0)
202e0d1f481SDong Aisheng #define IR_ERR_STATE	(IR_BO | IR_EW | IR_EP)
2035e1bd15aSMario Huettel 
2045e1bd15aSMario Huettel /* Interrupts for version 3.0.x */
2055e1bd15aSMario Huettel #define IR_ERR_LEC_30X	(IR_STE	| IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
206f58ac1adSBrian Silverman #define IR_ERR_BUS_30X	(IR_ERR_LEC_30X | IR_WDI | IR_BEU | IR_BEC | \
207f58ac1adSBrian Silverman 			 IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
208f58ac1adSBrian Silverman 			 IR_RF0L)
2095e1bd15aSMario Huettel #define IR_ERR_ALL_30X	(IR_ERR_STATE | IR_ERR_BUS_30X)
21020779943STorin Cooper-Bennun 
2115e1bd15aSMario Huettel /* Interrupts for version >= 3.1.x */
2125e1bd15aSMario Huettel #define IR_ERR_LEC_31X	(IR_PED | IR_PEA)
213f58ac1adSBrian Silverman #define IR_ERR_BUS_31X	(IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \
214f58ac1adSBrian Silverman 			 IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
215f58ac1adSBrian Silverman 			 IR_RF0L)
2165e1bd15aSMario Huettel #define IR_ERR_ALL_31X	(IR_ERR_STATE | IR_ERR_BUS_31X)
217e0d1f481SDong Aisheng 
218e0d1f481SDong Aisheng /* Interrupt Line Select (ILS) */
219e0d1f481SDong Aisheng #define ILS_ALL_INT0	0x0
220e0d1f481SDong Aisheng #define ILS_ALL_INT1	0xFFFFFFFF
221e0d1f481SDong Aisheng 
222e0d1f481SDong Aisheng /* Interrupt Line Enable (ILE) */
223e0d1f481SDong Aisheng #define ILE_EINT1	BIT(1)
2245e1bd15aSMario Huettel #define ILE_EINT0	BIT(0)
225e0d1f481SDong Aisheng 
226e0d1f481SDong Aisheng /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
22720779943STorin Cooper-Bennun #define RXFC_FWM_MASK	GENMASK(30, 24)
22820779943STorin Cooper-Bennun #define RXFC_FS_MASK	GENMASK(22, 16)
229e0d1f481SDong Aisheng 
230e0d1f481SDong Aisheng /* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
231e0d1f481SDong Aisheng #define RXFS_RFL	BIT(25)
232e0d1f481SDong Aisheng #define RXFS_FF		BIT(24)
23320779943STorin Cooper-Bennun #define RXFS_FPI_MASK	GENMASK(21, 16)
23420779943STorin Cooper-Bennun #define RXFS_FGI_MASK	GENMASK(13, 8)
23520779943STorin Cooper-Bennun #define RXFS_FFL_MASK	GENMASK(6, 0)
236e0d1f481SDong Aisheng 
237e0d1f481SDong Aisheng /* Rx Buffer / FIFO Element Size Configuration (RXESC) */
2380f315716STorin Cooper-Bennun #define RXESC_RBDS_MASK		GENMASK(10, 8)
2390f315716STorin Cooper-Bennun #define RXESC_F1DS_MASK		GENMASK(6, 4)
2400f315716STorin Cooper-Bennun #define RXESC_F0DS_MASK		GENMASK(2, 0)
2410f315716STorin Cooper-Bennun #define RXESC_64B		0x7
242e0d1f481SDong Aisheng 
243e0d1f481SDong Aisheng /* Tx Buffer Configuration (TXBC) */
24420779943STorin Cooper-Bennun #define TXBC_TFQS_MASK		GENMASK(29, 24)
24520779943STorin Cooper-Bennun #define TXBC_NDTB_MASK		GENMASK(21, 16)
2465e1bd15aSMario Huettel 
2475e1bd15aSMario Huettel /* Tx FIFO/Queue Status (TXFQS) */
2485e1bd15aSMario Huettel #define TXFQS_TFQF		BIT(21)
24920779943STorin Cooper-Bennun #define TXFQS_TFQPI_MASK	GENMASK(20, 16)
25020779943STorin Cooper-Bennun #define TXFQS_TFGI_MASK		GENMASK(12, 8)
25120779943STorin Cooper-Bennun #define TXFQS_TFFL_MASK		GENMASK(5, 0)
252e0d1f481SDong Aisheng 
253e0d1f481SDong Aisheng /* Tx Buffer Element Size Configuration (TXESC) */
2540f315716STorin Cooper-Bennun #define TXESC_TBDS_MASK		GENMASK(2, 0)
2550f315716STorin Cooper-Bennun #define TXESC_TBDS_64B		0x7
256e0d1f481SDong Aisheng 
2575e1bd15aSMario Huettel /* Tx Event FIFO Configuration (TXEFC) */
25820779943STorin Cooper-Bennun #define TXEFC_EFS_MASK		GENMASK(21, 16)
2595e1bd15aSMario Huettel 
2605e1bd15aSMario Huettel /* Tx Event FIFO Status (TXEFS) */
2615e1bd15aSMario Huettel #define TXEFS_TEFL		BIT(25)
2625e1bd15aSMario Huettel #define TXEFS_EFF		BIT(24)
26320779943STorin Cooper-Bennun #define TXEFS_EFGI_MASK		GENMASK(12, 8)
26420779943STorin Cooper-Bennun #define TXEFS_EFFL_MASK		GENMASK(5, 0)
2655e1bd15aSMario Huettel 
2665e1bd15aSMario Huettel /* Tx Event FIFO Acknowledge (TXEFA) */
26720779943STorin Cooper-Bennun #define TXEFA_EFAI_MASK		GENMASK(4, 0)
268e0d1f481SDong Aisheng 
269e0d1f481SDong Aisheng /* Message RAM Configuration (in bytes) */
270e0d1f481SDong Aisheng #define SIDF_ELEMENT_SIZE	4
271e0d1f481SDong Aisheng #define XIDF_ELEMENT_SIZE	8
27280646733SDong Aisheng #define RXF0_ELEMENT_SIZE	72
27380646733SDong Aisheng #define RXF1_ELEMENT_SIZE	72
2745e1bd15aSMario Huettel #define RXB_ELEMENT_SIZE	72
275e0d1f481SDong Aisheng #define TXE_ELEMENT_SIZE	8
27680646733SDong Aisheng #define TXB_ELEMENT_SIZE	72
277e0d1f481SDong Aisheng 
278e0d1f481SDong Aisheng /* Message RAM Elements */
279e0d1f481SDong Aisheng #define M_CAN_FIFO_ID		0x0
280e0d1f481SDong Aisheng #define M_CAN_FIFO_DLC		0x4
281812270e5SMatt Kline #define M_CAN_FIFO_DATA		0x8
282e0d1f481SDong Aisheng 
283e0d1f481SDong Aisheng /* Rx Buffer Element */
28480646733SDong Aisheng /* R0 */
285e0d1f481SDong Aisheng #define RX_BUF_ESI		BIT(31)
286e0d1f481SDong Aisheng #define RX_BUF_XTD		BIT(30)
287e0d1f481SDong Aisheng #define RX_BUF_RTR		BIT(29)
28880646733SDong Aisheng /* R1 */
28980646733SDong Aisheng #define RX_BUF_ANMF		BIT(31)
2905e1bd15aSMario Huettel #define RX_BUF_FDF		BIT(21)
29180646733SDong Aisheng #define RX_BUF_BRS		BIT(20)
29217447f08STorin Cooper-Bennun #define RX_BUF_RXTS_MASK	GENMASK(15, 0)
293e0d1f481SDong Aisheng 
294e0d1f481SDong Aisheng /* Tx Buffer Element */
2955e1bd15aSMario Huettel /* T0 */
2965e1bd15aSMario Huettel #define TX_BUF_ESI		BIT(31)
297e0d1f481SDong Aisheng #define TX_BUF_XTD		BIT(30)
298e0d1f481SDong Aisheng #define TX_BUF_RTR		BIT(29)
2995e1bd15aSMario Huettel /* T1 */
3005e1bd15aSMario Huettel #define TX_BUF_EFC		BIT(23)
3015e1bd15aSMario Huettel #define TX_BUF_FDF		BIT(21)
3025e1bd15aSMario Huettel #define TX_BUF_BRS		BIT(20)
30320779943STorin Cooper-Bennun #define TX_BUF_MM_MASK		GENMASK(31, 24)
30420779943STorin Cooper-Bennun #define TX_BUF_DLC_MASK		GENMASK(19, 16)
305e0d1f481SDong Aisheng 
30610c1c397SMario Huettel /* Tx event FIFO Element */
30710c1c397SMario Huettel /* E1 */
30820779943STorin Cooper-Bennun #define TX_EVENT_MM_MASK	GENMASK(31, 24)
30917447f08STorin Cooper-Bennun #define TX_EVENT_TXTS_MASK	GENMASK(15, 0)
31010c1c397SMario Huettel 
311b382380cSJudith Mendez /* Hrtimer polling interval */
312b382380cSJudith Mendez #define HRTIMER_POLL_INTERVAL_MS		1
313b382380cSJudith Mendez 
3141aa6772fSMatt Kline /* The ID and DLC registers are adjacent in M_CAN FIFO memory,
3151aa6772fSMatt Kline  * and we can save a (potentially slow) bus round trip by combining
3161aa6772fSMatt Kline  * reads and writes to them.
3171aa6772fSMatt Kline  */
3181aa6772fSMatt Kline struct id_and_dlc {
3191aa6772fSMatt Kline 	u32 id;
3201aa6772fSMatt Kline 	u32 dlc;
3211aa6772fSMatt Kline };
3221aa6772fSMatt Kline 
m_can_read(struct m_can_classdev * cdev,enum m_can_reg reg)323441ac340SDan Murphy static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg)
324e0d1f481SDong Aisheng {
325441ac340SDan Murphy 	return cdev->ops->read_reg(cdev, reg);
326e0d1f481SDong Aisheng }
327e0d1f481SDong Aisheng 
m_can_write(struct m_can_classdev * cdev,enum m_can_reg reg,u32 val)328441ac340SDan Murphy static inline void m_can_write(struct m_can_classdev *cdev, enum m_can_reg reg,
329f524f829SDan Murphy 			       u32 val)
330e0d1f481SDong Aisheng {
331441ac340SDan Murphy 	cdev->ops->write_reg(cdev, reg, val);
332e0d1f481SDong Aisheng }
333e0d1f481SDong Aisheng 
334e3938177SMatt Kline static int
m_can_fifo_read(struct m_can_classdev * cdev,u32 fgi,unsigned int offset,void * val,size_t val_count)335e3938177SMatt Kline m_can_fifo_read(struct m_can_classdev *cdev,
336e3938177SMatt Kline 		u32 fgi, unsigned int offset, void *val, size_t val_count)
337e0d1f481SDong Aisheng {
338441ac340SDan Murphy 	u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE +
339f524f829SDan Murphy 		offset;
340f524f829SDan Murphy 
341db72589cSMarc Kleine-Budde 	if (val_count == 0)
342db72589cSMarc Kleine-Budde 		return 0;
343db72589cSMarc Kleine-Budde 
344e3938177SMatt Kline 	return cdev->ops->read_fifo(cdev, addr_offset, val, val_count);
345e0d1f481SDong Aisheng }
346e0d1f481SDong Aisheng 
347e3938177SMatt Kline static int
m_can_fifo_write(struct m_can_classdev * cdev,u32 fpi,unsigned int offset,const void * val,size_t val_count)348e3938177SMatt Kline m_can_fifo_write(struct m_can_classdev *cdev,
349e3938177SMatt Kline 		 u32 fpi, unsigned int offset, const void *val, size_t val_count)
350e0d1f481SDong Aisheng {
351441ac340SDan Murphy 	u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE +
352f524f829SDan Murphy 		offset;
353f524f829SDan Murphy 
354db72589cSMarc Kleine-Budde 	if (val_count == 0)
355db72589cSMarc Kleine-Budde 		return 0;
356db72589cSMarc Kleine-Budde 
357e3938177SMatt Kline 	return cdev->ops->write_fifo(cdev, addr_offset, val, val_count);
358e0d1f481SDong Aisheng }
359e0d1f481SDong Aisheng 
m_can_fifo_write_no_off(struct m_can_classdev * cdev,u32 fpi,u32 val)360e3938177SMatt Kline static inline int m_can_fifo_write_no_off(struct m_can_classdev *cdev,
361f524f829SDan Murphy 					  u32 fpi, u32 val)
362f524f829SDan Murphy {
363e3938177SMatt Kline 	return cdev->ops->write_fifo(cdev, fpi, &val, 1);
364428479e4SMario Huettel }
365428479e4SMario Huettel 
366e3938177SMatt Kline static int
m_can_txe_fifo_read(struct m_can_classdev * cdev,u32 fgi,u32 offset,u32 * val)367e3938177SMatt Kline m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset, u32 *val)
368f524f829SDan Murphy {
369441ac340SDan Murphy 	u32 addr_offset = cdev->mcfg[MRAM_TXE].off + fgi * TXE_ELEMENT_SIZE +
370f524f829SDan Murphy 		offset;
371f524f829SDan Murphy 
372e3938177SMatt Kline 	return cdev->ops->read_fifo(cdev, addr_offset, val, 1);
373f524f829SDan Murphy }
374f524f829SDan Murphy 
_m_can_tx_fifo_full(u32 txfqs)375c1eaf8b9SMarkus Schneider-Pargmann static inline bool _m_can_tx_fifo_full(u32 txfqs)
376c1eaf8b9SMarkus Schneider-Pargmann {
377c1eaf8b9SMarkus Schneider-Pargmann 	return !!(txfqs & TXFQS_TFQF);
378c1eaf8b9SMarkus Schneider-Pargmann }
379c1eaf8b9SMarkus Schneider-Pargmann 
m_can_tx_fifo_full(struct m_can_classdev * cdev)380441ac340SDan Murphy static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev)
381428479e4SMario Huettel {
382c1eaf8b9SMarkus Schneider-Pargmann 	return _m_can_tx_fifo_full(m_can_read(cdev, M_CAN_TXFQS));
383428479e4SMario Huettel }
384428479e4SMario Huettel 
m_can_config_endisable(struct m_can_classdev * cdev,bool enable)38578e19a29SMarc Kleine-Budde static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
386e0d1f481SDong Aisheng {
387441ac340SDan Murphy 	u32 cccr = m_can_read(cdev, M_CAN_CCCR);
388e0d1f481SDong Aisheng 	u32 timeout = 10;
389e0d1f481SDong Aisheng 	u32 val = 0;
390e0d1f481SDong Aisheng 
391f524f829SDan Murphy 	/* Clear the Clock stop request if it was set */
392f524f829SDan Murphy 	if (cccr & CCCR_CSR)
393f524f829SDan Murphy 		cccr &= ~CCCR_CSR;
394f524f829SDan Murphy 
395e0d1f481SDong Aisheng 	if (enable) {
396e0d1f481SDong Aisheng 		/* enable m_can configuration */
397441ac340SDan Murphy 		m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT);
3987660f633SDong Aisheng 		udelay(5);
399e0d1f481SDong Aisheng 		/* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
400441ac340SDan Murphy 		m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
401e0d1f481SDong Aisheng 	} else {
402441ac340SDan Murphy 		m_can_write(cdev, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE));
403e0d1f481SDong Aisheng 	}
404e0d1f481SDong Aisheng 
405e0d1f481SDong Aisheng 	/* there's a delay for module initialization */
406e0d1f481SDong Aisheng 	if (enable)
407e0d1f481SDong Aisheng 		val = CCCR_INIT | CCCR_CCE;
408e0d1f481SDong Aisheng 
409441ac340SDan Murphy 	while ((m_can_read(cdev, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) {
410e0d1f481SDong Aisheng 		if (timeout == 0) {
411441ac340SDan Murphy 			netdev_warn(cdev->net, "Failed to init module\n");
412e0d1f481SDong Aisheng 			return;
413e0d1f481SDong Aisheng 		}
414e0d1f481SDong Aisheng 		timeout--;
415e0d1f481SDong Aisheng 		udelay(1);
416e0d1f481SDong Aisheng 	}
417e0d1f481SDong Aisheng }
418e0d1f481SDong Aisheng 
m_can_enable_all_interrupts(struct m_can_classdev * cdev)419441ac340SDan Murphy static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev)
420e0d1f481SDong Aisheng {
421887407b6SMarkus Schneider-Pargmann 	if (!cdev->net->irq) {
422887407b6SMarkus Schneider-Pargmann 		dev_dbg(cdev->dev, "Start hrtimer\n");
423887407b6SMarkus Schneider-Pargmann 		hrtimer_start(&cdev->hrtimer,
424887407b6SMarkus Schneider-Pargmann 			      ms_to_ktime(HRTIMER_POLL_INTERVAL_MS),
425887407b6SMarkus Schneider-Pargmann 			      HRTIMER_MODE_REL_PINNED);
426887407b6SMarkus Schneider-Pargmann 	}
427887407b6SMarkus Schneider-Pargmann 
42852973810SMario Huettel 	/* Only interrupt line 0 is used in this driver */
429441ac340SDan Murphy 	m_can_write(cdev, M_CAN_ILE, ILE_EINT0);
430e0d1f481SDong Aisheng }
431e0d1f481SDong Aisheng 
m_can_disable_all_interrupts(struct m_can_classdev * cdev)432441ac340SDan Murphy static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev)
433e0d1f481SDong Aisheng {
434441ac340SDan Murphy 	m_can_write(cdev, M_CAN_ILE, 0x0);
435887407b6SMarkus Schneider-Pargmann 
436887407b6SMarkus Schneider-Pargmann 	if (!cdev->net->irq) {
437887407b6SMarkus Schneider-Pargmann 		dev_dbg(cdev->dev, "Stop hrtimer\n");
438887407b6SMarkus Schneider-Pargmann 		hrtimer_cancel(&cdev->hrtimer);
439887407b6SMarkus Schneider-Pargmann 	}
440e0d1f481SDong Aisheng }
441e0d1f481SDong Aisheng 
44217447f08STorin Cooper-Bennun /* Retrieve internal timestamp counter from TSCV.TSC, and shift it to 32-bit
44317447f08STorin Cooper-Bennun  * width.
44417447f08STorin Cooper-Bennun  */
m_can_get_timestamp(struct m_can_classdev * cdev)44517447f08STorin Cooper-Bennun static u32 m_can_get_timestamp(struct m_can_classdev *cdev)
44617447f08STorin Cooper-Bennun {
44717447f08STorin Cooper-Bennun 	u32 tscv;
44817447f08STorin Cooper-Bennun 	u32 tsc;
44917447f08STorin Cooper-Bennun 
45017447f08STorin Cooper-Bennun 	tscv = m_can_read(cdev, M_CAN_TSCV);
45117447f08STorin Cooper-Bennun 	tsc = FIELD_GET(TSCV_TSC_MASK, tscv);
45217447f08STorin Cooper-Bennun 
45317447f08STorin Cooper-Bennun 	return (tsc << 16);
45417447f08STorin Cooper-Bennun }
45517447f08STorin Cooper-Bennun 
m_can_clean(struct net_device * net)456f524f829SDan Murphy static void m_can_clean(struct net_device *net)
457f524f829SDan Murphy {
458441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(net);
459f524f829SDan Murphy 
460441ac340SDan Murphy 	if (cdev->tx_skb) {
461f524f829SDan Murphy 		int putidx = 0;
462f524f829SDan Murphy 
463f524f829SDan Murphy 		net->stats.tx_errors++;
464441ac340SDan Murphy 		if (cdev->version > 30)
46520779943STorin Cooper-Bennun 			putidx = FIELD_GET(TXFQS_TFQPI_MASK,
46620779943STorin Cooper-Bennun 					   m_can_read(cdev, M_CAN_TXFQS));
467f524f829SDan Murphy 
468f318482aSMarc Kleine-Budde 		can_free_echo_skb(cdev->net, putidx, NULL);
469441ac340SDan Murphy 		cdev->tx_skb = NULL;
470f524f829SDan Murphy 	}
471f524f829SDan Murphy }
472f524f829SDan Murphy 
4731be37d3bSTorin Cooper-Bennun /* For peripherals, pass skb to rx-offload, which will push skb from
4741be37d3bSTorin Cooper-Bennun  * napi. For non-peripherals, RX is done in napi already, so push
4751be37d3bSTorin Cooper-Bennun  * directly. timestamp is used to ensure good skb ordering in
4761be37d3bSTorin Cooper-Bennun  * rx-offload and is ignored for non-peripherals.
4771be37d3bSTorin Cooper-Bennun  */
m_can_receive_skb(struct m_can_classdev * cdev,struct sk_buff * skb,u32 timestamp)4781be37d3bSTorin Cooper-Bennun static void m_can_receive_skb(struct m_can_classdev *cdev,
4791be37d3bSTorin Cooper-Bennun 			      struct sk_buff *skb,
4801be37d3bSTorin Cooper-Bennun 			      u32 timestamp)
4811be37d3bSTorin Cooper-Bennun {
482644022b1SMarc Kleine-Budde 	if (cdev->is_peripheral) {
483644022b1SMarc Kleine-Budde 		struct net_device_stats *stats = &cdev->net->stats;
484644022b1SMarc Kleine-Budde 		int err;
485644022b1SMarc Kleine-Budde 
486eb38c205SMarc Kleine-Budde 		err = can_rx_offload_queue_timestamp(&cdev->offload, skb,
487644022b1SMarc Kleine-Budde 						     timestamp);
488644022b1SMarc Kleine-Budde 		if (err)
489644022b1SMarc Kleine-Budde 			stats->rx_fifo_errors++;
490644022b1SMarc Kleine-Budde 	} else {
4911be37d3bSTorin Cooper-Bennun 		netif_receive_skb(skb);
4921be37d3bSTorin Cooper-Bennun 	}
493644022b1SMarc Kleine-Budde }
4941be37d3bSTorin Cooper-Bennun 
m_can_read_fifo(struct net_device * dev,u32 fgi)4956355a3c9SMarkus Schneider-Pargmann static int m_can_read_fifo(struct net_device *dev, u32 fgi)
496e0d1f481SDong Aisheng {
49780646733SDong Aisheng 	struct net_device_stats *stats = &dev->stats;
498441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
49980646733SDong Aisheng 	struct canfd_frame *cf;
50080646733SDong Aisheng 	struct sk_buff *skb;
5011aa6772fSMatt Kline 	struct id_and_dlc fifo_header;
5021be37d3bSTorin Cooper-Bennun 	u32 timestamp = 0;
5031aa6772fSMatt Kline 	int err;
504e0d1f481SDong Aisheng 
5051aa6772fSMatt Kline 	err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID, &fifo_header, 2);
506e3938177SMatt Kline 	if (err)
507e3938177SMatt Kline 		goto out_fail;
508e3938177SMatt Kline 
5091aa6772fSMatt Kline 	if (fifo_header.dlc & RX_BUF_FDF)
51080646733SDong Aisheng 		skb = alloc_canfd_skb(dev, &cf);
51180646733SDong Aisheng 	else
51280646733SDong Aisheng 		skb = alloc_can_skb(dev, (struct can_frame **)&cf);
51380646733SDong Aisheng 	if (!skb) {
51480646733SDong Aisheng 		stats->rx_dropped++;
515e3938177SMatt Kline 		return 0;
51680646733SDong Aisheng 	}
51780646733SDong Aisheng 
5181aa6772fSMatt Kline 	if (fifo_header.dlc & RX_BUF_FDF)
5191aa6772fSMatt Kline 		cf->len = can_fd_dlc2len((fifo_header.dlc >> 16) & 0x0F);
52080646733SDong Aisheng 	else
5211aa6772fSMatt Kline 		cf->len = can_cc_dlc2len((fifo_header.dlc >> 16) & 0x0F);
52280646733SDong Aisheng 
5231aa6772fSMatt Kline 	if (fifo_header.id & RX_BUF_XTD)
5241aa6772fSMatt Kline 		cf->can_id = (fifo_header.id & CAN_EFF_MASK) | CAN_EFF_FLAG;
525e0d1f481SDong Aisheng 	else
5261aa6772fSMatt Kline 		cf->can_id = (fifo_header.id >> 18) & CAN_SFF_MASK;
527e0d1f481SDong Aisheng 
5281aa6772fSMatt Kline 	if (fifo_header.id & RX_BUF_ESI) {
52980646733SDong Aisheng 		cf->flags |= CANFD_ESI;
53080646733SDong Aisheng 		netdev_dbg(dev, "ESI Error\n");
53180646733SDong Aisheng 	}
532921f1681SDong Aisheng 
5331aa6772fSMatt Kline 	if (!(fifo_header.dlc & RX_BUF_FDF) && (fifo_header.id & RX_BUF_RTR)) {
534e0d1f481SDong Aisheng 		cf->can_id |= CAN_RTR_FLAG;
535e0d1f481SDong Aisheng 	} else {
5361aa6772fSMatt Kline 		if (fifo_header.dlc & RX_BUF_BRS)
53780646733SDong Aisheng 			cf->flags |= CANFD_BRS;
53880646733SDong Aisheng 
539812270e5SMatt Kline 		err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DATA,
5401aa6772fSMatt Kline 				      cf->data, DIV_ROUND_UP(cf->len, 4));
541e3938177SMatt Kline 		if (err)
54231cb32a5SVincent Mailhol 			goto out_free_skb;
5438e674ca7SVincent Mailhol 
5448e674ca7SVincent Mailhol 		stats->rx_bytes += cf->len;
545e3938177SMatt Kline 	}
5468e674ca7SVincent Mailhol 	stats->rx_packets++;
547e0d1f481SDong Aisheng 
5484c333369SMarc Kleine-Budde 	timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
5491be37d3bSTorin Cooper-Bennun 
5501be37d3bSTorin Cooper-Bennun 	m_can_receive_skb(cdev, skb, timestamp);
551e3938177SMatt Kline 
552e3938177SMatt Kline 	return 0;
553e3938177SMatt Kline 
55431cb32a5SVincent Mailhol out_free_skb:
55531cb32a5SVincent Mailhol 	kfree_skb(skb);
556e3938177SMatt Kline out_fail:
557e3938177SMatt Kline 	netdev_err(dev, "FIFO read returned %d\n", err);
558e3938177SMatt Kline 	return err;
559e0d1f481SDong Aisheng }
560e0d1f481SDong Aisheng 
m_can_do_rx_poll(struct net_device * dev,int quota)561e0d1f481SDong Aisheng static int m_can_do_rx_poll(struct net_device *dev, int quota)
562e0d1f481SDong Aisheng {
563441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
564e0d1f481SDong Aisheng 	u32 pkts = 0;
565e0d1f481SDong Aisheng 	u32 rxfs;
5666355a3c9SMarkus Schneider-Pargmann 	u32 rx_count;
5676355a3c9SMarkus Schneider-Pargmann 	u32 fgi;
568e2f1c8cbSMarkus Schneider-Pargmann 	int ack_fgi = -1;
5696355a3c9SMarkus Schneider-Pargmann 	int i;
570e2f1c8cbSMarkus Schneider-Pargmann 	int err = 0;
571e0d1f481SDong Aisheng 
572441ac340SDan Murphy 	rxfs = m_can_read(cdev, M_CAN_RXF0S);
573e0d1f481SDong Aisheng 	if (!(rxfs & RXFS_FFL_MASK)) {
574e0d1f481SDong Aisheng 		netdev_dbg(dev, "no messages in fifo0\n");
575e0d1f481SDong Aisheng 		return 0;
576e0d1f481SDong Aisheng 	}
577e0d1f481SDong Aisheng 
5786355a3c9SMarkus Schneider-Pargmann 	rx_count = FIELD_GET(RXFS_FFL_MASK, rxfs);
5796355a3c9SMarkus Schneider-Pargmann 	fgi = FIELD_GET(RXFS_FGI_MASK, rxfs);
5806355a3c9SMarkus Schneider-Pargmann 
5816355a3c9SMarkus Schneider-Pargmann 	for (i = 0; i < rx_count && quota > 0; ++i) {
5826355a3c9SMarkus Schneider-Pargmann 		err = m_can_read_fifo(dev, fgi);
583e3938177SMatt Kline 		if (err)
584e2f1c8cbSMarkus Schneider-Pargmann 			break;
585e0d1f481SDong Aisheng 
586e0d1f481SDong Aisheng 		quota--;
587e0d1f481SDong Aisheng 		pkts++;
588e2f1c8cbSMarkus Schneider-Pargmann 		ack_fgi = fgi;
5896355a3c9SMarkus Schneider-Pargmann 		fgi = (++fgi >= cdev->mcfg[MRAM_RXF0].num ? 0 : fgi);
590e0d1f481SDong Aisheng 	}
591e0d1f481SDong Aisheng 
592e2f1c8cbSMarkus Schneider-Pargmann 	if (ack_fgi != -1)
593e2f1c8cbSMarkus Schneider-Pargmann 		m_can_write(cdev, M_CAN_RXF0A, ack_fgi);
594e2f1c8cbSMarkus Schneider-Pargmann 
595e2f1c8cbSMarkus Schneider-Pargmann 	if (err)
596e2f1c8cbSMarkus Schneider-Pargmann 		return err;
597e2f1c8cbSMarkus Schneider-Pargmann 
598e0d1f481SDong Aisheng 	return pkts;
599e0d1f481SDong Aisheng }
600e0d1f481SDong Aisheng 
m_can_handle_lost_msg(struct net_device * dev)601e0d1f481SDong Aisheng static int m_can_handle_lost_msg(struct net_device *dev)
602e0d1f481SDong Aisheng {
6031be37d3bSTorin Cooper-Bennun 	struct m_can_classdev *cdev = netdev_priv(dev);
604e0d1f481SDong Aisheng 	struct net_device_stats *stats = &dev->stats;
605e0d1f481SDong Aisheng 	struct sk_buff *skb;
606e0d1f481SDong Aisheng 	struct can_frame *frame;
6071be37d3bSTorin Cooper-Bennun 	u32 timestamp = 0;
608e0d1f481SDong Aisheng 
609e0d1f481SDong Aisheng 	netdev_err(dev, "msg lost in rxf0\n");
610e0d1f481SDong Aisheng 
611e0d1f481SDong Aisheng 	stats->rx_errors++;
612e0d1f481SDong Aisheng 	stats->rx_over_errors++;
613e0d1f481SDong Aisheng 
614e0d1f481SDong Aisheng 	skb = alloc_can_err_skb(dev, &frame);
615e0d1f481SDong Aisheng 	if (unlikely(!skb))
616e0d1f481SDong Aisheng 		return 0;
617e0d1f481SDong Aisheng 
618e0d1f481SDong Aisheng 	frame->can_id |= CAN_ERR_CRTL;
619e0d1f481SDong Aisheng 	frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
620e0d1f481SDong Aisheng 
6211be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
6221be37d3bSTorin Cooper-Bennun 		timestamp = m_can_get_timestamp(cdev);
6231be37d3bSTorin Cooper-Bennun 
6241be37d3bSTorin Cooper-Bennun 	m_can_receive_skb(cdev, skb, timestamp);
625e0d1f481SDong Aisheng 
626e0d1f481SDong Aisheng 	return 1;
627e0d1f481SDong Aisheng }
628e0d1f481SDong Aisheng 
m_can_handle_lec_err(struct net_device * dev,enum m_can_lec_type lec_type)629e0d1f481SDong Aisheng static int m_can_handle_lec_err(struct net_device *dev,
630e0d1f481SDong Aisheng 				enum m_can_lec_type lec_type)
631e0d1f481SDong Aisheng {
632441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
633e0d1f481SDong Aisheng 	struct net_device_stats *stats = &dev->stats;
634e0d1f481SDong Aisheng 	struct can_frame *cf;
635e0d1f481SDong Aisheng 	struct sk_buff *skb;
6361be37d3bSTorin Cooper-Bennun 	u32 timestamp = 0;
637e0d1f481SDong Aisheng 
638441ac340SDan Murphy 	cdev->can.can_stats.bus_error++;
639e0d1f481SDong Aisheng 
640e0d1f481SDong Aisheng 	/* propagate the error condition to the CAN stack */
641e0d1f481SDong Aisheng 	skb = alloc_can_err_skb(dev, &cf);
642e0d1f481SDong Aisheng 
643e0d1f481SDong Aisheng 	/* check for 'last error code' which tells us the
644e0d1f481SDong Aisheng 	 * type of the last error to occur on the CAN bus
645e0d1f481SDong Aisheng 	 */
646*dce292ffSDario Binacchi 	if (likely(skb))
647e0d1f481SDong Aisheng 		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
648e0d1f481SDong Aisheng 
649e0d1f481SDong Aisheng 	switch (lec_type) {
650e0d1f481SDong Aisheng 	case LEC_STUFF_ERROR:
651e0d1f481SDong Aisheng 		netdev_dbg(dev, "stuff error\n");
652*dce292ffSDario Binacchi 		stats->rx_errors++;
653*dce292ffSDario Binacchi 		if (likely(skb))
654e0d1f481SDong Aisheng 			cf->data[2] |= CAN_ERR_PROT_STUFF;
655e0d1f481SDong Aisheng 		break;
656e0d1f481SDong Aisheng 	case LEC_FORM_ERROR:
657e0d1f481SDong Aisheng 		netdev_dbg(dev, "form error\n");
658*dce292ffSDario Binacchi 		stats->rx_errors++;
659*dce292ffSDario Binacchi 		if (likely(skb))
660e0d1f481SDong Aisheng 			cf->data[2] |= CAN_ERR_PROT_FORM;
661e0d1f481SDong Aisheng 		break;
662e0d1f481SDong Aisheng 	case LEC_ACK_ERROR:
663e0d1f481SDong Aisheng 		netdev_dbg(dev, "ack error\n");
664*dce292ffSDario Binacchi 		stats->tx_errors++;
665*dce292ffSDario Binacchi 		if (likely(skb))
666ffd461f8SOliver Hartkopp 			cf->data[3] = CAN_ERR_PROT_LOC_ACK;
667e0d1f481SDong Aisheng 		break;
668e0d1f481SDong Aisheng 	case LEC_BIT1_ERROR:
669e0d1f481SDong Aisheng 		netdev_dbg(dev, "bit1 error\n");
670*dce292ffSDario Binacchi 		stats->tx_errors++;
671*dce292ffSDario Binacchi 		if (likely(skb))
672e0d1f481SDong Aisheng 			cf->data[2] |= CAN_ERR_PROT_BIT1;
673e0d1f481SDong Aisheng 		break;
674e0d1f481SDong Aisheng 	case LEC_BIT0_ERROR:
675e0d1f481SDong Aisheng 		netdev_dbg(dev, "bit0 error\n");
676*dce292ffSDario Binacchi 		stats->tx_errors++;
677*dce292ffSDario Binacchi 		if (likely(skb))
678e0d1f481SDong Aisheng 			cf->data[2] |= CAN_ERR_PROT_BIT0;
679e0d1f481SDong Aisheng 		break;
680e0d1f481SDong Aisheng 	case LEC_CRC_ERROR:
681e0d1f481SDong Aisheng 		netdev_dbg(dev, "CRC error\n");
682*dce292ffSDario Binacchi 		stats->rx_errors++;
683*dce292ffSDario Binacchi 		if (likely(skb))
684ffd461f8SOliver Hartkopp 			cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
685e0d1f481SDong Aisheng 		break;
686e0d1f481SDong Aisheng 	default:
687e0d1f481SDong Aisheng 		break;
688e0d1f481SDong Aisheng 	}
689e0d1f481SDong Aisheng 
690*dce292ffSDario Binacchi 	if (unlikely(!skb))
691*dce292ffSDario Binacchi 		return 0;
692*dce292ffSDario Binacchi 
6931be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
6941be37d3bSTorin Cooper-Bennun 		timestamp = m_can_get_timestamp(cdev);
6951be37d3bSTorin Cooper-Bennun 
6961be37d3bSTorin Cooper-Bennun 	m_can_receive_skb(cdev, skb, timestamp);
697e0d1f481SDong Aisheng 
698e0d1f481SDong Aisheng 	return 1;
699e0d1f481SDong Aisheng }
700e0d1f481SDong Aisheng 
__m_can_get_berr_counter(const struct net_device * dev,struct can_berr_counter * bec)701f6a99649SDong Aisheng static int __m_can_get_berr_counter(const struct net_device *dev,
702e0d1f481SDong Aisheng 				    struct can_berr_counter *bec)
703e0d1f481SDong Aisheng {
704441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
705e0d1f481SDong Aisheng 	unsigned int ecr;
706f6a99649SDong Aisheng 
707441ac340SDan Murphy 	ecr = m_can_read(cdev, M_CAN_ECR);
70820779943STorin Cooper-Bennun 	bec->rxerr = FIELD_GET(ECR_REC_MASK, ecr);
70920779943STorin Cooper-Bennun 	bec->txerr = FIELD_GET(ECR_TEC_MASK, ecr);
710f6a99649SDong Aisheng 
711f6a99649SDong Aisheng 	return 0;
712f6a99649SDong Aisheng }
713f6a99649SDong Aisheng 
m_can_clk_start(struct m_can_classdev * cdev)714441ac340SDan Murphy static int m_can_clk_start(struct m_can_classdev *cdev)
715f6a99649SDong Aisheng {
716441ac340SDan Murphy 	if (cdev->pm_clock_support == 0)
717f524f829SDan Murphy 		return 0;
718f524f829SDan Murphy 
719b8d62555SMarc Kleine-Budde 	return pm_runtime_resume_and_get(cdev->dev);
7201675bee3SFaiz Abbas }
7211675bee3SFaiz Abbas 
m_can_clk_stop(struct m_can_classdev * cdev)722441ac340SDan Murphy static void m_can_clk_stop(struct m_can_classdev *cdev)
723ef7b8aa8SQuentin Schulz {
724441ac340SDan Murphy 	if (cdev->pm_clock_support)
725441ac340SDan Murphy 		pm_runtime_put_sync(cdev->dev);
726ef7b8aa8SQuentin Schulz }
727ef7b8aa8SQuentin Schulz 
m_can_get_berr_counter(const struct net_device * dev,struct can_berr_counter * bec)728ef7b8aa8SQuentin Schulz static int m_can_get_berr_counter(const struct net_device *dev,
729ef7b8aa8SQuentin Schulz 				  struct can_berr_counter *bec)
730ef7b8aa8SQuentin Schulz {
731441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
732ef7b8aa8SQuentin Schulz 	int err;
733ef7b8aa8SQuentin Schulz 
734441ac340SDan Murphy 	err = m_can_clk_start(cdev);
735ef7b8aa8SQuentin Schulz 	if (err)
736ef7b8aa8SQuentin Schulz 		return err;
737ef7b8aa8SQuentin Schulz 
738ef7b8aa8SQuentin Schulz 	__m_can_get_berr_counter(dev, bec);
739ef7b8aa8SQuentin Schulz 
740441ac340SDan Murphy 	m_can_clk_stop(cdev);
741e0d1f481SDong Aisheng 
742e0d1f481SDong Aisheng 	return 0;
743e0d1f481SDong Aisheng }
744e0d1f481SDong Aisheng 
m_can_handle_state_change(struct net_device * dev,enum can_state new_state)745e0d1f481SDong Aisheng static int m_can_handle_state_change(struct net_device *dev,
746e0d1f481SDong Aisheng 				     enum can_state new_state)
747e0d1f481SDong Aisheng {
748441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
749e0d1f481SDong Aisheng 	struct can_frame *cf;
750e0d1f481SDong Aisheng 	struct sk_buff *skb;
751e0d1f481SDong Aisheng 	struct can_berr_counter bec;
752e0d1f481SDong Aisheng 	unsigned int ecr;
7531be37d3bSTorin Cooper-Bennun 	u32 timestamp = 0;
754e0d1f481SDong Aisheng 
755e0d1f481SDong Aisheng 	switch (new_state) {
756cd0d83eaSWu Bo 	case CAN_STATE_ERROR_WARNING:
757e0d1f481SDong Aisheng 		/* error warning state */
758441ac340SDan Murphy 		cdev->can.can_stats.error_warning++;
759441ac340SDan Murphy 		cdev->can.state = CAN_STATE_ERROR_WARNING;
760e0d1f481SDong Aisheng 		break;
761e0d1f481SDong Aisheng 	case CAN_STATE_ERROR_PASSIVE:
762e0d1f481SDong Aisheng 		/* error passive state */
763441ac340SDan Murphy 		cdev->can.can_stats.error_passive++;
764441ac340SDan Murphy 		cdev->can.state = CAN_STATE_ERROR_PASSIVE;
765e0d1f481SDong Aisheng 		break;
766e0d1f481SDong Aisheng 	case CAN_STATE_BUS_OFF:
767e0d1f481SDong Aisheng 		/* bus-off state */
768441ac340SDan Murphy 		cdev->can.state = CAN_STATE_BUS_OFF;
769441ac340SDan Murphy 		m_can_disable_all_interrupts(cdev);
770441ac340SDan Murphy 		cdev->can.can_stats.bus_off++;
771e0d1f481SDong Aisheng 		can_bus_off(dev);
772e0d1f481SDong Aisheng 		break;
773e0d1f481SDong Aisheng 	default:
774e0d1f481SDong Aisheng 		break;
775e0d1f481SDong Aisheng 	}
776e0d1f481SDong Aisheng 
777e0d1f481SDong Aisheng 	/* propagate the error condition to the CAN stack */
778e0d1f481SDong Aisheng 	skb = alloc_can_err_skb(dev, &cf);
779e0d1f481SDong Aisheng 	if (unlikely(!skb))
780e0d1f481SDong Aisheng 		return 0;
781e0d1f481SDong Aisheng 
782f6a99649SDong Aisheng 	__m_can_get_berr_counter(dev, &bec);
783e0d1f481SDong Aisheng 
784e0d1f481SDong Aisheng 	switch (new_state) {
785cd0d83eaSWu Bo 	case CAN_STATE_ERROR_WARNING:
786e0d1f481SDong Aisheng 		/* error warning state */
7873e5c291cSVincent Mailhol 		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
788e0d1f481SDong Aisheng 		cf->data[1] = (bec.txerr > bec.rxerr) ?
789e0d1f481SDong Aisheng 			CAN_ERR_CRTL_TX_WARNING :
790e0d1f481SDong Aisheng 			CAN_ERR_CRTL_RX_WARNING;
791e0d1f481SDong Aisheng 		cf->data[6] = bec.txerr;
792e0d1f481SDong Aisheng 		cf->data[7] = bec.rxerr;
793e0d1f481SDong Aisheng 		break;
794e0d1f481SDong Aisheng 	case CAN_STATE_ERROR_PASSIVE:
795e0d1f481SDong Aisheng 		/* error passive state */
7963e5c291cSVincent Mailhol 		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
797441ac340SDan Murphy 		ecr = m_can_read(cdev, M_CAN_ECR);
798e0d1f481SDong Aisheng 		if (ecr & ECR_RP)
799e0d1f481SDong Aisheng 			cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
800e0d1f481SDong Aisheng 		if (bec.txerr > 127)
801e0d1f481SDong Aisheng 			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
802e0d1f481SDong Aisheng 		cf->data[6] = bec.txerr;
803e0d1f481SDong Aisheng 		cf->data[7] = bec.rxerr;
804e0d1f481SDong Aisheng 		break;
805e0d1f481SDong Aisheng 	case CAN_STATE_BUS_OFF:
806e0d1f481SDong Aisheng 		/* bus-off state */
807e0d1f481SDong Aisheng 		cf->can_id |= CAN_ERR_BUSOFF;
808e0d1f481SDong Aisheng 		break;
809e0d1f481SDong Aisheng 	default:
810e0d1f481SDong Aisheng 		break;
811e0d1f481SDong Aisheng 	}
812e0d1f481SDong Aisheng 
8131be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
8141be37d3bSTorin Cooper-Bennun 		timestamp = m_can_get_timestamp(cdev);
8151be37d3bSTorin Cooper-Bennun 
8161be37d3bSTorin Cooper-Bennun 	m_can_receive_skb(cdev, skb, timestamp);
817e0d1f481SDong Aisheng 
818e0d1f481SDong Aisheng 	return 1;
819e0d1f481SDong Aisheng }
820e0d1f481SDong Aisheng 
m_can_handle_state_errors(struct net_device * dev,u32 psr)821e0d1f481SDong Aisheng static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
822e0d1f481SDong Aisheng {
823441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
824e0d1f481SDong Aisheng 	int work_done = 0;
825e0d1f481SDong Aisheng 
826441ac340SDan Murphy 	if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) {
827e0d1f481SDong Aisheng 		netdev_dbg(dev, "entered error warning state\n");
828e0d1f481SDong Aisheng 		work_done += m_can_handle_state_change(dev,
829e0d1f481SDong Aisheng 						       CAN_STATE_ERROR_WARNING);
830e0d1f481SDong Aisheng 	}
831e0d1f481SDong Aisheng 
832441ac340SDan Murphy 	if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) {
833a93f5caeSDong Aisheng 		netdev_dbg(dev, "entered error passive state\n");
834e0d1f481SDong Aisheng 		work_done += m_can_handle_state_change(dev,
835e0d1f481SDong Aisheng 						       CAN_STATE_ERROR_PASSIVE);
836e0d1f481SDong Aisheng 	}
837e0d1f481SDong Aisheng 
838441ac340SDan Murphy 	if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) {
839a93f5caeSDong Aisheng 		netdev_dbg(dev, "entered error bus off state\n");
840e0d1f481SDong Aisheng 		work_done += m_can_handle_state_change(dev,
841e0d1f481SDong Aisheng 						       CAN_STATE_BUS_OFF);
842e0d1f481SDong Aisheng 	}
843e0d1f481SDong Aisheng 
844e0d1f481SDong Aisheng 	return work_done;
845e0d1f481SDong Aisheng }
846e0d1f481SDong Aisheng 
m_can_handle_other_err(struct net_device * dev,u32 irqstatus)847e0d1f481SDong Aisheng static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
848e0d1f481SDong Aisheng {
849e0d1f481SDong Aisheng 	if (irqstatus & IR_WDI)
850e0d1f481SDong Aisheng 		netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
851e0d1f481SDong Aisheng 	if (irqstatus & IR_BEU)
852e0d1f481SDong Aisheng 		netdev_err(dev, "Bit Error Uncorrected\n");
853e0d1f481SDong Aisheng 	if (irqstatus & IR_BEC)
854e0d1f481SDong Aisheng 		netdev_err(dev, "Bit Error Corrected\n");
855e0d1f481SDong Aisheng 	if (irqstatus & IR_TOO)
856e0d1f481SDong Aisheng 		netdev_err(dev, "Timeout reached\n");
857e0d1f481SDong Aisheng 	if (irqstatus & IR_MRAF)
858e0d1f481SDong Aisheng 		netdev_err(dev, "Message RAM access failure occurred\n");
859e0d1f481SDong Aisheng }
860e0d1f481SDong Aisheng 
is_lec_err(u8 lec)8616a8836e3SMarc Kleine-Budde static inline bool is_lec_err(u8 lec)
862e0d1f481SDong Aisheng {
8636a8836e3SMarc Kleine-Budde 	return lec != LEC_NO_ERROR && lec != LEC_NO_CHANGE;
864e0d1f481SDong Aisheng }
865e0d1f481SDong Aisheng 
m_can_is_protocol_err(u32 irqstatus)8666b43a265SPankaj Sharma static inline bool m_can_is_protocol_err(u32 irqstatus)
8676b43a265SPankaj Sharma {
8686b43a265SPankaj Sharma 	return irqstatus & IR_ERR_LEC_31X;
8696b43a265SPankaj Sharma }
8706b43a265SPankaj Sharma 
m_can_handle_protocol_error(struct net_device * dev,u32 irqstatus)8716b43a265SPankaj Sharma static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
8726b43a265SPankaj Sharma {
8736b43a265SPankaj Sharma 	struct net_device_stats *stats = &dev->stats;
8746b43a265SPankaj Sharma 	struct m_can_classdev *cdev = netdev_priv(dev);
8756b43a265SPankaj Sharma 	struct can_frame *cf;
8766b43a265SPankaj Sharma 	struct sk_buff *skb;
8771be37d3bSTorin Cooper-Bennun 	u32 timestamp = 0;
8786b43a265SPankaj Sharma 
8796b43a265SPankaj Sharma 	/* propagate the error condition to the CAN stack */
8806b43a265SPankaj Sharma 	skb = alloc_can_err_skb(dev, &cf);
8816b43a265SPankaj Sharma 
8826b43a265SPankaj Sharma 	/* update tx error stats since there is protocol error */
8836b43a265SPankaj Sharma 	stats->tx_errors++;
8846b43a265SPankaj Sharma 
8856b43a265SPankaj Sharma 	/* update arbitration lost status */
8866b43a265SPankaj Sharma 	if (cdev->version >= 31 && (irqstatus & IR_PEA)) {
8876b43a265SPankaj Sharma 		netdev_dbg(dev, "Protocol error in Arbitration fail\n");
8886b43a265SPankaj Sharma 		cdev->can.can_stats.arbitration_lost++;
8896b43a265SPankaj Sharma 		if (skb) {
8906b43a265SPankaj Sharma 			cf->can_id |= CAN_ERR_LOSTARB;
8916b43a265SPankaj Sharma 			cf->data[0] |= CAN_ERR_LOSTARB_UNSPEC;
8926b43a265SPankaj Sharma 		}
8936b43a265SPankaj Sharma 	}
8946b43a265SPankaj Sharma 
8956b43a265SPankaj Sharma 	if (unlikely(!skb)) {
8966b43a265SPankaj Sharma 		netdev_dbg(dev, "allocation of skb failed\n");
8976b43a265SPankaj Sharma 		return 0;
8986b43a265SPankaj Sharma 	}
8991be37d3bSTorin Cooper-Bennun 
9001be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
9011be37d3bSTorin Cooper-Bennun 		timestamp = m_can_get_timestamp(cdev);
9021be37d3bSTorin Cooper-Bennun 
9031be37d3bSTorin Cooper-Bennun 	m_can_receive_skb(cdev, skb, timestamp);
9046b43a265SPankaj Sharma 
9056b43a265SPankaj Sharma 	return 1;
9066b43a265SPankaj Sharma }
9076b43a265SPankaj Sharma 
m_can_handle_bus_errors(struct net_device * dev,u32 irqstatus,u32 psr)908e0d1f481SDong Aisheng static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
909e0d1f481SDong Aisheng 				   u32 psr)
910e0d1f481SDong Aisheng {
911441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
912e0d1f481SDong Aisheng 	int work_done = 0;
913e0d1f481SDong Aisheng 
914e0d1f481SDong Aisheng 	if (irqstatus & IR_RF0L)
915e0d1f481SDong Aisheng 		work_done += m_can_handle_lost_msg(dev);
916e0d1f481SDong Aisheng 
917e0d1f481SDong Aisheng 	/* handle lec errors on the bus */
9186a8836e3SMarc Kleine-Budde 	if (cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
9196a8836e3SMarc Kleine-Budde 		u8 lec = FIELD_GET(PSR_LEC_MASK, psr);
920f5071d9eSVivek Yadav 		u8 dlec = FIELD_GET(PSR_DLEC_MASK, psr);
9216a8836e3SMarc Kleine-Budde 
922f5071d9eSVivek Yadav 		if (is_lec_err(lec)) {
923f5071d9eSVivek Yadav 			netdev_dbg(dev, "Arbitration phase error detected\n");
9246a8836e3SMarc Kleine-Budde 			work_done += m_can_handle_lec_err(dev, lec);
9256a8836e3SMarc Kleine-Budde 		}
926e0d1f481SDong Aisheng 
927f5071d9eSVivek Yadav 		if (is_lec_err(dlec)) {
928f5071d9eSVivek Yadav 			netdev_dbg(dev, "Data phase error detected\n");
929f5071d9eSVivek Yadav 			work_done += m_can_handle_lec_err(dev, dlec);
930f5071d9eSVivek Yadav 		}
931f5071d9eSVivek Yadav 	}
932f5071d9eSVivek Yadav 
9336b43a265SPankaj Sharma 	/* handle protocol errors in arbitration phase */
9346b43a265SPankaj Sharma 	if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
9356b43a265SPankaj Sharma 	    m_can_is_protocol_err(irqstatus))
9366b43a265SPankaj Sharma 		work_done += m_can_handle_protocol_error(dev, irqstatus);
9376b43a265SPankaj Sharma 
938e0d1f481SDong Aisheng 	/* other unproccessed error interrupts */
939e0d1f481SDong Aisheng 	m_can_handle_other_err(dev, irqstatus);
940e0d1f481SDong Aisheng 
941e0d1f481SDong Aisheng 	return work_done;
942e0d1f481SDong Aisheng }
943e0d1f481SDong Aisheng 
m_can_rx_handler(struct net_device * dev,int quota,u32 irqstatus)94457757937SMarkus Schneider-Pargmann static int m_can_rx_handler(struct net_device *dev, int quota, u32 irqstatus)
945e0d1f481SDong Aisheng {
946441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
947e3938177SMatt Kline 	int rx_work_or_err;
948e0d1f481SDong Aisheng 	int work_done = 0;
949e0d1f481SDong Aisheng 
950e0d1f481SDong Aisheng 	if (!irqstatus)
951e0d1f481SDong Aisheng 		goto end;
952e0d1f481SDong Aisheng 
9533e82f2f3SEugen Hristev 	/* Errata workaround for issue "Needless activation of MRAF irq"
9543e82f2f3SEugen Hristev 	 * During frame reception while the MCAN is in Error Passive state
9553e82f2f3SEugen Hristev 	 * and the Receive Error Counter has the value MCAN_ECR.REC = 127,
9563e82f2f3SEugen Hristev 	 * it may happen that MCAN_IR.MRAF is set although there was no
9573e82f2f3SEugen Hristev 	 * Message RAM access failure.
9583e82f2f3SEugen Hristev 	 * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated
9593e82f2f3SEugen Hristev 	 * The Message RAM Access Failure interrupt routine needs to check
9603e82f2f3SEugen Hristev 	 * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127.
9613e82f2f3SEugen Hristev 	 * In this case, reset MCAN_IR.MRAF. No further action is required.
9623e82f2f3SEugen Hristev 	 */
963441ac340SDan Murphy 	if (cdev->version <= 31 && irqstatus & IR_MRAF &&
964441ac340SDan Murphy 	    m_can_read(cdev, M_CAN_ECR) & ECR_RP) {
9653e82f2f3SEugen Hristev 		struct can_berr_counter bec;
9663e82f2f3SEugen Hristev 
9673e82f2f3SEugen Hristev 		__m_can_get_berr_counter(dev, &bec);
9683e82f2f3SEugen Hristev 		if (bec.rxerr == 127) {
969441ac340SDan Murphy 			m_can_write(cdev, M_CAN_IR, IR_MRAF);
9703e82f2f3SEugen Hristev 			irqstatus &= ~IR_MRAF;
9713e82f2f3SEugen Hristev 		}
9723e82f2f3SEugen Hristev 	}
9733e82f2f3SEugen Hristev 
974e0d1f481SDong Aisheng 	if (irqstatus & IR_ERR_STATE)
975fac52bf7SMarkus Schneider-Pargmann 		work_done += m_can_handle_state_errors(dev,
976fac52bf7SMarkus Schneider-Pargmann 						       m_can_read(cdev, M_CAN_PSR));
977e0d1f481SDong Aisheng 
9785e1bd15aSMario Huettel 	if (irqstatus & IR_ERR_BUS_30X)
979fac52bf7SMarkus Schneider-Pargmann 		work_done += m_can_handle_bus_errors(dev, irqstatus,
980fac52bf7SMarkus Schneider-Pargmann 						     m_can_read(cdev, M_CAN_PSR));
981e0d1f481SDong Aisheng 
982e3938177SMatt Kline 	if (irqstatus & IR_RF0N) {
983e3938177SMatt Kline 		rx_work_or_err = m_can_do_rx_poll(dev, (quota - work_done));
984e3938177SMatt Kline 		if (rx_work_or_err < 0)
985e3938177SMatt Kline 			return rx_work_or_err;
986e3938177SMatt Kline 
987e3938177SMatt Kline 		work_done += rx_work_or_err;
988e3938177SMatt Kline 	}
989f524f829SDan Murphy end:
990f524f829SDan Murphy 	return work_done;
991f524f829SDan Murphy }
992e0d1f481SDong Aisheng 
m_can_rx_peripheral(struct net_device * dev,u32 irqstatus)99357757937SMarkus Schneider-Pargmann static int m_can_rx_peripheral(struct net_device *dev, u32 irqstatus)
994f524f829SDan Murphy {
995441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
996e3938177SMatt Kline 	int work_done;
997f524f829SDan Murphy 
99857757937SMarkus Schneider-Pargmann 	work_done = m_can_rx_handler(dev, NAPI_POLL_WEIGHT, irqstatus);
999f524f829SDan Murphy 
1000e3938177SMatt Kline 	/* Don't re-enable interrupts if the driver had a fatal error
1001e3938177SMatt Kline 	 * (e.g., FIFO read failure).
1002e3938177SMatt Kline 	 */
10039083e0b0SMarkus Schneider-Pargmann 	if (work_done < 0)
10049083e0b0SMarkus Schneider-Pargmann 		m_can_disable_all_interrupts(cdev);
1005f524f829SDan Murphy 
1006e3938177SMatt Kline 	return work_done;
1007f524f829SDan Murphy }
1008f524f829SDan Murphy 
m_can_poll(struct napi_struct * napi,int quota)1009f524f829SDan Murphy static int m_can_poll(struct napi_struct *napi, int quota)
1010f524f829SDan Murphy {
1011f524f829SDan Murphy 	struct net_device *dev = napi->dev;
1012441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1013f524f829SDan Murphy 	int work_done;
101457757937SMarkus Schneider-Pargmann 	u32 irqstatus;
1015f524f829SDan Murphy 
101657757937SMarkus Schneider-Pargmann 	irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR);
101757757937SMarkus Schneider-Pargmann 
101857757937SMarkus Schneider-Pargmann 	work_done = m_can_rx_handler(dev, quota, irqstatus);
1019e3938177SMatt Kline 
1020e3938177SMatt Kline 	/* Don't re-enable interrupts if the driver had a fatal error
1021e3938177SMatt Kline 	 * (e.g., FIFO read failure).
1022e3938177SMatt Kline 	 */
1023e3938177SMatt Kline 	if (work_done >= 0 && work_done < quota) {
10246ad20165SEric Dumazet 		napi_complete_done(napi, work_done);
1025441ac340SDan Murphy 		m_can_enable_all_interrupts(cdev);
1026e0d1f481SDong Aisheng 	}
1027e0d1f481SDong Aisheng 
1028e0d1f481SDong Aisheng 	return work_done;
1029e0d1f481SDong Aisheng }
1030e0d1f481SDong Aisheng 
10311be37d3bSTorin Cooper-Bennun /* Echo tx skb and update net stats. Peripherals use rx-offload for
10321be37d3bSTorin Cooper-Bennun  * echo. timestamp is used for peripherals to ensure correct ordering
10331be37d3bSTorin Cooper-Bennun  * by rx-offload, and is ignored for non-peripherals.
10341be37d3bSTorin Cooper-Bennun  */
m_can_tx_update_stats(struct m_can_classdev * cdev,unsigned int msg_mark,u32 timestamp)10351be37d3bSTorin Cooper-Bennun static void m_can_tx_update_stats(struct m_can_classdev *cdev,
10361be37d3bSTorin Cooper-Bennun 				  unsigned int msg_mark,
10371be37d3bSTorin Cooper-Bennun 				  u32 timestamp)
10381be37d3bSTorin Cooper-Bennun {
10391be37d3bSTorin Cooper-Bennun 	struct net_device *dev = cdev->net;
10401be37d3bSTorin Cooper-Bennun 	struct net_device_stats *stats = &dev->stats;
10411be37d3bSTorin Cooper-Bennun 
10421be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
10431be37d3bSTorin Cooper-Bennun 		stats->tx_bytes +=
10442e3df4a3SMarc Kleine-Budde 			can_rx_offload_get_echo_skb_queue_timestamp(&cdev->offload,
10451be37d3bSTorin Cooper-Bennun 								    msg_mark,
10461be37d3bSTorin Cooper-Bennun 								    timestamp,
10471be37d3bSTorin Cooper-Bennun 								    NULL);
10481be37d3bSTorin Cooper-Bennun 	else
10491be37d3bSTorin Cooper-Bennun 		stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
10501be37d3bSTorin Cooper-Bennun 
10511be37d3bSTorin Cooper-Bennun 	stats->tx_packets++;
10521be37d3bSTorin Cooper-Bennun }
10531be37d3bSTorin Cooper-Bennun 
m_can_echo_tx_event(struct net_device * dev)1054e3938177SMatt Kline static int m_can_echo_tx_event(struct net_device *dev)
105510c1c397SMario Huettel {
105610c1c397SMario Huettel 	u32 txe_count = 0;
105710c1c397SMario Huettel 	u32 m_can_txefs;
105810c1c397SMario Huettel 	u32 fgi = 0;
1059e3bff525SMarkus Schneider-Pargmann 	int ack_fgi = -1;
106010c1c397SMario Huettel 	int i = 0;
1061e3bff525SMarkus Schneider-Pargmann 	int err = 0;
106210c1c397SMario Huettel 	unsigned int msg_mark;
106310c1c397SMario Huettel 
1064441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
106510c1c397SMario Huettel 
106610c1c397SMario Huettel 	/* read tx event fifo status */
1067441ac340SDan Murphy 	m_can_txefs = m_can_read(cdev, M_CAN_TXEFS);
106810c1c397SMario Huettel 
106910c1c397SMario Huettel 	/* Get Tx Event fifo element count */
107020779943STorin Cooper-Bennun 	txe_count = FIELD_GET(TXEFS_EFFL_MASK, m_can_txefs);
1071d4535b90SMarkus Schneider-Pargmann 	fgi = FIELD_GET(TXEFS_EFGI_MASK, m_can_txefs);
107210c1c397SMario Huettel 
107310c1c397SMario Huettel 	/* Get and process all sent elements */
107410c1c397SMario Huettel 	for (i = 0; i < txe_count; i++) {
10751be37d3bSTorin Cooper-Bennun 		u32 txe, timestamp = 0;
10761be37d3bSTorin Cooper-Bennun 
10771be37d3bSTorin Cooper-Bennun 		/* get message marker, timestamp */
1078e3938177SMatt Kline 		err = m_can_txe_fifo_read(cdev, fgi, 4, &txe);
1079e3938177SMatt Kline 		if (err) {
1080e3938177SMatt Kline 			netdev_err(dev, "TXE FIFO read returned %d\n", err);
1081e3bff525SMarkus Schneider-Pargmann 			break;
1082e3938177SMatt Kline 		}
1083e3938177SMatt Kline 
108420779943STorin Cooper-Bennun 		msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
10854c333369SMarc Kleine-Budde 		timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
108610c1c397SMario Huettel 
1087e3bff525SMarkus Schneider-Pargmann 		ack_fgi = fgi;
1088d4535b90SMarkus Schneider-Pargmann 		fgi = (++fgi >= cdev->mcfg[MRAM_TXE].num ? 0 : fgi);
108910c1c397SMario Huettel 
109010c1c397SMario Huettel 		/* update stats */
10911be37d3bSTorin Cooper-Bennun 		m_can_tx_update_stats(cdev, msg_mark, timestamp);
109210c1c397SMario Huettel 	}
1093e3938177SMatt Kline 
1094e3bff525SMarkus Schneider-Pargmann 	if (ack_fgi != -1)
1095e3bff525SMarkus Schneider-Pargmann 		m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
1096e3bff525SMarkus Schneider-Pargmann 							  ack_fgi));
1097e3bff525SMarkus Schneider-Pargmann 
1098e3bff525SMarkus Schneider-Pargmann 	return err;
109910c1c397SMario Huettel }
110010c1c397SMario Huettel 
m_can_isr(int irq,void * dev_id)1101e0d1f481SDong Aisheng static irqreturn_t m_can_isr(int irq, void *dev_id)
1102e0d1f481SDong Aisheng {
1103e0d1f481SDong Aisheng 	struct net_device *dev = (struct net_device *)dev_id;
1104441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1105e0d1f481SDong Aisheng 	u32 ir;
1106e0d1f481SDong Aisheng 
1107a1f63446SJarkko Nikula 	if (pm_runtime_suspended(cdev->dev))
1108a1f63446SJarkko Nikula 		return IRQ_NONE;
1109441ac340SDan Murphy 	ir = m_can_read(cdev, M_CAN_IR);
1110e0d1f481SDong Aisheng 	if (!ir)
1111e0d1f481SDong Aisheng 		return IRQ_NONE;
1112e0d1f481SDong Aisheng 
1113e0d1f481SDong Aisheng 	/* ACK all irqs */
1114441ac340SDan Murphy 	m_can_write(cdev, M_CAN_IR, ir);
1115e0d1f481SDong Aisheng 
1116441ac340SDan Murphy 	if (cdev->ops->clear_interrupts)
1117441ac340SDan Murphy 		cdev->ops->clear_interrupts(cdev);
1118f524f829SDan Murphy 
1119e0d1f481SDong Aisheng 	/* schedule NAPI in case of
1120e0d1f481SDong Aisheng 	 * - rx IRQ
1121e0d1f481SDong Aisheng 	 * - state change IRQ
1122e0d1f481SDong Aisheng 	 * - bus error IRQ and bus error reporting
1123e0d1f481SDong Aisheng 	 */
11245e1bd15aSMario Huettel 	if ((ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) {
1125441ac340SDan Murphy 		cdev->irqstatus = ir;
11269083e0b0SMarkus Schneider-Pargmann 		if (!cdev->is_peripheral) {
1127441ac340SDan Murphy 			m_can_disable_all_interrupts(cdev);
1128441ac340SDan Murphy 			napi_schedule(&cdev->napi);
11299083e0b0SMarkus Schneider-Pargmann 		} else if (m_can_rx_peripheral(dev, ir) < 0) {
1130e3938177SMatt Kline 			goto out_fail;
1131e0d1f481SDong Aisheng 		}
11329083e0b0SMarkus Schneider-Pargmann 	}
1133e0d1f481SDong Aisheng 
1134441ac340SDan Murphy 	if (cdev->version == 30) {
1135e0d1f481SDong Aisheng 		if (ir & IR_TC) {
113610c1c397SMario Huettel 			/* Transmission Complete Interrupt*/
11371be37d3bSTorin Cooper-Bennun 			u32 timestamp = 0;
11381be37d3bSTorin Cooper-Bennun 
11391be37d3bSTorin Cooper-Bennun 			if (cdev->is_peripheral)
11401be37d3bSTorin Cooper-Bennun 				timestamp = m_can_get_timestamp(cdev);
11411be37d3bSTorin Cooper-Bennun 			m_can_tx_update_stats(cdev, 0, timestamp);
1142e0d1f481SDong Aisheng 			netif_wake_queue(dev);
1143e0d1f481SDong Aisheng 		}
114410c1c397SMario Huettel 	} else  {
114510c1c397SMario Huettel 		if (ir & IR_TEFN) {
114610c1c397SMario Huettel 			/* New TX FIFO Element arrived */
1147e3938177SMatt Kline 			if (m_can_echo_tx_event(dev) != 0)
1148e3938177SMatt Kline 				goto out_fail;
1149e3938177SMatt Kline 
115010c1c397SMario Huettel 			if (netif_queue_stopped(dev) &&
1151441ac340SDan Murphy 			    !m_can_tx_fifo_full(cdev))
115210c1c397SMario Huettel 				netif_wake_queue(dev);
115310c1c397SMario Huettel 		}
115410c1c397SMario Huettel 	}
1155e0d1f481SDong Aisheng 
1156c757096eSMarc Kleine-Budde 	if (cdev->is_peripheral)
115730bfec4fSMarc Kleine-Budde 		can_rx_offload_threaded_irq_finish(&cdev->offload);
1158c757096eSMarc Kleine-Budde 
1159e0d1f481SDong Aisheng 	return IRQ_HANDLED;
1160e3938177SMatt Kline 
1161e3938177SMatt Kline out_fail:
1162e3938177SMatt Kline 	m_can_disable_all_interrupts(cdev);
1163e3938177SMatt Kline 	return IRQ_HANDLED;
1164e0d1f481SDong Aisheng }
1165e0d1f481SDong Aisheng 
1166b03cfc5bSMario Huettel static const struct can_bittiming_const m_can_bittiming_const_30X = {
1167e0d1f481SDong Aisheng 	.name = KBUILD_MODNAME,
1168e0d1f481SDong Aisheng 	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
1169e0d1f481SDong Aisheng 	.tseg1_max = 64,
1170e0d1f481SDong Aisheng 	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
1171e0d1f481SDong Aisheng 	.tseg2_max = 16,
1172e0d1f481SDong Aisheng 	.sjw_max = 16,
1173e0d1f481SDong Aisheng 	.brp_min = 1,
1174e0d1f481SDong Aisheng 	.brp_max = 1024,
1175e0d1f481SDong Aisheng 	.brp_inc = 1,
1176e0d1f481SDong Aisheng };
1177e0d1f481SDong Aisheng 
1178b03cfc5bSMario Huettel static const struct can_bittiming_const m_can_data_bittiming_const_30X = {
117980646733SDong Aisheng 	.name = KBUILD_MODNAME,
118080646733SDong Aisheng 	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
118180646733SDong Aisheng 	.tseg1_max = 16,
118280646733SDong Aisheng 	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
118380646733SDong Aisheng 	.tseg2_max = 8,
118480646733SDong Aisheng 	.sjw_max = 4,
118580646733SDong Aisheng 	.brp_min = 1,
118680646733SDong Aisheng 	.brp_max = 32,
118780646733SDong Aisheng 	.brp_inc = 1,
118880646733SDong Aisheng };
118980646733SDong Aisheng 
1190b03cfc5bSMario Huettel static const struct can_bittiming_const m_can_bittiming_const_31X = {
1191b03cfc5bSMario Huettel 	.name = KBUILD_MODNAME,
1192b03cfc5bSMario Huettel 	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
1193b03cfc5bSMario Huettel 	.tseg1_max = 256,
1194e3409e41SMarc Kleine-Budde 	.tseg2_min = 2,		/* Time segment 2 = phase_seg2 */
1195b03cfc5bSMario Huettel 	.tseg2_max = 128,
1196b03cfc5bSMario Huettel 	.sjw_max = 128,
1197b03cfc5bSMario Huettel 	.brp_min = 1,
1198b03cfc5bSMario Huettel 	.brp_max = 512,
1199b03cfc5bSMario Huettel 	.brp_inc = 1,
1200b03cfc5bSMario Huettel };
1201b03cfc5bSMario Huettel 
1202b03cfc5bSMario Huettel static const struct can_bittiming_const m_can_data_bittiming_const_31X = {
1203b03cfc5bSMario Huettel 	.name = KBUILD_MODNAME,
1204b03cfc5bSMario Huettel 	.tseg1_min = 1,		/* Time segment 1 = prop_seg + phase_seg1 */
1205b03cfc5bSMario Huettel 	.tseg1_max = 32,
1206b03cfc5bSMario Huettel 	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
1207b03cfc5bSMario Huettel 	.tseg2_max = 16,
1208b03cfc5bSMario Huettel 	.sjw_max = 16,
1209b03cfc5bSMario Huettel 	.brp_min = 1,
1210b03cfc5bSMario Huettel 	.brp_max = 32,
1211b03cfc5bSMario Huettel 	.brp_inc = 1,
1212b03cfc5bSMario Huettel };
1213b03cfc5bSMario Huettel 
m_can_set_bittiming(struct net_device * dev)1214e0d1f481SDong Aisheng static int m_can_set_bittiming(struct net_device *dev)
1215e0d1f481SDong Aisheng {
1216441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1217441ac340SDan Murphy 	const struct can_bittiming *bt = &cdev->can.bittiming;
1218441ac340SDan Murphy 	const struct can_bittiming *dbt = &cdev->can.data_bittiming;
1219e0d1f481SDong Aisheng 	u16 brp, sjw, tseg1, tseg2;
1220e0d1f481SDong Aisheng 	u32 reg_btp;
1221e0d1f481SDong Aisheng 
1222e0d1f481SDong Aisheng 	brp = bt->brp - 1;
1223e0d1f481SDong Aisheng 	sjw = bt->sjw - 1;
1224e0d1f481SDong Aisheng 	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
1225e0d1f481SDong Aisheng 	tseg2 = bt->phase_seg2 - 1;
122620779943STorin Cooper-Bennun 	reg_btp = FIELD_PREP(NBTP_NBRP_MASK, brp) |
122720779943STorin Cooper-Bennun 		  FIELD_PREP(NBTP_NSJW_MASK, sjw) |
122820779943STorin Cooper-Bennun 		  FIELD_PREP(NBTP_NTSEG1_MASK, tseg1) |
122920779943STorin Cooper-Bennun 		  FIELD_PREP(NBTP_NTSEG2_MASK, tseg2);
1230441ac340SDan Murphy 	m_can_write(cdev, M_CAN_NBTP, reg_btp);
123180646733SDong Aisheng 
1232441ac340SDan Murphy 	if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
1233e759c626SFranklin S Cooper Jr 		reg_btp = 0;
123480646733SDong Aisheng 		brp = dbt->brp - 1;
123580646733SDong Aisheng 		sjw = dbt->sjw - 1;
123680646733SDong Aisheng 		tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
123780646733SDong Aisheng 		tseg2 = dbt->phase_seg2 - 1;
1238e759c626SFranklin S Cooper Jr 
1239e759c626SFranklin S Cooper Jr 		/* TDC is only needed for bitrates beyond 2.5 MBit/s.
1240e759c626SFranklin S Cooper Jr 		 * This is mentioned in the "Bit Time Requirements for CAN FD"
1241e759c626SFranklin S Cooper Jr 		 * paper presented at the International CAN Conference 2013
1242e759c626SFranklin S Cooper Jr 		 */
1243e759c626SFranklin S Cooper Jr 		if (dbt->bitrate > 2500000) {
1244e759c626SFranklin S Cooper Jr 			u32 tdco, ssp;
1245e759c626SFranklin S Cooper Jr 
1246e759c626SFranklin S Cooper Jr 			/* Use the same value of secondary sampling point
1247e759c626SFranklin S Cooper Jr 			 * as the data sampling point
1248e759c626SFranklin S Cooper Jr 			 */
1249e759c626SFranklin S Cooper Jr 			ssp = dbt->sample_point;
1250e759c626SFranklin S Cooper Jr 
1251e759c626SFranklin S Cooper Jr 			/* Equation based on Bosch's M_CAN User Manual's
1252e759c626SFranklin S Cooper Jr 			 * Transmitter Delay Compensation Section
1253e759c626SFranklin S Cooper Jr 			 */
1254441ac340SDan Murphy 			tdco = (cdev->can.clock.freq / 1000) *
1255e759c626SFranklin S Cooper Jr 				ssp / dbt->bitrate;
1256e759c626SFranklin S Cooper Jr 
1257e759c626SFranklin S Cooper Jr 			/* Max valid TDCO value is 127 */
1258e759c626SFranklin S Cooper Jr 			if (tdco > 127) {
1259e759c626SFranklin S Cooper Jr 				netdev_warn(dev, "TDCO value of %u is beyond maximum. Using maximum possible value\n",
1260e759c626SFranklin S Cooper Jr 					    tdco);
1261e759c626SFranklin S Cooper Jr 				tdco = 127;
1262e759c626SFranklin S Cooper Jr 			}
1263e759c626SFranklin S Cooper Jr 
1264e759c626SFranklin S Cooper Jr 			reg_btp |= DBTP_TDC;
1265441ac340SDan Murphy 			m_can_write(cdev, M_CAN_TDCR,
126620779943STorin Cooper-Bennun 				    FIELD_PREP(TDCR_TDCO_MASK, tdco));
1267e759c626SFranklin S Cooper Jr 		}
1268e759c626SFranklin S Cooper Jr 
1269aae32b78SHussein Alasadi 		reg_btp |= FIELD_PREP(DBTP_DBRP_MASK, brp) |
1270aae32b78SHussein Alasadi 			FIELD_PREP(DBTP_DSJW_MASK, sjw) |
1271aae32b78SHussein Alasadi 			FIELD_PREP(DBTP_DTSEG1_MASK, tseg1) |
1272aae32b78SHussein Alasadi 			FIELD_PREP(DBTP_DTSEG2_MASK, tseg2);
1273e759c626SFranklin S Cooper Jr 
1274441ac340SDan Murphy 		m_can_write(cdev, M_CAN_DBTP, reg_btp);
127580646733SDong Aisheng 	}
1276e0d1f481SDong Aisheng 
1277e0d1f481SDong Aisheng 	return 0;
1278e0d1f481SDong Aisheng }
1279e0d1f481SDong Aisheng 
1280e0d1f481SDong Aisheng /* Configure M_CAN chip:
1281e0d1f481SDong Aisheng  * - set rx buffer/fifo element size
1282e0d1f481SDong Aisheng  * - configure rx fifo
1283e0d1f481SDong Aisheng  * - accept non-matching frame into fifo 0
1284e0d1f481SDong Aisheng  * - configure tx buffer
1285428479e4SMario Huettel  *		- >= v3.1.x: TX FIFO is used
1286e0d1f481SDong Aisheng  * - configure mode
1287e0d1f481SDong Aisheng  * - setup bittiming
1288df06fd67STorin Cooper-Bennun  * - configure timestamp generation
1289e0d1f481SDong Aisheng  */
m_can_chip_config(struct net_device * dev)1290eaacfeacSVivek Yadav static int m_can_chip_config(struct net_device *dev)
1291e0d1f481SDong Aisheng {
1292441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1293897e6632SMarkus Schneider-Pargmann 	u32 interrupts = IR_ALL_INT;
1294e0d1f481SDong Aisheng 	u32 cccr, test;
1295eaacfeacSVivek Yadav 	int err;
1296eaacfeacSVivek Yadav 
1297eaacfeacSVivek Yadav 	err = m_can_init_ram(cdev);
1298eaacfeacSVivek Yadav 	if (err) {
1299eaacfeacSVivek Yadav 		dev_err(cdev->dev, "Message RAM configuration failed\n");
1300eaacfeacSVivek Yadav 		return err;
1301eaacfeacSVivek Yadav 	}
1302e0d1f481SDong Aisheng 
1303897e6632SMarkus Schneider-Pargmann 	/* Disable unused interrupts */
1304897e6632SMarkus Schneider-Pargmann 	interrupts &= ~(IR_ARA | IR_ELO | IR_DRX | IR_TEFF | IR_TEFW | IR_TFE |
1305897e6632SMarkus Schneider-Pargmann 			IR_TCF | IR_HPM | IR_RF1F | IR_RF1W | IR_RF1N |
1306897e6632SMarkus Schneider-Pargmann 			IR_RF0F | IR_RF0W);
1307897e6632SMarkus Schneider-Pargmann 
1308441ac340SDan Murphy 	m_can_config_endisable(cdev, true);
1309e0d1f481SDong Aisheng 
131080646733SDong Aisheng 	/* RX Buffer/FIFO Element Size 64 bytes data field */
13110f315716STorin Cooper-Bennun 	m_can_write(cdev, M_CAN_RXESC,
13120f315716STorin Cooper-Bennun 		    FIELD_PREP(RXESC_RBDS_MASK, RXESC_64B) |
13130f315716STorin Cooper-Bennun 		    FIELD_PREP(RXESC_F1DS_MASK, RXESC_64B) |
13140f315716STorin Cooper-Bennun 		    FIELD_PREP(RXESC_F0DS_MASK, RXESC_64B));
1315e0d1f481SDong Aisheng 
1316e0d1f481SDong Aisheng 	/* Accept Non-matching Frames Into FIFO 0 */
1317441ac340SDan Murphy 	m_can_write(cdev, M_CAN_GFC, 0x0);
1318e0d1f481SDong Aisheng 
1319441ac340SDan Murphy 	if (cdev->version == 30) {
1320e0d1f481SDong Aisheng 		/* only support one Tx Buffer currently */
132120779943STorin Cooper-Bennun 		m_can_write(cdev, M_CAN_TXBC, FIELD_PREP(TXBC_NDTB_MASK, 1) |
1322441ac340SDan Murphy 			    cdev->mcfg[MRAM_TXB].off);
1323428479e4SMario Huettel 	} else {
1324428479e4SMario Huettel 		/* TX FIFO is used for newer IP Core versions */
1325441ac340SDan Murphy 		m_can_write(cdev, M_CAN_TXBC,
132620779943STorin Cooper-Bennun 			    FIELD_PREP(TXBC_TFQS_MASK,
132720779943STorin Cooper-Bennun 				       cdev->mcfg[MRAM_TXB].num) |
132820779943STorin Cooper-Bennun 			    cdev->mcfg[MRAM_TXB].off);
1329428479e4SMario Huettel 	}
1330e0d1f481SDong Aisheng 
133180646733SDong Aisheng 	/* support 64 bytes payload */
13320f315716STorin Cooper-Bennun 	m_can_write(cdev, M_CAN_TXESC,
13330f315716STorin Cooper-Bennun 		    FIELD_PREP(TXESC_TBDS_MASK, TXESC_TBDS_64B));
1334e0d1f481SDong Aisheng 
1335428479e4SMario Huettel 	/* TX Event FIFO */
1336441ac340SDan Murphy 	if (cdev->version == 30) {
133720779943STorin Cooper-Bennun 		m_can_write(cdev, M_CAN_TXEFC,
133820779943STorin Cooper-Bennun 			    FIELD_PREP(TXEFC_EFS_MASK, 1) |
1339441ac340SDan Murphy 			    cdev->mcfg[MRAM_TXE].off);
1340428479e4SMario Huettel 	} else {
1341428479e4SMario Huettel 		/* Full TX Event FIFO is used */
1342441ac340SDan Murphy 		m_can_write(cdev, M_CAN_TXEFC,
134320779943STorin Cooper-Bennun 			    FIELD_PREP(TXEFC_EFS_MASK,
134420779943STorin Cooper-Bennun 				       cdev->mcfg[MRAM_TXE].num) |
1345441ac340SDan Murphy 			    cdev->mcfg[MRAM_TXE].off);
1346428479e4SMario Huettel 	}
1347e0d1f481SDong Aisheng 
1348e0d1f481SDong Aisheng 	/* rx fifo configuration, blocking mode, fifo size 1 */
1349441ac340SDan Murphy 	m_can_write(cdev, M_CAN_RXF0C,
135020779943STorin Cooper-Bennun 		    FIELD_PREP(RXFC_FS_MASK, cdev->mcfg[MRAM_RXF0].num) |
1351441ac340SDan Murphy 		    cdev->mcfg[MRAM_RXF0].off);
1352e0d1f481SDong Aisheng 
1353441ac340SDan Murphy 	m_can_write(cdev, M_CAN_RXF1C,
135420779943STorin Cooper-Bennun 		    FIELD_PREP(RXFC_FS_MASK, cdev->mcfg[MRAM_RXF1].num) |
1355441ac340SDan Murphy 		    cdev->mcfg[MRAM_RXF1].off);
1356e0d1f481SDong Aisheng 
1357441ac340SDan Murphy 	cccr = m_can_read(cdev, M_CAN_CCCR);
1358441ac340SDan Murphy 	test = m_can_read(cdev, M_CAN_TEST);
1359e0d1f481SDong Aisheng 	test &= ~TEST_LBCK;
1360441ac340SDan Murphy 	if (cdev->version == 30) {
1361b03cfc5bSMario Huettel 		/* Version 3.0.x */
1362e0d1f481SDong Aisheng 
1363fb7d6a81SPankaj Sharma 		cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR |
136420779943STorin Cooper-Bennun 			  FIELD_PREP(CCCR_CMR_MASK, FIELD_MAX(CCCR_CMR_MASK)) |
136520779943STorin Cooper-Bennun 			  FIELD_PREP(CCCR_CME_MASK, FIELD_MAX(CCCR_CME_MASK)));
1366e0d1f481SDong Aisheng 
1367441ac340SDan Murphy 		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
136820779943STorin Cooper-Bennun 			cccr |= FIELD_PREP(CCCR_CME_MASK, CCCR_CME_CANFD_BRS);
136980646733SDong Aisheng 
1370b03cfc5bSMario Huettel 	} else {
1371b03cfc5bSMario Huettel 		/* Version 3.1.x or 3.2.x */
1372393753b2SRoman Fietze 		cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
1373fb7d6a81SPankaj Sharma 			  CCCR_NISO | CCCR_DAR);
1374b03cfc5bSMario Huettel 
1375b03cfc5bSMario Huettel 		/* Only 3.2.x has NISO Bit implemented */
1376441ac340SDan Murphy 		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
1377b03cfc5bSMario Huettel 			cccr |= CCCR_NISO;
1378b03cfc5bSMario Huettel 
1379441ac340SDan Murphy 		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
1380b03cfc5bSMario Huettel 			cccr |= (CCCR_BRSE | CCCR_FDOE);
1381b03cfc5bSMario Huettel 	}
1382b03cfc5bSMario Huettel 
1383b03cfc5bSMario Huettel 	/* Loopback Mode */
1384441ac340SDan Murphy 	if (cdev->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
1385b03cfc5bSMario Huettel 		cccr |= CCCR_TEST | CCCR_MON;
1386b03cfc5bSMario Huettel 		test |= TEST_LBCK;
1387b03cfc5bSMario Huettel 	}
1388b03cfc5bSMario Huettel 
1389b03cfc5bSMario Huettel 	/* Enable Monitoring (all versions) */
1390441ac340SDan Murphy 	if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
1391b03cfc5bSMario Huettel 		cccr |= CCCR_MON;
1392b03cfc5bSMario Huettel 
1393fb7d6a81SPankaj Sharma 	/* Disable Auto Retransmission (all versions) */
1394fb7d6a81SPankaj Sharma 	if (cdev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
1395fb7d6a81SPankaj Sharma 		cccr |= CCCR_DAR;
1396fb7d6a81SPankaj Sharma 
1397b03cfc5bSMario Huettel 	/* Write config */
1398441ac340SDan Murphy 	m_can_write(cdev, M_CAN_CCCR, cccr);
1399441ac340SDan Murphy 	m_can_write(cdev, M_CAN_TEST, test);
1400e0d1f481SDong Aisheng 
1401b03cfc5bSMario Huettel 	/* Enable interrupts */
1402897e6632SMarkus Schneider-Pargmann 	if (!(cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) {
1403441ac340SDan Murphy 		if (cdev->version == 30)
1404897e6632SMarkus Schneider-Pargmann 			interrupts &= ~(IR_ERR_LEC_30X);
1405b03cfc5bSMario Huettel 		else
1406897e6632SMarkus Schneider-Pargmann 			interrupts &= ~(IR_ERR_LEC_31X);
1407897e6632SMarkus Schneider-Pargmann 	}
1408897e6632SMarkus Schneider-Pargmann 	m_can_write(cdev, M_CAN_IE, interrupts);
1409e0d1f481SDong Aisheng 
1410e0d1f481SDong Aisheng 	/* route all interrupts to INT0 */
1411441ac340SDan Murphy 	m_can_write(cdev, M_CAN_ILS, ILS_ALL_INT0);
1412e0d1f481SDong Aisheng 
1413e0d1f481SDong Aisheng 	/* set bittiming params */
1414e0d1f481SDong Aisheng 	m_can_set_bittiming(dev);
1415e0d1f481SDong Aisheng 
1416c38fb531SMarc Kleine-Budde 	/* enable internal timestamp generation, with a prescaler of 16. The
1417c38fb531SMarc Kleine-Budde 	 * prescaler is applied to the nominal bit timing
14185020ced4SMarc Kleine-Budde 	 */
14195b12933dSMarc Kleine-Budde 	m_can_write(cdev, M_CAN_TSCC,
14205b12933dSMarc Kleine-Budde 		    FIELD_PREP(TSCC_TCP_MASK, 0xf) |
14215b12933dSMarc Kleine-Budde 		    FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
1422df06fd67STorin Cooper-Bennun 
1423441ac340SDan Murphy 	m_can_config_endisable(cdev, false);
1424f524f829SDan Murphy 
1425441ac340SDan Murphy 	if (cdev->ops->init)
1426441ac340SDan Murphy 		cdev->ops->init(cdev);
1427eaacfeacSVivek Yadav 
1428eaacfeacSVivek Yadav 	return 0;
1429e0d1f481SDong Aisheng }
1430e0d1f481SDong Aisheng 
m_can_start(struct net_device * dev)1431eaacfeacSVivek Yadav static int m_can_start(struct net_device *dev)
1432e0d1f481SDong Aisheng {
1433441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1434eaacfeacSVivek Yadav 	int ret;
1435e0d1f481SDong Aisheng 
1436e0d1f481SDong Aisheng 	/* basic m_can configuration */
1437eaacfeacSVivek Yadav 	ret = m_can_chip_config(dev);
1438eaacfeacSVivek Yadav 	if (ret)
1439eaacfeacSVivek Yadav 		return ret;
1440e0d1f481SDong Aisheng 
1441441ac340SDan Murphy 	cdev->can.state = CAN_STATE_ERROR_ACTIVE;
1442e0d1f481SDong Aisheng 
1443441ac340SDan Murphy 	m_can_enable_all_interrupts(cdev);
1444eaacfeacSVivek Yadav 
1445eaacfeacSVivek Yadav 	return 0;
1446e0d1f481SDong Aisheng }
1447e0d1f481SDong Aisheng 
m_can_set_mode(struct net_device * dev,enum can_mode mode)1448e0d1f481SDong Aisheng static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
1449e0d1f481SDong Aisheng {
1450e0d1f481SDong Aisheng 	switch (mode) {
1451e0d1f481SDong Aisheng 	case CAN_MODE_START:
1452f524f829SDan Murphy 		m_can_clean(dev);
1453e0d1f481SDong Aisheng 		m_can_start(dev);
1454e0d1f481SDong Aisheng 		netif_wake_queue(dev);
1455e0d1f481SDong Aisheng 		break;
1456e0d1f481SDong Aisheng 	default:
1457e0d1f481SDong Aisheng 		return -EOPNOTSUPP;
1458e0d1f481SDong Aisheng 	}
1459e0d1f481SDong Aisheng 
1460e0d1f481SDong Aisheng 	return 0;
1461e0d1f481SDong Aisheng }
1462e0d1f481SDong Aisheng 
1463b03cfc5bSMario Huettel /* Checks core release number of M_CAN
1464b03cfc5bSMario Huettel  * returns 0 if an unsupported device is detected
1465b03cfc5bSMario Huettel  * else it returns the release and step coded as:
1466b03cfc5bSMario Huettel  * return value = 10 * <release> + 1 * <step>
1467b03cfc5bSMario Huettel  */
m_can_check_core_release(struct m_can_classdev * cdev)1468441ac340SDan Murphy static int m_can_check_core_release(struct m_can_classdev *cdev)
1469b03cfc5bSMario Huettel {
1470b03cfc5bSMario Huettel 	u32 crel_reg;
1471b03cfc5bSMario Huettel 	u8 rel;
1472b03cfc5bSMario Huettel 	u8 step;
1473b03cfc5bSMario Huettel 	int res;
1474b03cfc5bSMario Huettel 
1475b03cfc5bSMario Huettel 	/* Read Core Release Version and split into version number
1476b03cfc5bSMario Huettel 	 * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1;
1477b03cfc5bSMario Huettel 	 */
1478441ac340SDan Murphy 	crel_reg = m_can_read(cdev, M_CAN_CREL);
147920779943STorin Cooper-Bennun 	rel = (u8)FIELD_GET(CREL_REL_MASK, crel_reg);
148020779943STorin Cooper-Bennun 	step = (u8)FIELD_GET(CREL_STEP_MASK, crel_reg);
1481b03cfc5bSMario Huettel 
1482b03cfc5bSMario Huettel 	if (rel == 3) {
1483b03cfc5bSMario Huettel 		/* M_CAN v3.x.y: create return value */
1484b03cfc5bSMario Huettel 		res = 30 + step;
1485b03cfc5bSMario Huettel 	} else {
1486b03cfc5bSMario Huettel 		/* Unsupported M_CAN version */
1487b03cfc5bSMario Huettel 		res = 0;
1488b03cfc5bSMario Huettel 	}
1489b03cfc5bSMario Huettel 
1490b03cfc5bSMario Huettel 	return res;
1491b03cfc5bSMario Huettel }
1492b03cfc5bSMario Huettel 
1493b03cfc5bSMario Huettel /* Selectable Non ISO support only in version 3.2.x
1494b03cfc5bSMario Huettel  * This function checks if the bit is writable.
1495b03cfc5bSMario Huettel  */
m_can_niso_supported(struct m_can_classdev * cdev)1496441ac340SDan Murphy static bool m_can_niso_supported(struct m_can_classdev *cdev)
1497b03cfc5bSMario Huettel {
1498f524f829SDan Murphy 	u32 cccr_reg, cccr_poll = 0;
1499f524f829SDan Murphy 	int niso_timeout = -ETIMEDOUT;
1500f524f829SDan Murphy 	int i;
1501b03cfc5bSMario Huettel 
1502441ac340SDan Murphy 	m_can_config_endisable(cdev, true);
1503441ac340SDan Murphy 	cccr_reg = m_can_read(cdev, M_CAN_CCCR);
1504b03cfc5bSMario Huettel 	cccr_reg |= CCCR_NISO;
1505441ac340SDan Murphy 	m_can_write(cdev, M_CAN_CCCR, cccr_reg);
1506b03cfc5bSMario Huettel 
1507f524f829SDan Murphy 	for (i = 0; i <= 10; i++) {
1508441ac340SDan Murphy 		cccr_poll = m_can_read(cdev, M_CAN_CCCR);
1509f524f829SDan Murphy 		if (cccr_poll == cccr_reg) {
1510f524f829SDan Murphy 			niso_timeout = 0;
1511f524f829SDan Murphy 			break;
1512f524f829SDan Murphy 		}
1513f524f829SDan Murphy 
1514f524f829SDan Murphy 		usleep_range(1, 5);
1515f524f829SDan Murphy 	}
1516b03cfc5bSMario Huettel 
1517b03cfc5bSMario Huettel 	/* Clear NISO */
1518b03cfc5bSMario Huettel 	cccr_reg &= ~(CCCR_NISO);
1519441ac340SDan Murphy 	m_can_write(cdev, M_CAN_CCCR, cccr_reg);
1520b03cfc5bSMario Huettel 
1521441ac340SDan Murphy 	m_can_config_endisable(cdev, false);
1522b03cfc5bSMario Huettel 
1523b03cfc5bSMario Huettel 	/* return false if time out (-ETIMEDOUT), else return true */
1524b03cfc5bSMario Huettel 	return !niso_timeout;
1525b03cfc5bSMario Huettel }
1526b03cfc5bSMario Huettel 
m_can_dev_setup(struct m_can_classdev * cdev)15273b464affSMarc Kleine-Budde static int m_can_dev_setup(struct m_can_classdev *cdev)
1528e0d1f481SDong Aisheng {
15293b464affSMarc Kleine-Budde 	struct net_device *dev = cdev->net;
15307d4a101cSVincent Mailhol 	int m_can_version, err;
1531e0d1f481SDong Aisheng 
15323b464affSMarc Kleine-Budde 	m_can_version = m_can_check_core_release(cdev);
1533b03cfc5bSMario Huettel 	/* return if unsupported version */
1534b03cfc5bSMario Huettel 	if (!m_can_version) {
15353b464affSMarc Kleine-Budde 		dev_err(cdev->dev, "Unsupported version number: %2d",
15365e520eddSFaiz Abbas 			m_can_version);
15375e520eddSFaiz Abbas 		return -EINVAL;
1538b03cfc5bSMario Huettel 	}
1539e0d1f481SDong Aisheng 
15403b464affSMarc Kleine-Budde 	if (!cdev->is_peripheral)
1541b48b89f9SJakub Kicinski 		netif_napi_add(dev, &cdev->napi, m_can_poll);
1542e0d1f481SDong Aisheng 
1543b03cfc5bSMario Huettel 	/* Shared properties of all M_CAN versions */
15443b464affSMarc Kleine-Budde 	cdev->version = m_can_version;
15453b464affSMarc Kleine-Budde 	cdev->can.do_set_mode = m_can_set_mode;
15463b464affSMarc Kleine-Budde 	cdev->can.do_get_berr_counter = m_can_get_berr_counter;
15476cfda7fbSOliver Hartkopp 
1548b03cfc5bSMario Huettel 	/* Set M_CAN supported operations */
15493b464affSMarc Kleine-Budde 	cdev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
1550e0d1f481SDong Aisheng 		CAN_CTRLMODE_LISTENONLY |
155180646733SDong Aisheng 		CAN_CTRLMODE_BERR_REPORTING |
1552fb7d6a81SPankaj Sharma 		CAN_CTRLMODE_FD |
1553fb7d6a81SPankaj Sharma 		CAN_CTRLMODE_ONE_SHOT;
1554e0d1f481SDong Aisheng 
1555b03cfc5bSMario Huettel 	/* Set properties depending on M_CAN version */
15563b464affSMarc Kleine-Budde 	switch (cdev->version) {
1557b03cfc5bSMario Huettel 	case 30:
1558b03cfc5bSMario Huettel 		/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
15597d4a101cSVincent Mailhol 		err = can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
15607d4a101cSVincent Mailhol 		if (err)
15617d4a101cSVincent Mailhol 			return err;
1562d6da7881SJarkko Nikula 		cdev->can.bittiming_const = &m_can_bittiming_const_30X;
1563d6da7881SJarkko Nikula 		cdev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;
1564b03cfc5bSMario Huettel 		break;
1565b03cfc5bSMario Huettel 	case 31:
1566b03cfc5bSMario Huettel 		/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
15677d4a101cSVincent Mailhol 		err = can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
15687d4a101cSVincent Mailhol 		if (err)
15697d4a101cSVincent Mailhol 			return err;
1570d6da7881SJarkko Nikula 		cdev->can.bittiming_const = &m_can_bittiming_const_31X;
1571d6da7881SJarkko Nikula 		cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
1572b03cfc5bSMario Huettel 		break;
1573b03cfc5bSMario Huettel 	case 32:
15745c7d55bdSPankaj Sharma 	case 33:
15755c7d55bdSPankaj Sharma 		/* Support both MCAN version v3.2.x and v3.3.0 */
1576d6da7881SJarkko Nikula 		cdev->can.bittiming_const = &m_can_bittiming_const_31X;
1577d6da7881SJarkko Nikula 		cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
1578f524f829SDan Murphy 
15793b464affSMarc Kleine-Budde 		cdev->can.ctrlmode_supported |=
15803b464affSMarc Kleine-Budde 			(m_can_niso_supported(cdev) ?
1581709efa6fSMarc Kleine-Budde 			 CAN_CTRLMODE_FD_NON_ISO : 0);
1582b03cfc5bSMario Huettel 		break;
1583b03cfc5bSMario Huettel 	default:
15843b464affSMarc Kleine-Budde 		dev_err(cdev->dev, "Unsupported version number: %2d",
15853b464affSMarc Kleine-Budde 			cdev->version);
15865e520eddSFaiz Abbas 		return -EINVAL;
1587b03cfc5bSMario Huettel 	}
1588b03cfc5bSMario Huettel 
15893b464affSMarc Kleine-Budde 	if (cdev->ops->init)
15903b464affSMarc Kleine-Budde 		cdev->ops->init(cdev);
1591e0d1f481SDong Aisheng 
1592e0d1f481SDong Aisheng 	return 0;
1593e0d1f481SDong Aisheng }
1594e0d1f481SDong Aisheng 
m_can_stop(struct net_device * dev)1595e0d1f481SDong Aisheng static void m_can_stop(struct net_device *dev)
1596e0d1f481SDong Aisheng {
1597441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1598e0d1f481SDong Aisheng 
1599e0d1f481SDong Aisheng 	/* disable all interrupts */
1600441ac340SDan Murphy 	m_can_disable_all_interrupts(cdev);
1601e0d1f481SDong Aisheng 
1602a584e9bcSFaiz Abbas 	/* Set init mode to disengage from the network */
1603a584e9bcSFaiz Abbas 	m_can_config_endisable(cdev, true);
1604a584e9bcSFaiz Abbas 
1605e0d1f481SDong Aisheng 	/* set the state as STOPPED */
1606441ac340SDan Murphy 	cdev->can.state = CAN_STATE_STOPPED;
1607e0d1f481SDong Aisheng }
1608e0d1f481SDong Aisheng 
m_can_close(struct net_device * dev)1609e0d1f481SDong Aisheng static int m_can_close(struct net_device *dev)
1610e0d1f481SDong Aisheng {
1611441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1612e0d1f481SDong Aisheng 
1613e0d1f481SDong Aisheng 	netif_stop_queue(dev);
1614441ac340SDan Murphy 
1615e0d1f481SDong Aisheng 	m_can_stop(dev);
161689d8048dSMarc Kleine-Budde 	if (dev->irq)
1617e0d1f481SDong Aisheng 		free_irq(dev->irq, dev);
1618f524f829SDan Murphy 
1619441ac340SDan Murphy 	if (cdev->is_peripheral) {
1620441ac340SDan Murphy 		cdev->tx_skb = NULL;
1621441ac340SDan Murphy 		destroy_workqueue(cdev->tx_wq);
1622441ac340SDan Murphy 		cdev->tx_wq = NULL;
16231be37d3bSTorin Cooper-Bennun 		can_rx_offload_disable(&cdev->offload);
16247fb4f560SJake Hamby 	} else {
16257fb4f560SJake Hamby 		napi_disable(&cdev->napi);
162673042934SMarkus Schneider-Pargmann 	}
16271be37d3bSTorin Cooper-Bennun 
1628e0d1f481SDong Aisheng 	close_candev(dev);
1629e0d1f481SDong Aisheng 
1630d7572187SMarc Kleine-Budde 	m_can_clk_stop(cdev);
1631d836cb5fSFaiz Abbas 	phy_power_off(cdev->transceiver);
1632d836cb5fSFaiz Abbas 
1633e0d1f481SDong Aisheng 	return 0;
1634e0d1f481SDong Aisheng }
1635e0d1f481SDong Aisheng 
m_can_next_echo_skb_occupied(struct net_device * dev,int putidx)163610c1c397SMario Huettel static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)
163710c1c397SMario Huettel {
1638441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
163910c1c397SMario Huettel 	/*get wrap around for loopback skb index */
1640441ac340SDan Murphy 	unsigned int wrap = cdev->can.echo_skb_max;
164110c1c397SMario Huettel 	int next_idx;
164210c1c397SMario Huettel 
164310c1c397SMario Huettel 	/* calculate next index */
164410c1c397SMario Huettel 	next_idx = (++putidx >= wrap ? 0 : putidx);
164510c1c397SMario Huettel 
164610c1c397SMario Huettel 	/* check if occupied */
1647441ac340SDan Murphy 	return !!cdev->can.echo_skb[next_idx];
164810c1c397SMario Huettel }
164910c1c397SMario Huettel 
m_can_tx_handler(struct m_can_classdev * cdev)1650441ac340SDan Murphy static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
1651e0d1f481SDong Aisheng {
1652441ac340SDan Murphy 	struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data;
1653441ac340SDan Murphy 	struct net_device *dev = cdev->net;
1654441ac340SDan Murphy 	struct sk_buff *skb = cdev->tx_skb;
1655812270e5SMatt Kline 	struct id_and_dlc fifo_header;
1656812270e5SMatt Kline 	u32 cccr, fdflags;
1657c1eaf8b9SMarkus Schneider-Pargmann 	u32 txfqs;
1658812270e5SMatt Kline 	int err;
165910c1c397SMario Huettel 	int putidx;
1660e0d1f481SDong Aisheng 
1661e04b2cfeSMarc Kleine-Budde 	cdev->tx_skb = NULL;
1662e04b2cfeSMarc Kleine-Budde 
166310c1c397SMario Huettel 	/* Generate ID field for TX buffer Element */
166410c1c397SMario Huettel 	/* Common to all supported M_CAN versions */
1665e0d1f481SDong Aisheng 	if (cf->can_id & CAN_EFF_FLAG) {
1666812270e5SMatt Kline 		fifo_header.id = cf->can_id & CAN_EFF_MASK;
1667812270e5SMatt Kline 		fifo_header.id |= TX_BUF_XTD;
1668e0d1f481SDong Aisheng 	} else {
1669812270e5SMatt Kline 		fifo_header.id = ((cf->can_id & CAN_SFF_MASK) << 18);
1670e0d1f481SDong Aisheng 	}
1671e0d1f481SDong Aisheng 
1672e0d1f481SDong Aisheng 	if (cf->can_id & CAN_RTR_FLAG)
1673812270e5SMatt Kline 		fifo_header.id |= TX_BUF_RTR;
1674e0d1f481SDong Aisheng 
1675441ac340SDan Murphy 	if (cdev->version == 30) {
167610c1c397SMario Huettel 		netif_stop_queue(dev);
167710c1c397SMario Huettel 
1678812270e5SMatt Kline 		fifo_header.dlc = can_fd_len2dlc(cf->len) << 16;
1679812270e5SMatt Kline 
1680812270e5SMatt Kline 		/* Write the frame ID, DLC, and payload to the FIFO element. */
1681812270e5SMatt Kline 		err = m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, &fifo_header, 2);
1682e3938177SMatt Kline 		if (err)
1683e3938177SMatt Kline 			goto out_fail;
168480646733SDong Aisheng 
1685812270e5SMatt Kline 		err = m_can_fifo_write(cdev, 0, M_CAN_FIFO_DATA,
1686812270e5SMatt Kline 				       cf->data, DIV_ROUND_UP(cf->len, 4));
1687e3938177SMatt Kline 		if (err)
1688e3938177SMatt Kline 			goto out_fail;
1689e3938177SMatt Kline 
1690441ac340SDan Murphy 		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
1691441ac340SDan Murphy 			cccr = m_can_read(cdev, M_CAN_CCCR);
169220779943STorin Cooper-Bennun 			cccr &= ~CCCR_CMR_MASK;
169380646733SDong Aisheng 			if (can_is_canfd_skb(skb)) {
169480646733SDong Aisheng 				if (cf->flags & CANFD_BRS)
169520779943STorin Cooper-Bennun 					cccr |= FIELD_PREP(CCCR_CMR_MASK,
169620779943STorin Cooper-Bennun 							   CCCR_CMR_CANFD_BRS);
169780646733SDong Aisheng 				else
169820779943STorin Cooper-Bennun 					cccr |= FIELD_PREP(CCCR_CMR_MASK,
169920779943STorin Cooper-Bennun 							   CCCR_CMR_CANFD);
170080646733SDong Aisheng 			} else {
170120779943STorin Cooper-Bennun 				cccr |= FIELD_PREP(CCCR_CMR_MASK, CCCR_CMR_CAN);
170280646733SDong Aisheng 			}
1703441ac340SDan Murphy 			m_can_write(cdev, M_CAN_CCCR, cccr);
170480646733SDong Aisheng 		}
1705441ac340SDan Murphy 		m_can_write(cdev, M_CAN_TXBTIE, 0x1);
17062e8e79c4SMarc Kleine-Budde 
17072e8e79c4SMarc Kleine-Budde 		can_put_echo_skb(skb, dev, 0, 0);
17082e8e79c4SMarc Kleine-Budde 
1709441ac340SDan Murphy 		m_can_write(cdev, M_CAN_TXBAR, 0x1);
171010c1c397SMario Huettel 		/* End of xmit function for version 3.0.x */
171110c1c397SMario Huettel 	} else {
171210c1c397SMario Huettel 		/* Transmit routine for version >= v3.1.x */
171310c1c397SMario Huettel 
1714c1eaf8b9SMarkus Schneider-Pargmann 		txfqs = m_can_read(cdev, M_CAN_TXFQS);
1715c1eaf8b9SMarkus Schneider-Pargmann 
171610c1c397SMario Huettel 		/* Check if FIFO full */
1717c1eaf8b9SMarkus Schneider-Pargmann 		if (_m_can_tx_fifo_full(txfqs)) {
171810c1c397SMario Huettel 			/* This shouldn't happen */
171910c1c397SMario Huettel 			netif_stop_queue(dev);
172010c1c397SMario Huettel 			netdev_warn(dev,
172110c1c397SMario Huettel 				    "TX queue active although FIFO is full.");
1722441ac340SDan Murphy 
1723441ac340SDan Murphy 			if (cdev->is_peripheral) {
1724f524f829SDan Murphy 				kfree_skb(skb);
1725f524f829SDan Murphy 				dev->stats.tx_dropped++;
1726f524f829SDan Murphy 				return NETDEV_TX_OK;
1727f524f829SDan Murphy 			} else {
172810c1c397SMario Huettel 				return NETDEV_TX_BUSY;
172910c1c397SMario Huettel 			}
1730f524f829SDan Murphy 		}
173110c1c397SMario Huettel 
173210c1c397SMario Huettel 		/* get put index for frame */
1733c1eaf8b9SMarkus Schneider-Pargmann 		putidx = FIELD_GET(TXFQS_TFQPI_MASK, txfqs);
1734812270e5SMatt Kline 
1735812270e5SMatt Kline 		/* Construct DLC Field, with CAN-FD configuration.
1736812270e5SMatt Kline 		 * Use the put index of the fifo as the message marker,
1737812270e5SMatt Kline 		 * used in the TX interrupt for sending the correct echo frame.
1738812270e5SMatt Kline 		 */
173910c1c397SMario Huettel 
174010c1c397SMario Huettel 		/* get CAN FD configuration of frame */
174110c1c397SMario Huettel 		fdflags = 0;
174210c1c397SMario Huettel 		if (can_is_canfd_skb(skb)) {
174310c1c397SMario Huettel 			fdflags |= TX_BUF_FDF;
174410c1c397SMario Huettel 			if (cf->flags & CANFD_BRS)
174510c1c397SMario Huettel 				fdflags |= TX_BUF_BRS;
174610c1c397SMario Huettel 		}
174710c1c397SMario Huettel 
1748812270e5SMatt Kline 		fifo_header.dlc = FIELD_PREP(TX_BUF_MM_MASK, putidx) |
1749e3938177SMatt Kline 			FIELD_PREP(TX_BUF_DLC_MASK, can_fd_len2dlc(cf->len)) |
1750e3938177SMatt Kline 			fdflags | TX_BUF_EFC;
1751812270e5SMatt Kline 		err = m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, &fifo_header, 2);
1752e3938177SMatt Kline 		if (err)
1753e3938177SMatt Kline 			goto out_fail;
175410c1c397SMario Huettel 
1755812270e5SMatt Kline 		err = m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DATA,
1756812270e5SMatt Kline 				       cf->data, DIV_ROUND_UP(cf->len, 4));
1757e3938177SMatt Kline 		if (err)
1758e3938177SMatt Kline 			goto out_fail;
175910c1c397SMario Huettel 
176010c1c397SMario Huettel 		/* Push loopback echo.
176110c1c397SMario Huettel 		 * Will be looped back on TX interrupt based on message marker
176210c1c397SMario Huettel 		 */
17631dcb6e57SVincent Mailhol 		can_put_echo_skb(skb, dev, putidx, 0);
176410c1c397SMario Huettel 
176510c1c397SMario Huettel 		/* Enable TX FIFO element to start transfer  */
1766441ac340SDan Murphy 		m_can_write(cdev, M_CAN_TXBAR, (1 << putidx));
176710c1c397SMario Huettel 
176810c1c397SMario Huettel 		/* stop network queue if fifo full */
1769441ac340SDan Murphy 		if (m_can_tx_fifo_full(cdev) ||
177010c1c397SMario Huettel 		    m_can_next_echo_skb_occupied(dev, putidx))
177110c1c397SMario Huettel 			netif_stop_queue(dev);
177210c1c397SMario Huettel 	}
1773e0d1f481SDong Aisheng 
1774e0d1f481SDong Aisheng 	return NETDEV_TX_OK;
1775e3938177SMatt Kline 
1776e3938177SMatt Kline out_fail:
1777e3938177SMatt Kline 	netdev_err(dev, "FIFO write returned %d\n", err);
1778e3938177SMatt Kline 	m_can_disable_all_interrupts(cdev);
1779e3938177SMatt Kline 	return NETDEV_TX_BUSY;
1780e0d1f481SDong Aisheng }
1781e0d1f481SDong Aisheng 
m_can_tx_work_queue(struct work_struct * ws)1782f524f829SDan Murphy static void m_can_tx_work_queue(struct work_struct *ws)
1783f524f829SDan Murphy {
1784441ac340SDan Murphy 	struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev,
1785f524f829SDan Murphy 						   tx_work);
1786441ac340SDan Murphy 
1787441ac340SDan Murphy 	m_can_tx_handler(cdev);
1788f524f829SDan Murphy }
1789f524f829SDan Murphy 
m_can_start_xmit(struct sk_buff * skb,struct net_device * dev)1790f524f829SDan Murphy static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
1791f524f829SDan Murphy 				    struct net_device *dev)
1792f524f829SDan Murphy {
1793441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1794f524f829SDan Murphy 
1795ae64438bSOliver Hartkopp 	if (can_dev_dropped_skb(dev, skb))
1796f524f829SDan Murphy 		return NETDEV_TX_OK;
1797f524f829SDan Murphy 
1798441ac340SDan Murphy 	if (cdev->is_peripheral) {
1799441ac340SDan Murphy 		if (cdev->tx_skb) {
1800f524f829SDan Murphy 			netdev_err(dev, "hard_xmit called while tx busy\n");
1801f524f829SDan Murphy 			return NETDEV_TX_BUSY;
1802f524f829SDan Murphy 		}
1803f524f829SDan Murphy 
1804441ac340SDan Murphy 		if (cdev->can.state == CAN_STATE_BUS_OFF) {
1805f524f829SDan Murphy 			m_can_clean(dev);
1806f524f829SDan Murphy 		} else {
1807f524f829SDan Murphy 			/* Need to stop the queue to avoid numerous requests
1808f524f829SDan Murphy 			 * from being sent.  Suggested improvement is to create
1809f524f829SDan Murphy 			 * a queueing mechanism that will queue the skbs and
1810f524f829SDan Murphy 			 * process them in order.
1811f524f829SDan Murphy 			 */
1812441ac340SDan Murphy 			cdev->tx_skb = skb;
1813441ac340SDan Murphy 			netif_stop_queue(cdev->net);
1814441ac340SDan Murphy 			queue_work(cdev->tx_wq, &cdev->tx_work);
1815f524f829SDan Murphy 		}
1816f524f829SDan Murphy 	} else {
1817441ac340SDan Murphy 		cdev->tx_skb = skb;
1818441ac340SDan Murphy 		return m_can_tx_handler(cdev);
1819f524f829SDan Murphy 	}
1820f524f829SDan Murphy 
1821f524f829SDan Murphy 	return NETDEV_TX_OK;
1822f524f829SDan Murphy }
1823f524f829SDan Murphy 
hrtimer_callback(struct hrtimer * timer)1824b382380cSJudith Mendez static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
1825b382380cSJudith Mendez {
1826b382380cSJudith Mendez 	struct m_can_classdev *cdev = container_of(timer, struct
1827b382380cSJudith Mendez 						   m_can_classdev, hrtimer);
1828b382380cSJudith Mendez 
1829b382380cSJudith Mendez 	m_can_isr(0, cdev->net);
1830b382380cSJudith Mendez 
1831b382380cSJudith Mendez 	hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS));
1832b382380cSJudith Mendez 
1833b382380cSJudith Mendez 	return HRTIMER_RESTART;
1834b382380cSJudith Mendez }
1835b382380cSJudith Mendez 
m_can_open(struct net_device * dev)1836f524f829SDan Murphy static int m_can_open(struct net_device *dev)
1837f524f829SDan Murphy {
1838441ac340SDan Murphy 	struct m_can_classdev *cdev = netdev_priv(dev);
1839f524f829SDan Murphy 	int err;
1840f524f829SDan Murphy 
1841d836cb5fSFaiz Abbas 	err = phy_power_on(cdev->transceiver);
1842f524f829SDan Murphy 	if (err)
1843f524f829SDan Murphy 		return err;
1844f524f829SDan Murphy 
1845d836cb5fSFaiz Abbas 	err = m_can_clk_start(cdev);
1846d836cb5fSFaiz Abbas 	if (err)
1847d836cb5fSFaiz Abbas 		goto out_phy_power_off;
1848d836cb5fSFaiz Abbas 
1849f524f829SDan Murphy 	/* open the can device */
1850f524f829SDan Murphy 	err = open_candev(dev);
1851f524f829SDan Murphy 	if (err) {
1852f524f829SDan Murphy 		netdev_err(dev, "failed to open can device\n");
1853f524f829SDan Murphy 		goto exit_disable_clks;
1854f524f829SDan Murphy 	}
1855f524f829SDan Murphy 
18561be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
18571be37d3bSTorin Cooper-Bennun 		can_rx_offload_enable(&cdev->offload);
18587fb4f560SJake Hamby 	else
18597fb4f560SJake Hamby 		napi_enable(&cdev->napi);
18601be37d3bSTorin Cooper-Bennun 
1861f524f829SDan Murphy 	/* register interrupt handler */
1862441ac340SDan Murphy 	if (cdev->is_peripheral) {
1863441ac340SDan Murphy 		cdev->tx_skb = NULL;
1864441ac340SDan Murphy 		cdev->tx_wq = alloc_workqueue("mcan_wq",
1865f524f829SDan Murphy 					      WQ_FREEZABLE | WQ_MEM_RECLAIM, 0);
1866441ac340SDan Murphy 		if (!cdev->tx_wq) {
1867f524f829SDan Murphy 			err = -ENOMEM;
1868f524f829SDan Murphy 			goto out_wq_fail;
1869f524f829SDan Murphy 		}
1870f524f829SDan Murphy 
1871441ac340SDan Murphy 		INIT_WORK(&cdev->tx_work, m_can_tx_work_queue);
1872f524f829SDan Murphy 
1873f524f829SDan Murphy 		err = request_threaded_irq(dev->irq, NULL, m_can_isr,
1874865f5b67SMarc Kleine-Budde 					   IRQF_ONESHOT,
1875f524f829SDan Murphy 					   dev->name, dev);
1876b382380cSJudith Mendez 	} else if (dev->irq) {
1877f524f829SDan Murphy 		err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
1878f524f829SDan Murphy 				  dev);
1879f524f829SDan Murphy 	}
1880f524f829SDan Murphy 
1881f524f829SDan Murphy 	if (err < 0) {
1882f524f829SDan Murphy 		netdev_err(dev, "failed to request interrupt\n");
1883f524f829SDan Murphy 		goto exit_irq_fail;
1884f524f829SDan Murphy 	}
1885f524f829SDan Murphy 
1886f524f829SDan Murphy 	/* start the m_can controller */
1887eaacfeacSVivek Yadav 	err = m_can_start(dev);
1888eaacfeacSVivek Yadav 	if (err)
1889db5aca78SSimon Horman 		goto exit_start_fail;
1890f524f829SDan Murphy 
1891f524f829SDan Murphy 	netif_start_queue(dev);
1892f524f829SDan Murphy 
1893f524f829SDan Murphy 	return 0;
1894f524f829SDan Murphy 
1895db5aca78SSimon Horman exit_start_fail:
1896db5aca78SSimon Horman 	if (cdev->is_peripheral || dev->irq)
1897db5aca78SSimon Horman 		free_irq(dev->irq, dev);
1898f524f829SDan Murphy exit_irq_fail:
1899441ac340SDan Murphy 	if (cdev->is_peripheral)
1900441ac340SDan Murphy 		destroy_workqueue(cdev->tx_wq);
1901f524f829SDan Murphy out_wq_fail:
19021be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
19031be37d3bSTorin Cooper-Bennun 		can_rx_offload_disable(&cdev->offload);
19047fb4f560SJake Hamby 	else
19057fb4f560SJake Hamby 		napi_disable(&cdev->napi);
1906f524f829SDan Murphy 	close_candev(dev);
1907f524f829SDan Murphy exit_disable_clks:
1908441ac340SDan Murphy 	m_can_clk_stop(cdev);
1909d836cb5fSFaiz Abbas out_phy_power_off:
1910d836cb5fSFaiz Abbas 	phy_power_off(cdev->transceiver);
1911f524f829SDan Murphy 	return err;
1912f524f829SDan Murphy }
1913f524f829SDan Murphy 
1914e0d1f481SDong Aisheng static const struct net_device_ops m_can_netdev_ops = {
1915e0d1f481SDong Aisheng 	.ndo_open = m_can_open,
1916e0d1f481SDong Aisheng 	.ndo_stop = m_can_close,
1917e0d1f481SDong Aisheng 	.ndo_start_xmit = m_can_start_xmit,
1918d6fdb38bSDong Aisheng 	.ndo_change_mtu = can_change_mtu,
1919e0d1f481SDong Aisheng };
1920e0d1f481SDong Aisheng 
1921409c188cSVincent Mailhol static const struct ethtool_ops m_can_ethtool_ops = {
1922409c188cSVincent Mailhol 	.get_ts_info = ethtool_op_get_ts_info,
1923409c188cSVincent Mailhol };
1924409c188cSVincent Mailhol 
register_m_can_dev(struct net_device * dev)1925e0d1f481SDong Aisheng static int register_m_can_dev(struct net_device *dev)
1926e0d1f481SDong Aisheng {
1927e0d1f481SDong Aisheng 	dev->flags |= IFF_ECHO;	/* we support local echo */
1928e0d1f481SDong Aisheng 	dev->netdev_ops = &m_can_netdev_ops;
1929409c188cSVincent Mailhol 	dev->ethtool_ops = &m_can_ethtool_ops;
1930e0d1f481SDong Aisheng 
1931e0d1f481SDong Aisheng 	return register_candev(dev);
1932e0d1f481SDong Aisheng }
1933e0d1f481SDong Aisheng 
m_can_check_mram_cfg(struct m_can_classdev * cdev,u32 mram_max_size)1934c1b17ea7SMarkus Schneider-Pargmann int m_can_check_mram_cfg(struct m_can_classdev *cdev, u32 mram_max_size)
1935c1b17ea7SMarkus Schneider-Pargmann {
1936c1b17ea7SMarkus Schneider-Pargmann 	u32 total_size;
1937c1b17ea7SMarkus Schneider-Pargmann 
1938c1b17ea7SMarkus Schneider-Pargmann 	total_size = cdev->mcfg[MRAM_TXB].off - cdev->mcfg[MRAM_SIDF].off +
1939c1b17ea7SMarkus Schneider-Pargmann 			cdev->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
1940c1b17ea7SMarkus Schneider-Pargmann 	if (total_size > mram_max_size) {
1941c1b17ea7SMarkus Schneider-Pargmann 		dev_err(cdev->dev, "Total size of mram config(%u) exceeds mram(%u)\n",
1942c1b17ea7SMarkus Schneider-Pargmann 			total_size, mram_max_size);
1943c1b17ea7SMarkus Schneider-Pargmann 		return -EINVAL;
1944c1b17ea7SMarkus Schneider-Pargmann 	}
1945c1b17ea7SMarkus Schneider-Pargmann 
1946c1b17ea7SMarkus Schneider-Pargmann 	return 0;
1947c1b17ea7SMarkus Schneider-Pargmann }
1948c1b17ea7SMarkus Schneider-Pargmann EXPORT_SYMBOL_GPL(m_can_check_mram_cfg);
1949c1b17ea7SMarkus Schneider-Pargmann 
m_can_of_parse_mram(struct m_can_classdev * cdev,const u32 * mram_config_vals)1950441ac340SDan Murphy static void m_can_of_parse_mram(struct m_can_classdev *cdev,
1951b03cfc5bSMario Huettel 				const u32 *mram_config_vals)
1952e0d1f481SDong Aisheng {
1953441ac340SDan Murphy 	cdev->mcfg[MRAM_SIDF].off = mram_config_vals[0];
1954441ac340SDan Murphy 	cdev->mcfg[MRAM_SIDF].num = mram_config_vals[1];
1955441ac340SDan Murphy 	cdev->mcfg[MRAM_XIDF].off = cdev->mcfg[MRAM_SIDF].off +
1956441ac340SDan Murphy 		cdev->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
1957441ac340SDan Murphy 	cdev->mcfg[MRAM_XIDF].num = mram_config_vals[2];
1958441ac340SDan Murphy 	cdev->mcfg[MRAM_RXF0].off = cdev->mcfg[MRAM_XIDF].off +
1959441ac340SDan Murphy 		cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
1960441ac340SDan Murphy 	cdev->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
196120779943STorin Cooper-Bennun 		FIELD_MAX(RXFC_FS_MASK);
1962441ac340SDan Murphy 	cdev->mcfg[MRAM_RXF1].off = cdev->mcfg[MRAM_RXF0].off +
1963441ac340SDan Murphy 		cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
1964441ac340SDan Murphy 	cdev->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
196520779943STorin Cooper-Bennun 		FIELD_MAX(RXFC_FS_MASK);
1966441ac340SDan Murphy 	cdev->mcfg[MRAM_RXB].off = cdev->mcfg[MRAM_RXF1].off +
1967441ac340SDan Murphy 		cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
1968441ac340SDan Murphy 	cdev->mcfg[MRAM_RXB].num = mram_config_vals[5];
1969441ac340SDan Murphy 	cdev->mcfg[MRAM_TXE].off = cdev->mcfg[MRAM_RXB].off +
1970441ac340SDan Murphy 		cdev->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
1971441ac340SDan Murphy 	cdev->mcfg[MRAM_TXE].num = mram_config_vals[6];
1972441ac340SDan Murphy 	cdev->mcfg[MRAM_TXB].off = cdev->mcfg[MRAM_TXE].off +
1973441ac340SDan Murphy 		cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
1974441ac340SDan Murphy 	cdev->mcfg[MRAM_TXB].num = mram_config_vals[7] &
197520779943STorin Cooper-Bennun 		FIELD_MAX(TXBC_NDTB_MASK);
1976e0d1f481SDong Aisheng 
1977441ac340SDan Murphy 	dev_dbg(cdev->dev,
1978f524f829SDan Murphy 		"sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
1979441ac340SDan Murphy 		cdev->mcfg[MRAM_SIDF].off, cdev->mcfg[MRAM_SIDF].num,
1980441ac340SDan Murphy 		cdev->mcfg[MRAM_XIDF].off, cdev->mcfg[MRAM_XIDF].num,
1981441ac340SDan Murphy 		cdev->mcfg[MRAM_RXF0].off, cdev->mcfg[MRAM_RXF0].num,
1982441ac340SDan Murphy 		cdev->mcfg[MRAM_RXF1].off, cdev->mcfg[MRAM_RXF1].num,
1983441ac340SDan Murphy 		cdev->mcfg[MRAM_RXB].off, cdev->mcfg[MRAM_RXB].num,
1984441ac340SDan Murphy 		cdev->mcfg[MRAM_TXE].off, cdev->mcfg[MRAM_TXE].num,
1985441ac340SDan Murphy 		cdev->mcfg[MRAM_TXB].off, cdev->mcfg[MRAM_TXB].num);
1986e0d1f481SDong Aisheng }
1987e0d1f481SDong Aisheng 
m_can_init_ram(struct m_can_classdev * cdev)1988e3938177SMatt Kline int m_can_init_ram(struct m_can_classdev *cdev)
1989e0d1f481SDong Aisheng {
1990f524f829SDan Murphy 	int end, i, start;
1991e3938177SMatt Kline 	int err = 0;
1992f524f829SDan Murphy 
1993f524f829SDan Murphy 	/* initialize the entire Message RAM in use to avoid possible
1994f524f829SDan Murphy 	 * ECC/parity checksum errors when reading an uninitialized buffer
1995f524f829SDan Murphy 	 */
1996441ac340SDan Murphy 	start = cdev->mcfg[MRAM_SIDF].off;
1997441ac340SDan Murphy 	end = cdev->mcfg[MRAM_TXB].off +
1998441ac340SDan Murphy 		cdev->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
1999f524f829SDan Murphy 
2000e3938177SMatt Kline 	for (i = start; i < end; i += 4) {
2001e3938177SMatt Kline 		err = m_can_fifo_write_no_off(cdev, i, 0x0);
2002e3938177SMatt Kline 		if (err)
2003e3938177SMatt Kline 			break;
2004e3938177SMatt Kline 	}
2005e3938177SMatt Kline 
2006e3938177SMatt Kline 	return err;
2007f524f829SDan Murphy }
2008f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_init_ram);
2009f524f829SDan Murphy 
m_can_class_get_clocks(struct m_can_classdev * cdev)20103b464affSMarc Kleine-Budde int m_can_class_get_clocks(struct m_can_classdev *cdev)
2011f524f829SDan Murphy {
2012f524f829SDan Murphy 	int ret = 0;
2013f524f829SDan Murphy 
20143b464affSMarc Kleine-Budde 	cdev->hclk = devm_clk_get(cdev->dev, "hclk");
20153b464affSMarc Kleine-Budde 	cdev->cclk = devm_clk_get(cdev->dev, "cclk");
2016f524f829SDan Murphy 
201768b4f9e0SJiasheng Jiang 	if (IS_ERR(cdev->hclk) || IS_ERR(cdev->cclk)) {
20183b464affSMarc Kleine-Budde 		dev_err(cdev->dev, "no clock found\n");
2019f524f829SDan Murphy 		ret = -ENODEV;
2020f524f829SDan Murphy 	}
2021f524f829SDan Murphy 
2022f524f829SDan Murphy 	return ret;
2023f524f829SDan Murphy }
2024f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_class_get_clocks);
2025f524f829SDan Murphy 
m_can_class_allocate_dev(struct device * dev,int sizeof_priv)2026ac33ffd3SMarc Kleine-Budde struct m_can_classdev *m_can_class_allocate_dev(struct device *dev,
2027ac33ffd3SMarc Kleine-Budde 						int sizeof_priv)
2028f524f829SDan Murphy {
2029441ac340SDan Murphy 	struct m_can_classdev *class_dev = NULL;
2030b03cfc5bSMario Huettel 	u32 mram_config_vals[MRAM_CFG_LEN];
2031f524f829SDan Murphy 	struct net_device *net_dev;
2032b03cfc5bSMario Huettel 	u32 tx_fifo_size;
2033f524f829SDan Murphy 	int ret;
2034b03cfc5bSMario Huettel 
2035f524f829SDan Murphy 	ret = fwnode_property_read_u32_array(dev_fwnode(dev),
2036f524f829SDan Murphy 					     "bosch,mram-cfg",
2037b03cfc5bSMario Huettel 					     mram_config_vals,
2038b03cfc5bSMario Huettel 					     sizeof(mram_config_vals) / 4);
2039b03cfc5bSMario Huettel 	if (ret) {
2040f524f829SDan Murphy 		dev_err(dev, "Could not get Message RAM configuration.");
2041f524f829SDan Murphy 		goto out;
2042b03cfc5bSMario Huettel 	}
2043b03cfc5bSMario Huettel 
2044b03cfc5bSMario Huettel 	/* Get TX FIFO size
2045b03cfc5bSMario Huettel 	 * Defines the total amount of echo buffers for loopback
2046b03cfc5bSMario Huettel 	 */
2047b03cfc5bSMario Huettel 	tx_fifo_size = mram_config_vals[7];
2048e0d1f481SDong Aisheng 
2049e0d1f481SDong Aisheng 	/* allocate the m_can device */
2050ac33ffd3SMarc Kleine-Budde 	net_dev = alloc_candev(sizeof_priv, tx_fifo_size);
2051f524f829SDan Murphy 	if (!net_dev) {
2052f524f829SDan Murphy 		dev_err(dev, "Failed to allocate CAN device");
2053f524f829SDan Murphy 		goto out;
2054b03cfc5bSMario Huettel 	}
20555e520eddSFaiz Abbas 
2056f524f829SDan Murphy 	class_dev = netdev_priv(net_dev);
2057f524f829SDan Murphy 	class_dev->net = net_dev;
2058f524f829SDan Murphy 	class_dev->dev = dev;
2059f524f829SDan Murphy 	SET_NETDEV_DEV(net_dev, dev);
2060e0d1f481SDong Aisheng 
2061f524f829SDan Murphy 	m_can_of_parse_mram(class_dev, mram_config_vals);
2062f524f829SDan Murphy out:
2063f524f829SDan Murphy 	return class_dev;
2064f524f829SDan Murphy }
2065f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
2066f524f829SDan Murphy 
m_can_class_free_dev(struct net_device * net)2067a8c22f5bSDan Murphy void m_can_class_free_dev(struct net_device *net)
2068a8c22f5bSDan Murphy {
2069a8c22f5bSDan Murphy 	free_candev(net);
2070a8c22f5bSDan Murphy }
2071a8c22f5bSDan Murphy EXPORT_SYMBOL_GPL(m_can_class_free_dev);
2072a8c22f5bSDan Murphy 
m_can_class_register(struct m_can_classdev * cdev)20733b464affSMarc Kleine-Budde int m_can_class_register(struct m_can_classdev *cdev)
2074f524f829SDan Murphy {
2075f524f829SDan Murphy 	int ret;
2076f524f829SDan Murphy 
20773b464affSMarc Kleine-Budde 	if (cdev->pm_clock_support) {
20783b464affSMarc Kleine-Budde 		ret = m_can_clk_start(cdev);
2079cdf8259dSFaiz Abbas 		if (ret)
2080227619c3SPatrik Flykt 			return ret;
2081f524f829SDan Murphy 	}
2082cdf8259dSFaiz Abbas 
20831be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral) {
20841be37d3bSTorin Cooper-Bennun 		ret = can_rx_offload_add_manual(cdev->net, &cdev->offload,
2085e1cf330fSJakub Kicinski 						NAPI_POLL_WEIGHT);
2086cdf8259dSFaiz Abbas 		if (ret)
2087cdf8259dSFaiz Abbas 			goto clk_disable;
20881be37d3bSTorin Cooper-Bennun 	}
20891be37d3bSTorin Cooper-Bennun 
2090b382380cSJudith Mendez 	if (!cdev->net->irq)
2091b382380cSJudith Mendez 		cdev->hrtimer.function = &hrtimer_callback;
2092b382380cSJudith Mendez 
20931be37d3bSTorin Cooper-Bennun 	ret = m_can_dev_setup(cdev);
20941be37d3bSTorin Cooper-Bennun 	if (ret)
20951be37d3bSTorin Cooper-Bennun 		goto rx_offload_del;
2096cdf8259dSFaiz Abbas 
20973b464affSMarc Kleine-Budde 	ret = register_m_can_dev(cdev->net);
2098e0d1f481SDong Aisheng 	if (ret) {
20993b464affSMarc Kleine-Budde 		dev_err(cdev->dev, "registering %s failed (err=%d)\n",
21003b464affSMarc Kleine-Budde 			cdev->net->name, ret);
21011be37d3bSTorin Cooper-Bennun 		goto rx_offload_del;
2102e0d1f481SDong Aisheng 	}
2103e0d1f481SDong Aisheng 
21043b464affSMarc Kleine-Budde 	of_can_transceiver(cdev->net);
2105e0d1f481SDong Aisheng 
21063b464affSMarc Kleine-Budde 	dev_info(cdev->dev, "%s device registered (irq=%d, version=%d)\n",
21073b464affSMarc Kleine-Budde 		 KBUILD_MODNAME, cdev->net->irq, cdev->version);
2108e0d1f481SDong Aisheng 
2109b03cfc5bSMario Huettel 	/* Probe finished
2110b03cfc5bSMario Huettel 	 * Stop clocks. They will be reactivated once the M_CAN device is opened
2111b03cfc5bSMario Huettel 	 */
21121be37d3bSTorin Cooper-Bennun 	m_can_clk_stop(cdev);
21131be37d3bSTorin Cooper-Bennun 
21141be37d3bSTorin Cooper-Bennun 	return 0;
21151be37d3bSTorin Cooper-Bennun 
21161be37d3bSTorin Cooper-Bennun rx_offload_del:
21171be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
21181be37d3bSTorin Cooper-Bennun 		can_rx_offload_del(&cdev->offload);
2119cdf8259dSFaiz Abbas clk_disable:
21203b464affSMarc Kleine-Budde 	m_can_clk_stop(cdev);
2121e0d1f481SDong Aisheng 
2122f524f829SDan Murphy 	return ret;
2123f524f829SDan Murphy }
2124f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_class_register);
2125f524f829SDan Murphy 
m_can_class_unregister(struct m_can_classdev * cdev)21263b464affSMarc Kleine-Budde void m_can_class_unregister(struct m_can_classdev *cdev)
21276d9986b4SMarc Kleine-Budde {
21281be37d3bSTorin Cooper-Bennun 	if (cdev->is_peripheral)
21291be37d3bSTorin Cooper-Bennun 		can_rx_offload_del(&cdev->offload);
21303b464affSMarc Kleine-Budde 	unregister_candev(cdev->net);
21316d9986b4SMarc Kleine-Budde }
21326d9986b4SMarc Kleine-Budde EXPORT_SYMBOL_GPL(m_can_class_unregister);
21336d9986b4SMarc Kleine-Budde 
m_can_class_suspend(struct device * dev)2134f524f829SDan Murphy int m_can_class_suspend(struct device *dev)
2135e0d1f481SDong Aisheng {
2136c6b73489SMarc Kleine-Budde 	struct m_can_classdev *cdev = dev_get_drvdata(dev);
2137c6b73489SMarc Kleine-Budde 	struct net_device *ndev = cdev->net;
2138e0d1f481SDong Aisheng 
2139e0d1f481SDong Aisheng 	if (netif_running(ndev)) {
2140e0d1f481SDong Aisheng 		netif_stop_queue(ndev);
2141e0d1f481SDong Aisheng 		netif_device_detach(ndev);
2142d14ccea0SQuentin Schulz 		m_can_stop(ndev);
2143441ac340SDan Murphy 		m_can_clk_stop(cdev);
2144e0d1f481SDong Aisheng 	}
2145e0d1f481SDong Aisheng 
2146c9b3bce1SBich HEMON 	pinctrl_pm_select_sleep_state(dev);
2147c9b3bce1SBich HEMON 
2148441ac340SDan Murphy 	cdev->can.state = CAN_STATE_SLEEPING;
2149e0d1f481SDong Aisheng 
2150e0d1f481SDong Aisheng 	return 0;
2151e0d1f481SDong Aisheng }
2152f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_class_suspend);
2153e0d1f481SDong Aisheng 
m_can_class_resume(struct device * dev)2154f524f829SDan Murphy int m_can_class_resume(struct device *dev)
2155e0d1f481SDong Aisheng {
2156c6b73489SMarc Kleine-Budde 	struct m_can_classdev *cdev = dev_get_drvdata(dev);
2157c6b73489SMarc Kleine-Budde 	struct net_device *ndev = cdev->net;
2158e0d1f481SDong Aisheng 
2159c9b3bce1SBich HEMON 	pinctrl_pm_select_default_state(dev);
2160c9b3bce1SBich HEMON 
2161441ac340SDan Murphy 	cdev->can.state = CAN_STATE_ERROR_ACTIVE;
2162e0d1f481SDong Aisheng 
2163e0d1f481SDong Aisheng 	if (netif_running(ndev)) {
2164d14ccea0SQuentin Schulz 		int ret;
2165d14ccea0SQuentin Schulz 
2166441ac340SDan Murphy 		ret = m_can_clk_start(cdev);
2167d14ccea0SQuentin Schulz 		if (ret)
2168d14ccea0SQuentin Schulz 			return ret;
2169eaacfeacSVivek Yadav 		ret  = m_can_start(ndev);
2170eaacfeacSVivek Yadav 		if (ret) {
2171eaacfeacSVivek Yadav 			m_can_clk_stop(cdev);
2172d14ccea0SQuentin Schulz 
2173eaacfeacSVivek Yadav 			return ret;
2174eaacfeacSVivek Yadav 		}
2175eaacfeacSVivek Yadav 
2176e0d1f481SDong Aisheng 		netif_device_attach(ndev);
2177e0d1f481SDong Aisheng 		netif_start_queue(ndev);
2178e0d1f481SDong Aisheng 	}
2179e0d1f481SDong Aisheng 
2180e0d1f481SDong Aisheng 	return 0;
2181e0d1f481SDong Aisheng }
2182f524f829SDan Murphy EXPORT_SYMBOL_GPL(m_can_class_resume);
2183e0d1f481SDong Aisheng 
2184e0d1f481SDong Aisheng MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
2185f524f829SDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
2186e0d1f481SDong Aisheng MODULE_LICENSE("GPL v2");
2187e0d1f481SDong Aisheng MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
2188