]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
8e585f02 TL |
2 | /* |
3 | * (C) Copyright 2000-2004 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
5 | * | |
f2208fbc | 6 | * (C) Copyright 2007 Freescale Semiconductor, Inc. |
8e585f02 | 7 | * TsiChung Liew ([email protected]) |
a7bcace2 AD |
8 | * |
9 | * Conversion to DM | |
10 | * (C) 2019 Angelo Dureghello <[email protected]> | |
8e585f02 TL |
11 | */ |
12 | ||
03de305e | 13 | #include <config.h> |
8f25b150 | 14 | #include <cpu_func.h> |
7b51b576 | 15 | #include <env.h> |
db41d65a | 16 | #include <hang.h> |
8e585f02 | 17 | #include <malloc.h> |
8e585f02 | 18 | #include <command.h> |
8e585f02 TL |
19 | #include <net.h> |
20 | #include <miiphy.h> | |
54bdcc9f | 21 | #include <asm/fec.h> |
401d1c4f | 22 | #include <asm/global_data.h> |
54bdcc9f | 23 | #include <asm/immap.h> |
c05ed00a | 24 | #include <linux/delay.h> |
68a6aa85 | 25 | #include <linux/mii.h> |
54bdcc9f | 26 | |
8e585f02 TL |
27 | #undef ET_DEBUG |
28 | #undef MII_DEBUG | |
29 | ||
30 | /* Ethernet Transmit and Receive Buffers */ | |
f2208fbc TL |
31 | #define DBUF_LENGTH 1520 |
32 | #define TX_BUF_CNT 2 | |
8e585f02 | 33 | #define PKT_MAXBUF_SIZE 1518 |
8e585f02 TL |
34 | #define PKT_MAXBLR_SIZE 1520 |
35 | #define LAST_PKTBUFSRX PKTBUFSRX - 1 | |
36 | #define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY) | |
37 | #define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST) | |
38 | ||
a7bcace2 AD |
39 | DECLARE_GLOBAL_DATA_PTR; |
40 | ||
41 | static void init_eth_info(struct fec_info_s *info) | |
42 | { | |
65cc0e2a | 43 | #ifdef CFG_SYS_FEC_BUF_USE_SRAM |
a7bcace2 AD |
44 | static u32 tmp; |
45 | ||
46 | if (info->index == 0) | |
65cc0e2a | 47 | tmp = CFG_SYS_INIT_RAM_ADDR + 0x1000; |
a7bcace2 AD |
48 | else |
49 | info->rxbd = (cbd_t *)DBUF_LENGTH; | |
50 | ||
51 | /* setup Receive and Transmit buffer descriptor */ | |
52 | info->rxbd = (cbd_t *)((u32)info->rxbd + tmp); | |
53 | tmp = (u32)info->rxbd; | |
54 | info->txbd = | |
55 | (cbd_t *)((u32)info->txbd + tmp + | |
56 | (PKTBUFSRX * sizeof(cbd_t))); | |
57 | tmp = (u32)info->txbd; | |
58 | info->txbuf = | |
59 | (char *)((u32)info->txbuf + tmp + | |
65cc0e2a | 60 | (CFG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); |
a7bcace2 | 61 | tmp = (u32)info->txbuf; |
1803f7f9 | 62 | #else |
a7bcace2 AD |
63 | info->rxbd = |
64 | (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, | |
65 | (PKTBUFSRX * sizeof(cbd_t))); | |
66 | info->txbd = | |
67 | (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, | |
68 | (TX_BUF_CNT * sizeof(cbd_t))); | |
69 | info->txbuf = | |
70 | (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); | |
1803f7f9 | 71 | #endif |
a7bcace2 AD |
72 | |
73 | #ifdef ET_DEBUG | |
74 | printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd); | |
8e585f02 | 75 | #endif |
a7bcace2 AD |
76 | info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); |
77 | } | |
78 | ||
79 | static void fec_reset(struct fec_info_s *info) | |
80 | { | |
81 | volatile fec_t *fecp = (fec_t *)(info->iobase); | |
82 | int i; | |
83 | ||
84 | fecp->ecr = FEC_ECR_RESET; | |
85 | for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) | |
86 | udelay(1); | |
8e585f02 | 87 | |
a7bcace2 AD |
88 | if (i == FEC_RESET_DELAY) |
89 | printf("FEC_RESET_DELAY timeout\n"); | |
90 | } | |
8e585f02 | 91 | |
a7bcace2 | 92 | static void set_fec_duplex_speed(volatile fec_t *fecp, int dup_spd) |
8e585f02 | 93 | { |
b75d8dc5 | 94 | struct bd_info *bd = gd->bd; |
a7bcace2 | 95 | |
8e585f02 TL |
96 | if ((dup_spd >> 16) == FULL) { |
97 | /* Set maximum frame length */ | |
98 | fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE | | |
99 | FEC_RCR_PROM | 0x100; | |
100 | fecp->tcr = FEC_TCR_FDEN; | |
101 | } else { | |
102 | /* Half duplex mode */ | |
103 | fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | | |
104 | FEC_RCR_MII_MODE | FEC_RCR_DRT; | |
105 | fecp->tcr &= ~FEC_TCR_FDEN; | |
106 | } | |
107 | ||
108 | if ((dup_spd & 0xFFFF) == _100BASET) { | |
109 | #ifdef MII_DEBUG | |
110 | printf("100Mbps\n"); | |
111 | #endif | |
112 | bd->bi_ethspeed = 100; | |
113 | } else { | |
114 | #ifdef MII_DEBUG | |
115 | printf("10Mbps\n"); | |
116 | #endif | |
117 | bd->bi_ethspeed = 10; | |
118 | } | |
119 | } | |
120 | ||
8e585f02 | 121 | #ifdef ET_DEBUG |
a7bcace2 | 122 | static void dbg_fec_regs(struct udevice *dev) |
8e585f02 | 123 | { |
0fd3d911 | 124 | struct fec_info_s *info = dev_get_priv(dev); |
a7bcace2 | 125 | volatile fec_t *fecp = (fec_t *)(info->iobase); |
8e585f02 TL |
126 | |
127 | printf("=====\n"); | |
128 | printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir); | |
129 | printf("imask %x - %x\n", (int)&fecp->eimr, fecp->eimr); | |
130 | printf("r_des_active %x - %x\n", (int)&fecp->rdar, fecp->rdar); | |
131 | printf("x_des_active %x - %x\n", (int)&fecp->tdar, fecp->tdar); | |
132 | printf("ecntrl %x - %x\n", (int)&fecp->ecr, fecp->ecr); | |
133 | printf("mii_mframe %x - %x\n", (int)&fecp->mmfr, fecp->mmfr); | |
134 | printf("mii_speed %x - %x\n", (int)&fecp->mscr, fecp->mscr); | |
135 | printf("mii_ctrlstat %x - %x\n", (int)&fecp->mibc, fecp->mibc); | |
136 | printf("r_cntrl %x - %x\n", (int)&fecp->rcr, fecp->rcr); | |
137 | printf("x_cntrl %x - %x\n", (int)&fecp->tcr, fecp->tcr); | |
138 | printf("padr_l %x - %x\n", (int)&fecp->palr, fecp->palr); | |
139 | printf("padr_u %x - %x\n", (int)&fecp->paur, fecp->paur); | |
140 | printf("op_pause %x - %x\n", (int)&fecp->opd, fecp->opd); | |
141 | printf("iadr_u %x - %x\n", (int)&fecp->iaur, fecp->iaur); | |
142 | printf("iadr_l %x - %x\n", (int)&fecp->ialr, fecp->ialr); | |
143 | printf("gadr_u %x - %x\n", (int)&fecp->gaur, fecp->gaur); | |
144 | printf("gadr_l %x - %x\n", (int)&fecp->galr, fecp->galr); | |
145 | printf("x_wmrk %x - %x\n", (int)&fecp->tfwr, fecp->tfwr); | |
146 | printf("r_bound %x - %x\n", (int)&fecp->frbr, fecp->frbr); | |
147 | printf("r_fstart %x - %x\n", (int)&fecp->frsr, fecp->frsr); | |
148 | printf("r_drng %x - %x\n", (int)&fecp->erdsr, fecp->erdsr); | |
149 | printf("x_drng %x - %x\n", (int)&fecp->etdsr, fecp->etdsr); | |
150 | printf("r_bufsz %x - %x\n", (int)&fecp->emrbr, fecp->emrbr); | |
151 | ||
152 | printf("\n"); | |
153 | printf("rmon_t_drop %x - %x\n", (int)&fecp->rmon_t_drop, | |
154 | fecp->rmon_t_drop); | |
155 | printf("rmon_t_packets %x - %x\n", (int)&fecp->rmon_t_packets, | |
156 | fecp->rmon_t_packets); | |
157 | printf("rmon_t_bc_pkt %x - %x\n", (int)&fecp->rmon_t_bc_pkt, | |
158 | fecp->rmon_t_bc_pkt); | |
159 | printf("rmon_t_mc_pkt %x - %x\n", (int)&fecp->rmon_t_mc_pkt, | |
160 | fecp->rmon_t_mc_pkt); | |
161 | printf("rmon_t_crc_align %x - %x\n", (int)&fecp->rmon_t_crc_align, | |
162 | fecp->rmon_t_crc_align); | |
163 | printf("rmon_t_undersize %x - %x\n", (int)&fecp->rmon_t_undersize, | |
164 | fecp->rmon_t_undersize); | |
165 | printf("rmon_t_oversize %x - %x\n", (int)&fecp->rmon_t_oversize, | |
166 | fecp->rmon_t_oversize); | |
167 | printf("rmon_t_frag %x - %x\n", (int)&fecp->rmon_t_frag, | |
168 | fecp->rmon_t_frag); | |
169 | printf("rmon_t_jab %x - %x\n", (int)&fecp->rmon_t_jab, | |
170 | fecp->rmon_t_jab); | |
171 | printf("rmon_t_col %x - %x\n", (int)&fecp->rmon_t_col, | |
172 | fecp->rmon_t_col); | |
173 | printf("rmon_t_p64 %x - %x\n", (int)&fecp->rmon_t_p64, | |
174 | fecp->rmon_t_p64); | |
175 | printf("rmon_t_p65to127 %x - %x\n", (int)&fecp->rmon_t_p65to127, | |
176 | fecp->rmon_t_p65to127); | |
177 | printf("rmon_t_p128to255 %x - %x\n", (int)&fecp->rmon_t_p128to255, | |
178 | fecp->rmon_t_p128to255); | |
179 | printf("rmon_t_p256to511 %x - %x\n", (int)&fecp->rmon_t_p256to511, | |
180 | fecp->rmon_t_p256to511); | |
181 | printf("rmon_t_p512to1023 %x - %x\n", (int)&fecp->rmon_t_p512to1023, | |
182 | fecp->rmon_t_p512to1023); | |
183 | printf("rmon_t_p1024to2047 %x - %x\n", (int)&fecp->rmon_t_p1024to2047, | |
184 | fecp->rmon_t_p1024to2047); | |
185 | printf("rmon_t_p_gte2048 %x - %x\n", (int)&fecp->rmon_t_p_gte2048, | |
186 | fecp->rmon_t_p_gte2048); | |
187 | printf("rmon_t_octets %x - %x\n", (int)&fecp->rmon_t_octets, | |
188 | fecp->rmon_t_octets); | |
189 | ||
190 | printf("\n"); | |
191 | printf("ieee_t_drop %x - %x\n", (int)&fecp->ieee_t_drop, | |
192 | fecp->ieee_t_drop); | |
193 | printf("ieee_t_frame_ok %x - %x\n", (int)&fecp->ieee_t_frame_ok, | |
194 | fecp->ieee_t_frame_ok); | |
195 | printf("ieee_t_1col %x - %x\n", (int)&fecp->ieee_t_1col, | |
196 | fecp->ieee_t_1col); | |
197 | printf("ieee_t_mcol %x - %x\n", (int)&fecp->ieee_t_mcol, | |
198 | fecp->ieee_t_mcol); | |
199 | printf("ieee_t_def %x - %x\n", (int)&fecp->ieee_t_def, | |
200 | fecp->ieee_t_def); | |
201 | printf("ieee_t_lcol %x - %x\n", (int)&fecp->ieee_t_lcol, | |
202 | fecp->ieee_t_lcol); | |
203 | printf("ieee_t_excol %x - %x\n", (int)&fecp->ieee_t_excol, | |
204 | fecp->ieee_t_excol); | |
205 | printf("ieee_t_macerr %x - %x\n", (int)&fecp->ieee_t_macerr, | |
206 | fecp->ieee_t_macerr); | |
207 | printf("ieee_t_cserr %x - %x\n", (int)&fecp->ieee_t_cserr, | |
208 | fecp->ieee_t_cserr); | |
209 | printf("ieee_t_sqe %x - %x\n", (int)&fecp->ieee_t_sqe, | |
210 | fecp->ieee_t_sqe); | |
211 | printf("ieee_t_fdxfc %x - %x\n", (int)&fecp->ieee_t_fdxfc, | |
212 | fecp->ieee_t_fdxfc); | |
213 | printf("ieee_t_octets_ok %x - %x\n", (int)&fecp->ieee_t_octets_ok, | |
214 | fecp->ieee_t_octets_ok); | |
215 | ||
216 | printf("\n"); | |
217 | printf("rmon_r_drop %x - %x\n", (int)&fecp->rmon_r_drop, | |
218 | fecp->rmon_r_drop); | |
219 | printf("rmon_r_packets %x - %x\n", (int)&fecp->rmon_r_packets, | |
220 | fecp->rmon_r_packets); | |
221 | printf("rmon_r_bc_pkt %x - %x\n", (int)&fecp->rmon_r_bc_pkt, | |
222 | fecp->rmon_r_bc_pkt); | |
223 | printf("rmon_r_mc_pkt %x - %x\n", (int)&fecp->rmon_r_mc_pkt, | |
224 | fecp->rmon_r_mc_pkt); | |
225 | printf("rmon_r_crc_align %x - %x\n", (int)&fecp->rmon_r_crc_align, | |
226 | fecp->rmon_r_crc_align); | |
227 | printf("rmon_r_undersize %x - %x\n", (int)&fecp->rmon_r_undersize, | |
228 | fecp->rmon_r_undersize); | |
229 | printf("rmon_r_oversize %x - %x\n", (int)&fecp->rmon_r_oversize, | |
230 | fecp->rmon_r_oversize); | |
231 | printf("rmon_r_frag %x - %x\n", (int)&fecp->rmon_r_frag, | |
232 | fecp->rmon_r_frag); | |
233 | printf("rmon_r_jab %x - %x\n", (int)&fecp->rmon_r_jab, | |
234 | fecp->rmon_r_jab); | |
235 | printf("rmon_r_p64 %x - %x\n", (int)&fecp->rmon_r_p64, | |
236 | fecp->rmon_r_p64); | |
237 | printf("rmon_r_p65to127 %x - %x\n", (int)&fecp->rmon_r_p65to127, | |
238 | fecp->rmon_r_p65to127); | |
239 | printf("rmon_r_p128to255 %x - %x\n", (int)&fecp->rmon_r_p128to255, | |
240 | fecp->rmon_r_p128to255); | |
241 | printf("rmon_r_p256to511 %x - %x\n", (int)&fecp->rmon_r_p256to511, | |
242 | fecp->rmon_r_p256to511); | |
243 | printf("rmon_r_p512to1023 %x - %x\n", (int)&fecp->rmon_r_p512to1023, | |
244 | fecp->rmon_r_p512to1023); | |
245 | printf("rmon_r_p1024to2047 %x - %x\n", (int)&fecp->rmon_r_p1024to2047, | |
246 | fecp->rmon_r_p1024to2047); | |
247 | printf("rmon_r_p_gte2048 %x - %x\n", (int)&fecp->rmon_r_p_gte2048, | |
248 | fecp->rmon_r_p_gte2048); | |
249 | printf("rmon_r_octets %x - %x\n", (int)&fecp->rmon_r_octets, | |
250 | fecp->rmon_r_octets); | |
251 | ||
252 | printf("\n"); | |
253 | printf("ieee_r_drop %x - %x\n", (int)&fecp->ieee_r_drop, | |
254 | fecp->ieee_r_drop); | |
255 | printf("ieee_r_frame_ok %x - %x\n", (int)&fecp->ieee_r_frame_ok, | |
256 | fecp->ieee_r_frame_ok); | |
257 | printf("ieee_r_crc %x - %x\n", (int)&fecp->ieee_r_crc, | |
258 | fecp->ieee_r_crc); | |
259 | printf("ieee_r_align %x - %x\n", (int)&fecp->ieee_r_align, | |
260 | fecp->ieee_r_align); | |
261 | printf("ieee_r_macerr %x - %x\n", (int)&fecp->ieee_r_macerr, | |
262 | fecp->ieee_r_macerr); | |
263 | printf("ieee_r_fdxfc %x - %x\n", (int)&fecp->ieee_r_fdxfc, | |
264 | fecp->ieee_r_fdxfc); | |
265 | printf("ieee_r_octets_ok %x - %x\n", (int)&fecp->ieee_r_octets_ok, | |
266 | fecp->ieee_r_octets_ok); | |
267 | ||
268 | printf("\n\n\n"); | |
269 | } | |
270 | #endif | |
271 | ||
a7bcace2 | 272 | int mcffec_init(struct udevice *dev) |
8e585f02 | 273 | { |
0fd3d911 | 274 | struct fec_info_s *info = dev_get_priv(dev); |
8e585f02 | 275 | volatile fec_t *fecp = (fec_t *) (info->iobase); |
a7bcace2 | 276 | int rval, i; |
d3f87148 | 277 | uchar ea[6]; |
8e585f02 | 278 | |
a7bcace2 AD |
279 | fecpin_setclear(info, 1); |
280 | fec_reset(info); | |
8e585f02 | 281 | |
8e585f02 TL |
282 | mii_init(); |
283 | ||
a7bcace2 | 284 | set_fec_duplex_speed(fecp, info->dup_spd); |
8e585f02 TL |
285 | |
286 | /* We use strictly polling mode only */ | |
287 | fecp->eimr = 0; | |
288 | ||
289 | /* Clear any pending interrupt */ | |
290 | fecp->eir = 0xffffffff; | |
291 | ||
292 | /* Set station address */ | |
a7bcace2 AD |
293 | if (info->index == 0) |
294 | rval = eth_env_get_enetaddr("ethaddr", ea); | |
295 | else | |
296 | rval = eth_env_get_enetaddr("eth1addr", ea); | |
297 | ||
298 | if (!rval) { | |
299 | puts("Please set a valid MAC address\n"); | |
300 | return -EINVAL; | |
8e585f02 TL |
301 | } |
302 | ||
a7bcace2 AD |
303 | fecp->palr = |
304 | (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); | |
305 | fecp->paur = (ea[4] << 24) | (ea[5] << 16); | |
306 | ||
8e585f02 TL |
307 | /* Clear unicast address hash table */ |
308 | fecp->iaur = 0; | |
309 | fecp->ialr = 0; | |
310 | ||
311 | /* Clear multicast address hash table */ | |
312 | fecp->gaur = 0; | |
313 | fecp->galr = 0; | |
314 | ||
315 | /* Set maximum receive buffer size. */ | |
316 | fecp->emrbr = PKT_MAXBLR_SIZE; | |
317 | ||
318 | /* | |
e4691564 | 319 | * Setup Buffers and Buffer Descriptors |
8e585f02 | 320 | */ |
a7bcace2 AD |
321 | info->rx_idx = 0; |
322 | info->tx_idx = 0; | |
8e585f02 TL |
323 | |
324 | /* | |
325 | * Setup Receiver Buffer Descriptors (13.14.24.18) | |
326 | * Settings: | |
327 | * Empty, Wrap | |
328 | */ | |
329 | for (i = 0; i < PKTBUFSRX; i++) { | |
330 | info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; | |
331 | info->rxbd[i].cbd_datlen = 0; /* Reset */ | |
1fd92db8 | 332 | info->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i]; |
8e585f02 TL |
333 | } |
334 | info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; | |
335 | ||
336 | /* | |
337 | * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19) | |
338 | * Settings: | |
339 | * Last, Tx CRC | |
340 | */ | |
341 | for (i = 0; i < TX_BUF_CNT; i++) { | |
342 | info->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; | |
343 | info->txbd[i].cbd_datlen = 0; /* Reset */ | |
344 | info->txbd[i].cbd_bufaddr = (uint) (&info->txbuf[0]); | |
345 | } | |
346 | info->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; | |
347 | ||
348 | /* Set receive and transmit descriptor base */ | |
349 | fecp->erdsr = (unsigned int)(&info->rxbd[0]); | |
350 | fecp->etdsr = (unsigned int)(&info->txbd[0]); | |
351 | ||
352 | /* Now enable the transmit and receive processing */ | |
353 | fecp->ecr |= FEC_ECR_ETHER_EN; | |
354 | ||
a7bcace2 AD |
355 | /* And last, try to fill Rx Buffer Descriptors |
356 | * Descriptor polling active | |
357 | */ | |
358 | fecp->rdar = 0x01000000; | |
8e585f02 | 359 | |
a7bcace2 | 360 | return 0; |
8e585f02 TL |
361 | } |
362 | ||
a7bcace2 | 363 | static int mcffec_send(struct udevice *dev, void *packet, int length) |
8e585f02 | 364 | { |
0fd3d911 | 365 | struct fec_info_s *info = dev_get_priv(dev); |
a7bcace2 AD |
366 | volatile fec_t *fecp = (fec_t *)info->iobase; |
367 | int j, rc; | |
368 | u16 phy_status; | |
8e585f02 | 369 | |
a7bcace2 AD |
370 | miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status); |
371 | ||
372 | /* section 16.9.23.3 | |
373 | * Wait for ready | |
374 | */ | |
375 | j = 0; | |
376 | while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && | |
377 | (j < info->to_loop)) { | |
8e585f02 | 378 | udelay(1); |
a7bcace2 | 379 | j++; |
8e585f02 | 380 | } |
a7bcace2 AD |
381 | if (j >= info->to_loop) |
382 | printf("TX not ready\n"); | |
383 | ||
384 | info->txbd[info->tx_idx].cbd_bufaddr = (uint)packet; | |
385 | info->txbd[info->tx_idx].cbd_datlen = length; | |
386 | info->txbd[info->tx_idx].cbd_sc |= BD_ENET_TX_RDY_LST; | |
387 | ||
388 | /* Activate transmit Buffer Descriptor polling */ | |
389 | fecp->tdar = 0x01000000; /* Descriptor polling active */ | |
390 | ||
65cc0e2a | 391 | #ifndef CFG_SYS_FEC_BUF_USE_SRAM |
a7bcace2 AD |
392 | /* |
393 | * FEC unable to initial transmit data packet. | |
394 | * A nop will ensure the descriptor polling active completed. | |
395 | * CF Internal RAM has shorter cycle access than DRAM. If use | |
396 | * DRAM as Buffer descriptor and data, a nop is a must. | |
397 | * Affect only V2 and V3. | |
398 | */ | |
399 | __asm__ ("nop"); | |
400 | #endif | |
401 | ||
402 | #ifdef CONFIG_SYS_UNIFY_CACHE | |
8f25b150 | 403 | invalidate_icache_all(); |
a7bcace2 AD |
404 | #endif |
405 | ||
406 | j = 0; | |
407 | while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && | |
408 | (j < info->to_loop)) { | |
409 | udelay(1); | |
410 | j++; | |
411 | } | |
412 | if (j >= info->to_loop) | |
413 | printf("TX timeout\n"); | |
414 | ||
415 | #ifdef ET_DEBUG | |
416 | printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", | |
417 | __FILE__, __LINE__, __func__, j, | |
418 | info->txbd[info->tx_idx].cbd_sc, | |
419 | (info->txbd[info->tx_idx].cbd_sc & 0x003C) >> 2); | |
420 | #endif | |
421 | ||
422 | /* return only status bits */ | |
423 | rc = (info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS); | |
424 | info->tx_idx = (info->tx_idx + 1) % TX_BUF_CNT; | |
425 | ||
426 | return rc; | |
427 | } | |
428 | ||
429 | static int mcffec_recv(struct udevice *dev, int flags, uchar **packetp) | |
430 | { | |
0fd3d911 | 431 | struct fec_info_s *info = dev_get_priv(dev); |
a7bcace2 AD |
432 | volatile fec_t *fecp = (fec_t *)info->iobase; |
433 | int length = -1; | |
434 | ||
435 | for (;;) { | |
436 | #ifdef CONFIG_SYS_UNIFY_CACHE | |
8f25b150 | 437 | invalidate_icache_all(); |
a7bcace2 AD |
438 | #endif |
439 | /* If nothing received - leave for() loop */ | |
440 | if (info->rxbd[info->rx_idx].cbd_sc & BD_ENET_RX_EMPTY) | |
441 | break; | |
442 | ||
443 | length = info->rxbd[info->rx_idx].cbd_datlen; | |
444 | ||
445 | if (info->rxbd[info->rx_idx].cbd_sc & 0x003f) { | |
446 | printf("%s[%d] err: %x\n", | |
447 | __func__, __LINE__, | |
448 | info->rxbd[info->rx_idx].cbd_sc); | |
449 | } else { | |
450 | length -= 4; | |
451 | ||
452 | /* | |
453 | * Pass the buffer ptr up to the protocol layers. | |
454 | */ | |
455 | *packetp = net_rx_packets[info->rx_idx]; | |
456 | ||
457 | fecp->eir |= FEC_EIR_RXF; | |
458 | } | |
459 | ||
460 | /* Give the buffer back to the FEC. */ | |
461 | info->rxbd[info->rx_idx].cbd_datlen = 0; | |
462 | ||
463 | /* wrap around buffer index when necessary */ | |
464 | if (info->rx_idx == LAST_PKTBUFSRX) { | |
465 | info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E; | |
466 | info->rx_idx = 0; | |
467 | } else { | |
468 | info->rxbd[info->rx_idx].cbd_sc = BD_ENET_RX_EMPTY; | |
469 | info->rx_idx++; | |
470 | } | |
471 | ||
472 | /* Try to fill Buffer Descriptors | |
473 | * Descriptor polling active | |
474 | */ | |
475 | fecp->rdar = 0x01000000; | |
8e585f02 | 476 | } |
a7bcace2 AD |
477 | |
478 | return length; | |
8e585f02 TL |
479 | } |
480 | ||
a7bcace2 | 481 | static void mcffec_halt(struct udevice *dev) |
8e585f02 | 482 | { |
0fd3d911 | 483 | struct fec_info_s *info = dev_get_priv(dev); |
8e585f02 | 484 | |
a7bcace2 AD |
485 | fec_reset(info); |
486 | fecpin_setclear(info, 0); | |
8e585f02 | 487 | |
a7bcace2 AD |
488 | info->rx_idx = 0; |
489 | info->tx_idx = 0; | |
8e585f02 | 490 | |
8e585f02 TL |
491 | memset(info->rxbd, 0, PKTBUFSRX * sizeof(cbd_t)); |
492 | memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t)); | |
493 | memset(info->txbuf, 0, DBUF_LENGTH); | |
494 | } | |
495 | ||
a7bcace2 AD |
496 | static const struct eth_ops mcffec_ops = { |
497 | .start = mcffec_init, | |
498 | .send = mcffec_send, | |
499 | .recv = mcffec_recv, | |
500 | .stop = mcffec_halt, | |
501 | }; | |
502 | ||
503 | /* | |
d1998a9f | 504 | * Boot sequence, called just after mcffec_of_to_plat, |
a7bcace2 AD |
505 | * as DM way, it replaces old mcffec_initialize. |
506 | */ | |
507 | static int mcffec_probe(struct udevice *dev) | |
8e585f02 | 508 | { |
c69cda25 | 509 | struct eth_pdata *pdata = dev_get_plat(dev); |
0fd3d911 | 510 | struct fec_info_s *info = dev_get_priv(dev); |
a7bcace2 AD |
511 | int node = dev_of_offset(dev); |
512 | int retval, fec_idx; | |
513 | const u32 *val; | |
8e585f02 | 514 | |
8b85dfc6 | 515 | info->index = dev_seq(dev); |
a7bcace2 AD |
516 | info->iobase = pdata->iobase; |
517 | info->phy_addr = -1; | |
8e585f02 | 518 | |
a7bcace2 AD |
519 | val = fdt_getprop(gd->fdt_blob, node, "mii-base", NULL); |
520 | if (val) { | |
521 | u32 fec_iobase; | |
8e585f02 | 522 | |
a7bcace2 AD |
523 | fec_idx = fdt32_to_cpu(*val); |
524 | if (fec_idx == info->index) { | |
525 | fec_iobase = info->iobase; | |
526 | } else { | |
527 | printf("mii base != base address, fec_idx %d\n", | |
528 | fec_idx); | |
529 | retval = fec_get_base_addr(fec_idx, &fec_iobase); | |
530 | if (retval) | |
531 | return retval; | |
532 | } | |
533 | info->miibase = fec_iobase; | |
534 | } | |
8e585f02 | 535 | |
a7bcace2 AD |
536 | val = fdt_getprop(gd->fdt_blob, node, "phy-addr", NULL); |
537 | if (val) | |
538 | info->phy_addr = fdt32_to_cpu(*val); | |
8e585f02 | 539 | |
a7bcace2 AD |
540 | val = fdt_getprop(gd->fdt_blob, node, "timeout-loop", NULL); |
541 | if (val) | |
542 | info->to_loop = fdt32_to_cpu(*val); | |
8e585f02 | 543 | |
a7bcace2 | 544 | init_eth_info(info); |
1803f7f9 | 545 | |
a7bcace2 AD |
546 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) |
547 | info->bus = mdio_alloc(); | |
548 | if (!info->bus) | |
549 | return -ENOMEM; | |
550 | strcpy(info->bus->name, dev->name); | |
551 | info->bus->read = mcffec_miiphy_read; | |
552 | info->bus->write = mcffec_miiphy_write; | |
553 | ||
554 | retval = mdio_register(info->bus); | |
555 | if (retval < 0) | |
556 | return retval; | |
8e585f02 TL |
557 | #endif |
558 | ||
a7bcace2 AD |
559 | return 0; |
560 | } | |
8e585f02 | 561 | |
a7bcace2 AD |
562 | static int mcffec_remove(struct udevice *dev) |
563 | { | |
564 | struct fec_info_s *priv = dev_get_priv(dev); | |
8e585f02 | 565 | |
a7bcace2 AD |
566 | mdio_unregister(priv->bus); |
567 | mdio_free(priv->bus); | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | /* | |
573 | * Boot sequence, called 1st | |
574 | */ | |
d1998a9f | 575 | static int mcffec_of_to_plat(struct udevice *dev) |
a7bcace2 | 576 | { |
c69cda25 | 577 | struct eth_pdata *pdata = dev_get_plat(dev); |
a7bcace2 | 578 | const u32 *val; |
8e585f02 | 579 | |
2548493a | 580 | pdata->iobase = dev_read_addr(dev); |
a7bcace2 AD |
581 | /* Default to 10Mbit/s */ |
582 | pdata->max_speed = 10; | |
583 | ||
584 | val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), | |
585 | "max-speed", NULL); | |
586 | if (val) | |
587 | pdata->max_speed = fdt32_to_cpu(*val); | |
8e585f02 | 588 | |
86882b80 | 589 | return 0; |
8e585f02 | 590 | } |
a7bcace2 AD |
591 | |
592 | static const struct udevice_id mcffec_ids[] = { | |
593 | { .compatible = "fsl,mcf-fec" }, | |
594 | { } | |
595 | }; | |
596 | ||
597 | U_BOOT_DRIVER(mcffec) = { | |
598 | .name = "mcffec", | |
599 | .id = UCLASS_ETH, | |
600 | .of_match = mcffec_ids, | |
d1998a9f | 601 | .of_to_plat = mcffec_of_to_plat, |
a7bcace2 AD |
602 | .probe = mcffec_probe, |
603 | .remove = mcffec_remove, | |
604 | .ops = &mcffec_ops, | |
41575d8e | 605 | .priv_auto = sizeof(struct fec_info_s), |
caa4daa2 | 606 | .plat_auto = sizeof(struct eth_pdata), |
a7bcace2 | 607 | }; |