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