|
|
|
/*
|
|
|
|
* (C) Copyright 2005
|
|
|
|
* Ladislav Michl, 2N Telekomunikace, michl@2n.cz
|
|
|
|
*
|
|
|
|
* 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 version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* Some code shamelessly stolen back from Robin Getz.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define DEBUG
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <exports.h>
|
|
|
|
#include "../drivers/net/smc91111.h"
|
|
|
|
|
|
|
|
#define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE
|
|
|
|
|
|
|
|
static u16 read_eeprom_reg(u16 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int write_eeprom_reg(u16 value, u16 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int write_data(u16 *buf, int len)
|
|
|
|
{
|
|
|
|
u16 reg = 0x23;
|
|
|
|
|
|
|
|
while (len--)
|
|
|
|
write_eeprom_reg(*buf++, reg++);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_macaddr(char *s)
|
|
|
|
{
|
|
|
|
u16 reg;
|
|
|
|
int i, err = 0;
|
|
|
|
|
|
|
|
printf("MAC Address: ");
|
|
|
|
err = i = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
reg = read_eeprom_reg(0x20 + i);
|
|
|
|
printf("%02x:%02x%c", reg & 0xff, reg >> 8, i != 2 ? ':' : '\n');
|
|
|
|
if (s)
|
|
|
|
err |= reg != ((u16 *)s)[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return err ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_mac(char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *e, eaddr[6];
|
|
|
|
|
|
|
|
/* turn string into mac value */
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
eaddr[i] = simple_strtoul(s, &e, 16);
|
|
|
|
s = (*e) ? e+1 : e;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
write_eeprom_reg(*(((u16 *)eaddr) + i), 0x20 + i);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_element(char *s, unsigned char *buf, int len)
|
|
|
|
{
|
|
|
|
int cnt;
|
|
|
|
char *p, num[3];
|
|
|
|
unsigned char id;
|
|
|
|
|
|
|
|
id = simple_strtoul(s, &p, 16);
|
|
|
|
if (*p++ != ':')
|
|
|
|
return -1;
|
|
|
|
cnt = 2;
|
|
|
|
num[2] = 0;
|
|
|
|
for (; *p; p += 2) {
|
|
|
|
if (p[1] == 0)
|
|
|
|
return -2;
|
|
|
|
if (cnt + 3 > len)
|
|
|
|
return -3;
|
|
|
|
num[0] = p[0];
|
|
|
|
num[1] = p[1];
|
|
|
|
buf[cnt++] = simple_strtoul(num, NULL, 16);
|
|
|
|
}
|
|
|
|
buf[0] = id;
|
|
|
|
buf[1] = cnt - 2;
|
|
|
|
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int crcek(void);
|
|
|
|
|
|
|
|
int eeprom(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i, len, ret;
|
|
|
|
unsigned char buf[58], *p;
|
|
|
|
|
|
|
|
app_startup(argv);
|
|
|
|
if (get_version() != XF_VERSION) {
|
|
|
|
printf("Wrong XF_VERSION.\n");
|
|
|
|
printf("Application expects ABI version %d\n", XF_VERSION);
|
|
|
|
printf("Actual U-Boot ABI version %d\n", (int)get_version());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return crcek();
|
|
|
|
|
|
|
|
if ((SMC_inw (BANK_SELECT) & 0xFF00) != 0x3300) {
|
|
|
|
printf("SMSC91111 not found.\n");
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called without parameters - print MAC address */
|
|
|
|
if (argc < 2) {
|
|
|
|
verify_macaddr(NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print help message */
|
|
|
|
if (argv[1][1] == 'h') {
|
|
|
|
printf("VoiceBlue EEPROM writer\n");
|
|
|
|
printf("Built: %s at %s\n", __DATE__ , __TIME__ );
|
|
|
|
printf("Usage:\n\t<mac_address> [<element_1>] [<...>]\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to parse information elements */
|
|
|
|
len = sizeof(buf);
|
|
|
|
p = buf;
|
|
|
|
for (i = 2; i < argc; i++) {
|
|
|
|
ret = parse_element(argv[i], p, len);
|
|
|
|
switch (ret) {
|
|
|
|
case -1:
|
|
|
|
printf("Element %d: malformed\n", i - 1);
|
|
|
|
return 3;
|
|
|
|
case -2:
|
|
|
|
printf("Element %d: odd character count\n", i - 1);
|
|
|
|
return 3;
|
|
|
|
case -3:
|
|
|
|
printf("Out of EEPROM memory\n");
|
|
|
|
return 3;
|
|
|
|
default:
|
|
|
|
p += ret;
|
|
|
|
len -= ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First argument (MAC) is mandatory */
|
|
|
|
set_mac(argv[1]);
|
|
|
|
if (verify_macaddr(argv[1])) {
|
|
|
|
printf("*** MAC address does not match! ***\n");
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len--)
|
|
|
|
*p++ = 0;
|
|
|
|
|
|
|
|
write_data((u16 *)buf, sizeof(buf) >> 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|