xref: /linux/drivers/net/ethernet/ti/icssm/icssm_prueth.c (revision a99b56577da4398e602394518618c720db5b7cbb)
1511f6c1aSRoger Quadros // SPDX-License-Identifier: GPL-2.0
2511f6c1aSRoger Quadros 
3511f6c1aSRoger Quadros /* Texas Instruments ICSSM Ethernet Driver
4511f6c1aSRoger Quadros  *
5511f6c1aSRoger Quadros  * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
6511f6c1aSRoger Quadros  *
7511f6c1aSRoger Quadros  */
8511f6c1aSRoger Quadros 
9511f6c1aSRoger Quadros #include <linux/etherdevice.h>
10511f6c1aSRoger Quadros #include <linux/genalloc.h>
11511f6c1aSRoger Quadros #include <linux/if_bridge.h>
12511f6c1aSRoger Quadros #include <linux/if_hsr.h>
13511f6c1aSRoger Quadros #include <linux/if_vlan.h>
14511f6c1aSRoger Quadros #include <linux/interrupt.h>
15511f6c1aSRoger Quadros #include <linux/kernel.h>
16511f6c1aSRoger Quadros #include <linux/mfd/syscon.h>
17511f6c1aSRoger Quadros #include <linux/module.h>
18511f6c1aSRoger Quadros #include <linux/net_tstamp.h>
19511f6c1aSRoger Quadros #include <linux/of.h>
20511f6c1aSRoger Quadros #include <linux/of_irq.h>
21511f6c1aSRoger Quadros #include <linux/of_mdio.h>
22511f6c1aSRoger Quadros #include <linux/of_net.h>
23511f6c1aSRoger Quadros #include <linux/platform_device.h>
24511f6c1aSRoger Quadros #include <linux/phy.h>
25511f6c1aSRoger Quadros #include <linux/remoteproc/pruss.h>
26511f6c1aSRoger Quadros #include <linux/ptp_classify.h>
27511f6c1aSRoger Quadros #include <linux/regmap.h>
28511f6c1aSRoger Quadros #include <linux/remoteproc.h>
29511f6c1aSRoger Quadros #include <net/pkt_cls.h>
30511f6c1aSRoger Quadros 
31511f6c1aSRoger Quadros #include "icssm_prueth.h"
32*a99b5657SRoger Quadros #include "../icssg/icssg_mii_rt.h"
33*a99b5657SRoger Quadros 
34*a99b5657SRoger Quadros #define OCMC_RAM_SIZE		(SZ_64K)
35*a99b5657SRoger Quadros 
36*a99b5657SRoger Quadros #define TX_START_DELAY		0x40
37*a99b5657SRoger Quadros #define TX_CLK_DELAY_100M	0x6
38*a99b5657SRoger Quadros 
39*a99b5657SRoger Quadros /* Below macro is for 1528 Byte Frame support, to Allow even with
40*a99b5657SRoger Quadros  * Redundancy tag
41*a99b5657SRoger Quadros  */
42*a99b5657SRoger Quadros #define PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC  (VLAN_ETH_FRAME_LEN + \
43*a99b5657SRoger Quadros 						ETH_FCS_LEN + \
44*a99b5657SRoger Quadros 						ICSSM_LRE_TAG_SIZE)
45*a99b5657SRoger Quadros 
46*a99b5657SRoger Quadros /* ensure that order of PRUSS mem regions is same as enum prueth_mem */
47*a99b5657SRoger Quadros static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1,
48*a99b5657SRoger Quadros 					  PRUSS_MEM_SHRD_RAM2 };
49*a99b5657SRoger Quadros 
50*a99b5657SRoger Quadros static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = {
51*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
52*a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
53*a99b5657SRoger Quadros 			P0_Q1_BUFFER_OFFSET,
54*a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET,
55*a99b5657SRoger Quadros 			P0_Q1_BD_OFFSET,
56*a99b5657SRoger Quadros 			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
57*a99b5657SRoger Quadros 		},
58*a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
59*a99b5657SRoger Quadros 			P0_Q2_BUFFER_OFFSET,
60*a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 8,
61*a99b5657SRoger Quadros 			P0_Q2_BD_OFFSET,
62*a99b5657SRoger Quadros 			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
63*a99b5657SRoger Quadros 		},
64*a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
65*a99b5657SRoger Quadros 			P0_Q3_BUFFER_OFFSET,
66*a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 16,
67*a99b5657SRoger Quadros 			P0_Q3_BD_OFFSET,
68*a99b5657SRoger Quadros 			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
69*a99b5657SRoger Quadros 		},
70*a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
71*a99b5657SRoger Quadros 			P0_Q4_BUFFER_OFFSET,
72*a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 24,
73*a99b5657SRoger Quadros 			P0_Q4_BD_OFFSET,
74*a99b5657SRoger Quadros 			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
75*a99b5657SRoger Quadros 		},
76*a99b5657SRoger Quadros 	},
77*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
78*a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
79*a99b5657SRoger Quadros 			P1_Q1_BUFFER_OFFSET,
80*a99b5657SRoger Quadros 			P1_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) *
81*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
82*a99b5657SRoger Quadros 			P1_Q1_BD_OFFSET,
83*a99b5657SRoger Quadros 			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
84*a99b5657SRoger Quadros 		},
85*a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
86*a99b5657SRoger Quadros 			P1_Q2_BUFFER_OFFSET,
87*a99b5657SRoger Quadros 			P1_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) *
88*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
89*a99b5657SRoger Quadros 			P1_Q2_BD_OFFSET,
90*a99b5657SRoger Quadros 			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
91*a99b5657SRoger Quadros 		},
92*a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
93*a99b5657SRoger Quadros 			P1_Q3_BUFFER_OFFSET,
94*a99b5657SRoger Quadros 			P1_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) *
95*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
96*a99b5657SRoger Quadros 			P1_Q3_BD_OFFSET,
97*a99b5657SRoger Quadros 			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
98*a99b5657SRoger Quadros 		},
99*a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
100*a99b5657SRoger Quadros 			P1_Q4_BUFFER_OFFSET,
101*a99b5657SRoger Quadros 			P1_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) *
102*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
103*a99b5657SRoger Quadros 			P1_Q4_BD_OFFSET,
104*a99b5657SRoger Quadros 			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
105*a99b5657SRoger Quadros 		},
106*a99b5657SRoger Quadros 	},
107*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
108*a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
109*a99b5657SRoger Quadros 			P2_Q1_BUFFER_OFFSET,
110*a99b5657SRoger Quadros 			P2_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) *
111*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
112*a99b5657SRoger Quadros 			P2_Q1_BD_OFFSET,
113*a99b5657SRoger Quadros 			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
114*a99b5657SRoger Quadros 		},
115*a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
116*a99b5657SRoger Quadros 			P2_Q2_BUFFER_OFFSET,
117*a99b5657SRoger Quadros 			P2_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) *
118*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
119*a99b5657SRoger Quadros 			P2_Q2_BD_OFFSET,
120*a99b5657SRoger Quadros 			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
121*a99b5657SRoger Quadros 		},
122*a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
123*a99b5657SRoger Quadros 			P2_Q3_BUFFER_OFFSET,
124*a99b5657SRoger Quadros 			P2_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) *
125*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
126*a99b5657SRoger Quadros 			P2_Q3_BD_OFFSET,
127*a99b5657SRoger Quadros 			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
128*a99b5657SRoger Quadros 		},
129*a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
130*a99b5657SRoger Quadros 			P2_Q4_BUFFER_OFFSET,
131*a99b5657SRoger Quadros 			P2_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) *
132*a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
133*a99b5657SRoger Quadros 			P2_Q4_BD_OFFSET,
134*a99b5657SRoger Quadros 			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
135*a99b5657SRoger Quadros 		},
136*a99b5657SRoger Quadros 	},
137*a99b5657SRoger Quadros };
138*a99b5657SRoger Quadros 
139*a99b5657SRoger Quadros static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
140*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
141*a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, },
142*a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, },
143*a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q3_BD_OFFSET, .wr_ptr = P0_Q3_BD_OFFSET, },
144*a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q4_BD_OFFSET, .wr_ptr = P0_Q4_BD_OFFSET, },
145*a99b5657SRoger Quadros 	},
146*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
147*a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q1_BD_OFFSET, .wr_ptr = P1_Q1_BD_OFFSET, },
148*a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q2_BD_OFFSET, .wr_ptr = P1_Q2_BD_OFFSET, },
149*a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q3_BD_OFFSET, .wr_ptr = P1_Q3_BD_OFFSET, },
150*a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q4_BD_OFFSET, .wr_ptr = P1_Q4_BD_OFFSET, },
151*a99b5657SRoger Quadros 	},
152*a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
153*a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q1_BD_OFFSET, .wr_ptr = P2_Q1_BD_OFFSET, },
154*a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q2_BD_OFFSET, .wr_ptr = P2_Q2_BD_OFFSET, },
155*a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q3_BD_OFFSET, .wr_ptr = P2_Q3_BD_OFFSET, },
156*a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q4_BD_OFFSET, .wr_ptr = P2_Q4_BD_OFFSET, },
157*a99b5657SRoger Quadros 	}
158*a99b5657SRoger Quadros };
159*a99b5657SRoger Quadros 
160*a99b5657SRoger Quadros static void icssm_prueth_hostconfig(struct prueth *prueth)
161*a99b5657SRoger Quadros {
162*a99b5657SRoger Quadros 	void __iomem *sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
163*a99b5657SRoger Quadros 	void __iomem *sram;
164*a99b5657SRoger Quadros 
165*a99b5657SRoger Quadros 	/* queue size lookup table */
166*a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_SIZE_ADDR;
167*a99b5657SRoger Quadros 	writew(HOST_QUEUE_1_SIZE, sram);
168*a99b5657SRoger Quadros 	writew(HOST_QUEUE_2_SIZE, sram + 2);
169*a99b5657SRoger Quadros 	writew(HOST_QUEUE_3_SIZE, sram + 4);
170*a99b5657SRoger Quadros 	writew(HOST_QUEUE_4_SIZE, sram + 6);
171*a99b5657SRoger Quadros 
172*a99b5657SRoger Quadros 	/* queue information table */
173*a99b5657SRoger Quadros 	sram = sram_base + HOST_Q1_RX_CONTEXT_OFFSET;
174*a99b5657SRoger Quadros 	memcpy_toio(sram, queue_infos[PRUETH_PORT_QUEUE_HOST],
175*a99b5657SRoger Quadros 		    sizeof(queue_infos[PRUETH_PORT_QUEUE_HOST]));
176*a99b5657SRoger Quadros 
177*a99b5657SRoger Quadros 	/* buffer offset table */
178*a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_OFFSET_ADDR;
179*a99b5657SRoger Quadros 	writew(P0_Q1_BUFFER_OFFSET, sram);
180*a99b5657SRoger Quadros 	writew(P0_Q2_BUFFER_OFFSET, sram + 2);
181*a99b5657SRoger Quadros 	writew(P0_Q3_BUFFER_OFFSET, sram + 4);
182*a99b5657SRoger Quadros 	writew(P0_Q4_BUFFER_OFFSET, sram + 6);
183*a99b5657SRoger Quadros 
184*a99b5657SRoger Quadros 	/* buffer descriptor offset table*/
185*a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR;
186*a99b5657SRoger Quadros 	writew(P0_Q1_BD_OFFSET, sram);
187*a99b5657SRoger Quadros 	writew(P0_Q2_BD_OFFSET, sram + 2);
188*a99b5657SRoger Quadros 	writew(P0_Q3_BD_OFFSET, sram + 4);
189*a99b5657SRoger Quadros 	writew(P0_Q4_BD_OFFSET, sram + 6);
190*a99b5657SRoger Quadros 
191*a99b5657SRoger Quadros 	/* queue table */
192*a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_DESC_OFFSET;
193*a99b5657SRoger Quadros 	memcpy_toio(sram, queue_descs[PRUETH_PORT_QUEUE_HOST],
194*a99b5657SRoger Quadros 		    sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST]));
195*a99b5657SRoger Quadros }
196*a99b5657SRoger Quadros 
197*a99b5657SRoger Quadros static void icssm_prueth_mii_init(struct prueth *prueth)
198*a99b5657SRoger Quadros {
199*a99b5657SRoger Quadros 	struct regmap *mii_rt;
200*a99b5657SRoger Quadros 	u32 rxcfg_reg, rxcfg;
201*a99b5657SRoger Quadros 	u32 txcfg_reg, txcfg;
202*a99b5657SRoger Quadros 
203*a99b5657SRoger Quadros 	mii_rt = prueth->mii_rt;
204*a99b5657SRoger Quadros 
205*a99b5657SRoger Quadros 	rxcfg = PRUSS_MII_RT_RXCFG_RX_ENABLE |
206*a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS |
207*a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_L2_EN |
208*a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE |
209*a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS;
210*a99b5657SRoger Quadros 
211*a99b5657SRoger Quadros 	/* Configuration of Port 0 Rx */
212*a99b5657SRoger Quadros 	rxcfg_reg = PRUSS_MII_RT_RXCFG0;
213*a99b5657SRoger Quadros 
214*a99b5657SRoger Quadros 	regmap_write(mii_rt, rxcfg_reg, rxcfg);
215*a99b5657SRoger Quadros 
216*a99b5657SRoger Quadros 	/* Configuration of Port 1 Rx */
217*a99b5657SRoger Quadros 	rxcfg_reg = PRUSS_MII_RT_RXCFG1;
218*a99b5657SRoger Quadros 
219*a99b5657SRoger Quadros 	rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
220*a99b5657SRoger Quadros 
221*a99b5657SRoger Quadros 	regmap_write(mii_rt, rxcfg_reg, rxcfg);
222*a99b5657SRoger Quadros 
223*a99b5657SRoger Quadros 	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
224*a99b5657SRoger Quadros 		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
225*a99b5657SRoger Quadros 		PRUSS_MII_RT_TXCFG_TX_32_MODE_EN |
226*a99b5657SRoger Quadros 		(TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) |
227*a99b5657SRoger Quadros 		(TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT);
228*a99b5657SRoger Quadros 
229*a99b5657SRoger Quadros 	/* Configuration of Port 0 Tx */
230*a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_TXCFG0;
231*a99b5657SRoger Quadros 
232*a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
233*a99b5657SRoger Quadros 
234*a99b5657SRoger Quadros 	txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
235*a99b5657SRoger Quadros 
236*a99b5657SRoger Quadros 	/* Configuration of Port 1 Tx */
237*a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_TXCFG1;
238*a99b5657SRoger Quadros 
239*a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
240*a99b5657SRoger Quadros 
241*a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_RX_FRMS0;
242*a99b5657SRoger Quadros 
243*a99b5657SRoger Quadros 	/* Min frame length should be set to 64 to allow receive of standard
244*a99b5657SRoger Quadros 	 * Ethernet frames such as PTP, LLDP that will not have the tag/rct.
245*a99b5657SRoger Quadros 	 * Actual size written to register is size - 1 per TRM. This also
246*a99b5657SRoger Quadros 	 * includes CRC/FCS.
247*a99b5657SRoger Quadros 	 */
248*a99b5657SRoger Quadros 	txcfg = FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK,
249*a99b5657SRoger Quadros 			   (PRUSS_MII_RT_RX_FRMS_MIN_FRM - 1));
250*a99b5657SRoger Quadros 
251*a99b5657SRoger Quadros 	/* For EMAC, set Max frame size to 1528 i.e size with VLAN.
252*a99b5657SRoger Quadros 	 * Actual size written to register is size - 1 as per TRM.
253*a99b5657SRoger Quadros 	 * Since driver support run time change of protocol, driver
254*a99b5657SRoger Quadros 	 * must overwrite the values based on Ethernet type.
255*a99b5657SRoger Quadros 	 */
256*a99b5657SRoger Quadros 	txcfg |= FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK,
257*a99b5657SRoger Quadros 			    (PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC - 1));
258*a99b5657SRoger Quadros 
259*a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
260*a99b5657SRoger Quadros 
261*a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_RX_FRMS1;
262*a99b5657SRoger Quadros 
263*a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
264*a99b5657SRoger Quadros }
265*a99b5657SRoger Quadros 
266*a99b5657SRoger Quadros static void icssm_prueth_clearmem(struct prueth *prueth, enum prueth_mem region)
267*a99b5657SRoger Quadros {
268*a99b5657SRoger Quadros 	memset_io(prueth->mem[region].va, 0, prueth->mem[region].size);
269*a99b5657SRoger Quadros }
270*a99b5657SRoger Quadros 
271*a99b5657SRoger Quadros static void icssm_prueth_hostinit(struct prueth *prueth)
272*a99b5657SRoger Quadros {
273*a99b5657SRoger Quadros 	/* Clear shared RAM */
274*a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, PRUETH_MEM_SHARED_RAM);
275*a99b5657SRoger Quadros 
276*a99b5657SRoger Quadros 	/* Clear OCMC RAM */
277*a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, PRUETH_MEM_OCMC);
278*a99b5657SRoger Quadros 
279*a99b5657SRoger Quadros 	/* Clear data RAMs */
280*a99b5657SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC0])
281*a99b5657SRoger Quadros 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM0);
282*a99b5657SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC1])
283*a99b5657SRoger Quadros 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1);
284*a99b5657SRoger Quadros 
285*a99b5657SRoger Quadros 	/* Initialize host queues in shared RAM */
286*a99b5657SRoger Quadros 	icssm_prueth_hostconfig(prueth);
287*a99b5657SRoger Quadros 
288*a99b5657SRoger Quadros 	/* Configure MII_RT */
289*a99b5657SRoger Quadros 	icssm_prueth_mii_init(prueth);
290*a99b5657SRoger Quadros }
291*a99b5657SRoger Quadros 
292*a99b5657SRoger Quadros /* This function initialize the driver in EMAC or HSR or PRP mode
293*a99b5657SRoger Quadros  * based on eth_type
294*a99b5657SRoger Quadros  */
295*a99b5657SRoger Quadros static void icssm_prueth_init_ethernet_mode(struct prueth *prueth)
296*a99b5657SRoger Quadros {
297*a99b5657SRoger Quadros 	icssm_prueth_hostinit(prueth);
298*a99b5657SRoger Quadros }
299*a99b5657SRoger Quadros 
300*a99b5657SRoger Quadros static int icssm_prueth_emac_config(struct prueth_emac *emac)
301*a99b5657SRoger Quadros {
302*a99b5657SRoger Quadros 	struct prueth *prueth = emac->prueth;
303*a99b5657SRoger Quadros 	u32 sharedramaddr, ocmcaddr;
304*a99b5657SRoger Quadros 	void __iomem *dram_base;
305*a99b5657SRoger Quadros 	void __iomem *mac_addr;
306*a99b5657SRoger Quadros 	void __iomem *dram;
307*a99b5657SRoger Quadros 
308*a99b5657SRoger Quadros 	/* PRU needs local shared RAM address for C28 */
309*a99b5657SRoger Quadros 	sharedramaddr = ICSS_LOCAL_SHARED_RAM;
310*a99b5657SRoger Quadros 	/* PRU needs real global OCMC address for C30*/
311*a99b5657SRoger Quadros 	ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa;
312*a99b5657SRoger Quadros 
313*a99b5657SRoger Quadros 	/* Clear data RAM */
314*a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, emac->dram);
315*a99b5657SRoger Quadros 
316*a99b5657SRoger Quadros 	dram_base = prueth->mem[emac->dram].va;
317*a99b5657SRoger Quadros 
318*a99b5657SRoger Quadros 	/* setup mac address */
319*a99b5657SRoger Quadros 	mac_addr = dram_base + PORT_MAC_ADDR;
320*a99b5657SRoger Quadros 	memcpy_toio(mac_addr, emac->mac_addr, 6);
321*a99b5657SRoger Quadros 
322*a99b5657SRoger Quadros 	/* queue information table */
323*a99b5657SRoger Quadros 	dram = dram_base + TX_CONTEXT_Q1_OFFSET_ADDR;
324*a99b5657SRoger Quadros 	memcpy_toio(dram, queue_infos[emac->port_id],
325*a99b5657SRoger Quadros 		    sizeof(queue_infos[emac->port_id]));
326*a99b5657SRoger Quadros 
327*a99b5657SRoger Quadros 	/* queue table */
328*a99b5657SRoger Quadros 	dram = dram_base + PORT_QUEUE_DESC_OFFSET;
329*a99b5657SRoger Quadros 	memcpy_toio(dram, queue_descs[emac->port_id],
330*a99b5657SRoger Quadros 		    sizeof(queue_descs[emac->port_id]));
331*a99b5657SRoger Quadros 
332*a99b5657SRoger Quadros 	/* Set in constant table C28 of PRU0 to ICSS Shared memory */
333*a99b5657SRoger Quadros 	pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr);
334*a99b5657SRoger Quadros 
335*a99b5657SRoger Quadros 	/* Set in constant table C30 of PRU0 to OCMC memory */
336*a99b5657SRoger Quadros 	pru_rproc_set_ctable(emac->pru, PRU_C30, ocmcaddr);
337*a99b5657SRoger Quadros 
338*a99b5657SRoger Quadros 	return 0;
339*a99b5657SRoger Quadros }
340511f6c1aSRoger Quadros 
341511f6c1aSRoger Quadros /* called back by PHY layer if there is change in link state of hw port*/
342511f6c1aSRoger Quadros static void icssm_emac_adjust_link(struct net_device *ndev)
343511f6c1aSRoger Quadros {
344511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
345511f6c1aSRoger Quadros 	struct phy_device *phydev = emac->phydev;
346511f6c1aSRoger Quadros 	bool new_state = false;
347511f6c1aSRoger Quadros 	unsigned long flags;
348511f6c1aSRoger Quadros 
349511f6c1aSRoger Quadros 	spin_lock_irqsave(&emac->lock, flags);
350511f6c1aSRoger Quadros 
351511f6c1aSRoger Quadros 	if (phydev->link) {
352511f6c1aSRoger Quadros 		/* check the mode of operation */
353511f6c1aSRoger Quadros 		if (phydev->duplex != emac->duplex) {
354511f6c1aSRoger Quadros 			new_state = true;
355511f6c1aSRoger Quadros 			emac->duplex = phydev->duplex;
356511f6c1aSRoger Quadros 		}
357511f6c1aSRoger Quadros 		if (phydev->speed != emac->speed) {
358511f6c1aSRoger Quadros 			new_state = true;
359511f6c1aSRoger Quadros 			emac->speed = phydev->speed;
360511f6c1aSRoger Quadros 		}
361511f6c1aSRoger Quadros 		if (!emac->link) {
362511f6c1aSRoger Quadros 			new_state = true;
363511f6c1aSRoger Quadros 			emac->link = 1;
364511f6c1aSRoger Quadros 		}
365511f6c1aSRoger Quadros 	} else if (emac->link) {
366511f6c1aSRoger Quadros 		new_state = true;
367511f6c1aSRoger Quadros 		emac->link = 0;
368511f6c1aSRoger Quadros 	}
369511f6c1aSRoger Quadros 
370511f6c1aSRoger Quadros 	if (new_state)
371511f6c1aSRoger Quadros 		phy_print_status(phydev);
372511f6c1aSRoger Quadros 
373511f6c1aSRoger Quadros 	if (emac->link) {
374511f6c1aSRoger Quadros 	       /* reactivate the transmit queue if it is stopped */
375511f6c1aSRoger Quadros 		if (netif_running(ndev) && netif_queue_stopped(ndev))
376511f6c1aSRoger Quadros 			netif_wake_queue(ndev);
377511f6c1aSRoger Quadros 	} else {
378511f6c1aSRoger Quadros 		if (!netif_queue_stopped(ndev))
379511f6c1aSRoger Quadros 			netif_stop_queue(ndev);
380511f6c1aSRoger Quadros 	}
381511f6c1aSRoger Quadros 
382511f6c1aSRoger Quadros 	spin_unlock_irqrestore(&emac->lock, flags);
383511f6c1aSRoger Quadros }
384511f6c1aSRoger Quadros 
385511f6c1aSRoger Quadros static int icssm_emac_set_boot_pru(struct prueth_emac *emac,
386511f6c1aSRoger Quadros 				   struct net_device *ndev)
387511f6c1aSRoger Quadros {
388511f6c1aSRoger Quadros 	const struct prueth_firmware *pru_firmwares;
389511f6c1aSRoger Quadros 	struct prueth *prueth = emac->prueth;
390511f6c1aSRoger Quadros 	const char *fw_name;
391511f6c1aSRoger Quadros 	int ret;
392511f6c1aSRoger Quadros 
393511f6c1aSRoger Quadros 	pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1];
394511f6c1aSRoger Quadros 	fw_name = pru_firmwares->fw_name[prueth->eth_type];
395511f6c1aSRoger Quadros 	if (!fw_name) {
396511f6c1aSRoger Quadros 		netdev_err(ndev, "eth_type %d not supported\n",
397511f6c1aSRoger Quadros 			   prueth->eth_type);
398511f6c1aSRoger Quadros 		return -ENODEV;
399511f6c1aSRoger Quadros 	}
400511f6c1aSRoger Quadros 
401511f6c1aSRoger Quadros 	ret = rproc_set_firmware(emac->pru, fw_name);
402511f6c1aSRoger Quadros 	if (ret) {
403511f6c1aSRoger Quadros 		netdev_err(ndev, "failed to set %s firmware: %d\n",
404511f6c1aSRoger Quadros 			   fw_name, ret);
405511f6c1aSRoger Quadros 		return ret;
406511f6c1aSRoger Quadros 	}
407511f6c1aSRoger Quadros 
408511f6c1aSRoger Quadros 	ret = rproc_boot(emac->pru);
409511f6c1aSRoger Quadros 	if (ret) {
410511f6c1aSRoger Quadros 		netdev_err(ndev, "failed to boot %s firmware: %d\n",
411511f6c1aSRoger Quadros 			   fw_name, ret);
412511f6c1aSRoger Quadros 		return ret;
413511f6c1aSRoger Quadros 	}
414511f6c1aSRoger Quadros 
415511f6c1aSRoger Quadros 	return ret;
416511f6c1aSRoger Quadros }
417511f6c1aSRoger Quadros 
418511f6c1aSRoger Quadros /**
419511f6c1aSRoger Quadros  * icssm_emac_ndo_open - EMAC device open
420511f6c1aSRoger Quadros  * @ndev: network adapter device
421511f6c1aSRoger Quadros  *
422511f6c1aSRoger Quadros  * Called when system wants to start the interface.
423511f6c1aSRoger Quadros  *
424511f6c1aSRoger Quadros  * Return: 0 for a successful open, or appropriate error code
425511f6c1aSRoger Quadros  */
426511f6c1aSRoger Quadros static int icssm_emac_ndo_open(struct net_device *ndev)
427511f6c1aSRoger Quadros {
428511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
429*a99b5657SRoger Quadros 	struct prueth *prueth = emac->prueth;
430511f6c1aSRoger Quadros 	int ret;
431511f6c1aSRoger Quadros 
432*a99b5657SRoger Quadros 	/* set h/w MAC as user might have re-configured */
433*a99b5657SRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
434*a99b5657SRoger Quadros 
435*a99b5657SRoger Quadros 	if (!prueth->emac_configured)
436*a99b5657SRoger Quadros 		icssm_prueth_init_ethernet_mode(prueth);
437*a99b5657SRoger Quadros 
438*a99b5657SRoger Quadros 	icssm_prueth_emac_config(emac);
439*a99b5657SRoger Quadros 
440511f6c1aSRoger Quadros 	ret = icssm_emac_set_boot_pru(emac, ndev);
441511f6c1aSRoger Quadros 	if (ret)
442511f6c1aSRoger Quadros 		return ret;
443511f6c1aSRoger Quadros 
444511f6c1aSRoger Quadros 	/* start PHY */
445511f6c1aSRoger Quadros 	phy_start(emac->phydev);
446*a99b5657SRoger Quadros 	prueth->emac_configured |= BIT(emac->port_id);
447511f6c1aSRoger Quadros 	return 0;
448511f6c1aSRoger Quadros }
449511f6c1aSRoger Quadros 
450511f6c1aSRoger Quadros /**
451511f6c1aSRoger Quadros  * icssm_emac_ndo_stop - EMAC device stop
452511f6c1aSRoger Quadros  * @ndev: network adapter device
453511f6c1aSRoger Quadros  *
454511f6c1aSRoger Quadros  * Called when system wants to stop or down the interface.
455511f6c1aSRoger Quadros  *
456511f6c1aSRoger Quadros  * Return: Always 0 (Success)
457511f6c1aSRoger Quadros  */
458511f6c1aSRoger Quadros static int icssm_emac_ndo_stop(struct net_device *ndev)
459511f6c1aSRoger Quadros {
460511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
461511f6c1aSRoger Quadros 
462511f6c1aSRoger Quadros 	/* stop PHY */
463511f6c1aSRoger Quadros 	phy_stop(emac->phydev);
464511f6c1aSRoger Quadros 
465511f6c1aSRoger Quadros 	rproc_shutdown(emac->pru);
466511f6c1aSRoger Quadros 
467511f6c1aSRoger Quadros 	return 0;
468511f6c1aSRoger Quadros }
469511f6c1aSRoger Quadros 
470511f6c1aSRoger Quadros static const struct net_device_ops emac_netdev_ops = {
471511f6c1aSRoger Quadros 	.ndo_open = icssm_emac_ndo_open,
472511f6c1aSRoger Quadros 	.ndo_stop = icssm_emac_ndo_stop,
473511f6c1aSRoger Quadros };
474511f6c1aSRoger Quadros 
475511f6c1aSRoger Quadros /* get emac_port corresponding to eth_node name */
476511f6c1aSRoger Quadros static int icssm_prueth_node_port(struct device_node *eth_node)
477511f6c1aSRoger Quadros {
478511f6c1aSRoger Quadros 	u32 port_id;
479511f6c1aSRoger Quadros 	int ret;
480511f6c1aSRoger Quadros 
481511f6c1aSRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
482511f6c1aSRoger Quadros 	if (ret)
483511f6c1aSRoger Quadros 		return ret;
484511f6c1aSRoger Quadros 
485511f6c1aSRoger Quadros 	if (port_id == 0)
486511f6c1aSRoger Quadros 		return PRUETH_PORT_MII0;
487511f6c1aSRoger Quadros 	else if (port_id == 1)
488511f6c1aSRoger Quadros 		return PRUETH_PORT_MII1;
489511f6c1aSRoger Quadros 	else
490511f6c1aSRoger Quadros 		return PRUETH_PORT_INVALID;
491511f6c1aSRoger Quadros }
492511f6c1aSRoger Quadros 
493511f6c1aSRoger Quadros /* get MAC instance corresponding to eth_node name */
494511f6c1aSRoger Quadros static int icssm_prueth_node_mac(struct device_node *eth_node)
495511f6c1aSRoger Quadros {
496511f6c1aSRoger Quadros 	u32 port_id;
497511f6c1aSRoger Quadros 	int ret;
498511f6c1aSRoger Quadros 
499511f6c1aSRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
500511f6c1aSRoger Quadros 	if (ret)
501511f6c1aSRoger Quadros 		return ret;
502511f6c1aSRoger Quadros 
503511f6c1aSRoger Quadros 	if (port_id == 0)
504511f6c1aSRoger Quadros 		return PRUETH_MAC0;
505511f6c1aSRoger Quadros 	else if (port_id == 1)
506511f6c1aSRoger Quadros 		return PRUETH_MAC1;
507511f6c1aSRoger Quadros 	else
508511f6c1aSRoger Quadros 		return PRUETH_MAC_INVALID;
509511f6c1aSRoger Quadros }
510511f6c1aSRoger Quadros 
511511f6c1aSRoger Quadros static int icssm_prueth_netdev_init(struct prueth *prueth,
512511f6c1aSRoger Quadros 				    struct device_node *eth_node)
513511f6c1aSRoger Quadros {
514511f6c1aSRoger Quadros 	struct prueth_emac *emac;
515511f6c1aSRoger Quadros 	struct net_device *ndev;
516511f6c1aSRoger Quadros 	enum prueth_port port;
517511f6c1aSRoger Quadros 	enum prueth_mac mac;
518511f6c1aSRoger Quadros 	int ret;
519511f6c1aSRoger Quadros 
520511f6c1aSRoger Quadros 	port = icssm_prueth_node_port(eth_node);
521511f6c1aSRoger Quadros 	if (port == PRUETH_PORT_INVALID)
522511f6c1aSRoger Quadros 		return -EINVAL;
523511f6c1aSRoger Quadros 
524511f6c1aSRoger Quadros 	mac = icssm_prueth_node_mac(eth_node);
525511f6c1aSRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
526511f6c1aSRoger Quadros 		return -EINVAL;
527511f6c1aSRoger Quadros 
528511f6c1aSRoger Quadros 	ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac));
529511f6c1aSRoger Quadros 	if (!ndev)
530511f6c1aSRoger Quadros 		return -ENOMEM;
531511f6c1aSRoger Quadros 
532511f6c1aSRoger Quadros 	SET_NETDEV_DEV(ndev, prueth->dev);
533511f6c1aSRoger Quadros 	emac = netdev_priv(ndev);
534511f6c1aSRoger Quadros 	prueth->emac[mac] = emac;
535511f6c1aSRoger Quadros 	emac->prueth = prueth;
536511f6c1aSRoger Quadros 	emac->ndev = ndev;
537511f6c1aSRoger Quadros 	emac->port_id = port;
538511f6c1aSRoger Quadros 
539511f6c1aSRoger Quadros 	/* by default eth_type is EMAC */
540511f6c1aSRoger Quadros 	switch (port) {
541511f6c1aSRoger Quadros 	case PRUETH_PORT_MII0:
542*a99b5657SRoger Quadros 		emac->dram = PRUETH_MEM_DRAM0;
543511f6c1aSRoger Quadros 		emac->pru = prueth->pru0;
544511f6c1aSRoger Quadros 		break;
545511f6c1aSRoger Quadros 	case PRUETH_PORT_MII1:
546*a99b5657SRoger Quadros 		emac->dram = PRUETH_MEM_DRAM1;
547511f6c1aSRoger Quadros 		emac->pru = prueth->pru1;
548511f6c1aSRoger Quadros 		break;
549511f6c1aSRoger Quadros 	default:
550511f6c1aSRoger Quadros 		return -EINVAL;
551511f6c1aSRoger Quadros 	}
552511f6c1aSRoger Quadros 	/* get mac address from DT and set private and netdev addr */
553511f6c1aSRoger Quadros 	ret = of_get_ethdev_address(eth_node, ndev);
554511f6c1aSRoger Quadros 	if (!is_valid_ether_addr(ndev->dev_addr)) {
555511f6c1aSRoger Quadros 		eth_hw_addr_random(ndev);
556511f6c1aSRoger Quadros 		dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
557511f6c1aSRoger Quadros 			 port, ndev->dev_addr);
558511f6c1aSRoger Quadros 	}
559511f6c1aSRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
560511f6c1aSRoger Quadros 
561511f6c1aSRoger Quadros 	/* connect PHY */
562511f6c1aSRoger Quadros 	emac->phydev = of_phy_get_and_connect(ndev, eth_node,
563511f6c1aSRoger Quadros 					      icssm_emac_adjust_link);
564511f6c1aSRoger Quadros 	if (!emac->phydev) {
565511f6c1aSRoger Quadros 		dev_dbg(prueth->dev, "PHY connection failed\n");
566511f6c1aSRoger Quadros 		ret = -ENODEV;
567511f6c1aSRoger Quadros 		goto free;
568511f6c1aSRoger Quadros 	}
569511f6c1aSRoger Quadros 
570511f6c1aSRoger Quadros 	/* remove unsupported modes */
571511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
572511f6c1aSRoger Quadros 
573511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
574511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
575511f6c1aSRoger Quadros 
576511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
577511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
578511f6c1aSRoger Quadros 
579511f6c1aSRoger Quadros 	ndev->dev.of_node = eth_node;
580511f6c1aSRoger Quadros 	ndev->netdev_ops = &emac_netdev_ops;
581511f6c1aSRoger Quadros 
582511f6c1aSRoger Quadros 	return 0;
583511f6c1aSRoger Quadros free:
584511f6c1aSRoger Quadros 	emac->ndev = NULL;
585511f6c1aSRoger Quadros 	prueth->emac[mac] = NULL;
586511f6c1aSRoger Quadros 
587511f6c1aSRoger Quadros 	return ret;
588511f6c1aSRoger Quadros }
589511f6c1aSRoger Quadros 
590511f6c1aSRoger Quadros static void icssm_prueth_netdev_exit(struct prueth *prueth,
591511f6c1aSRoger Quadros 				     struct device_node *eth_node)
592511f6c1aSRoger Quadros {
593511f6c1aSRoger Quadros 	struct prueth_emac *emac;
594511f6c1aSRoger Quadros 	enum prueth_mac mac;
595511f6c1aSRoger Quadros 
596511f6c1aSRoger Quadros 	mac = icssm_prueth_node_mac(eth_node);
597511f6c1aSRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
598511f6c1aSRoger Quadros 		return;
599511f6c1aSRoger Quadros 
600511f6c1aSRoger Quadros 	emac = prueth->emac[mac];
601511f6c1aSRoger Quadros 	if (!emac)
602511f6c1aSRoger Quadros 		return;
603511f6c1aSRoger Quadros 
604511f6c1aSRoger Quadros 	phy_disconnect(emac->phydev);
605511f6c1aSRoger Quadros 
606511f6c1aSRoger Quadros 	prueth->emac[mac] = NULL;
607511f6c1aSRoger Quadros }
608511f6c1aSRoger Quadros 
609511f6c1aSRoger Quadros static int icssm_prueth_probe(struct platform_device *pdev)
610511f6c1aSRoger Quadros {
611511f6c1aSRoger Quadros 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
612511f6c1aSRoger Quadros 	struct device_node *eth_node, *eth_ports_node;
613511f6c1aSRoger Quadros 	enum pruss_pru_id pruss_id0, pruss_id1;
614511f6c1aSRoger Quadros 	struct device *dev = &pdev->dev;
615511f6c1aSRoger Quadros 	struct device_node *np;
616511f6c1aSRoger Quadros 	struct prueth *prueth;
617*a99b5657SRoger Quadros 	struct pruss *pruss;
618511f6c1aSRoger Quadros 	int i, ret;
619511f6c1aSRoger Quadros 
620511f6c1aSRoger Quadros 	np = dev->of_node;
621511f6c1aSRoger Quadros 	if (!np)
622511f6c1aSRoger Quadros 		return -ENODEV; /* we don't support non DT */
623511f6c1aSRoger Quadros 
624511f6c1aSRoger Quadros 	prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
625511f6c1aSRoger Quadros 	if (!prueth)
626511f6c1aSRoger Quadros 		return -ENOMEM;
627511f6c1aSRoger Quadros 
628511f6c1aSRoger Quadros 	platform_set_drvdata(pdev, prueth);
629511f6c1aSRoger Quadros 	prueth->dev = dev;
630511f6c1aSRoger Quadros 	prueth->fw_data = device_get_match_data(dev);
631511f6c1aSRoger Quadros 
632511f6c1aSRoger Quadros 	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
633511f6c1aSRoger Quadros 	if (!eth_ports_node)
634511f6c1aSRoger Quadros 		return -ENOENT;
635511f6c1aSRoger Quadros 
636511f6c1aSRoger Quadros 	for_each_child_of_node(eth_ports_node, eth_node) {
637511f6c1aSRoger Quadros 		u32 reg;
638511f6c1aSRoger Quadros 
639511f6c1aSRoger Quadros 		if (strcmp(eth_node->name, "ethernet-port"))
640511f6c1aSRoger Quadros 			continue;
641511f6c1aSRoger Quadros 		ret = of_property_read_u32(eth_node, "reg", &reg);
642511f6c1aSRoger Quadros 		if (ret < 0) {
643511f6c1aSRoger Quadros 			dev_err(dev, "%pOF error reading port_id %d\n",
644511f6c1aSRoger Quadros 				eth_node, ret);
645511f6c1aSRoger Quadros 			of_node_put(eth_node);
646511f6c1aSRoger Quadros 			return ret;
647511f6c1aSRoger Quadros 		}
648511f6c1aSRoger Quadros 
649511f6c1aSRoger Quadros 		of_node_get(eth_node);
650511f6c1aSRoger Quadros 
651511f6c1aSRoger Quadros 		if (reg == 0 && !eth0_node) {
652511f6c1aSRoger Quadros 			eth0_node = eth_node;
653511f6c1aSRoger Quadros 			if (!of_device_is_available(eth0_node)) {
654511f6c1aSRoger Quadros 				of_node_put(eth0_node);
655511f6c1aSRoger Quadros 				eth0_node = NULL;
656511f6c1aSRoger Quadros 			}
657511f6c1aSRoger Quadros 		} else if (reg == 1 && !eth1_node) {
658511f6c1aSRoger Quadros 			eth1_node = eth_node;
659511f6c1aSRoger Quadros 			if (!of_device_is_available(eth1_node)) {
660511f6c1aSRoger Quadros 				of_node_put(eth1_node);
661511f6c1aSRoger Quadros 				eth1_node = NULL;
662511f6c1aSRoger Quadros 			}
663511f6c1aSRoger Quadros 		} else {
664511f6c1aSRoger Quadros 			if (reg == 0 || reg == 1)
665511f6c1aSRoger Quadros 				dev_err(dev, "duplicate port reg value: %d\n",
666511f6c1aSRoger Quadros 					reg);
667511f6c1aSRoger Quadros 			else
668511f6c1aSRoger Quadros 				dev_err(dev, "invalid port reg value: %d\n",
669511f6c1aSRoger Quadros 					reg);
670511f6c1aSRoger Quadros 
671511f6c1aSRoger Quadros 			of_node_put(eth_node);
672511f6c1aSRoger Quadros 		}
673511f6c1aSRoger Quadros 	}
674511f6c1aSRoger Quadros 
675511f6c1aSRoger Quadros 	of_node_put(eth_ports_node);
676511f6c1aSRoger Quadros 
677511f6c1aSRoger Quadros 	/* At least one node must be present and available else we fail */
678511f6c1aSRoger Quadros 	if (!eth0_node && !eth1_node) {
679511f6c1aSRoger Quadros 		dev_err(dev, "neither port0 nor port1 node available\n");
680511f6c1aSRoger Quadros 		return -ENODEV;
681511f6c1aSRoger Quadros 	}
682511f6c1aSRoger Quadros 
683511f6c1aSRoger Quadros 	prueth->eth_node[PRUETH_MAC0] = eth0_node;
684511f6c1aSRoger Quadros 	prueth->eth_node[PRUETH_MAC1] = eth1_node;
685511f6c1aSRoger Quadros 
686*a99b5657SRoger Quadros 	prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");
687*a99b5657SRoger Quadros 	if (IS_ERR(prueth->mii_rt)) {
688*a99b5657SRoger Quadros 		dev_err(dev, "couldn't get mii-rt syscon regmap\n");
689*a99b5657SRoger Quadros 		return -ENODEV;
690*a99b5657SRoger Quadros 	}
691*a99b5657SRoger Quadros 
692511f6c1aSRoger Quadros 	if (eth0_node) {
693511f6c1aSRoger Quadros 		prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0);
694511f6c1aSRoger Quadros 		if (IS_ERR(prueth->pru0)) {
695511f6c1aSRoger Quadros 			ret = PTR_ERR(prueth->pru0);
696511f6c1aSRoger Quadros 			dev_err_probe(dev, ret, "unable to get PRU0");
697511f6c1aSRoger Quadros 			goto put_pru;
698511f6c1aSRoger Quadros 		}
699511f6c1aSRoger Quadros 	}
700511f6c1aSRoger Quadros 
701511f6c1aSRoger Quadros 	if (eth1_node) {
702511f6c1aSRoger Quadros 		prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1);
703511f6c1aSRoger Quadros 		if (IS_ERR(prueth->pru1)) {
704511f6c1aSRoger Quadros 			ret = PTR_ERR(prueth->pru1);
705511f6c1aSRoger Quadros 			dev_err_probe(dev, ret, "unable to get PRU1");
706511f6c1aSRoger Quadros 			goto put_pru;
707511f6c1aSRoger Quadros 		}
708511f6c1aSRoger Quadros 	}
709511f6c1aSRoger Quadros 
710*a99b5657SRoger Quadros 	pruss = pruss_get(prueth->pru0 ? prueth->pru0 : prueth->pru1);
711*a99b5657SRoger Quadros 	if (IS_ERR(pruss)) {
712*a99b5657SRoger Quadros 		ret = PTR_ERR(pruss);
713*a99b5657SRoger Quadros 		dev_err(dev, "unable to get pruss handle\n");
714*a99b5657SRoger Quadros 		goto put_pru;
715*a99b5657SRoger Quadros 	}
716*a99b5657SRoger Quadros 	prueth->pruss = pruss;
717*a99b5657SRoger Quadros 
718*a99b5657SRoger Quadros 	/* Configure PRUSS */
719*a99b5657SRoger Quadros 	if (eth0_node)
720*a99b5657SRoger Quadros 		pruss_cfg_gpimode(pruss, pruss_id0, PRUSS_GPI_MODE_MII);
721*a99b5657SRoger Quadros 	if (eth1_node)
722*a99b5657SRoger Quadros 		pruss_cfg_gpimode(pruss, pruss_id1, PRUSS_GPI_MODE_MII);
723*a99b5657SRoger Quadros 	pruss_cfg_miirt_enable(pruss, true);
724*a99b5657SRoger Quadros 	pruss_cfg_xfr_enable(pruss, PRU_TYPE_PRU, true);
725*a99b5657SRoger Quadros 
726*a99b5657SRoger Quadros 	/* Get PRUSS mem resources */
727*a99b5657SRoger Quadros 	/* OCMC is system resource which we get separately */
728*a99b5657SRoger Quadros 	for (i = 0; i < ARRAY_SIZE(pruss_mem_ids); i++) {
729*a99b5657SRoger Quadros 		/* skip appropriate DRAM if not required */
730*a99b5657SRoger Quadros 		if (!eth0_node && i == PRUETH_MEM_DRAM0)
731*a99b5657SRoger Quadros 			continue;
732*a99b5657SRoger Quadros 
733*a99b5657SRoger Quadros 		if (!eth1_node && i == PRUETH_MEM_DRAM1)
734*a99b5657SRoger Quadros 			continue;
735*a99b5657SRoger Quadros 
736*a99b5657SRoger Quadros 		ret = pruss_request_mem_region(pruss, pruss_mem_ids[i],
737*a99b5657SRoger Quadros 					       &prueth->mem[i]);
738*a99b5657SRoger Quadros 		if (ret) {
739*a99b5657SRoger Quadros 			dev_err(dev, "unable to get PRUSS resource %d: %d\n",
740*a99b5657SRoger Quadros 				i, ret);
741*a99b5657SRoger Quadros 			goto put_mem;
742*a99b5657SRoger Quadros 		}
743*a99b5657SRoger Quadros 	}
744*a99b5657SRoger Quadros 
745*a99b5657SRoger Quadros 	prueth->sram_pool = of_gen_pool_get(np, "sram", 0);
746*a99b5657SRoger Quadros 	if (!prueth->sram_pool) {
747*a99b5657SRoger Quadros 		dev_err(dev, "unable to get SRAM pool\n");
748*a99b5657SRoger Quadros 		ret = -ENODEV;
749*a99b5657SRoger Quadros 		goto put_mem;
750*a99b5657SRoger Quadros 	}
751*a99b5657SRoger Quadros 
752*a99b5657SRoger Quadros 	prueth->ocmc_ram_size = OCMC_RAM_SIZE;
753*a99b5657SRoger Quadros 	/* Decreased by 8KB to address the reserved region for AM33x */
754*a99b5657SRoger Quadros 	if (prueth->fw_data->driver_data == PRUSS_AM33XX)
755*a99b5657SRoger Quadros 		prueth->ocmc_ram_size = (SZ_64K - SZ_8K);
756*a99b5657SRoger Quadros 
757*a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].va =
758*a99b5657SRoger Quadros 			(void __iomem *)gen_pool_alloc(prueth->sram_pool,
759*a99b5657SRoger Quadros 						       prueth->ocmc_ram_size);
760*a99b5657SRoger Quadros 	if (!prueth->mem[PRUETH_MEM_OCMC].va) {
761*a99b5657SRoger Quadros 		dev_err(dev, "unable to allocate OCMC resource\n");
762*a99b5657SRoger Quadros 		ret = -ENOMEM;
763*a99b5657SRoger Quadros 		goto put_mem;
764*a99b5657SRoger Quadros 	}
765*a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].pa = gen_pool_virt_to_phys
766*a99b5657SRoger Quadros 		(prueth->sram_pool, (unsigned long)
767*a99b5657SRoger Quadros 		 prueth->mem[PRUETH_MEM_OCMC].va);
768*a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].size = prueth->ocmc_ram_size;
769*a99b5657SRoger Quadros 	dev_dbg(dev, "ocmc: pa %pa va %p size %#zx\n",
770*a99b5657SRoger Quadros 		&prueth->mem[PRUETH_MEM_OCMC].pa,
771*a99b5657SRoger Quadros 		prueth->mem[PRUETH_MEM_OCMC].va,
772*a99b5657SRoger Quadros 		prueth->mem[PRUETH_MEM_OCMC].size);
773*a99b5657SRoger Quadros 
774511f6c1aSRoger Quadros 	/* setup netdev interfaces */
775511f6c1aSRoger Quadros 	if (eth0_node) {
776511f6c1aSRoger Quadros 		ret = icssm_prueth_netdev_init(prueth, eth0_node);
777511f6c1aSRoger Quadros 		if (ret) {
778511f6c1aSRoger Quadros 			if (ret != -EPROBE_DEFER) {
779511f6c1aSRoger Quadros 				dev_err(dev, "netdev init %s failed: %d\n",
780511f6c1aSRoger Quadros 					eth0_node->name, ret);
781511f6c1aSRoger Quadros 			}
782*a99b5657SRoger Quadros 			goto free_pool;
783511f6c1aSRoger Quadros 		}
784511f6c1aSRoger Quadros 	}
785511f6c1aSRoger Quadros 
786511f6c1aSRoger Quadros 	if (eth1_node) {
787511f6c1aSRoger Quadros 		ret = icssm_prueth_netdev_init(prueth, eth1_node);
788511f6c1aSRoger Quadros 		if (ret) {
789511f6c1aSRoger Quadros 			if (ret != -EPROBE_DEFER) {
790511f6c1aSRoger Quadros 				dev_err(dev, "netdev init %s failed: %d\n",
791511f6c1aSRoger Quadros 					eth1_node->name, ret);
792511f6c1aSRoger Quadros 			}
793511f6c1aSRoger Quadros 			goto netdev_exit;
794511f6c1aSRoger Quadros 		}
795511f6c1aSRoger Quadros 	}
796511f6c1aSRoger Quadros 
797511f6c1aSRoger Quadros 	/* register the network devices */
798511f6c1aSRoger Quadros 	if (eth0_node) {
799511f6c1aSRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);
800511f6c1aSRoger Quadros 		if (ret) {
801511f6c1aSRoger Quadros 			dev_err(dev, "can't register netdev for port MII0");
802511f6c1aSRoger Quadros 			goto netdev_exit;
803511f6c1aSRoger Quadros 		}
804511f6c1aSRoger Quadros 
805511f6c1aSRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC0] =
806511f6c1aSRoger Quadros 			prueth->emac[PRUETH_MAC0]->ndev;
807511f6c1aSRoger Quadros 	}
808511f6c1aSRoger Quadros 
809511f6c1aSRoger Quadros 	if (eth1_node) {
810511f6c1aSRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);
811511f6c1aSRoger Quadros 		if (ret) {
812511f6c1aSRoger Quadros 			dev_err(dev, "can't register netdev for port MII1");
813511f6c1aSRoger Quadros 			goto netdev_unregister;
814511f6c1aSRoger Quadros 		}
815511f6c1aSRoger Quadros 
816511f6c1aSRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC1] =
817511f6c1aSRoger Quadros 			prueth->emac[PRUETH_MAC1]->ndev;
818511f6c1aSRoger Quadros 	}
819511f6c1aSRoger Quadros 
820*a99b5657SRoger Quadros 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
821*a99b5657SRoger Quadros 		 (!eth0_node || !eth1_node) ? "single" : "dual");
822*a99b5657SRoger Quadros 
823511f6c1aSRoger Quadros 	if (eth1_node)
824511f6c1aSRoger Quadros 		of_node_put(eth1_node);
825511f6c1aSRoger Quadros 	if (eth0_node)
826511f6c1aSRoger Quadros 		of_node_put(eth0_node);
827511f6c1aSRoger Quadros 	return 0;
828511f6c1aSRoger Quadros 
829511f6c1aSRoger Quadros netdev_unregister:
830511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
831511f6c1aSRoger Quadros 		if (!prueth->registered_netdevs[i])
832511f6c1aSRoger Quadros 			continue;
833511f6c1aSRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
834511f6c1aSRoger Quadros 	}
835511f6c1aSRoger Quadros 
836511f6c1aSRoger Quadros netdev_exit:
837511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
838511f6c1aSRoger Quadros 		eth_node = prueth->eth_node[i];
839511f6c1aSRoger Quadros 		if (!eth_node)
840511f6c1aSRoger Quadros 			continue;
841511f6c1aSRoger Quadros 
842511f6c1aSRoger Quadros 		icssm_prueth_netdev_exit(prueth, eth_node);
843511f6c1aSRoger Quadros 	}
844511f6c1aSRoger Quadros 
845*a99b5657SRoger Quadros free_pool:
846*a99b5657SRoger Quadros 	gen_pool_free(prueth->sram_pool,
847*a99b5657SRoger Quadros 		      (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va,
848*a99b5657SRoger Quadros 		      prueth->ocmc_ram_size);
849*a99b5657SRoger Quadros 
850*a99b5657SRoger Quadros put_mem:
851*a99b5657SRoger Quadros 	for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) {
852*a99b5657SRoger Quadros 		if (prueth->mem[i].va)
853*a99b5657SRoger Quadros 			pruss_release_mem_region(pruss, &prueth->mem[i]);
854*a99b5657SRoger Quadros 	}
855*a99b5657SRoger Quadros 	pruss_put(prueth->pruss);
856*a99b5657SRoger Quadros 
857511f6c1aSRoger Quadros put_pru:
858511f6c1aSRoger Quadros 	if (eth1_node) {
859511f6c1aSRoger Quadros 		if (prueth->pru1)
860511f6c1aSRoger Quadros 			pru_rproc_put(prueth->pru1);
861511f6c1aSRoger Quadros 		of_node_put(eth1_node);
862511f6c1aSRoger Quadros 	}
863511f6c1aSRoger Quadros 
864511f6c1aSRoger Quadros 	if (eth0_node) {
865511f6c1aSRoger Quadros 		if (prueth->pru0)
866511f6c1aSRoger Quadros 			pru_rproc_put(prueth->pru0);
867511f6c1aSRoger Quadros 		of_node_put(eth0_node);
868511f6c1aSRoger Quadros 	}
869511f6c1aSRoger Quadros 
870511f6c1aSRoger Quadros 	return ret;
871511f6c1aSRoger Quadros }
872511f6c1aSRoger Quadros 
873511f6c1aSRoger Quadros static void icssm_prueth_remove(struct platform_device *pdev)
874511f6c1aSRoger Quadros {
875511f6c1aSRoger Quadros 	struct prueth *prueth = platform_get_drvdata(pdev);
876511f6c1aSRoger Quadros 	struct device_node *eth_node;
877511f6c1aSRoger Quadros 	int i;
878511f6c1aSRoger Quadros 
879511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
880511f6c1aSRoger Quadros 		if (!prueth->registered_netdevs[i])
881511f6c1aSRoger Quadros 			continue;
882511f6c1aSRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
883511f6c1aSRoger Quadros 	}
884511f6c1aSRoger Quadros 
885511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
886511f6c1aSRoger Quadros 		eth_node = prueth->eth_node[i];
887511f6c1aSRoger Quadros 		if (!eth_node)
888511f6c1aSRoger Quadros 			continue;
889511f6c1aSRoger Quadros 
890511f6c1aSRoger Quadros 		icssm_prueth_netdev_exit(prueth, eth_node);
891511f6c1aSRoger Quadros 		of_node_put(eth_node);
892511f6c1aSRoger Quadros 	}
893511f6c1aSRoger Quadros 
894*a99b5657SRoger Quadros 	gen_pool_free(prueth->sram_pool,
895*a99b5657SRoger Quadros 		      (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va,
896*a99b5657SRoger Quadros 		      prueth->ocmc_ram_size);
897*a99b5657SRoger Quadros 
898*a99b5657SRoger Quadros 	for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) {
899*a99b5657SRoger Quadros 		if (prueth->mem[i].va)
900*a99b5657SRoger Quadros 			pruss_release_mem_region(prueth->pruss,
901*a99b5657SRoger Quadros 						 &prueth->mem[i]);
902*a99b5657SRoger Quadros 	}
903*a99b5657SRoger Quadros 
904511f6c1aSRoger Quadros 	pruss_put(prueth->pruss);
905511f6c1aSRoger Quadros 
906511f6c1aSRoger Quadros 	if (prueth->eth_node[PRUETH_MAC0])
907511f6c1aSRoger Quadros 		pru_rproc_put(prueth->pru0);
908511f6c1aSRoger Quadros 	if (prueth->eth_node[PRUETH_MAC1])
909511f6c1aSRoger Quadros 		pru_rproc_put(prueth->pru1);
910511f6c1aSRoger Quadros }
911511f6c1aSRoger Quadros 
912511f6c1aSRoger Quadros #ifdef CONFIG_PM_SLEEP
913511f6c1aSRoger Quadros static int icssm_prueth_suspend(struct device *dev)
914511f6c1aSRoger Quadros {
915511f6c1aSRoger Quadros 	struct prueth *prueth = dev_get_drvdata(dev);
916511f6c1aSRoger Quadros 	struct net_device *ndev;
917511f6c1aSRoger Quadros 	int i, ret;
918511f6c1aSRoger Quadros 
919511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
920511f6c1aSRoger Quadros 		ndev = prueth->registered_netdevs[i];
921511f6c1aSRoger Quadros 
922511f6c1aSRoger Quadros 		if (!ndev)
923511f6c1aSRoger Quadros 			continue;
924511f6c1aSRoger Quadros 
925511f6c1aSRoger Quadros 		if (netif_running(ndev)) {
926511f6c1aSRoger Quadros 			netif_device_detach(ndev);
927511f6c1aSRoger Quadros 			ret = icssm_emac_ndo_stop(ndev);
928511f6c1aSRoger Quadros 			if (ret < 0) {
929511f6c1aSRoger Quadros 				netdev_err(ndev, "failed to stop: %d", ret);
930511f6c1aSRoger Quadros 				return ret;
931511f6c1aSRoger Quadros 			}
932511f6c1aSRoger Quadros 		}
933511f6c1aSRoger Quadros 	}
934511f6c1aSRoger Quadros 
935511f6c1aSRoger Quadros 	return 0;
936511f6c1aSRoger Quadros }
937511f6c1aSRoger Quadros 
938511f6c1aSRoger Quadros static int icssm_prueth_resume(struct device *dev)
939511f6c1aSRoger Quadros {
940511f6c1aSRoger Quadros 	struct prueth *prueth = dev_get_drvdata(dev);
941511f6c1aSRoger Quadros 	struct net_device *ndev;
942511f6c1aSRoger Quadros 	int i, ret;
943511f6c1aSRoger Quadros 
944511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
945511f6c1aSRoger Quadros 		ndev = prueth->registered_netdevs[i];
946511f6c1aSRoger Quadros 
947511f6c1aSRoger Quadros 		if (!ndev)
948511f6c1aSRoger Quadros 			continue;
949511f6c1aSRoger Quadros 
950511f6c1aSRoger Quadros 		if (netif_running(ndev)) {
951511f6c1aSRoger Quadros 			ret = icssm_emac_ndo_open(ndev);
952511f6c1aSRoger Quadros 			if (ret < 0) {
953511f6c1aSRoger Quadros 				netdev_err(ndev, "failed to start: %d", ret);
954511f6c1aSRoger Quadros 				return ret;
955511f6c1aSRoger Quadros 			}
956511f6c1aSRoger Quadros 			netif_device_attach(ndev);
957511f6c1aSRoger Quadros 		}
958511f6c1aSRoger Quadros 	}
959511f6c1aSRoger Quadros 
960511f6c1aSRoger Quadros 	return 0;
961511f6c1aSRoger Quadros }
962511f6c1aSRoger Quadros 
963511f6c1aSRoger Quadros #endif /* CONFIG_PM_SLEEP */
964511f6c1aSRoger Quadros 
965511f6c1aSRoger Quadros static const struct dev_pm_ops prueth_dev_pm_ops = {
966511f6c1aSRoger Quadros 	SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume)
967511f6c1aSRoger Quadros };
968511f6c1aSRoger Quadros 
969511f6c1aSRoger Quadros /* AM335x SoC-specific firmware data */
970511f6c1aSRoger Quadros static struct prueth_private_data am335x_prueth_pdata = {
971*a99b5657SRoger Quadros 	.driver_data = PRUSS_AM33XX,
972511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
973511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
974511f6c1aSRoger Quadros 			"ti-pruss/am335x-pru0-prueth-fw.elf",
975511f6c1aSRoger Quadros 	},
976511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
977511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
978511f6c1aSRoger Quadros 			"ti-pruss/am335x-pru1-prueth-fw.elf",
979511f6c1aSRoger Quadros 	},
980511f6c1aSRoger Quadros };
981511f6c1aSRoger Quadros 
982511f6c1aSRoger Quadros /* AM437x SoC-specific firmware data */
983511f6c1aSRoger Quadros static struct prueth_private_data am437x_prueth_pdata = {
984*a99b5657SRoger Quadros 	.driver_data = PRUSS_AM43XX,
985511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
986511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
987511f6c1aSRoger Quadros 			"ti-pruss/am437x-pru0-prueth-fw.elf",
988511f6c1aSRoger Quadros 	},
989511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
990511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
991511f6c1aSRoger Quadros 			"ti-pruss/am437x-pru1-prueth-fw.elf",
992511f6c1aSRoger Quadros 	},
993511f6c1aSRoger Quadros };
994511f6c1aSRoger Quadros 
995511f6c1aSRoger Quadros /* AM57xx SoC-specific firmware data */
996511f6c1aSRoger Quadros static struct prueth_private_data am57xx_prueth_pdata = {
997*a99b5657SRoger Quadros 	.driver_data = PRUSS_AM57XX,
998511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
999511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1000511f6c1aSRoger Quadros 			"ti-pruss/am57xx-pru0-prueth-fw.elf",
1001511f6c1aSRoger Quadros 	},
1002511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
1003511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1004511f6c1aSRoger Quadros 			"ti-pruss/am57xx-pru1-prueth-fw.elf",
1005511f6c1aSRoger Quadros 	},
1006511f6c1aSRoger Quadros };
1007511f6c1aSRoger Quadros 
1008511f6c1aSRoger Quadros static const struct of_device_id prueth_dt_match[] = {
1009511f6c1aSRoger Quadros 	{ .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, },
1010511f6c1aSRoger Quadros 	{ .compatible = "ti,am4376-prueth", .data = &am437x_prueth_pdata, },
1011511f6c1aSRoger Quadros 	{ .compatible = "ti,am3359-prueth", .data = &am335x_prueth_pdata, },
1012511f6c1aSRoger Quadros 	{ /* sentinel */ }
1013511f6c1aSRoger Quadros };
1014511f6c1aSRoger Quadros MODULE_DEVICE_TABLE(of, prueth_dt_match);
1015511f6c1aSRoger Quadros 
1016511f6c1aSRoger Quadros static struct platform_driver prueth_driver = {
1017511f6c1aSRoger Quadros 	.probe = icssm_prueth_probe,
1018511f6c1aSRoger Quadros 	.remove = icssm_prueth_remove,
1019511f6c1aSRoger Quadros 	.driver = {
1020511f6c1aSRoger Quadros 		.name = "prueth",
1021511f6c1aSRoger Quadros 		.of_match_table = prueth_dt_match,
1022511f6c1aSRoger Quadros 		.pm = &prueth_dev_pm_ops,
1023511f6c1aSRoger Quadros 	},
1024511f6c1aSRoger Quadros };
1025511f6c1aSRoger Quadros module_platform_driver(prueth_driver);
1026511f6c1aSRoger Quadros 
1027511f6c1aSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
1028511f6c1aSRoger Quadros MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
1029511f6c1aSRoger Quadros MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver");
1030511f6c1aSRoger Quadros MODULE_LICENSE("GPL");
1031