11bc15386SPeter Tyser /* 21bc15386SPeter Tyser * smc911x_eeprom.c - EEPROM interface to SMC911x parts. 31bc15386SPeter Tyser * Only tested on SMSC9118 though ... 41bc15386SPeter Tyser * 5c44efcf9SMike 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 #include "../drivers/net/smc911x.h" 201bc15386SPeter Tyser 211bc15386SPeter Tyser /** 221bc15386SPeter Tyser * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) 231bc15386SPeter Tyser */ 241bc15386SPeter Tyser static int smsc_ctrlc(void) 251bc15386SPeter Tyser { 261bc15386SPeter Tyser return (tstc() && getc() == 0x03); 271bc15386SPeter Tyser } 281bc15386SPeter Tyser 291bc15386SPeter Tyser /** 301bc15386SPeter Tyser * usage - dump usage information 311bc15386SPeter Tyser */ 321bc15386SPeter Tyser static void usage(void) 331bc15386SPeter Tyser { 341bc15386SPeter Tyser puts( 351bc15386SPeter Tyser "MAC/EEPROM Commands:\n" 361bc15386SPeter Tyser " P : Print the MAC addresses\n" 371bc15386SPeter Tyser " D : Dump the EEPROM contents\n" 381bc15386SPeter Tyser " M : Dump the MAC contents\n" 391bc15386SPeter Tyser " C : Copy the MAC address from the EEPROM to the MAC\n" 401bc15386SPeter Tyser " W : Write a register in the EEPROM or in the MAC\n" 411bc15386SPeter Tyser " Q : Quit\n" 421bc15386SPeter Tyser "\n" 431bc15386SPeter Tyser "Some commands take arguments:\n" 441bc15386SPeter Tyser " W <E|M> <register> <value>\n" 451bc15386SPeter Tyser " E: EEPROM M: MAC\n" 461bc15386SPeter Tyser ); 471bc15386SPeter Tyser } 481bc15386SPeter Tyser 491bc15386SPeter Tyser /** 501bc15386SPeter Tyser * dump_regs - dump the MAC registers 511bc15386SPeter Tyser * 521bc15386SPeter Tyser * Registers 0x00 - 0x50 are FIFOs. The 0x50+ are the control registers 531bc15386SPeter Tyser * and they're all 32bits long. 0xB8+ are reserved, so don't bother. 541bc15386SPeter Tyser */ 55c44efcf9SMike Frysinger static void dump_regs(struct eth_device *dev) 561bc15386SPeter Tyser { 571bc15386SPeter Tyser u8 i, j = 0; 581bc15386SPeter Tyser for (i = 0x50; i < 0xB8; i += sizeof(u32)) 591bc15386SPeter Tyser printf("%02x: 0x%08x %c", i, 60c44efcf9SMike Frysinger smc911x_reg_read(dev, i), 611bc15386SPeter Tyser (j++ % 2 ? '\n' : ' ')); 621bc15386SPeter Tyser } 631bc15386SPeter Tyser 641bc15386SPeter Tyser /** 651bc15386SPeter Tyser * do_eeprom_cmd - handle eeprom communication 661bc15386SPeter Tyser */ 67c44efcf9SMike Frysinger static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg) 681bc15386SPeter Tyser { 69c44efcf9SMike Frysinger if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) { 701bc15386SPeter Tyser printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", 71c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 721bc15386SPeter Tyser return -1; 731bc15386SPeter Tyser } 741bc15386SPeter Tyser 75c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); 761bc15386SPeter Tyser 77c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 781bc15386SPeter Tyser if (smsc_ctrlc()) { 791bc15386SPeter Tyser printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", 80c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 811bc15386SPeter Tyser return -1; 821bc15386SPeter Tyser } 831bc15386SPeter Tyser 841bc15386SPeter Tyser return 0; 851bc15386SPeter Tyser } 861bc15386SPeter Tyser 871bc15386SPeter Tyser /** 881bc15386SPeter Tyser * read_eeprom_reg - read specified register in EEPROM 891bc15386SPeter Tyser */ 90c44efcf9SMike Frysinger static u8 read_eeprom_reg(struct eth_device *dev, u8 reg) 911bc15386SPeter Tyser { 92c44efcf9SMike Frysinger int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg); 93c44efcf9SMike Frysinger return (ret ? : smc911x_reg_read(dev, E2P_DATA)); 941bc15386SPeter Tyser } 951bc15386SPeter Tyser 961bc15386SPeter Tyser /** 971bc15386SPeter Tyser * write_eeprom_reg - write specified value into specified register in EEPROM 981bc15386SPeter Tyser */ 99c44efcf9SMike Frysinger static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg) 1001bc15386SPeter Tyser { 1011bc15386SPeter Tyser int ret; 1021bc15386SPeter Tyser 1031bc15386SPeter Tyser /* enable erasing/writing */ 104c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg); 1051bc15386SPeter Tyser if (ret) 1061bc15386SPeter Tyser goto done; 1071bc15386SPeter Tyser 1081bc15386SPeter Tyser /* erase the eeprom reg */ 109c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg); 1101bc15386SPeter Tyser if (ret) 1111bc15386SPeter Tyser goto done; 1121bc15386SPeter Tyser 1131bc15386SPeter Tyser /* write the eeprom reg */ 114c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_DATA, value); 115c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg); 1161bc15386SPeter Tyser if (ret) 1171bc15386SPeter Tyser goto done; 1181bc15386SPeter Tyser 1191bc15386SPeter Tyser /* disable erasing/writing */ 120c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWDS, reg); 1211bc15386SPeter Tyser 1221bc15386SPeter Tyser done: 1231bc15386SPeter Tyser return ret; 1241bc15386SPeter Tyser } 1251bc15386SPeter Tyser 1261bc15386SPeter Tyser /** 1271bc15386SPeter Tyser * skip_space - find first non-whitespace in given pointer 1281bc15386SPeter Tyser */ 1291bc15386SPeter Tyser static char *skip_space(char *buf) 1301bc15386SPeter Tyser { 1311bc15386SPeter Tyser while (buf[0] == ' ' || buf[0] == '\t') 1321bc15386SPeter Tyser ++buf; 1331bc15386SPeter Tyser return buf; 1341bc15386SPeter Tyser } 1351bc15386SPeter Tyser 1361bc15386SPeter Tyser /** 1371bc15386SPeter Tyser * write_stuff - handle writing of MAC registers / eeprom 1381bc15386SPeter Tyser */ 139c44efcf9SMike Frysinger static void write_stuff(struct eth_device *dev, char *line) 1401bc15386SPeter Tyser { 1411bc15386SPeter Tyser char dest; 1421bc15386SPeter Tyser char *endp; 1431bc15386SPeter Tyser u8 reg; 1441bc15386SPeter Tyser u32 value; 1451bc15386SPeter Tyser 1461bc15386SPeter Tyser /* Skip over the "W " part of the command */ 1471bc15386SPeter Tyser line = skip_space(line + 1); 1481bc15386SPeter Tyser 1491bc15386SPeter Tyser /* Figure out destination */ 1501bc15386SPeter Tyser switch (line[0]) { 1511bc15386SPeter Tyser case 'E': 1521bc15386SPeter Tyser case 'M': 1531bc15386SPeter Tyser dest = line[0]; 1541bc15386SPeter Tyser break; 1551bc15386SPeter Tyser default: 1561bc15386SPeter Tyser invalid_usage: 1571bc15386SPeter Tyser printf("ERROR: Invalid write usage\n"); 1581bc15386SPeter Tyser usage(); 1591bc15386SPeter Tyser return; 1601bc15386SPeter Tyser } 1611bc15386SPeter Tyser 1621bc15386SPeter Tyser /* Get the register to write */ 1631bc15386SPeter Tyser line = skip_space(line + 1); 1641bc15386SPeter Tyser reg = simple_strtoul(line, &endp, 16); 1651bc15386SPeter Tyser if (line == endp) 1661bc15386SPeter Tyser goto invalid_usage; 1671bc15386SPeter Tyser 1681bc15386SPeter Tyser /* Get the value to write */ 1691bc15386SPeter Tyser line = skip_space(endp); 1701bc15386SPeter Tyser value = simple_strtoul(line, &endp, 16); 1711bc15386SPeter Tyser if (line == endp) 1721bc15386SPeter Tyser goto invalid_usage; 1731bc15386SPeter Tyser 1741bc15386SPeter Tyser /* Check for trailing cruft */ 1751bc15386SPeter Tyser line = skip_space(endp); 1761bc15386SPeter Tyser if (line[0]) 1771bc15386SPeter Tyser goto invalid_usage; 1781bc15386SPeter Tyser 1791bc15386SPeter Tyser /* Finally, execute the command */ 1801bc15386SPeter Tyser if (dest == 'E') { 1811bc15386SPeter Tyser printf("Writing EEPROM register %02x with %02x\n", reg, value); 182c44efcf9SMike Frysinger write_eeprom_reg(dev, value, reg); 1831bc15386SPeter Tyser } else { 1841bc15386SPeter Tyser printf("Writing MAC register %02x with %08x\n", reg, value); 185c44efcf9SMike Frysinger smc911x_reg_write(dev, reg, value); 1861bc15386SPeter Tyser } 1871bc15386SPeter Tyser } 1881bc15386SPeter Tyser 1891bc15386SPeter Tyser /** 1901bc15386SPeter Tyser * copy_from_eeprom - copy MAC address in eeprom to address registers 1911bc15386SPeter Tyser */ 192c44efcf9SMike Frysinger static void copy_from_eeprom(struct eth_device *dev) 1931bc15386SPeter Tyser { 1941bc15386SPeter Tyser ulong addrl = 195c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x01) | 196c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x02) << 8 | 197c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x03) << 16 | 198c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x04) << 24; 1991bc15386SPeter Tyser ulong addrh = 200c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x05) | 201c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x06) << 8; 202c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRL, addrl); 203c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRH, addrh); 2041bc15386SPeter Tyser puts("EEPROM contents copied to MAC\n"); 2051bc15386SPeter Tyser } 2061bc15386SPeter Tyser 2071bc15386SPeter Tyser /** 2081bc15386SPeter Tyser * print_macaddr - print MAC address registers and MAC address in eeprom 2091bc15386SPeter Tyser */ 210c44efcf9SMike Frysinger static void print_macaddr(struct eth_device *dev) 2111bc15386SPeter Tyser { 2121bc15386SPeter Tyser puts("Current MAC Address in MAC: "); 213c44efcf9SMike Frysinger ulong addrl = smc911x_get_mac_csr(dev, ADDRL); 214c44efcf9SMike Frysinger ulong addrh = smc911x_get_mac_csr(dev, ADDRH); 2151bc15386SPeter Tyser printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 2161bc15386SPeter Tyser (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16), 2171bc15386SPeter Tyser (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8)); 2181bc15386SPeter Tyser 2191bc15386SPeter Tyser puts("Current MAC Address in EEPROM: "); 2201bc15386SPeter Tyser int i; 2211bc15386SPeter Tyser for (i = 1; i < 6; ++i) 222c44efcf9SMike Frysinger printf("%02x:", read_eeprom_reg(dev, i)); 223c44efcf9SMike Frysinger printf("%02x\n", read_eeprom_reg(dev, i)); 2241bc15386SPeter Tyser } 2251bc15386SPeter Tyser 2261bc15386SPeter Tyser /** 2271bc15386SPeter Tyser * dump_eeprom - dump the whole content of the EEPROM 2281bc15386SPeter Tyser */ 229c44efcf9SMike Frysinger static void dump_eeprom(struct eth_device *dev) 2301bc15386SPeter Tyser { 2311bc15386SPeter Tyser int i; 2321bc15386SPeter Tyser puts("EEPROM:\n"); 2331bc15386SPeter Tyser for (i = 0; i < 7; ++i) 234c44efcf9SMike Frysinger printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i)); 2351bc15386SPeter Tyser } 2361bc15386SPeter Tyser 2371bc15386SPeter Tyser /** 2381bc15386SPeter Tyser * smc911x_init - get the MAC/EEPROM up and ready for use 2391bc15386SPeter Tyser */ 240c44efcf9SMike Frysinger static int smc911x_init(struct eth_device *dev) 2411bc15386SPeter Tyser { 2421bc15386SPeter Tyser /* See if there is anything there */ 243*aa9fba53SJuergen Kilb if (smc911x_detect_chip(dev)) 2441bc15386SPeter Tyser return 1; 2451bc15386SPeter Tyser 246c44efcf9SMike Frysinger smc911x_reset(dev); 2471bc15386SPeter Tyser 2481bc15386SPeter Tyser /* Make sure we set EEDIO/EECLK to the EEPROM */ 249c44efcf9SMike Frysinger if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) { 250c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 2511bc15386SPeter Tyser if (smsc_ctrlc()) { 2521bc15386SPeter Tyser printf("init: timeout (E2P_CMD = 0x%08x)\n", 253c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 2541bc15386SPeter Tyser return 1; 2551bc15386SPeter Tyser } 256c44efcf9SMike Frysinger smc911x_reg_write(dev, GPIO_CFG, 257c44efcf9SMike Frysinger smc911x_reg_read(dev, GPIO_CFG) & ~GPIO_CFG_EEPR_EN); 2581bc15386SPeter Tyser } 2591bc15386SPeter Tyser 2601bc15386SPeter Tyser return 0; 2611bc15386SPeter Tyser } 2621bc15386SPeter Tyser 2631bc15386SPeter Tyser /** 2641bc15386SPeter Tyser * getline - consume a line of input and handle some escape sequences 2651bc15386SPeter Tyser */ 2661bc15386SPeter Tyser static char *getline(void) 2671bc15386SPeter Tyser { 2681bc15386SPeter Tyser static char buffer[100]; 2691bc15386SPeter Tyser char c; 2701bc15386SPeter Tyser size_t i; 2711bc15386SPeter Tyser 2721bc15386SPeter Tyser i = 0; 2731bc15386SPeter Tyser while (1) { 2741bc15386SPeter Tyser buffer[i] = '\0'; 2751bc15386SPeter Tyser while (!tstc()) 2761bc15386SPeter Tyser continue; 2771bc15386SPeter Tyser 2781bc15386SPeter Tyser c = getc(); 2791bc15386SPeter Tyser /* Convert to uppercase */ 2801bc15386SPeter Tyser if (c >= 'a' && c <= 'z') 2811bc15386SPeter Tyser c -= ('a' - 'A'); 2821bc15386SPeter Tyser 2831bc15386SPeter Tyser switch (c) { 2841bc15386SPeter Tyser case '\r': /* Enter/Return key */ 2851bc15386SPeter Tyser case '\n': 2861bc15386SPeter Tyser puts("\n"); 2871bc15386SPeter Tyser return buffer; 2881bc15386SPeter Tyser 2891bc15386SPeter Tyser case 0x03: /* ^C - break */ 2901bc15386SPeter Tyser return NULL; 2911bc15386SPeter Tyser 2921bc15386SPeter Tyser case 0x5F: 2931bc15386SPeter Tyser case 0x08: /* ^H - backspace */ 2941bc15386SPeter Tyser case 0x7F: /* DEL - backspace */ 2951bc15386SPeter Tyser if (i) { 2961bc15386SPeter Tyser puts("\b \b"); 2971bc15386SPeter Tyser i--; 2981bc15386SPeter Tyser } 2991bc15386SPeter Tyser break; 3001bc15386SPeter Tyser 3011bc15386SPeter Tyser default: 3021bc15386SPeter Tyser /* Ignore control characters */ 3031bc15386SPeter Tyser if (c < 0x20) 3041bc15386SPeter Tyser break; 3051bc15386SPeter Tyser /* Queue up all other characters */ 3061bc15386SPeter Tyser buffer[i++] = c; 3071bc15386SPeter Tyser printf("%c", c); 3081bc15386SPeter Tyser break; 3091bc15386SPeter Tyser } 3101bc15386SPeter Tyser } 3111bc15386SPeter Tyser } 3121bc15386SPeter Tyser 3131bc15386SPeter Tyser /** 3141bc15386SPeter Tyser * smc911x_eeprom - our application's main() function 3151bc15386SPeter Tyser */ 31654841ab5SWolfgang Denk int smc911x_eeprom(int argc, char * const argv[]) 3171bc15386SPeter Tyser { 318c44efcf9SMike Frysinger /* Avoid initializing on stack as gcc likes to call memset() */ 319c44efcf9SMike Frysinger struct eth_device dev; 320c44efcf9SMike Frysinger dev.iobase = CONFIG_SMC911X_BASE; 321c44efcf9SMike Frysinger 3221bc15386SPeter Tyser /* Print the ABI version */ 3231bc15386SPeter Tyser app_startup(argv); 3241bc15386SPeter Tyser if (XF_VERSION != get_version()) { 3251bc15386SPeter Tyser printf("Expects ABI version %d\n", XF_VERSION); 3261bc15386SPeter Tyser printf("Actual U-Boot ABI version %lu\n", get_version()); 3271bc15386SPeter Tyser printf("Can't run\n\n"); 3281bc15386SPeter Tyser return 1; 3291bc15386SPeter Tyser } 3301bc15386SPeter Tyser 3311bc15386SPeter Tyser /* Initialize the MAC/EEPROM somewhat */ 3321bc15386SPeter Tyser puts("\n"); 333c44efcf9SMike Frysinger if (smc911x_init(&dev)) 3341bc15386SPeter Tyser return 1; 3351bc15386SPeter Tyser 3361bc15386SPeter Tyser /* Dump helpful usage information */ 3371bc15386SPeter Tyser puts("\n"); 3381bc15386SPeter Tyser usage(); 3391bc15386SPeter Tyser puts("\n"); 3401bc15386SPeter Tyser 3411bc15386SPeter Tyser while (1) { 3421bc15386SPeter Tyser char *line; 3431bc15386SPeter Tyser 3441bc15386SPeter Tyser /* Send the prompt and wait for a line */ 3451bc15386SPeter Tyser puts("eeprom> "); 3461bc15386SPeter Tyser line = getline(); 3471bc15386SPeter Tyser 3481bc15386SPeter Tyser /* Got a ctrl+c */ 3491bc15386SPeter Tyser if (!line) 3501bc15386SPeter Tyser return 0; 3511bc15386SPeter Tyser 3521bc15386SPeter Tyser /* Eat leading space */ 3531bc15386SPeter Tyser line = skip_space(line); 3541bc15386SPeter Tyser 3551bc15386SPeter Tyser /* Empty line, try again */ 3561bc15386SPeter Tyser if (!line[0]) 3571bc15386SPeter Tyser continue; 3581bc15386SPeter Tyser 3591bc15386SPeter Tyser /* Only accept 1 letter commands */ 3601bc15386SPeter Tyser if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t') 3611bc15386SPeter Tyser goto unknown_cmd; 3621bc15386SPeter Tyser 3631bc15386SPeter Tyser /* Now parse the command */ 3641bc15386SPeter Tyser switch (line[0]) { 365c44efcf9SMike Frysinger case 'W': write_stuff(&dev, line); break; 366c44efcf9SMike Frysinger case 'D': dump_eeprom(&dev); break; 367c44efcf9SMike Frysinger case 'M': dump_regs(&dev); break; 368c44efcf9SMike Frysinger case 'C': copy_from_eeprom(&dev); break; 369c44efcf9SMike Frysinger case 'P': print_macaddr(&dev); break; 3701bc15386SPeter Tyser unknown_cmd: 3711bc15386SPeter Tyser default: puts("ERROR: Unknown command!\n\n"); 3721bc15386SPeter Tyser case '?': 3731bc15386SPeter Tyser case 'H': usage(); break; 3741bc15386SPeter Tyser case 'Q': return 0; 3751bc15386SPeter Tyser } 3761bc15386SPeter Tyser } 3771bc15386SPeter Tyser } 378