mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-20 03:38:43 +00:00
b29ff62772
Defining partially initialized struct eth_device on stack means gcc has to zero out it, and some gcc versions optimize this with an implicit call to memset. Move definition to data section to avoid that (it has also nice side effect that we need not to pass it to helper functions anymore) Signed-off-by: Ladislav Michl <ladis@linux-mips.org> Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
219 lines
4.4 KiB
C
219 lines
4.4 KiB
C
/*
|
|
* (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.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <exports.h>
|
|
#include <timestamp.h>
|
|
#include <net.h>
|
|
#include "../drivers/net/smc91111.h"
|
|
|
|
static struct eth_device dev = {
|
|
.iobase = CONFIG_SMC91111_BASE
|
|
};
|
|
|
|
static u16 read_eeprom_reg(u16 reg)
|
|
{
|
|
int timeout;
|
|
|
|
SMC_SELECT_BANK(&dev, 2);
|
|
SMC_outw(&dev, reg, PTR_REG);
|
|
|
|
SMC_SELECT_BANK(&dev, 1);
|
|
SMC_outw(&dev, SMC_inw(&dev, CTL_REG) | CTL_EEPROM_SELECT |
|
|
CTL_RELOAD, CTL_REG);
|
|
|
|
timeout = 100;
|
|
|
|
while ((SMC_inw(&dev, CTL_REG) & CTL_RELOAD) && --timeout)
|
|
udelay(100);
|
|
if (timeout == 0) {
|
|
printf("Timeout Reading EEPROM register %02x\n", reg);
|
|
return 0;
|
|
}
|
|
|
|
return SMC_inw(&dev, GP_REG);
|
|
}
|
|
|
|
static int write_eeprom_reg(u16 value, u16 reg)
|
|
{
|
|
int timeout;
|
|
|
|
SMC_SELECT_BANK(&dev, 2);
|
|
SMC_outw(&dev, reg, PTR_REG);
|
|
|
|
SMC_SELECT_BANK(&dev, 1);
|
|
|
|
SMC_outw(&dev, value, GP_REG);
|
|
SMC_outw(&dev, SMC_inw(&dev, CTL_REG) | CTL_EEPROM_SELECT |
|
|
CTL_STORE, CTL_REG);
|
|
|
|
timeout = 100;
|
|
|
|
while ((SMC_inw(&dev, 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if ((SMC_inw(&dev, 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("NetStar EEPROM writer\n");
|
|
printf("Built: %s at %s\n", U_BOOT_DATE, U_BOOT_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;
|
|
}
|