Added FSP
[people/lynusvaz/gpxe.git] / src / arch / armnommu / drivers / net / p2001_eth.c
1 /**************************************************************************
2 Etherboot -  BOOTP/TFTP Bootstrap Program
3 P2001 NIC driver for Etherboot
4 ***************************************************************************/
5
6 /*
7  *  Copyright (C) 2004 Tobias Lorenz
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 /* to get some global routines like printf */
15 #include "etherboot.h"
16 /* to get the interface to the body of the program */
17 #include "nic.h"
18 /* to get the ISA support functions, if this is an ISA NIC */
19 #include "isa.h"
20
21 #include "hardware.h"
22 #include "lxt971a.h"
23 #include "timer.h"
24
25
26 /* NIC specific static variables go here */
27 static unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
28
29 /* DMA descriptors and buffers */
30 #define NUM_RX_DESC     4       /* Number of Rx descriptor registers. */
31 #define DMA_BUF_SIZE    2048    /* Buffer size */
32 static DMA_DSC txd              __attribute__ ((__section__(".dma.desc")));
33 static DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((__section__(".dma.desc")));
34 static unsigned char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
35 static unsigned char txb[              DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
36 static unsigned int cur_rx;
37
38 /* Device selectors */
39 static unsigned int cur_channel;        // DMA channel    : 0..3
40 static unsigned int cur_phy;            // PHY Address    : 0..31
41 static P2001_ETH_regs_ptr EU;           // Ethernet Unit  : 0x0018_000 with _=0..3
42 static P2001_ETH_regs_ptr MU;           // Management Unit: 0x00180000
43
44 #define MDIO_MAXCOUNT 1000                      /* mdio abort */
45 static unsigned int mdio_error;                 /* mdio error */
46
47 /* Function prototypes */
48 static void         p2001_eth_mdio_init ();
49 static void         p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data);
50 static unsigned int p2001_eth_mdio_read (unsigned int phyadr, unsigned int regadr);
51 extern unsigned int p2001_eth_mdio_error;
52
53 static int          p2001_eth_poll      (struct nic *nic, int retrieve);
54 static void         p2001_eth_transmit  (struct nic *nic, const char *d,
55                                         unsigned int t, unsigned int s, const char *p);
56
57 static void         p2001_eth_irq       (struct nic *nic, irq_action_t action);
58
59 static void         p2001_eth_init      ();
60 static void         p2001_eth_disable   (struct dev *dev);
61
62 static int          p2001_eth_check_link(unsigned int phy);
63 static int          p2001_eth_probe     (struct dev *dev, unsigned short *probe_addrs __unused);
64
65
66 /**************************************************************************
67 PHY MANAGEMENT UNIT - Read/write
68 ***************************************************************************/
69 static void p2001_eth_mdio_init()
70 {
71         /* reset ethernet PHYs */
72         printf("Resetting PHYs...\n");
73
74         /* GPIO24/25: TX_ER2/TX_ER0 */
75         /* GPIO26/27: PHY_RESET/TX_ER1 */
76         P2001_GPIO->PIN_MUX |= 0x0018;
77         // 31-16: 0000 1111 0000 0000
78         P2001_GPIO->GPIO2_En |= 0x0400;
79
80         P2001_GPIO->GPIO2_Out |= 0x04000000;
81         P2001_GPIO->GPIO2_Out &= ~0x0400;
82         mdelay(500);
83         P2001_GPIO->GPIO2_Out |= 0x0400;
84
85         /* set management unit clock divisor */
86         // max. MDIO CLK = 2.048 MHz (EU.doc)
87         // max. MDIO CLK = 8.000 MHz (LXT971A)
88         // sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz
89         // n >= sysclk/4.096 MHz - 1
90 #if SYSCLK == 73728000
91         P2001_MU->MU_DIV = 17;  // 73.728 MHZ =17=> 2.020 MHz
92 #else
93         //MU->MU_DIV = (SYSCLK/4.096)-1;
94 #error "Please define a proper MDIO CLK divisor for that sysclk."
95 #endif
96         asm("nop \n nop");
97 }
98
99 static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data)
100 {
101         static unsigned int count;
102         count = 0;
103
104         /* Warten bis Hardware inaktiv (MIU = "0") */
105         while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
106                 count++;
107
108         /* Schreiben MU_DATA */
109         MU->MU_DATA = data;
110
111         /* Schreiben MU_CNTL */
112         MU->MU_CNTL = regadr + (phyadr<<5) + (1<<10);
113
114         /* Warten bis Hardware aktiv (MIU = "1") */
115         while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
116                 count++;
117         //asm("nop \r\n nop");
118
119         /* Warten bis Hardware inaktiv (MIU = "0") */
120         while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
121                 count++;
122
123         mdio_error = (count >= MDIO_MAXCOUNT);
124 }
125
126 static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr)
127 {
128         static unsigned int count;
129         count = 0;
130
131         do {
132                 /* Warten bis Hardware inaktiv (MIU = "0") */
133                 while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
134                         count++;
135
136                 /* Schreiben MU_CNTL */
137                 MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10);
138
139                 /* Warten bis Hardware aktiv (MIU = "1") */
140                 while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
141                         count++;
142                 //asm("nop \r\n nop");
143
144                 /* Warten bis Hardware inaktiv (MIU = "0") */
145                 while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
146                         count++;
147
148                 /* Fehler, wenn MDIO Read Error (MRE = "1") */
149         } while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT));
150
151         /* Lesen MU_DATA */
152         mdio_error = (count >= MDIO_MAXCOUNT);
153         return MU->MU_DATA;
154 }
155
156
157 /**************************************************************************
158 POLL - Wait for a frame
159 ***************************************************************************/
160 /* Function: p2001_eth_poll
161  *
162  * Description: checks for a received packet and returns it if found.
163  *
164  * Arguments: struct nic *nic:          NIC data structure
165  *
166  * Returns:   1 if a packet was received.
167  *            0 if no pacet was received.
168  *
169  * Side effects:
170  *            Returns (copies) the packet to the array nic->packet.
171  *            Returns the length of the packet in nic->packetlen.
172  */
173 static int p2001_eth_poll(struct nic *nic, int retrieve)
174 {
175         /* return true if there's an ethernet packet ready to read */
176         /* nic->packet should contain data on return */
177         /* nic->packetlen should contain length of data */
178
179         int retstat = 0;
180
181         if (rxd[cur_rx].stat & (1<<31)) // OWN
182                 return retstat;
183
184         if (!retrieve)
185                 return 1;
186
187         nic->packetlen = rxd[cur_rx].cntl & 0xffff;
188
189         if (rxd[cur_rx].stat & ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22))) {
190                 /* corrupted packet received */
191                 printf("p2001_eth_poll: Corrupted packet received, stat = %X\n",
192                                rxd[cur_rx].stat);
193                 retstat = 0;
194         } else {
195                 /* give packet to higher routine */
196                 memcpy(nic->packet, (rxb + cur_rx*DMA_BUF_SIZE), nic->packetlen);
197                 retstat = 1;
198         }
199
200 #ifdef DEBUG_NIC
201         printf("p2001_eth_poll: packet from %! to %! received\n", 
202                 (rxb+cur_rx*DMA_BUF_SIZE)+ETH_ALEN,
203                 (rxb+cur_rx*DMA_BUF_SIZE));
204 #endif
205
206         /* disable receiver */
207         // FIXME: is that ok? it can produce grave errors.
208         EU->RMAC_DMA_EN = 0;                            /* clear run bit */
209
210         /* return the descriptor and buffer to receive ring */
211         rxd[cur_rx].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
212         rxd[cur_rx].cntl = (1<<23);                     // DSC1 RECEIVE
213         rxd[cur_rx].cntl |= cur_channel << 16;          // DSC1 CHANNEL
214         rxd[cur_rx].cntl |= DMA_BUF_SIZE;               // DSC1 LEN
215
216         if (++cur_rx == NUM_RX_DESC)
217                 cur_rx = 0;
218
219         /* enable receiver */
220         if (!(EU->RMAC_DMA_EN & 0x01))
221                 EU->RMAC_DMA_EN = 0x01;                 /* set run bit */
222
223 #ifdef DEBUG_NIC
224         printf("RMAC_MIB0..5: %d:%d:%d:%d:%d:%d\n",
225                 EU->RMAC_MIB0, EU->RMAC_MIB1,
226                 EU->RMAC_MIB2, EU->RMAC_MIB3,
227                 EU->RMAC_MIB4, EU->RMAC_MIB5);
228 #endif
229
230         return retstat; /* initially as this is called to flush the input */
231 }
232
233
234 /**************************************************************************
235 TRANSMIT - Transmit a frame
236 ***************************************************************************/
237 /* Function: p2001_eth_transmit
238  *
239  * Description: transmits a packet and waits for completion or timeout.
240  *
241  * Arguments: char d[6]:          destination ethernet address.
242  *            unsigned short t:   ethernet protocol type.
243  *            unsigned short s:   size of the data-part of the packet.
244  *            char *p:            the data for the packet.
245  *    
246  * Returns:   void.
247  */
248 static void p2001_eth_transmit(
249         struct nic *nic __unused,
250         const char *d,                  /* Destination */
251         unsigned int t,                 /* Type */
252         unsigned int s,                 /* size */
253         const char *p)                  /* Packet */
254 {
255         unsigned int nstype;
256 #ifdef DEBUG_NIC
257         unsigned int status;
258 #endif
259
260         /* assemble packet */
261         memcpy(txb, d, ETH_ALEN);                       // destination
262         memcpy(txb+ETH_ALEN, nic->node_addr, ETH_ALEN); // source
263         nstype = htons(t);
264         memcpy(txb+2*ETH_ALEN, (char*)&nstype, 2);      // type
265         memcpy(txb+ETH_HLEN, p, s);                     // packet
266         s += ETH_HLEN;
267
268         /* pad to minimum packet size */
269 //      while (s<ETH_ZLEN)
270 //              txb[s++] = '\0';
271         // TMAC_CNTL.ATP does the same
272
273 #ifdef DEBUG_NIC
274         printf("p2001_eth_transmit: packet from %! to %! sent\n", txb+ETH_ALEN, txb);
275 #endif
276
277         /* configure descriptor */
278         txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
279         txd.cntl = cur_channel << 16;           // DSC1 CHANNEL
280         txd.cntl |= s;                          // DSC1 LEN
281
282         /* restart the transmitter */
283         EU->TMAC_DMA_EN = 0x01;         /* set run bit */
284         while(EU->TMAC_DMA_EN & 0x01) ; /* wait */
285
286 #ifdef DEBUG_NIC
287         /* check status */
288         status = EU->TMAC_DMA_STAT;
289         if (status & ~(0x40))
290                 printf("p2001_eth_transmit: dma status=0x%hx\n", status);
291
292         printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
293 #endif
294 }
295
296
297 /**************************************************************************
298 IRQ - Enable, Disable or Force Interrupts
299 ***************************************************************************/
300 /* Function: p2001_eth_irq
301  *
302  * Description: Enable, Disable, or Force, interrupts
303  *    
304  * Arguments: struct nic *nic:          NIC data structure
305  *            irq_action_t action:      Requested action       
306  *
307  * Returns:   void.
308  */
309
310 static void
311 p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused)
312 {
313         switch ( action ) {
314                 case DISABLE :
315                         break;
316                 case ENABLE :
317                         break;
318                 case FORCE :
319                         break;
320         }
321 }
322
323
324 /**************************************************************************
325 INIT - Initialize device
326 ***************************************************************************/
327 /* Function: p2001_init
328  *
329  * Description: resets the ethernet controller chip and various
330  *    data structures required for sending and receiving packets.
331  *    
332  * returns:   void.
333  */
334 static void p2001_eth_init()
335 {
336         static int i;
337
338         /* disable transceiver */
339 //      EU->TMAC_DMA_EN = 0;            /* clear run bit */
340 //      EU->RMAC_DMA_EN = 0;            /* clear run bit */
341
342         /* set rx filter (physical mac addresses) */
343         EU->RMAC_PHYU =
344                 (MAC_HW_ADDR[0]<< 8) +
345                 (MAC_HW_ADDR[1]<< 0);
346         EU->RMAC_PHYL =
347                 (MAC_HW_ADDR[2]<<24) +
348                 (MAC_HW_ADDR[3]<<16) +
349                 (MAC_HW_ADDR[4]<<8 ) +
350                 (MAC_HW_ADDR[5]<<0 );
351
352         /* initialize the tx descriptor ring */
353 //      txd.stat = (1<<31) | (1<<30) | (1<<29);                 // DSC0 OWN|START|END
354 //      txd.cntl = cur_channel << 16;                           // DSC1 CHANNEL
355 //      txd.cntl |= DMA_BUF_SIZE;                               // DSC1 LEN
356         txd.buf = &txb;                                         // DSC2 BUFFER
357         txd.next = &txd;                                        // DSC3 NEXTDSC @self
358         EU->TMAC_DMA_DESC = &txd;
359
360         /* initialize the rx descriptor ring */
361         cur_rx = 0;
362         for (i = 0; i < NUM_RX_DESC; i++) {
363                 rxd[i].stat = (1<<31) | (1<<30) | (1<<29);      // DSC0 OWN|START|END
364                 rxd[i].cntl = (1<<23);                          // DSC1 RECEIVE
365                 rxd[i].cntl |= cur_channel << 16;               // DSC1 CHANNEL
366                 rxd[i].cntl |= DMA_BUF_SIZE;                    // DSC1 LEN
367                 rxd[i].buf = &rxb[i*DMA_BUF_SIZE];              // DSC2 BUFFER (EU-RX data)
368                 rxd[i].next = &rxd[i+1];                        // DSC3 NEXTDSC @next
369         }
370         rxd[NUM_RX_DESC-1].next = &rxd[0];                      // DSC3 NEXTDSC @first
371         EU->RMAC_DMA_DESC = &rxd[0];
372
373         /* set transmitter mode */
374         EU->TMAC_CNTL = (1<<4) |        /* COI: Collision ignore */
375                         //(1<<3) |      /* CSI: Carrier Sense ignore */
376                         (1<<2);         /* ATP: Automatic Transmit Padding */
377
378         /* set receive mode */
379         EU->RMAC_CNTL = (1<<3) |        /* BROAD: Broadcast packets */
380                         (1<<1);         /* PHY  : Packets to out MAC address */
381
382         /* enable receiver */
383         EU->RMAC_DMA_EN = 1;            /* set run bit */
384 }
385
386
387 /**************************************************************************
388 DISABLE - Turn off ethernet interface
389 ***************************************************************************/
390 static void p2001_eth_disable(struct dev *dev __unused)
391 {
392         /* put the card in its initial state */
393         /* This function serves 3 purposes.
394          * This disables DMA and interrupts so we don't receive
395          *  unexpected packets or interrupts from the card after
396          *  etherboot has finished. 
397          * This frees resources so etherboot may use
398          *  this driver on another interface
399          * This allows etherboot to reinitialize the interface
400          *  if something is something goes wrong.
401          */
402
403         /* disable transmitter */
404         EU->TMAC_DMA_EN = 0;            /* clear run bit */
405
406         /* disable receiver */
407         EU->RMAC_DMA_EN = 0;            /* clear run bit */
408 }
409
410
411 /**************************************************************************
412 LINK - Check for valid link
413 ***************************************************************************/
414 static int p2001_eth_check_link(unsigned int phy)
415 {
416         static int status;
417         static unsigned int count;
418         count = 0;
419
420         /* Use 0x3300 for restarting NWay */
421         printf("Starting auto-negotiation... ");
422         p2001_eth_mdio_write(phy, Adr_LXT971A_Control, 0x3300);
423         if (mdio_error)
424                 goto failed;
425
426         /* Bits 1.5 and 17.7 are set to 1 once the Auto-Negotiation process to completed. */
427         do {
428                 mdelay(500);
429                 status = p2001_eth_mdio_read(phy, Adr_LXT971A_Status1);
430                 if (mdio_error || (count++ > 6))        // 6*500ms = 3s timeout
431                         goto failed;
432         } while (!(status & 0x20));
433         
434         /* Bits 1.2 and 17.10 are set to 1 once the link is established. */
435         if (p2001_eth_mdio_read(phy, Adr_LXT971A_Status1) & 0x04) {
436                 /* Bits 17.14 and 17.9 can be used to determine the link operation conditions (speed and duplex). */
437                 printf("Valid link, operating at: %sMb-%s\n",
438                         (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x4000) ? "100" : "10",
439                         (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x0200) ? "FD" : "HD");
440                         return 1;
441         }
442
443 failed:
444         if (mdio_error)
445                 printf("Failed\n");
446         else
447                 printf("No valid link\n");
448         return 0;
449 }
450
451
452 /**************************************************************************
453 PROBE - Look for an adapter, this routine's visible to the outside
454 ***************************************************************************/
455 static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
456 {
457         struct nic *nic = (struct nic *)dev;
458         /* if probe_addrs is 0, then routine can use a hardwired default */
459         static int board_found;
460         static int valid_link;
461
462         /* reset phys and configure mdio clk */
463         p2001_eth_mdio_init();
464
465         /* find the correct PHY/DMA/MAC combination */
466         MU = P2001_MU;  // MU for all PHYs is only in EU0
467         printf("Searching for P2001 NICs...\n");
468         for (cur_channel=0; cur_channel<4; cur_channel++) {
469                 switch(cur_channel) {
470                         case 0:
471                                 EU = P2001_EU0;
472                                 cur_phy = 0;
473                                 break;
474                         case 1:
475                                 EU = P2001_EU1;
476                                 cur_phy = 1;
477                                 break;
478                         case 2:
479                                 EU = P2001_EU2;
480                                 cur_phy = 2;
481                                 break;
482                         case 3:
483                                 EU = P2001_EU3;
484                                 cur_phy = 3;
485                                 break;
486                 }
487
488                 /* first a non destructive test for initial value RMAC_TLEN=1518 */
489                 board_found = (EU->RMAC_TLEN == 1518);
490                 if (board_found) {
491                         printf("Checking EU%d...\n", cur_channel);
492
493                         valid_link = p2001_eth_check_link(cur_phy);
494                         if (valid_link) {
495                                 /* initialize device */
496                                 p2001_eth_init(nic);
497
498                                 /* set node address */
499                                 printf("Setting MAC address to %!\n", MAC_HW_ADDR);
500                                 memcpy(nic->node_addr, MAC_HW_ADDR, 6);
501
502                                 /* point to NIC specific routines */
503                                 dev->disable  = p2001_eth_disable;
504                                 nic->poll     = p2001_eth_poll;
505                                 nic->transmit = p2001_eth_transmit;
506                                 nic->irq      = p2001_eth_irq;
507
508                                 /* Report the ISA pnp id of the board */
509                                 dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
510                                 dev->devid.vendor_id = htons(0x1234);
511                                 return 1;
512                         }
513                 }
514         }
515         /* else */
516         return 0;
517 }
518
519 ISA_ROM("p2001_eth", "P2001 Ethernet Driver")
520 static struct isa_driver p2001_eth_driver __isa_driver = {
521         .type    = NIC_DRIVER,
522         .name    = "P2001 Ethernet Driver",
523         .probe   = p2001_eth_probe,
524         .ioaddrs = 0,
525 };