xref: /openbmc/u-boot/drivers/net/ti/cpsw.c (revision ffad5fa0)
1*ffad5fa0SGrygorii Strashko /*
2*ffad5fa0SGrygorii Strashko  * CPSW Ethernet Switch Driver
3*ffad5fa0SGrygorii Strashko  *
4*ffad5fa0SGrygorii Strashko  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
5*ffad5fa0SGrygorii Strashko  *
6*ffad5fa0SGrygorii Strashko  * This program is free software; you can redistribute it and/or
7*ffad5fa0SGrygorii Strashko  * modify it under the terms of the GNU General Public License as
8*ffad5fa0SGrygorii Strashko  * published by the Free Software Foundation version 2.
9*ffad5fa0SGrygorii Strashko  *
10*ffad5fa0SGrygorii Strashko  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11*ffad5fa0SGrygorii Strashko  * kind, whether express or implied; without even the implied warranty
12*ffad5fa0SGrygorii Strashko  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*ffad5fa0SGrygorii Strashko  * GNU General Public License for more details.
14*ffad5fa0SGrygorii Strashko  */
15*ffad5fa0SGrygorii Strashko 
16*ffad5fa0SGrygorii Strashko #include <common.h>
17*ffad5fa0SGrygorii Strashko #include <command.h>
18*ffad5fa0SGrygorii Strashko #include <net.h>
19*ffad5fa0SGrygorii Strashko #include <miiphy.h>
20*ffad5fa0SGrygorii Strashko #include <malloc.h>
21*ffad5fa0SGrygorii Strashko #include <net.h>
22*ffad5fa0SGrygorii Strashko #include <netdev.h>
23*ffad5fa0SGrygorii Strashko #include <cpsw.h>
24*ffad5fa0SGrygorii Strashko #include <linux/errno.h>
25*ffad5fa0SGrygorii Strashko #include <asm/gpio.h>
26*ffad5fa0SGrygorii Strashko #include <asm/io.h>
27*ffad5fa0SGrygorii Strashko #include <phy.h>
28*ffad5fa0SGrygorii Strashko #include <asm/arch/cpu.h>
29*ffad5fa0SGrygorii Strashko #include <dm.h>
30*ffad5fa0SGrygorii Strashko #include <fdt_support.h>
31*ffad5fa0SGrygorii Strashko 
32*ffad5fa0SGrygorii Strashko DECLARE_GLOBAL_DATA_PTR;
33*ffad5fa0SGrygorii Strashko 
34*ffad5fa0SGrygorii Strashko #define BITMASK(bits)		(BIT(bits) - 1)
35*ffad5fa0SGrygorii Strashko #define PHY_REG_MASK		0x1f
36*ffad5fa0SGrygorii Strashko #define PHY_ID_MASK		0x1f
37*ffad5fa0SGrygorii Strashko #define NUM_DESCS		(PKTBUFSRX * 2)
38*ffad5fa0SGrygorii Strashko #define PKT_MIN			60
39*ffad5fa0SGrygorii Strashko #define PKT_MAX			(1500 + 14 + 4 + 4)
40*ffad5fa0SGrygorii Strashko #define CLEAR_BIT		1
41*ffad5fa0SGrygorii Strashko #define GIGABITEN		BIT(7)
42*ffad5fa0SGrygorii Strashko #define FULLDUPLEXEN		BIT(0)
43*ffad5fa0SGrygorii Strashko #define MIIEN			BIT(15)
44*ffad5fa0SGrygorii Strashko 
45*ffad5fa0SGrygorii Strashko /* reg offset */
46*ffad5fa0SGrygorii Strashko #define CPSW_HOST_PORT_OFFSET	0x108
47*ffad5fa0SGrygorii Strashko #define CPSW_SLAVE0_OFFSET	0x208
48*ffad5fa0SGrygorii Strashko #define CPSW_SLAVE1_OFFSET	0x308
49*ffad5fa0SGrygorii Strashko #define CPSW_SLAVE_SIZE		0x100
50*ffad5fa0SGrygorii Strashko #define CPSW_CPDMA_OFFSET	0x800
51*ffad5fa0SGrygorii Strashko #define CPSW_HW_STATS		0x900
52*ffad5fa0SGrygorii Strashko #define CPSW_STATERAM_OFFSET	0xa00
53*ffad5fa0SGrygorii Strashko #define CPSW_CPTS_OFFSET	0xc00
54*ffad5fa0SGrygorii Strashko #define CPSW_ALE_OFFSET		0xd00
55*ffad5fa0SGrygorii Strashko #define CPSW_SLIVER0_OFFSET	0xd80
56*ffad5fa0SGrygorii Strashko #define CPSW_SLIVER1_OFFSET	0xdc0
57*ffad5fa0SGrygorii Strashko #define CPSW_BD_OFFSET		0x2000
58*ffad5fa0SGrygorii Strashko #define CPSW_MDIO_DIV		0xff
59*ffad5fa0SGrygorii Strashko 
60*ffad5fa0SGrygorii Strashko #define AM335X_GMII_SEL_OFFSET	0x630
61*ffad5fa0SGrygorii Strashko 
62*ffad5fa0SGrygorii Strashko /* DMA Registers */
63*ffad5fa0SGrygorii Strashko #define CPDMA_TXCONTROL		0x004
64*ffad5fa0SGrygorii Strashko #define CPDMA_RXCONTROL		0x014
65*ffad5fa0SGrygorii Strashko #define CPDMA_SOFTRESET		0x01c
66*ffad5fa0SGrygorii Strashko #define CPDMA_RXFREE		0x0e0
67*ffad5fa0SGrygorii Strashko #define CPDMA_TXHDP_VER1	0x100
68*ffad5fa0SGrygorii Strashko #define CPDMA_TXHDP_VER2	0x200
69*ffad5fa0SGrygorii Strashko #define CPDMA_RXHDP_VER1	0x120
70*ffad5fa0SGrygorii Strashko #define CPDMA_RXHDP_VER2	0x220
71*ffad5fa0SGrygorii Strashko #define CPDMA_TXCP_VER1		0x140
72*ffad5fa0SGrygorii Strashko #define CPDMA_TXCP_VER2		0x240
73*ffad5fa0SGrygorii Strashko #define CPDMA_RXCP_VER1		0x160
74*ffad5fa0SGrygorii Strashko #define CPDMA_RXCP_VER2		0x260
75*ffad5fa0SGrygorii Strashko 
76*ffad5fa0SGrygorii Strashko /* Descriptor mode bits */
77*ffad5fa0SGrygorii Strashko #define CPDMA_DESC_SOP		BIT(31)
78*ffad5fa0SGrygorii Strashko #define CPDMA_DESC_EOP		BIT(30)
79*ffad5fa0SGrygorii Strashko #define CPDMA_DESC_OWNER	BIT(29)
80*ffad5fa0SGrygorii Strashko #define CPDMA_DESC_EOQ		BIT(28)
81*ffad5fa0SGrygorii Strashko 
82*ffad5fa0SGrygorii Strashko /*
83*ffad5fa0SGrygorii Strashko  * This timeout definition is a worst-case ultra defensive measure against
84*ffad5fa0SGrygorii Strashko  * unexpected controller lock ups.  Ideally, we should never ever hit this
85*ffad5fa0SGrygorii Strashko  * scenario in practice.
86*ffad5fa0SGrygorii Strashko  */
87*ffad5fa0SGrygorii Strashko #define MDIO_TIMEOUT            100 /* msecs */
88*ffad5fa0SGrygorii Strashko #define CPDMA_TIMEOUT		100 /* msecs */
89*ffad5fa0SGrygorii Strashko 
90*ffad5fa0SGrygorii Strashko struct cpsw_mdio_regs {
91*ffad5fa0SGrygorii Strashko 	u32	version;
92*ffad5fa0SGrygorii Strashko 	u32	control;
93*ffad5fa0SGrygorii Strashko #define CONTROL_IDLE		BIT(31)
94*ffad5fa0SGrygorii Strashko #define CONTROL_ENABLE		BIT(30)
95*ffad5fa0SGrygorii Strashko 
96*ffad5fa0SGrygorii Strashko 	u32	alive;
97*ffad5fa0SGrygorii Strashko 	u32	link;
98*ffad5fa0SGrygorii Strashko 	u32	linkintraw;
99*ffad5fa0SGrygorii Strashko 	u32	linkintmasked;
100*ffad5fa0SGrygorii Strashko 	u32	__reserved_0[2];
101*ffad5fa0SGrygorii Strashko 	u32	userintraw;
102*ffad5fa0SGrygorii Strashko 	u32	userintmasked;
103*ffad5fa0SGrygorii Strashko 	u32	userintmaskset;
104*ffad5fa0SGrygorii Strashko 	u32	userintmaskclr;
105*ffad5fa0SGrygorii Strashko 	u32	__reserved_1[20];
106*ffad5fa0SGrygorii Strashko 
107*ffad5fa0SGrygorii Strashko 	struct {
108*ffad5fa0SGrygorii Strashko 		u32		access;
109*ffad5fa0SGrygorii Strashko 		u32		physel;
110*ffad5fa0SGrygorii Strashko #define USERACCESS_GO		BIT(31)
111*ffad5fa0SGrygorii Strashko #define USERACCESS_WRITE	BIT(30)
112*ffad5fa0SGrygorii Strashko #define USERACCESS_ACK		BIT(29)
113*ffad5fa0SGrygorii Strashko #define USERACCESS_READ		(0)
114*ffad5fa0SGrygorii Strashko #define USERACCESS_DATA		(0xffff)
115*ffad5fa0SGrygorii Strashko 	} user[0];
116*ffad5fa0SGrygorii Strashko };
117*ffad5fa0SGrygorii Strashko 
118*ffad5fa0SGrygorii Strashko struct cpsw_regs {
119*ffad5fa0SGrygorii Strashko 	u32	id_ver;
120*ffad5fa0SGrygorii Strashko 	u32	control;
121*ffad5fa0SGrygorii Strashko 	u32	soft_reset;
122*ffad5fa0SGrygorii Strashko 	u32	stat_port_en;
123*ffad5fa0SGrygorii Strashko 	u32	ptype;
124*ffad5fa0SGrygorii Strashko };
125*ffad5fa0SGrygorii Strashko 
126*ffad5fa0SGrygorii Strashko struct cpsw_slave_regs {
127*ffad5fa0SGrygorii Strashko 	u32	max_blks;
128*ffad5fa0SGrygorii Strashko 	u32	blk_cnt;
129*ffad5fa0SGrygorii Strashko 	u32	flow_thresh;
130*ffad5fa0SGrygorii Strashko 	u32	port_vlan;
131*ffad5fa0SGrygorii Strashko 	u32	tx_pri_map;
132*ffad5fa0SGrygorii Strashko #ifdef CONFIG_AM33XX
133*ffad5fa0SGrygorii Strashko 	u32	gap_thresh;
134*ffad5fa0SGrygorii Strashko #elif defined(CONFIG_TI814X)
135*ffad5fa0SGrygorii Strashko 	u32	ts_ctl;
136*ffad5fa0SGrygorii Strashko 	u32	ts_seq_ltype;
137*ffad5fa0SGrygorii Strashko 	u32	ts_vlan;
138*ffad5fa0SGrygorii Strashko #endif
139*ffad5fa0SGrygorii Strashko 	u32	sa_lo;
140*ffad5fa0SGrygorii Strashko 	u32	sa_hi;
141*ffad5fa0SGrygorii Strashko };
142*ffad5fa0SGrygorii Strashko 
143*ffad5fa0SGrygorii Strashko struct cpsw_host_regs {
144*ffad5fa0SGrygorii Strashko 	u32	max_blks;
145*ffad5fa0SGrygorii Strashko 	u32	blk_cnt;
146*ffad5fa0SGrygorii Strashko 	u32	flow_thresh;
147*ffad5fa0SGrygorii Strashko 	u32	port_vlan;
148*ffad5fa0SGrygorii Strashko 	u32	tx_pri_map;
149*ffad5fa0SGrygorii Strashko 	u32	cpdma_tx_pri_map;
150*ffad5fa0SGrygorii Strashko 	u32	cpdma_rx_chan_map;
151*ffad5fa0SGrygorii Strashko };
152*ffad5fa0SGrygorii Strashko 
153*ffad5fa0SGrygorii Strashko struct cpsw_sliver_regs {
154*ffad5fa0SGrygorii Strashko 	u32	id_ver;
155*ffad5fa0SGrygorii Strashko 	u32	mac_control;
156*ffad5fa0SGrygorii Strashko 	u32	mac_status;
157*ffad5fa0SGrygorii Strashko 	u32	soft_reset;
158*ffad5fa0SGrygorii Strashko 	u32	rx_maxlen;
159*ffad5fa0SGrygorii Strashko 	u32	__reserved_0;
160*ffad5fa0SGrygorii Strashko 	u32	rx_pause;
161*ffad5fa0SGrygorii Strashko 	u32	tx_pause;
162*ffad5fa0SGrygorii Strashko 	u32	__reserved_1;
163*ffad5fa0SGrygorii Strashko 	u32	rx_pri_map;
164*ffad5fa0SGrygorii Strashko };
165*ffad5fa0SGrygorii Strashko 
166*ffad5fa0SGrygorii Strashko #define ALE_ENTRY_BITS		68
167*ffad5fa0SGrygorii Strashko #define ALE_ENTRY_WORDS		DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
168*ffad5fa0SGrygorii Strashko 
169*ffad5fa0SGrygorii Strashko /* ALE Registers */
170*ffad5fa0SGrygorii Strashko #define ALE_CONTROL		0x08
171*ffad5fa0SGrygorii Strashko #define ALE_UNKNOWNVLAN		0x18
172*ffad5fa0SGrygorii Strashko #define ALE_TABLE_CONTROL	0x20
173*ffad5fa0SGrygorii Strashko #define ALE_TABLE		0x34
174*ffad5fa0SGrygorii Strashko #define ALE_PORTCTL		0x40
175*ffad5fa0SGrygorii Strashko 
176*ffad5fa0SGrygorii Strashko #define ALE_TABLE_WRITE		BIT(31)
177*ffad5fa0SGrygorii Strashko 
178*ffad5fa0SGrygorii Strashko #define ALE_TYPE_FREE			0
179*ffad5fa0SGrygorii Strashko #define ALE_TYPE_ADDR			1
180*ffad5fa0SGrygorii Strashko #define ALE_TYPE_VLAN			2
181*ffad5fa0SGrygorii Strashko #define ALE_TYPE_VLAN_ADDR		3
182*ffad5fa0SGrygorii Strashko 
183*ffad5fa0SGrygorii Strashko #define ALE_UCAST_PERSISTANT		0
184*ffad5fa0SGrygorii Strashko #define ALE_UCAST_UNTOUCHED		1
185*ffad5fa0SGrygorii Strashko #define ALE_UCAST_OUI			2
186*ffad5fa0SGrygorii Strashko #define ALE_UCAST_TOUCHED		3
187*ffad5fa0SGrygorii Strashko 
188*ffad5fa0SGrygorii Strashko #define ALE_MCAST_FWD			0
189*ffad5fa0SGrygorii Strashko #define ALE_MCAST_BLOCK_LEARN_FWD	1
190*ffad5fa0SGrygorii Strashko #define ALE_MCAST_FWD_LEARN		2
191*ffad5fa0SGrygorii Strashko #define ALE_MCAST_FWD_2			3
192*ffad5fa0SGrygorii Strashko 
193*ffad5fa0SGrygorii Strashko enum cpsw_ale_port_state {
194*ffad5fa0SGrygorii Strashko 	ALE_PORT_STATE_DISABLE	= 0x00,
195*ffad5fa0SGrygorii Strashko 	ALE_PORT_STATE_BLOCK	= 0x01,
196*ffad5fa0SGrygorii Strashko 	ALE_PORT_STATE_LEARN	= 0x02,
197*ffad5fa0SGrygorii Strashko 	ALE_PORT_STATE_FORWARD	= 0x03,
198*ffad5fa0SGrygorii Strashko };
199*ffad5fa0SGrygorii Strashko 
200*ffad5fa0SGrygorii Strashko /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
201*ffad5fa0SGrygorii Strashko #define ALE_SECURE	1
202*ffad5fa0SGrygorii Strashko #define ALE_BLOCKED	2
203*ffad5fa0SGrygorii Strashko 
204*ffad5fa0SGrygorii Strashko struct cpsw_slave {
205*ffad5fa0SGrygorii Strashko 	struct cpsw_slave_regs		*regs;
206*ffad5fa0SGrygorii Strashko 	struct cpsw_sliver_regs		*sliver;
207*ffad5fa0SGrygorii Strashko 	int				slave_num;
208*ffad5fa0SGrygorii Strashko 	u32				mac_control;
209*ffad5fa0SGrygorii Strashko 	struct cpsw_slave_data		*data;
210*ffad5fa0SGrygorii Strashko };
211*ffad5fa0SGrygorii Strashko 
212*ffad5fa0SGrygorii Strashko struct cpdma_desc {
213*ffad5fa0SGrygorii Strashko 	/* hardware fields */
214*ffad5fa0SGrygorii Strashko 	u32			hw_next;
215*ffad5fa0SGrygorii Strashko 	u32			hw_buffer;
216*ffad5fa0SGrygorii Strashko 	u32			hw_len;
217*ffad5fa0SGrygorii Strashko 	u32			hw_mode;
218*ffad5fa0SGrygorii Strashko 	/* software fields */
219*ffad5fa0SGrygorii Strashko 	u32			sw_buffer;
220*ffad5fa0SGrygorii Strashko 	u32			sw_len;
221*ffad5fa0SGrygorii Strashko };
222*ffad5fa0SGrygorii Strashko 
223*ffad5fa0SGrygorii Strashko struct cpdma_chan {
224*ffad5fa0SGrygorii Strashko 	struct cpdma_desc	*head, *tail;
225*ffad5fa0SGrygorii Strashko 	void			*hdp, *cp, *rxfree;
226*ffad5fa0SGrygorii Strashko };
227*ffad5fa0SGrygorii Strashko 
228*ffad5fa0SGrygorii Strashko /* AM33xx SoC specific definitions for the CONTROL port */
229*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_MODE_MII	0
230*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_MODE_RMII	1
231*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_MODE_RGMII	2
232*ffad5fa0SGrygorii Strashko 
233*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_RGMII1_IDMODE	BIT(4)
234*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_RGMII2_IDMODE	BIT(5)
235*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_RMII1_IO_CLK_EN	BIT(6)
236*ffad5fa0SGrygorii Strashko #define AM33XX_GMII_SEL_RMII2_IO_CLK_EN	BIT(7)
237*ffad5fa0SGrygorii Strashko 
238*ffad5fa0SGrygorii Strashko #define GMII_SEL_MODE_MASK		0x3
239*ffad5fa0SGrygorii Strashko 
240*ffad5fa0SGrygorii Strashko #define desc_write(desc, fld, val)	__raw_writel((u32)(val), &(desc)->fld)
241*ffad5fa0SGrygorii Strashko #define desc_read(desc, fld)		__raw_readl(&(desc)->fld)
242*ffad5fa0SGrygorii Strashko #define desc_read_ptr(desc, fld)	((void *)__raw_readl(&(desc)->fld))
243*ffad5fa0SGrygorii Strashko 
244*ffad5fa0SGrygorii Strashko #define chan_write(chan, fld, val)	__raw_writel((u32)(val), (chan)->fld)
245*ffad5fa0SGrygorii Strashko #define chan_read(chan, fld)		__raw_readl((chan)->fld)
246*ffad5fa0SGrygorii Strashko #define chan_read_ptr(chan, fld)	((void *)__raw_readl((chan)->fld))
247*ffad5fa0SGrygorii Strashko 
248*ffad5fa0SGrygorii Strashko #define for_active_slave(slave, priv) \
249*ffad5fa0SGrygorii Strashko 	slave = (priv)->slaves + (priv)->data.active_slave; if (slave)
250*ffad5fa0SGrygorii Strashko #define for_each_slave(slave, priv) \
251*ffad5fa0SGrygorii Strashko 	for (slave = (priv)->slaves; slave != (priv)->slaves + \
252*ffad5fa0SGrygorii Strashko 				(priv)->data.slaves; slave++)
253*ffad5fa0SGrygorii Strashko 
254*ffad5fa0SGrygorii Strashko struct cpsw_priv {
255*ffad5fa0SGrygorii Strashko #ifdef CONFIG_DM_ETH
256*ffad5fa0SGrygorii Strashko 	struct udevice			*dev;
257*ffad5fa0SGrygorii Strashko #else
258*ffad5fa0SGrygorii Strashko 	struct eth_device		*dev;
259*ffad5fa0SGrygorii Strashko #endif
260*ffad5fa0SGrygorii Strashko 	struct cpsw_platform_data	data;
261*ffad5fa0SGrygorii Strashko 	int				host_port;
262*ffad5fa0SGrygorii Strashko 
263*ffad5fa0SGrygorii Strashko 	struct cpsw_regs		*regs;
264*ffad5fa0SGrygorii Strashko 	void				*dma_regs;
265*ffad5fa0SGrygorii Strashko 	struct cpsw_host_regs		*host_port_regs;
266*ffad5fa0SGrygorii Strashko 	void				*ale_regs;
267*ffad5fa0SGrygorii Strashko 
268*ffad5fa0SGrygorii Strashko 	struct cpdma_desc		*descs;
269*ffad5fa0SGrygorii Strashko 	struct cpdma_desc		*desc_free;
270*ffad5fa0SGrygorii Strashko 	struct cpdma_chan		rx_chan, tx_chan;
271*ffad5fa0SGrygorii Strashko 
272*ffad5fa0SGrygorii Strashko 	struct cpsw_slave		*slaves;
273*ffad5fa0SGrygorii Strashko 	struct phy_device		*phydev;
274*ffad5fa0SGrygorii Strashko 	struct mii_dev			*bus;
275*ffad5fa0SGrygorii Strashko 
276*ffad5fa0SGrygorii Strashko 	u32				phy_mask;
277*ffad5fa0SGrygorii Strashko };
278*ffad5fa0SGrygorii Strashko 
279*ffad5fa0SGrygorii Strashko static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
280*ffad5fa0SGrygorii Strashko {
281*ffad5fa0SGrygorii Strashko 	int idx;
282*ffad5fa0SGrygorii Strashko 
283*ffad5fa0SGrygorii Strashko 	idx    = start / 32;
284*ffad5fa0SGrygorii Strashko 	start -= idx * 32;
285*ffad5fa0SGrygorii Strashko 	idx    = 2 - idx; /* flip */
286*ffad5fa0SGrygorii Strashko 	return (ale_entry[idx] >> start) & BITMASK(bits);
287*ffad5fa0SGrygorii Strashko }
288*ffad5fa0SGrygorii Strashko 
289*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
290*ffad5fa0SGrygorii Strashko 				      u32 value)
291*ffad5fa0SGrygorii Strashko {
292*ffad5fa0SGrygorii Strashko 	int idx;
293*ffad5fa0SGrygorii Strashko 
294*ffad5fa0SGrygorii Strashko 	value &= BITMASK(bits);
295*ffad5fa0SGrygorii Strashko 	idx    = start / 32;
296*ffad5fa0SGrygorii Strashko 	start -= idx * 32;
297*ffad5fa0SGrygorii Strashko 	idx    = 2 - idx; /* flip */
298*ffad5fa0SGrygorii Strashko 	ale_entry[idx] &= ~(BITMASK(bits) << start);
299*ffad5fa0SGrygorii Strashko 	ale_entry[idx] |=  (value << start);
300*ffad5fa0SGrygorii Strashko }
301*ffad5fa0SGrygorii Strashko 
302*ffad5fa0SGrygorii Strashko #define DEFINE_ALE_FIELD(name, start, bits)				\
303*ffad5fa0SGrygorii Strashko static inline int cpsw_ale_get_##name(u32 *ale_entry)			\
304*ffad5fa0SGrygorii Strashko {									\
305*ffad5fa0SGrygorii Strashko 	return cpsw_ale_get_field(ale_entry, start, bits);		\
306*ffad5fa0SGrygorii Strashko }									\
307*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value)	\
308*ffad5fa0SGrygorii Strashko {									\
309*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_field(ale_entry, start, bits, value);		\
310*ffad5fa0SGrygorii Strashko }
311*ffad5fa0SGrygorii Strashko 
312*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(entry_type,		60,	2)
313*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(mcast_state,		62,	2)
314*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(port_mask,		66,	3)
315*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(ucast_type,		62,	2)
316*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(port_num,		66,	2)
317*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(blocked,		65,	1)
318*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(secure,		64,	1)
319*ffad5fa0SGrygorii Strashko DEFINE_ALE_FIELD(mcast,			40,	1)
320*ffad5fa0SGrygorii Strashko 
321*ffad5fa0SGrygorii Strashko /* The MAC address field in the ALE entry cannot be macroized as above */
322*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
323*ffad5fa0SGrygorii Strashko {
324*ffad5fa0SGrygorii Strashko 	int i;
325*ffad5fa0SGrygorii Strashko 
326*ffad5fa0SGrygorii Strashko 	for (i = 0; i < 6; i++)
327*ffad5fa0SGrygorii Strashko 		addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
328*ffad5fa0SGrygorii Strashko }
329*ffad5fa0SGrygorii Strashko 
330*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
331*ffad5fa0SGrygorii Strashko {
332*ffad5fa0SGrygorii Strashko 	int i;
333*ffad5fa0SGrygorii Strashko 
334*ffad5fa0SGrygorii Strashko 	for (i = 0; i < 6; i++)
335*ffad5fa0SGrygorii Strashko 		cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]);
336*ffad5fa0SGrygorii Strashko }
337*ffad5fa0SGrygorii Strashko 
338*ffad5fa0SGrygorii Strashko static int cpsw_ale_read(struct cpsw_priv *priv, int idx, u32 *ale_entry)
339*ffad5fa0SGrygorii Strashko {
340*ffad5fa0SGrygorii Strashko 	int i;
341*ffad5fa0SGrygorii Strashko 
342*ffad5fa0SGrygorii Strashko 	__raw_writel(idx, priv->ale_regs + ALE_TABLE_CONTROL);
343*ffad5fa0SGrygorii Strashko 
344*ffad5fa0SGrygorii Strashko 	for (i = 0; i < ALE_ENTRY_WORDS; i++)
345*ffad5fa0SGrygorii Strashko 		ale_entry[i] = __raw_readl(priv->ale_regs + ALE_TABLE + 4 * i);
346*ffad5fa0SGrygorii Strashko 
347*ffad5fa0SGrygorii Strashko 	return idx;
348*ffad5fa0SGrygorii Strashko }
349*ffad5fa0SGrygorii Strashko 
350*ffad5fa0SGrygorii Strashko static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry)
351*ffad5fa0SGrygorii Strashko {
352*ffad5fa0SGrygorii Strashko 	int i;
353*ffad5fa0SGrygorii Strashko 
354*ffad5fa0SGrygorii Strashko 	for (i = 0; i < ALE_ENTRY_WORDS; i++)
355*ffad5fa0SGrygorii Strashko 		__raw_writel(ale_entry[i], priv->ale_regs + ALE_TABLE + 4 * i);
356*ffad5fa0SGrygorii Strashko 
357*ffad5fa0SGrygorii Strashko 	__raw_writel(idx | ALE_TABLE_WRITE, priv->ale_regs + ALE_TABLE_CONTROL);
358*ffad5fa0SGrygorii Strashko 
359*ffad5fa0SGrygorii Strashko 	return idx;
360*ffad5fa0SGrygorii Strashko }
361*ffad5fa0SGrygorii Strashko 
362*ffad5fa0SGrygorii Strashko static int cpsw_ale_match_addr(struct cpsw_priv *priv, const u8 *addr)
363*ffad5fa0SGrygorii Strashko {
364*ffad5fa0SGrygorii Strashko 	u32 ale_entry[ALE_ENTRY_WORDS];
365*ffad5fa0SGrygorii Strashko 	int type, idx;
366*ffad5fa0SGrygorii Strashko 
367*ffad5fa0SGrygorii Strashko 	for (idx = 0; idx < priv->data.ale_entries; idx++) {
368*ffad5fa0SGrygorii Strashko 		u8 entry_addr[6];
369*ffad5fa0SGrygorii Strashko 
370*ffad5fa0SGrygorii Strashko 		cpsw_ale_read(priv, idx, ale_entry);
371*ffad5fa0SGrygorii Strashko 		type = cpsw_ale_get_entry_type(ale_entry);
372*ffad5fa0SGrygorii Strashko 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
373*ffad5fa0SGrygorii Strashko 			continue;
374*ffad5fa0SGrygorii Strashko 		cpsw_ale_get_addr(ale_entry, entry_addr);
375*ffad5fa0SGrygorii Strashko 		if (memcmp(entry_addr, addr, 6) == 0)
376*ffad5fa0SGrygorii Strashko 			return idx;
377*ffad5fa0SGrygorii Strashko 	}
378*ffad5fa0SGrygorii Strashko 	return -ENOENT;
379*ffad5fa0SGrygorii Strashko }
380*ffad5fa0SGrygorii Strashko 
381*ffad5fa0SGrygorii Strashko static int cpsw_ale_match_free(struct cpsw_priv *priv)
382*ffad5fa0SGrygorii Strashko {
383*ffad5fa0SGrygorii Strashko 	u32 ale_entry[ALE_ENTRY_WORDS];
384*ffad5fa0SGrygorii Strashko 	int type, idx;
385*ffad5fa0SGrygorii Strashko 
386*ffad5fa0SGrygorii Strashko 	for (idx = 0; idx < priv->data.ale_entries; idx++) {
387*ffad5fa0SGrygorii Strashko 		cpsw_ale_read(priv, idx, ale_entry);
388*ffad5fa0SGrygorii Strashko 		type = cpsw_ale_get_entry_type(ale_entry);
389*ffad5fa0SGrygorii Strashko 		if (type == ALE_TYPE_FREE)
390*ffad5fa0SGrygorii Strashko 			return idx;
391*ffad5fa0SGrygorii Strashko 	}
392*ffad5fa0SGrygorii Strashko 	return -ENOENT;
393*ffad5fa0SGrygorii Strashko }
394*ffad5fa0SGrygorii Strashko 
395*ffad5fa0SGrygorii Strashko static int cpsw_ale_find_ageable(struct cpsw_priv *priv)
396*ffad5fa0SGrygorii Strashko {
397*ffad5fa0SGrygorii Strashko 	u32 ale_entry[ALE_ENTRY_WORDS];
398*ffad5fa0SGrygorii Strashko 	int type, idx;
399*ffad5fa0SGrygorii Strashko 
400*ffad5fa0SGrygorii Strashko 	for (idx = 0; idx < priv->data.ale_entries; idx++) {
401*ffad5fa0SGrygorii Strashko 		cpsw_ale_read(priv, idx, ale_entry);
402*ffad5fa0SGrygorii Strashko 		type = cpsw_ale_get_entry_type(ale_entry);
403*ffad5fa0SGrygorii Strashko 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
404*ffad5fa0SGrygorii Strashko 			continue;
405*ffad5fa0SGrygorii Strashko 		if (cpsw_ale_get_mcast(ale_entry))
406*ffad5fa0SGrygorii Strashko 			continue;
407*ffad5fa0SGrygorii Strashko 		type = cpsw_ale_get_ucast_type(ale_entry);
408*ffad5fa0SGrygorii Strashko 		if (type != ALE_UCAST_PERSISTANT &&
409*ffad5fa0SGrygorii Strashko 		    type != ALE_UCAST_OUI)
410*ffad5fa0SGrygorii Strashko 			return idx;
411*ffad5fa0SGrygorii Strashko 	}
412*ffad5fa0SGrygorii Strashko 	return -ENOENT;
413*ffad5fa0SGrygorii Strashko }
414*ffad5fa0SGrygorii Strashko 
415*ffad5fa0SGrygorii Strashko static int cpsw_ale_add_ucast(struct cpsw_priv *priv, const u8 *addr,
416*ffad5fa0SGrygorii Strashko 			      int port, int flags)
417*ffad5fa0SGrygorii Strashko {
418*ffad5fa0SGrygorii Strashko 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
419*ffad5fa0SGrygorii Strashko 	int idx;
420*ffad5fa0SGrygorii Strashko 
421*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
422*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_addr(ale_entry, addr);
423*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
424*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
425*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
426*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_port_num(ale_entry, port);
427*ffad5fa0SGrygorii Strashko 
428*ffad5fa0SGrygorii Strashko 	idx = cpsw_ale_match_addr(priv, addr);
429*ffad5fa0SGrygorii Strashko 	if (idx < 0)
430*ffad5fa0SGrygorii Strashko 		idx = cpsw_ale_match_free(priv);
431*ffad5fa0SGrygorii Strashko 	if (idx < 0)
432*ffad5fa0SGrygorii Strashko 		idx = cpsw_ale_find_ageable(priv);
433*ffad5fa0SGrygorii Strashko 	if (idx < 0)
434*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
435*ffad5fa0SGrygorii Strashko 
436*ffad5fa0SGrygorii Strashko 	cpsw_ale_write(priv, idx, ale_entry);
437*ffad5fa0SGrygorii Strashko 	return 0;
438*ffad5fa0SGrygorii Strashko }
439*ffad5fa0SGrygorii Strashko 
440*ffad5fa0SGrygorii Strashko static int cpsw_ale_add_mcast(struct cpsw_priv *priv, const u8 *addr,
441*ffad5fa0SGrygorii Strashko 			      int port_mask)
442*ffad5fa0SGrygorii Strashko {
443*ffad5fa0SGrygorii Strashko 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
444*ffad5fa0SGrygorii Strashko 	int idx, mask;
445*ffad5fa0SGrygorii Strashko 
446*ffad5fa0SGrygorii Strashko 	idx = cpsw_ale_match_addr(priv, addr);
447*ffad5fa0SGrygorii Strashko 	if (idx >= 0)
448*ffad5fa0SGrygorii Strashko 		cpsw_ale_read(priv, idx, ale_entry);
449*ffad5fa0SGrygorii Strashko 
450*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
451*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_addr(ale_entry, addr);
452*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2);
453*ffad5fa0SGrygorii Strashko 
454*ffad5fa0SGrygorii Strashko 	mask = cpsw_ale_get_port_mask(ale_entry);
455*ffad5fa0SGrygorii Strashko 	port_mask |= mask;
456*ffad5fa0SGrygorii Strashko 	cpsw_ale_set_port_mask(ale_entry, port_mask);
457*ffad5fa0SGrygorii Strashko 
458*ffad5fa0SGrygorii Strashko 	if (idx < 0)
459*ffad5fa0SGrygorii Strashko 		idx = cpsw_ale_match_free(priv);
460*ffad5fa0SGrygorii Strashko 	if (idx < 0)
461*ffad5fa0SGrygorii Strashko 		idx = cpsw_ale_find_ageable(priv);
462*ffad5fa0SGrygorii Strashko 	if (idx < 0)
463*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
464*ffad5fa0SGrygorii Strashko 
465*ffad5fa0SGrygorii Strashko 	cpsw_ale_write(priv, idx, ale_entry);
466*ffad5fa0SGrygorii Strashko 	return 0;
467*ffad5fa0SGrygorii Strashko }
468*ffad5fa0SGrygorii Strashko 
469*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_control(struct cpsw_priv *priv, int bit, int val)
470*ffad5fa0SGrygorii Strashko {
471*ffad5fa0SGrygorii Strashko 	u32 tmp, mask = BIT(bit);
472*ffad5fa0SGrygorii Strashko 
473*ffad5fa0SGrygorii Strashko 	tmp  = __raw_readl(priv->ale_regs + ALE_CONTROL);
474*ffad5fa0SGrygorii Strashko 	tmp &= ~mask;
475*ffad5fa0SGrygorii Strashko 	tmp |= val ? mask : 0;
476*ffad5fa0SGrygorii Strashko 	__raw_writel(tmp, priv->ale_regs + ALE_CONTROL);
477*ffad5fa0SGrygorii Strashko }
478*ffad5fa0SGrygorii Strashko 
479*ffad5fa0SGrygorii Strashko #define cpsw_ale_enable(priv, val)	cpsw_ale_control(priv, 31, val)
480*ffad5fa0SGrygorii Strashko #define cpsw_ale_clear(priv, val)	cpsw_ale_control(priv, 30, val)
481*ffad5fa0SGrygorii Strashko #define cpsw_ale_vlan_aware(priv, val)	cpsw_ale_control(priv,  2, val)
482*ffad5fa0SGrygorii Strashko 
483*ffad5fa0SGrygorii Strashko static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port,
484*ffad5fa0SGrygorii Strashko 				       int val)
485*ffad5fa0SGrygorii Strashko {
486*ffad5fa0SGrygorii Strashko 	int offset = ALE_PORTCTL + 4 * port;
487*ffad5fa0SGrygorii Strashko 	u32 tmp, mask = 0x3;
488*ffad5fa0SGrygorii Strashko 
489*ffad5fa0SGrygorii Strashko 	tmp  = __raw_readl(priv->ale_regs + offset);
490*ffad5fa0SGrygorii Strashko 	tmp &= ~mask;
491*ffad5fa0SGrygorii Strashko 	tmp |= val & mask;
492*ffad5fa0SGrygorii Strashko 	__raw_writel(tmp, priv->ale_regs + offset);
493*ffad5fa0SGrygorii Strashko }
494*ffad5fa0SGrygorii Strashko 
495*ffad5fa0SGrygorii Strashko static struct cpsw_mdio_regs *mdio_regs;
496*ffad5fa0SGrygorii Strashko 
497*ffad5fa0SGrygorii Strashko /* wait until hardware is ready for another user access */
498*ffad5fa0SGrygorii Strashko static inline u32 wait_for_user_access(void)
499*ffad5fa0SGrygorii Strashko {
500*ffad5fa0SGrygorii Strashko 	u32 reg = 0;
501*ffad5fa0SGrygorii Strashko 	int timeout = MDIO_TIMEOUT;
502*ffad5fa0SGrygorii Strashko 
503*ffad5fa0SGrygorii Strashko 	while (timeout-- &&
504*ffad5fa0SGrygorii Strashko 	((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO))
505*ffad5fa0SGrygorii Strashko 		udelay(10);
506*ffad5fa0SGrygorii Strashko 
507*ffad5fa0SGrygorii Strashko 	if (timeout == -1) {
508*ffad5fa0SGrygorii Strashko 		printf("wait_for_user_access Timeout\n");
509*ffad5fa0SGrygorii Strashko 		return -ETIMEDOUT;
510*ffad5fa0SGrygorii Strashko 	}
511*ffad5fa0SGrygorii Strashko 	return reg;
512*ffad5fa0SGrygorii Strashko }
513*ffad5fa0SGrygorii Strashko 
514*ffad5fa0SGrygorii Strashko /* wait until hardware state machine is idle */
515*ffad5fa0SGrygorii Strashko static inline void wait_for_idle(void)
516*ffad5fa0SGrygorii Strashko {
517*ffad5fa0SGrygorii Strashko 	int timeout = MDIO_TIMEOUT;
518*ffad5fa0SGrygorii Strashko 
519*ffad5fa0SGrygorii Strashko 	while (timeout-- &&
520*ffad5fa0SGrygorii Strashko 		((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0))
521*ffad5fa0SGrygorii Strashko 		udelay(10);
522*ffad5fa0SGrygorii Strashko 
523*ffad5fa0SGrygorii Strashko 	if (timeout == -1)
524*ffad5fa0SGrygorii Strashko 		printf("wait_for_idle Timeout\n");
525*ffad5fa0SGrygorii Strashko }
526*ffad5fa0SGrygorii Strashko 
527*ffad5fa0SGrygorii Strashko static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
528*ffad5fa0SGrygorii Strashko 				int dev_addr, int phy_reg)
529*ffad5fa0SGrygorii Strashko {
530*ffad5fa0SGrygorii Strashko 	int data;
531*ffad5fa0SGrygorii Strashko 	u32 reg;
532*ffad5fa0SGrygorii Strashko 
533*ffad5fa0SGrygorii Strashko 	if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
534*ffad5fa0SGrygorii Strashko 		return -EINVAL;
535*ffad5fa0SGrygorii Strashko 
536*ffad5fa0SGrygorii Strashko 	wait_for_user_access();
537*ffad5fa0SGrygorii Strashko 	reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
538*ffad5fa0SGrygorii Strashko 	       (phy_id << 16));
539*ffad5fa0SGrygorii Strashko 	__raw_writel(reg, &mdio_regs->user[0].access);
540*ffad5fa0SGrygorii Strashko 	reg = wait_for_user_access();
541*ffad5fa0SGrygorii Strashko 
542*ffad5fa0SGrygorii Strashko 	data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
543*ffad5fa0SGrygorii Strashko 	return data;
544*ffad5fa0SGrygorii Strashko }
545*ffad5fa0SGrygorii Strashko 
546*ffad5fa0SGrygorii Strashko static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
547*ffad5fa0SGrygorii Strashko 				int phy_reg, u16 data)
548*ffad5fa0SGrygorii Strashko {
549*ffad5fa0SGrygorii Strashko 	u32 reg;
550*ffad5fa0SGrygorii Strashko 
551*ffad5fa0SGrygorii Strashko 	if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
552*ffad5fa0SGrygorii Strashko 		return -EINVAL;
553*ffad5fa0SGrygorii Strashko 
554*ffad5fa0SGrygorii Strashko 	wait_for_user_access();
555*ffad5fa0SGrygorii Strashko 	reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
556*ffad5fa0SGrygorii Strashko 		   (phy_id << 16) | (data & USERACCESS_DATA));
557*ffad5fa0SGrygorii Strashko 	__raw_writel(reg, &mdio_regs->user[0].access);
558*ffad5fa0SGrygorii Strashko 	wait_for_user_access();
559*ffad5fa0SGrygorii Strashko 
560*ffad5fa0SGrygorii Strashko 	return 0;
561*ffad5fa0SGrygorii Strashko }
562*ffad5fa0SGrygorii Strashko 
563*ffad5fa0SGrygorii Strashko static void cpsw_mdio_init(const char *name, u32 mdio_base, u32 div)
564*ffad5fa0SGrygorii Strashko {
565*ffad5fa0SGrygorii Strashko 	struct mii_dev *bus = mdio_alloc();
566*ffad5fa0SGrygorii Strashko 
567*ffad5fa0SGrygorii Strashko 	mdio_regs = (struct cpsw_mdio_regs *)mdio_base;
568*ffad5fa0SGrygorii Strashko 
569*ffad5fa0SGrygorii Strashko 	/* set enable and clock divider */
570*ffad5fa0SGrygorii Strashko 	__raw_writel(div | CONTROL_ENABLE, &mdio_regs->control);
571*ffad5fa0SGrygorii Strashko 
572*ffad5fa0SGrygorii Strashko 	/*
573*ffad5fa0SGrygorii Strashko 	 * wait for scan logic to settle:
574*ffad5fa0SGrygorii Strashko 	 * the scan time consists of (a) a large fixed component, and (b) a
575*ffad5fa0SGrygorii Strashko 	 * small component that varies with the mii bus frequency.  These
576*ffad5fa0SGrygorii Strashko 	 * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
577*ffad5fa0SGrygorii Strashko 	 * silicon.  Since the effect of (b) was found to be largely
578*ffad5fa0SGrygorii Strashko 	 * negligible, we keep things simple here.
579*ffad5fa0SGrygorii Strashko 	 */
580*ffad5fa0SGrygorii Strashko 	udelay(1000);
581*ffad5fa0SGrygorii Strashko 
582*ffad5fa0SGrygorii Strashko 	bus->read = cpsw_mdio_read;
583*ffad5fa0SGrygorii Strashko 	bus->write = cpsw_mdio_write;
584*ffad5fa0SGrygorii Strashko 	strcpy(bus->name, name);
585*ffad5fa0SGrygorii Strashko 
586*ffad5fa0SGrygorii Strashko 	mdio_register(bus);
587*ffad5fa0SGrygorii Strashko }
588*ffad5fa0SGrygorii Strashko 
589*ffad5fa0SGrygorii Strashko /* Set a self-clearing bit in a register, and wait for it to clear */
590*ffad5fa0SGrygorii Strashko static inline void setbit_and_wait_for_clear32(void *addr)
591*ffad5fa0SGrygorii Strashko {
592*ffad5fa0SGrygorii Strashko 	__raw_writel(CLEAR_BIT, addr);
593*ffad5fa0SGrygorii Strashko 	while (__raw_readl(addr) & CLEAR_BIT)
594*ffad5fa0SGrygorii Strashko 		;
595*ffad5fa0SGrygorii Strashko }
596*ffad5fa0SGrygorii Strashko 
597*ffad5fa0SGrygorii Strashko #define mac_hi(mac)	(((mac)[0] << 0) | ((mac)[1] << 8) |	\
598*ffad5fa0SGrygorii Strashko 			 ((mac)[2] << 16) | ((mac)[3] << 24))
599*ffad5fa0SGrygorii Strashko #define mac_lo(mac)	(((mac)[4] << 0) | ((mac)[5] << 8))
600*ffad5fa0SGrygorii Strashko 
601*ffad5fa0SGrygorii Strashko static void cpsw_set_slave_mac(struct cpsw_slave *slave,
602*ffad5fa0SGrygorii Strashko 			       struct cpsw_priv *priv)
603*ffad5fa0SGrygorii Strashko {
604*ffad5fa0SGrygorii Strashko #ifdef CONFIG_DM_ETH
605*ffad5fa0SGrygorii Strashko 	struct eth_pdata *pdata = dev_get_platdata(priv->dev);
606*ffad5fa0SGrygorii Strashko 
607*ffad5fa0SGrygorii Strashko 	writel(mac_hi(pdata->enetaddr), &slave->regs->sa_hi);
608*ffad5fa0SGrygorii Strashko 	writel(mac_lo(pdata->enetaddr), &slave->regs->sa_lo);
609*ffad5fa0SGrygorii Strashko #else
610*ffad5fa0SGrygorii Strashko 	__raw_writel(mac_hi(priv->dev->enetaddr), &slave->regs->sa_hi);
611*ffad5fa0SGrygorii Strashko 	__raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo);
612*ffad5fa0SGrygorii Strashko #endif
613*ffad5fa0SGrygorii Strashko }
614*ffad5fa0SGrygorii Strashko 
615*ffad5fa0SGrygorii Strashko static int cpsw_slave_update_link(struct cpsw_slave *slave,
616*ffad5fa0SGrygorii Strashko 				   struct cpsw_priv *priv, int *link)
617*ffad5fa0SGrygorii Strashko {
618*ffad5fa0SGrygorii Strashko 	struct phy_device *phy;
619*ffad5fa0SGrygorii Strashko 	u32 mac_control = 0;
620*ffad5fa0SGrygorii Strashko 	int ret = -ENODEV;
621*ffad5fa0SGrygorii Strashko 
622*ffad5fa0SGrygorii Strashko 	phy = priv->phydev;
623*ffad5fa0SGrygorii Strashko 	if (!phy)
624*ffad5fa0SGrygorii Strashko 		goto out;
625*ffad5fa0SGrygorii Strashko 
626*ffad5fa0SGrygorii Strashko 	ret = phy_startup(phy);
627*ffad5fa0SGrygorii Strashko 	if (ret)
628*ffad5fa0SGrygorii Strashko 		goto out;
629*ffad5fa0SGrygorii Strashko 
630*ffad5fa0SGrygorii Strashko 	if (link)
631*ffad5fa0SGrygorii Strashko 		*link = phy->link;
632*ffad5fa0SGrygorii Strashko 
633*ffad5fa0SGrygorii Strashko 	if (phy->link) { /* link up */
634*ffad5fa0SGrygorii Strashko 		mac_control = priv->data.mac_control;
635*ffad5fa0SGrygorii Strashko 		if (phy->speed == 1000)
636*ffad5fa0SGrygorii Strashko 			mac_control |= GIGABITEN;
637*ffad5fa0SGrygorii Strashko 		if (phy->duplex == DUPLEX_FULL)
638*ffad5fa0SGrygorii Strashko 			mac_control |= FULLDUPLEXEN;
639*ffad5fa0SGrygorii Strashko 		if (phy->speed == 100)
640*ffad5fa0SGrygorii Strashko 			mac_control |= MIIEN;
641*ffad5fa0SGrygorii Strashko 	}
642*ffad5fa0SGrygorii Strashko 
643*ffad5fa0SGrygorii Strashko 	if (mac_control == slave->mac_control)
644*ffad5fa0SGrygorii Strashko 		goto out;
645*ffad5fa0SGrygorii Strashko 
646*ffad5fa0SGrygorii Strashko 	if (mac_control) {
647*ffad5fa0SGrygorii Strashko 		printf("link up on port %d, speed %d, %s duplex\n",
648*ffad5fa0SGrygorii Strashko 				slave->slave_num, phy->speed,
649*ffad5fa0SGrygorii Strashko 				(phy->duplex == DUPLEX_FULL) ? "full" : "half");
650*ffad5fa0SGrygorii Strashko 	} else {
651*ffad5fa0SGrygorii Strashko 		printf("link down on port %d\n", slave->slave_num);
652*ffad5fa0SGrygorii Strashko 	}
653*ffad5fa0SGrygorii Strashko 
654*ffad5fa0SGrygorii Strashko 	__raw_writel(mac_control, &slave->sliver->mac_control);
655*ffad5fa0SGrygorii Strashko 	slave->mac_control = mac_control;
656*ffad5fa0SGrygorii Strashko 
657*ffad5fa0SGrygorii Strashko out:
658*ffad5fa0SGrygorii Strashko 	return ret;
659*ffad5fa0SGrygorii Strashko }
660*ffad5fa0SGrygorii Strashko 
661*ffad5fa0SGrygorii Strashko static int cpsw_update_link(struct cpsw_priv *priv)
662*ffad5fa0SGrygorii Strashko {
663*ffad5fa0SGrygorii Strashko 	int ret = -ENODEV;
664*ffad5fa0SGrygorii Strashko 	struct cpsw_slave *slave;
665*ffad5fa0SGrygorii Strashko 
666*ffad5fa0SGrygorii Strashko 	for_active_slave(slave, priv)
667*ffad5fa0SGrygorii Strashko 		ret = cpsw_slave_update_link(slave, priv, NULL);
668*ffad5fa0SGrygorii Strashko 
669*ffad5fa0SGrygorii Strashko 	return ret;
670*ffad5fa0SGrygorii Strashko }
671*ffad5fa0SGrygorii Strashko 
672*ffad5fa0SGrygorii Strashko static inline u32  cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
673*ffad5fa0SGrygorii Strashko {
674*ffad5fa0SGrygorii Strashko 	if (priv->host_port == 0)
675*ffad5fa0SGrygorii Strashko 		return slave_num + 1;
676*ffad5fa0SGrygorii Strashko 	else
677*ffad5fa0SGrygorii Strashko 		return slave_num;
678*ffad5fa0SGrygorii Strashko }
679*ffad5fa0SGrygorii Strashko 
680*ffad5fa0SGrygorii Strashko static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
681*ffad5fa0SGrygorii Strashko {
682*ffad5fa0SGrygorii Strashko 	u32     slave_port;
683*ffad5fa0SGrygorii Strashko 
684*ffad5fa0SGrygorii Strashko 	setbit_and_wait_for_clear32(&slave->sliver->soft_reset);
685*ffad5fa0SGrygorii Strashko 
686*ffad5fa0SGrygorii Strashko 	/* setup priority mapping */
687*ffad5fa0SGrygorii Strashko 	__raw_writel(0x76543210, &slave->sliver->rx_pri_map);
688*ffad5fa0SGrygorii Strashko 	__raw_writel(0x33221100, &slave->regs->tx_pri_map);
689*ffad5fa0SGrygorii Strashko 
690*ffad5fa0SGrygorii Strashko 	/* setup max packet size, and mac address */
691*ffad5fa0SGrygorii Strashko 	__raw_writel(PKT_MAX, &slave->sliver->rx_maxlen);
692*ffad5fa0SGrygorii Strashko 	cpsw_set_slave_mac(slave, priv);
693*ffad5fa0SGrygorii Strashko 
694*ffad5fa0SGrygorii Strashko 	slave->mac_control = 0;	/* no link yet */
695*ffad5fa0SGrygorii Strashko 
696*ffad5fa0SGrygorii Strashko 	/* enable forwarding */
697*ffad5fa0SGrygorii Strashko 	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
698*ffad5fa0SGrygorii Strashko 	cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD);
699*ffad5fa0SGrygorii Strashko 
700*ffad5fa0SGrygorii Strashko 	cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << slave_port);
701*ffad5fa0SGrygorii Strashko 
702*ffad5fa0SGrygorii Strashko 	priv->phy_mask |= 1 << slave->data->phy_addr;
703*ffad5fa0SGrygorii Strashko }
704*ffad5fa0SGrygorii Strashko 
705*ffad5fa0SGrygorii Strashko static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv)
706*ffad5fa0SGrygorii Strashko {
707*ffad5fa0SGrygorii Strashko 	struct cpdma_desc *desc = priv->desc_free;
708*ffad5fa0SGrygorii Strashko 
709*ffad5fa0SGrygorii Strashko 	if (desc)
710*ffad5fa0SGrygorii Strashko 		priv->desc_free = desc_read_ptr(desc, hw_next);
711*ffad5fa0SGrygorii Strashko 	return desc;
712*ffad5fa0SGrygorii Strashko }
713*ffad5fa0SGrygorii Strashko 
714*ffad5fa0SGrygorii Strashko static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc)
715*ffad5fa0SGrygorii Strashko {
716*ffad5fa0SGrygorii Strashko 	if (desc) {
717*ffad5fa0SGrygorii Strashko 		desc_write(desc, hw_next, priv->desc_free);
718*ffad5fa0SGrygorii Strashko 		priv->desc_free = desc;
719*ffad5fa0SGrygorii Strashko 	}
720*ffad5fa0SGrygorii Strashko }
721*ffad5fa0SGrygorii Strashko 
722*ffad5fa0SGrygorii Strashko static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan,
723*ffad5fa0SGrygorii Strashko 			void *buffer, int len)
724*ffad5fa0SGrygorii Strashko {
725*ffad5fa0SGrygorii Strashko 	struct cpdma_desc *desc, *prev;
726*ffad5fa0SGrygorii Strashko 	u32 mode;
727*ffad5fa0SGrygorii Strashko 
728*ffad5fa0SGrygorii Strashko 	desc = cpdma_desc_alloc(priv);
729*ffad5fa0SGrygorii Strashko 	if (!desc)
730*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
731*ffad5fa0SGrygorii Strashko 
732*ffad5fa0SGrygorii Strashko 	if (len < PKT_MIN)
733*ffad5fa0SGrygorii Strashko 		len = PKT_MIN;
734*ffad5fa0SGrygorii Strashko 
735*ffad5fa0SGrygorii Strashko 	mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
736*ffad5fa0SGrygorii Strashko 
737*ffad5fa0SGrygorii Strashko 	desc_write(desc, hw_next,   0);
738*ffad5fa0SGrygorii Strashko 	desc_write(desc, hw_buffer, buffer);
739*ffad5fa0SGrygorii Strashko 	desc_write(desc, hw_len,    len);
740*ffad5fa0SGrygorii Strashko 	desc_write(desc, hw_mode,   mode | len);
741*ffad5fa0SGrygorii Strashko 	desc_write(desc, sw_buffer, buffer);
742*ffad5fa0SGrygorii Strashko 	desc_write(desc, sw_len,    len);
743*ffad5fa0SGrygorii Strashko 
744*ffad5fa0SGrygorii Strashko 	if (!chan->head) {
745*ffad5fa0SGrygorii Strashko 		/* simple case - first packet enqueued */
746*ffad5fa0SGrygorii Strashko 		chan->head = desc;
747*ffad5fa0SGrygorii Strashko 		chan->tail = desc;
748*ffad5fa0SGrygorii Strashko 		chan_write(chan, hdp, desc);
749*ffad5fa0SGrygorii Strashko 		goto done;
750*ffad5fa0SGrygorii Strashko 	}
751*ffad5fa0SGrygorii Strashko 
752*ffad5fa0SGrygorii Strashko 	/* not the first packet - enqueue at the tail */
753*ffad5fa0SGrygorii Strashko 	prev = chan->tail;
754*ffad5fa0SGrygorii Strashko 	desc_write(prev, hw_next, desc);
755*ffad5fa0SGrygorii Strashko 	chan->tail = desc;
756*ffad5fa0SGrygorii Strashko 
757*ffad5fa0SGrygorii Strashko 	/* next check if EOQ has been triggered already */
758*ffad5fa0SGrygorii Strashko 	if (desc_read(prev, hw_mode) & CPDMA_DESC_EOQ)
759*ffad5fa0SGrygorii Strashko 		chan_write(chan, hdp, desc);
760*ffad5fa0SGrygorii Strashko 
761*ffad5fa0SGrygorii Strashko done:
762*ffad5fa0SGrygorii Strashko 	if (chan->rxfree)
763*ffad5fa0SGrygorii Strashko 		chan_write(chan, rxfree, 1);
764*ffad5fa0SGrygorii Strashko 	return 0;
765*ffad5fa0SGrygorii Strashko }
766*ffad5fa0SGrygorii Strashko 
767*ffad5fa0SGrygorii Strashko static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan,
768*ffad5fa0SGrygorii Strashko 			 void **buffer, int *len)
769*ffad5fa0SGrygorii Strashko {
770*ffad5fa0SGrygorii Strashko 	struct cpdma_desc *desc = chan->head;
771*ffad5fa0SGrygorii Strashko 	u32 status;
772*ffad5fa0SGrygorii Strashko 
773*ffad5fa0SGrygorii Strashko 	if (!desc)
774*ffad5fa0SGrygorii Strashko 		return -ENOENT;
775*ffad5fa0SGrygorii Strashko 
776*ffad5fa0SGrygorii Strashko 	status = desc_read(desc, hw_mode);
777*ffad5fa0SGrygorii Strashko 
778*ffad5fa0SGrygorii Strashko 	if (len)
779*ffad5fa0SGrygorii Strashko 		*len = status & 0x7ff;
780*ffad5fa0SGrygorii Strashko 
781*ffad5fa0SGrygorii Strashko 	if (buffer)
782*ffad5fa0SGrygorii Strashko 		*buffer = desc_read_ptr(desc, sw_buffer);
783*ffad5fa0SGrygorii Strashko 
784*ffad5fa0SGrygorii Strashko 	if (status & CPDMA_DESC_OWNER) {
785*ffad5fa0SGrygorii Strashko 		if (chan_read(chan, hdp) == 0) {
786*ffad5fa0SGrygorii Strashko 			if (desc_read(desc, hw_mode) & CPDMA_DESC_OWNER)
787*ffad5fa0SGrygorii Strashko 				chan_write(chan, hdp, desc);
788*ffad5fa0SGrygorii Strashko 		}
789*ffad5fa0SGrygorii Strashko 
790*ffad5fa0SGrygorii Strashko 		return -EBUSY;
791*ffad5fa0SGrygorii Strashko 	}
792*ffad5fa0SGrygorii Strashko 
793*ffad5fa0SGrygorii Strashko 	chan->head = desc_read_ptr(desc, hw_next);
794*ffad5fa0SGrygorii Strashko 	chan_write(chan, cp, desc);
795*ffad5fa0SGrygorii Strashko 
796*ffad5fa0SGrygorii Strashko 	cpdma_desc_free(priv, desc);
797*ffad5fa0SGrygorii Strashko 	return 0;
798*ffad5fa0SGrygorii Strashko }
799*ffad5fa0SGrygorii Strashko 
800*ffad5fa0SGrygorii Strashko static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr)
801*ffad5fa0SGrygorii Strashko {
802*ffad5fa0SGrygorii Strashko 	struct cpsw_slave	*slave;
803*ffad5fa0SGrygorii Strashko 	int i, ret;
804*ffad5fa0SGrygorii Strashko 
805*ffad5fa0SGrygorii Strashko 	/* soft reset the controller and initialize priv */
806*ffad5fa0SGrygorii Strashko 	setbit_and_wait_for_clear32(&priv->regs->soft_reset);
807*ffad5fa0SGrygorii Strashko 
808*ffad5fa0SGrygorii Strashko 	/* initialize and reset the address lookup engine */
809*ffad5fa0SGrygorii Strashko 	cpsw_ale_enable(priv, 1);
810*ffad5fa0SGrygorii Strashko 	cpsw_ale_clear(priv, 1);
811*ffad5fa0SGrygorii Strashko 	cpsw_ale_vlan_aware(priv, 0); /* vlan unaware mode */
812*ffad5fa0SGrygorii Strashko 
813*ffad5fa0SGrygorii Strashko 	/* setup host port priority mapping */
814*ffad5fa0SGrygorii Strashko 	__raw_writel(0x76543210, &priv->host_port_regs->cpdma_tx_pri_map);
815*ffad5fa0SGrygorii Strashko 	__raw_writel(0, &priv->host_port_regs->cpdma_rx_chan_map);
816*ffad5fa0SGrygorii Strashko 
817*ffad5fa0SGrygorii Strashko 	/* disable priority elevation and enable statistics on all ports */
818*ffad5fa0SGrygorii Strashko 	__raw_writel(0, &priv->regs->ptype);
819*ffad5fa0SGrygorii Strashko 
820*ffad5fa0SGrygorii Strashko 	/* enable statistics collection only on the host port */
821*ffad5fa0SGrygorii Strashko 	__raw_writel(BIT(priv->host_port), &priv->regs->stat_port_en);
822*ffad5fa0SGrygorii Strashko 	__raw_writel(0x7, &priv->regs->stat_port_en);
823*ffad5fa0SGrygorii Strashko 
824*ffad5fa0SGrygorii Strashko 	cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD);
825*ffad5fa0SGrygorii Strashko 
826*ffad5fa0SGrygorii Strashko 	cpsw_ale_add_ucast(priv, enetaddr, priv->host_port, ALE_SECURE);
827*ffad5fa0SGrygorii Strashko 	cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port);
828*ffad5fa0SGrygorii Strashko 
829*ffad5fa0SGrygorii Strashko 	for_active_slave(slave, priv)
830*ffad5fa0SGrygorii Strashko 		cpsw_slave_init(slave, priv);
831*ffad5fa0SGrygorii Strashko 
832*ffad5fa0SGrygorii Strashko 	ret = cpsw_update_link(priv);
833*ffad5fa0SGrygorii Strashko 	if (ret)
834*ffad5fa0SGrygorii Strashko 		goto out;
835*ffad5fa0SGrygorii Strashko 
836*ffad5fa0SGrygorii Strashko 	/* init descriptor pool */
837*ffad5fa0SGrygorii Strashko 	for (i = 0; i < NUM_DESCS; i++) {
838*ffad5fa0SGrygorii Strashko 		desc_write(&priv->descs[i], hw_next,
839*ffad5fa0SGrygorii Strashko 			   (i == (NUM_DESCS - 1)) ? 0 : &priv->descs[i+1]);
840*ffad5fa0SGrygorii Strashko 	}
841*ffad5fa0SGrygorii Strashko 	priv->desc_free = &priv->descs[0];
842*ffad5fa0SGrygorii Strashko 
843*ffad5fa0SGrygorii Strashko 	/* initialize channels */
844*ffad5fa0SGrygorii Strashko 	if (priv->data.version == CPSW_CTRL_VERSION_2) {
845*ffad5fa0SGrygorii Strashko 		memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan));
846*ffad5fa0SGrygorii Strashko 		priv->rx_chan.hdp       = priv->dma_regs + CPDMA_RXHDP_VER2;
847*ffad5fa0SGrygorii Strashko 		priv->rx_chan.cp        = priv->dma_regs + CPDMA_RXCP_VER2;
848*ffad5fa0SGrygorii Strashko 		priv->rx_chan.rxfree    = priv->dma_regs + CPDMA_RXFREE;
849*ffad5fa0SGrygorii Strashko 
850*ffad5fa0SGrygorii Strashko 		memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan));
851*ffad5fa0SGrygorii Strashko 		priv->tx_chan.hdp       = priv->dma_regs + CPDMA_TXHDP_VER2;
852*ffad5fa0SGrygorii Strashko 		priv->tx_chan.cp        = priv->dma_regs + CPDMA_TXCP_VER2;
853*ffad5fa0SGrygorii Strashko 	} else {
854*ffad5fa0SGrygorii Strashko 		memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan));
855*ffad5fa0SGrygorii Strashko 		priv->rx_chan.hdp       = priv->dma_regs + CPDMA_RXHDP_VER1;
856*ffad5fa0SGrygorii Strashko 		priv->rx_chan.cp        = priv->dma_regs + CPDMA_RXCP_VER1;
857*ffad5fa0SGrygorii Strashko 		priv->rx_chan.rxfree    = priv->dma_regs + CPDMA_RXFREE;
858*ffad5fa0SGrygorii Strashko 
859*ffad5fa0SGrygorii Strashko 		memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan));
860*ffad5fa0SGrygorii Strashko 		priv->tx_chan.hdp       = priv->dma_regs + CPDMA_TXHDP_VER1;
861*ffad5fa0SGrygorii Strashko 		priv->tx_chan.cp        = priv->dma_regs + CPDMA_TXCP_VER1;
862*ffad5fa0SGrygorii Strashko 	}
863*ffad5fa0SGrygorii Strashko 
864*ffad5fa0SGrygorii Strashko 	/* clear dma state */
865*ffad5fa0SGrygorii Strashko 	setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET);
866*ffad5fa0SGrygorii Strashko 
867*ffad5fa0SGrygorii Strashko 	if (priv->data.version == CPSW_CTRL_VERSION_2) {
868*ffad5fa0SGrygorii Strashko 		for (i = 0; i < priv->data.channels; i++) {
869*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4
870*ffad5fa0SGrygorii Strashko 					* i);
871*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4
872*ffad5fa0SGrygorii Strashko 					* i);
873*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4
874*ffad5fa0SGrygorii Strashko 					* i);
875*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4
876*ffad5fa0SGrygorii Strashko 					* i);
877*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4
878*ffad5fa0SGrygorii Strashko 					* i);
879*ffad5fa0SGrygorii Strashko 		}
880*ffad5fa0SGrygorii Strashko 	} else {
881*ffad5fa0SGrygorii Strashko 		for (i = 0; i < priv->data.channels; i++) {
882*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4
883*ffad5fa0SGrygorii Strashko 					* i);
884*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4
885*ffad5fa0SGrygorii Strashko 					* i);
886*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4
887*ffad5fa0SGrygorii Strashko 					* i);
888*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4
889*ffad5fa0SGrygorii Strashko 					* i);
890*ffad5fa0SGrygorii Strashko 			__raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4
891*ffad5fa0SGrygorii Strashko 					* i);
892*ffad5fa0SGrygorii Strashko 
893*ffad5fa0SGrygorii Strashko 		}
894*ffad5fa0SGrygorii Strashko 	}
895*ffad5fa0SGrygorii Strashko 
896*ffad5fa0SGrygorii Strashko 	__raw_writel(1, priv->dma_regs + CPDMA_TXCONTROL);
897*ffad5fa0SGrygorii Strashko 	__raw_writel(1, priv->dma_regs + CPDMA_RXCONTROL);
898*ffad5fa0SGrygorii Strashko 
899*ffad5fa0SGrygorii Strashko 	/* submit rx descs */
900*ffad5fa0SGrygorii Strashko 	for (i = 0; i < PKTBUFSRX; i++) {
901*ffad5fa0SGrygorii Strashko 		ret = cpdma_submit(priv, &priv->rx_chan, net_rx_packets[i],
902*ffad5fa0SGrygorii Strashko 				   PKTSIZE);
903*ffad5fa0SGrygorii Strashko 		if (ret < 0) {
904*ffad5fa0SGrygorii Strashko 			printf("error %d submitting rx desc\n", ret);
905*ffad5fa0SGrygorii Strashko 			break;
906*ffad5fa0SGrygorii Strashko 		}
907*ffad5fa0SGrygorii Strashko 	}
908*ffad5fa0SGrygorii Strashko 
909*ffad5fa0SGrygorii Strashko out:
910*ffad5fa0SGrygorii Strashko 	return ret;
911*ffad5fa0SGrygorii Strashko }
912*ffad5fa0SGrygorii Strashko 
913*ffad5fa0SGrygorii Strashko static int cpsw_reap_completed_packets(struct cpsw_priv *priv)
914*ffad5fa0SGrygorii Strashko {
915*ffad5fa0SGrygorii Strashko 	int timeout = CPDMA_TIMEOUT;
916*ffad5fa0SGrygorii Strashko 
917*ffad5fa0SGrygorii Strashko 	/* reap completed packets */
918*ffad5fa0SGrygorii Strashko 	while (timeout-- &&
919*ffad5fa0SGrygorii Strashko 	       (cpdma_process(priv, &priv->tx_chan, NULL, NULL) >= 0))
920*ffad5fa0SGrygorii Strashko 		;
921*ffad5fa0SGrygorii Strashko 
922*ffad5fa0SGrygorii Strashko 	return timeout;
923*ffad5fa0SGrygorii Strashko }
924*ffad5fa0SGrygorii Strashko 
925*ffad5fa0SGrygorii Strashko static void _cpsw_halt(struct cpsw_priv *priv)
926*ffad5fa0SGrygorii Strashko {
927*ffad5fa0SGrygorii Strashko 	cpsw_reap_completed_packets(priv);
928*ffad5fa0SGrygorii Strashko 
929*ffad5fa0SGrygorii Strashko 	writel(0, priv->dma_regs + CPDMA_TXCONTROL);
930*ffad5fa0SGrygorii Strashko 	writel(0, priv->dma_regs + CPDMA_RXCONTROL);
931*ffad5fa0SGrygorii Strashko 
932*ffad5fa0SGrygorii Strashko 	/* soft reset the controller and initialize priv */
933*ffad5fa0SGrygorii Strashko 	setbit_and_wait_for_clear32(&priv->regs->soft_reset);
934*ffad5fa0SGrygorii Strashko 
935*ffad5fa0SGrygorii Strashko 	/* clear dma state */
936*ffad5fa0SGrygorii Strashko 	setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET);
937*ffad5fa0SGrygorii Strashko 
938*ffad5fa0SGrygorii Strashko }
939*ffad5fa0SGrygorii Strashko 
940*ffad5fa0SGrygorii Strashko static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length)
941*ffad5fa0SGrygorii Strashko {
942*ffad5fa0SGrygorii Strashko 	int timeout;
943*ffad5fa0SGrygorii Strashko 
944*ffad5fa0SGrygorii Strashko 	flush_dcache_range((unsigned long)packet,
945*ffad5fa0SGrygorii Strashko 			   (unsigned long)packet + ALIGN(length, PKTALIGN));
946*ffad5fa0SGrygorii Strashko 
947*ffad5fa0SGrygorii Strashko 	timeout = cpsw_reap_completed_packets(priv);
948*ffad5fa0SGrygorii Strashko 	if (timeout == -1) {
949*ffad5fa0SGrygorii Strashko 		printf("cpdma_process timeout\n");
950*ffad5fa0SGrygorii Strashko 		return -ETIMEDOUT;
951*ffad5fa0SGrygorii Strashko 	}
952*ffad5fa0SGrygorii Strashko 
953*ffad5fa0SGrygorii Strashko 	return cpdma_submit(priv, &priv->tx_chan, packet, length);
954*ffad5fa0SGrygorii Strashko }
955*ffad5fa0SGrygorii Strashko 
956*ffad5fa0SGrygorii Strashko static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt)
957*ffad5fa0SGrygorii Strashko {
958*ffad5fa0SGrygorii Strashko 	void *buffer;
959*ffad5fa0SGrygorii Strashko 	int len;
960*ffad5fa0SGrygorii Strashko 	int ret;
961*ffad5fa0SGrygorii Strashko 
962*ffad5fa0SGrygorii Strashko 	ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len);
963*ffad5fa0SGrygorii Strashko 	if (ret < 0)
964*ffad5fa0SGrygorii Strashko 		return ret;
965*ffad5fa0SGrygorii Strashko 
966*ffad5fa0SGrygorii Strashko 	invalidate_dcache_range((unsigned long)buffer,
967*ffad5fa0SGrygorii Strashko 				(unsigned long)buffer + PKTSIZE_ALIGN);
968*ffad5fa0SGrygorii Strashko 	*pkt = buffer;
969*ffad5fa0SGrygorii Strashko 
970*ffad5fa0SGrygorii Strashko 	return len;
971*ffad5fa0SGrygorii Strashko }
972*ffad5fa0SGrygorii Strashko 
973*ffad5fa0SGrygorii Strashko static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num,
974*ffad5fa0SGrygorii Strashko 			    struct cpsw_priv *priv)
975*ffad5fa0SGrygorii Strashko {
976*ffad5fa0SGrygorii Strashko 	void			*regs = priv->regs;
977*ffad5fa0SGrygorii Strashko 	struct cpsw_slave_data	*data = priv->data.slave_data + slave_num;
978*ffad5fa0SGrygorii Strashko 	slave->slave_num = slave_num;
979*ffad5fa0SGrygorii Strashko 	slave->data	= data;
980*ffad5fa0SGrygorii Strashko 	slave->regs	= regs + data->slave_reg_ofs;
981*ffad5fa0SGrygorii Strashko 	slave->sliver	= regs + data->sliver_reg_ofs;
982*ffad5fa0SGrygorii Strashko }
983*ffad5fa0SGrygorii Strashko 
984*ffad5fa0SGrygorii Strashko static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave)
985*ffad5fa0SGrygorii Strashko {
986*ffad5fa0SGrygorii Strashko 	struct phy_device *phydev;
987*ffad5fa0SGrygorii Strashko 	u32 supported = PHY_GBIT_FEATURES;
988*ffad5fa0SGrygorii Strashko 
989*ffad5fa0SGrygorii Strashko 	phydev = phy_connect(priv->bus,
990*ffad5fa0SGrygorii Strashko 			slave->data->phy_addr,
991*ffad5fa0SGrygorii Strashko 			priv->dev,
992*ffad5fa0SGrygorii Strashko 			slave->data->phy_if);
993*ffad5fa0SGrygorii Strashko 
994*ffad5fa0SGrygorii Strashko 	if (!phydev)
995*ffad5fa0SGrygorii Strashko 		return -1;
996*ffad5fa0SGrygorii Strashko 
997*ffad5fa0SGrygorii Strashko 	phydev->supported &= supported;
998*ffad5fa0SGrygorii Strashko 	phydev->advertising = phydev->supported;
999*ffad5fa0SGrygorii Strashko 
1000*ffad5fa0SGrygorii Strashko #ifdef CONFIG_DM_ETH
1001*ffad5fa0SGrygorii Strashko 	if (slave->data->phy_of_handle)
1002*ffad5fa0SGrygorii Strashko 		phydev->node = offset_to_ofnode(slave->data->phy_of_handle);
1003*ffad5fa0SGrygorii Strashko #endif
1004*ffad5fa0SGrygorii Strashko 
1005*ffad5fa0SGrygorii Strashko 	priv->phydev = phydev;
1006*ffad5fa0SGrygorii Strashko 	phy_config(phydev);
1007*ffad5fa0SGrygorii Strashko 
1008*ffad5fa0SGrygorii Strashko 	return 1;
1009*ffad5fa0SGrygorii Strashko }
1010*ffad5fa0SGrygorii Strashko 
1011*ffad5fa0SGrygorii Strashko static void cpsw_phy_addr_update(struct cpsw_priv *priv)
1012*ffad5fa0SGrygorii Strashko {
1013*ffad5fa0SGrygorii Strashko 	struct cpsw_platform_data *data = &priv->data;
1014*ffad5fa0SGrygorii Strashko 	u16 alive = mdio_regs->alive & GENMASK(15, 0);
1015*ffad5fa0SGrygorii Strashko 	int active = data->active_slave;
1016*ffad5fa0SGrygorii Strashko 	int new_addr = ffs(alive) - 1;
1017*ffad5fa0SGrygorii Strashko 
1018*ffad5fa0SGrygorii Strashko 	/*
1019*ffad5fa0SGrygorii Strashko 	 * If there is only one phy alive and its address does not match
1020*ffad5fa0SGrygorii Strashko 	 * that of active slave, then phy address can safely be updated.
1021*ffad5fa0SGrygorii Strashko 	 */
1022*ffad5fa0SGrygorii Strashko 	if (hweight16(alive) == 1 &&
1023*ffad5fa0SGrygorii Strashko 	    data->slave_data[active].phy_addr != new_addr) {
1024*ffad5fa0SGrygorii Strashko 		printf("Updated phy address for CPSW#%d, old: %d, new: %d\n",
1025*ffad5fa0SGrygorii Strashko 		       active, data->slave_data[active].phy_addr, new_addr);
1026*ffad5fa0SGrygorii Strashko 		data->slave_data[active].phy_addr = new_addr;
1027*ffad5fa0SGrygorii Strashko 	}
1028*ffad5fa0SGrygorii Strashko }
1029*ffad5fa0SGrygorii Strashko 
1030*ffad5fa0SGrygorii Strashko int _cpsw_register(struct cpsw_priv *priv)
1031*ffad5fa0SGrygorii Strashko {
1032*ffad5fa0SGrygorii Strashko 	struct cpsw_slave	*slave;
1033*ffad5fa0SGrygorii Strashko 	struct cpsw_platform_data *data = &priv->data;
1034*ffad5fa0SGrygorii Strashko 	void			*regs = (void *)data->cpsw_base;
1035*ffad5fa0SGrygorii Strashko 
1036*ffad5fa0SGrygorii Strashko 	priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves);
1037*ffad5fa0SGrygorii Strashko 	if (!priv->slaves) {
1038*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
1039*ffad5fa0SGrygorii Strashko 	}
1040*ffad5fa0SGrygorii Strashko 
1041*ffad5fa0SGrygorii Strashko 	priv->host_port		= data->host_port_num;
1042*ffad5fa0SGrygorii Strashko 	priv->regs		= regs;
1043*ffad5fa0SGrygorii Strashko 	priv->host_port_regs	= regs + data->host_port_reg_ofs;
1044*ffad5fa0SGrygorii Strashko 	priv->dma_regs		= regs + data->cpdma_reg_ofs;
1045*ffad5fa0SGrygorii Strashko 	priv->ale_regs		= regs + data->ale_reg_ofs;
1046*ffad5fa0SGrygorii Strashko 	priv->descs		= (void *)regs + data->bd_ram_ofs;
1047*ffad5fa0SGrygorii Strashko 
1048*ffad5fa0SGrygorii Strashko 	int idx = 0;
1049*ffad5fa0SGrygorii Strashko 
1050*ffad5fa0SGrygorii Strashko 	for_each_slave(slave, priv) {
1051*ffad5fa0SGrygorii Strashko 		cpsw_slave_setup(slave, idx, priv);
1052*ffad5fa0SGrygorii Strashko 		idx = idx + 1;
1053*ffad5fa0SGrygorii Strashko 	}
1054*ffad5fa0SGrygorii Strashko 
1055*ffad5fa0SGrygorii Strashko 	cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div);
1056*ffad5fa0SGrygorii Strashko 
1057*ffad5fa0SGrygorii Strashko 	cpsw_phy_addr_update(priv);
1058*ffad5fa0SGrygorii Strashko 
1059*ffad5fa0SGrygorii Strashko 	priv->bus = miiphy_get_dev_by_name(priv->dev->name);
1060*ffad5fa0SGrygorii Strashko 	for_active_slave(slave, priv)
1061*ffad5fa0SGrygorii Strashko 		cpsw_phy_init(priv, slave);
1062*ffad5fa0SGrygorii Strashko 
1063*ffad5fa0SGrygorii Strashko 	return 0;
1064*ffad5fa0SGrygorii Strashko }
1065*ffad5fa0SGrygorii Strashko 
1066*ffad5fa0SGrygorii Strashko #ifndef CONFIG_DM_ETH
1067*ffad5fa0SGrygorii Strashko static int cpsw_init(struct eth_device *dev, bd_t *bis)
1068*ffad5fa0SGrygorii Strashko {
1069*ffad5fa0SGrygorii Strashko 	struct cpsw_priv	*priv = dev->priv;
1070*ffad5fa0SGrygorii Strashko 
1071*ffad5fa0SGrygorii Strashko 	return _cpsw_init(priv, dev->enetaddr);
1072*ffad5fa0SGrygorii Strashko }
1073*ffad5fa0SGrygorii Strashko 
1074*ffad5fa0SGrygorii Strashko static void cpsw_halt(struct eth_device *dev)
1075*ffad5fa0SGrygorii Strashko {
1076*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev->priv;
1077*ffad5fa0SGrygorii Strashko 
1078*ffad5fa0SGrygorii Strashko 	return _cpsw_halt(priv);
1079*ffad5fa0SGrygorii Strashko }
1080*ffad5fa0SGrygorii Strashko 
1081*ffad5fa0SGrygorii Strashko static int cpsw_send(struct eth_device *dev, void *packet, int length)
1082*ffad5fa0SGrygorii Strashko {
1083*ffad5fa0SGrygorii Strashko 	struct cpsw_priv	*priv = dev->priv;
1084*ffad5fa0SGrygorii Strashko 
1085*ffad5fa0SGrygorii Strashko 	return _cpsw_send(priv, packet, length);
1086*ffad5fa0SGrygorii Strashko }
1087*ffad5fa0SGrygorii Strashko 
1088*ffad5fa0SGrygorii Strashko static int cpsw_recv(struct eth_device *dev)
1089*ffad5fa0SGrygorii Strashko {
1090*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev->priv;
1091*ffad5fa0SGrygorii Strashko 	uchar *pkt = NULL;
1092*ffad5fa0SGrygorii Strashko 	int len;
1093*ffad5fa0SGrygorii Strashko 
1094*ffad5fa0SGrygorii Strashko 	len = _cpsw_recv(priv, &pkt);
1095*ffad5fa0SGrygorii Strashko 
1096*ffad5fa0SGrygorii Strashko 	if (len > 0) {
1097*ffad5fa0SGrygorii Strashko 		net_process_received_packet(pkt, len);
1098*ffad5fa0SGrygorii Strashko 		cpdma_submit(priv, &priv->rx_chan, pkt, PKTSIZE);
1099*ffad5fa0SGrygorii Strashko 	}
1100*ffad5fa0SGrygorii Strashko 
1101*ffad5fa0SGrygorii Strashko 	return len;
1102*ffad5fa0SGrygorii Strashko }
1103*ffad5fa0SGrygorii Strashko 
1104*ffad5fa0SGrygorii Strashko int cpsw_register(struct cpsw_platform_data *data)
1105*ffad5fa0SGrygorii Strashko {
1106*ffad5fa0SGrygorii Strashko 	struct cpsw_priv	*priv;
1107*ffad5fa0SGrygorii Strashko 	struct eth_device	*dev;
1108*ffad5fa0SGrygorii Strashko 	int ret;
1109*ffad5fa0SGrygorii Strashko 
1110*ffad5fa0SGrygorii Strashko 	dev = calloc(sizeof(*dev), 1);
1111*ffad5fa0SGrygorii Strashko 	if (!dev)
1112*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
1113*ffad5fa0SGrygorii Strashko 
1114*ffad5fa0SGrygorii Strashko 	priv = calloc(sizeof(*priv), 1);
1115*ffad5fa0SGrygorii Strashko 	if (!priv) {
1116*ffad5fa0SGrygorii Strashko 		free(dev);
1117*ffad5fa0SGrygorii Strashko 		return -ENOMEM;
1118*ffad5fa0SGrygorii Strashko 	}
1119*ffad5fa0SGrygorii Strashko 
1120*ffad5fa0SGrygorii Strashko 	priv->dev = dev;
1121*ffad5fa0SGrygorii Strashko 	priv->data = *data;
1122*ffad5fa0SGrygorii Strashko 
1123*ffad5fa0SGrygorii Strashko 	strcpy(dev->name, "cpsw");
1124*ffad5fa0SGrygorii Strashko 	dev->iobase	= 0;
1125*ffad5fa0SGrygorii Strashko 	dev->init	= cpsw_init;
1126*ffad5fa0SGrygorii Strashko 	dev->halt	= cpsw_halt;
1127*ffad5fa0SGrygorii Strashko 	dev->send	= cpsw_send;
1128*ffad5fa0SGrygorii Strashko 	dev->recv	= cpsw_recv;
1129*ffad5fa0SGrygorii Strashko 	dev->priv	= priv;
1130*ffad5fa0SGrygorii Strashko 
1131*ffad5fa0SGrygorii Strashko 	eth_register(dev);
1132*ffad5fa0SGrygorii Strashko 
1133*ffad5fa0SGrygorii Strashko 	ret = _cpsw_register(priv);
1134*ffad5fa0SGrygorii Strashko 	if (ret < 0) {
1135*ffad5fa0SGrygorii Strashko 		eth_unregister(dev);
1136*ffad5fa0SGrygorii Strashko 		free(dev);
1137*ffad5fa0SGrygorii Strashko 		free(priv);
1138*ffad5fa0SGrygorii Strashko 		return ret;
1139*ffad5fa0SGrygorii Strashko 	}
1140*ffad5fa0SGrygorii Strashko 
1141*ffad5fa0SGrygorii Strashko 	return 1;
1142*ffad5fa0SGrygorii Strashko }
1143*ffad5fa0SGrygorii Strashko #else
1144*ffad5fa0SGrygorii Strashko static int cpsw_eth_start(struct udevice *dev)
1145*ffad5fa0SGrygorii Strashko {
1146*ffad5fa0SGrygorii Strashko 	struct eth_pdata *pdata = dev_get_platdata(dev);
1147*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1148*ffad5fa0SGrygorii Strashko 
1149*ffad5fa0SGrygorii Strashko 	return _cpsw_init(priv, pdata->enetaddr);
1150*ffad5fa0SGrygorii Strashko }
1151*ffad5fa0SGrygorii Strashko 
1152*ffad5fa0SGrygorii Strashko static int cpsw_eth_send(struct udevice *dev, void *packet, int length)
1153*ffad5fa0SGrygorii Strashko {
1154*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1155*ffad5fa0SGrygorii Strashko 
1156*ffad5fa0SGrygorii Strashko 	return _cpsw_send(priv, packet, length);
1157*ffad5fa0SGrygorii Strashko }
1158*ffad5fa0SGrygorii Strashko 
1159*ffad5fa0SGrygorii Strashko static int cpsw_eth_recv(struct udevice *dev, int flags, uchar **packetp)
1160*ffad5fa0SGrygorii Strashko {
1161*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1162*ffad5fa0SGrygorii Strashko 
1163*ffad5fa0SGrygorii Strashko 	return _cpsw_recv(priv, packetp);
1164*ffad5fa0SGrygorii Strashko }
1165*ffad5fa0SGrygorii Strashko 
1166*ffad5fa0SGrygorii Strashko static int cpsw_eth_free_pkt(struct udevice *dev, uchar *packet,
1167*ffad5fa0SGrygorii Strashko 				   int length)
1168*ffad5fa0SGrygorii Strashko {
1169*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1170*ffad5fa0SGrygorii Strashko 
1171*ffad5fa0SGrygorii Strashko 	return cpdma_submit(priv, &priv->rx_chan, packet, PKTSIZE);
1172*ffad5fa0SGrygorii Strashko }
1173*ffad5fa0SGrygorii Strashko 
1174*ffad5fa0SGrygorii Strashko static void cpsw_eth_stop(struct udevice *dev)
1175*ffad5fa0SGrygorii Strashko {
1176*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1177*ffad5fa0SGrygorii Strashko 
1178*ffad5fa0SGrygorii Strashko 	return _cpsw_halt(priv);
1179*ffad5fa0SGrygorii Strashko }
1180*ffad5fa0SGrygorii Strashko 
1181*ffad5fa0SGrygorii Strashko 
1182*ffad5fa0SGrygorii Strashko static int cpsw_eth_probe(struct udevice *dev)
1183*ffad5fa0SGrygorii Strashko {
1184*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1185*ffad5fa0SGrygorii Strashko 
1186*ffad5fa0SGrygorii Strashko 	priv->dev = dev;
1187*ffad5fa0SGrygorii Strashko 
1188*ffad5fa0SGrygorii Strashko 	return _cpsw_register(priv);
1189*ffad5fa0SGrygorii Strashko }
1190*ffad5fa0SGrygorii Strashko 
1191*ffad5fa0SGrygorii Strashko static const struct eth_ops cpsw_eth_ops = {
1192*ffad5fa0SGrygorii Strashko 	.start		= cpsw_eth_start,
1193*ffad5fa0SGrygorii Strashko 	.send		= cpsw_eth_send,
1194*ffad5fa0SGrygorii Strashko 	.recv		= cpsw_eth_recv,
1195*ffad5fa0SGrygorii Strashko 	.free_pkt	= cpsw_eth_free_pkt,
1196*ffad5fa0SGrygorii Strashko 	.stop		= cpsw_eth_stop,
1197*ffad5fa0SGrygorii Strashko };
1198*ffad5fa0SGrygorii Strashko 
1199*ffad5fa0SGrygorii Strashko static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
1200*ffad5fa0SGrygorii Strashko {
1201*ffad5fa0SGrygorii Strashko 	return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL,
1202*ffad5fa0SGrygorii Strashko 						  false);
1203*ffad5fa0SGrygorii Strashko }
1204*ffad5fa0SGrygorii Strashko 
1205*ffad5fa0SGrygorii Strashko static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv,
1206*ffad5fa0SGrygorii Strashko 				 phy_interface_t phy_mode)
1207*ffad5fa0SGrygorii Strashko {
1208*ffad5fa0SGrygorii Strashko 	u32 reg;
1209*ffad5fa0SGrygorii Strashko 	u32 mask;
1210*ffad5fa0SGrygorii Strashko 	u32 mode = 0;
1211*ffad5fa0SGrygorii Strashko 	bool rgmii_id = false;
1212*ffad5fa0SGrygorii Strashko 	int slave = priv->data.active_slave;
1213*ffad5fa0SGrygorii Strashko 
1214*ffad5fa0SGrygorii Strashko 	reg = readl(priv->data.gmii_sel);
1215*ffad5fa0SGrygorii Strashko 
1216*ffad5fa0SGrygorii Strashko 	switch (phy_mode) {
1217*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RMII:
1218*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_RMII;
1219*ffad5fa0SGrygorii Strashko 		break;
1220*ffad5fa0SGrygorii Strashko 
1221*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII:
1222*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_RGMII;
1223*ffad5fa0SGrygorii Strashko 		break;
1224*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_ID:
1225*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_RXID:
1226*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_TXID:
1227*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_RGMII;
1228*ffad5fa0SGrygorii Strashko 		rgmii_id = true;
1229*ffad5fa0SGrygorii Strashko 		break;
1230*ffad5fa0SGrygorii Strashko 
1231*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_MII:
1232*ffad5fa0SGrygorii Strashko 	default:
1233*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_MII;
1234*ffad5fa0SGrygorii Strashko 		break;
1235*ffad5fa0SGrygorii Strashko 	};
1236*ffad5fa0SGrygorii Strashko 
1237*ffad5fa0SGrygorii Strashko 	mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
1238*ffad5fa0SGrygorii Strashko 	mode <<= slave * 2;
1239*ffad5fa0SGrygorii Strashko 
1240*ffad5fa0SGrygorii Strashko 	if (priv->data.rmii_clock_external) {
1241*ffad5fa0SGrygorii Strashko 		if (slave == 0)
1242*ffad5fa0SGrygorii Strashko 			mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
1243*ffad5fa0SGrygorii Strashko 		else
1244*ffad5fa0SGrygorii Strashko 			mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
1245*ffad5fa0SGrygorii Strashko 	}
1246*ffad5fa0SGrygorii Strashko 
1247*ffad5fa0SGrygorii Strashko 	if (rgmii_id) {
1248*ffad5fa0SGrygorii Strashko 		if (slave == 0)
1249*ffad5fa0SGrygorii Strashko 			mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
1250*ffad5fa0SGrygorii Strashko 		else
1251*ffad5fa0SGrygorii Strashko 			mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
1252*ffad5fa0SGrygorii Strashko 	}
1253*ffad5fa0SGrygorii Strashko 
1254*ffad5fa0SGrygorii Strashko 	reg &= ~mask;
1255*ffad5fa0SGrygorii Strashko 	reg |= mode;
1256*ffad5fa0SGrygorii Strashko 
1257*ffad5fa0SGrygorii Strashko 	writel(reg, priv->data.gmii_sel);
1258*ffad5fa0SGrygorii Strashko }
1259*ffad5fa0SGrygorii Strashko 
1260*ffad5fa0SGrygorii Strashko static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv,
1261*ffad5fa0SGrygorii Strashko 				 phy_interface_t phy_mode)
1262*ffad5fa0SGrygorii Strashko {
1263*ffad5fa0SGrygorii Strashko 	u32 reg;
1264*ffad5fa0SGrygorii Strashko 	u32 mask;
1265*ffad5fa0SGrygorii Strashko 	u32 mode = 0;
1266*ffad5fa0SGrygorii Strashko 	int slave = priv->data.active_slave;
1267*ffad5fa0SGrygorii Strashko 
1268*ffad5fa0SGrygorii Strashko 	reg = readl(priv->data.gmii_sel);
1269*ffad5fa0SGrygorii Strashko 
1270*ffad5fa0SGrygorii Strashko 	switch (phy_mode) {
1271*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RMII:
1272*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_RMII;
1273*ffad5fa0SGrygorii Strashko 		break;
1274*ffad5fa0SGrygorii Strashko 
1275*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII:
1276*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_ID:
1277*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_RXID:
1278*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_RGMII_TXID:
1279*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_RGMII;
1280*ffad5fa0SGrygorii Strashko 		break;
1281*ffad5fa0SGrygorii Strashko 
1282*ffad5fa0SGrygorii Strashko 	case PHY_INTERFACE_MODE_MII:
1283*ffad5fa0SGrygorii Strashko 	default:
1284*ffad5fa0SGrygorii Strashko 		mode = AM33XX_GMII_SEL_MODE_MII;
1285*ffad5fa0SGrygorii Strashko 		break;
1286*ffad5fa0SGrygorii Strashko 	};
1287*ffad5fa0SGrygorii Strashko 
1288*ffad5fa0SGrygorii Strashko 	switch (slave) {
1289*ffad5fa0SGrygorii Strashko 	case 0:
1290*ffad5fa0SGrygorii Strashko 		mask = GMII_SEL_MODE_MASK;
1291*ffad5fa0SGrygorii Strashko 		break;
1292*ffad5fa0SGrygorii Strashko 	case 1:
1293*ffad5fa0SGrygorii Strashko 		mask = GMII_SEL_MODE_MASK << 4;
1294*ffad5fa0SGrygorii Strashko 		mode <<= 4;
1295*ffad5fa0SGrygorii Strashko 		break;
1296*ffad5fa0SGrygorii Strashko 	default:
1297*ffad5fa0SGrygorii Strashko 		dev_err(priv->dev, "invalid slave number...\n");
1298*ffad5fa0SGrygorii Strashko 		return;
1299*ffad5fa0SGrygorii Strashko 	}
1300*ffad5fa0SGrygorii Strashko 
1301*ffad5fa0SGrygorii Strashko 	if (priv->data.rmii_clock_external)
1302*ffad5fa0SGrygorii Strashko 		dev_err(priv->dev, "RMII External clock is not supported\n");
1303*ffad5fa0SGrygorii Strashko 
1304*ffad5fa0SGrygorii Strashko 	reg &= ~mask;
1305*ffad5fa0SGrygorii Strashko 	reg |= mode;
1306*ffad5fa0SGrygorii Strashko 
1307*ffad5fa0SGrygorii Strashko 	writel(reg, priv->data.gmii_sel);
1308*ffad5fa0SGrygorii Strashko }
1309*ffad5fa0SGrygorii Strashko 
1310*ffad5fa0SGrygorii Strashko static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat,
1311*ffad5fa0SGrygorii Strashko 			 phy_interface_t phy_mode)
1312*ffad5fa0SGrygorii Strashko {
1313*ffad5fa0SGrygorii Strashko 	if (!strcmp(compat, "ti,am3352-cpsw-phy-sel"))
1314*ffad5fa0SGrygorii Strashko 		cpsw_gmii_sel_am3352(priv, phy_mode);
1315*ffad5fa0SGrygorii Strashko 	if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel"))
1316*ffad5fa0SGrygorii Strashko 		cpsw_gmii_sel_am3352(priv, phy_mode);
1317*ffad5fa0SGrygorii Strashko 	else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel"))
1318*ffad5fa0SGrygorii Strashko 		cpsw_gmii_sel_dra7xx(priv, phy_mode);
1319*ffad5fa0SGrygorii Strashko }
1320*ffad5fa0SGrygorii Strashko 
1321*ffad5fa0SGrygorii Strashko static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
1322*ffad5fa0SGrygorii Strashko {
1323*ffad5fa0SGrygorii Strashko 	struct eth_pdata *pdata = dev_get_platdata(dev);
1324*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1325*ffad5fa0SGrygorii Strashko 	struct gpio_desc *mode_gpios;
1326*ffad5fa0SGrygorii Strashko 	const char *phy_mode;
1327*ffad5fa0SGrygorii Strashko 	const char *phy_sel_compat = NULL;
1328*ffad5fa0SGrygorii Strashko 	const void *fdt = gd->fdt_blob;
1329*ffad5fa0SGrygorii Strashko 	int node = dev_of_offset(dev);
1330*ffad5fa0SGrygorii Strashko 	int subnode;
1331*ffad5fa0SGrygorii Strashko 	int slave_index = 0;
1332*ffad5fa0SGrygorii Strashko 	int active_slave;
1333*ffad5fa0SGrygorii Strashko 	int num_mode_gpios;
1334*ffad5fa0SGrygorii Strashko 	int ret;
1335*ffad5fa0SGrygorii Strashko 
1336*ffad5fa0SGrygorii Strashko 	pdata->iobase = devfdt_get_addr(dev);
1337*ffad5fa0SGrygorii Strashko 	priv->data.version = CPSW_CTRL_VERSION_2;
1338*ffad5fa0SGrygorii Strashko 	priv->data.bd_ram_ofs = CPSW_BD_OFFSET;
1339*ffad5fa0SGrygorii Strashko 	priv->data.ale_reg_ofs = CPSW_ALE_OFFSET;
1340*ffad5fa0SGrygorii Strashko 	priv->data.cpdma_reg_ofs = CPSW_CPDMA_OFFSET;
1341*ffad5fa0SGrygorii Strashko 	priv->data.mdio_div = CPSW_MDIO_DIV;
1342*ffad5fa0SGrygorii Strashko 	priv->data.host_port_reg_ofs = CPSW_HOST_PORT_OFFSET,
1343*ffad5fa0SGrygorii Strashko 
1344*ffad5fa0SGrygorii Strashko 	pdata->phy_interface = -1;
1345*ffad5fa0SGrygorii Strashko 
1346*ffad5fa0SGrygorii Strashko 	priv->data.cpsw_base = pdata->iobase;
1347*ffad5fa0SGrygorii Strashko 	priv->data.channels = fdtdec_get_int(fdt, node, "cpdma_channels", -1);
1348*ffad5fa0SGrygorii Strashko 	if (priv->data.channels <= 0) {
1349*ffad5fa0SGrygorii Strashko 		printf("error: cpdma_channels not found in dt\n");
1350*ffad5fa0SGrygorii Strashko 		return -ENOENT;
1351*ffad5fa0SGrygorii Strashko 	}
1352*ffad5fa0SGrygorii Strashko 
1353*ffad5fa0SGrygorii Strashko 	priv->data.slaves = fdtdec_get_int(fdt, node, "slaves", -1);
1354*ffad5fa0SGrygorii Strashko 	if (priv->data.slaves <= 0) {
1355*ffad5fa0SGrygorii Strashko 		printf("error: slaves not found in dt\n");
1356*ffad5fa0SGrygorii Strashko 		return -ENOENT;
1357*ffad5fa0SGrygorii Strashko 	}
1358*ffad5fa0SGrygorii Strashko 	priv->data.slave_data = malloc(sizeof(struct cpsw_slave_data) *
1359*ffad5fa0SGrygorii Strashko 				       priv->data.slaves);
1360*ffad5fa0SGrygorii Strashko 
1361*ffad5fa0SGrygorii Strashko 	priv->data.ale_entries = fdtdec_get_int(fdt, node, "ale_entries", -1);
1362*ffad5fa0SGrygorii Strashko 	if (priv->data.ale_entries <= 0) {
1363*ffad5fa0SGrygorii Strashko 		printf("error: ale_entries not found in dt\n");
1364*ffad5fa0SGrygorii Strashko 		return -ENOENT;
1365*ffad5fa0SGrygorii Strashko 	}
1366*ffad5fa0SGrygorii Strashko 
1367*ffad5fa0SGrygorii Strashko 	priv->data.bd_ram_ofs = fdtdec_get_int(fdt, node, "bd_ram_size", -1);
1368*ffad5fa0SGrygorii Strashko 	if (priv->data.bd_ram_ofs <= 0) {
1369*ffad5fa0SGrygorii Strashko 		printf("error: bd_ram_size not found in dt\n");
1370*ffad5fa0SGrygorii Strashko 		return -ENOENT;
1371*ffad5fa0SGrygorii Strashko 	}
1372*ffad5fa0SGrygorii Strashko 
1373*ffad5fa0SGrygorii Strashko 	priv->data.mac_control = fdtdec_get_int(fdt, node, "mac_control", -1);
1374*ffad5fa0SGrygorii Strashko 	if (priv->data.mac_control <= 0) {
1375*ffad5fa0SGrygorii Strashko 		printf("error: ale_entries not found in dt\n");
1376*ffad5fa0SGrygorii Strashko 		return -ENOENT;
1377*ffad5fa0SGrygorii Strashko 	}
1378*ffad5fa0SGrygorii Strashko 
1379*ffad5fa0SGrygorii Strashko 	num_mode_gpios = gpio_get_list_count(dev, "mode-gpios");
1380*ffad5fa0SGrygorii Strashko 	if (num_mode_gpios > 0) {
1381*ffad5fa0SGrygorii Strashko 		mode_gpios = malloc(sizeof(struct gpio_desc) *
1382*ffad5fa0SGrygorii Strashko 				    num_mode_gpios);
1383*ffad5fa0SGrygorii Strashko 		gpio_request_list_by_name(dev, "mode-gpios", mode_gpios,
1384*ffad5fa0SGrygorii Strashko 					  num_mode_gpios, GPIOD_IS_OUT);
1385*ffad5fa0SGrygorii Strashko 		free(mode_gpios);
1386*ffad5fa0SGrygorii Strashko 	}
1387*ffad5fa0SGrygorii Strashko 
1388*ffad5fa0SGrygorii Strashko 	active_slave = fdtdec_get_int(fdt, node, "active_slave", 0);
1389*ffad5fa0SGrygorii Strashko 	priv->data.active_slave = active_slave;
1390*ffad5fa0SGrygorii Strashko 
1391*ffad5fa0SGrygorii Strashko 	fdt_for_each_subnode(subnode, fdt, node) {
1392*ffad5fa0SGrygorii Strashko 		int len;
1393*ffad5fa0SGrygorii Strashko 		const char *name;
1394*ffad5fa0SGrygorii Strashko 
1395*ffad5fa0SGrygorii Strashko 		name = fdt_get_name(fdt, subnode, &len);
1396*ffad5fa0SGrygorii Strashko 		if (!strncmp(name, "mdio", 4)) {
1397*ffad5fa0SGrygorii Strashko 			u32 mdio_base;
1398*ffad5fa0SGrygorii Strashko 
1399*ffad5fa0SGrygorii Strashko 			mdio_base = cpsw_get_addr_by_node(fdt, subnode);
1400*ffad5fa0SGrygorii Strashko 			if (mdio_base == FDT_ADDR_T_NONE) {
1401*ffad5fa0SGrygorii Strashko 				pr_err("Not able to get MDIO address space\n");
1402*ffad5fa0SGrygorii Strashko 				return -ENOENT;
1403*ffad5fa0SGrygorii Strashko 			}
1404*ffad5fa0SGrygorii Strashko 			priv->data.mdio_base = mdio_base;
1405*ffad5fa0SGrygorii Strashko 		}
1406*ffad5fa0SGrygorii Strashko 
1407*ffad5fa0SGrygorii Strashko 		if (!strncmp(name, "slave", 5)) {
1408*ffad5fa0SGrygorii Strashko 			u32 phy_id[2];
1409*ffad5fa0SGrygorii Strashko 
1410*ffad5fa0SGrygorii Strashko 			if (slave_index >= priv->data.slaves)
1411*ffad5fa0SGrygorii Strashko 				continue;
1412*ffad5fa0SGrygorii Strashko 			phy_mode = fdt_getprop(fdt, subnode, "phy-mode", NULL);
1413*ffad5fa0SGrygorii Strashko 			if (phy_mode)
1414*ffad5fa0SGrygorii Strashko 				priv->data.slave_data[slave_index].phy_if =
1415*ffad5fa0SGrygorii Strashko 					phy_get_interface_by_name(phy_mode);
1416*ffad5fa0SGrygorii Strashko 
1417*ffad5fa0SGrygorii Strashko 			priv->data.slave_data[slave_index].phy_of_handle =
1418*ffad5fa0SGrygorii Strashko 				fdtdec_lookup_phandle(fdt, subnode,
1419*ffad5fa0SGrygorii Strashko 						      "phy-handle");
1420*ffad5fa0SGrygorii Strashko 
1421*ffad5fa0SGrygorii Strashko 			if (priv->data.slave_data[slave_index].phy_of_handle >= 0) {
1422*ffad5fa0SGrygorii Strashko 				priv->data.slave_data[slave_index].phy_addr =
1423*ffad5fa0SGrygorii Strashko 						fdtdec_get_int(gd->fdt_blob,
1424*ffad5fa0SGrygorii Strashko 							       priv->data.slave_data[slave_index].phy_of_handle,
1425*ffad5fa0SGrygorii Strashko 							       "reg", -1);
1426*ffad5fa0SGrygorii Strashko 			} else {
1427*ffad5fa0SGrygorii Strashko 				fdtdec_get_int_array(fdt, subnode, "phy_id",
1428*ffad5fa0SGrygorii Strashko 						     phy_id, 2);
1429*ffad5fa0SGrygorii Strashko 				priv->data.slave_data[slave_index].phy_addr =
1430*ffad5fa0SGrygorii Strashko 						phy_id[1];
1431*ffad5fa0SGrygorii Strashko 			}
1432*ffad5fa0SGrygorii Strashko 			slave_index++;
1433*ffad5fa0SGrygorii Strashko 		}
1434*ffad5fa0SGrygorii Strashko 
1435*ffad5fa0SGrygorii Strashko 		if (!strncmp(name, "cpsw-phy-sel", 12)) {
1436*ffad5fa0SGrygorii Strashko 			priv->data.gmii_sel = cpsw_get_addr_by_node(fdt,
1437*ffad5fa0SGrygorii Strashko 								    subnode);
1438*ffad5fa0SGrygorii Strashko 
1439*ffad5fa0SGrygorii Strashko 			if (priv->data.gmii_sel == FDT_ADDR_T_NONE) {
1440*ffad5fa0SGrygorii Strashko 				pr_err("Not able to get gmii_sel reg address\n");
1441*ffad5fa0SGrygorii Strashko 				return -ENOENT;
1442*ffad5fa0SGrygorii Strashko 			}
1443*ffad5fa0SGrygorii Strashko 
1444*ffad5fa0SGrygorii Strashko 			if (fdt_get_property(fdt, subnode, "rmii-clock-ext",
1445*ffad5fa0SGrygorii Strashko 					     NULL))
1446*ffad5fa0SGrygorii Strashko 				priv->data.rmii_clock_external = true;
1447*ffad5fa0SGrygorii Strashko 
1448*ffad5fa0SGrygorii Strashko 			phy_sel_compat = fdt_getprop(fdt, subnode, "compatible",
1449*ffad5fa0SGrygorii Strashko 						     NULL);
1450*ffad5fa0SGrygorii Strashko 			if (!phy_sel_compat) {
1451*ffad5fa0SGrygorii Strashko 				pr_err("Not able to get gmii_sel compatible\n");
1452*ffad5fa0SGrygorii Strashko 				return -ENOENT;
1453*ffad5fa0SGrygorii Strashko 			}
1454*ffad5fa0SGrygorii Strashko 		}
1455*ffad5fa0SGrygorii Strashko 	}
1456*ffad5fa0SGrygorii Strashko 
1457*ffad5fa0SGrygorii Strashko 	priv->data.slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET;
1458*ffad5fa0SGrygorii Strashko 	priv->data.slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET;
1459*ffad5fa0SGrygorii Strashko 
1460*ffad5fa0SGrygorii Strashko 	if (priv->data.slaves == 2) {
1461*ffad5fa0SGrygorii Strashko 		priv->data.slave_data[1].slave_reg_ofs = CPSW_SLAVE1_OFFSET;
1462*ffad5fa0SGrygorii Strashko 		priv->data.slave_data[1].sliver_reg_ofs = CPSW_SLIVER1_OFFSET;
1463*ffad5fa0SGrygorii Strashko 	}
1464*ffad5fa0SGrygorii Strashko 
1465*ffad5fa0SGrygorii Strashko 	ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr);
1466*ffad5fa0SGrygorii Strashko 	if (ret < 0) {
1467*ffad5fa0SGrygorii Strashko 		pr_err("cpsw read efuse mac failed\n");
1468*ffad5fa0SGrygorii Strashko 		return ret;
1469*ffad5fa0SGrygorii Strashko 	}
1470*ffad5fa0SGrygorii Strashko 
1471*ffad5fa0SGrygorii Strashko 	pdata->phy_interface = priv->data.slave_data[active_slave].phy_if;
1472*ffad5fa0SGrygorii Strashko 	if (pdata->phy_interface == -1) {
1473*ffad5fa0SGrygorii Strashko 		debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
1474*ffad5fa0SGrygorii Strashko 		return -EINVAL;
1475*ffad5fa0SGrygorii Strashko 	}
1476*ffad5fa0SGrygorii Strashko 
1477*ffad5fa0SGrygorii Strashko 	/* Select phy interface in control module */
1478*ffad5fa0SGrygorii Strashko 	cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface);
1479*ffad5fa0SGrygorii Strashko 
1480*ffad5fa0SGrygorii Strashko 	return 0;
1481*ffad5fa0SGrygorii Strashko }
1482*ffad5fa0SGrygorii Strashko 
1483*ffad5fa0SGrygorii Strashko int cpsw_get_slave_phy_addr(struct udevice *dev, int slave)
1484*ffad5fa0SGrygorii Strashko {
1485*ffad5fa0SGrygorii Strashko 	struct cpsw_priv *priv = dev_get_priv(dev);
1486*ffad5fa0SGrygorii Strashko 	struct cpsw_platform_data *data = &priv->data;
1487*ffad5fa0SGrygorii Strashko 
1488*ffad5fa0SGrygorii Strashko 	return data->slave_data[slave].phy_addr;
1489*ffad5fa0SGrygorii Strashko }
1490*ffad5fa0SGrygorii Strashko 
1491*ffad5fa0SGrygorii Strashko static const struct udevice_id cpsw_eth_ids[] = {
1492*ffad5fa0SGrygorii Strashko 	{ .compatible = "ti,cpsw" },
1493*ffad5fa0SGrygorii Strashko 	{ .compatible = "ti,am335x-cpsw" },
1494*ffad5fa0SGrygorii Strashko 	{ }
1495*ffad5fa0SGrygorii Strashko };
1496*ffad5fa0SGrygorii Strashko 
1497*ffad5fa0SGrygorii Strashko U_BOOT_DRIVER(eth_cpsw) = {
1498*ffad5fa0SGrygorii Strashko 	.name	= "eth_cpsw",
1499*ffad5fa0SGrygorii Strashko 	.id	= UCLASS_ETH,
1500*ffad5fa0SGrygorii Strashko 	.of_match = cpsw_eth_ids,
1501*ffad5fa0SGrygorii Strashko 	.ofdata_to_platdata = cpsw_eth_ofdata_to_platdata,
1502*ffad5fa0SGrygorii Strashko 	.probe	= cpsw_eth_probe,
1503*ffad5fa0SGrygorii Strashko 	.ops	= &cpsw_eth_ops,
1504*ffad5fa0SGrygorii Strashko 	.priv_auto_alloc_size = sizeof(struct cpsw_priv),
1505*ffad5fa0SGrygorii Strashko 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
1506*ffad5fa0SGrygorii Strashko 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
1507*ffad5fa0SGrygorii Strashko };
1508*ffad5fa0SGrygorii Strashko #endif /* CONFIG_DM_ETH */
1509