| /* |
| * (C) Copyright 2005 |
| * Ladislav Michl, 2N Telekomunikace, michl@2n.cz |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| * |
| * Some code shamelessly stolen back from Robin Getz. |
| */ |
| |
| #define DEBUG |
| |
| #include <common.h> |
| #include <exports.h> |
| #include <timestamp.h> |
| #include <net.h> |
| #include "../drivers/net/smc91111.h" |
| |
| static u16 read_eeprom_reg(struct eth_device *dev, u16 reg) |
| { |
| int timeout; |
| |
| SMC_SELECT_BANK(dev, 2); |
| SMC_outw(dev, reg, PTR_REG); |
| |
| SMC_SELECT_BANK(dev, 1); |
| SMC_outw(dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD, |
| CTL_REG); |
| timeout = 100; |
| while((SMC_inw (dev, CTL_REG) & CTL_RELOAD) && --timeout) |
| udelay(100); |
| if (timeout == 0) { |
| printf("Timeout Reading EEPROM register %02x\n", reg); |
| return 0; |
| } |
| |
| return SMC_inw (dev, GP_REG); |
| } |
| |
| static int write_eeprom_reg(struct eth_device *dev, u16 value, u16 reg) |
| { |
| int timeout; |
| |
| SMC_SELECT_BANK(dev, 2); |
| SMC_outw(dev, reg, PTR_REG); |
| |
| SMC_SELECT_BANK(dev, 1); |
| SMC_outw(dev, value, GP_REG); |
| SMC_outw(dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG); |
| timeout = 100; |
| while ((SMC_inw(dev, CTL_REG) & CTL_STORE) && --timeout) |
| udelay (100); |
| if (timeout == 0) { |
| printf("Timeout Writing EEPROM register %02x\n", reg); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int write_data(struct eth_device *dev, u16 *buf, int len) |
| { |
| u16 reg = 0x23; |
| |
| while (len--) |
| write_eeprom_reg(dev, *buf++, reg++); |
| |
| return 0; |
| } |
| |
| static int verify_macaddr(struct eth_device *dev, char *s) |
| { |
| u16 reg; |
| int i, err = 0; |
| |
| printf("MAC Address: "); |
| err = i = 0; |
| for (i = 0; i < 3; i++) { |
| reg = read_eeprom_reg(dev, 0x20 + i); |
| printf("%02x:%02x%c", reg & 0xff, reg >> 8, i != 2 ? ':' : '\n'); |
| if (s) |
| err |= reg != ((u16 *)s)[i]; |
| } |
| |
| return err ? 0 : 1; |
| } |
| |
| static int set_mac(struct eth_device *dev, char *s) |
| { |
| int i; |
| char *e, eaddr[6]; |
| |
| /* turn string into mac value */ |
| for (i = 0; i < 6; i++) { |
| eaddr[i] = simple_strtoul(s, &e, 16); |
| s = (*e) ? e+1 : e; |
| } |
| |
| for (i = 0; i < 3; i++) |
| write_eeprom_reg(dev, *(((u16 *)eaddr) + i), 0x20 + i); |
| |
| return 0; |
| } |
| |
| static int parse_element(char *s, unsigned char *buf, int len) |
| { |
| int cnt; |
| char *p, num[3]; |
| unsigned char id; |
| |
| id = simple_strtoul(s, &p, 16); |
| if (*p++ != ':') |
| return -1; |
| cnt = 2; |
| num[2] = 0; |
| for (; *p; p += 2) { |
| if (p[1] == 0) |
| return -2; |
| if (cnt + 3 > len) |
| return -3; |
| num[0] = p[0]; |
| num[1] = p[1]; |
| buf[cnt++] = simple_strtoul(num, NULL, 16); |
| } |
| buf[0] = id; |
| buf[1] = cnt - 2; |
| |
| return cnt; |
| } |
| |
| int eeprom(int argc, char *argv[]) |
| { |
| int i, len, ret; |
| unsigned char buf[58], *p; |
| |
| struct eth_device dev = { |
| .iobase = CONFIG_SMC91111_BASE |
| }; |
| |
| app_startup(argv); |
| if (get_version() != XF_VERSION) { |
| printf("Wrong XF_VERSION.\n"); |
| printf("Application expects ABI version %d\n", XF_VERSION); |
| printf("Actual U-Boot ABI version %d\n", (int)get_version()); |
| return 1; |
| } |
| |
| if ((SMC_inw (&dev, BANK_SELECT) & 0xFF00) != 0x3300) { |
| printf("SMSC91111 not found.\n"); |
| return 2; |
| } |
| |
| /* Called without parameters - print MAC address */ |
| if (argc < 2) { |
| verify_macaddr(&dev, NULL); |
| return 0; |
| } |
| |
| /* Print help message */ |
| if (argv[1][1] == 'h') { |
| printf("VoiceBlue EEPROM writer\n"); |
| printf("Built: %s at %s\n", U_BOOT_DATE, U_BOOT_TIME); |
| printf("Usage:\n\t<mac_address> [<element_1>] [<...>]\n"); |
| return 0; |
| } |
| |
| /* Try to parse information elements */ |
| len = sizeof(buf); |
| p = buf; |
| for (i = 2; i < argc; i++) { |
| ret = parse_element(argv[i], p, len); |
| switch (ret) { |
| case -1: |
| printf("Element %d: malformed\n", i - 1); |
| return 3; |
| case -2: |
| printf("Element %d: odd character count\n", i - 1); |
| return 3; |
| case -3: |
| printf("Out of EEPROM memory\n"); |
| return 3; |
| default: |
| p += ret; |
| len -= ret; |
| } |
| } |
| |
| /* First argument (MAC) is mandatory */ |
| set_mac(&dev, argv[1]); |
| if (verify_macaddr(&dev, argv[1])) { |
| printf("*** MAC address does not match! ***\n"); |
| return 4; |
| } |
| |
| while (len--) |
| *p++ = 0; |
| |
| write_data(&dev, (u16 *)buf, sizeof(buf) >> 1); |
| |
| return 0; |
| } |