|  | /* | 
|  | * (C) Copyright 2004 | 
|  | * Robin Getz rgetz@blacfin.uclinux.org | 
|  | * | 
|  | * 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 as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * 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 | 
|  | * | 
|  | * Heavily borrowed from the following peoples GPL'ed software: | 
|  | *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de | 
|  | *       Das U-boot | 
|  | *  - Ladislav Michl ladis@linux-mips.org | 
|  | *       A rejected patch on the U-Boot mailing list | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <exports.h> | 
|  | #include "../drivers/net/smc91111.h" | 
|  |  | 
|  | #ifdef CONFIG_DRIVER_SMC91111 | 
|  |  | 
|  | #ifndef SMC91111_EEPROM_INIT | 
|  | # define SMC91111_EEPROM_INIT() | 
|  | #endif | 
|  |  | 
|  | #define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE | 
|  | #define EEPROM		0x1 | 
|  | #define MAC		0x2 | 
|  | #define UNKNOWN		0x4 | 
|  |  | 
|  | void dump_reg (void); | 
|  | void dump_eeprom (void); | 
|  | int write_eeprom_reg (int, int); | 
|  | void copy_from_eeprom (void); | 
|  | void print_MAC (void); | 
|  | int read_eeprom_reg (int); | 
|  | void print_macaddr (void); | 
|  |  | 
|  | int smc91111_eeprom (int argc, char *argv[]) | 
|  | { | 
|  | int c, i, j, done, line, reg, value, start, what; | 
|  | char input[50]; | 
|  |  | 
|  | /* Print the ABI version */ | 
|  | app_startup (argv); | 
|  | if (XF_VERSION != (int) get_version ()) { | 
|  | printf ("Expects ABI version %d\n", XF_VERSION); | 
|  | printf ("Actual U-Boot ABI version %d\n", | 
|  | (int) get_version ()); | 
|  | printf ("Can't run\n\n"); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | SMC91111_EEPROM_INIT(); | 
|  |  | 
|  | if ((SMC_inw (BANK_SELECT) & 0xFF00) != 0x3300) { | 
|  | printf ("Can't find SMSC91111\n"); | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | done = 0; | 
|  | what = UNKNOWN; | 
|  | printf ("\n"); | 
|  | while (!done) { | 
|  | /* print the prompt */ | 
|  | printf ("SMC91111> "); | 
|  | line = 0; | 
|  | i = 0; | 
|  | start = 1; | 
|  | while (!line) { | 
|  | /* Wait for a keystroke */ | 
|  | while (!tstc ()); | 
|  |  | 
|  | c = getc (); | 
|  | /* Make Uppercase */ | 
|  | if (c >= 'Z') | 
|  | c -= ('a' - 'A'); | 
|  | /* printf(" |%02x| ",c); */ | 
|  |  | 
|  | switch (c) { | 
|  | case '\r':	/* Enter                */ | 
|  | case '\n': | 
|  | input[i] = 0; | 
|  | puts ("\r\n"); | 
|  | line = 1; | 
|  | break; | 
|  | case '\0':	/* nul                  */ | 
|  | continue; | 
|  |  | 
|  | case 0x03:	/* ^C - break           */ | 
|  | input[0] = 0; | 
|  | i = 0; | 
|  | line = 1; | 
|  | done = 1; | 
|  | break; | 
|  |  | 
|  | case 0x5F: | 
|  | case 0x08:	/* ^H  - backspace      */ | 
|  | case 0x7F:	/* DEL - backspace      */ | 
|  | if (i > 0) { | 
|  | puts ("\b \b"); | 
|  | i--; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | if (start) { | 
|  | if ((c == 'W') || (c == 'D') | 
|  | || (c == 'M') || (c == 'C') | 
|  | || (c == 'P')) { | 
|  | putc (c); | 
|  | input[i] = c; | 
|  | if (i <= 45) | 
|  | i++; | 
|  | start = 0; | 
|  | } | 
|  | } else { | 
|  | if ((c >= '0' && c <= '9') | 
|  | || (c >= 'A' && c <= 'F') | 
|  | || (c == 'E') || (c == 'M') | 
|  | || (c == ' ')) { | 
|  | putc (c); | 
|  | input[i] = c; | 
|  | if (i <= 45) | 
|  | i++; | 
|  | break; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (; i < 49; i++) | 
|  | input[i] = 0; | 
|  |  | 
|  | switch (input[0]) { | 
|  | case ('W'): | 
|  | /* Line should be w reg value */ | 
|  | i = 0; | 
|  | reg = 0; | 
|  | value = 0; | 
|  | /* Skip to the next space or end) */ | 
|  | while ((input[i] != ' ') && (input[i] != 0)) | 
|  | i++; | 
|  |  | 
|  | if (input[i] != 0) | 
|  | i++; | 
|  |  | 
|  | /* Are we writing to EEPROM or MAC */ | 
|  | switch (input[i]) { | 
|  | case ('E'): | 
|  | what = EEPROM; | 
|  | break; | 
|  | case ('M'): | 
|  | what = MAC; | 
|  | break; | 
|  | default: | 
|  | what = UNKNOWN; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* skip to the next space or end */ | 
|  | while ((input[i] != ' ') && (input[i] != 0)) | 
|  | i++; | 
|  | if (input[i] != 0) | 
|  | i++; | 
|  |  | 
|  | /* Find register to write into */ | 
|  | j = 0; | 
|  | while ((input[i] != ' ') && (input[i] != 0)) { | 
|  | j = input[i] - 0x30; | 
|  | if (j >= 0xA) { | 
|  | j -= 0x07; | 
|  | } | 
|  | reg = (reg * 0x10) + j; | 
|  | i++; | 
|  | } | 
|  |  | 
|  | while ((input[i] != ' ') && (input[i] != 0)) | 
|  | i++; | 
|  |  | 
|  | if (input[i] != 0) | 
|  | i++; | 
|  | else | 
|  | what = UNKNOWN; | 
|  |  | 
|  | /* Get the value to write */ | 
|  | j = 0; | 
|  | while ((input[i] != ' ') && (input[i] != 0)) { | 
|  | j = input[i] - 0x30; | 
|  | if (j >= 0xA) { | 
|  | j -= 0x07; | 
|  | } | 
|  | value = (value * 0x10) + j; | 
|  | i++; | 
|  | } | 
|  |  | 
|  | switch (what) { | 
|  | case 1: | 
|  | printf ("Writing EEPROM register %02x with %04x\n", reg, value); | 
|  | write_eeprom_reg (value, reg); | 
|  | break; | 
|  | case 2: | 
|  | printf ("Writing MAC register bank %i, reg %02x with %04x\n", reg >> 4, reg & 0xE, value); | 
|  | SMC_SELECT_BANK (reg >> 4); | 
|  | SMC_outw (value, reg & 0xE); | 
|  | break; | 
|  | default: | 
|  | printf ("Wrong\n"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case ('D'): | 
|  | dump_eeprom (); | 
|  | break; | 
|  | case ('M'): | 
|  | dump_reg (); | 
|  | break; | 
|  | case ('C'): | 
|  | copy_from_eeprom (); | 
|  | break; | 
|  | case ('P'): | 
|  | print_macaddr (); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | void copy_from_eeprom (void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | SMC_SELECT_BANK (1); | 
|  | SMC_outw ((SMC_inw (CTL_REG) & !CTL_EEPROM_SELECT) | CTL_RELOAD, | 
|  | CTL_REG); | 
|  | i = 100; | 
|  | while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --i) | 
|  | udelay (100); | 
|  | if (i == 0) { | 
|  | printf ("Timeout Refreshing EEPROM registers\n"); | 
|  | } else { | 
|  | printf ("EEPROM contents copied to MAC\n"); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | void print_macaddr (void) | 
|  | { | 
|  | int i, j, k, mac[6]; | 
|  |  | 
|  | printf ("Current MAC Address in SMSC91111 "); | 
|  | SMC_SELECT_BANK (1); | 
|  | for (i = 0; i < 5; i++) { | 
|  | printf ("%02x:", SMC_inb (ADDR0_REG + i)); | 
|  | } | 
|  |  | 
|  | printf ("%02x\n", SMC_inb (ADDR0_REG + 5)); | 
|  |  | 
|  | i = 0; | 
|  | for (j = 0x20; j < 0x23; j++) { | 
|  | k = read_eeprom_reg (j); | 
|  | mac[i] = k & 0xFF; | 
|  | i++; | 
|  | mac[i] = k >> 8; | 
|  | i++; | 
|  | } | 
|  |  | 
|  | printf ("Current MAC Address in EEPROM    "); | 
|  | for (i = 0; i < 5; i++) | 
|  | printf ("%02x:", mac[i]); | 
|  | printf ("%02x\n", mac[5]); | 
|  |  | 
|  | } | 
|  | void dump_eeprom (void) | 
|  | { | 
|  | int j, k; | 
|  |  | 
|  | printf ("IOS2-0    "); | 
|  | for (j = 0; j < 8; j++) { | 
|  | printf ("%03x     ", j); | 
|  | } | 
|  | printf ("\n"); | 
|  |  | 
|  | for (k = 0; k < 4; k++) { | 
|  | if (k == 0) | 
|  | printf ("CONFIG "); | 
|  | if (k == 1) | 
|  | printf ("BASE   "); | 
|  | if ((k == 2) || (k == 3)) | 
|  | printf ("       "); | 
|  | for (j = 0; j < 0x20; j += 4) { | 
|  | printf ("%02x:%04x ", j + k, read_eeprom_reg (j + k)); | 
|  | } | 
|  | printf ("\n"); | 
|  | } | 
|  |  | 
|  | for (j = 0x20; j < 0x40; j++) { | 
|  | if ((j & 0x07) == 0) | 
|  | printf ("\n"); | 
|  | printf ("%02x:%04x ", j, read_eeprom_reg (j)); | 
|  | } | 
|  | printf ("\n"); | 
|  |  | 
|  | } | 
|  |  | 
|  | int read_eeprom_reg (int reg) | 
|  | { | 
|  | int timeout; | 
|  |  | 
|  | SMC_SELECT_BANK (2); | 
|  | SMC_outw (reg, PTR_REG); | 
|  |  | 
|  | SMC_SELECT_BANK (1); | 
|  | SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD, | 
|  | CTL_REG); | 
|  | timeout = 100; | 
|  | while ((SMC_inw (CTL_REG) & CTL_RELOAD) && --timeout) | 
|  | udelay (100); | 
|  | if (timeout == 0) { | 
|  | printf ("Timeout Reading EEPROM register %02x\n", reg); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return SMC_inw (GP_REG); | 
|  |  | 
|  | } | 
|  |  | 
|  | int write_eeprom_reg (int value, int reg) | 
|  | { | 
|  | int timeout; | 
|  |  | 
|  | SMC_SELECT_BANK (2); | 
|  | SMC_outw (reg, PTR_REG); | 
|  |  | 
|  | SMC_SELECT_BANK (1); | 
|  | SMC_outw (value, GP_REG); | 
|  | SMC_outw (SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG); | 
|  | timeout = 100; | 
|  | while ((SMC_inw (CTL_REG) & CTL_STORE) && --timeout) | 
|  | udelay (100); | 
|  | if (timeout == 0) { | 
|  | printf ("Timeout Writing EEPROM register %02x\n", reg); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  |  | 
|  | } | 
|  |  | 
|  | void dump_reg (void) | 
|  | { | 
|  | int i, j; | 
|  |  | 
|  | printf ("    "); | 
|  | for (j = 0; j < 4; j++) { | 
|  | printf ("Bank%i ", j); | 
|  | } | 
|  | printf ("\n"); | 
|  | for (i = 0; i < 0xF; i += 2) { | 
|  | printf ("%02x  ", i); | 
|  | for (j = 0; j < 4; j++) { | 
|  | SMC_SELECT_BANK (j); | 
|  | printf ("%04x  ", SMC_inw (i)); | 
|  | } | 
|  | printf ("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | int smc91111_eeprom (int argc, char *argv[]) | 
|  | { | 
|  | printf("Not supported for this board\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #endif |