1*1bc15386SPeter Tyser /* 2*1bc15386SPeter Tyser * smc911x_eeprom.c - EEPROM interface to SMC911x parts. 3*1bc15386SPeter Tyser * Only tested on SMSC9118 though ... 4*1bc15386SPeter Tyser * 5*1bc15386SPeter Tyser * Copyright 2004-2008 Analog Devices Inc. 6*1bc15386SPeter Tyser * 7*1bc15386SPeter Tyser * Licensed under the GPL-2 or later. 8*1bc15386SPeter Tyser * 9*1bc15386SPeter Tyser * Based on smc91111_eeprom.c which: 10*1bc15386SPeter Tyser * Heavily borrowed from the following peoples GPL'ed software: 11*1bc15386SPeter Tyser * - Wolfgang Denk, DENX Software Engineering, wd@denx.de 12*1bc15386SPeter Tyser * Das U-boot 13*1bc15386SPeter Tyser * - Ladislav Michl ladis@linux-mips.org 14*1bc15386SPeter Tyser * A rejected patch on the U-Boot mailing list 15*1bc15386SPeter Tyser */ 16*1bc15386SPeter Tyser 17*1bc15386SPeter Tyser #include <common.h> 18*1bc15386SPeter Tyser #include <exports.h> 19*1bc15386SPeter Tyser 20*1bc15386SPeter Tyser #ifdef CONFIG_DRIVER_SMC911X 21*1bc15386SPeter Tyser 22*1bc15386SPeter Tyser #include "../drivers/net/smc911x.h" 23*1bc15386SPeter Tyser 24*1bc15386SPeter Tyser /** 25*1bc15386SPeter Tyser * smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?) 26*1bc15386SPeter Tyser */ 27*1bc15386SPeter Tyser static int smsc_ctrlc(void) 28*1bc15386SPeter Tyser { 29*1bc15386SPeter Tyser return (tstc() && getc() == 0x03); 30*1bc15386SPeter Tyser } 31*1bc15386SPeter Tyser 32*1bc15386SPeter Tyser /** 33*1bc15386SPeter Tyser * usage - dump usage information 34*1bc15386SPeter Tyser */ 35*1bc15386SPeter Tyser static void usage(void) 36*1bc15386SPeter Tyser { 37*1bc15386SPeter Tyser puts( 38*1bc15386SPeter Tyser "MAC/EEPROM Commands:\n" 39*1bc15386SPeter Tyser " P : Print the MAC addresses\n" 40*1bc15386SPeter Tyser " D : Dump the EEPROM contents\n" 41*1bc15386SPeter Tyser " M : Dump the MAC contents\n" 42*1bc15386SPeter Tyser " C : Copy the MAC address from the EEPROM to the MAC\n" 43*1bc15386SPeter Tyser " W : Write a register in the EEPROM or in the MAC\n" 44*1bc15386SPeter Tyser " Q : Quit\n" 45*1bc15386SPeter Tyser "\n" 46*1bc15386SPeter Tyser "Some commands take arguments:\n" 47*1bc15386SPeter Tyser " W <E|M> <register> <value>\n" 48*1bc15386SPeter Tyser " E: EEPROM M: MAC\n" 49*1bc15386SPeter Tyser ); 50*1bc15386SPeter Tyser } 51*1bc15386SPeter Tyser 52*1bc15386SPeter Tyser /** 53*1bc15386SPeter Tyser * dump_regs - dump the MAC registers 54*1bc15386SPeter Tyser * 55*1bc15386SPeter Tyser * Registers 0x00 - 0x50 are FIFOs. The 0x50+ are the control registers 56*1bc15386SPeter Tyser * and they're all 32bits long. 0xB8+ are reserved, so don't bother. 57*1bc15386SPeter Tyser */ 58*1bc15386SPeter Tyser static void dump_regs(void) 59*1bc15386SPeter Tyser { 60*1bc15386SPeter Tyser u8 i, j = 0; 61*1bc15386SPeter Tyser for (i = 0x50; i < 0xB8; i += sizeof(u32)) 62*1bc15386SPeter Tyser printf("%02x: 0x%08x %c", i, 63*1bc15386SPeter Tyser smc911x_reg_read(CONFIG_DRIVER_SMC911X_BASE + i), 64*1bc15386SPeter Tyser (j++ % 2 ? '\n' : ' ')); 65*1bc15386SPeter Tyser } 66*1bc15386SPeter Tyser 67*1bc15386SPeter Tyser /** 68*1bc15386SPeter Tyser * do_eeprom_cmd - handle eeprom communication 69*1bc15386SPeter Tyser */ 70*1bc15386SPeter Tyser static int do_eeprom_cmd(int cmd, u8 reg) 71*1bc15386SPeter Tyser { 72*1bc15386SPeter Tyser if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) { 73*1bc15386SPeter Tyser printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n", 74*1bc15386SPeter Tyser smc911x_reg_read(E2P_CMD)); 75*1bc15386SPeter Tyser return -1; 76*1bc15386SPeter Tyser } 77*1bc15386SPeter Tyser 78*1bc15386SPeter Tyser smc911x_reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg); 79*1bc15386SPeter Tyser 80*1bc15386SPeter Tyser while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) 81*1bc15386SPeter Tyser if (smsc_ctrlc()) { 82*1bc15386SPeter Tyser printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n", 83*1bc15386SPeter Tyser smc911x_reg_read(E2P_CMD)); 84*1bc15386SPeter Tyser return -1; 85*1bc15386SPeter Tyser } 86*1bc15386SPeter Tyser 87*1bc15386SPeter Tyser return 0; 88*1bc15386SPeter Tyser } 89*1bc15386SPeter Tyser 90*1bc15386SPeter Tyser /** 91*1bc15386SPeter Tyser * read_eeprom_reg - read specified register in EEPROM 92*1bc15386SPeter Tyser */ 93*1bc15386SPeter Tyser static u8 read_eeprom_reg(u8 reg) 94*1bc15386SPeter Tyser { 95*1bc15386SPeter Tyser int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg); 96*1bc15386SPeter Tyser return (ret ? : smc911x_reg_read(E2P_DATA)); 97*1bc15386SPeter Tyser } 98*1bc15386SPeter Tyser 99*1bc15386SPeter Tyser /** 100*1bc15386SPeter Tyser * write_eeprom_reg - write specified value into specified register in EEPROM 101*1bc15386SPeter Tyser */ 102*1bc15386SPeter Tyser static int write_eeprom_reg(u8 value, u8 reg) 103*1bc15386SPeter Tyser { 104*1bc15386SPeter Tyser int ret; 105*1bc15386SPeter Tyser 106*1bc15386SPeter Tyser /* enable erasing/writing */ 107*1bc15386SPeter Tyser ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWEN, reg); 108*1bc15386SPeter Tyser if (ret) 109*1bc15386SPeter Tyser goto done; 110*1bc15386SPeter Tyser 111*1bc15386SPeter Tyser /* erase the eeprom reg */ 112*1bc15386SPeter Tyser ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_ERASE, reg); 113*1bc15386SPeter Tyser if (ret) 114*1bc15386SPeter Tyser goto done; 115*1bc15386SPeter Tyser 116*1bc15386SPeter Tyser /* write the eeprom reg */ 117*1bc15386SPeter Tyser smc911x_reg_write(E2P_DATA, value); 118*1bc15386SPeter Tyser ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg); 119*1bc15386SPeter Tyser if (ret) 120*1bc15386SPeter Tyser goto done; 121*1bc15386SPeter Tyser 122*1bc15386SPeter Tyser /* disable erasing/writing */ 123*1bc15386SPeter Tyser ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWDS, reg); 124*1bc15386SPeter Tyser 125*1bc15386SPeter Tyser done: 126*1bc15386SPeter Tyser return ret; 127*1bc15386SPeter Tyser } 128*1bc15386SPeter Tyser 129*1bc15386SPeter Tyser /** 130*1bc15386SPeter Tyser * skip_space - find first non-whitespace in given pointer 131*1bc15386SPeter Tyser */ 132*1bc15386SPeter Tyser static char *skip_space(char *buf) 133*1bc15386SPeter Tyser { 134*1bc15386SPeter Tyser while (buf[0] == ' ' || buf[0] == '\t') 135*1bc15386SPeter Tyser ++buf; 136*1bc15386SPeter Tyser return buf; 137*1bc15386SPeter Tyser } 138*1bc15386SPeter Tyser 139*1bc15386SPeter Tyser /** 140*1bc15386SPeter Tyser * write_stuff - handle writing of MAC registers / eeprom 141*1bc15386SPeter Tyser */ 142*1bc15386SPeter Tyser static void write_stuff(char *line) 143*1bc15386SPeter Tyser { 144*1bc15386SPeter Tyser char dest; 145*1bc15386SPeter Tyser char *endp; 146*1bc15386SPeter Tyser u8 reg; 147*1bc15386SPeter Tyser u32 value; 148*1bc15386SPeter Tyser 149*1bc15386SPeter Tyser /* Skip over the "W " part of the command */ 150*1bc15386SPeter Tyser line = skip_space(line + 1); 151*1bc15386SPeter Tyser 152*1bc15386SPeter Tyser /* Figure out destination */ 153*1bc15386SPeter Tyser switch (line[0]) { 154*1bc15386SPeter Tyser case 'E': 155*1bc15386SPeter Tyser case 'M': 156*1bc15386SPeter Tyser dest = line[0]; 157*1bc15386SPeter Tyser break; 158*1bc15386SPeter Tyser default: 159*1bc15386SPeter Tyser invalid_usage: 160*1bc15386SPeter Tyser printf("ERROR: Invalid write usage\n"); 161*1bc15386SPeter Tyser usage(); 162*1bc15386SPeter Tyser return; 163*1bc15386SPeter Tyser } 164*1bc15386SPeter Tyser 165*1bc15386SPeter Tyser /* Get the register to write */ 166*1bc15386SPeter Tyser line = skip_space(line + 1); 167*1bc15386SPeter Tyser reg = simple_strtoul(line, &endp, 16); 168*1bc15386SPeter Tyser if (line == endp) 169*1bc15386SPeter Tyser goto invalid_usage; 170*1bc15386SPeter Tyser 171*1bc15386SPeter Tyser /* Get the value to write */ 172*1bc15386SPeter Tyser line = skip_space(endp); 173*1bc15386SPeter Tyser value = simple_strtoul(line, &endp, 16); 174*1bc15386SPeter Tyser if (line == endp) 175*1bc15386SPeter Tyser goto invalid_usage; 176*1bc15386SPeter Tyser 177*1bc15386SPeter Tyser /* Check for trailing cruft */ 178*1bc15386SPeter Tyser line = skip_space(endp); 179*1bc15386SPeter Tyser if (line[0]) 180*1bc15386SPeter Tyser goto invalid_usage; 181*1bc15386SPeter Tyser 182*1bc15386SPeter Tyser /* Finally, execute the command */ 183*1bc15386SPeter Tyser if (dest == 'E') { 184*1bc15386SPeter Tyser printf("Writing EEPROM register %02x with %02x\n", reg, value); 185*1bc15386SPeter Tyser write_eeprom_reg(value, reg); 186*1bc15386SPeter Tyser } else { 187*1bc15386SPeter Tyser printf("Writing MAC register %02x with %08x\n", reg, value); 188*1bc15386SPeter Tyser smc911x_reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value); 189*1bc15386SPeter Tyser } 190*1bc15386SPeter Tyser } 191*1bc15386SPeter Tyser 192*1bc15386SPeter Tyser /** 193*1bc15386SPeter Tyser * copy_from_eeprom - copy MAC address in eeprom to address registers 194*1bc15386SPeter Tyser */ 195*1bc15386SPeter Tyser static void copy_from_eeprom(void) 196*1bc15386SPeter Tyser { 197*1bc15386SPeter Tyser ulong addrl = 198*1bc15386SPeter Tyser read_eeprom_reg(0x01) | 199*1bc15386SPeter Tyser read_eeprom_reg(0x02) << 8 | 200*1bc15386SPeter Tyser read_eeprom_reg(0x03) << 16 | 201*1bc15386SPeter Tyser read_eeprom_reg(0x04) << 24; 202*1bc15386SPeter Tyser ulong addrh = 203*1bc15386SPeter Tyser read_eeprom_reg(0x05) | 204*1bc15386SPeter Tyser read_eeprom_reg(0x06) << 8; 205*1bc15386SPeter Tyser smc911x_set_mac_csr(ADDRL, addrl); 206*1bc15386SPeter Tyser smc911x_set_mac_csr(ADDRH, addrh); 207*1bc15386SPeter Tyser puts("EEPROM contents copied to MAC\n"); 208*1bc15386SPeter Tyser } 209*1bc15386SPeter Tyser 210*1bc15386SPeter Tyser /** 211*1bc15386SPeter Tyser * print_macaddr - print MAC address registers and MAC address in eeprom 212*1bc15386SPeter Tyser */ 213*1bc15386SPeter Tyser static void print_macaddr(void) 214*1bc15386SPeter Tyser { 215*1bc15386SPeter Tyser puts("Current MAC Address in MAC: "); 216*1bc15386SPeter Tyser ulong addrl = smc911x_get_mac_csr(ADDRL); 217*1bc15386SPeter Tyser ulong addrh = smc911x_get_mac_csr(ADDRH); 218*1bc15386SPeter Tyser printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 219*1bc15386SPeter Tyser (u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16), 220*1bc15386SPeter Tyser (u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8)); 221*1bc15386SPeter Tyser 222*1bc15386SPeter Tyser puts("Current MAC Address in EEPROM: "); 223*1bc15386SPeter Tyser int i; 224*1bc15386SPeter Tyser for (i = 1; i < 6; ++i) 225*1bc15386SPeter Tyser printf("%02x:", read_eeprom_reg(i)); 226*1bc15386SPeter Tyser printf("%02x\n", read_eeprom_reg(i)); 227*1bc15386SPeter Tyser } 228*1bc15386SPeter Tyser 229*1bc15386SPeter Tyser /** 230*1bc15386SPeter Tyser * dump_eeprom - dump the whole content of the EEPROM 231*1bc15386SPeter Tyser */ 232*1bc15386SPeter Tyser static void dump_eeprom(void) 233*1bc15386SPeter Tyser { 234*1bc15386SPeter Tyser int i; 235*1bc15386SPeter Tyser puts("EEPROM:\n"); 236*1bc15386SPeter Tyser for (i = 0; i < 7; ++i) 237*1bc15386SPeter Tyser printf("%02x: 0x%02x\n", i, read_eeprom_reg(i)); 238*1bc15386SPeter Tyser } 239*1bc15386SPeter Tyser 240*1bc15386SPeter Tyser /** 241*1bc15386SPeter Tyser * smc911x_init - get the MAC/EEPROM up and ready for use 242*1bc15386SPeter Tyser */ 243*1bc15386SPeter Tyser static int smc911x_init(void) 244*1bc15386SPeter Tyser { 245*1bc15386SPeter Tyser /* See if there is anything there */ 246*1bc15386SPeter Tyser if (!smc911x_detect_chip()) 247*1bc15386SPeter Tyser return 1; 248*1bc15386SPeter Tyser 249*1bc15386SPeter Tyser smc911x_reset(); 250*1bc15386SPeter Tyser 251*1bc15386SPeter Tyser /* Make sure we set EEDIO/EECLK to the EEPROM */ 252*1bc15386SPeter Tyser if (smc911x_reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) { 253*1bc15386SPeter Tyser while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) 254*1bc15386SPeter Tyser if (smsc_ctrlc()) { 255*1bc15386SPeter Tyser printf("init: timeout (E2P_CMD = 0x%08x)\n", 256*1bc15386SPeter Tyser smc911x_reg_read(E2P_CMD)); 257*1bc15386SPeter Tyser return 1; 258*1bc15386SPeter Tyser } 259*1bc15386SPeter Tyser smc911x_reg_write(GPIO_CFG, smc911x_reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN); 260*1bc15386SPeter Tyser } 261*1bc15386SPeter Tyser 262*1bc15386SPeter Tyser return 0; 263*1bc15386SPeter Tyser } 264*1bc15386SPeter Tyser 265*1bc15386SPeter Tyser /** 266*1bc15386SPeter Tyser * getline - consume a line of input and handle some escape sequences 267*1bc15386SPeter Tyser */ 268*1bc15386SPeter Tyser static char *getline(void) 269*1bc15386SPeter Tyser { 270*1bc15386SPeter Tyser static char buffer[100]; 271*1bc15386SPeter Tyser char c; 272*1bc15386SPeter Tyser size_t i; 273*1bc15386SPeter Tyser 274*1bc15386SPeter Tyser i = 0; 275*1bc15386SPeter Tyser while (1) { 276*1bc15386SPeter Tyser buffer[i] = '\0'; 277*1bc15386SPeter Tyser while (!tstc()) 278*1bc15386SPeter Tyser continue; 279*1bc15386SPeter Tyser 280*1bc15386SPeter Tyser c = getc(); 281*1bc15386SPeter Tyser /* Convert to uppercase */ 282*1bc15386SPeter Tyser if (c >= 'a' && c <= 'z') 283*1bc15386SPeter Tyser c -= ('a' - 'A'); 284*1bc15386SPeter Tyser 285*1bc15386SPeter Tyser switch (c) { 286*1bc15386SPeter Tyser case '\r': /* Enter/Return key */ 287*1bc15386SPeter Tyser case '\n': 288*1bc15386SPeter Tyser puts("\n"); 289*1bc15386SPeter Tyser return buffer; 290*1bc15386SPeter Tyser 291*1bc15386SPeter Tyser case 0x03: /* ^C - break */ 292*1bc15386SPeter Tyser return NULL; 293*1bc15386SPeter Tyser 294*1bc15386SPeter Tyser case 0x5F: 295*1bc15386SPeter Tyser case 0x08: /* ^H - backspace */ 296*1bc15386SPeter Tyser case 0x7F: /* DEL - backspace */ 297*1bc15386SPeter Tyser if (i) { 298*1bc15386SPeter Tyser puts("\b \b"); 299*1bc15386SPeter Tyser i--; 300*1bc15386SPeter Tyser } 301*1bc15386SPeter Tyser break; 302*1bc15386SPeter Tyser 303*1bc15386SPeter Tyser default: 304*1bc15386SPeter Tyser /* Ignore control characters */ 305*1bc15386SPeter Tyser if (c < 0x20) 306*1bc15386SPeter Tyser break; 307*1bc15386SPeter Tyser /* Queue up all other characters */ 308*1bc15386SPeter Tyser buffer[i++] = c; 309*1bc15386SPeter Tyser printf("%c", c); 310*1bc15386SPeter Tyser break; 311*1bc15386SPeter Tyser } 312*1bc15386SPeter Tyser } 313*1bc15386SPeter Tyser } 314*1bc15386SPeter Tyser 315*1bc15386SPeter Tyser /** 316*1bc15386SPeter Tyser * smc911x_eeprom - our application's main() function 317*1bc15386SPeter Tyser */ 318*1bc15386SPeter Tyser int smc911x_eeprom(int argc, char *argv[]) 319*1bc15386SPeter Tyser { 320*1bc15386SPeter Tyser /* Print the ABI version */ 321*1bc15386SPeter Tyser app_startup(argv); 322*1bc15386SPeter Tyser if (XF_VERSION != get_version()) { 323*1bc15386SPeter Tyser printf("Expects ABI version %d\n", XF_VERSION); 324*1bc15386SPeter Tyser printf("Actual U-Boot ABI version %lu\n", get_version()); 325*1bc15386SPeter Tyser printf("Can't run\n\n"); 326*1bc15386SPeter Tyser return 1; 327*1bc15386SPeter Tyser } 328*1bc15386SPeter Tyser 329*1bc15386SPeter Tyser /* Initialize the MAC/EEPROM somewhat */ 330*1bc15386SPeter Tyser puts("\n"); 331*1bc15386SPeter Tyser if (smc911x_init()) 332*1bc15386SPeter Tyser return 1; 333*1bc15386SPeter Tyser 334*1bc15386SPeter Tyser /* Dump helpful usage information */ 335*1bc15386SPeter Tyser puts("\n"); 336*1bc15386SPeter Tyser usage(); 337*1bc15386SPeter Tyser puts("\n"); 338*1bc15386SPeter Tyser 339*1bc15386SPeter Tyser while (1) { 340*1bc15386SPeter Tyser char *line; 341*1bc15386SPeter Tyser 342*1bc15386SPeter Tyser /* Send the prompt and wait for a line */ 343*1bc15386SPeter Tyser puts("eeprom> "); 344*1bc15386SPeter Tyser line = getline(); 345*1bc15386SPeter Tyser 346*1bc15386SPeter Tyser /* Got a ctrl+c */ 347*1bc15386SPeter Tyser if (!line) 348*1bc15386SPeter Tyser return 0; 349*1bc15386SPeter Tyser 350*1bc15386SPeter Tyser /* Eat leading space */ 351*1bc15386SPeter Tyser line = skip_space(line); 352*1bc15386SPeter Tyser 353*1bc15386SPeter Tyser /* Empty line, try again */ 354*1bc15386SPeter Tyser if (!line[0]) 355*1bc15386SPeter Tyser continue; 356*1bc15386SPeter Tyser 357*1bc15386SPeter Tyser /* Only accept 1 letter commands */ 358*1bc15386SPeter Tyser if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t') 359*1bc15386SPeter Tyser goto unknown_cmd; 360*1bc15386SPeter Tyser 361*1bc15386SPeter Tyser /* Now parse the command */ 362*1bc15386SPeter Tyser switch (line[0]) { 363*1bc15386SPeter Tyser case 'W': write_stuff(line); break; 364*1bc15386SPeter Tyser case 'D': dump_eeprom(); break; 365*1bc15386SPeter Tyser case 'M': dump_regs(); break; 366*1bc15386SPeter Tyser case 'C': copy_from_eeprom(); break; 367*1bc15386SPeter Tyser case 'P': print_macaddr(); break; 368*1bc15386SPeter Tyser unknown_cmd: 369*1bc15386SPeter Tyser default: puts("ERROR: Unknown command!\n\n"); 370*1bc15386SPeter Tyser case '?': 371*1bc15386SPeter Tyser case 'H': usage(); break; 372*1bc15386SPeter Tyser case 'Q': return 0; 373*1bc15386SPeter Tyser } 374*1bc15386SPeter Tyser } 375*1bc15386SPeter Tyser } 376*1bc15386SPeter Tyser 377*1bc15386SPeter Tyser #else 378*1bc15386SPeter Tyser int smc911x_eeprom(int argc, char *argv[]) 379*1bc15386SPeter Tyser { 380*1bc15386SPeter Tyser puts("Not supported for this board\n"); 381*1bc15386SPeter Tyser return 1; 382*1bc15386SPeter Tyser } 383*1bc15386SPeter Tyser #endif 384