From e22ede21f2ce0f805c25434bfc9555674ddcf35c Mon Sep 17 00:00:00 2001 From: wdenk Date: Tue, 27 Aug 2002 05:55:31 +0000 Subject: [PATCH] Das U-Boot: Universal Boot Loader --- common/cmd_cache.c | 98 +++++ common/cmd_console.c | 61 ++++ common/cmd_date.c | 189 ++++++++++ common/cmd_dcr.c | 103 ++++++ common/cmd_dtt.c | 49 +++ common/cmd_eeprom.c | 353 ++++++++++++++++++ common/cmd_fdc.c | 735 +++++++++++++++++++++++++++++++++++++ common/cmd_mem.c | 850 +++++++++++++++++++++++++++++++++++++++++++ common/cmd_misc.c | 56 +++ common/cmd_net.c | 164 +++++++++ 10 files changed, 2658 insertions(+) create mode 100644 common/cmd_cache.c create mode 100644 common/cmd_console.c create mode 100644 common/cmd_date.c create mode 100644 common/cmd_dcr.c create mode 100644 common/cmd_dtt.c create mode 100644 common/cmd_eeprom.c create mode 100644 common/cmd_fdc.c create mode 100644 common/cmd_mem.c create mode 100644 common/cmd_misc.c create mode 100644 common/cmd_net.c diff --git a/common/cmd_cache.c b/common/cmd_cache.c new file mode 100644 index 0000000000..f2015b3ee5 --- /dev/null +++ b/common/cmd_cache.c @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * Cache support: switch on or off, get status + */ +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_CACHE) + +static int on_off (const char *); + +int do_icache ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + switch (argc) { + case 2: /* on / off */ + switch (on_off(argv[1])) { +#if 0 /* prevented by varargs handling; FALLTROUGH is harmless, too */ + default: printf ("Usage:\n%s\n", cmdtp->usage); + return; +#endif + case 0: icache_disable(); + break; + case 1: icache_enable (); + break; + } + /* FALL TROUGH */ + case 1: /* get status */ + printf ("Instruction Cache is %s\n", + icache_status() ? "ON" : "OFF"); + return 0; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + return 0; +} + +int do_dcache ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + switch (argc) { + case 2: /* on / off */ + switch (on_off(argv[1])) { +#if 0 /* prevented by varargs handling; FALLTROUGH is harmless, too */ + default: printf ("Usage:\n%s\n", cmdtp->usage); + return; +#endif + case 0: dcache_disable(); + break; + case 1: dcache_enable (); + break; + } + /* FALL TROUGH */ + case 1: /* get status */ + printf ("Data (writethrough) Cache is %s\n", + dcache_status() ? "ON" : "OFF"); + return 0; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + return 0; + +} + +static int on_off (const char *s) +{ + if (strcmp(s, "on") == 0) { + return (1); + } else if (strcmp(s, "off") == 0) { + return (0); + } + return (-1); +} + +#endif /* CFG_CMD_CACHE */ diff --git a/common/cmd_console.c b/common/cmd_console.c new file mode 100644 index 0000000000..a5f792b064 --- /dev/null +++ b/common/cmd_console.c @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * Boot support + */ +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_CONSOLE) + +extern void _do_coninfo (void); +int do_coninfo (cmd_tbl_t * cmd, int flag, int argc, char *argv[]) +{ + int i, l; + + /* Scan for valid output and input devices */ + + printf ("List of available devices:\n"); + + for (i = 1; i <= ListNumItems (devlist); i++) { + device_t *dev = ListGetPtrToItem (devlist, i); + + printf ("%-8s %08x %c%c%c ", + dev->name, + dev->flags, + (dev->flags & DEV_FLAGS_SYSTEM) ? 'S' : '.', + (dev->flags & DEV_FLAGS_INPUT) ? 'I' : '.', + (dev->flags & DEV_FLAGS_OUTPUT) ? 'O' : '.'); + + for (l = 0; l < MAX_FILES; l++) { + if (stdio_devices[l] == dev) { + printf ("%s ", stdio_names[l]); + } + } + putc ('\n'); + } + return 0; +} +#endif /* CFG_CMD_CONSOLE */ diff --git a/common/cmd_date.c b/common/cmd_date.c new file mode 100644 index 0000000000..1472e3f1aa --- /dev/null +++ b/common/cmd_date.c @@ -0,0 +1,189 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * RTC, Date & Time support: get and set date & time + */ +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_DATE) + +const char *weekdays[] = { + "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur", +}; + +int mk_date (char *, struct rtc_time *); + +int do_date (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + struct rtc_time tm; + int rcode = 0; + + switch (argc) { + case 2: /* set date & time */ + if (strcmp(argv[1],"reset") == 0) { + printf ("Reset RTC...\n"); + rtc_reset (); + } else { + /* initialize tm with current time */ + rtc_get (&tm); + /* insert new date & time */ + if (mk_date (argv[1], &tm) != 0) { + printf ("## Bad date format\n"); + return 1; + } + /* and write to RTC */ + rtc_set (&tm); + } + /* FALL TROUGH */ + case 1: /* get date & time */ + rtc_get (&tm); + + printf ("Date: %4d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + (tm.tm_wday<0 || tm.tm_wday>6) ? + "unknown " : weekdays[tm.tm_wday], + tm.tm_hour, tm.tm_min, tm.tm_sec); + + return 0; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + rcode = 1; + } + return rcode; +} + +/* + * simple conversion of two-digit string with error checking + */ +static int cnvrt2 (char *str, int *valp) +{ + int val; + + if ((*str < '0') || (*str > '9')) + return (-1); + + val = *str - '0'; + + ++str; + + if ((*str < '0') || (*str > '9')) + return (-1); + + *valp = 10 * val + (*str - '0'); + + return (0); +} + +/* + * Convert date string: MMDDhhmm[[CC]YY][.ss] + * + * Some basic checking for valid values is done, but this will not catch + * all possible error conditions. + */ +int mk_date (char *datestr, struct rtc_time *tmp) +{ + int len, val; + char *ptr; + + ptr = strchr (datestr,'.'); + len = strlen (datestr); + + /* Set seconds */ + if (ptr) { + int sec; + + *ptr++ = '\0'; + if ((len - (ptr - datestr)) != 2) + return (-1); + + len = strlen (datestr); + + if (cnvrt2 (ptr, &sec)) + return (-1); + + tmp->tm_sec = sec; + } else { + tmp->tm_sec = 0; + } + + if (len == 12) { /* MMDDhhmmCCYY */ + int year, century; + + if (cnvrt2 (datestr+ 8, ¢ury) || + cnvrt2 (datestr+10, &year) ) { + return (-1); + } + tmp->tm_year = 100 * century + year; + } else if (len == 10) { /* MMDDhhmmYY */ + int year, century; + + century = tmp->tm_year / 100; + if (cnvrt2 (datestr+ 8, &year)) + return (-1); + tmp->tm_year = 100 * century + year; + } + + switch (len) { + case 8: /* MMDDhhmm */ + /* fall thru */ + case 10: /* MMDDhhmmYY */ + /* fall thru */ + case 12: /* MMDDhhmmCCYY */ + if (cnvrt2 (datestr+0, &val) || + val > 12) { + break; + } + tmp->tm_mon = val; + if (cnvrt2 (datestr+2, &val) || + val > ((tmp->tm_mon==2) ? 29 : 31)) { + break; + } + tmp->tm_mday = val; + + if (cnvrt2 (datestr+4, &val) || + val > 23) { + break; + } + tmp->tm_hour = val; + + if (cnvrt2 (datestr+6, &val) || + val > 59) { + break; + } + tmp->tm_min = val; + + /* calculate day of week */ + GregorianDay (tmp); + + return (0); + default: + break; + } + + return (-1); +} + +#endif /* CFG_CMD_DATE */ diff --git a/common/cmd_dcr.c b/common/cmd_dcr.c new file mode 100644 index 0000000000..072685e4e3 --- /dev/null +++ b/common/cmd_dcr.c @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. + * + * 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 + */ + +/* + * IBM 4XX DCR Functions + */ + +#include +#include +#include +#include + +#if defined(CONFIG_4xx) && defined(CFG_CMD_SETGETDCR) + +/* ====================================================================== + * Interpreter command to retrieve an IBM PPC 4xx Device Control Register + * ====================================================================== + */ +int do_getdcr ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] ) +{ + unsigned short dcrn; /* Device Control Register Num */ + unsigned long value; /* DCR's value */ + + /* Validate arguments */ + if (argc < 2) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Get a DCR */ + dcrn = (unsigned short)simple_strtoul(argv[ 1 ], NULL, 16); + value = get_dcr(dcrn); + + printf("%04x: %08lx\n", dcrn, value); + + return 0; +} /* do_getdcr */ + + +/* ====================================================================== + * Interpreter command to set an IBM PPC 4xx Device Control Register + * ====================================================================== +*/ +int do_setdcr ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned short dcrn; /* Device Control Register Num */ + unsigned long value; /* DCR's value */ + int nbytes; + extern char console_buffer[]; + + /* Validate arguments */ + if (argc < 2) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Set a DCR */ + dcrn = (unsigned short)simple_strtoul(argv[1], NULL, 16); + do { + value = get_dcr(dcrn); + printf("%04x: %08lx", dcrn, value); + nbytes = readline(" ? "); + if (nbytes == 0) { + /* + * pressed as only input, don't modify current + * location and exit command. + */ + nbytes = 1; + return 0; + } else { + unsigned long i; + char *endp; + i = simple_strtoul(console_buffer, &endp, 16); + nbytes = endp - console_buffer; + if (nbytes) + set_dcr(dcrn, i); + } + } while (nbytes); + + return 0; +} /* do_setdcr */ + +#endif /* CONFIG_4xx & CFG_CMD_SETGETDCR */ diff --git a/common/cmd_dtt.c b/common/cmd_dtt.c new file mode 100644 index 0000000000..943b0c73e2 --- /dev/null +++ b/common/cmd_dtt.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com + * + * 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 + */ + +#include +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_DTT) + +#include + +int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int i; + unsigned char sensors[] = CONFIG_DTT_SENSORS; + + /* + * Loop through sensors, read + * temperature, and output it. + */ + for (i = 0; i < sizeof (sensors); i++) { + printf ("DTT%d: %i C\n", i + 1, dtt_get_temp (sensors[i])); + } + + return 0; +} /* do_dtt() */ + +#endif /* CONFIG_COMMANDS & CFG_CMD_DTT */ diff --git a/common/cmd_eeprom.c b/common/cmd_eeprom.c new file mode 100644 index 0000000000..29e9faf2b2 --- /dev/null +++ b/common/cmd_eeprom.c @@ -0,0 +1,353 @@ +/* + * (C) Copyright 2000, 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + * + */ + +#include +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_EEPROM) || defined(CFG_ENV_IS_IN_EEPROM) + +extern void eeprom_init (void); +extern int eeprom_read (unsigned dev_addr, unsigned offset, + uchar *buffer, unsigned cnt); +extern int eeprom_write (unsigned dev_addr, unsigned offset, + uchar *buffer, unsigned cnt); +#endif + + +#if defined(CFG_EEPROM_X40430) + /* Maximum number of times to poll for acknowledge after write */ +#define MAX_ACKNOWLEDGE_POLLS 10 +#endif + +/* ------------------------------------------------------------------------- */ + +#if (CONFIG_COMMANDS & CFG_CMD_EEPROM) +int do_eeprom ( cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + const char *const fmt = + "\nEEPROM @0x%lX %s: addr %08lx off %04lx count %ld ... "; + +#if defined(CFG_I2C_MULTI_EEPROMS) + if (argc == 6) { + ulong dev_addr = simple_strtoul (argv[2], NULL, 16); + ulong addr = simple_strtoul (argv[3], NULL, 16); + ulong off = simple_strtoul (argv[4], NULL, 16); + ulong cnt = simple_strtoul (argv[5], NULL, 16); +#else + if (argc == 5) { + ulong dev_addr = CFG_DEF_EEPROM_ADDR; + ulong addr = simple_strtoul (argv[2], NULL, 16); + ulong off = simple_strtoul (argv[3], NULL, 16); + ulong cnt = simple_strtoul (argv[4], NULL, 16); +#endif /* CFG_I2C_MULTI_EEPROMS */ + +# ifndef CONFIG_SPI + eeprom_init (); +# endif /* !CONFIG_SPI */ + + if (strcmp (argv[1], "read") == 0) { + int rcode; + + printf (fmt, dev_addr, argv[1], addr, off, cnt); + + rcode = eeprom_read (dev_addr, off, (uchar *) addr, cnt); + + printf ("done\n"); + return rcode; + } else if (strcmp (argv[1], "write") == 0) { + int rcode; + + printf (fmt, dev_addr, argv[1], addr, off, cnt); + + rcode = eeprom_write (dev_addr, off, (uchar *) addr, cnt); + + printf ("done\n"); + return rcode; + } + } + + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} +#endif /* CFG_CMD_EEPROM */ + +/*----------------------------------------------------------------------- + * + * for CFG_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is + * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. + * + * for CFG_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is + * 0x00000nxx for EEPROM address selectors and page number at n. + */ + +#if (CONFIG_COMMANDS & CFG_CMD_EEPROM) || defined(CFG_ENV_IS_IN_EEPROM) + +#ifndef CONFIG_SPI +#if !defined(CFG_I2C_EEPROM_ADDR_LEN) || CFG_I2C_EEPROM_ADDR_LEN < 1 || CFG_I2C_EEPROM_ADDR_LEN > 2 +#error CFG_I2C_EEPROM_ADDR_LEN must be 1 or 2 +#endif +#endif + +int eeprom_read (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) +{ + unsigned end = offset + cnt; + unsigned blk_off; + int rcode = 0; + + /* Read data until done or would cross a page boundary. + * We must write the address again when changing pages + * because the next page may be in a different device. + */ + while (offset < end) { + unsigned alen, len, maxlen; +#if CFG_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X) + uchar addr[2]; + + blk_off = offset & 0xFF; /* block offset */ + + addr[0] = offset >> 8; /* block number */ + addr[1] = blk_off; /* block offset */ + alen = 2; +#else + uchar addr[3]; + + blk_off = offset & 0xFF; /* block offset */ + + addr[0] = offset >> 16; /* block number */ + addr[1] = offset >> 8; /* upper address octet */ + addr[2] = blk_off; /* lower address octet */ + alen = 3; +#endif /* CFG_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */ + + addr[0] |= dev_addr; /* insert device address */ + + maxlen = 0x100 - blk_off; + if (maxlen > I2C_RXTX_LEN) + maxlen = I2C_RXTX_LEN; + len = end - offset; + if (len > maxlen) + len = maxlen; +#ifdef CONFIG_SPI + spi_read (addr, alen, buffer, len); +#else + if (i2c_read (addr[0], offset, alen-1, buffer, len) != 0) + rcode = 1; +#endif + buffer += len; + offset += len; + } + return rcode; +} + +/*----------------------------------------------------------------------- + * + * for CFG_I2C_EEPROM_ADDR_LEN == 2 (16-bit EEPROM address) offset is + * 0x000nxxxx for EEPROM address selectors at n, offset xxxx in EEPROM. + * + * for CFG_I2C_EEPROM_ADDR_LEN == 1 (8-bit EEPROM page address) offset is + * 0x00000nxx for EEPROM address selectors and page number at n. + */ + +int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned cnt) +{ + unsigned end = offset + cnt; + unsigned blk_off; + int rcode = 0; + +#if defined(CFG_EEPROM_X40430) + uchar contr_r_addr[2]; + uchar addr_void[2]; + uchar contr_reg[2]; + uchar ctrl_reg_v; + int i; +#endif + + /* Write data until done or would cross a write page boundary. + * We must write the address again when changing pages + * because the address counter only increments within a page. + */ + + while (offset < end) { + unsigned alen, len, maxlen; +#if CFG_I2C_EEPROM_ADDR_LEN == 1 && !defined(CONFIG_SPI_X) + uchar addr[2]; + + blk_off = offset & 0xFF; /* block offset */ + + addr[0] = offset >> 8; /* block number */ + addr[1] = blk_off; /* block offset */ + alen = 2; +#else + uchar addr[3]; + + blk_off = offset & 0xFF; /* block offset */ + + addr[0] = offset >> 16; /* block number */ + addr[1] = offset >> 8; /* upper address octet */ + addr[2] = blk_off; /* lower address octet */ + alen = 3; +#endif /* CFG_I2C_EEPROM_ADDR_LEN, CONFIG_SPI_X */ + + addr[0] |= dev_addr; /* insert device address */ + +#if defined(CFG_EEPROM_PAGE_WRITE_BITS) + +#define EEPROM_PAGE_SIZE (1 << CFG_EEPROM_PAGE_WRITE_BITS) +#define EEPROM_PAGE_OFFSET(x) ((x) & (EEPROM_PAGE_SIZE - 1)) + + maxlen = EEPROM_PAGE_SIZE - EEPROM_PAGE_OFFSET(blk_off); +#else + maxlen = 0x100 - blk_off; +#endif + if (maxlen > I2C_RXTX_LEN) + maxlen = I2C_RXTX_LEN; + + len = end - offset; + if (len > maxlen) + len = maxlen; +#ifdef CONFIG_SPI + spi_write (addr, alen, buffer, len); +#else +#if defined(CFG_EEPROM_X40430) + /* Get the value of the control register. + * Set current address (internal pointer in the x40430) + * to 0x1ff. + */ + contr_r_addr[0] = 9; + contr_r_addr[1] = 0xff; + addr_void[0] = 0; + addr_void[1] = addr[1]; +#ifdef CFG_I2C_EEPROM_ADDR + contr_r_addr[0] |= CFG_I2C_EEPROM_ADDR; + addr_void[0] |= CFG_I2C_EEPROM_ADDR; +#endif + contr_reg[0] = 0xff; + if (i2c_read (contr_r_addr[0], contr_r_addr[1], 1, contr_reg, 1) != 0) { + rcode = 1; + } + ctrl_reg_v = contr_reg[0]; + + /* Are any of the eeprom blocks write protected? + */ + if (ctrl_reg_v & 0x18) { + ctrl_reg_v &= ~0x18; /* reset block protect bits */ + ctrl_reg_v |= 0x02; /* set write enable latch */ + ctrl_reg_v &= ~0x04; /* clear RWEL */ + + /* Set write enable latch. + */ + contr_reg[0] = 0x02; + if (i2c_write (contr_r_addr[0], 0xff, 1, contr_reg, 1) != 0) { + rcode = 1; + } + + /* Set register write enable latch. + */ + contr_reg[0] = 0x06; + if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) { + rcode = 1; + } + + /* Modify ctrl register. + */ + contr_reg[0] = ctrl_reg_v; + if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) { + rcode = 1; + } + + /* The write (above) is an operation on NV memory. + * These can take some time (~5ms), and the device + * will not respond to further I2C messages till + * it's completed the write. + * So poll device for an I2C acknowledge. + * When we get one we know we can continue with other + * operations. + */ + contr_reg[0] = 0; + for (i = 0; i < MAX_ACKNOWLEDGE_POLLS; i++) { + if (i2c_read (addr_void[0], addr_void[1], 1, contr_reg, 1) == 1) + break; /* got ack */ +#if defined(CFG_EEPROM_PAGE_WRITE_DELAY_MS) + udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000); +#endif + } + if (i == MAX_ACKNOWLEDGE_POLLS) { + printf("EEPROM poll acknowledge failed\n"); + rcode = 1; + } + } + + /* Is the write enable latch on?. + */ + else if (!(ctrl_reg_v & 0x02)) { + /* Set write enable latch. + */ + contr_reg[0] = 0x02; + if (i2c_write (contr_r_addr[0], 0xFF, 1, contr_reg, 1) != 0) { + rcode = 1; + } + } + /* Write is enabled ... now write eeprom value. + */ +#endif + if (i2c_write (addr[0], offset, alen-1, buffer, len) != 0) + rcode = 1; + +#endif + buffer += len; + offset += len; + +#if defined(CFG_EEPROM_PAGE_WRITE_DELAY_MS) + udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000); +#endif + } + return rcode; +} + +/*----------------------------------------------------------------------- + * Set default values + */ +#ifndef CFG_I2C_SPEED +#define CFG_I2C_SPEED 50000 +#endif + +#ifndef CFG_I2C_SLAVE +#define CFG_I2C_SLAVE 0xFE +#endif + +void eeprom_init (void) +{ +#if defined(CONFIG_SPI) + spi_init_f (); +#endif +#if defined(CONFIG_HARD_I2C) || \ + defined(CONFIG_SOFT_I2C) + i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE); +#endif +} +/*----------------------------------------------------------------------- + */ +#endif /* CFG_CMD_EEPROM */ diff --git a/common/cmd_fdc.c b/common/cmd_fdc.c new file mode 100644 index 0000000000..712c14b57c --- /dev/null +++ b/common/cmd_fdc.c @@ -0,0 +1,735 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG, d.peter@mpl.ch. + * + * 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 + * + */ +/* + * Floppy Disk support + */ + +#include +#include +#include +#include + + +#undef FDC_DEBUG + +#ifdef FDC_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + + +#if (CONFIG_COMMANDS & CFG_CMD_DATE) +#include +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_FDC) + + +typedef struct { + int flags; /* connected drives ect */ + unsigned long blnr; /* Logical block nr */ + uchar drive; /* drive no */ + uchar cmdlen; /* cmd length */ + uchar cmd[16]; /* cmd desc */ + uchar dma; /* if > 0 dma enabled */ + uchar result[11];/* status information */ + uchar resultlen; /* lenght of result */ +} FDC_COMMAND_STRUCT; +/* flags: only the lower 8bit used: + * bit 0 if set drive 0 is present + * bit 1 if set drive 1 is present + * bit 2 if set drive 2 is present + * bit 3 if set drive 3 is present + * bit 4 if set disk in drive 0 is inserted + * bit 5 if set disk in drive 1 is inserted + * bit 6 if set disk in drive 2 is inserted + * bit 7 if set disk in drive 4 is inserted + */ + + +/* cmd indexes */ +#define COMMAND 0 +#define DRIVE 1 +#define CONFIG0 1 +#define SPEC_HUTSRT 1 +#define TRACK 2 +#define CONFIG1 2 +#define SPEC_HLT 2 +#define HEAD 3 +#define CONFIG2 3 +#define SECTOR 4 +#define SECTOR_SIZE 5 +#define LAST_TRACK 6 +#define GAP 7 +#define DTL 8 +/* result indexes */ +#define STATUS_0 0 +#define STATUS_PCN 1 +#define STATUS_1 1 +#define STATUS_2 2 +#define STATUS_TRACK 3 +#define STATUS_HEAD 4 +#define STATUS_SECT 5 +#define STATUS_SECT_SIZE 6 + + +/* Register addresses */ +#define FDC_BASE 0x3F0 +#define FDC_SRA FDC_BASE + 0 /* Status Register A */ +#define FDC_SRB FDC_BASE + 1 /* Status Register B */ +#define FDC_DOR FDC_BASE + 2 /* Digital Output Register */ +#define FDC_TDR FDC_BASE + 3 /* Tape Drive Register */ +#define FDC_DSR FDC_BASE + 4 /* Data rate Register */ +#define FDC_MSR FDC_BASE + 4 /* Main Status Register */ +#define FDC_FIFO FDC_BASE + 5 /* FIFO */ +#define FDC_DIR FDC_BASE + 6 /* Digital Input Register */ +#define FDC_CCR FDC_BASE + 7 /* Configuration Control */ +/* Commands */ +#define FDC_CMD_SENSE_INT 0x08 +#define FDC_CMD_CONFIGURE 0x13 +#define FDC_CMD_SPECIFY 0x03 +#define FDC_CMD_RECALIBRATE 0x07 +#define FDC_CMD_READ 0x06 +#define FDC_CMD_READ_TRACK 0x02 +#define FDC_CMD_READ_ID 0x0A +#define FDC_CMD_DUMP_REG 0x0E +#define FDC_CMD_SEEK 0x0F + +#define FDC_CMD_SENSE_INT_LEN 0x01 +#define FDC_CMD_CONFIGURE_LEN 0x04 +#define FDC_CMD_SPECIFY_LEN 0x03 +#define FDC_CMD_RECALIBRATE_LEN 0x02 +#define FDC_CMD_READ_LEN 0x09 +#define FDC_CMD_READ_TRACK_LEN 0x09 +#define FDC_CMD_READ_ID_LEN 0x02 +#define FDC_CMD_DUMP_REG_LEN 0x01 +#define FDC_CMD_SEEK_LEN 0x03 + +#define FDC_FIFO_THR 0x0C +#define FDC_FIFO_DIS 0x00 +#define FDC_IMPLIED_SEEK 0x01 +#define FDC_POLL_DIS 0x00 +#define FDC_PRE_TRK 0x00 +#define FDC_CONFIGURE FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6) +#define FDC_MFM_MODE 0x01 /* MFM enable */ +#define FDC_SKIP_MODE 0x00 /* skip enable */ + +#define FDC_TIME_OUT 100000 /* time out */ +#define FDC_RW_RETRIES 3 /* read write retries */ +#define FDC_CAL_RETRIES 3 /* calibration and seek retries */ + + +/* Disk structure */ +typedef struct { + unsigned int size; /* nr of sectors total */ + unsigned int sect; /* sectors per track */ + unsigned int head; /* nr of heads */ + unsigned int track; /* nr of tracks */ + unsigned int stretch; /* !=0 means double track steps */ + unsigned char gap; /* gap1 size */ + unsigned char rate; /* data rate. |= 0x40 for perpendicular */ + unsigned char spec1; /* stepping rate, head unload time */ + unsigned char fmt_gap; /* gap2 size */ + unsigned char hlt; /* head load time */ + unsigned char sect_code; /* Sector Size code */ + const char * name; /* used only for predefined formats */ +} FD_GEO_STRUCT; + + +/* supported Floppy types (currently only one) */ +const static FD_GEO_STRUCT floppy_type[2] = { + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" }, /* 7 1.44MB 3.5" */ + { 0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL }, /* end of table */ +}; + +static FDC_COMMAND_STRUCT cmd; /* global command struct */ + +/* Supporting Functions */ +/* reads a Register of the FDC */ +unsigned char read_fdc_reg(unsigned int addr) +{ + volatile unsigned char *val = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS | addr); + return val[0]; +} + +/* writes a Register of the FDC */ +void write_fdc_reg(unsigned int addr, unsigned char val) +{ + volatile unsigned char *tmp = (volatile unsigned char *)(CFG_ISA_IO_BASE_ADDRESS | addr); + tmp[0]=val; +} + +/* waits for an interrupt (polling) */ +int wait_for_fdc_int(void) +{ + unsigned long timeout; + timeout = FDC_TIME_OUT; + while((read_fdc_reg(FDC_SRA)&0x80)==0) { + timeout--; + udelay(10); + if(timeout==0) /* timeout occured */ + return FALSE; + } + return TRUE; +} + + +/* reads a byte from the FIFO of the FDC and checks direction and RQM bit + of the MSR. returns -1 if timeout, or byte if ok */ +int read_fdc_byte(void) +{ + unsigned long timeout; + timeout = FDC_TIME_OUT; + while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) { + /* direction out and ready */ + udelay(10); + timeout--; + if(timeout==0) /* timeout occured */ + return -1; + } + return read_fdc_reg(FDC_FIFO); +} + +/* if the direction of the FIFO is wrong, this routine is used to + empty the FIFO. Should _not_ be used */ +int fdc_need_more_output(void) +{ + unsigned char c; + while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0) { + c=(unsigned char)read_fdc_byte(); + printf("Error: more output: %x\n",c); + } + return TRUE; +} + + +/* writes a byte to the FIFO of the FDC and checks direction and RQM bit + of the MSR */ +int write_fdc_byte(unsigned char val) +{ + unsigned long timeout; + timeout = FDC_TIME_OUT; + while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) { + /* direction in and ready for byte */ + timeout--; + udelay(10); + fdc_need_more_output(); + if(timeout==0) /* timeout occured */ + return FALSE; + } + write_fdc_reg(FDC_FIFO,val); + return TRUE; +} + +/* sets up all FDC commands and issues it to the FDC. If + the command causes direct results (no Execution Phase) + the result is be read as well. */ + +int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG) +{ + int i; + unsigned long head,track,sect,timeout; + track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */ + sect = pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */ + head = sect / pFG->sect; /* head nr */ + sect = sect % pFG->sect; /* remaining blocks */ + sect++; /* sectors are 1 based */ + PRINTF("Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",track,head,sect,pCMD->drive,pCMD->blnr); + if(head|=0) { /* max heads = 2 */ + pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */ + pCMD->cmd[HEAD]=(unsigned char) head; /* head register */ + } + else { + pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */ + pCMD->cmd[HEAD]=(unsigned char) head; /* head register */ + } + pCMD->cmd[TRACK]=(unsigned char) track; /* track */ + switch (pCMD->cmd[COMMAND]) { + case FDC_CMD_READ: + pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */ + pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */ + pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */ + pCMD->cmd[GAP]=pFG->gap; /* gap */ + pCMD->cmd[DTL]=0xFF; /* DTL */ + pCMD->cmdlen=FDC_CMD_READ_LEN; + pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */ + pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */ + pCMD->resultlen=0; /* result only after execution */ + break; + case FDC_CMD_SEEK: + pCMD->cmdlen=FDC_CMD_SEEK_LEN; + pCMD->resultlen=0; /* no result */ + break; + case FDC_CMD_CONFIGURE: + pCMD->cmd[CONFIG0]=0; + pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */ + pCMD->cmd[CONFIG2]=FDC_PRE_TRK; /* Precompensation Track */ + pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN; + pCMD->resultlen=0; /* no result */ + break; + case FDC_CMD_SPECIFY: + pCMD->cmd[SPEC_HUTSRT]=pFG->spec1; + pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */ + if(pCMD->dma==0) + pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */ + pCMD->cmdlen=FDC_CMD_SPECIFY_LEN; + pCMD->resultlen=0; /* no result */ + break; + case FDC_CMD_DUMP_REG: + pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN; + pCMD->resultlen=10; /* 10 byte result */ + break; + case FDC_CMD_READ_ID: + pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */ + pCMD->cmdlen=FDC_CMD_READ_ID_LEN; + pCMD->resultlen=7; /* 7 byte result */ + break; + case FDC_CMD_RECALIBRATE: + pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */ + pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN; + pCMD->resultlen=0; /* no result */ + break; + break; + case FDC_CMD_SENSE_INT: + pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN; + pCMD->resultlen=2; + break; + } + for(i=0;icmdlen;i++) { + /* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */ + if(write_fdc_byte(pCMD->cmd[i])==FALSE) { + PRINTF("Error: timeout while issue cmd%d\n",i); + return FALSE; + } + } + timeout=FDC_TIME_OUT; + for(i=0;iresultlen;i++) { + while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) { + timeout--; + if(timeout==0) { + PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR)); + return FALSE; + } + } + pCMD->result[i]=(unsigned char)read_fdc_byte(); + } + return TRUE; +} + +/* selects the drive assigned in the cmd structur and + switches on the Motor */ +void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD) +{ + unsigned char val; + + val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */ + if((read_fdc_reg(FDC_DOR)&val)!=val) { + write_fdc_reg(FDC_DOR,val); + for(val=0;val<255;val++) + udelay(500); /* wait some time to start motor */ + } +} + +/* switches off the Motor of the specified drive */ +void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD) +{ + unsigned char val; + + val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */ + write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val)); +} + +/* issues a recalibrate command, waits for interrupt and + * issues a sense_interrupt */ +int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG) +{ + pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) + return FALSE; + while(wait_for_fdc_int()!=TRUE); + pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT; + return(fdc_issue_cmd(pCMD,pFG)); +} + +/* issues a recalibrate command, waits for interrupt and + * issues a sense_interrupt */ +int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG) +{ + pCMD->cmd[COMMAND]=FDC_CMD_SEEK; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) + return FALSE; + while(wait_for_fdc_int()!=TRUE); + pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT; + return(fdc_issue_cmd(pCMD,pFG)); +} + + +/* terminates current command, by not servicing the FIFO + * waits for interrupt and fills in the result bytes */ +int fdc_terminate(FDC_COMMAND_STRUCT *pCMD) +{ + int i; + for(i=0;i<100;i++) + udelay(500); /* wait 500usec for fifo overrun */ + while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occured */ + for(i=0;i<7;i++) { + pCMD->result[i]=(unsigned char)read_fdc_byte(); + } + return TRUE; +} + +/* reads data from FDC, seek commands are issued automatic */ +int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) +{ + /* first seek to start address */ + unsigned long len,lastblk,readblk,i,timeout,ii,offset; + unsigned char pcn,c,retriesrw,retriescal; + unsigned char *bufferw; /* working buffer */ + int sect_size; + int flags; + + flags=disable_interrupts(); /* switch off all Interrupts */ + select_fdc_drive(pCMD); /* switch on drive */ + sect_size=0x080<sect_code; + retriesrw=0; + retriescal=0; + offset=0; + if(fdc_seek(pCMD,pFG)==FALSE) { + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + if((pCMD->result[STATUS_0]&0x20)!=0x20) { + printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]); + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + pcn=pCMD->result[STATUS_PCN]; /* current track */ + /* now determine the next seek point */ + lastblk=pCMD->blnr + blocks; + /* readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */ + readblk=pFG->sect-(pCMD->blnr%pFG->sect); + PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr); + if(readblk>blocks) /* is end within 1st track */ + readblk=blocks; /* yes, correct it */ + PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr); + bufferw=&buffer[0]; /* setup working buffer */ + do { +retryrw: + len=sect_size * readblk; + pCMD->cmd[COMMAND]=FDC_CMD_READ; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) { + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + for (i=0;i6) { + for(ii=0;ii<7;ii++) { + pCMD->result[ii]=bufferw[(i-7+ii)]; + } /* for */ + } + if(retriesrw++>FDC_RW_RETRIES) { + if (retriescal++>FDC_CAL_RETRIES) { + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + else { + PRINTF(" trying to recalibrate Try %d\n",retriescal); + if(fdc_recalibrate(pCMD,pFG)==FALSE) { + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + retriesrw=0; + goto retrycal; + } /* else >FDC_CAL_RETRIES */ + } + else { + PRINTF("Read retry %d\n",retriesrw); + goto retryrw; + } /* else >FDC_RW_RETRIES */ + }/* if output */ + timeout--; + }while(TRUE); + } /* for len */ + /* the last sector of a track or all data has been read, + * we need to get the results */ + fdc_terminate(pCMD); + offset+=(sect_size*readblk); /* set up buffer pointer */ + bufferw=&buffer[offset]; + pCMD->blnr+=readblk; /* update current block nr */ + blocks-=readblk; /* update blocks */ + if(blocks==0) + break; /* we are finish */ + /* setup new read blocks */ + /* readblk=pFG->head*pFG->sect; */ + readblk=pFG->sect; + if(readblk>blocks) + readblk=blocks; +retrycal: + /* a seek is necessary */ + if(fdc_seek(pCMD,pFG)==FALSE) { + stop_fdc_drive(pCMD); + enable_interrupts(); + return FALSE; + } + if((pCMD->result[STATUS_0]&0x20)!=0x20) { + PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]); + stop_fdc_drive(pCMD); + return FALSE; + } + pcn=pCMD->result[STATUS_PCN]; /* current track */ + }while(TRUE); /* start over */ + stop_fdc_drive(pCMD); /* switch off drive */ + enable_interrupts(); + return TRUE; +} + +/* Scan all drives and check if drive is present and disk is inserted */ +int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) +{ + int i,drives,state; + /* OK procedure of data book is satisfied. + * trying to get some information over the drives */ + state=0; /* no drives, no disks */ + for(drives=0;drives<4;drives++) { + pCMD->drive=drives; + select_fdc_drive(pCMD); + pCMD->blnr=0; /* set to the 1st block */ + if(fdc_recalibrate(pCMD,pFG)==FALSE) + break; + if((pCMD->result[STATUS_0]&0x10)==0x10) + break; + /* ok drive connected check for disk */ + state|=(1<blnr=pFG->size; /* set to the last block */ + if(fdc_seek(pCMD,pFG)==FALSE) + break; + pCMD->blnr=0; /* set to the 1st block */ + if(fdc_recalibrate(pCMD,pFG)==FALSE) + break; + pCMD->cmd[COMMAND]=FDC_CMD_READ_ID; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) + break; + state|=(0x10<name : ""); + } + pCMD->flags=state; + return TRUE; +} + + +/************************************************************************** +* int fdc_setup +* setup the fdc according the datasheet +* assuming in PS2 Mode +*/ +int fdc_setup(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG) +{ + + int i; + /* first, we reset the FDC via the DOR */ + write_fdc_reg(FDC_DOR,0x00); + for(i=0; i<255; i++) /* then we wait some time */ + udelay(500); + /* then, we clear the reset in the DOR */ + pCMD->drive=0; + select_fdc_drive(pCMD); + /* initialize the CCR */ + write_fdc_reg(FDC_CCR,pFG->rate); + /* then initialize the DSR */ + write_fdc_reg(FDC_DSR,pFG->rate); + if(wait_for_fdc_int()==FALSE) { + PRINTF("Time Out after writing CCR\n"); + return FALSE; + } + /* now issue sense Interrupt and status command + * assuming only one drive present (drive 0) */ + pCMD->dma=0; /* we don't use any dma at all */ + for(i=0;i<4;i++) { + /* issue sense interrupt for all 4 possible drives */ + pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) { + PRINTF("Sense Interrupt for drive %d failed\n",i); + } + } + /* assuming drive 0 for rest of configuration + * issue the configure command */ + pCMD->drive=0; + select_fdc_drive(pCMD); + pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) { + PRINTF(" configure timeout\n"); + stop_fdc_drive(pCMD); + return FALSE; + } + /* issue specify command */ + pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY; + if(fdc_issue_cmd(pCMD,pFG)==FALSE) { + PRINTF(" specify timeout\n"); + stop_fdc_drive(pCMD); + return FALSE; + + } + /* then, we clear the reset in the DOR */ + /* fdc_check_drive(pCMD,pFG); */ + /* write_fdc_reg(FDC_DOR,0x04); */ + return TRUE; +} + +/**************************************************************************** + * main routine do_fdcboot + */ +int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type; + FDC_COMMAND_STRUCT *pCMD = &cmd; + unsigned long addr,imsize; + image_header_t *hdr; /* used for fdc boot */ + unsigned char boot_drive; + int i,nrofblk; + char *ep; + int rcode = 0; + + switch (argc) { + case 1: + addr = CFG_LOAD_ADDR; + boot_drive=0; /* default boot from drive 0 */ + break; + case 2: + addr = simple_strtoul(argv[1], NULL, 16); + boot_drive=0; /* default boot from drive 0 */ + break; + case 3: + addr = simple_strtoul(argv[1], NULL, 16); + boot_drive=simple_strtoul(argv[2], NULL, 10); + break; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + /* setup FDC and scan for drives */ + if(fdc_setup(pCMD,pFG)==FALSE) { + printf("\n** Error in setup FDC **\n"); + return 1; + } + if(fdc_check_drive(pCMD,pFG)==FALSE) { + printf("\n** Error in check_drives **\n"); + return 1; + } + if((pCMD->flags&(1<flags&(0x10<drive=boot_drive; + /* read first block */ + pCMD->blnr=0; + if(fdc_read_data((unsigned char *)addr,1,pCMD,pFG)==FALSE) { + printf("\nRead error:"); + for(i=0;i<7;i++) + printf("result%d: 0x%02X\n",i,pCMD->result[i]); + return 1; + } + hdr = (image_header_t *)addr; + if (hdr->ih_magic != IH_MAGIC) { + printf ("Bad Magic Number\n"); + return 1; + } + print_image_hdr(hdr); + + imsize= hdr->ih_size+sizeof(image_header_t); + nrofblk=imsize/512; + if((imsize%512)>0) + nrofblk++; + printf("Loading %ld Bytes (%d blocks) at 0x%08lx..\n",imsize,nrofblk,addr); + pCMD->blnr=0; + if(fdc_read_data((unsigned char *)addr,nrofblk,pCMD,pFG)==FALSE) { + /* read image block */ + printf("\nRead error:"); + for(i=0;i<7;i++) + printf("result%d: 0x%02X\n",i,pCMD->result[i]); + return 1; + } + printf("OK %ld Bytes loaded.\n",imsize); + + flush_cache (addr, imsize); + /* Loading ok, update default load address */ + + load_addr = addr; + if(hdr->ih_type == IH_TYPE_KERNEL) { + /* Check if we should attempt an auto-start */ + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { + char *local_args[2]; + extern int do_bootm (cmd_tbl_t *, int, int, char *[]); + + local_args[0] = argv[0]; + local_args[1] = NULL; + + printf ("Automatic boot of image at addr 0x%08lX ...\n", addr); + + do_bootm (cmdtp, 0, 1, local_args); + rcode ++; + } + } + return rcode; +} + + + +#endif /* CONFIG_COMMANDS & CFG_CMD_FDC */ + + diff --git a/common/cmd_mem.c b/common/cmd_mem.c new file mode 100644 index 0000000000..eb44f2e01e --- /dev/null +++ b/common/cmd_mem.c @@ -0,0 +1,850 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * Memory Functions + * + * Copied from FADS ROM, Dan Malek (dmalek@jlc.net) + */ + +#include +#include +#include + +#if (CONFIG_COMMANDS & (CFG_CMD_MEMORY | CFG_CMD_PCI | CFG_CMD_I2C)) +int cmd_get_data_size(char* arg, int default_size) +{ + /* Check for a size specification .b, .w or .l. + */ + int len = strlen(arg); + if (len > 2 && arg[len-2] == '.') { + switch(arg[len-1]) { + case 'b': + return 1; + case 'w': + return 2; + case 'l': + return 4; + } + } + return default_size; +} +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_MEMORY) + +#ifdef CMD_MEM_DEBUG +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +static int mod_mem(cmd_tbl_t *, int, int, int, char *[]); + +/* Display values from last command. + * Memory modify remembered values are different from display memory. + */ +uint dp_last_addr, dp_last_size; +uint dp_last_length = 0x40; +uint mm_last_addr, mm_last_size; + +static ulong base_address = 0; + +/* Memory Display + * + * Syntax: + * md{.b, .w, .l} {addr} {len} + */ +#define DISP_LINE_LEN 16 +int do_mem_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, size, length; + ulong i, nbytes, linebytes; + u_char *cp; + int rc = 0; + + /* We use the last specified parameters, unless new ones are + * entered. + */ + addr = dp_last_addr; + size = dp_last_size; + length = dp_last_length; + + if (argc < 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if ((flag & CMD_FLAG_REPEAT) == 0) { + /* New command specified. Check for a size specification. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + + /* Address is specified since argc > 1 + */ + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + + /* If another parameter, it is the length to display. + * Length is the number of objects, not number of bytes. + */ + if (argc > 2) + length = simple_strtoul(argv[2], NULL, 16); + } + + /* Print the lines. + * + * We buffer all read data, so we can make sure data is read only + * once, and all accesses are with the specified bus width. + */ + nbytes = length * size; + do { + char linebuf[DISP_LINE_LEN]; + uint *uip = (uint *)linebuf; + ushort *usp = (ushort *)linebuf; + u_char *ucp = (u_char *)linebuf; + + printf("%08lx:", addr); + linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes; + for (i=0; i 0x7e)) + printf("."); + else + printf("%c", *cp); + cp++; + } + printf("\n"); + nbytes -= linebytes; + if (ctrlc()) { + rc = 1; + break; + } + } while (nbytes > 0); + + dp_last_addr = addr; + dp_last_length = length; + dp_last_size = size; + return (rc); +} + +int do_mem_mm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return mod_mem (cmdtp, 1, flag, argc, argv); +} +int do_mem_nm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return mod_mem (cmdtp, 0, flag, argc, argv); +} + +int do_mem_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, size, writeval, count; + + if ((argc < 3) || (argc > 4)) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for size specification. + */ + size = cmd_get_data_size(argv[0], 4); + + /* Address is specified since argc > 1 + */ + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + + /* Get the value to write. + */ + writeval = simple_strtoul(argv[2], NULL, 16); + + /* Count ? */ + if (argc == 4) { + count = simple_strtoul(argv[3], NULL, 16); + } else { + count = 1; + } + + while (count-- > 0) { + if (size == 4) + *((ulong *)addr) = (ulong )writeval; + else if (size == 2) + *((ushort *)addr) = (ushort)writeval; + else + *((u_char *)addr) = (u_char)writeval; + addr += size; + } + return 0; +} + +int do_mem_cmp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong size, addr1, addr2, count, ngood; + int rcode = 0; + + if (argc != 4) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for size specification. + */ + size = cmd_get_data_size(argv[0], 4); + + addr1 = simple_strtoul(argv[1], NULL, 16); + addr1 += base_address; + + addr2 = simple_strtoul(argv[2], NULL, 16); + addr2 += base_address; + + count = simple_strtoul(argv[3], NULL, 16); + + ngood = 0; + + while (count-- > 0) { + if (size == 4) { + ulong word1 = *(ulong *)addr1; + ulong word2 = *(ulong *)addr2; + if (word1 != word2) { + printf("word at 0x%08lx (0x%08lx) " + "!= word at 0x%08lx (0x%08lx)\n", + addr1, word1, addr2, word2); + rcode = 1; + break; + } + } + else if (size == 2) { + ushort hword1 = *(ushort *)addr1; + ushort hword2 = *(ushort *)addr2; + if (hword1 != hword2) { + printf("halfword at 0x%08lx (0x%04x) " + "!= halfword at 0x%08lx (0x%04x)\n", + addr1, hword1, addr2, hword2); + rcode = 1; + break; + } + } + else { + u_char byte1 = *(u_char *)addr1; + u_char byte2 = *(u_char *)addr2; + if (byte1 != byte2) { + printf("byte at 0x%08lx (0x%02x) " + "!= byte at 0x%08lx (0x%02x)\n", + addr1, byte1, addr2, byte2); + rcode = 1; + break; + } + } + ngood++; + addr1 += size; + addr2 += size; + } + + printf("Total of %ld %s%s were the same\n", + ngood, size == 4 ? "word" : size == 2 ? "halfword" : "byte", + ngood == 1 ? "" : "s"); + return rcode; +} + +int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, size, dest, count; + + if (argc != 4) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for size specification. + */ + size = cmd_get_data_size(argv[0], 4); + + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + + dest = simple_strtoul(argv[2], NULL, 16); + dest += base_address; + + count = simple_strtoul(argv[3], NULL, 16); + + if (count == 0) { + puts ("Zero length ???\n"); + return 1; + } + +#ifndef CFG_NO_FLASH + /* check if we are copying to Flash */ + if (addr2info(dest) != NULL) { + int rc; + + printf ("Copy to Flash... "); + + rc = flash_write ((uchar *)addr, dest, count*size); + if (rc != 0) { + flash_perror (rc); + return (1); + } + puts ("done\n"); + return 0; + } +#endif + + while (count-- > 0) { + if (size == 4) + *((ulong *)dest) = *((ulong *)addr); + else if (size == 2) + *((ushort *)dest) = *((ushort *)addr); + else + *((u_char *)dest) = *((u_char *)addr); + addr += size; + dest += size; + } + return 0; +} + +int do_mem_base (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (argc > 1) { + /* Set new base address. + */ + base_address = simple_strtoul(argv[1], NULL, 16); + } + /* Print the current base address. + */ + printf("Base Address: 0x%08lx\n", base_address); + return 0; +} + +int do_mem_loop (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, size, length, i, junk; + volatile uint *longp; + volatile ushort *shortp; + volatile u_char *cp; + + if (argc < 3) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* Check for a size spefication. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + + /* Address is always specified. + */ + addr = simple_strtoul(argv[1], NULL, 16); + + /* Length is the number of objects, not number of bytes. + */ + length = simple_strtoul(argv[2], NULL, 16); + + /* We want to optimize the loops to run as fast as possible. + * If we have only one object, just run infinite loops. + */ + if (length == 1) { + if (size == 4) { + longp = (uint *)addr; + for (;;) + i = *longp; + } + if (size == 2) { + shortp = (ushort *)addr; + for (;;) + i = *shortp; + } + cp = (u_char *)addr; + for (;;) + i = *cp; + } + + if (size == 4) { + for (;;) { + longp = (uint *)addr; + i = length; + while (i-- > 0) + junk = *longp++; + } + } + if (size == 2) { + for (;;) { + shortp = (ushort *)addr; + i = length; + while (i-- > 0) + junk = *shortp++; + } + } + for (;;) { + cp = (u_char *)addr; + i = length; + while (i-- > 0) + junk = *cp++; + } +} + +/* + * Perform a memory test. A more complete alternative test can be + * configured using CFG_ALT_MEMTEST. The complete test loops until + * interrupted by ctrl-c or by a failure of one of the sub-tests. + */ +int do_mem_mtest (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + vu_long *addr, *start, *end; + ulong val; + ulong readback; + +#if defined(CFG_ALT_MEMTEST) + vu_long addr_mask; + vu_long offset; + vu_long test_offset; + vu_long pattern; + vu_long temp; + vu_long anti_pattern; + vu_long num_words; + vu_long *dummy = NULL; + int j; + int iterations = 1; + + static const ulong bitpattern[] = { + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xaaaaaaaa, /* alternating 1/0 */ + }; +#else + ulong incr; + ulong pattern; + int rcode = 0; +#endif + + if (argc > 1) { + start = (ulong *)simple_strtoul(argv[1], NULL, 16); + } else { + start = (ulong *)CFG_MEMTEST_START; + } + + if (argc > 2) { + end = (ulong *)simple_strtoul(argv[2], NULL, 16); + } else { + end = (ulong *)(CFG_MEMTEST_END); + } + + if (argc > 3) { + pattern = (ulong)simple_strtoul(argv[3], NULL, 16); + } else { + pattern = 0; + } + +#if defined(CFG_ALT_MEMTEST) + printf ("Testing %08x ... %08x:\n", (uint)start, (uint)end); + PRINTF("%s:%d: start 0x%p end 0x%p\n", + __FUNCTION__, __LINE__, start, end); + + for (;;) { + if (ctrlc()) { + putc ('\n'); + return 1; + } + + printf("Iteration: %6d\r", iterations); + PRINTF("Iteration: %6d\n", iterations); + iterations++; + + /* + * Data line test: write a pattern to the first + * location, write the 1's complement to a 'parking' + * address (changes the state of the data bus so a + * floating bus doen't give a false OK), and then + * read the value back. Note that we read it back + * into a variable because the next time we read it, + * it might be right (been there, tough to explain to + * the quality guys why it prints a failure when the + * "is" and "should be" are obviously the same in the + * error message). + * + * Rather than exhaustively testing, we test some + * patterns by shifting '1' bits through a field of + * '0's and '0' bits through a field of '1's (i.e. + * pattern and ~pattern). + */ + addr = start; + for (j = 0; j < sizeof(bitpattern)/sizeof(bitpattern[0]); j++) { + val = bitpattern[j]; + for(; val != 0; val <<= 1) { + *addr = val; + *dummy = ~val; /* clear the test data off of the bus */ + readback = *addr; + if(readback != val) { + printf ("FAILURE (data line): " + "expected %08lx, actual %08lx\n", + val, readback); + } + *addr = ~val; + *dummy = val; + readback = *addr; + if(readback != ~val) { + printf ("FAILURE (data line): " + "Is %08lx, should be %08lx\n", + val, readback); + } + } + } + + /* + * Based on code whose Original Author and Copyright + * information follows: Copyright (c) 1998 by Michael + * Barr. This software is placed into the public + * domain and may be used for any purpose. However, + * this notice must not be changed or removed and no + * warranty is either expressed or implied by its + * publication or distribution. + */ + + /* + * Address line test + * + * Description: Test the address bus wiring in a + * memory region by performing a walking + * 1's test on the relevant bits of the + * address and checking for aliasing. + * This test will find single-bit + * address failures such as stuck -high, + * stuck-low, and shorted pins. The base + * address and size of the region are + * selected by the caller. + * + * Notes: For best results, the selected base + * address should have enough LSB 0's to + * guarantee single address bit changes. + * For example, to test a 64-Kbyte + * region, select a base address on a + * 64-Kbyte boundary. Also, select the + * region size as a power-of-two if at + * all possible. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + * + * ## NOTE ## Be sure to specify start and end + * addresses such that addr_mask has + * lots of bits set. For example an + * address range of 01000000 02000000 is + * bad while a range of 01000000 + * 01ffffff is perfect. + */ + addr_mask = ((ulong)end - (ulong)start)/sizeof(vu_long); + pattern = (vu_long) 0xaaaaaaaa; + anti_pattern = (vu_long) 0x55555555; + + PRINTF("%s:%d: addr mask = 0x%.8lx\n", + __FUNCTION__, __LINE__, + addr_mask); + /* + * Write the default pattern at each of the + * power-of-two offsets. + */ + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + start[offset] = pattern; + } + + /* + * Check for address bits stuck high. + */ + test_offset = 0; + start[test_offset] = anti_pattern; + + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if (temp != pattern) { + printf ("\nFAILURE: Address bit stuck high @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + + /* + * Check for addr bits stuck low or shorted. + */ + for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) { + start[test_offset] = anti_pattern; + + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if ((temp != pattern) && (offset != test_offset)) { + printf ("\nFAILURE: Address bit stuck low or shorted @" + " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + } + + /* + * Description: Test the integrity of a physical + * memory device by performing an + * increment/decrement test over the + * entire region. In the process every + * storage bit in the device is tested + * as a zero and a one. The base address + * and the size of the region are + * selected by the caller. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + */ + num_words = ((ulong)end - (ulong)start)/sizeof(vu_long) + 1; + + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + start[offset] = pattern; + } + + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + temp = start[offset]; + if (temp != pattern) { + printf ("\nFAILURE (read/write) @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (ulong)&start[offset], pattern, temp); + return 1; + } + + anti_pattern = ~pattern; + start[offset] = anti_pattern; + } + + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + anti_pattern = ~pattern; + temp = start[offset]; + if (temp != anti_pattern) { + printf ("\nFAILURE (read/write): @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (ulong)&start[offset], anti_pattern, temp); + return 1; + } + start[offset] = 0; + } + } + +#else /* The original, quickie test */ + incr = 1; + for (;;) { + if (ctrlc()) { + putc ('\n'); + return 1; + } + + printf ("\rPattern %08lX Writing..." + "%12s" + "\b\b\b\b\b\b\b\b\b\b", + pattern, ""); + + for (addr=start,val=pattern; addrusage); + return 1; + } + +#ifdef CONFIG_BOOT_RETRY_TIME + reset_cmd_timeout(); /* got a good command to get here */ +#endif + /* We use the last specified parameters, unless new ones are + * entered. + */ + addr = mm_last_addr; + size = mm_last_size; + + if ((flag & CMD_FLAG_REPEAT) == 0) { + /* New command specified. Check for a size specification. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + + /* Address is specified since argc > 1 + */ + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + } + + /* Print the address, followed by value. Then accept input for + * the next value. A non-converted value exits. + */ + do { + printf("%08lx:", addr); + if (size == 4) + printf(" %08x", *((uint *)addr)); + else if (size == 2) + printf(" %04x", *((ushort *)addr)); + else + printf(" %02x", *((u_char *)addr)); + + nbytes = readline (" ? "); + if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) { + /* pressed as only input, don't modify current + * location and move to next. "-" pressed will go back. + */ + if (incrflag) + addr += nbytes ? -size : size; + nbytes = 1; +#ifdef CONFIG_BOOT_RETRY_TIME + reset_cmd_timeout(); /* good enough to not time out */ +#endif + } +#ifdef CONFIG_BOOT_RETRY_TIME + else if (nbytes == -2) { + break; /* timed out, exit the command */ + } +#endif + else { + char *endp; + i = simple_strtoul(console_buffer, &endp, 16); + nbytes = endp - console_buffer; + if (nbytes) { +#ifdef CONFIG_BOOT_RETRY_TIME + /* good enough to not time out + */ + reset_cmd_timeout(); +#endif + if (size == 4) + *((uint *)addr) = i; + else if (size == 2) + *((ushort *)addr) = i; + else + *((u_char *)addr) = i; + if (incrflag) + addr += size; + } + } + } while (nbytes); + + mm_last_addr = addr; + mm_last_size = size; + return 0; +} + +int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, length; + ulong crc; + ulong *ptr; + + if (argc < 3) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + + length = simple_strtoul(argv[2], NULL, 16); + + crc = crc32 (0, (const uchar *)addr, length); + + printf ("CRC32 for %08lx ... %08lx ==> %08lx\n", + addr, addr + length -1, crc); + + if (argc > 3) + { + ptr = (ulong *)simple_strtoul(argv[3], NULL, 16); + *ptr = crc; + } + + return 0; +} + +#endif /* CFG_CMD_MEMORY */ diff --git a/common/cmd_misc.c b/common/cmd_misc.c new file mode 100644 index 0000000000..e3e0e44869 --- /dev/null +++ b/common/cmd_misc.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * Misc functions + */ +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_MISC) + +int do_sleep (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong delay; + + if (argc != 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + delay = simple_strtoul(argv[1], NULL, 10); + + while (delay) { + int i; + for (i=0; i<1000; ++i) { + if (ctrlc ()) { + return (-1); + } + udelay (1000); + } + --delay; + } + return 0; +} + +#endif /* CFG_CMD_MISC */ diff --git a/common/cmd_net.c b/common/cmd_net.c new file mode 100644 index 0000000000..c9ce85ffe3 --- /dev/null +++ b/common/cmd_net.c @@ -0,0 +1,164 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +/* + * Boot support + */ +#include +#include +#include +#include + +#if (CONFIG_COMMANDS & CFG_CMD_NET) + +# if (CONFIG_COMMANDS & CFG_CMD_AUTOSCRIPT) +# include +# endif + +extern int do_bootm (cmd_tbl_t *, int, int, char *[]); + +static int netboot_common (int, cmd_tbl_t *, int , char *[]); + +int do_bootp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return netboot_common (BOOTP, cmdtp, argc, argv); +} + +int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return netboot_common (TFTP, cmdtp, argc, argv); +} + +int do_rarpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return netboot_common (RARP, cmdtp, argc, argv); +} + +#if (CONFIG_COMMANDS & CFG_CMD_DHCP) +int do_dhcp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + return netboot_common(DHCP, cmdtp, argc, argv); +} +#endif /* CFG_CMD_DHCP */ + +static void netboot_update_env(void) +{ + char tmp[16] ; + + if (NetOurGatewayIP) { + ip_to_string (NetOurGatewayIP, tmp); + setenv("gatewayip", tmp); + } + + if (NetOurSubnetMask) { + ip_to_string (NetOurSubnetMask, tmp); + setenv("netmask", tmp); + } + + if (NetOurHostName[0]) + setenv("hostname", NetOurHostName); + + if (NetOurRootPath[0]) + setenv("rootpath", NetOurRootPath); + + if (NetOurIP) { + ip_to_string (NetOurIP, tmp); + setenv("ipaddr", tmp); + } + + if (NetServerIP) { + ip_to_string (NetServerIP, tmp); + setenv("serverip", tmp); + } + + if (NetOurDNSIP) { + ip_to_string (NetOurDNSIP, tmp); + setenv("dnsip", tmp); + } +} +static int +netboot_common (int proto, cmd_tbl_t *cmdtp, int argc, char *argv[]) +{ + char *s; + int rcode = 0; + int size; + + /* pre-set load_addr */ + if ((s = getenv("loadaddr")) != NULL) { + load_addr = simple_strtoul(s, NULL, 16); + } + + switch (argc) { + case 1: + break; + + case 2: /* only one arg - accept two forms: + * just load address, or just boot file name. + * The latter form must be written "filename" here. + */ + if (argv[1][0] == '"') { /* just boot filename */ + copy_filename (BootFile, argv[1], sizeof(BootFile)); + } else { /* load address */ + load_addr = simple_strtoul(argv[1], NULL, 16); + } + break; + + case 3: load_addr = simple_strtoul(argv[1], NULL, 16); + copy_filename (BootFile, argv[2], sizeof(BootFile)); + + break; + + default: printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if ((size = NetLoop(proto)) == 0) + return 1; + + /* NetLoop ok, update environment */ + netboot_update_env(); + + /* flush cache */ + flush_cache(load_addr, size); + + /* Loading ok, check if we should attempt an auto-start */ + if (((s = getenv("autostart")) != NULL) && (strcmp(s,"yes") == 0)) { + char *local_args[2]; + local_args[0] = argv[0]; + local_args[1] = NULL; + + printf ("Automatic boot of image at addr 0x%08lX ...\n", + load_addr); + rcode = do_bootm (cmdtp, 0, 1, local_args); + } + +#ifdef CONFIG_AUTOSCRIPT + if (((s = getenv("autoscript")) != NULL) && (strcmp(s,"yes") == 0)) { + printf("Running autoscript at addr 0x%08lX ...\n", load_addr); + rcode = autoscript (load_addr); + } +#endif + return rcode; +} + +#endif /* CFG_CMD_NET */ -- 2.39.5