blob: 2d0517af2158a81535fe5dbb7bcd6fbdae2abd41 [file] [log] [blame]
wdenk42d1f032003-10-15 23:53:47 +00001/*
2 * tsec.c
3 * Motorola Three Speed Ethernet Controller driver
4 *
5 * This software may be used and distributed according to the
6 * terms of the GNU Public License, Version 2, incorporated
7 * herein by reference.
8 *
9 * (C) Copyright 2003, Motorola, Inc.
10 * maintained by Xianghua Xiao (x.xiao@motorola.com)
11 * author Andy Fleming
12 *
13 */
14
15#include <config.h>
16#include <mpc85xx.h>
17#include <common.h>
18#include <malloc.h>
19#include <net.h>
20#include <command.h>
21
22#if defined(CONFIG_TSEC_ENET)
23#include "tsec.h"
24
25#define TX_BUF_CNT 2
26
27#undef TSEC_DEBUG
28#ifdef TSEC_DEBUG
29#define DBGPRINT(x) printf(x)
30#else
31#define DBGPRINT(x)
32#endif
33
34static uint rxIdx; /* index of the current RX buffer */
35static uint txIdx; /* index of the current TX buffer */
36
37typedef volatile struct rtxbd {
38 txbd8_t txbd[TX_BUF_CNT];
39 rxbd8_t rxbd[PKTBUFSRX];
40} RTXBD;
41
42#ifdef __GNUC__
43static RTXBD rtx __attribute__ ((aligned(8)));
44#else
45#error "rtx must be 64-bit aligned"
46#endif
47
48static int tsec_send(struct eth_device* dev, volatile void *packet, int length);
49static int tsec_recv(struct eth_device* dev);
50static int tsec_init(struct eth_device* dev, bd_t * bd);
51static void tsec_halt(struct eth_device* dev);
wdenk7abf0c52004-04-18 21:45:42 +000052static void init_registers(tsec_t *regs);
53static void startup_tsec(tsec_t *regs);
54static void init_phy(tsec_t *regs);
55uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset);
56
57static int phy_id = -1;
wdenk42d1f032003-10-15 23:53:47 +000058
59/* Initialize device structure. returns 0 on failure, 1 on
60 * success */
61int tsec_initialize(bd_t *bis)
62{
63 struct eth_device* dev;
64 int i;
wdenk7abf0c52004-04-18 21:45:42 +000065 tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
wdenk42d1f032003-10-15 23:53:47 +000066
67 dev = (struct eth_device*) malloc(sizeof *dev);
68
69 if(dev == NULL)
70 return 0;
71
72 memset(dev, 0, sizeof *dev);
73
wdenk7abf0c52004-04-18 21:45:42 +000074 sprintf(dev->name, "MOTO ETHERNET");
wdenk42d1f032003-10-15 23:53:47 +000075 dev->iobase = 0;
76 dev->priv = 0;
77 dev->init = tsec_init;
78 dev->halt = tsec_halt;
79 dev->send = tsec_send;
80 dev->recv = tsec_recv;
81
82 /* Tell u-boot to get the addr from the env */
83 for(i=0;i<6;i++)
84 dev->enetaddr[i] = 0;
85
86 eth_register(dev);
87
wdenk7abf0c52004-04-18 21:45:42 +000088 /* Reconfigure the PHY to advertise everything here
89 * so that it works with both gigabit and 10/100 */
90#ifdef CONFIG_PHY_M88E1011
91 /* Assign a Physical address to the TBI */
92 regs->tbipa=TBIPA_VALUE;
93
94 /* reset the management interface */
95 regs->miimcfg=MIIMCFG_RESET;
96
97 regs->miimcfg=MIIMCFG_INIT_VALUE;
98
99 /* Wait until the bus is free */
100 while(regs->miimind & MIIMIND_BUSY);
101
102 /* Locate PHYs. Skip TBIPA, which we know is 31.
103 */
104 for (i=0; i<31; i++) {
105 if (read_phy_reg(regs, i, 2) == 0x141) {
106 if (phy_id == -1)
107 phy_id = i;
108#ifdef TSEC_DEBUG
109 printf("Found Marvell PHY at 0x%02x\n", i);
110#endif
111 }
112 }
113#ifdef TSEC_DEBUG
114 printf("Using PHY ID 0x%02x\n", phy_id);
115#endif
116 write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET);
117
118 RESET_ERRATA(regs, phy_id);
119
120 /* Configure the PHY to advertise gbit and 10/100 */
121 write_phy_reg(regs, phy_id, MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT);
122 write_phy_reg(regs, phy_id, MIIM_ANAR, MIIM_ANAR_INIT);
123
124 /* Reset the PHY so the new settings take effect */
125 write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET);
126#endif
wdenk42d1f032003-10-15 23:53:47 +0000127 return 1;
128}
129
130
131/* Initializes data structures and registers for the controller,
132 * and brings the interface up */
133int tsec_init(struct eth_device* dev, bd_t * bd)
134{
wdenk7abf0c52004-04-18 21:45:42 +0000135 tsec_t *regs;
wdenk42d1f032003-10-15 23:53:47 +0000136 uint tempval;
137 char tmpbuf[MAC_ADDR_LEN];
138 int i;
139
wdenk7abf0c52004-04-18 21:45:42 +0000140 regs = (tsec_t *)(TSEC_BASE_ADDR);
wdenk42d1f032003-10-15 23:53:47 +0000141
142 /* Make sure the controller is stopped */
143 tsec_halt(dev);
144
145 /* Reset the MAC */
146 regs->maccfg1 |= MACCFG1_SOFT_RESET;
147
148 /* Clear MACCFG1[Soft_Reset] */
149 regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
150
151 /* Init MACCFG2. Defaults to GMII/MII */
152 regs->maccfg2 = MACCFG2_INIT_SETTINGS;
153
154 /* Init ECNTRL */
155 regs->ecntrl = ECNTRL_INIT_SETTINGS;
156
157 /* Copy the station address into the address registers.
158 * Backwards, because little endian MACS are dumb */
159 for(i=0;i<MAC_ADDR_LEN;i++) {
160 tmpbuf[MAC_ADDR_LEN - 1 - i] = bd->bi_enetaddr[i];
161 }
162 (uint)(regs->macstnaddr1) = *((uint *)(tmpbuf));
163
164 tempval = *((uint *)(tmpbuf +4));
165
166 (uint)(regs->macstnaddr2) = tempval;
167
168 /* Initialize the PHY */
169 init_phy(regs);
170
171 /* reset the indices to zero */
172 rxIdx = 0;
173 txIdx = 0;
174
175 /* Clear out (for the most part) the other registers */
176 init_registers(regs);
177
178 /* Ready the device for tx/rx */
179 startup_tsec(regs);
180
181 return 1;
182
183}
184
185
186/* Reads from the register at offset in the PHY at phyid, */
187/* using the register set defined in regbase. It waits until the */
188/* bits in the miimstat are valid (miimind notvalid bit cleared), */
189/* and then passes those bits on to the variable specified in */
190/* value */
191/* Before it does the read, it needs to clear the command field */
wdenk7abf0c52004-04-18 21:45:42 +0000192uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset)
wdenk42d1f032003-10-15 23:53:47 +0000193{
194 uint value;
195
196 /* Put the address of the phy, and the register number into
197 * MIIMADD
198 */
199 regbase->miimadd = (phyid << 8) | offset;
200
201 /* Clear the command register, and wait */
202 regbase->miimcom = 0;
203 asm("msync");
204
205 /* Initiate a read command, and wait */
206 regbase->miimcom = MIIM_READ_COMMAND;
207 asm("msync");
208
209 /* Wait for the the indication that the read is done */
210 while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY)));
211
212 /* Grab the value read from the PHY */
213 value = regbase->miimstat;
214
215 return value;
216}
217
218/* Setup the PHY */
wdenk7abf0c52004-04-18 21:45:42 +0000219static void init_phy(tsec_t *regs)
wdenk42d1f032003-10-15 23:53:47 +0000220{
221 uint testval;
222 unsigned int timeout = TSEC_TIMEOUT;
223
224 /* Assign a Physical address to the TBI */
225 regs->tbipa=TBIPA_VALUE;
226
227 /* reset the management interface */
228 regs->miimcfg=MIIMCFG_RESET;
229
230 regs->miimcfg=MIIMCFG_INIT_VALUE;
231
232 /* Wait until the bus is free */
233 while(regs->miimind & MIIMIND_BUSY);
234
235#ifdef CONFIG_PHY_CIS8201
236 /* override PHY config settings */
237 write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT);
238
239 /* Set up interface mode */
240 write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT);
241#endif
242
243 /* Set the PHY to gigabit, full duplex, Auto-negotiate */
wdenk7abf0c52004-04-18 21:45:42 +0000244 write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_INIT);
wdenk42d1f032003-10-15 23:53:47 +0000245
wdenk7abf0c52004-04-18 21:45:42 +0000246 /* Wait until STATUS indicates Auto-Negotiation is done */
wdenk42d1f032003-10-15 23:53:47 +0000247 DBGPRINT("Waiting for Auto-negotiation to complete\n");
wdenk7abf0c52004-04-18 21:45:42 +0000248 testval=read_phy_reg(regs, phy_id, MIIM_STATUS);
wdenk42d1f032003-10-15 23:53:47 +0000249
wdenk7abf0c52004-04-18 21:45:42 +0000250 while((!(testval & MIIM_STATUS_AN_DONE))&& timeout--) {
251 testval=read_phy_reg(regs, phy_id, MIIM_STATUS);
wdenk42d1f032003-10-15 23:53:47 +0000252 }
253
wdenk7abf0c52004-04-18 21:45:42 +0000254 if(testval & MIIM_STATUS_AN_DONE)
wdenk42d1f032003-10-15 23:53:47 +0000255 DBGPRINT("Auto-negotiation done\n");
256 else
257 DBGPRINT("Auto-negotiation timed-out.\n");
258
259#ifdef CONFIG_PHY_CIS8201
260 /* Find out what duplexity (duplicity?) we have */
261 /* Read it twice to make sure */
wdenk7abf0c52004-04-18 21:45:42 +0000262 testval=read_phy_reg(regs, phy_id, MIIM_AUX_CONSTAT);
wdenk42d1f032003-10-15 23:53:47 +0000263
264 if(testval & MIIM_AUXCONSTAT_DUPLEX) {
265 DBGPRINT("Enet starting in full duplex\n");
266 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
267 } else {
268 DBGPRINT("Enet starting in half duplex\n");
269 regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
270 }
271
272 /* Also, we look to see what speed we are at
273 * if Gigabit, MACCFG2 goes in GMII, otherwise,
274 * MII mode.
275 */
276 if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) {
277 if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100)
278 DBGPRINT("Enet starting in 100BT\n");
279 else
280 DBGPRINT("Enet starting in 10BT\n");
281
282 /* mark the mode in MACCFG2 */
283 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
284 } else {
285 DBGPRINT("Enet starting in 1000BT\n");
286 }
287
288#endif
289
290#ifdef CONFIG_PHY_M88E1011
291 /* Read the PHY to see what speed and duplex we are */
wdenk7abf0c52004-04-18 21:45:42 +0000292 testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS);
wdenk42d1f032003-10-15 23:53:47 +0000293
294 timeout = TSEC_TIMEOUT;
295 while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) {
wdenk7abf0c52004-04-18 21:45:42 +0000296 testval = read_phy_reg(regs,phy_id,MIIM_PHY_STATUS);
wdenk42d1f032003-10-15 23:53:47 +0000297 }
298
299 if(!(testval & MIIM_PHYSTAT_SPDDONE))
300 DBGPRINT("Enet: Speed not resolved\n");
301
wdenk7abf0c52004-04-18 21:45:42 +0000302 testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS);
wdenk42d1f032003-10-15 23:53:47 +0000303 if(testval & MIIM_PHYSTAT_DUPLEX) {
304 DBGPRINT("Enet starting in Full Duplex\n");
305 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
306 } else {
307 DBGPRINT("Enet starting in Half Duplex\n");
308 regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
309 }
310
311 if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) {
312 if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100)
313 DBGPRINT("Enet starting in 100BT\n");
314 else
315 DBGPRINT("Enet starting in 10BT\n");
316
317 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
318 } else {
319 DBGPRINT("Enet starting in 1000BT\n");
320 }
321#endif
322
323}
324
325
wdenk7abf0c52004-04-18 21:45:42 +0000326static void init_registers(tsec_t *regs)
wdenk42d1f032003-10-15 23:53:47 +0000327{
328 /* Clear IEVENT */
329 regs->ievent = IEVENT_INIT_CLEAR;
330
331 regs->imask = IMASK_INIT_CLEAR;
332
333 regs->hash.iaddr0 = 0;
334 regs->hash.iaddr1 = 0;
335 regs->hash.iaddr2 = 0;
336 regs->hash.iaddr3 = 0;
337 regs->hash.iaddr4 = 0;
338 regs->hash.iaddr5 = 0;
339 regs->hash.iaddr6 = 0;
340 regs->hash.iaddr7 = 0;
341
342 regs->hash.gaddr0 = 0;
343 regs->hash.gaddr1 = 0;
344 regs->hash.gaddr2 = 0;
345 regs->hash.gaddr3 = 0;
346 regs->hash.gaddr4 = 0;
347 regs->hash.gaddr5 = 0;
348 regs->hash.gaddr6 = 0;
349 regs->hash.gaddr7 = 0;
350
351 regs->rctrl = 0x00000000;
352
353 /* Init RMON mib registers */
354 memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
355
356 regs->rmon.cam1 = 0xffffffff;
357 regs->rmon.cam2 = 0xffffffff;
358
359 regs->mrblr = MRBLR_INIT_SETTINGS;
360
361 regs->minflr = MINFLR_INIT_SETTINGS;
362
363 regs->attr = ATTR_INIT_SETTINGS;
364 regs->attreli = ATTRELI_INIT_SETTINGS;
365
366}
367
wdenk7abf0c52004-04-18 21:45:42 +0000368static void startup_tsec(tsec_t *regs)
wdenk42d1f032003-10-15 23:53:47 +0000369{
370 int i;
371
372 /* Point to the buffer descriptors */
373 regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
374 regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
375
376 /* Initialize the Rx Buffer descriptors */
377 for (i = 0; i < PKTBUFSRX; i++) {
378 rtx.rxbd[i].status = RXBD_EMPTY;
379 rtx.rxbd[i].length = 0;
380 rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
381 }
382 rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP;
383
384 /* Initialize the TX Buffer Descriptors */
385 for(i=0; i<TX_BUF_CNT; i++) {
386 rtx.txbd[i].status = 0;
387 rtx.txbd[i].length = 0;
388 rtx.txbd[i].bufPtr = 0;
389 }
390 rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP;
391
392 /* Enable Transmit and Receive */
393 regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
394
395 /* Tell the DMA it is clear to go */
396 regs->dmactrl |= DMACTRL_INIT_SETTINGS;
397 regs->tstat = TSTAT_CLEAR_THALT;
398 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
399}
400
401/* This returns the status bits of the device. The return value
402 * is never checked, and this is what the 8260 driver did, so we
403 * do the same. Presumably, this would be zero if there were no
404 * errors */
405static int tsec_send(struct eth_device* dev, volatile void *packet, int length)
406{
407 int i;
408 int result = 0;
wdenk7abf0c52004-04-18 21:45:42 +0000409 tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR);
wdenk42d1f032003-10-15 23:53:47 +0000410
411 /* Find an empty buffer descriptor */
412 for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
413 if (i >= TOUT_LOOP) {
414 DBGPRINT("tsec: tx buffers full\n");
415 return result;
416 }
417 }
418
419 rtx.txbd[txIdx].bufPtr = (uint)packet;
420 rtx.txbd[txIdx].length = length;
421 rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
422
423 /* Tell the DMA to go */
424 regs->tstat = TSTAT_CLEAR_THALT;
425
426 /* Wait for buffer to be transmitted */
427 for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
428 if (i >= TOUT_LOOP) {
429 DBGPRINT("tsec: tx error\n");
430 return result;
431 }
432 }
433
434 txIdx = (txIdx + 1) % TX_BUF_CNT;
435 result = rtx.txbd[txIdx].status & TXBD_STATS;
436
437 return result;
438}
439
440static int tsec_recv(struct eth_device* dev)
441{
442 int length;
wdenk7abf0c52004-04-18 21:45:42 +0000443 tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
wdenk42d1f032003-10-15 23:53:47 +0000444
445 while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
446
447 length = rtx.rxbd[rxIdx].length;
448
449 /* Send the packet up if there were no errors */
450 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
451 NetReceive(NetRxPackets[rxIdx], length - 4);
452 }
453
454 rtx.rxbd[rxIdx].length = 0;
455
456 /* Set the wrap bit if this is the last element in the list */
457 rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
458
459 rxIdx = (rxIdx + 1) % PKTBUFSRX;
460 }
461
462 if(regs->ievent&IEVENT_BSY) {
463 regs->ievent = IEVENT_BSY;
464 regs->rstat = RSTAT_CLEAR_RHALT;
465 }
466
467 return -1;
468
469}
470
471
472static void tsec_halt(struct eth_device* dev)
473{
wdenk7abf0c52004-04-18 21:45:42 +0000474 tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
wdenk42d1f032003-10-15 23:53:47 +0000475
476 regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
477 regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
478
479 while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)));
480
481 regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
482
483}
wdenk7abf0c52004-04-18 21:45:42 +0000484
485#ifndef CONFIG_BITBANGMII
486/*
487 * Read a MII PHY register.
488 *
489 * Returns:
490 * 0 on success
491 */
492int miiphy_read(unsigned char addr,
493 unsigned char reg,
494 unsigned short *value)
495{
496 tsec_t *regs;
497 unsigned short rv;
498
499 regs = (tsec_t *)(TSEC_BASE_ADDR);
500 rv = (unsigned short)read_phy_reg(regs, addr, reg);
501 *value = rv;
502
503 return 0;
504}
505
506/*
507 * Write a MII PHY register.
508 *
509 * Returns:
510 * 0 on success
511 */
512int miiphy_write(unsigned char addr,
513 unsigned char reg,
514 unsigned short value)
515{
516 tsec_t *regs;
517
518 regs = (tsec_t *)(TSEC_BASE_ADDR);
519 write_phy_reg(regs, addr, reg, value);
520
521 return 0;
522}
523#endif /* CONFIG_BITBANGMII */
wdenk42d1f032003-10-15 23:53:47 +0000524#endif /* CONFIG_TSEC_ENET */