]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/smsc/lan92xx/v2_0/src/if_lan92xx.c
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / smsc / lan92xx / v2_0 / src / if_lan92xx.c
1 //==========================================================================
2 //
3 //      dev/if_lan92xx.c
4 //
5 //      Ethernet device driver for SMSC LAN92XX compatible controllers
6 //
7 //==========================================================================
8 //==========================================================================
9
10 //#####DESCRIPTIONBEGIN####
11 //
12 // Author(s):    Fred Fan
13 // Contributors:
14 // Date:         2007-10-16
15 // Purpose:
16 // Description:  Driver for SMSC LAN92xx ethernet controller
17 //
18 // Note:
19 //
20 //####DESCRIPTIONEND####
21 //
22 //==========================================================================
23 #include <pkgconf/system.h>
24 #include <pkgconf/io_eth_drivers.h>
25
26 #include <cyg/infra/cyg_type.h>
27 #include <cyg/hal/hal_arch.h>
28 #include <cyg/hal/hal_intr.h>
29 #include <cyg/hal/hal_diag.h>
30 #include <cyg/infra/cyg_ass.h>
31 #include <cyg/infra/diag.h>
32 #include <cyg/hal/drv_api.h>
33 #include <cyg/io/eth/netdev.h>
34 #include <cyg/io/eth/eth_drv.h>
35 #include <cyg/io/smsc_lan92xx.h>
36
37
38 #ifdef CYGPKG_NET
39 #include <pkgconf/net.h>
40 #include <cyg/kernel/kapi.h>
41 #include <net/if.h>  /* Needed for struct ifnet */
42 #endif
43
44 //#define LAN92XX_DEBUG
45 #ifdef LAN92XX_DEBUG
46 #define PDEBUG(fmt, args...) diag_printf(fmt, ##args)
47 #else
48 #define PDEBUG(fmt, args...)
49 #endif /*LAN92XX_DEBUG*/
50
51 #define __WANT_DEVS
52 #include CYGDAT_DEVS_ETH_SMSC_LAN92XX_INL
53 #undef __WANT_DEVS
54
55 #define LAN_92XX_DRV_VER    "1.1"
56
57 #define MAX_RX_NUM (CYGNUM_IO_ETH_DRIVERS_NUM_PKT - 1)
58 static smsc_lan92xx_id_t smsc_lan92xx_id_table[] =
59 {
60     {0x117A, 0x0000, "SMSC LAN9217"},
61     {0x9220, 0x0000, "SMSC LAN9220"},
62     {0},
63 };
64
65 static int lan92xx_eeprom_present = 1;
66
67 static smsc_lan92xx_t lan92xx_dev;
68 static inline void
69 lan92xx_set_mac_addr(struct eth_drv_sc *sc, unsigned char *enaddr);
70 static void lan92xx_soft_reset(struct eth_drv_sc *sc);
71 static inline unsigned int
72 lan92xx_mac_read(struct eth_drv_sc *sc, unsigned char reg);
73 static inline void
74 lan92xx_mac_write(struct eth_drv_sc *sc, unsigned char reg, unsigned long val);
75 static inline unsigned int
76 lan92xx_mii_read(struct eth_drv_sc *sc, unsigned char addr);
77 static inline void
78 lan92xx_mii_write(struct eth_drv_sc *sc, unsigned char addr, unsigned int val);
79
80 /*!
81  * This function set the value of PHY registers by MII interface
82  */
83 static void
84 lan92xx_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
85 {
86     unsigned int val;
87     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
88
89     lan92xx_set_mac_addr(sc, enaddr);
90
91     pdev->tx_busy = 0;
92
93     val = lan92xx_mac_read(sc, MAC_MAC_CR)& (~0x800);
94     val |= 0x0010080C;
95     lan92xx_mac_write(sc, MAC_MAC_CR, val);
96     val = lan92xx_mac_read(sc, MAC_MAC_CR);
97 }
98
99 /*!
100  * This function pauses the FEC controller.
101  */
102 static void
103 lan92xx_stop(struct eth_drv_sc *sc)
104 {
105     unsigned int val;
106
107     val = lan92xx_mac_read(sc, MAC_MAC_CR);
108     val &= ~(0x0000000C);
109     lan92xx_mac_write(sc, MAC_MAC_CR, val);
110 }
111
112 static int
113 lan92xx_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
114 {
115     /*TODO:: Add support */
116     PDEBUG("%s: key=0x%x, data=0x%x, data_len=0x%x\n",
117            __FUNCTION__, key, (unsigned long)data, (unsigned long)data_length);
118     return 0;
119 }
120
121 /*!
122  * This function checks the status of FEC control.
123  */
124 static int
125 lan92xx_can_send(struct eth_drv_sc *sc)
126 {
127     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
128
129     if (!(pdev->status & PHY_LINK_ON)) return 0;
130     if (pdev->tx_busy) return 0;
131
132     return 1;
133 }
134
135 /*!
136  * This function transmits a frame.
137  */
138 static void
139 lan92xx_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total, unsigned long key)
140 {
141     int i, j, len, freespace;
142     unsigned int tx_cmd1, tx_cmd2, data, *pdata;
143     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
144     freespace = LAN92XX_REG_READ(LAN92XX_TX_FIFO_INF) & 0xFFFF;
145
146     if (freespace < total + 16 ) {
147         sc->funs->eth_drv->tx_done(sc, key, -1);
148         return;
149     }
150     for (i = 0; i < sg_len; i++) {
151         len = (sg_list[i].len + 3) >> 2;
152         if (i == (sg_len - 1))
153             tx_cmd1 = 0x1000;
154         else if (i)
155             tx_cmd1 = 0x0000;
156         else
157             tx_cmd1 = 0x2000;
158
159         tx_cmd1 |= sg_list[i].len;
160         tx_cmd2 = (total << 16) + total;
161         LAN92XX_REG_WRITE(LAN92XX_TX_DATA, tx_cmd1);
162
163         LAN92XX_REG_WRITE(LAN92XX_TX_DATA, tx_cmd2);
164         pdata = (unsigned int *)sg_list[i].buf;
165
166         for (j=0; j<len; j++) {
167             data = *(pdata++);
168             LAN92XX_REG_WRITE(LAN92XX_TX_DATA, data);
169             for (data=0; data<2; data++) {
170                 asm volatile("nop");
171                 asm volatile("nop");
172                 asm volatile("nop");
173                 asm volatile("nop");
174             }
175         }
176     }
177     pdev->tx_busy = 1;
178     pdev->tx_key = key;
179 }
180
181 static void
182 lan92xx_drop_packet(struct eth_drv_sc *sc, int count)
183 {
184     unsigned int data;
185     if (count >= 4) {
186         LAN92XX_REG_WRITE(LAN92XX_RX_DP_CTRL, 0x80000000);
187         while (LAN92XX_REG_READ(LAN92XX_RX_DP_CTRL) & 0x80000000) {
188         }
189     } else {
190         while (count--)
191             data = LAN92XX_REG_READ(LAN92XX_RX_DATA);
192     }
193 }
194
195 /*!
196  * This function receives ready Frame in DB.
197  */
198 static void
199 lan92xx_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
200 {
201     unsigned int i, rlen;
202     unsigned int *pdata = (unsigned int *)(sg_list->buf);
203
204     rlen = (sg_list->len + 3) >> 2;
205     if ((void *)(sg_list->buf) == NULL) {
206         goto Drop;
207     }
208
209     for (i = 0; i < rlen; i++) {
210         *(pdata++) = LAN92XX_REG_READ(LAN92XX_RX_DATA);
211     }
212     return;
213 Drop:
214     lan92xx_drop_packet(sc, rlen);
215 }
216
217 static void
218 lan92xx_deliver(struct eth_drv_sc *sc)
219 {
220     /*TODO::When redboot support thread ,
221      *      the polling function will be called at here
222      */
223     return;
224 }
225
226 static void
227 lan92xx_link_status(struct eth_drv_sc *sc)
228 {
229     unsigned int val;
230     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
231     val = lan92xx_mii_read(sc, PHY_ISR);
232     if (val&0x50) {
233         val = lan92xx_mii_read(sc, PHY_BSR);
234         if (val != pdev->status) {
235             pdev->status = val;
236             val = lan92xx_mac_read(sc, MAC_MAC_CR) & (~0x802F0800);
237             if ( IS_DUPLEX(pdev->status)) {
238                 val |= 0x00100000;
239             }
240             lan92xx_mac_write(sc, MAC_MAC_CR, val);
241         }
242     }
243 }
244 /*!
245  * This function checks the event of FEC controller
246  */
247 static void
248 lan92xx_poll(struct eth_drv_sc *sc)
249 {
250     unsigned int val, reg;
251     int rx_num = 0;
252     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
253
254     reg = LAN92XX_REG_READ(LAN92XX_INT_STS);
255     LAN92XX_REG_WRITE(LAN92XX_INT_STS, reg);
256
257     //diag_printf("INT_STS: %x\n", reg);
258     if (reg & 0x40000) {
259         lan92xx_link_status(sc);
260     }
261
262     if (reg & 0xE000) {
263         diag_printf("%s:: TX or RX error [0x%x]\n", __FUNCTION__, reg);
264         lan92xx_soft_reset(sc);
265         return;
266     }
267
268     while (1) {
269         reg = LAN92XX_REG_READ(LAN92XX_RX_FIFO_INF);
270         if (!(reg & 0xFF0000))
271             break;
272         reg = LAN92XX_REG_READ(LAN92XX_RX_STATUS1);
273
274         if (reg & 0x4000909A) {
275             val = (reg >> 16) & 0x3FFF;
276             val = (val + 3) >> 2;
277             lan92xx_drop_packet(sc, val);
278         } else {
279             val = (reg >> 16) & 0x3FFF;
280             sc->funs->eth_drv->recv(sc, val);
281             rx_num++;
282         }
283
284         if ( rx_num >= MAX_RX_NUM) break;
285     }
286
287     while (1) {
288         reg = LAN92XX_REG_READ(LAN92XX_TX_FIFO_INF);
289         if (!(reg & 0xFF0000)) break;
290
291         if (!LAN92XX_REG_READ(LAN92XX_TX_STATUS2)) {
292             diag_printf("***FIFO %x, wrong status =%x: int_sts=%x\n",
293                         reg, LAN92XX_REG_READ(LAN92XX_TX_STATUS2),
294                         LAN92XX_REG_READ(LAN92XX_INT_STS));
295             continue;
296         }
297         reg = LAN92XX_REG_READ(LAN92XX_TX_STATUS1);
298         if (reg & 0x8000) {
299             sc->funs->eth_drv->tx_done(sc, pdev->tx_key, -1);
300         } else {
301             sc->funs->eth_drv->tx_done(sc, pdev->tx_key, 0);
302         }
303         pdev->tx_busy = 0;
304     }
305 }
306
307 static int
308 lan92xx_int_vector(struct eth_drv_sc *sc)
309 {
310     PDEBUG("%s::\n", __FUNCTION__);
311
312     /*TODO::
313      *      get FEC interrupt number
314      */
315     return -1;
316 }
317
318 static smsc_lan92xx_id_t *lan92xx_probe(unsigned long id)
319 {
320     smsc_lan92xx_id_t *p = smsc_lan92xx_id_table;
321     while (p->id) {
322         if (id == p->id)
323             return p;
324         p++;
325     }
326     return NULL;
327 }
328
329 static inline unsigned int
330 lan92xx_mac_read(struct eth_drv_sc *sc, unsigned char reg)
331 {
332     unsigned int cmd;
333
334     if (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000) {
335         diag_printf("Error: %d. MAC is busy\n", __LINE__);
336         return 0xFFFFFFFF;
337     }
338
339     cmd = 0xC0000000 | (reg & 0xFF);
340     LAN92XX_REG_WRITE(LAN92XX_MAC_CMD, cmd);
341
342     /* Workaround for hardware read-after-write */
343     LAN92XX_REG_READ(LAN92XX_BYTE_TEST);
344
345     while (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000);
346
347     return LAN92XX_REG_READ(LAN92XX_MAC_DATA);
348 }
349
350 static inline void
351 lan92xx_mac_write(struct eth_drv_sc *sc, unsigned char reg, unsigned long val)
352 {
353     unsigned int cmd;
354
355     if (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000) {
356         diag_printf("Error: %d. MAC is busy\n", __LINE__);
357         return;
358     }
359
360     LAN92XX_REG_WRITE(LAN92XX_MAC_DATA, val);
361     cmd = 0x80000000 | (reg & 0xFF);
362     LAN92XX_REG_WRITE(LAN92XX_MAC_CMD, cmd);
363
364     /* Workaround for hardware read-after-write */
365     LAN92XX_REG_READ(LAN92XX_BYTE_TEST);
366
367     while (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000);
368 }
369
370 static inline void
371 lan92xx_set_mac_addr(struct eth_drv_sc *sc, unsigned char *enaddr)
372 {
373     unsigned int val;
374     val = enaddr[3];
375     val = (val << 8) | enaddr[2];
376     val = (val << 8) | enaddr[1];
377     val = (val << 8) | enaddr[0];
378     lan92xx_mac_write(sc, MAC_ADDRL, val);
379
380     val = lan92xx_mac_read(sc, MAC_ADDRH) >> 16;
381     val = (val << 8) | enaddr[5];
382     val = (val << 8) | enaddr[4];
383     lan92xx_mac_write(sc, MAC_ADDRH, val);
384 }
385
386 static inline unsigned int
387 lan92xx_mii_read(struct eth_drv_sc *sc, unsigned char addr)
388 {
389     unsigned int cmd;
390
391     cmd = (0x1 << 11 ) | (addr << 6) | 1;
392     lan92xx_mac_write(sc, MAC_MII_ACC, cmd);
393     while (lan92xx_mac_read(sc, MAC_MII_ACC) & 1);
394
395     return lan92xx_mac_read(sc, MAC_MII_DATA)&0xFFFF;
396 }
397
398 static inline void
399 lan92xx_mii_write(struct eth_drv_sc *sc, unsigned char addr, unsigned int val)
400 {
401     unsigned int cmd;
402
403     cmd = (0x1 << 11 ) | (addr << 6) | 3;
404     lan92xx_mac_write(sc, MAC_MII_DATA, val);
405     lan92xx_mac_read(sc, MAC_MII_DATA);
406     lan92xx_mac_write(sc, MAC_MII_ACC, cmd);
407
408     while (lan92xx_mac_read(sc, MAC_MII_ACC) & 1);
409 }
410
411 static int lan92xx_phy_init(struct eth_drv_sc *sc)
412 {
413     int val;
414     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
415
416     lan92xx_mii_write(sc, PHY_BCR, 0x8000);
417
418     while (lan92xx_mii_read(sc, PHY_BCR) & 0x8000);
419
420     for (val = 0; val < 2500; val++)
421         hal_delay_us(4);
422
423     val = lan92xx_mii_read(sc, PHY_ANAR);
424     val |= 0x01E1;
425     lan92xx_mii_write(sc, PHY_ANAR, val);
426     lan92xx_mii_write(sc, PHY_SMR, 0x00E1);
427     lan92xx_mii_write(sc, PHY_SCSI, 0x400B);
428     lan92xx_mii_write(sc, PHY_IMR, 0x00F0);
429     lan92xx_mii_write(sc, PHY_BCR, 0x1200);
430
431     while ((lan92xx_mii_read(sc, PHY_BCR) & 0x200));
432
433     pdev->status = lan92xx_mii_read(sc, PHY_BSR);
434
435     return 0;
436 }
437
438 static int lan92xx_mac_init(struct eth_drv_sc *sc)
439 {
440     static int mac_init = 0;
441     unsigned int val;
442     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
443
444     val = lan92xx_mac_read(sc, MAC_MAC_CR) & (~0x802F0800);
445     if (IS_DUPLEX(pdev->status)) {
446         val |= 0x00100000;
447     }
448     lan92xx_mac_write(sc, MAC_MAC_CR, val);
449
450     lan92xx_mac_write(sc, MAC_HASHH, 0);
451     lan92xx_mac_write(sc, MAC_HASHL, 0);
452
453     if (mac_init)
454         return 0;
455
456     mac_init = 1;
457
458 #if CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
459     if (!_board_provide_eth0_esa(pdev->mac_addr))
460 #endif
461     {
462         // make sure EPC not busy
463         while ((val = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
464
465         if (val & E2P_CMD_TIMEOUT) {
466             lan92xx_eeprom_present = 0;
467             diag_printf("LAN9217: NO EEPROM\n");
468             return -1;
469         }
470
471         if (!(LAN92XX_REG_READ(LAN92XX_E2P_CMD) & E2P_CMD_LOADED)) {
472             diag_printf("LAN9217:EEPROM is empty\n");
473         }
474         val = lan92xx_mac_read(sc, MAC_ADDRH);
475         pdev->mac_addr[5] = (val >> 8) & 0xFF;
476         pdev->mac_addr[4] = val&0xFF;
477         val = lan92xx_mac_read(sc, MAC_ADDRL);
478         pdev->mac_addr[3] = (val >> 24) & 0xFF;
479         pdev->mac_addr[2] = (val >> 16) & 0xFF;
480         pdev->mac_addr[1] = (val >> 8) & 0xFF;
481         pdev->mac_addr[0] = val & 0xFF;
482     }
483     return 0;
484 }
485
486 /*
487  * This function reset LAN9219 .
488  */
489 static void
490 lan92xx_soft_reset(struct eth_drv_sc *sc)
491 {
492     unsigned int timeout = MAC_TIMEOUT;
493
494     LAN92XX_REG_WRITE(LAN92XX_HW_CFG, 1);
495     while ((LAN92XX_REG_READ(LAN92XX_HW_CFG) & 1) && (--timeout)) {
496         hal_delay_us(MAC_TICKET);
497     }
498
499     if (!timeout) {
500         diag_printf("LAN92XX: Reset fail \n");
501         return ;
502     }
503
504     LAN92XX_REG_WRITE(LAN92XX_INT_EN, 0);
505     LAN92XX_REG_WRITE(LAN92XX_HW_CFG, 0x150000);
506     LAN92XX_REG_WRITE(LAN92XX_AFC_CFG, 0x6E3740);
507     LAN92XX_REG_WRITE(LAN92XX_TX_CFG, 0x2);
508
509     timeout = MAC_TIMEOUT;
510
511     while ((LAN92XX_REG_READ(LAN92XX_E2P_CMD) & 0x80000000) && (--timeout)) {
512         hal_delay_us(MAC_TICKET);
513     }
514
515     LAN92XX_REG_WRITE(LAN92XX_GPIO_CFG, 0x70070000);
516     LAN92XX_REG_WRITE(LAN92XX_INT_STS, 0xFFFFFFFF);
517     lan92xx_mac_init(sc);
518 }
519
520 /*!
521  * This function initializes the LAN92xx driver.
522  * It is called by net_init in net module of RedBoot during RedBoot init
523  */
524 static bool
525 lan92xx_init(struct cyg_netdevtab_entry *tab)
526 {
527     unsigned int reg, timeout;
528     smsc_lan92xx_id_t *id;
529     struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
530     smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
531
532     diag_printf("\nLAN92xx Driver version %s\n", LAN_92XX_DRV_VER);
533     if (!pdev) {
534         diag_printf("LAN92xx:: Driver don't attach with device\n");
535         return false;
536     }
537     reg = LAN92XX_REG_READ(LAN92XX_ID_REV);
538     id = lan92xx_probe(reg >> 16);
539     if (id) {
540         diag_printf("%s: ID = 0x%x REV = 0x%x\n", id->id_name, id->id, id->ver);
541     } else {
542         diag_printf("LAN92XX: unknow chip ID = %x\n", reg);
543         return false;
544     }
545
546     timeout = MAC_TIMEOUT;
547     while ((!(LAN92XX_REG_READ(LAN92XX_PMT_CTRL) & 1)) && (--timeout)) {
548         hal_delay_us(MAC_TICKET);
549     }
550     if (timeout == 0) {
551         diag_printf("LAN92XX: is not ready to access\n");
552         return false;
553     }
554
555     lan92xx_phy_init(sc);
556
557     lan92xx_soft_reset(sc);
558     (sc->funs->eth_drv->init)(sc, pdev->mac_addr);
559     return true;
560 }
561
562 /*!
563  * Global variable which defines the LAN92xx driver,
564  */
565 ETH_DRV_SC(lan92xx_sc,
566            &lan92xx_dev, // Driver specific data
567            CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME,
568            lan92xx_start,
569            lan92xx_stop,
570            lan92xx_control,
571            lan92xx_can_send,
572            lan92xx_send,
573            lan92xx_recv,
574            lan92xx_deliver,     // "pseudoDSR" called from fast net thread
575            lan92xx_poll,        // poll function, encapsulates ISR and DSR
576            lan92xx_int_vector);
577
578 /*!
579  * Global variable which defines the FEC device
580  */
581 NETDEVTAB_ENTRY(lan92xx_netdev,
582                 "lan92xx_" CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME,
583                 lan92xx_init,
584                 &lan92xx_sc);
585
586 // Low level function to issue a command to the eeprom controller.
587 // return 0 on success and -1 on failure
588 static inline int
589 _lan92xx_e2p_do_cmd(unsigned int cmd)
590 {
591     unsigned int v;
592     LAN92XX_REG_WRITE(LAN92XX_E2P_CMD, cmd);
593     while ((v = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
594     if (v & E2P_CMD_TIMEOUT) {
595         diag_printf("%s:: EEPROM timeout\n", __FUNCTION__);
596         // clear the timeout status bit
597         LAN92XX_REG_WRITE(LAN92XX_E2P_CMD, E2P_CMD_TIMEOUT);
598         while ((v = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
599         return -1;
600     }
601     return 0;
602 }
603
604 // for all the 7 EEPROM operations
605 // return 0 on success and -1 on failure
606 static int
607 lan92xx_e2p_op(enum epc_cmd cmd, unsigned char addr, unsigned char *data)
608 {
609     switch (cmd) {
610     case E2P_CMD_READ:
611         if (_lan92xx_e2p_do_cmd(E2P_CMD(cmd, addr)) != 0)
612             return -1;
613         *data = (unsigned char)LAN92XX_REG_READ(LAN92XX_E2P_DATA);
614         return 0;
615         break;
616     case E2P_CMD_WRAL:
617     case E2P_CMD_WRITE:
618         LAN92XX_REG_WRITE(LAN92XX_E2P_DATA, *data);
619         break;
620     default:
621         break;
622     }
623
624     if (_lan92xx_e2p_do_cmd(E2P_CMD(cmd, addr)) != 0)
625         return -1;
626
627     return 0;
628 }
629
630 static void setMac(int argc, char *argv[])
631 {
632     int i;
633     unsigned char data[7];
634     unsigned long temp;
635
636     if (!lan92xx_eeprom_present) {
637         diag_printf("NO EEPROM present\n\n");
638         return;
639     }
640
641     if (argc == 1) {
642         for (i = 0; i < 7 ; i++) {
643             if (lan92xx_e2p_op(E2P_CMD_READ, i, &data[i]) != 0) {
644                 diag_printf("read MAC %d address fail\n\n", i);
645                 return;
646             }
647         }
648
649         if (data[0] != E2P_CONTEXT_ID) {
650             diag_printf("Warning: Unprogrammed MAC address: 0x%x\n", data[0]);
651             return;
652         }
653
654         diag_printf("MAC address: ");
655         diag_printf("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n\n",
656                     data[1], data[2], data[3],
657                     data[4], data[5], data[6]);
658         return;
659     }
660
661     if (argc != 2) {
662         diag_printf("Error: Wrong argument\n");
663         return;
664     }
665
666     data[0] = E2P_CONTEXT_ID;
667     for (i = 1;  i < 7;  i++) {
668         if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
669             diag_printf("Error: failed to parse command: %d\n", __LINE__);
670             return;
671         }
672         if (temp > 0xFF) {
673             diag_printf("Error: invalid valie: 0x%x\n", (unsigned int)temp);
674             return;
675         }
676         data[i] = temp;
677     }
678
679     // enable erase/write
680     if (lan92xx_e2p_op(E2P_CMD_EWEN, 0, data) != 0) {
681         diag_printf("%s:: Enable write/erase fail\n", __FUNCTION__);
682         return;
683     }
684     for (i = 0; i < 7; i++) {
685         if (lan92xx_e2p_op(E2P_CMD_ERASE, i, &data[i]) != 0 ||
686             lan92xx_e2p_op(E2P_CMD_WRITE, i, &data[i]) != 0) {
687             diag_printf("Error: failed to program eeprom at %d\n", i);
688             return;
689         }
690     }
691
692     // disable erase/write
693     if (lan92xx_e2p_op(E2P_CMD_EWDS, 0, data) != 0) {
694         diag_printf("%s:: Enable write/erase fail\n", __FUNCTION__);
695     }
696 }
697
698 RedBoot_cmd("setmac",
699             "Set Ethernet MAC address in EEPROM",
700             "[0x##:0x##:0x##:0x##:0x##:0x##]",
701             setMac
702            );