xref: /linux/drivers/net/ethernet/ti/icssm/icssm_prueth.c (revision e15472e8f2e7eb2abf9059bba3797463f4f6d2d5)
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"
32a99b5657SRoger Quadros #include "../icssg/icssg_mii_rt.h"
33a99b5657SRoger Quadros 
34a99b5657SRoger Quadros #define OCMC_RAM_SIZE		(SZ_64K)
35a99b5657SRoger Quadros 
36a99b5657SRoger Quadros #define TX_START_DELAY		0x40
37a99b5657SRoger Quadros #define TX_CLK_DELAY_100M	0x6
38*e15472e8SRoger Quadros #define HR_TIMER_TX_DELAY_US	100
39*e15472e8SRoger Quadros 
40*e15472e8SRoger Quadros static void icssm_prueth_write_reg(struct prueth *prueth,
41*e15472e8SRoger Quadros 				   enum prueth_mem region,
42*e15472e8SRoger Quadros 				   unsigned int reg, u32 val)
43*e15472e8SRoger Quadros {
44*e15472e8SRoger Quadros 	writel_relaxed(val, prueth->mem[region].va + reg);
45*e15472e8SRoger Quadros }
46a99b5657SRoger Quadros 
47a99b5657SRoger Quadros /* Below macro is for 1528 Byte Frame support, to Allow even with
48a99b5657SRoger Quadros  * Redundancy tag
49a99b5657SRoger Quadros  */
50a99b5657SRoger Quadros #define PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC  (VLAN_ETH_FRAME_LEN + \
51a99b5657SRoger Quadros 						ETH_FCS_LEN + \
52a99b5657SRoger Quadros 						ICSSM_LRE_TAG_SIZE)
53a99b5657SRoger Quadros 
54a99b5657SRoger Quadros /* ensure that order of PRUSS mem regions is same as enum prueth_mem */
55a99b5657SRoger Quadros static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1,
56a99b5657SRoger Quadros 					  PRUSS_MEM_SHRD_RAM2 };
57a99b5657SRoger Quadros 
58a99b5657SRoger Quadros static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = {
59a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
60a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
61a99b5657SRoger Quadros 			P0_Q1_BUFFER_OFFSET,
62a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET,
63a99b5657SRoger Quadros 			P0_Q1_BD_OFFSET,
64a99b5657SRoger Quadros 			P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE),
65a99b5657SRoger Quadros 		},
66a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
67a99b5657SRoger Quadros 			P0_Q2_BUFFER_OFFSET,
68a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 8,
69a99b5657SRoger Quadros 			P0_Q2_BD_OFFSET,
70a99b5657SRoger Quadros 			P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE),
71a99b5657SRoger Quadros 		},
72a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
73a99b5657SRoger Quadros 			P0_Q3_BUFFER_OFFSET,
74a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 16,
75a99b5657SRoger Quadros 			P0_Q3_BD_OFFSET,
76a99b5657SRoger Quadros 			P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE),
77a99b5657SRoger Quadros 		},
78a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
79a99b5657SRoger Quadros 			P0_Q4_BUFFER_OFFSET,
80a99b5657SRoger Quadros 			HOST_QUEUE_DESC_OFFSET + 24,
81a99b5657SRoger Quadros 			P0_Q4_BD_OFFSET,
82a99b5657SRoger Quadros 			P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE),
83a99b5657SRoger Quadros 		},
84a99b5657SRoger Quadros 	},
85a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
86a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
87a99b5657SRoger Quadros 			P1_Q1_BUFFER_OFFSET,
88a99b5657SRoger Quadros 			P1_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) *
89a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
90a99b5657SRoger Quadros 			P1_Q1_BD_OFFSET,
91a99b5657SRoger Quadros 			P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
92a99b5657SRoger Quadros 		},
93a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
94a99b5657SRoger Quadros 			P1_Q2_BUFFER_OFFSET,
95a99b5657SRoger Quadros 			P1_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) *
96a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
97a99b5657SRoger Quadros 			P1_Q2_BD_OFFSET,
98a99b5657SRoger Quadros 			P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
99a99b5657SRoger Quadros 		},
100a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
101a99b5657SRoger Quadros 			P1_Q3_BUFFER_OFFSET,
102a99b5657SRoger Quadros 			P1_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) *
103a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
104a99b5657SRoger Quadros 			P1_Q3_BD_OFFSET,
105a99b5657SRoger Quadros 			P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
106a99b5657SRoger Quadros 		},
107a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
108a99b5657SRoger Quadros 			P1_Q4_BUFFER_OFFSET,
109a99b5657SRoger Quadros 			P1_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) *
110a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
111a99b5657SRoger Quadros 			P1_Q4_BD_OFFSET,
112a99b5657SRoger Quadros 			P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
113a99b5657SRoger Quadros 		},
114a99b5657SRoger Quadros 	},
115a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
116a99b5657SRoger Quadros 		[PRUETH_QUEUE1] = {
117a99b5657SRoger Quadros 			P2_Q1_BUFFER_OFFSET,
118a99b5657SRoger Quadros 			P2_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) *
119a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
120a99b5657SRoger Quadros 			P2_Q1_BD_OFFSET,
121a99b5657SRoger Quadros 			P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE),
122a99b5657SRoger Quadros 		},
123a99b5657SRoger Quadros 		[PRUETH_QUEUE2] = {
124a99b5657SRoger Quadros 			P2_Q2_BUFFER_OFFSET,
125a99b5657SRoger Quadros 			P2_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) *
126a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
127a99b5657SRoger Quadros 			P2_Q2_BD_OFFSET,
128a99b5657SRoger Quadros 			P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE),
129a99b5657SRoger Quadros 		},
130a99b5657SRoger Quadros 		[PRUETH_QUEUE3] = {
131a99b5657SRoger Quadros 			P2_Q3_BUFFER_OFFSET,
132a99b5657SRoger Quadros 			P2_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) *
133a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
134a99b5657SRoger Quadros 			P2_Q3_BD_OFFSET,
135a99b5657SRoger Quadros 			P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE),
136a99b5657SRoger Quadros 		},
137a99b5657SRoger Quadros 		[PRUETH_QUEUE4] = {
138a99b5657SRoger Quadros 			P2_Q4_BUFFER_OFFSET,
139a99b5657SRoger Quadros 			P2_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) *
140a99b5657SRoger Quadros 					ICSS_BLOCK_SIZE),
141a99b5657SRoger Quadros 			P2_Q4_BD_OFFSET,
142a99b5657SRoger Quadros 			P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE),
143a99b5657SRoger Quadros 		},
144a99b5657SRoger Quadros 	},
145a99b5657SRoger Quadros };
146a99b5657SRoger Quadros 
147a99b5657SRoger Quadros static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = {
148a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_HOST] = {
149a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, },
150a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, },
151a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q3_BD_OFFSET, .wr_ptr = P0_Q3_BD_OFFSET, },
152a99b5657SRoger Quadros 		{ .rd_ptr = P0_Q4_BD_OFFSET, .wr_ptr = P0_Q4_BD_OFFSET, },
153a99b5657SRoger Quadros 	},
154a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII0] = {
155a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q1_BD_OFFSET, .wr_ptr = P1_Q1_BD_OFFSET, },
156a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q2_BD_OFFSET, .wr_ptr = P1_Q2_BD_OFFSET, },
157a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q3_BD_OFFSET, .wr_ptr = P1_Q3_BD_OFFSET, },
158a99b5657SRoger Quadros 		{ .rd_ptr = P1_Q4_BD_OFFSET, .wr_ptr = P1_Q4_BD_OFFSET, },
159a99b5657SRoger Quadros 	},
160a99b5657SRoger Quadros 	[PRUETH_PORT_QUEUE_MII1] = {
161a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q1_BD_OFFSET, .wr_ptr = P2_Q1_BD_OFFSET, },
162a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q2_BD_OFFSET, .wr_ptr = P2_Q2_BD_OFFSET, },
163a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q3_BD_OFFSET, .wr_ptr = P2_Q3_BD_OFFSET, },
164a99b5657SRoger Quadros 		{ .rd_ptr = P2_Q4_BD_OFFSET, .wr_ptr = P2_Q4_BD_OFFSET, },
165a99b5657SRoger Quadros 	}
166a99b5657SRoger Quadros };
167a99b5657SRoger Quadros 
168a99b5657SRoger Quadros static void icssm_prueth_hostconfig(struct prueth *prueth)
169a99b5657SRoger Quadros {
170a99b5657SRoger Quadros 	void __iomem *sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
171a99b5657SRoger Quadros 	void __iomem *sram;
172a99b5657SRoger Quadros 
173a99b5657SRoger Quadros 	/* queue size lookup table */
174a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_SIZE_ADDR;
175a99b5657SRoger Quadros 	writew(HOST_QUEUE_1_SIZE, sram);
176a99b5657SRoger Quadros 	writew(HOST_QUEUE_2_SIZE, sram + 2);
177a99b5657SRoger Quadros 	writew(HOST_QUEUE_3_SIZE, sram + 4);
178a99b5657SRoger Quadros 	writew(HOST_QUEUE_4_SIZE, sram + 6);
179a99b5657SRoger Quadros 
180a99b5657SRoger Quadros 	/* queue information table */
181a99b5657SRoger Quadros 	sram = sram_base + HOST_Q1_RX_CONTEXT_OFFSET;
182a99b5657SRoger Quadros 	memcpy_toio(sram, queue_infos[PRUETH_PORT_QUEUE_HOST],
183a99b5657SRoger Quadros 		    sizeof(queue_infos[PRUETH_PORT_QUEUE_HOST]));
184a99b5657SRoger Quadros 
185a99b5657SRoger Quadros 	/* buffer offset table */
186a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_OFFSET_ADDR;
187a99b5657SRoger Quadros 	writew(P0_Q1_BUFFER_OFFSET, sram);
188a99b5657SRoger Quadros 	writew(P0_Q2_BUFFER_OFFSET, sram + 2);
189a99b5657SRoger Quadros 	writew(P0_Q3_BUFFER_OFFSET, sram + 4);
190a99b5657SRoger Quadros 	writew(P0_Q4_BUFFER_OFFSET, sram + 6);
191a99b5657SRoger Quadros 
192a99b5657SRoger Quadros 	/* buffer descriptor offset table*/
193a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR;
194a99b5657SRoger Quadros 	writew(P0_Q1_BD_OFFSET, sram);
195a99b5657SRoger Quadros 	writew(P0_Q2_BD_OFFSET, sram + 2);
196a99b5657SRoger Quadros 	writew(P0_Q3_BD_OFFSET, sram + 4);
197a99b5657SRoger Quadros 	writew(P0_Q4_BD_OFFSET, sram + 6);
198a99b5657SRoger Quadros 
199a99b5657SRoger Quadros 	/* queue table */
200a99b5657SRoger Quadros 	sram = sram_base + HOST_QUEUE_DESC_OFFSET;
201a99b5657SRoger Quadros 	memcpy_toio(sram, queue_descs[PRUETH_PORT_QUEUE_HOST],
202a99b5657SRoger Quadros 		    sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST]));
203a99b5657SRoger Quadros }
204a99b5657SRoger Quadros 
205a99b5657SRoger Quadros static void icssm_prueth_mii_init(struct prueth *prueth)
206a99b5657SRoger Quadros {
207a99b5657SRoger Quadros 	struct regmap *mii_rt;
208a99b5657SRoger Quadros 	u32 rxcfg_reg, rxcfg;
209a99b5657SRoger Quadros 	u32 txcfg_reg, txcfg;
210a99b5657SRoger Quadros 
211a99b5657SRoger Quadros 	mii_rt = prueth->mii_rt;
212a99b5657SRoger Quadros 
213a99b5657SRoger Quadros 	rxcfg = PRUSS_MII_RT_RXCFG_RX_ENABLE |
214a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS |
215a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_L2_EN |
216a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE |
217a99b5657SRoger Quadros 		PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS;
218a99b5657SRoger Quadros 
219a99b5657SRoger Quadros 	/* Configuration of Port 0 Rx */
220a99b5657SRoger Quadros 	rxcfg_reg = PRUSS_MII_RT_RXCFG0;
221a99b5657SRoger Quadros 
222a99b5657SRoger Quadros 	regmap_write(mii_rt, rxcfg_reg, rxcfg);
223a99b5657SRoger Quadros 
224a99b5657SRoger Quadros 	/* Configuration of Port 1 Rx */
225a99b5657SRoger Quadros 	rxcfg_reg = PRUSS_MII_RT_RXCFG1;
226a99b5657SRoger Quadros 
227a99b5657SRoger Quadros 	rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
228a99b5657SRoger Quadros 
229a99b5657SRoger Quadros 	regmap_write(mii_rt, rxcfg_reg, rxcfg);
230a99b5657SRoger Quadros 
231a99b5657SRoger Quadros 	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
232a99b5657SRoger Quadros 		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
233a99b5657SRoger Quadros 		PRUSS_MII_RT_TXCFG_TX_32_MODE_EN |
234a99b5657SRoger Quadros 		(TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) |
235a99b5657SRoger Quadros 		(TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT);
236a99b5657SRoger Quadros 
237a99b5657SRoger Quadros 	/* Configuration of Port 0 Tx */
238a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_TXCFG0;
239a99b5657SRoger Quadros 
240a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
241a99b5657SRoger Quadros 
242a99b5657SRoger Quadros 	txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
243a99b5657SRoger Quadros 
244a99b5657SRoger Quadros 	/* Configuration of Port 1 Tx */
245a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_TXCFG1;
246a99b5657SRoger Quadros 
247a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
248a99b5657SRoger Quadros 
249a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_RX_FRMS0;
250a99b5657SRoger Quadros 
251a99b5657SRoger Quadros 	/* Min frame length should be set to 64 to allow receive of standard
252a99b5657SRoger Quadros 	 * Ethernet frames such as PTP, LLDP that will not have the tag/rct.
253a99b5657SRoger Quadros 	 * Actual size written to register is size - 1 per TRM. This also
254a99b5657SRoger Quadros 	 * includes CRC/FCS.
255a99b5657SRoger Quadros 	 */
256a99b5657SRoger Quadros 	txcfg = FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK,
257a99b5657SRoger Quadros 			   (PRUSS_MII_RT_RX_FRMS_MIN_FRM - 1));
258a99b5657SRoger Quadros 
259a99b5657SRoger Quadros 	/* For EMAC, set Max frame size to 1528 i.e size with VLAN.
260a99b5657SRoger Quadros 	 * Actual size written to register is size - 1 as per TRM.
261a99b5657SRoger Quadros 	 * Since driver support run time change of protocol, driver
262a99b5657SRoger Quadros 	 * must overwrite the values based on Ethernet type.
263a99b5657SRoger Quadros 	 */
264a99b5657SRoger Quadros 	txcfg |= FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK,
265a99b5657SRoger Quadros 			    (PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC - 1));
266a99b5657SRoger Quadros 
267a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
268a99b5657SRoger Quadros 
269a99b5657SRoger Quadros 	txcfg_reg = PRUSS_MII_RT_RX_FRMS1;
270a99b5657SRoger Quadros 
271a99b5657SRoger Quadros 	regmap_write(mii_rt, txcfg_reg, txcfg);
272a99b5657SRoger Quadros }
273a99b5657SRoger Quadros 
274a99b5657SRoger Quadros static void icssm_prueth_clearmem(struct prueth *prueth, enum prueth_mem region)
275a99b5657SRoger Quadros {
276a99b5657SRoger Quadros 	memset_io(prueth->mem[region].va, 0, prueth->mem[region].size);
277a99b5657SRoger Quadros }
278a99b5657SRoger Quadros 
279a99b5657SRoger Quadros static void icssm_prueth_hostinit(struct prueth *prueth)
280a99b5657SRoger Quadros {
281a99b5657SRoger Quadros 	/* Clear shared RAM */
282a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, PRUETH_MEM_SHARED_RAM);
283a99b5657SRoger Quadros 
284a99b5657SRoger Quadros 	/* Clear OCMC RAM */
285a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, PRUETH_MEM_OCMC);
286a99b5657SRoger Quadros 
287a99b5657SRoger Quadros 	/* Clear data RAMs */
288a99b5657SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC0])
289a99b5657SRoger Quadros 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM0);
290a99b5657SRoger Quadros 	if (prueth->eth_node[PRUETH_MAC1])
291a99b5657SRoger Quadros 		icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1);
292a99b5657SRoger Quadros 
293a99b5657SRoger Quadros 	/* Initialize host queues in shared RAM */
294a99b5657SRoger Quadros 	icssm_prueth_hostconfig(prueth);
295a99b5657SRoger Quadros 
296a99b5657SRoger Quadros 	/* Configure MII_RT */
297a99b5657SRoger Quadros 	icssm_prueth_mii_init(prueth);
298a99b5657SRoger Quadros }
299a99b5657SRoger Quadros 
300*e15472e8SRoger Quadros /* This function initialize the driver in EMAC mode
301a99b5657SRoger Quadros  * based on eth_type
302a99b5657SRoger Quadros  */
303a99b5657SRoger Quadros static void icssm_prueth_init_ethernet_mode(struct prueth *prueth)
304a99b5657SRoger Quadros {
305a99b5657SRoger Quadros 	icssm_prueth_hostinit(prueth);
306a99b5657SRoger Quadros }
307a99b5657SRoger Quadros 
308*e15472e8SRoger Quadros static void icssm_prueth_port_enable(struct prueth_emac *emac, bool enable)
309*e15472e8SRoger Quadros {
310*e15472e8SRoger Quadros 	struct prueth *prueth = emac->prueth;
311*e15472e8SRoger Quadros 	void __iomem *port_ctrl;
312*e15472e8SRoger Quadros 	void __iomem *ram;
313*e15472e8SRoger Quadros 
314*e15472e8SRoger Quadros 	ram = prueth->mem[emac->dram].va;
315*e15472e8SRoger Quadros 	port_ctrl = ram + PORT_CONTROL_ADDR;
316*e15472e8SRoger Quadros 	writeb(!!enable, port_ctrl);
317*e15472e8SRoger Quadros }
318*e15472e8SRoger Quadros 
319a99b5657SRoger Quadros static int icssm_prueth_emac_config(struct prueth_emac *emac)
320a99b5657SRoger Quadros {
321a99b5657SRoger Quadros 	struct prueth *prueth = emac->prueth;
322a99b5657SRoger Quadros 	u32 sharedramaddr, ocmcaddr;
323a99b5657SRoger Quadros 	void __iomem *dram_base;
324a99b5657SRoger Quadros 	void __iomem *mac_addr;
325a99b5657SRoger Quadros 	void __iomem *dram;
326*e15472e8SRoger Quadros 	void __iomem *sram;
327a99b5657SRoger Quadros 
328a99b5657SRoger Quadros 	/* PRU needs local shared RAM address for C28 */
329a99b5657SRoger Quadros 	sharedramaddr = ICSS_LOCAL_SHARED_RAM;
330a99b5657SRoger Quadros 	/* PRU needs real global OCMC address for C30*/
331a99b5657SRoger Quadros 	ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa;
332*e15472e8SRoger Quadros 	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
333a99b5657SRoger Quadros 
334a99b5657SRoger Quadros 	/* Clear data RAM */
335a99b5657SRoger Quadros 	icssm_prueth_clearmem(prueth, emac->dram);
336a99b5657SRoger Quadros 
337a99b5657SRoger Quadros 	dram_base = prueth->mem[emac->dram].va;
338a99b5657SRoger Quadros 
339a99b5657SRoger Quadros 	/* setup mac address */
340a99b5657SRoger Quadros 	mac_addr = dram_base + PORT_MAC_ADDR;
341a99b5657SRoger Quadros 	memcpy_toio(mac_addr, emac->mac_addr, 6);
342a99b5657SRoger Quadros 
343a99b5657SRoger Quadros 	/* queue information table */
344a99b5657SRoger Quadros 	dram = dram_base + TX_CONTEXT_Q1_OFFSET_ADDR;
345a99b5657SRoger Quadros 	memcpy_toio(dram, queue_infos[emac->port_id],
346a99b5657SRoger Quadros 		    sizeof(queue_infos[emac->port_id]));
347a99b5657SRoger Quadros 
348a99b5657SRoger Quadros 	/* queue table */
349a99b5657SRoger Quadros 	dram = dram_base + PORT_QUEUE_DESC_OFFSET;
350a99b5657SRoger Quadros 	memcpy_toio(dram, queue_descs[emac->port_id],
351a99b5657SRoger Quadros 		    sizeof(queue_descs[emac->port_id]));
352a99b5657SRoger Quadros 
353*e15472e8SRoger Quadros 	emac->rx_queue_descs = sram + HOST_QUEUE_DESC_OFFSET;
354*e15472e8SRoger Quadros 	emac->tx_queue_descs = dram;
355*e15472e8SRoger Quadros 
356a99b5657SRoger Quadros 	/* Set in constant table C28 of PRU0 to ICSS Shared memory */
357a99b5657SRoger Quadros 	pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr);
358a99b5657SRoger Quadros 
359a99b5657SRoger Quadros 	/* Set in constant table C30 of PRU0 to OCMC memory */
360a99b5657SRoger Quadros 	pru_rproc_set_ctable(emac->pru, PRU_C30, ocmcaddr);
361a99b5657SRoger Quadros 
362a99b5657SRoger Quadros 	return 0;
363a99b5657SRoger Quadros }
364511f6c1aSRoger Quadros 
365511f6c1aSRoger Quadros /* called back by PHY layer if there is change in link state of hw port*/
366511f6c1aSRoger Quadros static void icssm_emac_adjust_link(struct net_device *ndev)
367511f6c1aSRoger Quadros {
368511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
369511f6c1aSRoger Quadros 	struct phy_device *phydev = emac->phydev;
370*e15472e8SRoger Quadros 	struct prueth *prueth = emac->prueth;
371511f6c1aSRoger Quadros 	bool new_state = false;
372*e15472e8SRoger Quadros 	enum prueth_mem region;
373511f6c1aSRoger Quadros 	unsigned long flags;
374*e15472e8SRoger Quadros 	u32 port_status = 0;
375*e15472e8SRoger Quadros 	u32 txcfg, mask;
376*e15472e8SRoger Quadros 	u32 delay;
377511f6c1aSRoger Quadros 
378511f6c1aSRoger Quadros 	spin_lock_irqsave(&emac->lock, flags);
379511f6c1aSRoger Quadros 
380511f6c1aSRoger Quadros 	if (phydev->link) {
381511f6c1aSRoger Quadros 		/* check the mode of operation */
382511f6c1aSRoger Quadros 		if (phydev->duplex != emac->duplex) {
383511f6c1aSRoger Quadros 			new_state = true;
384511f6c1aSRoger Quadros 			emac->duplex = phydev->duplex;
385511f6c1aSRoger Quadros 		}
386511f6c1aSRoger Quadros 		if (phydev->speed != emac->speed) {
387511f6c1aSRoger Quadros 			new_state = true;
388511f6c1aSRoger Quadros 			emac->speed = phydev->speed;
389511f6c1aSRoger Quadros 		}
390511f6c1aSRoger Quadros 		if (!emac->link) {
391511f6c1aSRoger Quadros 			new_state = true;
392511f6c1aSRoger Quadros 			emac->link = 1;
393511f6c1aSRoger Quadros 		}
394511f6c1aSRoger Quadros 	} else if (emac->link) {
395511f6c1aSRoger Quadros 		new_state = true;
396511f6c1aSRoger Quadros 		emac->link = 0;
397511f6c1aSRoger Quadros 	}
398511f6c1aSRoger Quadros 
399*e15472e8SRoger Quadros 	if (new_state) {
400511f6c1aSRoger Quadros 		phy_print_status(phydev);
401*e15472e8SRoger Quadros 		region = emac->dram;
402*e15472e8SRoger Quadros 
403*e15472e8SRoger Quadros 		/* update phy/port status information based on PHY values*/
404*e15472e8SRoger Quadros 		if (emac->link) {
405*e15472e8SRoger Quadros 			port_status |= PORT_LINK_MASK;
406*e15472e8SRoger Quadros 
407*e15472e8SRoger Quadros 			icssm_prueth_write_reg(prueth, region, PHY_SPEED_OFFSET,
408*e15472e8SRoger Quadros 					       emac->speed);
409*e15472e8SRoger Quadros 
410*e15472e8SRoger Quadros 			delay = TX_CLK_DELAY_100M;
411*e15472e8SRoger Quadros 			delay = delay << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT;
412*e15472e8SRoger Quadros 			mask = PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK;
413*e15472e8SRoger Quadros 
414*e15472e8SRoger Quadros 			if (emac->port_id)
415*e15472e8SRoger Quadros 				txcfg = PRUSS_MII_RT_TXCFG1;
416*e15472e8SRoger Quadros 			else
417*e15472e8SRoger Quadros 				txcfg = PRUSS_MII_RT_TXCFG0;
418*e15472e8SRoger Quadros 
419*e15472e8SRoger Quadros 			regmap_update_bits(prueth->mii_rt, txcfg, mask, delay);
420*e15472e8SRoger Quadros 		}
421*e15472e8SRoger Quadros 
422*e15472e8SRoger Quadros 		writeb(port_status, prueth->mem[region].va +
423*e15472e8SRoger Quadros 		       PORT_STATUS_OFFSET);
424*e15472e8SRoger Quadros 	}
425511f6c1aSRoger Quadros 
426511f6c1aSRoger Quadros 	if (emac->link) {
427511f6c1aSRoger Quadros 	       /* reactivate the transmit queue if it is stopped */
428511f6c1aSRoger Quadros 		if (netif_running(ndev) && netif_queue_stopped(ndev))
429511f6c1aSRoger Quadros 			netif_wake_queue(ndev);
430511f6c1aSRoger Quadros 	} else {
431511f6c1aSRoger Quadros 		if (!netif_queue_stopped(ndev))
432511f6c1aSRoger Quadros 			netif_stop_queue(ndev);
433511f6c1aSRoger Quadros 	}
434511f6c1aSRoger Quadros 
435511f6c1aSRoger Quadros 	spin_unlock_irqrestore(&emac->lock, flags);
436511f6c1aSRoger Quadros }
437511f6c1aSRoger Quadros 
438*e15472e8SRoger Quadros static unsigned int
439*e15472e8SRoger Quadros icssm_get_buff_desc_count(const struct prueth_queue_info *queue)
440*e15472e8SRoger Quadros {
441*e15472e8SRoger Quadros 	unsigned int buffer_desc_count;
442*e15472e8SRoger Quadros 
443*e15472e8SRoger Quadros 	buffer_desc_count = queue->buffer_desc_end -
444*e15472e8SRoger Quadros 			    queue->buffer_desc_offset;
445*e15472e8SRoger Quadros 	buffer_desc_count /= BD_SIZE;
446*e15472e8SRoger Quadros 	buffer_desc_count++;
447*e15472e8SRoger Quadros 
448*e15472e8SRoger Quadros 	return buffer_desc_count;
449*e15472e8SRoger Quadros }
450*e15472e8SRoger Quadros 
451*e15472e8SRoger Quadros static void icssm_get_block(struct prueth_queue_desc __iomem *queue_desc,
452*e15472e8SRoger Quadros 			    const struct prueth_queue_info *queue,
453*e15472e8SRoger Quadros 			    int *write_block, int *read_block)
454*e15472e8SRoger Quadros {
455*e15472e8SRoger Quadros 	*write_block = (readw(&queue_desc->wr_ptr) -
456*e15472e8SRoger Quadros 			queue->buffer_desc_offset) / BD_SIZE;
457*e15472e8SRoger Quadros 	*read_block = (readw(&queue_desc->rd_ptr) -
458*e15472e8SRoger Quadros 		       queue->buffer_desc_offset) / BD_SIZE;
459*e15472e8SRoger Quadros }
460*e15472e8SRoger Quadros 
461*e15472e8SRoger Quadros /**
462*e15472e8SRoger Quadros  * icssm_emac_rx_irq - EMAC Rx interrupt handler
463*e15472e8SRoger Quadros  * @irq: interrupt number
464*e15472e8SRoger Quadros  * @dev_id: pointer to net_device
465*e15472e8SRoger Quadros  *
466*e15472e8SRoger Quadros  * EMAC Interrupt handler - we only schedule NAPI and not process any packets
467*e15472e8SRoger Quadros  * here.
468*e15472e8SRoger Quadros  *
469*e15472e8SRoger Quadros  * Return: IRQ_HANDLED if the interrupt handled
470*e15472e8SRoger Quadros  */
471*e15472e8SRoger Quadros static irqreturn_t icssm_emac_rx_irq(int irq, void *dev_id)
472*e15472e8SRoger Quadros {
473*e15472e8SRoger Quadros 	struct net_device *ndev = (struct net_device *)dev_id;
474*e15472e8SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
475*e15472e8SRoger Quadros 
476*e15472e8SRoger Quadros 	if (likely(netif_running(ndev))) {
477*e15472e8SRoger Quadros 		/* disable Rx system event */
478*e15472e8SRoger Quadros 		disable_irq_nosync(emac->rx_irq);
479*e15472e8SRoger Quadros 		napi_schedule(&emac->napi);
480*e15472e8SRoger Quadros 	}
481*e15472e8SRoger Quadros 
482*e15472e8SRoger Quadros 	return IRQ_HANDLED;
483*e15472e8SRoger Quadros }
484*e15472e8SRoger Quadros 
485*e15472e8SRoger Quadros /**
486*e15472e8SRoger Quadros  * icssm_prueth_tx_enqueue - queue a packet to firmware for transmission
487*e15472e8SRoger Quadros  *
488*e15472e8SRoger Quadros  * @emac: EMAC data structure
489*e15472e8SRoger Quadros  * @skb: packet data buffer
490*e15472e8SRoger Quadros  * @queue_id: priority queue id
491*e15472e8SRoger Quadros  *
492*e15472e8SRoger Quadros  * Return: 0 (Success)
493*e15472e8SRoger Quadros  */
494*e15472e8SRoger Quadros static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
495*e15472e8SRoger Quadros 				   struct sk_buff *skb,
496*e15472e8SRoger Quadros 				   enum prueth_queue_id queue_id)
497*e15472e8SRoger Quadros {
498*e15472e8SRoger Quadros 	struct prueth_queue_desc __iomem *queue_desc;
499*e15472e8SRoger Quadros 	const struct prueth_queue_info *txqueue;
500*e15472e8SRoger Quadros 	struct net_device *ndev = emac->ndev;
501*e15472e8SRoger Quadros 	unsigned int buffer_desc_count;
502*e15472e8SRoger Quadros 	int free_blocks, update_block;
503*e15472e8SRoger Quadros 	bool buffer_wrapped = false;
504*e15472e8SRoger Quadros 	int write_block, read_block;
505*e15472e8SRoger Quadros 	void *src_addr, *dst_addr;
506*e15472e8SRoger Quadros 	int pkt_block_size;
507*e15472e8SRoger Quadros 	void __iomem *dram;
508*e15472e8SRoger Quadros 	int txport, pktlen;
509*e15472e8SRoger Quadros 	u16 update_wr_ptr;
510*e15472e8SRoger Quadros 	u32 wr_buf_desc;
511*e15472e8SRoger Quadros 	void *ocmc_ram;
512*e15472e8SRoger Quadros 
513*e15472e8SRoger Quadros 	dram = emac->prueth->mem[emac->dram].va;
514*e15472e8SRoger Quadros 	if (eth_skb_pad(skb)) {
515*e15472e8SRoger Quadros 		if (netif_msg_tx_err(emac) && net_ratelimit())
516*e15472e8SRoger Quadros 			netdev_err(ndev, "packet pad failed\n");
517*e15472e8SRoger Quadros 		return -ENOMEM;
518*e15472e8SRoger Quadros 	}
519*e15472e8SRoger Quadros 
520*e15472e8SRoger Quadros 	/* which port to tx: MII0 or MII1 */
521*e15472e8SRoger Quadros 	txport = emac->tx_port_queue;
522*e15472e8SRoger Quadros 	src_addr = skb->data;
523*e15472e8SRoger Quadros 	pktlen = skb->len;
524*e15472e8SRoger Quadros 	/* Get the tx queue */
525*e15472e8SRoger Quadros 	queue_desc = emac->tx_queue_descs + queue_id;
526*e15472e8SRoger Quadros 	txqueue = &queue_infos[txport][queue_id];
527*e15472e8SRoger Quadros 
528*e15472e8SRoger Quadros 	buffer_desc_count = icssm_get_buff_desc_count(txqueue);
529*e15472e8SRoger Quadros 
530*e15472e8SRoger Quadros 	/* the PRU firmware deals mostly in pointers already
531*e15472e8SRoger Quadros 	 * offset into ram, we would like to deal in indexes
532*e15472e8SRoger Quadros 	 * within the queue we are working with for code
533*e15472e8SRoger Quadros 	 * simplicity, calculate this here
534*e15472e8SRoger Quadros 	 */
535*e15472e8SRoger Quadros 	icssm_get_block(queue_desc, txqueue, &write_block, &read_block);
536*e15472e8SRoger Quadros 
537*e15472e8SRoger Quadros 	if (write_block > read_block) {
538*e15472e8SRoger Quadros 		free_blocks = buffer_desc_count - write_block;
539*e15472e8SRoger Quadros 		free_blocks += read_block;
540*e15472e8SRoger Quadros 	} else if (write_block < read_block) {
541*e15472e8SRoger Quadros 		free_blocks = read_block - write_block;
542*e15472e8SRoger Quadros 	} else { /* they are all free */
543*e15472e8SRoger Quadros 		free_blocks = buffer_desc_count;
544*e15472e8SRoger Quadros 	}
545*e15472e8SRoger Quadros 
546*e15472e8SRoger Quadros 	pkt_block_size = DIV_ROUND_UP(pktlen, ICSS_BLOCK_SIZE);
547*e15472e8SRoger Quadros 	if (pkt_block_size > free_blocks) /* out of queue space */
548*e15472e8SRoger Quadros 		return -ENOBUFS;
549*e15472e8SRoger Quadros 
550*e15472e8SRoger Quadros 	/* calculate end BD address post write */
551*e15472e8SRoger Quadros 	update_block = write_block + pkt_block_size;
552*e15472e8SRoger Quadros 
553*e15472e8SRoger Quadros 	/* Check for wrap around */
554*e15472e8SRoger Quadros 	if (update_block >= buffer_desc_count) {
555*e15472e8SRoger Quadros 		update_block %= buffer_desc_count;
556*e15472e8SRoger Quadros 		buffer_wrapped = true;
557*e15472e8SRoger Quadros 	}
558*e15472e8SRoger Quadros 
559*e15472e8SRoger Quadros 	/* OCMC RAM is not cached and write order is not important */
560*e15472e8SRoger Quadros 	ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va;
561*e15472e8SRoger Quadros 	dst_addr = ocmc_ram + txqueue->buffer_offset +
562*e15472e8SRoger Quadros 		   (write_block * ICSS_BLOCK_SIZE);
563*e15472e8SRoger Quadros 
564*e15472e8SRoger Quadros 	/* Copy the data from socket buffer(DRAM) to PRU buffers(OCMC) */
565*e15472e8SRoger Quadros 	if (buffer_wrapped) { /* wrapped around buffer */
566*e15472e8SRoger Quadros 		int bytes = (buffer_desc_count - write_block) * ICSS_BLOCK_SIZE;
567*e15472e8SRoger Quadros 		int remaining;
568*e15472e8SRoger Quadros 
569*e15472e8SRoger Quadros 		/* bytes is integral multiple of ICSS_BLOCK_SIZE but
570*e15472e8SRoger Quadros 		 * entire packet may have fit within the last BD
571*e15472e8SRoger Quadros 		 * if pkt_info.length is not integral multiple of
572*e15472e8SRoger Quadros 		 * ICSS_BLOCK_SIZE
573*e15472e8SRoger Quadros 		 */
574*e15472e8SRoger Quadros 		if (pktlen < bytes)
575*e15472e8SRoger Quadros 			bytes = pktlen;
576*e15472e8SRoger Quadros 
577*e15472e8SRoger Quadros 		/* copy non-wrapped part */
578*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, bytes);
579*e15472e8SRoger Quadros 
580*e15472e8SRoger Quadros 		/* copy wrapped part */
581*e15472e8SRoger Quadros 		src_addr += bytes;
582*e15472e8SRoger Quadros 		remaining = pktlen - bytes;
583*e15472e8SRoger Quadros 		dst_addr = ocmc_ram + txqueue->buffer_offset;
584*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, remaining);
585*e15472e8SRoger Quadros 	} else {
586*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, pktlen);
587*e15472e8SRoger Quadros 	}
588*e15472e8SRoger Quadros 
589*e15472e8SRoger Quadros        /* update first buffer descriptor */
590*e15472e8SRoger Quadros 	wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) &
591*e15472e8SRoger Quadros 		       PRUETH_BD_LENGTH_MASK;
592*e15472e8SRoger Quadros 	writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr));
593*e15472e8SRoger Quadros 
594*e15472e8SRoger Quadros 	/* update the write pointer in this queue descriptor, the firmware
595*e15472e8SRoger Quadros 	 * polls for this change so this will signal the start of transmission
596*e15472e8SRoger Quadros 	 */
597*e15472e8SRoger Quadros 	update_wr_ptr = txqueue->buffer_desc_offset + (update_block * BD_SIZE);
598*e15472e8SRoger Quadros 	writew(update_wr_ptr, &queue_desc->wr_ptr);
599*e15472e8SRoger Quadros 
600*e15472e8SRoger Quadros 	return 0;
601*e15472e8SRoger Quadros }
602*e15472e8SRoger Quadros 
603*e15472e8SRoger Quadros void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
604*e15472e8SRoger Quadros 			     struct prueth_packet_info *pkt_info)
605*e15472e8SRoger Quadros {
606*e15472e8SRoger Quadros 	pkt_info->shadow = !!(buffer_descriptor & PRUETH_BD_SHADOW_MASK);
607*e15472e8SRoger Quadros 	pkt_info->port = (buffer_descriptor & PRUETH_BD_PORT_MASK) >>
608*e15472e8SRoger Quadros 			 PRUETH_BD_PORT_SHIFT;
609*e15472e8SRoger Quadros 	pkt_info->length = (buffer_descriptor & PRUETH_BD_LENGTH_MASK) >>
610*e15472e8SRoger Quadros 			   PRUETH_BD_LENGTH_SHIFT;
611*e15472e8SRoger Quadros 	pkt_info->broadcast = !!(buffer_descriptor & PRUETH_BD_BROADCAST_MASK);
612*e15472e8SRoger Quadros 	pkt_info->error = !!(buffer_descriptor & PRUETH_BD_ERROR_MASK);
613*e15472e8SRoger Quadros 	pkt_info->lookup_success = !!(buffer_descriptor &
614*e15472e8SRoger Quadros 				      PRUETH_BD_LOOKUP_SUCCESS_MASK);
615*e15472e8SRoger Quadros 	pkt_info->flood = !!(buffer_descriptor & PRUETH_BD_SW_FLOOD_MASK);
616*e15472e8SRoger Quadros 	pkt_info->timestamp = !!(buffer_descriptor & PRUETH_BD_TIMESTAMP_MASK);
617*e15472e8SRoger Quadros }
618*e15472e8SRoger Quadros 
619*e15472e8SRoger Quadros /**
620*e15472e8SRoger Quadros  * icssm_emac_rx_packet - EMAC Receive function
621*e15472e8SRoger Quadros  *
622*e15472e8SRoger Quadros  * @emac: EMAC data structure
623*e15472e8SRoger Quadros  * @bd_rd_ptr: Buffer descriptor read pointer
624*e15472e8SRoger Quadros  * @pkt_info: packet information structure
625*e15472e8SRoger Quadros  * @rxqueue: Receive queue information structure
626*e15472e8SRoger Quadros  *
627*e15472e8SRoger Quadros  * Get a packet from receive queue
628*e15472e8SRoger Quadros  *
629*e15472e8SRoger Quadros  * Return: 0 (Success)
630*e15472e8SRoger Quadros  */
631*e15472e8SRoger Quadros int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
632*e15472e8SRoger Quadros 			 struct prueth_packet_info *pkt_info,
633*e15472e8SRoger Quadros 			 const struct prueth_queue_info *rxqueue)
634*e15472e8SRoger Quadros {
635*e15472e8SRoger Quadros 	struct net_device *ndev = emac->ndev;
636*e15472e8SRoger Quadros 	unsigned int buffer_desc_count;
637*e15472e8SRoger Quadros 	int read_block, update_block;
638*e15472e8SRoger Quadros 	unsigned int actual_pkt_len;
639*e15472e8SRoger Quadros 	bool buffer_wrapped = false;
640*e15472e8SRoger Quadros 	void *src_addr, *dst_addr;
641*e15472e8SRoger Quadros 	struct sk_buff *skb;
642*e15472e8SRoger Quadros 	int pkt_block_size;
643*e15472e8SRoger Quadros 	void *ocmc_ram;
644*e15472e8SRoger Quadros 
645*e15472e8SRoger Quadros 	/* the PRU firmware deals mostly in pointers already
646*e15472e8SRoger Quadros 	 * offset into ram, we would like to deal in indexes
647*e15472e8SRoger Quadros 	 * within the queue we are working with for code
648*e15472e8SRoger Quadros 	 * simplicity, calculate this here
649*e15472e8SRoger Quadros 	 */
650*e15472e8SRoger Quadros 	buffer_desc_count = icssm_get_buff_desc_count(rxqueue);
651*e15472e8SRoger Quadros 	read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE;
652*e15472e8SRoger Quadros 	pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE);
653*e15472e8SRoger Quadros 
654*e15472e8SRoger Quadros 	/* calculate end BD address post read */
655*e15472e8SRoger Quadros 	update_block = read_block + pkt_block_size;
656*e15472e8SRoger Quadros 
657*e15472e8SRoger Quadros 	/* Check for wrap around */
658*e15472e8SRoger Quadros 	if (update_block >= buffer_desc_count) {
659*e15472e8SRoger Quadros 		update_block %= buffer_desc_count;
660*e15472e8SRoger Quadros 		if (update_block)
661*e15472e8SRoger Quadros 			buffer_wrapped = true;
662*e15472e8SRoger Quadros 	}
663*e15472e8SRoger Quadros 
664*e15472e8SRoger Quadros 	/* calculate new pointer in ram */
665*e15472e8SRoger Quadros 	*bd_rd_ptr = rxqueue->buffer_desc_offset + (update_block * BD_SIZE);
666*e15472e8SRoger Quadros 
667*e15472e8SRoger Quadros 	actual_pkt_len = pkt_info->length;
668*e15472e8SRoger Quadros 
669*e15472e8SRoger Quadros 	/* Allocate a socket buffer for this packet */
670*e15472e8SRoger Quadros 	skb = netdev_alloc_skb_ip_align(ndev, actual_pkt_len);
671*e15472e8SRoger Quadros 	if (!skb) {
672*e15472e8SRoger Quadros 		if (netif_msg_rx_err(emac) && net_ratelimit())
673*e15472e8SRoger Quadros 			netdev_err(ndev, "failed rx buffer alloc\n");
674*e15472e8SRoger Quadros 		return -ENOMEM;
675*e15472e8SRoger Quadros 	}
676*e15472e8SRoger Quadros 
677*e15472e8SRoger Quadros 	dst_addr = skb->data;
678*e15472e8SRoger Quadros 
679*e15472e8SRoger Quadros 	/* OCMC RAM is not cached and read order is not important */
680*e15472e8SRoger Quadros 	ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va;
681*e15472e8SRoger Quadros 
682*e15472e8SRoger Quadros 	/* Get the start address of the first buffer from
683*e15472e8SRoger Quadros 	 * the read buffer description
684*e15472e8SRoger Quadros 	 */
685*e15472e8SRoger Quadros 	src_addr = ocmc_ram + rxqueue->buffer_offset +
686*e15472e8SRoger Quadros 		   (read_block * ICSS_BLOCK_SIZE);
687*e15472e8SRoger Quadros 
688*e15472e8SRoger Quadros 	/* Copy the data from PRU buffers(OCMC) to socket buffer(DRAM) */
689*e15472e8SRoger Quadros 	if (buffer_wrapped) { /* wrapped around buffer */
690*e15472e8SRoger Quadros 		int bytes = (buffer_desc_count - read_block) * ICSS_BLOCK_SIZE;
691*e15472e8SRoger Quadros 		int remaining;
692*e15472e8SRoger Quadros 		/* bytes is integral multiple of ICSS_BLOCK_SIZE but
693*e15472e8SRoger Quadros 		 * entire packet may have fit within the last BD
694*e15472e8SRoger Quadros 		 * if pkt_info.length is not integral multiple of
695*e15472e8SRoger Quadros 		 * ICSS_BLOCK_SIZE
696*e15472e8SRoger Quadros 		 */
697*e15472e8SRoger Quadros 		if (pkt_info->length < bytes)
698*e15472e8SRoger Quadros 			bytes = pkt_info->length;
699*e15472e8SRoger Quadros 
700*e15472e8SRoger Quadros 		/* copy non-wrapped part */
701*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, bytes);
702*e15472e8SRoger Quadros 
703*e15472e8SRoger Quadros 		/* copy wrapped part */
704*e15472e8SRoger Quadros 		dst_addr += bytes;
705*e15472e8SRoger Quadros 		remaining = actual_pkt_len - bytes;
706*e15472e8SRoger Quadros 
707*e15472e8SRoger Quadros 		src_addr = ocmc_ram + rxqueue->buffer_offset;
708*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, remaining);
709*e15472e8SRoger Quadros 		src_addr += remaining;
710*e15472e8SRoger Quadros 	} else {
711*e15472e8SRoger Quadros 		memcpy(dst_addr, src_addr, actual_pkt_len);
712*e15472e8SRoger Quadros 		src_addr += actual_pkt_len;
713*e15472e8SRoger Quadros 	}
714*e15472e8SRoger Quadros 
715*e15472e8SRoger Quadros 	skb_put(skb, actual_pkt_len);
716*e15472e8SRoger Quadros 
717*e15472e8SRoger Quadros 	/* send packet up the stack */
718*e15472e8SRoger Quadros 	skb->protocol = eth_type_trans(skb, ndev);
719*e15472e8SRoger Quadros 	netif_receive_skb(skb);
720*e15472e8SRoger Quadros 
721*e15472e8SRoger Quadros 	/* update stats */
722*e15472e8SRoger Quadros 	emac->stats.rx_bytes += actual_pkt_len;
723*e15472e8SRoger Quadros 	emac->stats.rx_packets++;
724*e15472e8SRoger Quadros 
725*e15472e8SRoger Quadros 	return 0;
726*e15472e8SRoger Quadros }
727*e15472e8SRoger Quadros 
728*e15472e8SRoger Quadros static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget)
729*e15472e8SRoger Quadros {
730*e15472e8SRoger Quadros 	struct prueth_queue_desc __iomem *queue_desc;
731*e15472e8SRoger Quadros 	const struct prueth_queue_info *rxqueue;
732*e15472e8SRoger Quadros 	struct prueth *prueth = emac->prueth;
733*e15472e8SRoger Quadros 	struct prueth_packet_info pkt_info;
734*e15472e8SRoger Quadros 	int start_queue, end_queue;
735*e15472e8SRoger Quadros 	void __iomem *shared_ram;
736*e15472e8SRoger Quadros 	u16 bd_rd_ptr, bd_wr_ptr;
737*e15472e8SRoger Quadros 	u16 update_rd_ptr;
738*e15472e8SRoger Quadros 	u8 overflow_cnt;
739*e15472e8SRoger Quadros 	u32 rd_buf_desc;
740*e15472e8SRoger Quadros 	int used = 0;
741*e15472e8SRoger Quadros 	int i, ret;
742*e15472e8SRoger Quadros 
743*e15472e8SRoger Quadros 	shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
744*e15472e8SRoger Quadros 
745*e15472e8SRoger Quadros 	start_queue = emac->rx_queue_start;
746*e15472e8SRoger Quadros 	end_queue = emac->rx_queue_end;
747*e15472e8SRoger Quadros 
748*e15472e8SRoger Quadros 	/* skip Rx if budget is 0 */
749*e15472e8SRoger Quadros 	if (!budget)
750*e15472e8SRoger Quadros 		return 0;
751*e15472e8SRoger Quadros 
752*e15472e8SRoger Quadros 	/* search host queues for packets */
753*e15472e8SRoger Quadros 	for (i = start_queue; i <= end_queue; i++) {
754*e15472e8SRoger Quadros 		queue_desc = emac->rx_queue_descs + i;
755*e15472e8SRoger Quadros 		rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
756*e15472e8SRoger Quadros 
757*e15472e8SRoger Quadros 		overflow_cnt = readb(&queue_desc->overflow_cnt);
758*e15472e8SRoger Quadros 		if (overflow_cnt > 0) {
759*e15472e8SRoger Quadros 			emac->stats.rx_over_errors += overflow_cnt;
760*e15472e8SRoger Quadros 			/* reset to zero */
761*e15472e8SRoger Quadros 			writeb(0, &queue_desc->overflow_cnt);
762*e15472e8SRoger Quadros 		}
763*e15472e8SRoger Quadros 
764*e15472e8SRoger Quadros 		bd_rd_ptr = readw(&queue_desc->rd_ptr);
765*e15472e8SRoger Quadros 		bd_wr_ptr = readw(&queue_desc->wr_ptr);
766*e15472e8SRoger Quadros 
767*e15472e8SRoger Quadros 		/* while packets are available in this queue */
768*e15472e8SRoger Quadros 		while (bd_rd_ptr != bd_wr_ptr) {
769*e15472e8SRoger Quadros 			/* get packet info from the read buffer descriptor */
770*e15472e8SRoger Quadros 			rd_buf_desc = readl(shared_ram + bd_rd_ptr);
771*e15472e8SRoger Quadros 			icssm_parse_packet_info(prueth, rd_buf_desc, &pkt_info);
772*e15472e8SRoger Quadros 
773*e15472e8SRoger Quadros 			if (pkt_info.length <= 0) {
774*e15472e8SRoger Quadros 				/* a packet length of zero will cause us to
775*e15472e8SRoger Quadros 				 * never move the read pointer ahead, locking
776*e15472e8SRoger Quadros 				 * the driver, so we manually have to move it
777*e15472e8SRoger Quadros 				 * to the write pointer, discarding all
778*e15472e8SRoger Quadros 				 * remaining packets in this queue. This should
779*e15472e8SRoger Quadros 				 * never happen.
780*e15472e8SRoger Quadros 				 */
781*e15472e8SRoger Quadros 				update_rd_ptr = bd_wr_ptr;
782*e15472e8SRoger Quadros 				emac->stats.rx_length_errors++;
783*e15472e8SRoger Quadros 			} else if (pkt_info.length > EMAC_MAX_FRM_SUPPORT) {
784*e15472e8SRoger Quadros 				/* if the packet is too large we skip it but we
785*e15472e8SRoger Quadros 				 * still need to move the read pointer ahead
786*e15472e8SRoger Quadros 				 * and assume something is wrong with the read
787*e15472e8SRoger Quadros 				 * pointer as the firmware should be filtering
788*e15472e8SRoger Quadros 				 * these packets
789*e15472e8SRoger Quadros 				 */
790*e15472e8SRoger Quadros 				update_rd_ptr = bd_wr_ptr;
791*e15472e8SRoger Quadros 				emac->stats.rx_length_errors++;
792*e15472e8SRoger Quadros 			} else {
793*e15472e8SRoger Quadros 				update_rd_ptr = bd_rd_ptr;
794*e15472e8SRoger Quadros 				ret = icssm_emac_rx_packet(emac, &update_rd_ptr,
795*e15472e8SRoger Quadros 							   &pkt_info, rxqueue);
796*e15472e8SRoger Quadros 				if (ret)
797*e15472e8SRoger Quadros 					return used;
798*e15472e8SRoger Quadros 				used++;
799*e15472e8SRoger Quadros 			}
800*e15472e8SRoger Quadros 
801*e15472e8SRoger Quadros 			/* after reading the buffer descriptor we clear it
802*e15472e8SRoger Quadros 			 * to prevent improperly moved read pointer errors
803*e15472e8SRoger Quadros 			 * from simply looking like old packets.
804*e15472e8SRoger Quadros 			 */
805*e15472e8SRoger Quadros 			writel(0, shared_ram + bd_rd_ptr);
806*e15472e8SRoger Quadros 
807*e15472e8SRoger Quadros 			/* update read pointer in queue descriptor */
808*e15472e8SRoger Quadros 			writew(update_rd_ptr, &queue_desc->rd_ptr);
809*e15472e8SRoger Quadros 			bd_rd_ptr = update_rd_ptr;
810*e15472e8SRoger Quadros 
811*e15472e8SRoger Quadros 			/* all we have room for? */
812*e15472e8SRoger Quadros 			if (used >= budget)
813*e15472e8SRoger Quadros 				return used;
814*e15472e8SRoger Quadros 		}
815*e15472e8SRoger Quadros 	}
816*e15472e8SRoger Quadros 
817*e15472e8SRoger Quadros 	return used;
818*e15472e8SRoger Quadros }
819*e15472e8SRoger Quadros 
820*e15472e8SRoger Quadros static int icssm_emac_napi_poll(struct napi_struct *napi, int budget)
821*e15472e8SRoger Quadros {
822*e15472e8SRoger Quadros 	struct prueth_emac *emac = container_of(napi, struct prueth_emac, napi);
823*e15472e8SRoger Quadros 	int num_rx;
824*e15472e8SRoger Quadros 
825*e15472e8SRoger Quadros 	num_rx = icssm_emac_rx_packets(emac, budget);
826*e15472e8SRoger Quadros 
827*e15472e8SRoger Quadros 	if (num_rx < budget && napi_complete_done(napi, num_rx))
828*e15472e8SRoger Quadros 		enable_irq(emac->rx_irq);
829*e15472e8SRoger Quadros 
830*e15472e8SRoger Quadros 	return num_rx;
831*e15472e8SRoger Quadros }
832*e15472e8SRoger Quadros 
833511f6c1aSRoger Quadros static int icssm_emac_set_boot_pru(struct prueth_emac *emac,
834511f6c1aSRoger Quadros 				   struct net_device *ndev)
835511f6c1aSRoger Quadros {
836511f6c1aSRoger Quadros 	const struct prueth_firmware *pru_firmwares;
837511f6c1aSRoger Quadros 	struct prueth *prueth = emac->prueth;
838511f6c1aSRoger Quadros 	const char *fw_name;
839511f6c1aSRoger Quadros 	int ret;
840511f6c1aSRoger Quadros 
841511f6c1aSRoger Quadros 	pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1];
842511f6c1aSRoger Quadros 	fw_name = pru_firmwares->fw_name[prueth->eth_type];
843511f6c1aSRoger Quadros 	if (!fw_name) {
844511f6c1aSRoger Quadros 		netdev_err(ndev, "eth_type %d not supported\n",
845511f6c1aSRoger Quadros 			   prueth->eth_type);
846511f6c1aSRoger Quadros 		return -ENODEV;
847511f6c1aSRoger Quadros 	}
848511f6c1aSRoger Quadros 
849511f6c1aSRoger Quadros 	ret = rproc_set_firmware(emac->pru, fw_name);
850511f6c1aSRoger Quadros 	if (ret) {
851511f6c1aSRoger Quadros 		netdev_err(ndev, "failed to set %s firmware: %d\n",
852511f6c1aSRoger Quadros 			   fw_name, ret);
853511f6c1aSRoger Quadros 		return ret;
854511f6c1aSRoger Quadros 	}
855511f6c1aSRoger Quadros 
856511f6c1aSRoger Quadros 	ret = rproc_boot(emac->pru);
857511f6c1aSRoger Quadros 	if (ret) {
858511f6c1aSRoger Quadros 		netdev_err(ndev, "failed to boot %s firmware: %d\n",
859511f6c1aSRoger Quadros 			   fw_name, ret);
860511f6c1aSRoger Quadros 		return ret;
861511f6c1aSRoger Quadros 	}
862*e15472e8SRoger Quadros 	return ret;
863*e15472e8SRoger Quadros }
864*e15472e8SRoger Quadros 
865*e15472e8SRoger Quadros static int icssm_emac_request_irqs(struct prueth_emac *emac)
866*e15472e8SRoger Quadros {
867*e15472e8SRoger Quadros 	struct net_device *ndev = emac->ndev;
868*e15472e8SRoger Quadros 	int ret;
869*e15472e8SRoger Quadros 
870*e15472e8SRoger Quadros 	ret = request_irq(emac->rx_irq, icssm_emac_rx_irq,
871*e15472e8SRoger Quadros 			  IRQF_TRIGGER_HIGH,
872*e15472e8SRoger Quadros 			  ndev->name, ndev);
873*e15472e8SRoger Quadros 	if (ret) {
874*e15472e8SRoger Quadros 		netdev_err(ndev, "unable to request RX IRQ\n");
875*e15472e8SRoger Quadros 		return ret;
876*e15472e8SRoger Quadros 	}
877511f6c1aSRoger Quadros 
878511f6c1aSRoger Quadros 	return ret;
879511f6c1aSRoger Quadros }
880511f6c1aSRoger Quadros 
881511f6c1aSRoger Quadros /**
882511f6c1aSRoger Quadros  * icssm_emac_ndo_open - EMAC device open
883511f6c1aSRoger Quadros  * @ndev: network adapter device
884511f6c1aSRoger Quadros  *
885511f6c1aSRoger Quadros  * Called when system wants to start the interface.
886511f6c1aSRoger Quadros  *
887511f6c1aSRoger Quadros  * Return: 0 for a successful open, or appropriate error code
888511f6c1aSRoger Quadros  */
889511f6c1aSRoger Quadros static int icssm_emac_ndo_open(struct net_device *ndev)
890511f6c1aSRoger Quadros {
891511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
892a99b5657SRoger Quadros 	struct prueth *prueth = emac->prueth;
893511f6c1aSRoger Quadros 	int ret;
894511f6c1aSRoger Quadros 
895a99b5657SRoger Quadros 	/* set h/w MAC as user might have re-configured */
896a99b5657SRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
897a99b5657SRoger Quadros 
898a99b5657SRoger Quadros 	if (!prueth->emac_configured)
899a99b5657SRoger Quadros 		icssm_prueth_init_ethernet_mode(prueth);
900a99b5657SRoger Quadros 
901a99b5657SRoger Quadros 	icssm_prueth_emac_config(emac);
902a99b5657SRoger Quadros 
903511f6c1aSRoger Quadros 	ret = icssm_emac_set_boot_pru(emac, ndev);
904511f6c1aSRoger Quadros 	if (ret)
905511f6c1aSRoger Quadros 		return ret;
906511f6c1aSRoger Quadros 
907*e15472e8SRoger Quadros 	ret = icssm_emac_request_irqs(emac);
908*e15472e8SRoger Quadros 	if (ret)
909*e15472e8SRoger Quadros 		goto rproc_shutdown;
910*e15472e8SRoger Quadros 
911*e15472e8SRoger Quadros 	napi_enable(&emac->napi);
912*e15472e8SRoger Quadros 
913511f6c1aSRoger Quadros 	/* start PHY */
914511f6c1aSRoger Quadros 	phy_start(emac->phydev);
915*e15472e8SRoger Quadros 
916*e15472e8SRoger Quadros 	/* enable the port and vlan */
917*e15472e8SRoger Quadros 	icssm_prueth_port_enable(emac, true);
918*e15472e8SRoger Quadros 
919a99b5657SRoger Quadros 	prueth->emac_configured |= BIT(emac->port_id);
920*e15472e8SRoger Quadros 
921*e15472e8SRoger Quadros 	if (netif_msg_drv(emac))
922*e15472e8SRoger Quadros 		dev_notice(&ndev->dev, "started\n");
923*e15472e8SRoger Quadros 
924511f6c1aSRoger Quadros 	return 0;
925*e15472e8SRoger Quadros 
926*e15472e8SRoger Quadros rproc_shutdown:
927*e15472e8SRoger Quadros 	rproc_shutdown(emac->pru);
928*e15472e8SRoger Quadros 
929*e15472e8SRoger Quadros 	return ret;
930511f6c1aSRoger Quadros }
931511f6c1aSRoger Quadros 
932511f6c1aSRoger Quadros /**
933511f6c1aSRoger Quadros  * icssm_emac_ndo_stop - EMAC device stop
934511f6c1aSRoger Quadros  * @ndev: network adapter device
935511f6c1aSRoger Quadros  *
936511f6c1aSRoger Quadros  * Called when system wants to stop or down the interface.
937511f6c1aSRoger Quadros  *
938511f6c1aSRoger Quadros  * Return: Always 0 (Success)
939511f6c1aSRoger Quadros  */
940511f6c1aSRoger Quadros static int icssm_emac_ndo_stop(struct net_device *ndev)
941511f6c1aSRoger Quadros {
942511f6c1aSRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
943*e15472e8SRoger Quadros 	struct prueth *prueth = emac->prueth;
944*e15472e8SRoger Quadros 
945*e15472e8SRoger Quadros 	prueth->emac_configured &= ~BIT(emac->port_id);
946*e15472e8SRoger Quadros 
947*e15472e8SRoger Quadros 	/* disable the mac port */
948*e15472e8SRoger Quadros 	icssm_prueth_port_enable(emac, false);
949511f6c1aSRoger Quadros 
950511f6c1aSRoger Quadros 	/* stop PHY */
951511f6c1aSRoger Quadros 	phy_stop(emac->phydev);
952511f6c1aSRoger Quadros 
953*e15472e8SRoger Quadros 	napi_disable(&emac->napi);
954*e15472e8SRoger Quadros 	hrtimer_cancel(&emac->tx_hrtimer);
955*e15472e8SRoger Quadros 
956*e15472e8SRoger Quadros 	/* stop the PRU */
957511f6c1aSRoger Quadros 	rproc_shutdown(emac->pru);
958511f6c1aSRoger Quadros 
959*e15472e8SRoger Quadros 	/* free rx interrupts */
960*e15472e8SRoger Quadros 	free_irq(emac->rx_irq, ndev);
961*e15472e8SRoger Quadros 
962*e15472e8SRoger Quadros 	if (netif_msg_drv(emac))
963*e15472e8SRoger Quadros 		dev_notice(&ndev->dev, "stopped\n");
964*e15472e8SRoger Quadros 
965511f6c1aSRoger Quadros 	return 0;
966511f6c1aSRoger Quadros }
967511f6c1aSRoger Quadros 
968*e15472e8SRoger Quadros /* VLAN-tag PCP to priority queue map for EMAC/Switch/HSR/PRP used by driver
969*e15472e8SRoger Quadros  * Index is PCP val / 2.
970*e15472e8SRoger Quadros  *   low  - pcp 0..3 maps to Q4 for Host
971*e15472e8SRoger Quadros  *   high - pcp 4..7 maps to Q3 for Host
972*e15472e8SRoger Quadros  *   low  - pcp 0..3 maps to Q2 (FWD Queue) for PRU-x
973*e15472e8SRoger Quadros  *   where x = 1 for PRUETH_PORT_MII0
974*e15472e8SRoger Quadros  *             0 for PRUETH_PORT_MII1
975*e15472e8SRoger Quadros  *   high - pcp 4..7 maps to Q1 (FWD Queue) for PRU-x
976*e15472e8SRoger Quadros  */
977*e15472e8SRoger Quadros static const unsigned short emac_pcp_tx_priority_queue_map[] = {
978*e15472e8SRoger Quadros 	PRUETH_QUEUE4, PRUETH_QUEUE4,
979*e15472e8SRoger Quadros 	PRUETH_QUEUE3, PRUETH_QUEUE3,
980*e15472e8SRoger Quadros 	PRUETH_QUEUE2, PRUETH_QUEUE2,
981*e15472e8SRoger Quadros 	PRUETH_QUEUE1, PRUETH_QUEUE1,
982*e15472e8SRoger Quadros };
983*e15472e8SRoger Quadros 
984*e15472e8SRoger Quadros static u16 icssm_prueth_get_tx_queue_id(struct prueth *prueth,
985*e15472e8SRoger Quadros 					struct sk_buff *skb)
986*e15472e8SRoger Quadros {
987*e15472e8SRoger Quadros 	u16 vlan_tci, pcp;
988*e15472e8SRoger Quadros 	int err;
989*e15472e8SRoger Quadros 
990*e15472e8SRoger Quadros 	err = vlan_get_tag(skb, &vlan_tci);
991*e15472e8SRoger Quadros 	if (likely(err))
992*e15472e8SRoger Quadros 		pcp = 0;
993*e15472e8SRoger Quadros 	else
994*e15472e8SRoger Quadros 		pcp = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
995*e15472e8SRoger Quadros 
996*e15472e8SRoger Quadros 	/* Below code (pcp >>= 1) is made common for all
997*e15472e8SRoger Quadros 	 * protocols (i.e., EMAC, RSTP, HSR and PRP)*
998*e15472e8SRoger Quadros 	 * pcp value 0,1 will be updated to 0 mapped to QUEUE4
999*e15472e8SRoger Quadros 	 * pcp value 2,3 will be updated to 1 mapped to QUEUE4
1000*e15472e8SRoger Quadros 	 * pcp value 4,5 will be updated to 2 mapped to QUEUE3
1001*e15472e8SRoger Quadros 	 * pcp value 6,7 will be updated to 3 mapped to QUEUE3
1002*e15472e8SRoger Quadros 	 */
1003*e15472e8SRoger Quadros 	pcp >>= 1;
1004*e15472e8SRoger Quadros 
1005*e15472e8SRoger Quadros 	return emac_pcp_tx_priority_queue_map[pcp];
1006*e15472e8SRoger Quadros }
1007*e15472e8SRoger Quadros 
1008*e15472e8SRoger Quadros /**
1009*e15472e8SRoger Quadros  * icssm_emac_ndo_start_xmit - EMAC Transmit function
1010*e15472e8SRoger Quadros  * @skb: SKB pointer
1011*e15472e8SRoger Quadros  * @ndev: EMAC network adapter
1012*e15472e8SRoger Quadros  *
1013*e15472e8SRoger Quadros  * Called by the system to transmit a packet - we queue the packet in
1014*e15472e8SRoger Quadros  * EMAC hardware transmit queue
1015*e15472e8SRoger Quadros  *
1016*e15472e8SRoger Quadros  * Return: enum netdev_tx
1017*e15472e8SRoger Quadros  */
1018*e15472e8SRoger Quadros static enum netdev_tx icssm_emac_ndo_start_xmit(struct sk_buff *skb,
1019*e15472e8SRoger Quadros 						struct net_device *ndev)
1020*e15472e8SRoger Quadros {
1021*e15472e8SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1022*e15472e8SRoger Quadros 	int ret;
1023*e15472e8SRoger Quadros 	u16 qid;
1024*e15472e8SRoger Quadros 
1025*e15472e8SRoger Quadros 	qid = icssm_prueth_get_tx_queue_id(emac->prueth, skb);
1026*e15472e8SRoger Quadros 	ret = icssm_prueth_tx_enqueue(emac, skb, qid);
1027*e15472e8SRoger Quadros 	if (ret) {
1028*e15472e8SRoger Quadros 		if (ret != -ENOBUFS && netif_msg_tx_err(emac) &&
1029*e15472e8SRoger Quadros 		    net_ratelimit())
1030*e15472e8SRoger Quadros 			netdev_err(ndev, "packet queue failed: %d\n", ret);
1031*e15472e8SRoger Quadros 		goto fail_tx;
1032*e15472e8SRoger Quadros 	}
1033*e15472e8SRoger Quadros 
1034*e15472e8SRoger Quadros 	emac->stats.tx_packets++;
1035*e15472e8SRoger Quadros 	emac->stats.tx_bytes += skb->len;
1036*e15472e8SRoger Quadros 	dev_kfree_skb_any(skb);
1037*e15472e8SRoger Quadros 
1038*e15472e8SRoger Quadros 	return NETDEV_TX_OK;
1039*e15472e8SRoger Quadros 
1040*e15472e8SRoger Quadros fail_tx:
1041*e15472e8SRoger Quadros 	if (ret == -ENOBUFS) {
1042*e15472e8SRoger Quadros 		netif_stop_queue(ndev);
1043*e15472e8SRoger Quadros 		hrtimer_start(&emac->tx_hrtimer,
1044*e15472e8SRoger Quadros 			      us_to_ktime(HR_TIMER_TX_DELAY_US),
1045*e15472e8SRoger Quadros 			      HRTIMER_MODE_REL_PINNED);
1046*e15472e8SRoger Quadros 		ret = NETDEV_TX_BUSY;
1047*e15472e8SRoger Quadros 	} else {
1048*e15472e8SRoger Quadros 		/* error */
1049*e15472e8SRoger Quadros 		emac->stats.tx_dropped++;
1050*e15472e8SRoger Quadros 		ret = NET_XMIT_DROP;
1051*e15472e8SRoger Quadros 	}
1052*e15472e8SRoger Quadros 
1053*e15472e8SRoger Quadros 	return ret;
1054*e15472e8SRoger Quadros }
1055*e15472e8SRoger Quadros 
1056*e15472e8SRoger Quadros /**
1057*e15472e8SRoger Quadros  * icssm_emac_ndo_get_stats64 - EMAC get statistics function
1058*e15472e8SRoger Quadros  * @ndev: The EMAC network adapter
1059*e15472e8SRoger Quadros  * @stats: rtnl_link_stats structure
1060*e15472e8SRoger Quadros  *
1061*e15472e8SRoger Quadros  * Called when system wants to get statistics from the device.
1062*e15472e8SRoger Quadros  *
1063*e15472e8SRoger Quadros  */
1064*e15472e8SRoger Quadros static void icssm_emac_ndo_get_stats64(struct net_device *ndev,
1065*e15472e8SRoger Quadros 				       struct rtnl_link_stats64 *stats)
1066*e15472e8SRoger Quadros {
1067*e15472e8SRoger Quadros 	struct prueth_emac *emac = netdev_priv(ndev);
1068*e15472e8SRoger Quadros 
1069*e15472e8SRoger Quadros 	stats->rx_packets = emac->stats.rx_packets;
1070*e15472e8SRoger Quadros 	stats->rx_bytes = emac->stats.rx_bytes;
1071*e15472e8SRoger Quadros 	stats->tx_packets = emac->stats.tx_packets;
1072*e15472e8SRoger Quadros 	stats->tx_bytes = emac->stats.tx_bytes;
1073*e15472e8SRoger Quadros 	stats->tx_dropped = emac->stats.tx_dropped;
1074*e15472e8SRoger Quadros 	stats->rx_over_errors = emac->stats.rx_over_errors;
1075*e15472e8SRoger Quadros 	stats->rx_length_errors = emac->stats.rx_length_errors;
1076*e15472e8SRoger Quadros }
1077*e15472e8SRoger Quadros 
1078511f6c1aSRoger Quadros static const struct net_device_ops emac_netdev_ops = {
1079511f6c1aSRoger Quadros 	.ndo_open = icssm_emac_ndo_open,
1080511f6c1aSRoger Quadros 	.ndo_stop = icssm_emac_ndo_stop,
1081*e15472e8SRoger Quadros 	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
1082*e15472e8SRoger Quadros 	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
1083511f6c1aSRoger Quadros };
1084511f6c1aSRoger Quadros 
1085511f6c1aSRoger Quadros /* get emac_port corresponding to eth_node name */
1086511f6c1aSRoger Quadros static int icssm_prueth_node_port(struct device_node *eth_node)
1087511f6c1aSRoger Quadros {
1088511f6c1aSRoger Quadros 	u32 port_id;
1089511f6c1aSRoger Quadros 	int ret;
1090511f6c1aSRoger Quadros 
1091511f6c1aSRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
1092511f6c1aSRoger Quadros 	if (ret)
1093511f6c1aSRoger Quadros 		return ret;
1094511f6c1aSRoger Quadros 
1095511f6c1aSRoger Quadros 	if (port_id == 0)
1096511f6c1aSRoger Quadros 		return PRUETH_PORT_MII0;
1097511f6c1aSRoger Quadros 	else if (port_id == 1)
1098511f6c1aSRoger Quadros 		return PRUETH_PORT_MII1;
1099511f6c1aSRoger Quadros 	else
1100511f6c1aSRoger Quadros 		return PRUETH_PORT_INVALID;
1101511f6c1aSRoger Quadros }
1102511f6c1aSRoger Quadros 
1103511f6c1aSRoger Quadros /* get MAC instance corresponding to eth_node name */
1104511f6c1aSRoger Quadros static int icssm_prueth_node_mac(struct device_node *eth_node)
1105511f6c1aSRoger Quadros {
1106511f6c1aSRoger Quadros 	u32 port_id;
1107511f6c1aSRoger Quadros 	int ret;
1108511f6c1aSRoger Quadros 
1109511f6c1aSRoger Quadros 	ret = of_property_read_u32(eth_node, "reg", &port_id);
1110511f6c1aSRoger Quadros 	if (ret)
1111511f6c1aSRoger Quadros 		return ret;
1112511f6c1aSRoger Quadros 
1113511f6c1aSRoger Quadros 	if (port_id == 0)
1114511f6c1aSRoger Quadros 		return PRUETH_MAC0;
1115511f6c1aSRoger Quadros 	else if (port_id == 1)
1116511f6c1aSRoger Quadros 		return PRUETH_MAC1;
1117511f6c1aSRoger Quadros 	else
1118511f6c1aSRoger Quadros 		return PRUETH_MAC_INVALID;
1119511f6c1aSRoger Quadros }
1120511f6c1aSRoger Quadros 
1121*e15472e8SRoger Quadros static enum hrtimer_restart icssm_emac_tx_timer_callback(struct hrtimer *timer)
1122*e15472e8SRoger Quadros {
1123*e15472e8SRoger Quadros 	struct prueth_emac *emac =
1124*e15472e8SRoger Quadros 			container_of(timer, struct prueth_emac, tx_hrtimer);
1125*e15472e8SRoger Quadros 
1126*e15472e8SRoger Quadros 	if (netif_queue_stopped(emac->ndev))
1127*e15472e8SRoger Quadros 		netif_wake_queue(emac->ndev);
1128*e15472e8SRoger Quadros 
1129*e15472e8SRoger Quadros 	return HRTIMER_NORESTART;
1130*e15472e8SRoger Quadros }
1131*e15472e8SRoger Quadros 
1132511f6c1aSRoger Quadros static int icssm_prueth_netdev_init(struct prueth *prueth,
1133511f6c1aSRoger Quadros 				    struct device_node *eth_node)
1134511f6c1aSRoger Quadros {
1135511f6c1aSRoger Quadros 	struct prueth_emac *emac;
1136511f6c1aSRoger Quadros 	struct net_device *ndev;
1137511f6c1aSRoger Quadros 	enum prueth_port port;
1138511f6c1aSRoger Quadros 	enum prueth_mac mac;
1139511f6c1aSRoger Quadros 	int ret;
1140511f6c1aSRoger Quadros 
1141511f6c1aSRoger Quadros 	port = icssm_prueth_node_port(eth_node);
1142511f6c1aSRoger Quadros 	if (port == PRUETH_PORT_INVALID)
1143511f6c1aSRoger Quadros 		return -EINVAL;
1144511f6c1aSRoger Quadros 
1145511f6c1aSRoger Quadros 	mac = icssm_prueth_node_mac(eth_node);
1146511f6c1aSRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
1147511f6c1aSRoger Quadros 		return -EINVAL;
1148511f6c1aSRoger Quadros 
1149511f6c1aSRoger Quadros 	ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac));
1150511f6c1aSRoger Quadros 	if (!ndev)
1151511f6c1aSRoger Quadros 		return -ENOMEM;
1152511f6c1aSRoger Quadros 
1153511f6c1aSRoger Quadros 	SET_NETDEV_DEV(ndev, prueth->dev);
1154511f6c1aSRoger Quadros 	emac = netdev_priv(ndev);
1155511f6c1aSRoger Quadros 	prueth->emac[mac] = emac;
1156511f6c1aSRoger Quadros 	emac->prueth = prueth;
1157511f6c1aSRoger Quadros 	emac->ndev = ndev;
1158511f6c1aSRoger Quadros 	emac->port_id = port;
1159511f6c1aSRoger Quadros 
1160511f6c1aSRoger Quadros 	/* by default eth_type is EMAC */
1161511f6c1aSRoger Quadros 	switch (port) {
1162511f6c1aSRoger Quadros 	case PRUETH_PORT_MII0:
1163*e15472e8SRoger Quadros 		emac->tx_port_queue = PRUETH_PORT_QUEUE_MII0;
1164*e15472e8SRoger Quadros 
1165*e15472e8SRoger Quadros 		/* packets from MII0 are on queues 1 through 2 */
1166*e15472e8SRoger Quadros 		emac->rx_queue_start = PRUETH_QUEUE1;
1167*e15472e8SRoger Quadros 		emac->rx_queue_end = PRUETH_QUEUE2;
1168*e15472e8SRoger Quadros 
1169a99b5657SRoger Quadros 		emac->dram = PRUETH_MEM_DRAM0;
1170511f6c1aSRoger Quadros 		emac->pru = prueth->pru0;
1171511f6c1aSRoger Quadros 		break;
1172511f6c1aSRoger Quadros 	case PRUETH_PORT_MII1:
1173*e15472e8SRoger Quadros 		emac->tx_port_queue = PRUETH_PORT_QUEUE_MII1;
1174*e15472e8SRoger Quadros 
1175*e15472e8SRoger Quadros 		/* packets from MII1 are on queues 3 through 4 */
1176*e15472e8SRoger Quadros 		emac->rx_queue_start = PRUETH_QUEUE3;
1177*e15472e8SRoger Quadros 		emac->rx_queue_end = PRUETH_QUEUE4;
1178*e15472e8SRoger Quadros 
1179a99b5657SRoger Quadros 		emac->dram = PRUETH_MEM_DRAM1;
1180511f6c1aSRoger Quadros 		emac->pru = prueth->pru1;
1181511f6c1aSRoger Quadros 		break;
1182511f6c1aSRoger Quadros 	default:
1183511f6c1aSRoger Quadros 		return -EINVAL;
1184511f6c1aSRoger Quadros 	}
1185*e15472e8SRoger Quadros 
1186*e15472e8SRoger Quadros 	emac->rx_irq = of_irq_get_byname(eth_node, "rx");
1187*e15472e8SRoger Quadros 	if (emac->rx_irq < 0) {
1188*e15472e8SRoger Quadros 		ret = emac->rx_irq;
1189*e15472e8SRoger Quadros 		if (ret != -EPROBE_DEFER)
1190*e15472e8SRoger Quadros 			dev_err(prueth->dev, "could not get rx irq\n");
1191*e15472e8SRoger Quadros 		goto free;
1192*e15472e8SRoger Quadros 	}
1193*e15472e8SRoger Quadros 
1194511f6c1aSRoger Quadros 	/* get mac address from DT and set private and netdev addr */
1195511f6c1aSRoger Quadros 	ret = of_get_ethdev_address(eth_node, ndev);
1196511f6c1aSRoger Quadros 	if (!is_valid_ether_addr(ndev->dev_addr)) {
1197511f6c1aSRoger Quadros 		eth_hw_addr_random(ndev);
1198511f6c1aSRoger Quadros 		dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
1199511f6c1aSRoger Quadros 			 port, ndev->dev_addr);
1200511f6c1aSRoger Quadros 	}
1201511f6c1aSRoger Quadros 	ether_addr_copy(emac->mac_addr, ndev->dev_addr);
1202511f6c1aSRoger Quadros 
1203511f6c1aSRoger Quadros 	/* connect PHY */
1204511f6c1aSRoger Quadros 	emac->phydev = of_phy_get_and_connect(ndev, eth_node,
1205511f6c1aSRoger Quadros 					      icssm_emac_adjust_link);
1206511f6c1aSRoger Quadros 	if (!emac->phydev) {
1207511f6c1aSRoger Quadros 		dev_dbg(prueth->dev, "PHY connection failed\n");
1208511f6c1aSRoger Quadros 		ret = -ENODEV;
1209511f6c1aSRoger Quadros 		goto free;
1210511f6c1aSRoger Quadros 	}
1211511f6c1aSRoger Quadros 
1212511f6c1aSRoger Quadros 	/* remove unsupported modes */
1213511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
1214511f6c1aSRoger Quadros 
1215511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
1216511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
1217511f6c1aSRoger Quadros 
1218511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
1219511f6c1aSRoger Quadros 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
1220511f6c1aSRoger Quadros 
1221511f6c1aSRoger Quadros 	ndev->dev.of_node = eth_node;
1222511f6c1aSRoger Quadros 	ndev->netdev_ops = &emac_netdev_ops;
1223511f6c1aSRoger Quadros 
1224*e15472e8SRoger Quadros 	netif_napi_add(ndev, &emac->napi, icssm_emac_napi_poll);
1225*e15472e8SRoger Quadros 
1226*e15472e8SRoger Quadros 	hrtimer_setup(&emac->tx_hrtimer, &icssm_emac_tx_timer_callback,
1227*e15472e8SRoger Quadros 		      CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
1228*e15472e8SRoger Quadros 
1229511f6c1aSRoger Quadros 	return 0;
1230511f6c1aSRoger Quadros free:
1231511f6c1aSRoger Quadros 	emac->ndev = NULL;
1232511f6c1aSRoger Quadros 	prueth->emac[mac] = NULL;
1233511f6c1aSRoger Quadros 
1234511f6c1aSRoger Quadros 	return ret;
1235511f6c1aSRoger Quadros }
1236511f6c1aSRoger Quadros 
1237511f6c1aSRoger Quadros static void icssm_prueth_netdev_exit(struct prueth *prueth,
1238511f6c1aSRoger Quadros 				     struct device_node *eth_node)
1239511f6c1aSRoger Quadros {
1240511f6c1aSRoger Quadros 	struct prueth_emac *emac;
1241511f6c1aSRoger Quadros 	enum prueth_mac mac;
1242511f6c1aSRoger Quadros 
1243511f6c1aSRoger Quadros 	mac = icssm_prueth_node_mac(eth_node);
1244511f6c1aSRoger Quadros 	if (mac == PRUETH_MAC_INVALID)
1245511f6c1aSRoger Quadros 		return;
1246511f6c1aSRoger Quadros 
1247511f6c1aSRoger Quadros 	emac = prueth->emac[mac];
1248511f6c1aSRoger Quadros 	if (!emac)
1249511f6c1aSRoger Quadros 		return;
1250511f6c1aSRoger Quadros 
1251511f6c1aSRoger Quadros 	phy_disconnect(emac->phydev);
1252511f6c1aSRoger Quadros 
1253*e15472e8SRoger Quadros 	netif_napi_del(&emac->napi);
1254511f6c1aSRoger Quadros 	prueth->emac[mac] = NULL;
1255511f6c1aSRoger Quadros }
1256511f6c1aSRoger Quadros 
1257511f6c1aSRoger Quadros static int icssm_prueth_probe(struct platform_device *pdev)
1258511f6c1aSRoger Quadros {
1259511f6c1aSRoger Quadros 	struct device_node *eth0_node = NULL, *eth1_node = NULL;
1260511f6c1aSRoger Quadros 	struct device_node *eth_node, *eth_ports_node;
1261511f6c1aSRoger Quadros 	enum pruss_pru_id pruss_id0, pruss_id1;
1262511f6c1aSRoger Quadros 	struct device *dev = &pdev->dev;
1263511f6c1aSRoger Quadros 	struct device_node *np;
1264511f6c1aSRoger Quadros 	struct prueth *prueth;
1265a99b5657SRoger Quadros 	struct pruss *pruss;
1266511f6c1aSRoger Quadros 	int i, ret;
1267511f6c1aSRoger Quadros 
1268511f6c1aSRoger Quadros 	np = dev->of_node;
1269511f6c1aSRoger Quadros 	if (!np)
1270511f6c1aSRoger Quadros 		return -ENODEV; /* we don't support non DT */
1271511f6c1aSRoger Quadros 
1272511f6c1aSRoger Quadros 	prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
1273511f6c1aSRoger Quadros 	if (!prueth)
1274511f6c1aSRoger Quadros 		return -ENOMEM;
1275511f6c1aSRoger Quadros 
1276511f6c1aSRoger Quadros 	platform_set_drvdata(pdev, prueth);
1277511f6c1aSRoger Quadros 	prueth->dev = dev;
1278511f6c1aSRoger Quadros 	prueth->fw_data = device_get_match_data(dev);
1279511f6c1aSRoger Quadros 
1280511f6c1aSRoger Quadros 	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
1281511f6c1aSRoger Quadros 	if (!eth_ports_node)
1282511f6c1aSRoger Quadros 		return -ENOENT;
1283511f6c1aSRoger Quadros 
1284511f6c1aSRoger Quadros 	for_each_child_of_node(eth_ports_node, eth_node) {
1285511f6c1aSRoger Quadros 		u32 reg;
1286511f6c1aSRoger Quadros 
1287511f6c1aSRoger Quadros 		if (strcmp(eth_node->name, "ethernet-port"))
1288511f6c1aSRoger Quadros 			continue;
1289511f6c1aSRoger Quadros 		ret = of_property_read_u32(eth_node, "reg", &reg);
1290511f6c1aSRoger Quadros 		if (ret < 0) {
1291511f6c1aSRoger Quadros 			dev_err(dev, "%pOF error reading port_id %d\n",
1292511f6c1aSRoger Quadros 				eth_node, ret);
1293511f6c1aSRoger Quadros 			of_node_put(eth_node);
1294511f6c1aSRoger Quadros 			return ret;
1295511f6c1aSRoger Quadros 		}
1296511f6c1aSRoger Quadros 
1297511f6c1aSRoger Quadros 		of_node_get(eth_node);
1298511f6c1aSRoger Quadros 
1299511f6c1aSRoger Quadros 		if (reg == 0 && !eth0_node) {
1300511f6c1aSRoger Quadros 			eth0_node = eth_node;
1301511f6c1aSRoger Quadros 			if (!of_device_is_available(eth0_node)) {
1302511f6c1aSRoger Quadros 				of_node_put(eth0_node);
1303511f6c1aSRoger Quadros 				eth0_node = NULL;
1304511f6c1aSRoger Quadros 			}
1305511f6c1aSRoger Quadros 		} else if (reg == 1 && !eth1_node) {
1306511f6c1aSRoger Quadros 			eth1_node = eth_node;
1307511f6c1aSRoger Quadros 			if (!of_device_is_available(eth1_node)) {
1308511f6c1aSRoger Quadros 				of_node_put(eth1_node);
1309511f6c1aSRoger Quadros 				eth1_node = NULL;
1310511f6c1aSRoger Quadros 			}
1311511f6c1aSRoger Quadros 		} else {
1312511f6c1aSRoger Quadros 			if (reg == 0 || reg == 1)
1313511f6c1aSRoger Quadros 				dev_err(dev, "duplicate port reg value: %d\n",
1314511f6c1aSRoger Quadros 					reg);
1315511f6c1aSRoger Quadros 			else
1316511f6c1aSRoger Quadros 				dev_err(dev, "invalid port reg value: %d\n",
1317511f6c1aSRoger Quadros 					reg);
1318511f6c1aSRoger Quadros 
1319511f6c1aSRoger Quadros 			of_node_put(eth_node);
1320511f6c1aSRoger Quadros 		}
1321511f6c1aSRoger Quadros 	}
1322511f6c1aSRoger Quadros 
1323511f6c1aSRoger Quadros 	of_node_put(eth_ports_node);
1324511f6c1aSRoger Quadros 
1325511f6c1aSRoger Quadros 	/* At least one node must be present and available else we fail */
1326511f6c1aSRoger Quadros 	if (!eth0_node && !eth1_node) {
1327511f6c1aSRoger Quadros 		dev_err(dev, "neither port0 nor port1 node available\n");
1328511f6c1aSRoger Quadros 		return -ENODEV;
1329511f6c1aSRoger Quadros 	}
1330511f6c1aSRoger Quadros 
1331511f6c1aSRoger Quadros 	prueth->eth_node[PRUETH_MAC0] = eth0_node;
1332511f6c1aSRoger Quadros 	prueth->eth_node[PRUETH_MAC1] = eth1_node;
1333511f6c1aSRoger Quadros 
1334a99b5657SRoger Quadros 	prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");
1335a99b5657SRoger Quadros 	if (IS_ERR(prueth->mii_rt)) {
1336a99b5657SRoger Quadros 		dev_err(dev, "couldn't get mii-rt syscon regmap\n");
1337a99b5657SRoger Quadros 		return -ENODEV;
1338a99b5657SRoger Quadros 	}
1339a99b5657SRoger Quadros 
1340511f6c1aSRoger Quadros 	if (eth0_node) {
1341511f6c1aSRoger Quadros 		prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0);
1342511f6c1aSRoger Quadros 		if (IS_ERR(prueth->pru0)) {
1343511f6c1aSRoger Quadros 			ret = PTR_ERR(prueth->pru0);
1344511f6c1aSRoger Quadros 			dev_err_probe(dev, ret, "unable to get PRU0");
1345511f6c1aSRoger Quadros 			goto put_pru;
1346511f6c1aSRoger Quadros 		}
1347511f6c1aSRoger Quadros 	}
1348511f6c1aSRoger Quadros 
1349511f6c1aSRoger Quadros 	if (eth1_node) {
1350511f6c1aSRoger Quadros 		prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1);
1351511f6c1aSRoger Quadros 		if (IS_ERR(prueth->pru1)) {
1352511f6c1aSRoger Quadros 			ret = PTR_ERR(prueth->pru1);
1353511f6c1aSRoger Quadros 			dev_err_probe(dev, ret, "unable to get PRU1");
1354511f6c1aSRoger Quadros 			goto put_pru;
1355511f6c1aSRoger Quadros 		}
1356511f6c1aSRoger Quadros 	}
1357511f6c1aSRoger Quadros 
1358a99b5657SRoger Quadros 	pruss = pruss_get(prueth->pru0 ? prueth->pru0 : prueth->pru1);
1359a99b5657SRoger Quadros 	if (IS_ERR(pruss)) {
1360a99b5657SRoger Quadros 		ret = PTR_ERR(pruss);
1361a99b5657SRoger Quadros 		dev_err(dev, "unable to get pruss handle\n");
1362a99b5657SRoger Quadros 		goto put_pru;
1363a99b5657SRoger Quadros 	}
1364a99b5657SRoger Quadros 	prueth->pruss = pruss;
1365a99b5657SRoger Quadros 
1366a99b5657SRoger Quadros 	/* Configure PRUSS */
1367a99b5657SRoger Quadros 	if (eth0_node)
1368a99b5657SRoger Quadros 		pruss_cfg_gpimode(pruss, pruss_id0, PRUSS_GPI_MODE_MII);
1369a99b5657SRoger Quadros 	if (eth1_node)
1370a99b5657SRoger Quadros 		pruss_cfg_gpimode(pruss, pruss_id1, PRUSS_GPI_MODE_MII);
1371a99b5657SRoger Quadros 	pruss_cfg_miirt_enable(pruss, true);
1372a99b5657SRoger Quadros 	pruss_cfg_xfr_enable(pruss, PRU_TYPE_PRU, true);
1373a99b5657SRoger Quadros 
1374a99b5657SRoger Quadros 	/* Get PRUSS mem resources */
1375a99b5657SRoger Quadros 	/* OCMC is system resource which we get separately */
1376a99b5657SRoger Quadros 	for (i = 0; i < ARRAY_SIZE(pruss_mem_ids); i++) {
1377a99b5657SRoger Quadros 		/* skip appropriate DRAM if not required */
1378a99b5657SRoger Quadros 		if (!eth0_node && i == PRUETH_MEM_DRAM0)
1379a99b5657SRoger Quadros 			continue;
1380a99b5657SRoger Quadros 
1381a99b5657SRoger Quadros 		if (!eth1_node && i == PRUETH_MEM_DRAM1)
1382a99b5657SRoger Quadros 			continue;
1383a99b5657SRoger Quadros 
1384a99b5657SRoger Quadros 		ret = pruss_request_mem_region(pruss, pruss_mem_ids[i],
1385a99b5657SRoger Quadros 					       &prueth->mem[i]);
1386a99b5657SRoger Quadros 		if (ret) {
1387a99b5657SRoger Quadros 			dev_err(dev, "unable to get PRUSS resource %d: %d\n",
1388a99b5657SRoger Quadros 				i, ret);
1389a99b5657SRoger Quadros 			goto put_mem;
1390a99b5657SRoger Quadros 		}
1391a99b5657SRoger Quadros 	}
1392a99b5657SRoger Quadros 
1393a99b5657SRoger Quadros 	prueth->sram_pool = of_gen_pool_get(np, "sram", 0);
1394a99b5657SRoger Quadros 	if (!prueth->sram_pool) {
1395a99b5657SRoger Quadros 		dev_err(dev, "unable to get SRAM pool\n");
1396a99b5657SRoger Quadros 		ret = -ENODEV;
1397a99b5657SRoger Quadros 		goto put_mem;
1398a99b5657SRoger Quadros 	}
1399a99b5657SRoger Quadros 
1400a99b5657SRoger Quadros 	prueth->ocmc_ram_size = OCMC_RAM_SIZE;
1401a99b5657SRoger Quadros 	/* Decreased by 8KB to address the reserved region for AM33x */
1402a99b5657SRoger Quadros 	if (prueth->fw_data->driver_data == PRUSS_AM33XX)
1403a99b5657SRoger Quadros 		prueth->ocmc_ram_size = (SZ_64K - SZ_8K);
1404a99b5657SRoger Quadros 
1405a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].va =
1406a99b5657SRoger Quadros 			(void __iomem *)gen_pool_alloc(prueth->sram_pool,
1407a99b5657SRoger Quadros 						       prueth->ocmc_ram_size);
1408a99b5657SRoger Quadros 	if (!prueth->mem[PRUETH_MEM_OCMC].va) {
1409a99b5657SRoger Quadros 		dev_err(dev, "unable to allocate OCMC resource\n");
1410a99b5657SRoger Quadros 		ret = -ENOMEM;
1411a99b5657SRoger Quadros 		goto put_mem;
1412a99b5657SRoger Quadros 	}
1413a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].pa = gen_pool_virt_to_phys
1414a99b5657SRoger Quadros 		(prueth->sram_pool, (unsigned long)
1415a99b5657SRoger Quadros 		 prueth->mem[PRUETH_MEM_OCMC].va);
1416a99b5657SRoger Quadros 	prueth->mem[PRUETH_MEM_OCMC].size = prueth->ocmc_ram_size;
1417a99b5657SRoger Quadros 	dev_dbg(dev, "ocmc: pa %pa va %p size %#zx\n",
1418a99b5657SRoger Quadros 		&prueth->mem[PRUETH_MEM_OCMC].pa,
1419a99b5657SRoger Quadros 		prueth->mem[PRUETH_MEM_OCMC].va,
1420a99b5657SRoger Quadros 		prueth->mem[PRUETH_MEM_OCMC].size);
1421a99b5657SRoger Quadros 
1422511f6c1aSRoger Quadros 	/* setup netdev interfaces */
1423511f6c1aSRoger Quadros 	if (eth0_node) {
1424511f6c1aSRoger Quadros 		ret = icssm_prueth_netdev_init(prueth, eth0_node);
1425511f6c1aSRoger Quadros 		if (ret) {
1426511f6c1aSRoger Quadros 			if (ret != -EPROBE_DEFER) {
1427511f6c1aSRoger Quadros 				dev_err(dev, "netdev init %s failed: %d\n",
1428511f6c1aSRoger Quadros 					eth0_node->name, ret);
1429511f6c1aSRoger Quadros 			}
1430a99b5657SRoger Quadros 			goto free_pool;
1431511f6c1aSRoger Quadros 		}
1432511f6c1aSRoger Quadros 	}
1433511f6c1aSRoger Quadros 
1434511f6c1aSRoger Quadros 	if (eth1_node) {
1435511f6c1aSRoger Quadros 		ret = icssm_prueth_netdev_init(prueth, eth1_node);
1436511f6c1aSRoger Quadros 		if (ret) {
1437511f6c1aSRoger Quadros 			if (ret != -EPROBE_DEFER) {
1438511f6c1aSRoger Quadros 				dev_err(dev, "netdev init %s failed: %d\n",
1439511f6c1aSRoger Quadros 					eth1_node->name, ret);
1440511f6c1aSRoger Quadros 			}
1441511f6c1aSRoger Quadros 			goto netdev_exit;
1442511f6c1aSRoger Quadros 		}
1443511f6c1aSRoger Quadros 	}
1444511f6c1aSRoger Quadros 
1445511f6c1aSRoger Quadros 	/* register the network devices */
1446511f6c1aSRoger Quadros 	if (eth0_node) {
1447511f6c1aSRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);
1448511f6c1aSRoger Quadros 		if (ret) {
1449511f6c1aSRoger Quadros 			dev_err(dev, "can't register netdev for port MII0");
1450511f6c1aSRoger Quadros 			goto netdev_exit;
1451511f6c1aSRoger Quadros 		}
1452511f6c1aSRoger Quadros 
1453511f6c1aSRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC0] =
1454511f6c1aSRoger Quadros 			prueth->emac[PRUETH_MAC0]->ndev;
1455511f6c1aSRoger Quadros 	}
1456511f6c1aSRoger Quadros 
1457511f6c1aSRoger Quadros 	if (eth1_node) {
1458511f6c1aSRoger Quadros 		ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);
1459511f6c1aSRoger Quadros 		if (ret) {
1460511f6c1aSRoger Quadros 			dev_err(dev, "can't register netdev for port MII1");
1461511f6c1aSRoger Quadros 			goto netdev_unregister;
1462511f6c1aSRoger Quadros 		}
1463511f6c1aSRoger Quadros 
1464511f6c1aSRoger Quadros 		prueth->registered_netdevs[PRUETH_MAC1] =
1465511f6c1aSRoger Quadros 			prueth->emac[PRUETH_MAC1]->ndev;
1466511f6c1aSRoger Quadros 	}
1467511f6c1aSRoger Quadros 
1468a99b5657SRoger Quadros 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
1469a99b5657SRoger Quadros 		 (!eth0_node || !eth1_node) ? "single" : "dual");
1470a99b5657SRoger Quadros 
1471511f6c1aSRoger Quadros 	if (eth1_node)
1472511f6c1aSRoger Quadros 		of_node_put(eth1_node);
1473511f6c1aSRoger Quadros 	if (eth0_node)
1474511f6c1aSRoger Quadros 		of_node_put(eth0_node);
1475511f6c1aSRoger Quadros 	return 0;
1476511f6c1aSRoger Quadros 
1477511f6c1aSRoger Quadros netdev_unregister:
1478511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1479511f6c1aSRoger Quadros 		if (!prueth->registered_netdevs[i])
1480511f6c1aSRoger Quadros 			continue;
1481511f6c1aSRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
1482511f6c1aSRoger Quadros 	}
1483511f6c1aSRoger Quadros 
1484511f6c1aSRoger Quadros netdev_exit:
1485511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1486511f6c1aSRoger Quadros 		eth_node = prueth->eth_node[i];
1487511f6c1aSRoger Quadros 		if (!eth_node)
1488511f6c1aSRoger Quadros 			continue;
1489511f6c1aSRoger Quadros 
1490511f6c1aSRoger Quadros 		icssm_prueth_netdev_exit(prueth, eth_node);
1491511f6c1aSRoger Quadros 	}
1492511f6c1aSRoger Quadros 
1493a99b5657SRoger Quadros free_pool:
1494a99b5657SRoger Quadros 	gen_pool_free(prueth->sram_pool,
1495a99b5657SRoger Quadros 		      (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va,
1496a99b5657SRoger Quadros 		      prueth->ocmc_ram_size);
1497a99b5657SRoger Quadros 
1498a99b5657SRoger Quadros put_mem:
1499a99b5657SRoger Quadros 	for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) {
1500a99b5657SRoger Quadros 		if (prueth->mem[i].va)
1501a99b5657SRoger Quadros 			pruss_release_mem_region(pruss, &prueth->mem[i]);
1502a99b5657SRoger Quadros 	}
1503a99b5657SRoger Quadros 	pruss_put(prueth->pruss);
1504a99b5657SRoger Quadros 
1505511f6c1aSRoger Quadros put_pru:
1506511f6c1aSRoger Quadros 	if (eth1_node) {
1507511f6c1aSRoger Quadros 		if (prueth->pru1)
1508511f6c1aSRoger Quadros 			pru_rproc_put(prueth->pru1);
1509511f6c1aSRoger Quadros 		of_node_put(eth1_node);
1510511f6c1aSRoger Quadros 	}
1511511f6c1aSRoger Quadros 
1512511f6c1aSRoger Quadros 	if (eth0_node) {
1513511f6c1aSRoger Quadros 		if (prueth->pru0)
1514511f6c1aSRoger Quadros 			pru_rproc_put(prueth->pru0);
1515511f6c1aSRoger Quadros 		of_node_put(eth0_node);
1516511f6c1aSRoger Quadros 	}
1517511f6c1aSRoger Quadros 
1518511f6c1aSRoger Quadros 	return ret;
1519511f6c1aSRoger Quadros }
1520511f6c1aSRoger Quadros 
1521511f6c1aSRoger Quadros static void icssm_prueth_remove(struct platform_device *pdev)
1522511f6c1aSRoger Quadros {
1523511f6c1aSRoger Quadros 	struct prueth *prueth = platform_get_drvdata(pdev);
1524511f6c1aSRoger Quadros 	struct device_node *eth_node;
1525511f6c1aSRoger Quadros 	int i;
1526511f6c1aSRoger Quadros 
1527511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1528511f6c1aSRoger Quadros 		if (!prueth->registered_netdevs[i])
1529511f6c1aSRoger Quadros 			continue;
1530511f6c1aSRoger Quadros 		unregister_netdev(prueth->registered_netdevs[i]);
1531511f6c1aSRoger Quadros 	}
1532511f6c1aSRoger Quadros 
1533511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1534511f6c1aSRoger Quadros 		eth_node = prueth->eth_node[i];
1535511f6c1aSRoger Quadros 		if (!eth_node)
1536511f6c1aSRoger Quadros 			continue;
1537511f6c1aSRoger Quadros 
1538511f6c1aSRoger Quadros 		icssm_prueth_netdev_exit(prueth, eth_node);
1539511f6c1aSRoger Quadros 		of_node_put(eth_node);
1540511f6c1aSRoger Quadros 	}
1541511f6c1aSRoger Quadros 
1542a99b5657SRoger Quadros 	gen_pool_free(prueth->sram_pool,
1543a99b5657SRoger Quadros 		      (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va,
1544a99b5657SRoger Quadros 		      prueth->ocmc_ram_size);
1545a99b5657SRoger Quadros 
1546a99b5657SRoger Quadros 	for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) {
1547a99b5657SRoger Quadros 		if (prueth->mem[i].va)
1548a99b5657SRoger Quadros 			pruss_release_mem_region(prueth->pruss,
1549a99b5657SRoger Quadros 						 &prueth->mem[i]);
1550a99b5657SRoger Quadros 	}
1551a99b5657SRoger Quadros 
1552511f6c1aSRoger Quadros 	pruss_put(prueth->pruss);
1553511f6c1aSRoger Quadros 
1554511f6c1aSRoger Quadros 	if (prueth->eth_node[PRUETH_MAC0])
1555511f6c1aSRoger Quadros 		pru_rproc_put(prueth->pru0);
1556511f6c1aSRoger Quadros 	if (prueth->eth_node[PRUETH_MAC1])
1557511f6c1aSRoger Quadros 		pru_rproc_put(prueth->pru1);
1558511f6c1aSRoger Quadros }
1559511f6c1aSRoger Quadros 
1560511f6c1aSRoger Quadros #ifdef CONFIG_PM_SLEEP
1561511f6c1aSRoger Quadros static int icssm_prueth_suspend(struct device *dev)
1562511f6c1aSRoger Quadros {
1563511f6c1aSRoger Quadros 	struct prueth *prueth = dev_get_drvdata(dev);
1564511f6c1aSRoger Quadros 	struct net_device *ndev;
1565511f6c1aSRoger Quadros 	int i, ret;
1566511f6c1aSRoger Quadros 
1567511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1568511f6c1aSRoger Quadros 		ndev = prueth->registered_netdevs[i];
1569511f6c1aSRoger Quadros 
1570511f6c1aSRoger Quadros 		if (!ndev)
1571511f6c1aSRoger Quadros 			continue;
1572511f6c1aSRoger Quadros 
1573511f6c1aSRoger Quadros 		if (netif_running(ndev)) {
1574511f6c1aSRoger Quadros 			netif_device_detach(ndev);
1575511f6c1aSRoger Quadros 			ret = icssm_emac_ndo_stop(ndev);
1576511f6c1aSRoger Quadros 			if (ret < 0) {
1577511f6c1aSRoger Quadros 				netdev_err(ndev, "failed to stop: %d", ret);
1578511f6c1aSRoger Quadros 				return ret;
1579511f6c1aSRoger Quadros 			}
1580511f6c1aSRoger Quadros 		}
1581511f6c1aSRoger Quadros 	}
1582511f6c1aSRoger Quadros 
1583511f6c1aSRoger Quadros 	return 0;
1584511f6c1aSRoger Quadros }
1585511f6c1aSRoger Quadros 
1586511f6c1aSRoger Quadros static int icssm_prueth_resume(struct device *dev)
1587511f6c1aSRoger Quadros {
1588511f6c1aSRoger Quadros 	struct prueth *prueth = dev_get_drvdata(dev);
1589511f6c1aSRoger Quadros 	struct net_device *ndev;
1590511f6c1aSRoger Quadros 	int i, ret;
1591511f6c1aSRoger Quadros 
1592511f6c1aSRoger Quadros 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
1593511f6c1aSRoger Quadros 		ndev = prueth->registered_netdevs[i];
1594511f6c1aSRoger Quadros 
1595511f6c1aSRoger Quadros 		if (!ndev)
1596511f6c1aSRoger Quadros 			continue;
1597511f6c1aSRoger Quadros 
1598511f6c1aSRoger Quadros 		if (netif_running(ndev)) {
1599511f6c1aSRoger Quadros 			ret = icssm_emac_ndo_open(ndev);
1600511f6c1aSRoger Quadros 			if (ret < 0) {
1601511f6c1aSRoger Quadros 				netdev_err(ndev, "failed to start: %d", ret);
1602511f6c1aSRoger Quadros 				return ret;
1603511f6c1aSRoger Quadros 			}
1604511f6c1aSRoger Quadros 			netif_device_attach(ndev);
1605511f6c1aSRoger Quadros 		}
1606511f6c1aSRoger Quadros 	}
1607511f6c1aSRoger Quadros 
1608511f6c1aSRoger Quadros 	return 0;
1609511f6c1aSRoger Quadros }
1610511f6c1aSRoger Quadros 
1611511f6c1aSRoger Quadros #endif /* CONFIG_PM_SLEEP */
1612511f6c1aSRoger Quadros 
1613511f6c1aSRoger Quadros static const struct dev_pm_ops prueth_dev_pm_ops = {
1614511f6c1aSRoger Quadros 	SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume)
1615511f6c1aSRoger Quadros };
1616511f6c1aSRoger Quadros 
1617511f6c1aSRoger Quadros /* AM335x SoC-specific firmware data */
1618511f6c1aSRoger Quadros static struct prueth_private_data am335x_prueth_pdata = {
1619a99b5657SRoger Quadros 	.driver_data = PRUSS_AM33XX,
1620511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
1621511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1622511f6c1aSRoger Quadros 			"ti-pruss/am335x-pru0-prueth-fw.elf",
1623511f6c1aSRoger Quadros 	},
1624511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
1625511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1626511f6c1aSRoger Quadros 			"ti-pruss/am335x-pru1-prueth-fw.elf",
1627511f6c1aSRoger Quadros 	},
1628511f6c1aSRoger Quadros };
1629511f6c1aSRoger Quadros 
1630511f6c1aSRoger Quadros /* AM437x SoC-specific firmware data */
1631511f6c1aSRoger Quadros static struct prueth_private_data am437x_prueth_pdata = {
1632a99b5657SRoger Quadros 	.driver_data = PRUSS_AM43XX,
1633511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
1634511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1635511f6c1aSRoger Quadros 			"ti-pruss/am437x-pru0-prueth-fw.elf",
1636511f6c1aSRoger Quadros 	},
1637511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
1638511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1639511f6c1aSRoger Quadros 			"ti-pruss/am437x-pru1-prueth-fw.elf",
1640511f6c1aSRoger Quadros 	},
1641511f6c1aSRoger Quadros };
1642511f6c1aSRoger Quadros 
1643511f6c1aSRoger Quadros /* AM57xx SoC-specific firmware data */
1644511f6c1aSRoger Quadros static struct prueth_private_data am57xx_prueth_pdata = {
1645a99b5657SRoger Quadros 	.driver_data = PRUSS_AM57XX,
1646511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU0] = {
1647511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1648511f6c1aSRoger Quadros 			"ti-pruss/am57xx-pru0-prueth-fw.elf",
1649511f6c1aSRoger Quadros 	},
1650511f6c1aSRoger Quadros 	.fw_pru[PRUSS_PRU1] = {
1651511f6c1aSRoger Quadros 		.fw_name[PRUSS_ETHTYPE_EMAC] =
1652511f6c1aSRoger Quadros 			"ti-pruss/am57xx-pru1-prueth-fw.elf",
1653511f6c1aSRoger Quadros 	},
1654511f6c1aSRoger Quadros };
1655511f6c1aSRoger Quadros 
1656511f6c1aSRoger Quadros static const struct of_device_id prueth_dt_match[] = {
1657511f6c1aSRoger Quadros 	{ .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, },
1658511f6c1aSRoger Quadros 	{ .compatible = "ti,am4376-prueth", .data = &am437x_prueth_pdata, },
1659511f6c1aSRoger Quadros 	{ .compatible = "ti,am3359-prueth", .data = &am335x_prueth_pdata, },
1660511f6c1aSRoger Quadros 	{ /* sentinel */ }
1661511f6c1aSRoger Quadros };
1662511f6c1aSRoger Quadros MODULE_DEVICE_TABLE(of, prueth_dt_match);
1663511f6c1aSRoger Quadros 
1664511f6c1aSRoger Quadros static struct platform_driver prueth_driver = {
1665511f6c1aSRoger Quadros 	.probe = icssm_prueth_probe,
1666511f6c1aSRoger Quadros 	.remove = icssm_prueth_remove,
1667511f6c1aSRoger Quadros 	.driver = {
1668511f6c1aSRoger Quadros 		.name = "prueth",
1669511f6c1aSRoger Quadros 		.of_match_table = prueth_dt_match,
1670511f6c1aSRoger Quadros 		.pm = &prueth_dev_pm_ops,
1671511f6c1aSRoger Quadros 	},
1672511f6c1aSRoger Quadros };
1673511f6c1aSRoger Quadros module_platform_driver(prueth_driver);
1674511f6c1aSRoger Quadros 
1675511f6c1aSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
1676511f6c1aSRoger Quadros MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
1677511f6c1aSRoger Quadros MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver");
1678511f6c1aSRoger Quadros MODULE_LICENSE("GPL");
1679