11bc15386SPeter Tyser /* 21bc15386SPeter Tyser * smc911x_eeprom.c - EEPROM interface to SMC911x parts. 31bc15386SPeter Tyser * Only tested on SMSC9118 though ... 41bc15386SPeter Tyser * 5*c44efcf9SMike Frysinger * Copyright 2004-2009 Analog Devices Inc. 61bc15386SPeter Tyser * 71bc15386SPeter Tyser * Licensed under the GPL-2 or later. 81bc15386SPeter Tyser * 91bc15386SPeter Tyser * Based on smc91111_eeprom.c which: 101bc15386SPeter Tyser * Heavily borrowed from the following peoples GPL'ed software: 111bc15386SPeter Tyser * - Wolfgang Denk, DENX Software Engineering, wd@denx.de 121bc15386SPeter Tyser * Das U-boot 131bc15386SPeter Tyser * - Ladislav Michl ladis@linux-mips.org 141bc15386SPeter Tyser * A rejected patch on the U-Boot mailing list 151bc15386SPeter Tyser */ 161bc15386SPeter Tyser 171bc15386SPeter Tyser #include <common.h> 181bc15386SPeter Tyser #include <exports.h> 191bc15386SPeter Tyser 20*c44efcf9SMike Frysinger /* the smc911x.h gets base addr through eth_device' iobase */ 21*c44efcf9SMike Frysinger struct eth_device { 22*c44efcf9SMike Frysinger const char *name; 23*c44efcf9SMike Frysinger unsigned long iobase; 24*c44efcf9SMike Frysinger void *priv; 25*c44efcf9SMike Frysinger }; 261bc15386SPeter Tyser #include "../drivers/net/smc911x.h" 271bc15386SPeter Tyser 281bc15386SPeter Tyser /** 291bc15386SPeter Tyser * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) 301bc15386SPeter Tyser */ 311bc15386SPeter Tyser static int smsc_ctrlc(void) 321bc15386SPeter Tyser { 331bc15386SPeter Tyser return (tstc() && getc() == 0x03); 341bc15386SPeter Tyser } 351bc15386SPeter Tyser 361bc15386SPeter Tyser /** 371bc15386SPeter Tyser * usage - dump usage information 381bc15386SPeter Tyser */ 391bc15386SPeter Tyser static void usage(void) 401bc15386SPeter Tyser { 411bc15386SPeter Tyser puts( 421bc15386SPeter Tyser "MAC/EEPROM Commands:\n" 431bc15386SPeter Tyser " P : Print the MAC addresses\n" 441bc15386SPeter Tyser " D : Dump the EEPROM contents\n" 451bc15386SPeter Tyser " M : Dump the MAC contents\n" 461bc15386SPeter Tyser " C : Copy the MAC address from the EEPROM to the MAC\n" 471bc15386SPeter Tyser " W : Write a register in the EEPROM or in the MAC\n" 481bc15386SPeter Tyser " Q : Quit\n" 491bc15386SPeter Tyser "\n" 501bc15386SPeter Tyser "Some commands take arguments:\n" 511bc15386SPeter Tyser " W <E|M> <register> <value>\n" 521bc15386SPeter Tyser " E: EEPROM M: MAC\n" 531bc15386SPeter Tyser ); 541bc15386SPeter Tyser } 551bc15386SPeter Tyser 561bc15386SPeter Tyser /** 571bc15386SPeter Tyser * dump_regs - dump the MAC registers 581bc15386SPeter Tyser * 591bc15386SPeter Tyser * Registers 0x00 - 0x50 are FIFOs. The 0x50+ are the control registers 601bc15386SPeter Tyser * and they're all 32bits long. 0xB8+ are reserved, so don't bother. 611bc15386SPeter Tyser */ 62*c44efcf9SMike Frysinger static void dump_regs(struct eth_device *dev) 631bc15386SPeter Tyser { 641bc15386SPeter Tyser u8 i, j = 0; 651bc15386SPeter Tyser for (i = 0x50; i < 0xB8; i += sizeof(u32)) 661bc15386SPeter Tyser printf("%02x: 0x%08x %c", i, 67*c44efcf9SMike Frysinger smc911x_reg_read(dev, i), 681bc15386SPeter Tyser (j++ % 2 ? '\n' : ' ')); 691bc15386SPeter Tyser } 701bc15386SPeter Tyser 711bc15386SPeter Tyser /** 721bc15386SPeter Tyser * do_eeprom_cmd - handle eeprom communication 731bc15386SPeter Tyser */ 74*c44efcf9SMike Frysinger static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg) 751bc15386SPeter Tyser { 76*c44efcf9SMike Frysinger if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) { 771bc15386SPeter Tyser printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", 78*c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 791bc15386SPeter Tyser return -1; 801bc15386SPeter Tyser } 811bc15386SPeter Tyser 82*c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); 831bc15386SPeter Tyser 84*c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 851bc15386SPeter Tyser if (smsc_ctrlc()) { 861bc15386SPeter Tyser printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", 87*c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 881bc15386SPeter Tyser return -1; 891bc15386SPeter Tyser } 901bc15386SPeter Tyser 911bc15386SPeter Tyser return 0; 921bc15386SPeter Tyser } 931bc15386SPeter Tyser 941bc15386SPeter Tyser /** 951bc15386SPeter Tyser * read_eeprom_reg - read specified register in EEPROM 961bc15386SPeter Tyser */ 97*c44efcf9SMike Frysinger static u8 read_eeprom_reg(struct eth_device *dev, u8 reg) 981bc15386SPeter Tyser { 99*c44efcf9SMike Frysinger int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg); 100*c44efcf9SMike Frysinger return (ret ? : smc911x_reg_read(dev, E2P_DATA)); 1011bc15386SPeter Tyser } 1021bc15386SPeter Tyser 1031bc15386SPeter Tyser /** 1041bc15386SPeter Tyser * write_eeprom_reg - write specified value into specified register in EEPROM 1051bc15386SPeter Tyser */ 106*c44efcf9SMike Frysinger static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg) 1071bc15386SPeter Tyser { 1081bc15386SPeter Tyser int ret; 1091bc15386SPeter Tyser 1101bc15386SPeter Tyser /* enable erasing/writing */ 111*c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg); 1121bc15386SPeter Tyser if (ret) 1131bc15386SPeter Tyser goto done; 1141bc15386SPeter Tyser 1151bc15386SPeter Tyser /* erase the eeprom reg */ 116*c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg); 1171bc15386SPeter Tyser if (ret) 1181bc15386SPeter Tyser goto done; 1191bc15386SPeter Tyser 1201bc15386SPeter Tyser /* write the eeprom reg */ 121*c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_DATA, value); 122*c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg); 1231bc15386SPeter Tyser if (ret) 1241bc15386SPeter Tyser goto done; 1251bc15386SPeter Tyser 1261bc15386SPeter Tyser /* disable erasing/writing */ 127*c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWDS, reg); 1281bc15386SPeter Tyser 1291bc15386SPeter Tyser done: 1301bc15386SPeter Tyser return ret; 1311bc15386SPeter Tyser } 1321bc15386SPeter Tyser 1331bc15386SPeter Tyser /** 1341bc15386SPeter Tyser * skip_space - find first non-whitespace in given pointer 1351bc15386SPeter Tyser */ 1361bc15386SPeter Tyser static char *skip_space(char *buf) 1371bc15386SPeter Tyser { 1381bc15386SPeter Tyser while (buf[0] == ' ' || buf[0] == '\t') 1391bc15386SPeter Tyser ++buf; 1401bc15386SPeter Tyser return buf; 1411bc15386SPeter Tyser } 1421bc15386SPeter Tyser 1431bc15386SPeter Tyser /** 1441bc15386SPeter Tyser * write_stuff - handle writing of MAC registers / eeprom 1451bc15386SPeter Tyser */ 146*c44efcf9SMike Frysinger static void write_stuff(struct eth_device *dev, char *line) 1471bc15386SPeter Tyser { 1481bc15386SPeter Tyser char dest; 1491bc15386SPeter Tyser char *endp; 1501bc15386SPeter Tyser u8 reg; 1511bc15386SPeter Tyser u32 value; 1521bc15386SPeter Tyser 1531bc15386SPeter Tyser /* Skip over the "W " part of the command */ 1541bc15386SPeter Tyser line = skip_space(line + 1); 1551bc15386SPeter Tyser 1561bc15386SPeter Tyser /* Figure out destination */ 1571bc15386SPeter Tyser switch (line[0]) { 1581bc15386SPeter Tyser case 'E': 1591bc15386SPeter Tyser case 'M': 1601bc15386SPeter Tyser dest = line[0]; 1611bc15386SPeter Tyser break; 1621bc15386SPeter Tyser default: 1631bc15386SPeter Tyser invalid_usage: 1641bc15386SPeter Tyser printf("ERROR: Invalid write usage\n"); 1651bc15386SPeter Tyser usage(); 1661bc15386SPeter Tyser return; 1671bc15386SPeter Tyser } 1681bc15386SPeter Tyser 1691bc15386SPeter Tyser /* Get the register to write */ 1701bc15386SPeter Tyser line = skip_space(line + 1); 1711bc15386SPeter Tyser reg = simple_strtoul(line, &endp, 16); 1721bc15386SPeter Tyser if (line == endp) 1731bc15386SPeter Tyser goto invalid_usage; 1741bc15386SPeter Tyser 1751bc15386SPeter Tyser /* Get the value to write */ 1761bc15386SPeter Tyser line = skip_space(endp); 1771bc15386SPeter Tyser value = simple_strtoul(line, &endp, 16); 1781bc15386SPeter Tyser if (line == endp) 1791bc15386SPeter Tyser goto invalid_usage; 1801bc15386SPeter Tyser 1811bc15386SPeter Tyser /* Check for trailing cruft */ 1821bc15386SPeter Tyser line = skip_space(endp); 1831bc15386SPeter Tyser if (line[0]) 1841bc15386SPeter Tyser goto invalid_usage; 1851bc15386SPeter Tyser 1861bc15386SPeter Tyser /* Finally, execute the command */ 1871bc15386SPeter Tyser if (dest == 'E') { 1881bc15386SPeter Tyser printf("Writing EEPROM register %02x with %02x\n", reg, value); 189*c44efcf9SMike Frysinger write_eeprom_reg(dev, value, reg); 1901bc15386SPeter Tyser } else { 1911bc15386SPeter Tyser printf("Writing MAC register %02x with %08x\n", reg, value); 192*c44efcf9SMike Frysinger smc911x_reg_write(dev, reg, value); 1931bc15386SPeter Tyser } 1941bc15386SPeter Tyser } 1951bc15386SPeter Tyser 1961bc15386SPeter Tyser /** 1971bc15386SPeter Tyser * copy_from_eeprom - copy MAC address in eeprom to address registers 1981bc15386SPeter Tyser */ 199*c44efcf9SMike Frysinger static void copy_from_eeprom(struct eth_device *dev) 2001bc15386SPeter Tyser { 2011bc15386SPeter Tyser ulong addrl = 202*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x01) | 203*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x02) << 8 | 204*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x03) << 16 | 205*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x04) << 24; 2061bc15386SPeter Tyser ulong addrh = 207*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x05) | 208*c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x06) << 8; 209*c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRL, addrl); 210*c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRH, addrh); 2111bc15386SPeter Tyser puts("EEPROM contents copied to MAC\n"); 2121bc15386SPeter Tyser } 2131bc15386SPeter Tyser 2141bc15386SPeter Tyser /** 2151bc15386SPeter Tyser * print_macaddr - print MAC address registers and MAC address in eeprom 2161bc15386SPeter Tyser */ 217*c44efcf9SMike Frysinger static void print_macaddr(struct eth_device *dev) 2181bc15386SPeter Tyser { 2191bc15386SPeter Tyser puts("Current MAC Address in MAC: "); 220*c44efcf9SMike Frysinger ulong addrl = smc911x_get_mac_csr(dev, ADDRL); 221*c44efcf9SMike Frysinger ulong addrh = smc911x_get_mac_csr(dev, ADDRH); 2221bc15386SPeter Tyser printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 2231bc15386SPeter Tyser (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16), 2241bc15386SPeter Tyser (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8)); 2251bc15386SPeter Tyser 2261bc15386SPeter Tyser puts("Current MAC Address in EEPROM: "); 2271bc15386SPeter Tyser int i; 2281bc15386SPeter Tyser for (i = 1; i < 6; ++i) 229*c44efcf9SMike Frysinger printf("%02x:", read_eeprom_reg(dev, i)); 230*c44efcf9SMike Frysinger printf("%02x\n", read_eeprom_reg(dev, i)); 2311bc15386SPeter Tyser } 2321bc15386SPeter Tyser 2331bc15386SPeter Tyser /** 2341bc15386SPeter Tyser * dump_eeprom - dump the whole content of the EEPROM 2351bc15386SPeter Tyser */ 236*c44efcf9SMike Frysinger static void dump_eeprom(struct eth_device *dev) 2371bc15386SPeter Tyser { 2381bc15386SPeter Tyser int i; 2391bc15386SPeter Tyser puts("EEPROM:\n"); 2401bc15386SPeter Tyser for (i = 0; i < 7; ++i) 241*c44efcf9SMike Frysinger printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i)); 2421bc15386SPeter Tyser } 2431bc15386SPeter Tyser 2441bc15386SPeter Tyser /** 2451bc15386SPeter Tyser * smc911x_init - get the MAC/EEPROM up and ready for use 2461bc15386SPeter Tyser */ 247*c44efcf9SMike Frysinger static int smc911x_init(struct eth_device *dev) 2481bc15386SPeter Tyser { 2491bc15386SPeter Tyser /* See if there is anything there */ 250*c44efcf9SMike Frysinger if (!smc911x_detect_chip(dev)) 2511bc15386SPeter Tyser return 1; 2521bc15386SPeter Tyser 253*c44efcf9SMike Frysinger smc911x_reset(dev); 2541bc15386SPeter Tyser 2551bc15386SPeter Tyser /* Make sure we set EEDIO/EECLK to the EEPROM */ 256*c44efcf9SMike Frysinger if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) { 257*c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 2581bc15386SPeter Tyser if (smsc_ctrlc()) { 2591bc15386SPeter Tyser printf("init: timeout (E2P_CMD = 0x%08x)\n", 260*c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 2611bc15386SPeter Tyser return 1; 2621bc15386SPeter Tyser } 263*c44efcf9SMike Frysinger smc911x_reg_write(dev, GPIO_CFG, 264*c44efcf9SMike Frysinger smc911x_reg_read(dev, GPIO_CFG) & ~GPIO_CFG_EEPR_EN); 2651bc15386SPeter Tyser } 2661bc15386SPeter Tyser 2671bc15386SPeter Tyser return 0; 2681bc15386SPeter Tyser } 2691bc15386SPeter Tyser 2701bc15386SPeter Tyser /** 2711bc15386SPeter Tyser * getline - consume a line of input and handle some escape sequences 2721bc15386SPeter Tyser */ 2731bc15386SPeter Tyser static char *getline(void) 2741bc15386SPeter Tyser { 2751bc15386SPeter Tyser static char buffer[100]; 2761bc15386SPeter Tyser char c; 2771bc15386SPeter Tyser size_t i; 2781bc15386SPeter Tyser 2791bc15386SPeter Tyser i = 0; 2801bc15386SPeter Tyser while (1) { 2811bc15386SPeter Tyser buffer[i] = '\0'; 2821bc15386SPeter Tyser while (!tstc()) 2831bc15386SPeter Tyser continue; 2841bc15386SPeter Tyser 2851bc15386SPeter Tyser c = getc(); 2861bc15386SPeter Tyser /* Convert to uppercase */ 2871bc15386SPeter Tyser if (c >= 'a' && c <= 'z') 2881bc15386SPeter Tyser c -= ('a' - 'A'); 2891bc15386SPeter Tyser 2901bc15386SPeter Tyser switch (c) { 2911bc15386SPeter Tyser case '\r': /* Enter/Return key */ 2921bc15386SPeter Tyser case '\n': 2931bc15386SPeter Tyser puts("\n"); 2941bc15386SPeter Tyser return buffer; 2951bc15386SPeter Tyser 2961bc15386SPeter Tyser case 0x03: /* ^C - break */ 2971bc15386SPeter Tyser return NULL; 2981bc15386SPeter Tyser 2991bc15386SPeter Tyser case 0x5F: 3001bc15386SPeter Tyser case 0x08: /* ^H - backspace */ 3011bc15386SPeter Tyser case 0x7F: /* DEL - backspace */ 3021bc15386SPeter Tyser if (i) { 3031bc15386SPeter Tyser puts("\b \b"); 3041bc15386SPeter Tyser i--; 3051bc15386SPeter Tyser } 3061bc15386SPeter Tyser break; 3071bc15386SPeter Tyser 3081bc15386SPeter Tyser default: 3091bc15386SPeter Tyser /* Ignore control characters */ 3101bc15386SPeter Tyser if (c < 0x20) 3111bc15386SPeter Tyser break; 3121bc15386SPeter Tyser /* Queue up all other characters */ 3131bc15386SPeter Tyser buffer[i++] = c; 3141bc15386SPeter Tyser printf("%c", c); 3151bc15386SPeter Tyser break; 3161bc15386SPeter Tyser } 3171bc15386SPeter Tyser } 3181bc15386SPeter Tyser } 3191bc15386SPeter Tyser 3201bc15386SPeter Tyser /** 3211bc15386SPeter Tyser * smc911x_eeprom - our application's main() function 3221bc15386SPeter Tyser */ 3231bc15386SPeter Tyser int smc911x_eeprom(int argc, char *argv[]) 3241bc15386SPeter Tyser { 325*c44efcf9SMike Frysinger /* Avoid initializing on stack as gcc likes to call memset() */ 326*c44efcf9SMike Frysinger struct eth_device dev; 327*c44efcf9SMike Frysinger dev.name = __func__; 328*c44efcf9SMike Frysinger dev.iobase = CONFIG_SMC911X_BASE; 329*c44efcf9SMike Frysinger 3301bc15386SPeter Tyser /* Print the ABI version */ 3311bc15386SPeter Tyser app_startup(argv); 3321bc15386SPeter Tyser if (XF_VERSION != get_version()) { 3331bc15386SPeter Tyser printf("Expects ABI version %d\n", XF_VERSION); 3341bc15386SPeter Tyser printf("Actual U-Boot ABI version %lu\n", get_version()); 3351bc15386SPeter Tyser printf("Can't run\n\n"); 3361bc15386SPeter Tyser return 1; 3371bc15386SPeter Tyser } 3381bc15386SPeter Tyser 3391bc15386SPeter Tyser /* Initialize the MAC/EEPROM somewhat */ 3401bc15386SPeter Tyser puts("\n"); 341*c44efcf9SMike Frysinger if (smc911x_init(&dev)) 3421bc15386SPeter Tyser return 1; 3431bc15386SPeter Tyser 3441bc15386SPeter Tyser /* Dump helpful usage information */ 3451bc15386SPeter Tyser puts("\n"); 3461bc15386SPeter Tyser usage(); 3471bc15386SPeter Tyser puts("\n"); 3481bc15386SPeter Tyser 3491bc15386SPeter Tyser while (1) { 3501bc15386SPeter Tyser char *line; 3511bc15386SPeter Tyser 3521bc15386SPeter Tyser /* Send the prompt and wait for a line */ 3531bc15386SPeter Tyser puts("eeprom> "); 3541bc15386SPeter Tyser line = getline(); 3551bc15386SPeter Tyser 3561bc15386SPeter Tyser /* Got a ctrl+c */ 3571bc15386SPeter Tyser if (!line) 3581bc15386SPeter Tyser return 0; 3591bc15386SPeter Tyser 3601bc15386SPeter Tyser /* Eat leading space */ 3611bc15386SPeter Tyser line = skip_space(line); 3621bc15386SPeter Tyser 3631bc15386SPeter Tyser /* Empty line, try again */ 3641bc15386SPeter Tyser if (!line[0]) 3651bc15386SPeter Tyser continue; 3661bc15386SPeter Tyser 3671bc15386SPeter Tyser /* Only accept 1 letter commands */ 3681bc15386SPeter Tyser if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t') 3691bc15386SPeter Tyser goto unknown_cmd; 3701bc15386SPeter Tyser 3711bc15386SPeter Tyser /* Now parse the command */ 3721bc15386SPeter Tyser switch (line[0]) { 373*c44efcf9SMike Frysinger case 'W': write_stuff(&dev, line); break; 374*c44efcf9SMike Frysinger case 'D': dump_eeprom(&dev); break; 375*c44efcf9SMike Frysinger case 'M': dump_regs(&dev); break; 376*c44efcf9SMike Frysinger case 'C': copy_from_eeprom(&dev); break; 377*c44efcf9SMike Frysinger case 'P': print_macaddr(&dev); break; 3781bc15386SPeter Tyser unknown_cmd: 3791bc15386SPeter Tyser default: puts("ERROR: Unknown command!\n\n"); 3801bc15386SPeter Tyser case '?': 3811bc15386SPeter Tyser case 'H': usage(); break; 3821bc15386SPeter Tyser case 'Q': return 0; 3831bc15386SPeter Tyser } 3841bc15386SPeter Tyser } 3851bc15386SPeter Tyser } 386