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