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> 19*4d91a6ecSJason Hobbs #include <linux/ctype.h> 201bc15386SPeter Tyser #include "../drivers/net/smc911x.h" 211bc15386SPeter Tyser 221bc15386SPeter Tyser /** 231bc15386SPeter Tyser * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) 241bc15386SPeter Tyser */ 251bc15386SPeter Tyser static int smsc_ctrlc(void) 261bc15386SPeter Tyser { 271bc15386SPeter Tyser return (tstc() && getc() == 0x03); 281bc15386SPeter Tyser } 291bc15386SPeter Tyser 301bc15386SPeter Tyser /** 311bc15386SPeter Tyser * usage - dump usage information 321bc15386SPeter Tyser */ 331bc15386SPeter Tyser static void usage(void) 341bc15386SPeter Tyser { 351bc15386SPeter Tyser puts( 361bc15386SPeter Tyser "MAC/EEPROM Commands:\n" 371bc15386SPeter Tyser " P : Print the MAC addresses\n" 381bc15386SPeter Tyser " D : Dump the EEPROM contents\n" 391bc15386SPeter Tyser " M : Dump the MAC contents\n" 401bc15386SPeter Tyser " C : Copy the MAC address from the EEPROM to the MAC\n" 411bc15386SPeter Tyser " W : Write a register in the EEPROM or in the MAC\n" 421bc15386SPeter Tyser " Q : Quit\n" 431bc15386SPeter Tyser "\n" 441bc15386SPeter Tyser "Some commands take arguments:\n" 451bc15386SPeter Tyser " W <E|M> <register> <value>\n" 461bc15386SPeter Tyser " E: EEPROM M: MAC\n" 471bc15386SPeter Tyser ); 481bc15386SPeter Tyser } 491bc15386SPeter Tyser 501bc15386SPeter Tyser /** 511bc15386SPeter Tyser * dump_regs - dump the MAC registers 521bc15386SPeter Tyser * 531bc15386SPeter Tyser * Registers 0x00 - 0x50 are FIFOs. The 0x50+ are the control registers 541bc15386SPeter Tyser * and they're all 32bits long. 0xB8+ are reserved, so don't bother. 551bc15386SPeter Tyser */ 56c44efcf9SMike Frysinger static void dump_regs(struct eth_device *dev) 571bc15386SPeter Tyser { 581bc15386SPeter Tyser u8 i, j = 0; 591bc15386SPeter Tyser for (i = 0x50; i < 0xB8; i += sizeof(u32)) 601bc15386SPeter Tyser printf("%02x: 0x%08x %c", i, 61c44efcf9SMike Frysinger smc911x_reg_read(dev, i), 621bc15386SPeter Tyser (j++ % 2 ? '\n' : ' ')); 631bc15386SPeter Tyser } 641bc15386SPeter Tyser 651bc15386SPeter Tyser /** 661bc15386SPeter Tyser * do_eeprom_cmd - handle eeprom communication 671bc15386SPeter Tyser */ 68c44efcf9SMike Frysinger static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg) 691bc15386SPeter Tyser { 70c44efcf9SMike Frysinger if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) { 711bc15386SPeter Tyser printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", 72c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 731bc15386SPeter Tyser return -1; 741bc15386SPeter Tyser } 751bc15386SPeter Tyser 76c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); 771bc15386SPeter Tyser 78c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 791bc15386SPeter Tyser if (smsc_ctrlc()) { 801bc15386SPeter Tyser printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", 81c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 821bc15386SPeter Tyser return -1; 831bc15386SPeter Tyser } 841bc15386SPeter Tyser 851bc15386SPeter Tyser return 0; 861bc15386SPeter Tyser } 871bc15386SPeter Tyser 881bc15386SPeter Tyser /** 891bc15386SPeter Tyser * read_eeprom_reg - read specified register in EEPROM 901bc15386SPeter Tyser */ 91c44efcf9SMike Frysinger static u8 read_eeprom_reg(struct eth_device *dev, u8 reg) 921bc15386SPeter Tyser { 93c44efcf9SMike Frysinger int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg); 94c44efcf9SMike Frysinger return (ret ? : smc911x_reg_read(dev, E2P_DATA)); 951bc15386SPeter Tyser } 961bc15386SPeter Tyser 971bc15386SPeter Tyser /** 981bc15386SPeter Tyser * write_eeprom_reg - write specified value into specified register in EEPROM 991bc15386SPeter Tyser */ 100c44efcf9SMike Frysinger static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg) 1011bc15386SPeter Tyser { 1021bc15386SPeter Tyser int ret; 1031bc15386SPeter Tyser 1041bc15386SPeter Tyser /* enable erasing/writing */ 105c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg); 1061bc15386SPeter Tyser if (ret) 1071bc15386SPeter Tyser goto done; 1081bc15386SPeter Tyser 1091bc15386SPeter Tyser /* erase the eeprom reg */ 110c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg); 1111bc15386SPeter Tyser if (ret) 1121bc15386SPeter Tyser goto done; 1131bc15386SPeter Tyser 1141bc15386SPeter Tyser /* write the eeprom reg */ 115c44efcf9SMike Frysinger smc911x_reg_write(dev, E2P_DATA, value); 116c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg); 1171bc15386SPeter Tyser if (ret) 1181bc15386SPeter Tyser goto done; 1191bc15386SPeter Tyser 1201bc15386SPeter Tyser /* disable erasing/writing */ 121c44efcf9SMike Frysinger ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWDS, reg); 1221bc15386SPeter Tyser 1231bc15386SPeter Tyser done: 1241bc15386SPeter Tyser return ret; 1251bc15386SPeter Tyser } 1261bc15386SPeter Tyser 1271bc15386SPeter Tyser /** 1281bc15386SPeter Tyser * skip_space - find first non-whitespace in given pointer 1291bc15386SPeter Tyser */ 1301bc15386SPeter Tyser static char *skip_space(char *buf) 1311bc15386SPeter Tyser { 132*4d91a6ecSJason Hobbs while (isblank(buf[0])) 1331bc15386SPeter Tyser ++buf; 1341bc15386SPeter Tyser return buf; 1351bc15386SPeter Tyser } 1361bc15386SPeter Tyser 1371bc15386SPeter Tyser /** 1381bc15386SPeter Tyser * write_stuff - handle writing of MAC registers / eeprom 1391bc15386SPeter Tyser */ 140c44efcf9SMike Frysinger static void write_stuff(struct eth_device *dev, char *line) 1411bc15386SPeter Tyser { 1421bc15386SPeter Tyser char dest; 1431bc15386SPeter Tyser char *endp; 1441bc15386SPeter Tyser u8 reg; 1451bc15386SPeter Tyser u32 value; 1461bc15386SPeter Tyser 1471bc15386SPeter Tyser /* Skip over the "W " part of the command */ 1481bc15386SPeter Tyser line = skip_space(line + 1); 1491bc15386SPeter Tyser 1501bc15386SPeter Tyser /* Figure out destination */ 1511bc15386SPeter Tyser switch (line[0]) { 1521bc15386SPeter Tyser case 'E': 1531bc15386SPeter Tyser case 'M': 1541bc15386SPeter Tyser dest = line[0]; 1551bc15386SPeter Tyser break; 1561bc15386SPeter Tyser default: 1571bc15386SPeter Tyser invalid_usage: 1581bc15386SPeter Tyser printf("ERROR: Invalid write usage\n"); 1591bc15386SPeter Tyser usage(); 1601bc15386SPeter Tyser return; 1611bc15386SPeter Tyser } 1621bc15386SPeter Tyser 1631bc15386SPeter Tyser /* Get the register to write */ 1641bc15386SPeter Tyser line = skip_space(line + 1); 1651bc15386SPeter Tyser reg = simple_strtoul(line, &endp, 16); 1661bc15386SPeter Tyser if (line == endp) 1671bc15386SPeter Tyser goto invalid_usage; 1681bc15386SPeter Tyser 1691bc15386SPeter Tyser /* Get the value to write */ 1701bc15386SPeter Tyser line = skip_space(endp); 1711bc15386SPeter Tyser value = simple_strtoul(line, &endp, 16); 1721bc15386SPeter Tyser if (line == endp) 1731bc15386SPeter Tyser goto invalid_usage; 1741bc15386SPeter Tyser 1751bc15386SPeter Tyser /* Check for trailing cruft */ 1761bc15386SPeter Tyser line = skip_space(endp); 1771bc15386SPeter Tyser if (line[0]) 1781bc15386SPeter Tyser goto invalid_usage; 1791bc15386SPeter Tyser 1801bc15386SPeter Tyser /* Finally, execute the command */ 1811bc15386SPeter Tyser if (dest == 'E') { 1821bc15386SPeter Tyser printf("Writing EEPROM register %02x with %02x\n", reg, value); 183c44efcf9SMike Frysinger write_eeprom_reg(dev, value, reg); 1841bc15386SPeter Tyser } else { 1851bc15386SPeter Tyser printf("Writing MAC register %02x with %08x\n", reg, value); 186c44efcf9SMike Frysinger smc911x_reg_write(dev, reg, value); 1871bc15386SPeter Tyser } 1881bc15386SPeter Tyser } 1891bc15386SPeter Tyser 1901bc15386SPeter Tyser /** 1911bc15386SPeter Tyser * copy_from_eeprom - copy MAC address in eeprom to address registers 1921bc15386SPeter Tyser */ 193c44efcf9SMike Frysinger static void copy_from_eeprom(struct eth_device *dev) 1941bc15386SPeter Tyser { 1951bc15386SPeter Tyser ulong addrl = 196c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x01) | 197c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x02) << 8 | 198c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x03) << 16 | 199c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x04) << 24; 2001bc15386SPeter Tyser ulong addrh = 201c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x05) | 202c44efcf9SMike Frysinger read_eeprom_reg(dev, 0x06) << 8; 203c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRL, addrl); 204c44efcf9SMike Frysinger smc911x_set_mac_csr(dev, ADDRH, addrh); 2051bc15386SPeter Tyser puts("EEPROM contents copied to MAC\n"); 2061bc15386SPeter Tyser } 2071bc15386SPeter Tyser 2081bc15386SPeter Tyser /** 2091bc15386SPeter Tyser * print_macaddr - print MAC address registers and MAC address in eeprom 2101bc15386SPeter Tyser */ 211c44efcf9SMike Frysinger static void print_macaddr(struct eth_device *dev) 2121bc15386SPeter Tyser { 2131bc15386SPeter Tyser puts("Current MAC Address in MAC: "); 214c44efcf9SMike Frysinger ulong addrl = smc911x_get_mac_csr(dev, ADDRL); 215c44efcf9SMike Frysinger ulong addrh = smc911x_get_mac_csr(dev, ADDRH); 2161bc15386SPeter Tyser printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 2171bc15386SPeter Tyser (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16), 2181bc15386SPeter Tyser (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8)); 2191bc15386SPeter Tyser 2201bc15386SPeter Tyser puts("Current MAC Address in EEPROM: "); 2211bc15386SPeter Tyser int i; 2221bc15386SPeter Tyser for (i = 1; i < 6; ++i) 223c44efcf9SMike Frysinger printf("%02x:", read_eeprom_reg(dev, i)); 224c44efcf9SMike Frysinger printf("%02x\n", read_eeprom_reg(dev, i)); 2251bc15386SPeter Tyser } 2261bc15386SPeter Tyser 2271bc15386SPeter Tyser /** 2281bc15386SPeter Tyser * dump_eeprom - dump the whole content of the EEPROM 2291bc15386SPeter Tyser */ 230c44efcf9SMike Frysinger static void dump_eeprom(struct eth_device *dev) 2311bc15386SPeter Tyser { 2321bc15386SPeter Tyser int i; 2331bc15386SPeter Tyser puts("EEPROM:\n"); 2341bc15386SPeter Tyser for (i = 0; i < 7; ++i) 235c44efcf9SMike Frysinger printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i)); 2361bc15386SPeter Tyser } 2371bc15386SPeter Tyser 2381bc15386SPeter Tyser /** 2391bc15386SPeter Tyser * smc911x_init - get the MAC/EEPROM up and ready for use 2401bc15386SPeter Tyser */ 241c44efcf9SMike Frysinger static int smc911x_init(struct eth_device *dev) 2421bc15386SPeter Tyser { 2431bc15386SPeter Tyser /* See if there is anything there */ 244aa9fba53SJuergen Kilb if (smc911x_detect_chip(dev)) 2451bc15386SPeter Tyser return 1; 2461bc15386SPeter Tyser 247c44efcf9SMike Frysinger smc911x_reset(dev); 2481bc15386SPeter Tyser 2491bc15386SPeter Tyser /* Make sure we set EEDIO/EECLK to the EEPROM */ 250c44efcf9SMike Frysinger if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) { 251c44efcf9SMike Frysinger while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) 2521bc15386SPeter Tyser if (smsc_ctrlc()) { 2531bc15386SPeter Tyser printf("init: timeout (E2P_CMD = 0x%08x)\n", 254c44efcf9SMike Frysinger smc911x_reg_read(dev, E2P_CMD)); 2551bc15386SPeter Tyser return 1; 2561bc15386SPeter Tyser } 257c44efcf9SMike Frysinger smc911x_reg_write(dev, GPIO_CFG, 258c44efcf9SMike Frysinger smc911x_reg_read(dev, GPIO_CFG) & ~GPIO_CFG_EEPR_EN); 2591bc15386SPeter Tyser } 2601bc15386SPeter Tyser 2611bc15386SPeter Tyser return 0; 2621bc15386SPeter Tyser } 2631bc15386SPeter Tyser 2641bc15386SPeter Tyser /** 2651bc15386SPeter Tyser * getline - consume a line of input and handle some escape sequences 2661bc15386SPeter Tyser */ 2671bc15386SPeter Tyser static char *getline(void) 2681bc15386SPeter Tyser { 2691bc15386SPeter Tyser static char buffer[100]; 2701bc15386SPeter Tyser char c; 2711bc15386SPeter Tyser size_t i; 2721bc15386SPeter Tyser 2731bc15386SPeter Tyser i = 0; 2741bc15386SPeter Tyser while (1) { 2751bc15386SPeter Tyser buffer[i] = '\0'; 2761bc15386SPeter Tyser while (!tstc()) 2771bc15386SPeter Tyser continue; 2781bc15386SPeter Tyser 2791bc15386SPeter Tyser c = getc(); 2801bc15386SPeter Tyser /* Convert to uppercase */ 2811bc15386SPeter Tyser if (c >= 'a' && c <= 'z') 2821bc15386SPeter Tyser c -= ('a' - 'A'); 2831bc15386SPeter Tyser 2841bc15386SPeter Tyser switch (c) { 2851bc15386SPeter Tyser case '\r': /* Enter/Return key */ 2861bc15386SPeter Tyser case '\n': 2871bc15386SPeter Tyser puts("\n"); 2881bc15386SPeter Tyser return buffer; 2891bc15386SPeter Tyser 2901bc15386SPeter Tyser case 0x03: /* ^C - break */ 2911bc15386SPeter Tyser return NULL; 2921bc15386SPeter Tyser 2931bc15386SPeter Tyser case 0x5F: 2941bc15386SPeter Tyser case 0x08: /* ^H - backspace */ 2951bc15386SPeter Tyser case 0x7F: /* DEL - backspace */ 2961bc15386SPeter Tyser if (i) { 2971bc15386SPeter Tyser puts("\b \b"); 2981bc15386SPeter Tyser i--; 2991bc15386SPeter Tyser } 3001bc15386SPeter Tyser break; 3011bc15386SPeter Tyser 3021bc15386SPeter Tyser default: 3031bc15386SPeter Tyser /* Ignore control characters */ 3041bc15386SPeter Tyser if (c < 0x20) 3051bc15386SPeter Tyser break; 3061bc15386SPeter Tyser /* Queue up all other characters */ 3071bc15386SPeter Tyser buffer[i++] = c; 3081bc15386SPeter Tyser printf("%c", c); 3091bc15386SPeter Tyser break; 3101bc15386SPeter Tyser } 3111bc15386SPeter Tyser } 3121bc15386SPeter Tyser } 3131bc15386SPeter Tyser 3141bc15386SPeter Tyser /** 3151bc15386SPeter Tyser * smc911x_eeprom - our application's main() function 3161bc15386SPeter Tyser */ 31754841ab5SWolfgang Denk int smc911x_eeprom(int argc, char * const argv[]) 3181bc15386SPeter Tyser { 319c44efcf9SMike Frysinger /* Avoid initializing on stack as gcc likes to call memset() */ 320c44efcf9SMike Frysinger struct eth_device dev; 321c44efcf9SMike Frysinger dev.iobase = CONFIG_SMC911X_BASE; 322c44efcf9SMike Frysinger 3231bc15386SPeter Tyser /* Print the ABI version */ 3241bc15386SPeter Tyser app_startup(argv); 3251bc15386SPeter Tyser if (XF_VERSION != get_version()) { 3261bc15386SPeter Tyser printf("Expects ABI version %d\n", XF_VERSION); 3271bc15386SPeter Tyser printf("Actual U-Boot ABI version %lu\n", get_version()); 3281bc15386SPeter Tyser printf("Can't run\n\n"); 3291bc15386SPeter Tyser return 1; 3301bc15386SPeter Tyser } 3311bc15386SPeter Tyser 3321bc15386SPeter Tyser /* Initialize the MAC/EEPROM somewhat */ 3331bc15386SPeter Tyser puts("\n"); 334c44efcf9SMike Frysinger if (smc911x_init(&dev)) 3351bc15386SPeter Tyser return 1; 3361bc15386SPeter Tyser 3371bc15386SPeter Tyser /* Dump helpful usage information */ 3381bc15386SPeter Tyser puts("\n"); 3391bc15386SPeter Tyser usage(); 3401bc15386SPeter Tyser puts("\n"); 3411bc15386SPeter Tyser 3421bc15386SPeter Tyser while (1) { 3431bc15386SPeter Tyser char *line; 3441bc15386SPeter Tyser 3451bc15386SPeter Tyser /* Send the prompt and wait for a line */ 3461bc15386SPeter Tyser puts("eeprom> "); 3471bc15386SPeter Tyser line = getline(); 3481bc15386SPeter Tyser 3491bc15386SPeter Tyser /* Got a ctrl+c */ 3501bc15386SPeter Tyser if (!line) 3511bc15386SPeter Tyser return 0; 3521bc15386SPeter Tyser 3531bc15386SPeter Tyser /* Eat leading space */ 3541bc15386SPeter Tyser line = skip_space(line); 3551bc15386SPeter Tyser 3561bc15386SPeter Tyser /* Empty line, try again */ 3571bc15386SPeter Tyser if (!line[0]) 3581bc15386SPeter Tyser continue; 3591bc15386SPeter Tyser 3601bc15386SPeter Tyser /* Only accept 1 letter commands */ 361*4d91a6ecSJason Hobbs if (line[0] && line[1] && !isblank(line[1])) 3621bc15386SPeter Tyser goto unknown_cmd; 3631bc15386SPeter Tyser 3641bc15386SPeter Tyser /* Now parse the command */ 3651bc15386SPeter Tyser switch (line[0]) { 366c44efcf9SMike Frysinger case 'W': write_stuff(&dev, line); break; 367c44efcf9SMike Frysinger case 'D': dump_eeprom(&dev); break; 368c44efcf9SMike Frysinger case 'M': dump_regs(&dev); break; 369c44efcf9SMike Frysinger case 'C': copy_from_eeprom(&dev); break; 370c44efcf9SMike Frysinger case 'P': print_macaddr(&dev); break; 3711bc15386SPeter Tyser unknown_cmd: 3721bc15386SPeter Tyser default: puts("ERROR: Unknown command!\n\n"); 3731bc15386SPeter Tyser case '?': 3741bc15386SPeter Tyser case 'H': usage(); break; 3751bc15386SPeter Tyser case 'Q': return 0; 3761bc15386SPeter Tyser } 3771bc15386SPeter Tyser } 3781bc15386SPeter Tyser } 379