Synced across updates from Etherboot 5.4 tree
[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) 2005 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 "mii.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 char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
35 static 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
43 /* mdio handling */
44 static int          p2001_eth_mdio_read (int phy_id, int location);
45 static void         p2001_eth_mdio_write(int phy_id, int location, int val);
46
47 /* net_device functions */
48 static int          p2001_eth_poll      (struct nic *nic, int retrieve);
49 static void         p2001_eth_transmit  (struct nic *nic, const char *d,
50                                         unsigned int t, unsigned int s, const char *p);
51
52 static void         p2001_eth_irq       (struct nic *nic, irq_action_t action);
53
54 static void         p2001_eth_init      ();
55 static void         p2001_eth_disable   (struct dev *dev);
56
57 static int          p2001_eth_check_link(unsigned int phy);
58 static int          link;
59 static void         p2001_eth_phyreset  ();
60 static int          p2001_eth_probe     (struct dev *dev, unsigned short *probe_addrs __unused);
61
62 /* Supported MII list */
63 static struct mii_chip_info {
64         const char * name;
65         unsigned int physid;    // (MII_PHYSID2 << 16) | MII_PHYSID1
66 } mii_chip_table[] = {
67         { "Intel LXT971A",      0x78e20013 },
68         { "Altima AC104-QF",    0x55410022 },
69         {NULL,0},
70 };
71
72
73
74 /**************************************************************************
75  * PHY MANAGEMENT UNIT - Read/write
76  **************************************************************************/
77
78 /**
79  *      mdio_read - read MII PHY register
80  *      @dev: the net device to read
81  *      @regadr: the phy register id to read
82  *
83  *      Read MII registers through MDIO and MDC
84  *      using MDIO management frame structure and protocol(defined by ISO/IEC).
85  */
86 static int p2001_eth_mdio_read(int phy_id, int location)
87 {
88         int result, boguscnt = 1000;
89
90         do {
91                 /* Warten bis Hardware inaktiv (MIU = "0") */
92                 while (P2001_MU->MU_CNTL & 0x8000)
93                         barrier();
94
95                 /* Schreiben MU_CNTL */
96                 P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<10);
97
98                 /* Warten bis Hardware aktiv (MIU = "1") */
99                 while ((P2001_MU->MU_CNTL & 0x8000) == 0)
100                         barrier();
101                 //asm("nop \r\n nop");
102
103                 /* Warten bis Hardware inaktiv (MIU = "0") */
104                 while (P2001_MU->MU_CNTL & 0x8000)
105                         barrier();
106
107                 /* Fehler, wenn MDIO Read Error (MRE = "1") */
108         } while ((P2001_MU->MU_CNTL & 0x4000) && (--boguscnt > 0));
109
110         /* Lesen MU_DATA */
111         result = P2001_MU->MU_DATA;
112
113         if (boguscnt == 0)
114                 return 0;
115         if ((result & 0xffff) == 0xffff)
116                 return 0;
117
118         return result & 0xffff;
119 }
120
121
122 /**
123  *      mdio_write - write MII PHY register
124  *      @dev: the net device to write
125  *      @regadr: the phy register id to write
126  *      @value: the register value to write with
127  *
128  *      Write MII registers with @value through MDIO and MDC
129  *      using MDIO management frame structure and protocol(defined by ISO/IEC)
130  */
131 static void p2001_eth_mdio_write(int phy_id, int location, int val)
132 {
133         /* Warten bis Hardware inaktiv (MIU = "0") */
134         while (P2001_MU->MU_CNTL & 0x8000)
135                 barrier();
136
137         /* Schreiben MU_DATA */
138         P2001_MU->MU_DATA = val;
139
140         /* Schreiben MU_CNTL */
141         P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10);
142
143         /* Warten bis Hardware aktiv (MIU = "1") */
144         while ((P2001_MU->MU_CNTL & 0x8000) == 0)
145                 barrier();
146         //asm("nop \r\n nop");
147
148         /* Warten bis Hardware inaktiv (MIU = "0") */
149         while (P2001_MU->MU_CNTL & 0x8000)
150                 barrier();
151 }
152
153
154
155 /**************************************************************************
156  * POLL - Wait for a frame
157  **************************************************************************/
158
159 /* Function: p2001_eth_poll
160  *
161  * Description: checks for a received packet and returns it if found.
162  *
163  * Arguments: struct nic *nic:          NIC data structure
164  *
165  * Returns:   1 if a packet was received.
166  *            0 if no pacet was received.
167  *
168  * Side effects:
169  *            Returns (copies) the packet to the array nic->packet.
170  *            Returns the length of the packet in nic->packetlen.
171  */
172 static int p2001_eth_poll(struct nic *nic, int retrieve)
173 {
174         /* return true if there's an ethernet packet ready to read */
175         /* nic->packet should contain data on return */
176         /* nic->packetlen should contain length of data */
177
178         int retstat = 0;
179
180         if (rxd[cur_rx].stat & (1<<31)) // OWN
181                 return retstat;
182
183         if (!retrieve)
184                 return 1;
185
186         nic->packetlen = rxd[cur_rx].cntl & 0xffff;
187
188         if (rxd[cur_rx].stat & ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22))) {
189                 /* corrupted packet received */
190                 printf("p2001_eth_poll: Corrupted packet received, stat = %X\n",
191                                rxd[cur_rx].stat);
192                 retstat = 0;
193         } else {
194                 /* give packet to higher routine */
195                 memcpy(nic->packet, (rxb + cur_rx*DMA_BUF_SIZE), nic->packetlen);
196                 retstat = 1;
197         }
198
199 #ifdef DEBUG_NIC
200         printf("p2001_eth_poll: packet from %! to %! received\n", 
201                 (rxb+cur_rx*DMA_BUF_SIZE)+ETH_ALEN,
202                 (rxb+cur_rx*DMA_BUF_SIZE));
203 #endif
204
205         /* disable receiver */
206         // FIXME: is that ok? it can produce grave errors.
207         EU->RMAC_DMA_EN = 0;                            /* clear run bit */
208
209         /* return the descriptor and buffer to receive ring */
210         rxd[cur_rx].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
211         rxd[cur_rx].cntl = (1<<23);                     // DSC1 RECEIVE
212         rxd[cur_rx].cntl |= cur_channel << 16;          // DSC1 CHANNEL
213         rxd[cur_rx].cntl |= DMA_BUF_SIZE;               // DSC1 LEN
214
215         if (++cur_rx == NUM_RX_DESC)
216                 cur_rx = 0;
217
218         /* enable receiver */
219         if (!(EU->RMAC_DMA_EN & 0x01))
220                 EU->RMAC_DMA_EN = 0x01;                 /* set run bit */
221
222 #ifdef DEBUG_NIC
223         printf("RMAC_MIB0..5: %d:%d:%d:%d:%d:%d\n",
224                 EU->RMAC_MIB0, EU->RMAC_MIB1,
225                 EU->RMAC_MIB2, EU->RMAC_MIB3,
226                 EU->RMAC_MIB4, EU->RMAC_MIB5);
227 #endif
228
229         return retstat; /* initially as this is called to flush the input */
230 }
231
232
233
234 /**************************************************************************
235  * TRANSMIT - Transmit a frame
236  **************************************************************************/
237
238 /* Function: p2001_eth_transmit
239  *
240  * Description: transmits a packet and waits for completion or timeout.
241  *
242  * Arguments: char d[6]:          destination ethernet address.
243  *            unsigned short t:   ethernet protocol type.
244  *            unsigned short s:   size of the data-part of the packet.
245  *            char *p:            the data for the packet.
246  *    
247  * Returns:   void.
248  */
249 static void p2001_eth_transmit(
250         struct nic *nic __unused,
251         const char *d,                  /* Destination */
252         unsigned int t,                 /* Type */
253         unsigned int s,                 /* size */
254         const char *p)                  /* Packet */
255 {
256         unsigned int nstype;
257 #ifdef DEBUG_NIC
258         unsigned int status;
259 #endif
260
261         /* assemble packet */
262         memcpy(txb, d, ETH_ALEN);                       // destination
263         memcpy(txb+ETH_ALEN, nic->node_addr, ETH_ALEN); // source
264         nstype = htons(t);
265         memcpy(txb+2*ETH_ALEN, (char*)&nstype, 2);      // type
266         memcpy(txb+ETH_HLEN, p, s);                     // packet
267         s += ETH_HLEN;
268
269         /* pad to minimum packet size */
270 //      while (s<ETH_ZLEN)
271 //              txb[s++] = '\0';
272         // TMAC_CNTL.ATP does the same
273
274 #ifdef DEBUG_NIC
275         printf("p2001_eth_transmit: packet from %! to %! sent (size: %d)\n", txb+ETH_ALEN, txb, s);
276 #endif
277
278         /* configure descriptor */
279         txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
280         txd.cntl = cur_channel << 16;           // DSC1 CHANNEL
281         txd.cntl |= s;                          // DSC1 LEN
282
283         /* restart the transmitter */
284         EU->TMAC_DMA_EN = 0x01;         /* set run bit */
285         while(EU->TMAC_DMA_EN & 0x01);  /* wait */
286
287 #ifdef DEBUG_NIC
288         /* check status */
289         status = EU->TMAC_DMA_STAT;
290         if (status & ~(0x40))   // not END
291                 printf("p2001_eth_transmit: dma status=0x%hx\n", status);
292
293         printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
294 #endif
295 }
296
297
298
299 /**************************************************************************
300  * IRQ - Enable, Disable or Force Interrupts
301  **************************************************************************/
302
303 /* Function: p2001_eth_irq
304  *
305  * Description: Enable, Disable, or Force, interrupts
306  *    
307  * Arguments: struct nic *nic:          NIC data structure
308  *            irq_action_t action:      Requested action       
309  *
310  * Returns:   void.
311  */
312
313 static void
314 p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused)
315 {
316         switch ( action ) {
317                 case DISABLE :
318                         break;
319                 case ENABLE :
320                         break;
321                 case FORCE :
322                         break;
323         }
324 }
325
326
327
328 /**************************************************************************
329  * INIT - Initialize device
330  **************************************************************************/
331
332 /* Function: p2001_init
333  *
334  * Description: resets the ethernet controller chip and various
335  *    data structures required for sending and receiving packets.
336  *    
337  * returns:   void.
338  */
339 static void p2001_eth_init()
340 {
341         static int i;
342
343         /* activate MII 3 */
344         if (cur_channel == 3)
345                 P2001_GPIO->PIN_MUX |= (1<<8);  // MII_3_en = 1
346
347 #ifdef RMII
348         /* RMII init sequence */
349         if (link & LPA_100) {
350                 EU->CONF_RMII = (1<<2) | (1<<1);                // softres | 100Mbit
351                 EU->CONF_RMII = (1<<2) | (1<<1) | (1<<0);       // softres | 100Mbit | RMII
352                 EU->CONF_RMII = (1<<1) | (1<<0);                // 100 Mbit | RMII
353         } else {
354                 EU->CONF_RMII = (1<<2);                         // softres
355                 EU->CONF_RMII = (1<<2) | (1<<0);                // softres | RMII
356                 EU->CONF_RMII = (1<<0);                         // RMII
357         }
358 #endif
359
360         /* disable transceiver */
361 //      EU->TMAC_DMA_EN = 0;            /* clear run bit */
362 //      EU->RMAC_DMA_EN = 0;            /* clear run bit */
363
364         /* set rx filter (physical mac addresses) */
365         EU->RMAC_PHYU =
366                 (MAC_HW_ADDR[0]<< 8) +
367                 (MAC_HW_ADDR[1]<< 0);
368         EU->RMAC_PHYL =
369                 (MAC_HW_ADDR[2]<<24) +
370                 (MAC_HW_ADDR[3]<<16) +
371                 (MAC_HW_ADDR[4]<<8 ) +
372                 (MAC_HW_ADDR[5]<<0 );
373
374         /* initialize the tx descriptor ring */
375 //      txd.stat = (1<<31) | (1<<30) | (1<<29);                 // DSC0 OWN|START|END
376 //      txd.cntl = cur_channel << 16;                           // DSC1 CHANNEL
377 //      txd.cntl |= DMA_BUF_SIZE;                               // DSC1 LEN
378         txd.buf = (char *)&txb;                                 // DSC2 BUFFER
379         txd.next = &txd;                                        // DSC3 NEXTDSC @self
380         EU->TMAC_DMA_DESC = &txd;
381
382         /* initialize the rx descriptor ring */
383         cur_rx = 0;
384         for (i = 0; i < NUM_RX_DESC; i++) {
385                 rxd[i].stat = (1<<31) | (1<<30) | (1<<29);      // DSC0 OWN|START|END
386                 rxd[i].cntl = (1<<23);                          // DSC1 RECEIVE
387                 rxd[i].cntl |= cur_channel << 16;               // DSC1 CHANNEL
388                 rxd[i].cntl |= DMA_BUF_SIZE;                    // DSC1 LEN
389                 rxd[i].buf = &rxb[i*DMA_BUF_SIZE];              // DSC2 BUFFER (EU-RX data)
390                 rxd[i].next = &rxd[i+1];                        // DSC3 NEXTDSC @next
391         }
392         rxd[NUM_RX_DESC-1].next = &rxd[0];                      // DSC3 NEXTDSC @first
393         EU->RMAC_DMA_DESC = &rxd[0];
394
395         /* set transmitter mode */
396         if (link & LPA_DUPLEX)
397                 EU->TMAC_CNTL = (1<<4) |        /* COI: Collision ignore */
398                                 (1<<3) |        /* CSI: Carrier Sense ignore */
399                                 (1<<2);         /* ATP: Automatic Transmit Padding */
400         else
401                 EU->TMAC_CNTL = (1<<2);         /* ATP: Automatic Transmit Padding */
402
403         /* set receive mode */
404         EU->RMAC_CNTL = (1<<3) |        /* BROAD: Broadcast packets */
405                         (1<<1);         /* PHY  : Packets to out MAC address */
406
407         /* enable receiver */
408         EU->RMAC_DMA_EN = 1;            /* set run bit */
409 }
410
411
412
413 /**************************************************************************
414  * DISABLE - Turn off ethernet interface
415  **************************************************************************/
416 static void p2001_eth_disable(struct dev *dev __unused)
417 {
418         /* put the card in its initial state */
419         /* This function serves 3 purposes.
420          * This disables DMA and interrupts so we don't receive
421          *  unexpected packets or interrupts from the card after
422          *  etherboot has finished. 
423          * This frees resources so etherboot may use
424          *  this driver on another interface
425          * This allows etherboot to reinitialize the interface
426          *  if something is something goes wrong.
427          */
428
429         /* disable transmitter */
430         EU->TMAC_DMA_EN = 0;            /* clear run bit */
431
432         /* disable receiver */
433         EU->RMAC_DMA_EN = 0;            /* clear run bit */
434 }
435
436
437
438 /**************************************************************************
439  * LINK - Check for valid link
440  **************************************************************************/
441 static int p2001_eth_check_link(unsigned int phy)
442 {
443         static int status;
444         static unsigned int i, physid;
445
446         /* print some information about out PHY */
447         physid = (p2001_eth_mdio_read(phy, MII_PHYSID2) << 16) |
448                   p2001_eth_mdio_read(phy, MII_PHYSID1);
449         printf("PHY %d, ID 0x%x ", phy, physid);
450         for (i = 0; mii_chip_table[i].physid; i++)
451                 if (mii_chip_table[i].physid == physid) {
452                         printf("(%s).\n", mii_chip_table[i].name);
453                         break;
454                 }
455         if (!mii_chip_table[i].physid)
456                 printf("(unknown).\n");
457
458         /* Use 0x3300 for restarting NWay */
459         printf("Starting auto-negotiation... ");
460         p2001_eth_mdio_write(phy, MII_BMCR, 0x3300);
461
462         /* Bit 1.5 is set once the Auto-Negotiation process is completed. */
463         i = 0;
464         do {
465                 mdelay(500);
466                 status = p2001_eth_mdio_read(phy, MII_BMSR);
467                 if (!status || (i++ > 6))       // 6*500ms = 3s timeout
468                         goto failed;
469         } while (!(status & BMSR_ANEGCOMPLETE));
470
471         /* Bits 1.2 is set once the link is established. */
472         if ((status = p2001_eth_mdio_read(phy, MII_BMSR)) & BMSR_LSTATUS) {
473                 link = p2001_eth_mdio_read(phy, MII_ADVERTISE) &
474                        p2001_eth_mdio_read(phy, MII_LPA);
475                 printf("  Valid link, operating at: %sMb-%s\n",
476                         (link & LPA_100) ? "100" : "10",
477                         (link & LPA_DUPLEX) ? "FD" : "HD");
478                 return 1;
479         }
480
481 failed:
482         if (!status)
483                 printf("Failed\n");
484         else
485                 printf("No valid link\n");
486         return 0;
487 }
488
489
490
491 /**************************************************************************
492  * PHYRESET - hardware reset all MII PHYs
493  **************************************************************************/
494
495 /**
496  *      p2001_eth_phyreset - hardware reset all MII PHYs
497  */
498 static void p2001_eth_phyreset()
499 {
500         /* GPIO24/25: TX_ER2/TX_ER0 */
501         /* GPIO26/27: PHY_RESET/TX_ER1 */
502         P2001_GPIO->PIN_MUX |= 0x0018;
503         // 31-16: 0000 1111 0000 0000
504         P2001_GPIO->GPIO2_En |= 0x0400;
505
506         P2001_GPIO->GPIO2_Out |= 0x04000000;
507         P2001_GPIO->GPIO2_Out &= ~0x0400;
508         mdelay(500);
509         P2001_GPIO->GPIO2_Out |= 0x0400;
510
511 #ifdef RMII
512         /* RMII_clk_sel = 0xxb  no RMII (default) */
513         /* RMII_clk_sel = 100b  COL_0 */
514         /* RMII_clk_sel = 101b  COL_1 */
515         /* RMII_clk_sel = 110b  COL_2 */
516         /* RMII_clk_sel = 111b  COL_3 */
517         P2001_GPIO->PIN_MUX |= (4 << 13);
518 #endif
519 }
520
521
522
523 /**************************************************************************
524  * PROBE - Look for an adapter, this routine's visible to the outside
525  **************************************************************************/
526
527 static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
528 {
529         struct nic *nic = (struct nic *)dev;
530         /* if probe_addrs is 0, then routine can use a hardwired default */
531
532         /* reset phys and configure mdio clk */
533         printf("Resetting PHYs...\n");
534         p2001_eth_phyreset();
535
536         /* set management unit clock divisor */
537         // max. MDIO CLK = 2.048 MHz (EU.doc)
538         P2001_MU->MU_DIV = (SYSCLK/4096000)-1;  // 2.048 MHz
539         //asm("nop \n nop");
540
541         /* find the correct PHY/DMA/MAC combination */
542         printf("Searching for P2001 NICs...\n");
543         cur_phy = -1;
544         for (cur_channel=0; cur_channel<4; cur_channel++) {
545                 EU = P2001_EU(cur_channel);
546
547                 /* find next phy */
548                 while (++cur_phy < 16) {
549                         //printf("phy detect %d\n", cur_phy);
550                         if (p2001_eth_mdio_read(cur_phy, MII_BMSR) != 0)
551                                 break;
552                 }
553                 if (cur_phy == 16) {
554                         printf("no more MII PHYs found\n");
555                         break;
556                 }
557
558                 /* first a non destructive test for initial value RMAC_TLEN=1518 */
559                 if (EU->RMAC_TLEN == 1518) {
560                         printf("Checking EU%d...\n", cur_channel);
561
562                         if (p2001_eth_check_link(cur_phy)) {
563                                 /* initialize device */
564                                 p2001_eth_init(nic);
565
566                                 /* set node address */
567                                 printf("Setting MAC address to %!\n", MAC_HW_ADDR);
568                                 memcpy(nic->node_addr, MAC_HW_ADDR, 6);
569
570                                 /* point to NIC specific routines */
571                                 dev->disable  = p2001_eth_disable;
572                                 nic->poll     = p2001_eth_poll;
573                                 nic->transmit = p2001_eth_transmit;
574                                 nic->irq      = p2001_eth_irq;
575
576                                 /* Report the ISA pnp id of the board */
577                                 dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
578                                 return 1;
579                         }
580                 }
581         }
582         /* else */
583         return 0;
584 }
585
586 ISA_ROM("p2001_eth", "P2001 Ethernet Driver")
587 static struct isa_driver p2001_eth_driver __isa_driver = {
588         .type    = NIC_DRIVER,
589         .name    = "P2001 Ethernet Driver",
590         .probe   = p2001_eth_probe,
591         .ioaddrs = 0,
592 };