mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-27 23:20:26 +09:00
Initial revision
This commit is contained in:
parent
f8cac651b3
commit
3863585bb1
98
common/cmd_cache.c
Normal file
98
common/cmd_cache.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
#include <cmd_cache.h>
|
||||
|
||||
#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 */
|
61
common/cmd_console.c
Normal file
61
common/cmd_console.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
#include <devices.h>
|
||||
|
||||
#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 */
|
189
common/cmd_date.c
Normal file
189
common/cmd_date.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#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 */
|
103
common/cmd_dcr.c
Normal file
103
common/cmd_dcr.c
Normal file
@ -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 <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <cmd_dcr.h>
|
||||
|
||||
#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) {
|
||||
/*
|
||||
* <CR> 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 */
|
49
common/cmd_dtt.c
Normal file
49
common/cmd_dtt.c
Normal file
@ -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 <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <cmd_dtt.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_DTT)
|
||||
|
||||
#include <dtt.h>
|
||||
|
||||
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 */
|
353
common/cmd_eeprom.c
Normal file
353
common/cmd_eeprom.c
Normal file
@ -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 <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <i2c.h>
|
||||
|
||||
#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 */
|
735
common/cmd_fdc.c
Normal file
735
common/cmd_fdc.c
Normal file
@ -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 <common.h>
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <image.h>
|
||||
|
||||
|
||||
#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 <rtc.h>
|
||||
#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;i<pCMD->cmdlen;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;i<pCMD->resultlen;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<<pFG->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;i<len;i++) {
|
||||
timeout=FDC_TIME_OUT;
|
||||
do {
|
||||
c=read_fdc_reg(FDC_MSR);
|
||||
if((c&0xC0)==0xC0) {
|
||||
bufferw[i]=read_fdc_reg(FDC_FIFO);
|
||||
break;
|
||||
}
|
||||
if((c&0xC0)==0x80) { /* output */
|
||||
PRINTF("Transfer error transfered: at %ld, MSR=%02X\n",i,c);
|
||||
if(i>6) {
|
||||
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<<drives);
|
||||
pCMD->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<<drives);
|
||||
}
|
||||
stop_fdc_drive(pCMD);
|
||||
for(i=0;i<4;i++) {
|
||||
PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
|
||||
((state&(1<<i))==(1<<i)) ? "":"not ",
|
||||
((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
|
||||
((state&(0x10<<i))==(0x10<<i)) ? pFG->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<<boot_drive))==0) {
|
||||
/* drive not available */
|
||||
printf("\n** Drive %d not availabe **\n",boot_drive);
|
||||
return 1;
|
||||
}
|
||||
if((pCMD->flags&(0x10<<boot_drive))==0) {
|
||||
/* no disk inserted */
|
||||
printf("\n** No disk inserted in drive %d **\n",boot_drive);
|
||||
return 1;
|
||||
}
|
||||
/* ok, we have a valid source */
|
||||
pCMD->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 */
|
||||
|
||||
|
850
common/cmd_mem.c
Normal file
850
common/cmd_mem.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
#include <cmd_mem.h>
|
||||
|
||||
#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<linebytes; i+= size) {
|
||||
if (size == 4) {
|
||||
printf(" %08x", (*uip++ = *((uint *)addr)));
|
||||
} else if (size == 2) {
|
||||
printf(" %04x", (*usp++ = *((ushort *)addr)));
|
||||
} else {
|
||||
printf(" %02x", (*ucp++ = *((u_char *)addr)));
|
||||
}
|
||||
addr += size;
|
||||
}
|
||||
printf(" ");
|
||||
cp = linebuf;
|
||||
for (i=0; i<linebytes; i++) {
|
||||
if ((*cp < 0x20) || (*cp > 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; addr<end; addr++) {
|
||||
*addr = val;
|
||||
val += incr;
|
||||
}
|
||||
|
||||
printf("Reading...");
|
||||
|
||||
for (addr=start,val=pattern; addr<end; addr++) {
|
||||
readback = *addr;
|
||||
if (readback != val) {
|
||||
printf ("\nMem error @ 0x%08X: "
|
||||
"found %08lX, expected %08lX\n",
|
||||
(uint)addr, readback, val);
|
||||
rcode = 1;
|
||||
}
|
||||
val += incr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flip the pattern each time to make lots of zeros and
|
||||
* then, the next time, lots of ones. We decrement
|
||||
* the "negative" patterns and increment the "positive"
|
||||
* patterns to preserve this feature.
|
||||
*/
|
||||
if(pattern & 0x80000000) {
|
||||
pattern = -pattern; /* complement & increment */
|
||||
}
|
||||
else {
|
||||
pattern = ~pattern;
|
||||
}
|
||||
incr = -incr;
|
||||
}
|
||||
return rcode;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Modify memory.
|
||||
*
|
||||
* Syntax:
|
||||
* mm{.b, .w, .l} {addr}
|
||||
* nm{.b, .w, .l} {addr}
|
||||
*/
|
||||
static int
|
||||
mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[])
|
||||
{
|
||||
ulong addr, size, i;
|
||||
int nbytes;
|
||||
extern char console_buffer[];
|
||||
|
||||
if (argc != 2) {
|
||||
printf ("Usage:\n%s\n", cmdtp->usage);
|
||||
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] == '-')) {
|
||||
/* <CR> 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 */
|
56
common/cmd_misc.c
Normal file
56
common/cmd_misc.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
|
||||
#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 */
|
164
common/cmd_net.c
Normal file
164
common/cmd_net.c
Normal file
@ -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 <common.h>
|
||||
#include <command.h>
|
||||
#include <cmd_net.h>
|
||||
#include <net.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_NET)
|
||||
|
||||
# if (CONFIG_COMMANDS & CFG_CMD_AUTOSCRIPT)
|
||||
# include <cmd_autoscript.h>
|
||||
# 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 */
|
Loading…
Reference in New Issue
Block a user