]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mpc85xx/tsec.c
* Patches by Xianghua Xiao, 15 Oct 2003:
[karo-tx-uboot.git] / cpu / mpc85xx / tsec.c
1 /*
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
34 static uint rxIdx;      /* index of the current RX buffer */
35 static uint txIdx;      /* index of the current TX buffer */
36
37 typedef volatile struct rtxbd {
38         txbd8_t txbd[TX_BUF_CNT];
39         rxbd8_t rxbd[PKTBUFSRX];
40 }  RTXBD;
41
42 #ifdef __GNUC__
43 static RTXBD rtx __attribute__ ((aligned(8)));
44 #else
45 #error "rtx must be 64-bit aligned"
46 #endif
47
48 static int tsec_send(struct eth_device* dev, volatile void *packet, int length);
49 static int tsec_recv(struct eth_device* dev);
50 static int tsec_init(struct eth_device* dev, bd_t * bd);
51 static void tsec_halt(struct eth_device* dev);
52 static void init_registers(tsec_t *regs);
53 static void startup_tsec(tsec_t *regs);
54 static void init_phy(tsec_t *regs);
55
56 /* Initialize device structure.  returns 0 on failure, 1 on
57  * success */
58 int tsec_initialize(bd_t *bis)
59 {
60         struct eth_device* dev;
61         int i;
62
63         dev = (struct eth_device*) malloc(sizeof *dev);
64
65         if(dev == NULL)
66                 return 0;
67
68         memset(dev, 0, sizeof *dev);
69
70         sprintf(dev->name, "MOTOROLA ETHERNET");
71         dev->iobase = 0;
72         dev->priv   = 0;
73         dev->init   = tsec_init;
74         dev->halt   = tsec_halt;
75         dev->send   = tsec_send;
76         dev->recv   = tsec_recv;
77
78         /* Tell u-boot to get the addr from the env */
79         for(i=0;i<6;i++)
80                 dev->enetaddr[i] = 0;
81
82         eth_register(dev);
83
84         return 1;
85 }
86
87
88 /* Initializes data structures and registers for the controller,
89  * and brings the interface up */
90 int tsec_init(struct eth_device* dev, bd_t * bd)
91 {
92         tsec_t *regs;
93         uint tempval;
94         char tmpbuf[MAC_ADDR_LEN];
95         int i;
96
97         regs = (tsec_t *)(TSEC_BASE_ADDR);
98
99         /* Make sure the controller is stopped */
100         tsec_halt(dev);
101
102         /* Reset the MAC */
103         regs->maccfg1 |= MACCFG1_SOFT_RESET;
104
105         /* Clear MACCFG1[Soft_Reset] */
106         regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
107
108         /* Init MACCFG2.  Defaults to GMII/MII */
109         regs->maccfg2 = MACCFG2_INIT_SETTINGS;
110
111         /* Init ECNTRL */
112         regs->ecntrl = ECNTRL_INIT_SETTINGS;
113
114         /* Copy the station address into the address registers.
115          * Backwards, because little endian MACS are dumb */
116         for(i=0;i<MAC_ADDR_LEN;i++) {
117                 tmpbuf[MAC_ADDR_LEN - 1 - i] = bd->bi_enetaddr[i];
118         }
119         (uint)(regs->macstnaddr1) = *((uint *)(tmpbuf));
120
121         tempval = *((uint *)(tmpbuf +4));
122
123         (uint)(regs->macstnaddr2) = tempval;
124
125         /* Initialize the PHY */
126         init_phy(regs);
127
128         /* reset the indices to zero */
129         rxIdx = 0;
130         txIdx = 0;
131
132         /* Clear out (for the most part) the other registers */
133         init_registers(regs);
134
135         /* Ready the device for tx/rx */
136         startup_tsec(regs);
137
138         return 1;
139
140 }
141
142
143 /* Reads from the register at offset in the PHY at phyid, */
144 /* using the register set defined in regbase.  It waits until the */
145 /* bits in the miimstat are valid (miimind notvalid bit cleared), */
146 /* and then passes those bits on to the variable specified in */
147 /* value */
148 /* Before it does the read, it needs to clear the command field */
149 uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset)
150 {
151         uint value;
152
153         /* Put the address of the phy, and the register number into
154          * MIIMADD
155          */
156         regbase->miimadd = (phyid << 8) | offset;
157
158         /* Clear the command register, and wait */
159         regbase->miimcom = 0;
160         asm("msync");
161
162         /* Initiate a read command, and wait */
163         regbase->miimcom = MIIM_READ_COMMAND;
164         asm("msync");
165
166         /* Wait for the the indication that the read is done */
167         while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY)));
168
169         /* Grab the value read from the PHY */
170         value = regbase->miimstat;
171
172         return value;
173 }
174
175 /* Setup the PHY */
176 static void init_phy(tsec_t *regs)
177 {
178         uint testval;
179         unsigned int timeout = TSEC_TIMEOUT;
180
181         /* Assign a Physical address to the TBI */
182         regs->tbipa=TBIPA_VALUE;
183
184         /* reset the management interface */
185         regs->miimcfg=MIIMCFG_RESET;
186
187         regs->miimcfg=MIIMCFG_INIT_VALUE;
188
189         /* Wait until the bus is free */
190         while(regs->miimind & MIIMIND_BUSY);
191
192 #ifdef CONFIG_PHY_CIS8201
193         /* override PHY config settings */
194         write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT);
195
196         /* Set up interface mode */
197         write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT);
198 #endif
199
200         /* Set the PHY to gigabit, full duplex, Auto-negotiate */
201         write_phy_reg(regs, 0, MIIM_CONTROL, MIIM_CONTROL_INIT);
202
203         /* Wait until TBI_STATUS indicates AN is done */
204         DBGPRINT("Waiting for Auto-negotiation to complete\n");
205         testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS);
206
207         while((!(testval & MIIM_TBI_STATUS_AN_DONE))&& timeout--) {
208                 testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS);
209         }
210
211         if(testval & MIIM_TBI_STATUS_AN_DONE)
212                 DBGPRINT("Auto-negotiation done\n");
213         else
214                 DBGPRINT("Auto-negotiation timed-out.\n");
215
216 #ifdef CONFIG_PHY_CIS8201
217         /* Find out what duplexity (duplicity?) we have */
218         /* Read it twice to make sure */
219         testval=read_phy_reg(regs, 0, MIIM_AUX_CONSTAT);
220
221         if(testval & MIIM_AUXCONSTAT_DUPLEX) {
222                 DBGPRINT("Enet starting in full duplex\n");
223                 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
224         } else {
225                 DBGPRINT("Enet starting in half duplex\n");
226                 regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
227         }
228
229         /* Also, we look to see what speed we are at
230          * if Gigabit, MACCFG2 goes in GMII, otherwise,
231          * MII mode.
232          */
233         if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) {
234                 if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100)
235                         DBGPRINT("Enet starting in 100BT\n");
236                 else
237                         DBGPRINT("Enet starting in 10BT\n");
238
239                 /* mark the mode in MACCFG2 */
240                 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
241         } else {
242                 DBGPRINT("Enet starting in 1000BT\n");
243         }
244
245 #endif
246
247 #ifdef CONFIG_PHY_M88E1011
248         /* Read the PHY to see what speed and duplex we are */
249         testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS);
250
251         timeout = TSEC_TIMEOUT;
252         while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) {
253                 testval = read_phy_reg(regs,0,MIIM_PHY_STATUS);
254         }
255
256         if(!(testval & MIIM_PHYSTAT_SPDDONE))
257                 DBGPRINT("Enet: Speed not resolved\n");
258
259         testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS);
260         if(testval & MIIM_PHYSTAT_DUPLEX) {
261                 DBGPRINT("Enet starting in Full Duplex\n");
262                 regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
263         } else {
264                 DBGPRINT("Enet starting in Half Duplex\n");
265                 regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
266         }
267
268         if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) {
269                 if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100)
270                         DBGPRINT("Enet starting in 100BT\n");
271                 else
272                         DBGPRINT("Enet starting in 10BT\n");
273
274                 regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
275         } else {
276                 DBGPRINT("Enet starting in 1000BT\n");
277         }
278 #endif
279
280 }
281
282
283 static void init_registers(tsec_t *regs)
284 {
285         /* Clear IEVENT */
286         regs->ievent = IEVENT_INIT_CLEAR;
287
288         regs->imask = IMASK_INIT_CLEAR;
289
290         regs->hash.iaddr0 = 0;
291         regs->hash.iaddr1 = 0;
292         regs->hash.iaddr2 = 0;
293         regs->hash.iaddr3 = 0;
294         regs->hash.iaddr4 = 0;
295         regs->hash.iaddr5 = 0;
296         regs->hash.iaddr6 = 0;
297         regs->hash.iaddr7 = 0;
298
299         regs->hash.gaddr0 = 0;
300         regs->hash.gaddr1 = 0;
301         regs->hash.gaddr2 = 0;
302         regs->hash.gaddr3 = 0;
303         regs->hash.gaddr4 = 0;
304         regs->hash.gaddr5 = 0;
305         regs->hash.gaddr6 = 0;
306         regs->hash.gaddr7 = 0;
307
308         regs->rctrl = 0x00000000;
309
310         /* Init RMON mib registers */
311         memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
312
313         regs->rmon.cam1 = 0xffffffff;
314         regs->rmon.cam2 = 0xffffffff;
315
316         regs->mrblr = MRBLR_INIT_SETTINGS;
317
318         regs->minflr = MINFLR_INIT_SETTINGS;
319
320         regs->attr = ATTR_INIT_SETTINGS;
321         regs->attreli = ATTRELI_INIT_SETTINGS;
322
323 }
324
325 static void startup_tsec(tsec_t *regs)
326 {
327         int i;
328
329         /* Point to the buffer descriptors */
330         regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
331         regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
332
333         /* Initialize the Rx Buffer descriptors */
334         for (i = 0; i < PKTBUFSRX; i++) {
335                 rtx.rxbd[i].status = RXBD_EMPTY;
336                 rtx.rxbd[i].length = 0;
337                 rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
338         }
339         rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP;
340
341         /* Initialize the TX Buffer Descriptors */
342         for(i=0; i<TX_BUF_CNT; i++) {
343                 rtx.txbd[i].status = 0;
344                 rtx.txbd[i].length = 0;
345                 rtx.txbd[i].bufPtr = 0;
346         }
347         rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP;
348
349         /* Enable Transmit and Receive */
350         regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
351
352         /* Tell the DMA it is clear to go */
353         regs->dmactrl |= DMACTRL_INIT_SETTINGS;
354         regs->tstat = TSTAT_CLEAR_THALT;
355         regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
356 }
357
358 /* This returns the status bits of the device.  The return value
359  * is never checked, and this is what the 8260 driver did, so we
360  * do the same.  Presumably, this would be zero if there were no
361  * errors */
362 static int tsec_send(struct eth_device* dev, volatile void *packet, int length)
363 {
364         int i;
365         int result = 0;
366         tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR);
367
368         /* Find an empty buffer descriptor */
369         for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
370                 if (i >= TOUT_LOOP) {
371                         DBGPRINT("tsec: tx buffers full\n");
372                         return result;
373                 }
374         }
375
376         rtx.txbd[txIdx].bufPtr = (uint)packet;
377         rtx.txbd[txIdx].length = length;
378         rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
379
380         /* Tell the DMA to go */
381         regs->tstat = TSTAT_CLEAR_THALT;
382
383         /* Wait for buffer to be transmitted */
384         for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
385                 if (i >= TOUT_LOOP) {
386                         DBGPRINT("tsec: tx error\n");
387                         return result;
388                 }
389         }
390
391         txIdx = (txIdx + 1) % TX_BUF_CNT;
392         result = rtx.txbd[txIdx].status & TXBD_STATS;
393
394         return result;
395 }
396
397 static int tsec_recv(struct eth_device* dev)
398 {
399         int length;
400         tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
401
402         while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
403
404                 length = rtx.rxbd[rxIdx].length;
405
406                 /* Send the packet up if there were no errors */
407                 if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
408                         NetReceive(NetRxPackets[rxIdx], length - 4);
409                 }
410
411                 rtx.rxbd[rxIdx].length = 0;
412
413                 /* Set the wrap bit if this is the last element in the list */
414                 rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
415
416                 rxIdx = (rxIdx + 1) % PKTBUFSRX;
417         }
418
419         if(regs->ievent&IEVENT_BSY) {
420                 regs->ievent = IEVENT_BSY;
421                 regs->rstat = RSTAT_CLEAR_RHALT;
422         }
423
424         return -1;
425
426 }
427
428
429 static void tsec_halt(struct eth_device* dev)
430 {
431         tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
432
433         regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
434         regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
435
436         while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)));
437
438         regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
439
440 }
441 #endif /* CONFIG_TSEC_ENET */