]>
Commit | Line | Data |
---|---|---|
42d1f039 | 1 | /* |
97d80fc3 | 2 | * Freescale Three Speed Ethernet Controller driver |
42d1f039 WD |
3 | * |
4 | * This software may be used and distributed according to the | |
5 | * terms of the GNU Public License, Version 2, incorporated | |
6 | * herein by reference. | |
7 | * | |
aec84bf6 | 8 | * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc. |
42d1f039 | 9 | * (C) Copyright 2003, Motorola, Inc. |
42d1f039 WD |
10 | * author Andy Fleming |
11 | * | |
12 | */ | |
13 | ||
14 | #include <config.h> | |
42d1f039 WD |
15 | #include <common.h> |
16 | #include <malloc.h> | |
17 | #include <net.h> | |
18 | #include <command.h> | |
dd3d1f56 | 19 | #include <tsec.h> |
063c1263 | 20 | #include <fsl_mdio.h> |
0d071cdd | 21 | #include <asm/errno.h> |
aada81de | 22 | #include <asm/processor.h> |
52d00a81 | 23 | #include <asm/io.h> |
42d1f039 | 24 | |
d87080b7 WD |
25 | DECLARE_GLOBAL_DATA_PTR; |
26 | ||
63ff004c | 27 | #define TX_BUF_CNT 2 |
42d1f039 | 28 | |
18b338fb CM |
29 | static uint rx_idx; /* index of the current RX buffer */ |
30 | static uint tx_idx; /* index of the current TX buffer */ | |
42d1f039 | 31 | |
42d1f039 | 32 | #ifdef __GNUC__ |
9c9141fd CM |
33 | static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8); |
34 | static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8); | |
35 | ||
42d1f039 WD |
36 | #else |
37 | #error "rtx must be 64-bit aligned" | |
38 | #endif | |
39 | ||
c8a60b53 | 40 | static int tsec_send(struct eth_device *dev, void *packet, int length); |
aada81de | 41 | |
75b9d4ae AF |
42 | /* Default initializations for TSEC controllers. */ |
43 | ||
44 | static struct tsec_info_struct tsec_info[] = { | |
45 | #ifdef CONFIG_TSEC1 | |
46 | STD_TSEC_INFO(1), /* TSEC1 */ | |
47 | #endif | |
48 | #ifdef CONFIG_TSEC2 | |
49 | STD_TSEC_INFO(2), /* TSEC2 */ | |
50 | #endif | |
51 | #ifdef CONFIG_MPC85XX_FEC | |
52 | { | |
aec84bf6 | 53 | .regs = TSEC_GET_REGS(2, 0x2000), |
75b9d4ae AF |
54 | .devname = CONFIG_MPC85XX_FEC_NAME, |
55 | .phyaddr = FEC_PHY_ADDR, | |
063c1263 AF |
56 | .flags = FEC_FLAGS, |
57 | .mii_devname = DEFAULT_MII_NAME | |
75b9d4ae AF |
58 | }, /* FEC */ |
59 | #endif | |
60 | #ifdef CONFIG_TSEC3 | |
61 | STD_TSEC_INFO(3), /* TSEC3 */ | |
62 | #endif | |
63 | #ifdef CONFIG_TSEC4 | |
64 | STD_TSEC_INFO(4), /* TSEC4 */ | |
65 | #endif | |
66 | }; | |
67 | ||
2abe361c AF |
68 | #define TBIANA_SETTINGS ( \ |
69 | TBIANA_ASYMMETRIC_PAUSE \ | |
70 | | TBIANA_SYMMETRIC_PAUSE \ | |
71 | | TBIANA_FULL_DUPLEX \ | |
72 | ) | |
73 | ||
90b5bf21 FR |
74 | /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ |
75 | #ifndef CONFIG_TSEC_TBICR_SETTINGS | |
72c96a68 | 76 | #define CONFIG_TSEC_TBICR_SETTINGS ( \ |
2abe361c | 77 | TBICR_PHY_RESET \ |
72c96a68 | 78 | | TBICR_ANEG_ENABLE \ |
2abe361c AF |
79 | | TBICR_FULL_DUPLEX \ |
80 | | TBICR_SPEED1_SET \ | |
81 | ) | |
90b5bf21 | 82 | #endif /* CONFIG_TSEC_TBICR_SETTINGS */ |
46e91674 | 83 | |
2abe361c AF |
84 | /* Configure the TBI for SGMII operation */ |
85 | static void tsec_configure_serdes(struct tsec_private *priv) | |
86 | { | |
c6dbdfda PT |
87 | /* Access TBI PHY registers at given TSEC register offset as opposed |
88 | * to the register offset used for external PHY accesses */ | |
063c1263 AF |
89 | tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), |
90 | 0, TBI_ANA, TBIANA_SETTINGS); | |
91 | tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), | |
92 | 0, TBI_TBICON, TBICON_CLK_SELECT); | |
93 | tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), | |
94 | 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); | |
97d80fc3 | 95 | } |
42d1f039 | 96 | |
90751910 MH |
97 | #ifdef CONFIG_MCAST_TFTP |
98 | ||
99 | /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ | |
100 | ||
101 | /* Set the appropriate hash bit for the given addr */ | |
102 | ||
103 | /* The algorithm works like so: | |
104 | * 1) Take the Destination Address (ie the multicast address), and | |
105 | * do a CRC on it (little endian), and reverse the bits of the | |
106 | * result. | |
107 | * 2) Use the 8 most significant bits as a hash into a 256-entry | |
108 | * table. The table is controlled through 8 32-bit registers: | |
876d4515 CM |
109 | * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry |
110 | * 255. This means that the 3 most significant bits in the | |
90751910 MH |
111 | * hash index which gaddr register to use, and the 5 other bits |
112 | * indicate which bit (assuming an IBM numbering scheme, which | |
876d4515 | 113 | * for PowerPC (tm) is usually the case) in the register holds |
90751910 MH |
114 | * the entry. */ |
115 | static int | |
9c4cffac | 116 | tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) |
90751910 | 117 | { |
b200204e | 118 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
876d4515 CM |
119 | struct tsec __iomem *regs = priv->regs; |
120 | u32 result, value; | |
121 | u8 whichbit, whichreg; | |
122 | ||
123 | result = ether_crc(MAC_ADDR_LEN, mcast_mac); | |
124 | whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */ | |
125 | whichreg = result >> 29; /* the 3 MSB = which reg to set it in */ | |
126 | ||
127 | value = 1 << (31-whichbit); | |
128 | ||
129 | if (set) | |
130 | setbits_be32(®s->hash.gaddr0 + whichreg, value); | |
131 | else | |
132 | clrbits_be32(®s->hash.gaddr0 + whichreg, value); | |
133 | ||
90751910 MH |
134 | return 0; |
135 | } | |
136 | #endif /* Multicast TFTP ? */ | |
137 | ||
138 | /* Initialized required registers to appropriate values, zeroing | |
139 | * those we don't care about (unless zero is bad, in which case, | |
140 | * choose a more appropriate value) | |
141 | */ | |
aec84bf6 | 142 | static void init_registers(struct tsec __iomem *regs) |
90751910 MH |
143 | { |
144 | /* Clear IEVENT */ | |
145 | out_be32(®s->ievent, IEVENT_INIT_CLEAR); | |
146 | ||
147 | out_be32(®s->imask, IMASK_INIT_CLEAR); | |
148 | ||
149 | out_be32(®s->hash.iaddr0, 0); | |
150 | out_be32(®s->hash.iaddr1, 0); | |
151 | out_be32(®s->hash.iaddr2, 0); | |
152 | out_be32(®s->hash.iaddr3, 0); | |
153 | out_be32(®s->hash.iaddr4, 0); | |
154 | out_be32(®s->hash.iaddr5, 0); | |
155 | out_be32(®s->hash.iaddr6, 0); | |
156 | out_be32(®s->hash.iaddr7, 0); | |
157 | ||
158 | out_be32(®s->hash.gaddr0, 0); | |
159 | out_be32(®s->hash.gaddr1, 0); | |
160 | out_be32(®s->hash.gaddr2, 0); | |
161 | out_be32(®s->hash.gaddr3, 0); | |
162 | out_be32(®s->hash.gaddr4, 0); | |
163 | out_be32(®s->hash.gaddr5, 0); | |
164 | out_be32(®s->hash.gaddr6, 0); | |
165 | out_be32(®s->hash.gaddr7, 0); | |
166 | ||
167 | out_be32(®s->rctrl, 0x00000000); | |
168 | ||
169 | /* Init RMON mib registers */ | |
82ef75ca | 170 | memset((void *)®s->rmon, 0, sizeof(regs->rmon)); |
90751910 MH |
171 | |
172 | out_be32(®s->rmon.cam1, 0xffffffff); | |
173 | out_be32(®s->rmon.cam2, 0xffffffff); | |
174 | ||
175 | out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); | |
176 | ||
177 | out_be32(®s->minflr, MINFLR_INIT_SETTINGS); | |
178 | ||
179 | out_be32(®s->attr, ATTR_INIT_SETTINGS); | |
180 | out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); | |
181 | ||
182 | } | |
183 | ||
184 | /* Configure maccfg2 based on negotiated speed and duplex | |
185 | * reported by PHY handling code | |
186 | */ | |
063c1263 | 187 | static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) |
90751910 | 188 | { |
aec84bf6 | 189 | struct tsec __iomem *regs = priv->regs; |
90751910 MH |
190 | u32 ecntrl, maccfg2; |
191 | ||
063c1263 AF |
192 | if (!phydev->link) { |
193 | printf("%s: No link.\n", phydev->dev->name); | |
90751910 MH |
194 | return; |
195 | } | |
196 | ||
197 | /* clear all bits relative with interface mode */ | |
198 | ecntrl = in_be32(®s->ecntrl); | |
199 | ecntrl &= ~ECNTRL_R100; | |
200 | ||
201 | maccfg2 = in_be32(®s->maccfg2); | |
202 | maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); | |
203 | ||
063c1263 | 204 | if (phydev->duplex) |
90751910 MH |
205 | maccfg2 |= MACCFG2_FULL_DUPLEX; |
206 | ||
063c1263 | 207 | switch (phydev->speed) { |
90751910 MH |
208 | case 1000: |
209 | maccfg2 |= MACCFG2_GMII; | |
210 | break; | |
211 | case 100: | |
212 | case 10: | |
213 | maccfg2 |= MACCFG2_MII; | |
214 | ||
215 | /* Set R100 bit in all modes although | |
216 | * it is only used in RGMII mode | |
217 | */ | |
063c1263 | 218 | if (phydev->speed == 100) |
90751910 MH |
219 | ecntrl |= ECNTRL_R100; |
220 | break; | |
221 | default: | |
063c1263 | 222 | printf("%s: Speed was bad\n", phydev->dev->name); |
90751910 MH |
223 | break; |
224 | } | |
225 | ||
226 | out_be32(®s->ecntrl, ecntrl); | |
227 | out_be32(®s->maccfg2, maccfg2); | |
3dd7f0f0 | 228 | |
063c1263 AF |
229 | printf("Speed: %d, %s duplex%s\n", phydev->speed, |
230 | (phydev->duplex) ? "full" : "half", | |
231 | (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); | |
90751910 | 232 | } |
9d46ea4a | 233 | |
aada81de | 234 | #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 |
235 | /* | |
236 | * When MACCFG1[Rx_EN] is enabled during system boot as part | |
237 | * of the eTSEC port initialization sequence, | |
238 | * the eTSEC Rx logic may not be properly initialized. | |
239 | */ | |
240 | void redundant_init(struct eth_device *dev) | |
241 | { | |
242 | struct tsec_private *priv = dev->priv; | |
aec84bf6 | 243 | struct tsec __iomem *regs = priv->regs; |
aada81de | 244 | uint t, count = 0; |
245 | int fail = 1; | |
246 | static const u8 pkt[] = { | |
247 | 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25, | |
248 | 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00, | |
249 | 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01, | |
250 | 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1, | |
251 | 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00, | |
252 | 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, | |
253 | 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, | |
254 | 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, | |
255 | 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, | |
256 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, | |
257 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, | |
258 | 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, | |
259 | 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, | |
260 | 0x71, 0x72}; | |
261 | ||
262 | /* Enable promiscuous mode */ | |
263 | setbits_be32(®s->rctrl, 0x8); | |
264 | /* Enable loopback mode */ | |
265 | setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); | |
266 | /* Enable transmit and receive */ | |
267 | setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); | |
268 | ||
269 | /* Tell the DMA it is clear to go */ | |
270 | setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); | |
271 | out_be32(®s->tstat, TSTAT_CLEAR_THALT); | |
272 | out_be32(®s->rstat, RSTAT_CLEAR_RHALT); | |
273 | clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); | |
52d00a81 AW |
274 | #ifdef CONFIG_LS102XA |
275 | setbits_be32(®s->dmactrl, DMACTRL_LE); | |
276 | #endif | |
aada81de | 277 | |
278 | do { | |
9c9141fd | 279 | uint16_t status; |
aada81de | 280 | tsec_send(dev, (void *)pkt, sizeof(pkt)); |
281 | ||
282 | /* Wait for buffer to be received */ | |
9c9141fd | 283 | for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) { |
aada81de | 284 | if (t >= 10 * TOUT_LOOP) { |
285 | printf("%s: tsec: rx error\n", dev->name); | |
286 | break; | |
287 | } | |
288 | } | |
289 | ||
18b338fb | 290 | if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt))) |
aada81de | 291 | fail = 0; |
292 | ||
9c9141fd CM |
293 | out_be16(&rxbd[rx_idx].length, 0); |
294 | status = RXBD_EMPTY; | |
295 | if ((rx_idx + 1) == PKTBUFSRX) | |
296 | status |= RXBD_WRAP; | |
297 | out_be16(&rxbd[rx_idx].status, status); | |
18b338fb | 298 | rx_idx = (rx_idx + 1) % PKTBUFSRX; |
aada81de | 299 | |
300 | if (in_be32(®s->ievent) & IEVENT_BSY) { | |
301 | out_be32(®s->ievent, IEVENT_BSY); | |
302 | out_be32(®s->rstat, RSTAT_CLEAR_RHALT); | |
303 | } | |
304 | if (fail) { | |
305 | printf("loopback recv packet error!\n"); | |
306 | clrbits_be32(®s->maccfg1, MACCFG1_RX_EN); | |
307 | udelay(1000); | |
308 | setbits_be32(®s->maccfg1, MACCFG1_RX_EN); | |
309 | } | |
310 | } while ((count++ < 4) && (fail == 1)); | |
311 | ||
312 | if (fail) | |
313 | panic("eTSEC init fail!\n"); | |
314 | /* Disable promiscuous mode */ | |
315 | clrbits_be32(®s->rctrl, 0x8); | |
316 | /* Disable loopback mode */ | |
317 | clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); | |
318 | } | |
319 | #endif | |
320 | ||
90751910 MH |
321 | /* Set up the buffers and their descriptors, and bring up the |
322 | * interface | |
89875e96 | 323 | */ |
90751910 | 324 | static void startup_tsec(struct eth_device *dev) |
be5048f1 | 325 | { |
90751910 | 326 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
aec84bf6 | 327 | struct tsec __iomem *regs = priv->regs; |
9c9141fd CM |
328 | uint16_t status; |
329 | int i; | |
be5048f1 | 330 | |
063c1263 | 331 | /* reset the indices to zero */ |
18b338fb CM |
332 | rx_idx = 0; |
333 | tx_idx = 0; | |
aada81de | 334 | #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 |
335 | uint svr; | |
336 | #endif | |
063c1263 | 337 | |
90751910 | 338 | /* Point to the buffer descriptors */ |
9c9141fd CM |
339 | out_be32(®s->tbase, (u32)&txbd[0]); |
340 | out_be32(®s->rbase, (u32)&rxbd[0]); | |
be5048f1 | 341 | |
90751910 MH |
342 | /* Initialize the Rx Buffer descriptors */ |
343 | for (i = 0; i < PKTBUFSRX; i++) { | |
9c9141fd CM |
344 | out_be16(&rxbd[i].status, RXBD_EMPTY); |
345 | out_be16(&rxbd[i].length, 0); | |
346 | out_be32(&rxbd[i].bufptr, (u32)NetRxPackets[i]); | |
90751910 | 347 | } |
9c9141fd CM |
348 | status = in_be16(&rxbd[PKTBUFSRX - 1].status); |
349 | out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP); | |
be5048f1 | 350 | |
90751910 MH |
351 | /* Initialize the TX Buffer Descriptors */ |
352 | for (i = 0; i < TX_BUF_CNT; i++) { | |
9c9141fd CM |
353 | out_be16(&txbd[i].status, 0); |
354 | out_be16(&txbd[i].length, 0); | |
355 | out_be32(&txbd[i].bufptr, 0); | |
be5048f1 | 356 | } |
9c9141fd CM |
357 | status = in_be16(&txbd[TX_BUF_CNT - 1].status); |
358 | out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP); | |
be5048f1 | 359 | |
aada81de | 360 | #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 |
361 | svr = get_svr(); | |
362 | if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) | |
363 | redundant_init(dev); | |
364 | #endif | |
90751910 MH |
365 | /* Enable Transmit and Receive */ |
366 | setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); | |
367 | ||
368 | /* Tell the DMA it is clear to go */ | |
369 | setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); | |
370 | out_be32(®s->tstat, TSTAT_CLEAR_THALT); | |
371 | out_be32(®s->rstat, RSTAT_CLEAR_RHALT); | |
372 | clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); | |
52d00a81 AW |
373 | #ifdef CONFIG_LS102XA |
374 | setbits_be32(®s->dmactrl, DMACTRL_LE); | |
375 | #endif | |
be5048f1 WD |
376 | } |
377 | ||
90751910 MH |
378 | /* This returns the status bits of the device. The return value |
379 | * is never checked, and this is what the 8260 driver did, so we | |
380 | * do the same. Presumably, this would be zero if there were no | |
381 | * errors | |
382 | */ | |
c8a60b53 | 383 | static int tsec_send(struct eth_device *dev, void *packet, int length) |
90751910 | 384 | { |
90751910 | 385 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
aec84bf6 | 386 | struct tsec __iomem *regs = priv->regs; |
9c9141fd CM |
387 | uint16_t status; |
388 | int result = 0; | |
389 | int i; | |
be5048f1 | 390 | |
90751910 | 391 | /* Find an empty buffer descriptor */ |
9c9141fd | 392 | for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { |
90751910 MH |
393 | if (i >= TOUT_LOOP) { |
394 | debug("%s: tsec: tx buffers full\n", dev->name); | |
395 | return result; | |
396 | } | |
397 | } | |
18ee320f | 398 | |
9c9141fd CM |
399 | out_be32(&txbd[tx_idx].bufptr, (u32)packet); |
400 | out_be16(&txbd[tx_idx].length, length); | |
401 | status = in_be16(&txbd[tx_idx].status); | |
402 | out_be16(&txbd[tx_idx].status, status | | |
403 | (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT)); | |
19d68d20 | 404 | |
90751910 MH |
405 | /* Tell the DMA to go */ |
406 | out_be32(®s->tstat, TSTAT_CLEAR_THALT); | |
97d80fc3 | 407 | |
90751910 | 408 | /* Wait for buffer to be transmitted */ |
9c9141fd | 409 | for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { |
90751910 MH |
410 | if (i >= TOUT_LOOP) { |
411 | debug("%s: tsec: tx error\n", dev->name); | |
412 | return result; | |
413 | } | |
414 | } | |
415 | ||
18b338fb | 416 | tx_idx = (tx_idx + 1) % TX_BUF_CNT; |
9c9141fd | 417 | result = in_be16(&txbd[tx_idx].status) & TXBD_STATS; |
90751910 MH |
418 | |
419 | return result; | |
420 | } | |
421 | ||
422 | static int tsec_recv(struct eth_device *dev) | |
97d80fc3 WD |
423 | { |
424 | struct tsec_private *priv = (struct tsec_private *)dev->priv; | |
aec84bf6 | 425 | struct tsec __iomem *regs = priv->regs; |
97d80fc3 | 426 | |
9c9141fd CM |
427 | while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) { |
428 | int length = in_be16(&rxbd[rx_idx].length); | |
429 | uint16_t status = in_be16(&rxbd[rx_idx].status); | |
97d80fc3 | 430 | |
90751910 | 431 | /* Send the packet up if there were no errors */ |
9c9141fd | 432 | if (!(status & RXBD_STATS)) |
18b338fb | 433 | NetReceive(NetRxPackets[rx_idx], length - 4); |
9c9141fd CM |
434 | else |
435 | printf("Got error %x\n", (status & RXBD_STATS)); | |
90751910 | 436 | |
9c9141fd | 437 | out_be16(&rxbd[rx_idx].length, 0); |
90751910 | 438 | |
9c9141fd | 439 | status = RXBD_EMPTY; |
90751910 | 440 | /* Set the wrap bit if this is the last element in the list */ |
9c9141fd CM |
441 | if ((rx_idx + 1) == PKTBUFSRX) |
442 | status |= RXBD_WRAP; | |
443 | out_be16(&rxbd[rx_idx].status, status); | |
90751910 | 444 | |
18b338fb | 445 | rx_idx = (rx_idx + 1) % PKTBUFSRX; |
97d80fc3 WD |
446 | } |
447 | ||
90751910 MH |
448 | if (in_be32(®s->ievent) & IEVENT_BSY) { |
449 | out_be32(®s->ievent, IEVENT_BSY); | |
450 | out_be32(®s->rstat, RSTAT_CLEAR_RHALT); | |
97d80fc3 WD |
451 | } |
452 | ||
90751910 MH |
453 | return -1; |
454 | ||
42d1f039 | 455 | } |
7abf0c58 | 456 | |
90751910 MH |
457 | /* Stop the interface */ |
458 | static void tsec_halt(struct eth_device *dev) | |
459 | { | |
460 | struct tsec_private *priv = (struct tsec_private *)dev->priv; | |
aec84bf6 | 461 | struct tsec __iomem *regs = priv->regs; |
90751910 MH |
462 | |
463 | clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); | |
464 | setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); | |
465 | ||
466 | while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) | |
467 | != (IEVENT_GRSC | IEVENT_GTSC)) | |
468 | ; | |
469 | ||
470 | clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); | |
471 | ||
472 | /* Shut down the PHY, as needed */ | |
063c1263 | 473 | phy_shutdown(priv->phydev); |
90751910 MH |
474 | } |
475 | ||
476 | /* Initializes data structures and registers for the controller, | |
477 | * and brings the interface up. Returns the link status, meaning | |
478 | * that it returns success if the link is up, failure otherwise. | |
479 | * This allows u-boot to find the first active controller. | |
89875e96 | 480 | */ |
90751910 | 481 | static int tsec_init(struct eth_device *dev, bd_t * bd) |
97d80fc3 | 482 | { |
90751910 | 483 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
aec84bf6 | 484 | struct tsec __iomem *regs = priv->regs; |
b1690bc3 | 485 | u32 tempval; |
11af8d65 | 486 | int ret; |
97d80fc3 | 487 | |
90751910 MH |
488 | /* Make sure the controller is stopped */ |
489 | tsec_halt(dev); | |
97d80fc3 | 490 | |
90751910 MH |
491 | /* Init MACCFG2. Defaults to GMII */ |
492 | out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); | |
97d80fc3 | 493 | |
90751910 MH |
494 | /* Init ECNTRL */ |
495 | out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); | |
97d80fc3 | 496 | |
90751910 | 497 | /* Copy the station address into the address registers. |
b1690bc3 CM |
498 | * For a station address of 0x12345678ABCD in transmission |
499 | * order (BE), MACnADDR1 is set to 0xCDAB7856 and | |
500 | * MACnADDR2 is set to 0x34120000. | |
501 | */ | |
502 | tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) | | |
503 | (dev->enetaddr[3] << 8) | dev->enetaddr[2]; | |
97d80fc3 | 504 | |
90751910 | 505 | out_be32(®s->macstnaddr1, tempval); |
97d80fc3 | 506 | |
b1690bc3 | 507 | tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); |
97d80fc3 | 508 | |
90751910 | 509 | out_be32(®s->macstnaddr2, tempval); |
97d80fc3 | 510 | |
90751910 MH |
511 | /* Clear out (for the most part) the other registers */ |
512 | init_registers(regs); | |
513 | ||
514 | /* Ready the device for tx/rx */ | |
515 | startup_tsec(dev); | |
516 | ||
063c1263 | 517 | /* Start up the PHY */ |
11af8d65 TT |
518 | ret = phy_startup(priv->phydev); |
519 | if (ret) { | |
520 | printf("Could not initialize PHY %s\n", | |
521 | priv->phydev->dev->name); | |
522 | return ret; | |
523 | } | |
063c1263 AF |
524 | |
525 | adjust_link(priv, priv->phydev); | |
526 | ||
90751910 | 527 | /* If there's no link, fail */ |
063c1263 AF |
528 | return priv->phydev->link ? 0 : -1; |
529 | } | |
530 | ||
531 | static phy_interface_t tsec_get_interface(struct tsec_private *priv) | |
532 | { | |
aec84bf6 | 533 | struct tsec __iomem *regs = priv->regs; |
063c1263 AF |
534 | u32 ecntrl; |
535 | ||
536 | ecntrl = in_be32(®s->ecntrl); | |
537 | ||
538 | if (ecntrl & ECNTRL_SGMII_MODE) | |
539 | return PHY_INTERFACE_MODE_SGMII; | |
540 | ||
541 | if (ecntrl & ECNTRL_TBI_MODE) { | |
542 | if (ecntrl & ECNTRL_REDUCED_MODE) | |
543 | return PHY_INTERFACE_MODE_RTBI; | |
544 | else | |
545 | return PHY_INTERFACE_MODE_TBI; | |
546 | } | |
547 | ||
548 | if (ecntrl & ECNTRL_REDUCED_MODE) { | |
549 | if (ecntrl & ECNTRL_REDUCED_MII_MODE) | |
550 | return PHY_INTERFACE_MODE_RMII; | |
551 | else { | |
552 | phy_interface_t interface = priv->interface; | |
553 | ||
554 | /* | |
555 | * This isn't autodetected, so it must | |
556 | * be set by the platform code. | |
557 | */ | |
558 | if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || | |
559 | (interface == PHY_INTERFACE_MODE_RGMII_TXID) || | |
560 | (interface == PHY_INTERFACE_MODE_RGMII_RXID)) | |
561 | return interface; | |
562 | ||
563 | return PHY_INTERFACE_MODE_RGMII; | |
564 | } | |
565 | } | |
566 | ||
567 | if (priv->flags & TSEC_GIGABIT) | |
568 | return PHY_INTERFACE_MODE_GMII; | |
569 | ||
570 | return PHY_INTERFACE_MODE_MII; | |
90751910 MH |
571 | } |
572 | ||
063c1263 | 573 | |
90751910 MH |
574 | /* Discover which PHY is attached to the device, and configure it |
575 | * properly. If the PHY is not recognized, then return 0 | |
576 | * (failure). Otherwise, return 1 | |
7abf0c58 | 577 | */ |
90751910 | 578 | static int init_phy(struct eth_device *dev) |
7abf0c58 | 579 | { |
90751910 | 580 | struct tsec_private *priv = (struct tsec_private *)dev->priv; |
063c1263 | 581 | struct phy_device *phydev; |
aec84bf6 | 582 | struct tsec __iomem *regs = priv->regs; |
063c1263 AF |
583 | u32 supported = (SUPPORTED_10baseT_Half | |
584 | SUPPORTED_10baseT_Full | | |
585 | SUPPORTED_100baseT_Half | | |
586 | SUPPORTED_100baseT_Full); | |
587 | ||
588 | if (priv->flags & TSEC_GIGABIT) | |
589 | supported |= SUPPORTED_1000baseT_Full; | |
97d80fc3 | 590 | |
90751910 MH |
591 | /* Assign a Physical address to the TBI */ |
592 | out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); | |
593 | ||
063c1263 | 594 | priv->interface = tsec_get_interface(priv); |
90751910 | 595 | |
063c1263 AF |
596 | if (priv->interface == PHY_INTERFACE_MODE_SGMII) |
597 | tsec_configure_serdes(priv); | |
90751910 | 598 | |
063c1263 | 599 | phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); |
7f233c05 CM |
600 | if (!phydev) |
601 | return 0; | |
7abf0c58 | 602 | |
063c1263 AF |
603 | phydev->supported &= supported; |
604 | phydev->advertising = phydev->supported; | |
7abf0c58 | 605 | |
063c1263 | 606 | priv->phydev = phydev; |
90751910 | 607 | |
063c1263 | 608 | phy_config(phydev); |
90751910 MH |
609 | |
610 | return 1; | |
7abf0c58 WD |
611 | } |
612 | ||
90751910 MH |
613 | /* Initialize device structure. Returns success if PHY |
614 | * initialization succeeded (i.e. if it recognizes the PHY) | |
7abf0c58 | 615 | */ |
90751910 | 616 | static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) |
7abf0c58 | 617 | { |
90751910 MH |
618 | struct eth_device *dev; |
619 | int i; | |
620 | struct tsec_private *priv; | |
97d80fc3 | 621 | |
90751910 | 622 | dev = (struct eth_device *)malloc(sizeof *dev); |
7abf0c58 | 623 | |
90751910 MH |
624 | if (NULL == dev) |
625 | return 0; | |
7abf0c58 | 626 | |
90751910 | 627 | memset(dev, 0, sizeof *dev); |
97d80fc3 | 628 | |
90751910 MH |
629 | priv = (struct tsec_private *)malloc(sizeof(*priv)); |
630 | ||
631 | if (NULL == priv) | |
632 | return 0; | |
633 | ||
90751910 | 634 | priv->regs = tsec_info->regs; |
90751910 MH |
635 | priv->phyregs_sgmii = tsec_info->miiregs_sgmii; |
636 | ||
637 | priv->phyaddr = tsec_info->phyaddr; | |
638 | priv->flags = tsec_info->flags; | |
97d80fc3 | 639 | |
90751910 | 640 | sprintf(dev->name, tsec_info->devname); |
063c1263 AF |
641 | priv->interface = tsec_info->interface; |
642 | priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); | |
90751910 MH |
643 | dev->iobase = 0; |
644 | dev->priv = priv; | |
645 | dev->init = tsec_init; | |
646 | dev->halt = tsec_halt; | |
647 | dev->send = tsec_send; | |
648 | dev->recv = tsec_recv; | |
53a5c424 | 649 | #ifdef CONFIG_MCAST_TFTP |
90751910 MH |
650 | dev->mcast = tsec_mcast_addr; |
651 | #endif | |
53a5c424 | 652 | |
90751910 MH |
653 | /* Tell u-boot to get the addr from the env */ |
654 | for (i = 0; i < 6; i++) | |
655 | dev->enetaddr[i] = 0; | |
53a5c424 | 656 | |
90751910 | 657 | eth_register(dev); |
53a5c424 | 658 | |
90751910 MH |
659 | /* Reset the MAC */ |
660 | setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); | |
661 | udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ | |
662 | clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); | |
53a5c424 | 663 | |
90751910 MH |
664 | /* Try to initialize PHY here, and return */ |
665 | return init_phy(dev); | |
666 | } | |
53a5c424 | 667 | |
90751910 MH |
668 | /* |
669 | * Initialize all the TSEC devices | |
670 | * | |
671 | * Returns the number of TSEC devices that were initialized | |
672 | */ | |
673 | int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) | |
674 | { | |
675 | int i; | |
676 | int ret, count = 0; | |
677 | ||
678 | for (i = 0; i < num; i++) { | |
679 | ret = tsec_initialize(bis, &tsecs[i]); | |
680 | if (ret > 0) | |
681 | count += ret; | |
53a5c424 | 682 | } |
90751910 MH |
683 | |
684 | return count; | |
53a5c424 | 685 | } |
90751910 MH |
686 | |
687 | int tsec_standard_init(bd_t *bis) | |
688 | { | |
063c1263 AF |
689 | struct fsl_pq_mdio_info info; |
690 | ||
aec84bf6 | 691 | info.regs = TSEC_GET_MDIO_REGS_BASE(1); |
063c1263 AF |
692 | info.name = DEFAULT_MII_NAME; |
693 | ||
694 | fsl_pq_mdio_init(bis, &info); | |
695 | ||
90751910 MH |
696 | return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); |
697 | } |