Initial revision
diff --git a/common/cmd_doc.c b/common/cmd_doc.c
new file mode 100644
index 0000000..37d0fbd
--- /dev/null
+++ b/common/cmd_doc.c
@@ -0,0 +1,1563 @@
+/*
+ * Driver for Disk-On-Chip 2000 and Millennium
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/doc2000.h>
+#include <linux/mtd/nftl.h>
+
+#ifdef CFG_DOC_SUPPORT_2000
+#define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
+#else
+#define DoC_is_2000(doc) (0)
+#endif
+
+#ifdef CFG_DOC_SUPPORT_MILLENNIUM
+#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
+#else
+#define DoC_is_Millennium(doc) (0)
+#endif
+
+/* CFG_DOC_PASSIVE_PROBE:
+ In order to ensure that the BIOS checksum is correct at boot time, and
+ hence that the onboard BIOS extension gets executed, the DiskOnChip
+ goes into reset mode when it is read sequentially: all registers
+ return 0xff until the chip is woken up again by writing to the
+ DOCControl register.
+
+ Unfortunately, this means that the probe for the DiskOnChip is unsafe,
+ because one of the first things it does is write to where it thinks
+ the DOCControl register should be - which may well be shared memory
+ for another device. I've had machines which lock up when this is
+ attempted. Hence the possibility to do a passive probe, which will fail
+ to detect a chip in reset mode, but is at least guaranteed not to lock
+ the machine.
+
+ If you have this problem, uncomment the following line:
+#define CFG_DOC_PASSIVE_PROBE
+*/
+
+#undef DOC_DEBUG
+#undef ECC_DEBUG
+#undef PSYCHO_DEBUG
+#undef NFTL_DEBUG
+
+static struct DiskOnChip doc_dev_desc[CFG_MAX_DOC_DEVICE];
+
+/* Current DOC Device */
+static int curr_device = -1;
+
+/* ------------------------------------------------------------------------- */
+
+int do_doc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int rcode = 0;
+
+ switch (argc) {
+ case 0:
+ case 1:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ case 2:
+ if (strcmp(argv[1],"info") == 0) {
+ int i;
+
+ putc ('\n');
+
+ for (i=0; i<CFG_MAX_DOC_DEVICE; ++i) {
+ if(doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN)
+ continue; /* list only known devices */
+ printf ("Device %d: ", i);
+ doc_print(&doc_dev_desc[i]);
+ }
+ return 0;
+
+ } else if (strcmp(argv[1],"device") == 0) {
+ if ((curr_device < 0) || (curr_device >= CFG_MAX_DOC_DEVICE)) {
+ puts ("\nno devices available\n");
+ return 1;
+ }
+ printf ("\nDevice %d: ", curr_device);
+ doc_print(&doc_dev_desc[curr_device]);
+ return 0;
+ }
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ case 3:
+ if (strcmp(argv[1],"device") == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ printf ("\nDevice %d: ", dev);
+ if (dev >= CFG_MAX_DOC_DEVICE) {
+ puts ("unknown device\n");
+ return 1;
+ }
+ doc_print(&doc_dev_desc[dev]);
+ /*doc_print (dev);*/
+
+ if (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN) {
+ return 1;
+ }
+
+ curr_device = dev;
+
+ puts ("... is now current device\n");
+
+ return 0;
+ }
+
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ default:
+ /* at least 4 args */
+
+ if (strcmp(argv[1],"read") == 0 || strcmp(argv[1],"write") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong off = simple_strtoul(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ int cmd = (strcmp(argv[1],"read") == 0);
+ int ret, total;
+
+ printf ("\nDOC %s: device %d offset %ld, size %ld ... ",
+ cmd ? "read" : "write", curr_device, off, size);
+
+ ret = doc_rw(doc_dev_desc + curr_device, cmd, off, size,
+ &total, (u_char*)addr);
+
+ printf ("%d bytes %s: %s\n", total, cmd ? "read" : "write",
+ ret ? "ERROR" : "OK");
+
+ return ret;
+ } else if (strcmp(argv[1],"erase") == 0) {
+ ulong off = simple_strtoul(argv[2], NULL, 16);
+ ulong size = simple_strtoul(argv[3], NULL, 16);
+ int ret;
+
+ printf ("\nDOC erase: device %d offset %ld, size %ld ... ",
+ curr_device, off, size);
+
+ ret = doc_erase (doc_dev_desc + curr_device, off, size);
+
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret;
+ } else {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ rcode = 1;
+ }
+
+ return rcode;
+ }
+}
+
+int do_docboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev;
+ ulong cnt;
+ ulong addr;
+ ulong offset = 0;
+ image_header_t *hdr;
+ int rcode = 0;
+
+ switch (argc) {
+ case 1:
+ addr = CFG_LOAD_ADDR;
+ boot_device = getenv ("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv ("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ case 4:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ offset = simple_strtoul(argv[3], NULL, 16);
+ break;
+ default:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (!boot_device) {
+ puts ("\n** No boot device **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+
+ if ((dev >= CFG_MAX_DOC_DEVICE) ||
+ (doc_dev_desc[dev].ChipID == DOC_ChipID_UNKNOWN)) {
+ printf ("\n** Device %d not available\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ printf ("\nLoading from device %d: %s at 0x%lX (offset 0x%lX)\n",
+ dev, doc_dev_desc[dev].name, doc_dev_desc[dev].physadr,
+ offset);
+
+ if (doc_rw (doc_dev_desc + dev, 1, offset,
+ SECTORSIZE, NULL, (u_char *)addr)) {
+ printf ("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ hdr = (image_header_t *)addr;
+
+ if (hdr->ih_magic == IH_MAGIC) {
+
+ print_image_hdr (hdr);
+
+ cnt = (hdr->ih_size + sizeof(image_header_t));
+ cnt -= SECTORSIZE;
+ } else {
+ puts ("\n** Bad Magic Number **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (doc_rw (doc_dev_desc + dev, 1, offset + SECTORSIZE, cnt,
+ NULL, (u_char *)(addr+SECTORSIZE))) {
+ printf ("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* 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 = 1;
+ }
+ return rcode;
+}
+
+int doc_rw (struct DiskOnChip* this, int cmd,
+ loff_t from, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ int noecc, ret = 0, n, total = 0;
+ char eccbuf[6];
+
+ while(len) {
+ /* The ECC will not be calculated correctly if
+ less than 512 is written or read */
+ noecc = (from != (from | 0x1ff) + 1) || (len < 0x200);
+
+ if (cmd)
+ ret = doc_read_ecc(this, from, len,
+ &n, (u_char*)buf,
+ noecc ? NULL : eccbuf);
+ else
+ ret = doc_write_ecc(this, from, len,
+ &n, (u_char*)buf,
+ noecc ? NULL : eccbuf);
+
+ if (ret)
+ break;
+
+ from += n;
+ buf += n;
+ total += n;
+ len -= n;
+ }
+
+ if (retlen)
+ *retlen = total;
+
+ return ret;
+}
+
+void doc_print(struct DiskOnChip *this) {
+ printf("%s at 0x%lX,\n"
+ "\t %d chip%s %s, size %d MB, \n"
+ "\t total size %ld MB, sector size %ld kB\n",
+ this->name, this->physadr, this->numchips,
+ this->numchips>1 ? "s" : "", this->chips_name,
+ 1 << (this->chipshift - 20),
+ this->totlen >> 20, this->erasesize >> 10);
+
+ if (this->nftl_found) {
+ struct NFTLrecord *nftl = &this->nftl;
+ unsigned long bin_size, flash_size;
+
+ bin_size = nftl->nb_boot_blocks * this->erasesize;
+ flash_size = (nftl->nb_blocks - nftl->nb_boot_blocks) * this->erasesize;
+
+ printf("\t NFTL boot record:\n"
+ "\t Binary partition: size %ld%s\n"
+ "\t Flash disk partition: size %ld%s, offset 0x%lx\n",
+ bin_size > (1 << 20) ? bin_size >> 20 : bin_size >> 10,
+ bin_size > (1 << 20) ? "MB" : "kB",
+ flash_size > (1 << 20) ? flash_size >> 20 : flash_size >> 10,
+ flash_size > (1 << 20) ? "MB" : "kB", bin_size);
+ } else {
+ puts ("\t No NFTL boot record found.\n");
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* This function is needed to avoid calls of the __ashrdi3 function. */
+static int shr(int val, int shift) {
+ return val >> shift;
+}
+
+/* Perform the required delay cycles by reading from the appropriate register */
+static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles)
+{
+ volatile char dummy;
+ int i;
+
+ for (i = 0; i < cycles; i++) {
+ if (DoC_is_Millennium(doc))
+ dummy = ReadDOC(doc->virtadr, NOP);
+ else
+ dummy = ReadDOC(doc->virtadr, DOCStatus);
+ }
+
+}
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(struct DiskOnChip *doc)
+{
+ unsigned long docptr = doc->virtadr;
+ unsigned long start = get_timer(0);
+
+#ifdef PSYCHO_DEBUG
+ puts ("_DoC_WaitReady called for out-of-line wait\n");
+#endif
+
+ /* Out-of-line routine to wait for chip response */
+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+#ifdef CFG_DOC_SHORT_TIMEOUT
+ /* it seems that after a certain time the DoC deasserts
+ * the CDSN_CTRL_FR_B although it is not ready...
+ * using a short timout solve this (timer increments every ms) */
+ if (get_timer(start) > 10) {
+ return DOC_ETIMEOUT;
+ }
+#else
+ if (get_timer(start) > 10 * 1000) {
+ puts ("_DoC_WaitReady timed out.\n");
+ return DOC_ETIMEOUT;
+ }
+#endif
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static int DoC_WaitReady(struct DiskOnChip *doc)
+{
+ unsigned long docptr = doc->virtadr;
+ /* This is inline, to optimise the common case, where it's ready instantly */
+ int ret = 0;
+
+ /* 4 read form NOP register should be issued in prior to the read from CDSNControl
+ see Software Requirement 11.4 item 2. */
+ DoC_Delay(doc, 4);
+
+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+ /* Call the out-of-line routine to wait */
+ ret = _DoC_WaitReady(doc);
+
+ /* issue 2 read from NOP register after reading from CDSNControl register
+ see Software Requirement 11.4 item 2. */
+ DoC_Delay(doc, 2);
+
+ return ret;
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
+ bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+ required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+ unsigned char xtraflags)
+{
+ unsigned long docptr = doc->virtadr;
+
+ if (DoC_is_2000(doc))
+ xtraflags |= CDSN_CTRL_FLASH_IO;
+
+ /* Assert the CLE (Command Latch Enable) line to the flash chip */
+ WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ if (DoC_is_Millennium(doc))
+ WriteDOC(command, docptr, CDSNSlowIO);
+
+ /* Send the command */
+ WriteDOC_(command, docptr, doc->ioreg);
+
+ /* Lower the CLE line */
+ WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ /* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
+ return DoC_WaitReady(doc);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
+ bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
+ required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
+
+static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
+ unsigned char xtraflags1, unsigned char xtraflags2)
+{
+ unsigned long docptr;
+ int i;
+
+ docptr = doc->virtadr;
+
+ if (DoC_is_2000(doc))
+ xtraflags1 |= CDSN_CTRL_FLASH_IO;
+
+ /* Assert the ALE (Address Latch Enable) line to the flash chip */
+ WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
+
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ /* Send the address */
+ /* Devices with 256-byte page are addressed as:
+ Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+ * there is no device on the market with page256
+ and more than 24 bits.
+ Devices with 512-byte page are addressed as:
+ Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+ * 25-31 is sent only if the chip support it.
+ * bit 8 changes the read command to be sent
+ (NAND_CMD_READ0 or NAND_CMD_READ1).
+ */
+
+ if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) {
+ if (DoC_is_Millennium(doc))
+ WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+ WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+ }
+
+ if (doc->page256) {
+ ofs = ofs >> 8;
+ } else {
+ ofs = ofs >> 9;
+ }
+
+ if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+ for (i = 0; i < doc->pageadrlen; i++, ofs = ofs >> 8) {
+ if (DoC_is_Millennium(doc))
+ WriteDOC(ofs & 0xff, docptr, CDSNSlowIO);
+ WriteDOC_(ofs & 0xff, docptr, doc->ioreg);
+ }
+ }
+
+ DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */
+
+ /* FIXME: The SlowIO's for millennium could be replaced by
+ a single WritePipeTerm here. mf. */
+
+ /* Lower the ALE line */
+ WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr,
+ CDSNControl);
+
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ /* Wait for the chip to respond - Software requirement 11.4.1 */
+ return DoC_WaitReady(doc);
+}
+
+/* Read a buffer from DoC, taking care of Millennium odditys */
+static void DoC_ReadBuf(struct DiskOnChip *doc, u_char * buf, int len)
+{
+ volatile int dummy;
+ int modulus = 0xffff;
+ unsigned long docptr;
+ int i;
+
+ docptr = doc->virtadr;
+
+ if (len <= 0)
+ return;
+
+ if (DoC_is_Millennium(doc)) {
+ /* Read the data via the internal pipeline through CDSN IO register,
+ see Pipelined Read Operations 11.3 */
+ dummy = ReadDOC(docptr, ReadPipeInit);
+
+ /* Millennium should use the LastDataRead register - Pipeline Reads */
+ len--;
+
+ /* This is needed for correctly ECC calculation */
+ modulus = 0xff;
+ }
+
+ for (i = 0; i < len; i++)
+ buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus));
+
+ if (DoC_is_Millennium(doc)) {
+ buf[i] = ReadDOC(docptr, LastDataRead);
+ }
+}
+
+/* Write a buffer to DoC, taking care of Millennium odditys */
+static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
+{
+ unsigned long docptr;
+ int i;
+
+ docptr = doc->virtadr;
+
+ if (len <= 0)
+ return;
+
+ for (i = 0; i < len; i++)
+ WriteDOC_(buf[i], docptr, doc->ioreg + i);
+
+ if (DoC_is_Millennium(doc)) {
+ WriteDOC(0x00, docptr, WritePipeTerm);
+ }
+}
+
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
+{
+ unsigned long docptr = doc->virtadr;
+
+ /* Software requirement 11.4.4 before writing DeviceSelect */
+ /* Deassert the CE line to eliminate glitches on the FCE# outputs */
+ WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl);
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ /* Select the individual flash chip requested */
+ WriteDOC(chip, docptr, CDSNDeviceSelect);
+ DoC_Delay(doc, 4);
+
+ /* Reassert the CE line */
+ WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr,
+ CDSNControl);
+ DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */
+
+ /* Wait for it to be ready */
+ return DoC_WaitReady(doc);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
+{
+ unsigned long docptr = doc->virtadr;
+
+ /* Select the floor (bank) of chips required */
+ WriteDOC(floor, docptr, FloorSelect);
+
+ /* Wait for the chip to be ready */
+ return DoC_WaitReady(doc);
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+ int mfr, id, i;
+ volatile char dummy;
+
+ /* Page in the required floor/chip */
+ DoC_SelectFloor(doc, floor);
+ DoC_SelectChip(doc, chip);
+
+ /* Reset the chip */
+ if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+ printf("DoC_Command (reset) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ return 0;
+ }
+
+
+ /* Read the NAND chip ID: 1. Send ReadID command */
+ if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {
+#ifdef DOC_DEBUG
+ printf("DoC_Command (ReadID) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 2. Send address byte zero */
+ DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0);
+
+ /* Read the manufacturer and device id codes from the device */
+
+ /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+ dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+ DoC_Delay(doc, 2);
+ mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+ /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
+ dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+ DoC_Delay(doc, 2);
+ id = ReadDOC_(doc->virtadr, doc->ioreg);
+
+ /* No response - return failure */
+ if (mfr == 0xff || mfr == 0)
+ return 0;
+
+ /* Check it's the same as the first chip we identified.
+ * M-Systems say that any given DiskOnChip device should only
+ * contain _one_ type of flash part, although that's not a
+ * hardware restriction. */
+ if (doc->mfr) {
+ if (doc->mfr == mfr && doc->id == id)
+ return 1; /* This is another the same the first */
+ else
+ printf("Flash chip at floor %d, chip %d is different:\n",
+ floor, chip);
+ }
+
+ /* Print and store the manufacturer and ID codes. */
+ for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+ if (mfr == nand_flash_ids[i].manufacture_id &&
+ id == nand_flash_ids[i].model_id) {
+#ifdef DOC_DEBUG
+ printf("Flash chip found: Manufacturer ID: %2.2X, "
+ "Chip ID: %2.2X (%s)\n", mfr, id,
+ nand_flash_ids[i].name);
+#endif
+ if (!doc->mfr) {
+ doc->mfr = mfr;
+ doc->id = id;
+ doc->chipshift =
+ nand_flash_ids[i].chipshift;
+ doc->page256 = nand_flash_ids[i].page256;
+ doc->pageadrlen =
+ nand_flash_ids[i].pageadrlen;
+ doc->erasesize =
+ nand_flash_ids[i].erasesize;
+ doc->chips_name =
+ nand_flash_ids[i].name;
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+
+#ifdef DOC_DEBUG
+ /* We haven't fully identified the chip. Print as much as we know. */
+ printf("Unknown flash chip found: %2.2X %2.2X\n",
+ id, mfr);
+#endif
+
+ return 0;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+
+static void DoC_ScanChips(struct DiskOnChip *this)
+{
+ int floor, chip;
+ int numchips[MAX_FLOORS];
+ int maxchips = MAX_CHIPS;
+ int ret = 1;
+
+ this->numchips = 0;
+ this->mfr = 0;
+ this->id = 0;
+
+ if (DoC_is_Millennium(this))
+ maxchips = MAX_CHIPS_MIL;
+
+ /* For each floor, find the number of valid chips it contains */
+ for (floor = 0; floor < MAX_FLOORS; floor++) {
+ ret = 1;
+ numchips[floor] = 0;
+ for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
+ ret = DoC_IdentChip(this, floor, chip);
+ if (ret) {
+ numchips[floor]++;
+ this->numchips++;
+ }
+ }
+ }
+
+ /* If there are none at all that we recognise, bail */
+ if (!this->numchips) {
+ puts ("No flash chips recognised.\n");
+ return;
+ }
+
+ /* Allocate an array to hold the information for each chip */
+ this->chips = malloc(sizeof(struct Nand) * this->numchips);
+ if (!this->chips) {
+ puts ("No memory for allocating chip info structures\n");
+ return;
+ }
+
+ ret = 0;
+
+ /* Fill out the chip array with {floor, chipno} for each
+ * detected chip in the device. */
+ for (floor = 0; floor < MAX_FLOORS; floor++) {
+ for (chip = 0; chip < numchips[floor]; chip++) {
+ this->chips[ret].floor = floor;
+ this->chips[ret].chip = chip;
+ this->chips[ret].curadr = 0;
+ this->chips[ret].curmode = 0x50;
+ ret++;
+ }
+ }
+
+ /* Calculate and print the total size of the device */
+ this->totlen = this->numchips * (1 << this->chipshift);
+
+#ifdef DOC_DEBUG
+ printf("%d flash chips found. Total DiskOnChip size: %ld MB\n",
+ this->numchips, this->totlen >> 20);
+#endif
+}
+
+/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
+ * various device information of the NFTL partition and Bad Unit Table. Update
+ * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
+ * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
+ */
+static int find_boot_record(struct NFTLrecord *nftl)
+{
+ struct nftl_uci1 h1;
+ struct nftl_oob oob;
+ unsigned int block, boot_record_count = 0;
+ int retlen;
+ u8 buf[SECTORSIZE];
+ struct NFTLMediaHeader *mh = &nftl->MediaHdr;
+ unsigned int i;
+
+ nftl->MediaUnit = BLOCK_NIL;
+ nftl->SpareMediaUnit = BLOCK_NIL;
+
+ /* search for a valid boot record */
+ for (block = 0; block < nftl->nb_blocks; block++) {
+ int ret;
+
+ /* Check for ANAND header first. Then can whinge if it's found but later
+ checks fail */
+ if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
+ &retlen, buf, NULL))) {
+ static int warncount = 5;
+
+ if (warncount) {
+ printf("Block read at 0x%x failed\n", block * nftl->EraseSize);
+ if (!--warncount)
+ puts ("Further failures for this block will not be printed\n");
+ }
+ continue;
+ }
+
+ if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
+ /* ANAND\0 not found. Continue */
+#ifdef PSYCHO_DEBUG
+ printf("ANAND header not found at 0x%x\n", block * nftl->EraseSize);
+#endif
+ continue;
+ }
+
+#ifdef NFTL_DEBUG
+ printf("ANAND header found at 0x%x\n", block * nftl->EraseSize);
+#endif
+
+ /* To be safer with BIOS, also use erase mark as discriminant */
+ if ((ret = doc_read_oob(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+ 8, &retlen, (char *)&h1) < 0)) {
+#ifdef NFTL_DEBUG
+ printf("ANAND header found at 0x%x, but OOB data read failed\n",
+ block * nftl->EraseSize);
+#endif
+ continue;
+ }
+
+ /* OK, we like it. */
+
+ if (boot_record_count) {
+ /* We've already processed one. So we just check if
+ this one is the same as the first one we found */
+ if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
+#ifdef NFTL_DEBUG
+ printf("NFTL Media Headers at 0x%x and 0x%x disagree.\n",
+ nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
+#endif
+ /* if (debug) Print both side by side */
+ return -1;
+ }
+ if (boot_record_count == 1)
+ nftl->SpareMediaUnit = block;
+
+ boot_record_count++;
+ continue;
+ }
+
+ /* This is the first we've seen. Copy the media header structure into place */
+ memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
+
+ /* Do some sanity checks on it */
+ if (mh->UnitSizeFactor != 0xff) {
+ puts ("Sorry, we don't support UnitSizeFactor "
+ "of != 1 yet.\n");
+ return -1;
+ }
+
+ nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
+ if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
+ printf ("NFTL Media Header sanity check failed:\n"
+ "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
+ nftl->nb_boot_blocks, nftl->nb_blocks);
+ return -1;
+ }
+
+ nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
+ if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
+ printf ("NFTL Media Header sanity check failed:\n"
+ "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
+ nftl->numvunits,
+ nftl->nb_blocks,
+ nftl->nb_boot_blocks);
+ return -1;
+ }
+
+ nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
+
+ /* If we're not using the last sectors in the device for some reason,
+ reduce nb_blocks accordingly so we forget they're there */
+ nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
+
+ /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
+ for (i = 0; i < nftl->nb_blocks; i++) {
+ if ((i & (SECTORSIZE - 1)) == 0) {
+ /* read one sector for every SECTORSIZE of blocks */
+ if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize +
+ i + SECTORSIZE, SECTORSIZE,
+ &retlen, buf, (char *)&oob)) < 0) {
+ puts ("Read of bad sector table failed\n");
+ return -1;
+ }
+ }
+ /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
+ if (buf[i & (SECTORSIZE - 1)] != 0xff)
+ nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+ }
+
+ nftl->MediaUnit = block;
+ boot_record_count++;
+
+ } /* foreach (block) */
+
+ return boot_record_count?0:-1;
+}
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoC2k_init(struct DiskOnChip* this)
+{
+ struct NFTLrecord *nftl;
+
+ switch (this->ChipID) {
+ case DOC_ChipID_Doc2k:
+ this->name = "DiskOnChip 2000";
+ this->ioreg = DoC_2k_CDSN_IO;
+ break;
+ case DOC_ChipID_DocMil:
+ this->name = "DiskOnChip Millennium";
+ this->ioreg = DoC_Mil_CDSN_IO;
+ break;
+ }
+
+#ifdef DOC_DEBUG
+ printf("%s found at address 0x%lX\n", this->name,
+ this->physadr);
+#endif
+
+ this->totlen = 0;
+ this->numchips = 0;
+
+ this->curfloor = -1;
+ this->curchip = -1;
+
+ /* Ident all the chips present. */
+ DoC_ScanChips(this);
+
+ nftl = &this->nftl;
+
+ /* Get physical parameters */
+ nftl->EraseSize = this->erasesize;
+ nftl->nb_blocks = this->totlen / this->erasesize;
+ nftl->mtd = this;
+
+ if (find_boot_record(nftl) != 0)
+ this->nftl_found = 0;
+ else
+ this->nftl_found = 1;
+
+ printf("%s @ 0x%lX, %ld MB\n", this->name, this->physadr, this->totlen >> 20);
+}
+
+int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * eccbuf)
+{
+ unsigned long docptr;
+ struct Nand *mychip;
+ unsigned char syndrome[6];
+ volatile char dummy;
+ int i, len256 = 0, ret=0;
+
+ docptr = this->virtadr;
+
+ /* Don't allow read past end of device */
+ if (from >= this->totlen) {
+ puts ("Out of flash\n");
+ return DOC_EINVAL;
+ }
+
+ /* Don't allow a single read to cross a 512-byte block boundary */
+ if (from + len > ((from | 0x1ff) + 1))
+ len = ((from | 0x1ff) + 1) - from;
+
+ /* The ECC will not be calculated correctly if less than 512 is read */
+ if (len != 0x200 && eccbuf)
+ printf("ECC needs a full sector read (adr: %lx size %lx)\n",
+ (long) from, (long) len);
+
+#ifdef PHYCH_DEBUG
+ printf("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len);
+#endif
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[shr(from, this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ DoC_Command(this,
+ (!this->page256
+ && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+ CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+ CDSN_CTRL_ECC_IO);
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+ } else {
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ }
+
+ /* treat crossing 256-byte sector for 2M x 8bits devices */
+ if (this->page256 && from + len > (from | 0xff) + 1) {
+ len256 = (from | 0xff) + 1 - from;
+ DoC_ReadBuf(this, buf, len256);
+
+ DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+ CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
+ }
+
+ DoC_ReadBuf(this, &buf[len256], len - len256);
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ if (eccbuf) {
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ /* Note: this will work even with 2M x 8bit devices as */
+ /* they have 8 bytes of OOB per 256 page. mf. */
+ DoC_ReadBuf(this, eccbuf, 6);
+
+ /* Flush the pipeline */
+ if (DoC_is_Millennium(this)) {
+ dummy = ReadDOC(docptr, ECCConf);
+ dummy = ReadDOC(docptr, ECCConf);
+ i = ReadDOC(docptr, ECCConf);
+ } else {
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ i = ReadDOC(docptr, 2k_ECCStatus);
+ }
+
+ /* Check the ECC Status */
+ if (i & 0x80) {
+ int nb_errors;
+ /* There was an ECC error */
+#ifdef ECC_DEBUG
+ printf("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+#endif
+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
+ These syndrome will be all ZERO when there is no error */
+ for (i = 0; i < 6; i++) {
+ syndrome[i] =
+ ReadDOC(docptr, ECCSyndrome0 + i);
+ }
+ nb_errors = doc_decode_ecc(buf, syndrome);
+
+#ifdef ECC_DEBUG
+ printf("Errors corrected: %x\n", nb_errors);
+#endif
+ if (nb_errors < 0) {
+ /* We return error, but have actually done the read. Not that
+ this can be told to user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by checking *retlen */
+ printf("ECC Errors at %lx\n", (long)from);
+ ret = DOC_EECC;
+ }
+ }
+
+#ifdef PSYCHO_DEBUG
+ printf("ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+ eccbuf[3], eccbuf[4], eccbuf[5]);
+#endif
+
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+ }
+
+ /* according to 11.4.1, we need to wait for the busy line
+ * drop if we read to the end of the page. */
+ if(0 == ((from + *retlen) & 0x1ff))
+ {
+ DoC_WaitReady(this);
+ }
+
+ return ret;
+}
+
+int doc_write_ecc(struct DiskOnChip* this, loff_t to, size_t len,
+ size_t * retlen, const u_char * buf,
+ u_char * eccbuf)
+{
+ int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+ unsigned long docptr;
+ volatile char dummy;
+ int len256 = 0;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ /* Don't allow write past end of device */
+ if (to >= this->totlen) {
+ puts ("Out of flash\n");
+ return DOC_EINVAL;
+ }
+
+ /* Don't allow a single write to cross a 512-byte block boundary */
+ if (to + len > ((to | 0x1ff) + 1))
+ len = ((to | 0x1ff) + 1) - to;
+
+ /* The ECC will not be calculated correctly if less than 512 is written */
+ if (len != 0x200 && eccbuf)
+ printf("ECC needs a full sector write (adr: %lx size %lx)\n",
+ (long) to, (long) len);
+
+ /* printf("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[shr(to, this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ /* Set device to main plane of flash */
+ DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(this,
+ (!this->page256
+ && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+ CDSN_CTRL_WP);
+
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+ } else {
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ }
+
+ /* treat crossing 256-byte sector for 2M x 8bits devices */
+ if (this->page256 && to + len > (to | 0xff) + 1) {
+ len256 = (to | 0xff) + 1 - to;
+ DoC_WriteBuf(this, buf, len256);
+
+ DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+ DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+ /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ puts ("Error programming flash\n");
+ /* Error in programming */
+ *retlen = 0;
+ return DOC_EIO;
+ }
+
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+ CDSN_CTRL_ECC_IO);
+ }
+
+ DoC_WriteBuf(this, &buf[len256], len - len256);
+
+ if (eccbuf) {
+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+ CDSNControl);
+
+ if (DoC_is_Millennium(this)) {
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ } else {
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ }
+
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di = 0; di < 6; di++) {
+ eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+ }
+
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+ printf
+ ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
+#endif
+ }
+
+ DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+ DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+ /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ puts ("Error programming flash\n");
+ /* Error in programming */
+ *retlen = 0;
+ return DOC_EIO;
+ }
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ if (eccbuf) {
+ unsigned char x[8];
+ size_t dummy;
+ int ret;
+
+ /* Write the ECC data to flash */
+ for (di=0; di<6; di++)
+ x[di] = eccbuf[di];
+
+ x[6]=0x55;
+ x[7]=0x55;
+
+ ret = doc_write_oob(this, to, 8, &dummy, x);
+ return ret;
+ }
+ return 0;
+}
+
+int doc_read_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ int len256 = 0, ret;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[shr(ofs, this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with doc_read_ecc. */
+ if (this->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }
+
+ DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, ofs, CDSN_CTRL_WP, 0);
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ DoC_ReadBuf(this, buf, len256);
+
+ DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff),
+ CDSN_CTRL_WP, 0);
+ }
+
+ DoC_ReadBuf(this, &buf[len256], len - len256);
+
+ *retlen = len;
+ /* Reading the full OOB data drops us off of the end of the page,
+ * causing the flash device to go into busy mode, so we need
+ * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
+
+ ret = DoC_WaitReady(this);
+
+ return ret;
+
+}
+
+int doc_write_oob(struct DiskOnChip* this, loff_t ofs, size_t len,
+ size_t * retlen, const u_char * buf)
+{
+ int len256 = 0;
+ unsigned long docptr = this->virtadr;
+ struct Nand *mychip = &this->chips[shr(ofs, this->chipshift)];
+ volatile int dummy;
+
+#ifdef PSYCHO_DEBUG
+ printf("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
+ (long)ofs, len, buf[0], buf[1], buf[2], buf[3],
+ buf[8], buf[9], buf[14],buf[15]);
+#endif
+
+ /* Find the chip which is to be used and select it */
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ /* disable the ECC engine */
+ WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
+
+ /* Reset the chip, see Software Requirement 11.4 item 1. */
+ DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+
+ /* issue the Read2 command to set the pointer to the Spare Data Area. */
+ DoC_Command(this, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with doc_read_ecc. */
+ if (this->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }
+
+ /* issue the Serial Data In command to initial the Page Program process */
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, ofs, 0, 0);
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ if (this->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ DoC_WriteBuf(this, buf, len256);
+
+ DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+ DoC_Command(this, NAND_CMD_STATUS, 0);
+ /* DoC_WaitReady() is implicit in DoC_Command */
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ *retlen = 0;
+ return DOC_EIO;
+ }
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, ofs & (~0x1ff), 0, 0);
+ }
+
+ DoC_WriteBuf(this, &buf[len256], len - len256);
+
+ DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+ DoC_Command(this, NAND_CMD_STATUS, 0);
+ /* DoC_WaitReady() is implicit in DoC_Command */
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ *retlen = 0;
+ return DOC_EIO;
+ }
+
+ *retlen = len;
+ return 0;
+
+}
+
+int doc_erase(struct DiskOnChip* this, loff_t ofs, size_t len)
+{
+ volatile int dummy;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ if (ofs & (this->erasesize-1) || len & (this->erasesize-1)) {
+ puts ("Offset and size must be sector aligned\n");
+ return DOC_EINVAL;
+ }
+
+ docptr = this->virtadr;
+
+ /* FIXME: Do this in the background. Use timers or schedule_task() */
+ while(len) {
+ mychip = &this->chips[shr(ofs, this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ DoC_Command(this, NAND_CMD_ERASE1, 0);
+ DoC_Address(this, ADDR_PAGE, ofs, 0, 0);
+ DoC_Command(this, NAND_CMD_ERASE2, 0);
+
+ DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ printf("Error erasing at 0x%lx\n", (long)ofs);
+ /* There was an error */
+ goto callback;
+ }
+ ofs += this->erasesize;
+ len -= this->erasesize;
+ }
+
+ callback:
+ return 0;
+}
+
+static inline int doccheck(unsigned long potential, unsigned long physadr)
+{
+ unsigned long window=potential;
+ unsigned char tmp, ChipID;
+#ifndef DOC_PASSIVE_PROBE
+ unsigned char tmp2;
+#endif
+
+ /* Routine copied from the Linux DOC driver */
+
+#ifdef CFG_DOCPROBE_55AA
+ /* Check for 0x55 0xAA signature at beginning of window,
+ this is no longer true once we remove the IPL (for Millennium */
+ if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
+ return 0;
+#endif /* CFG_DOCPROBE_55AA */
+
+#ifndef DOC_PASSIVE_PROBE
+ /* It's not possible to cleanly detect the DiskOnChip - the
+ * bootup procedure will put the device into reset mode, and
+ * it's not possible to talk to it without actually writing
+ * to the DOCControl register. So we store the current contents
+ * of the DOCControl register's location, in case we later decide
+ * that it's not a DiskOnChip, and want to put it back how we
+ * found it.
+ */
+ tmp2 = ReadDOC(window, DOCControl);
+
+ /* Reset the DiskOnChip ASIC */
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+ window, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+ window, DOCControl);
+
+ /* Enable the DiskOnChip ASIC */
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+ window, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+ window, DOCControl);
+#endif /* !DOC_PASSIVE_PROBE */
+
+ ChipID = ReadDOC(window, ChipID);
+
+ switch (ChipID) {
+ case DOC_ChipID_Doc2k:
+ /* Check the TOGGLE bit in the ECC register */
+ tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+ if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
+ return ChipID;
+ break;
+
+ case DOC_ChipID_DocMil:
+ /* Check the TOGGLE bit in the ECC register */
+ tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+ if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+ return ChipID;
+ break;
+
+ default:
+#ifndef CFG_DOCPROBE_55AA
+/*
+ * if the ID isn't the DoC2000 or DoCMillenium ID, so we can assume
+ * the DOC is missing
+ */
+# if 0
+ printf("Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+ ChipID, physadr);
+# endif
+#endif
+#ifndef DOC_PASSIVE_PROBE
+ /* Put back the contents of the DOCControl register, in case it's not
+ * actually a DiskOnChip.
+ */
+ WriteDOC(tmp2, window, DOCControl);
+#endif
+ return 0;
+ }
+
+ puts ("DiskOnChip failed TOGGLE test, dropping.\n");
+
+#ifndef DOC_PASSIVE_PROBE
+ /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
+ WriteDOC(tmp2, window, DOCControl);
+#endif
+ return 0;
+}
+
+void doc_probe(unsigned long physadr)
+{
+ struct DiskOnChip *this = NULL;
+ int i=0, ChipID;
+
+ if ((ChipID = doccheck(physadr, physadr))) {
+
+ for (i=0; i<CFG_MAX_DOC_DEVICE; i++) {
+ if (doc_dev_desc[i].ChipID == DOC_ChipID_UNKNOWN) {
+ this = doc_dev_desc + i;
+ break;
+ }
+ }
+
+ if (!this) {
+ puts ("Cannot allocate memory for data structures.\n");
+ return;
+ }
+
+ if (curr_device == -1)
+ curr_device = i;
+
+ memset((char *)this, 0, sizeof(struct DiskOnChip));
+
+ this->virtadr = physadr;
+ this->physadr = physadr;
+ this->ChipID = ChipID;
+
+ DoC2k_init(this);
+ } else {
+ puts ("No DiskOnChip found\n");
+ }
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
diff --git a/common/cmd_ide.c b/common/cmd_ide.c
new file mode 100644
index 0000000..9cbfe1b
--- /dev/null
+++ b/common/cmd_ide.c
@@ -0,0 +1,1563 @@
+/*
+ * (C) Copyright 2000-2002
+ * 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
+ *
+ */
+
+/*
+ * IDE support
+ */
+#include <common.h>
+#include <config.h>
+#include <watchdog.h>
+#include <command.h>
+#include <image.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA)
+# include <pcmcia.h>
+#endif
+#ifdef CONFIG_8xx
+# include <mpc8xx.h>
+#endif
+#include <ide.h>
+#include <ata.h>
+#include <cmd_ide.h>
+#include <cmd_disk.h>
+#ifdef CONFIG_STATUS_LED
+# include <status_led.h>
+#endif
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+
+#undef IDE_DEBUG
+
+#ifdef IDE_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+
+/* Timings for IDE Interface
+ *
+ * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
+ * 70 165 30 PIO-Mode 0, [ns]
+ * 4 9 2 [Cycles]
+ * 50 125 20 PIO-Mode 1, [ns]
+ * 3 7 2 [Cycles]
+ * 30 100 15 PIO-Mode 2, [ns]
+ * 2 6 1 [Cycles]
+ * 30 80 10 PIO-Mode 3, [ns]
+ * 2 5 1 [Cycles]
+ * 25 70 10 PIO-Mode 4, [ns]
+ * 2 4 1 [Cycles]
+ */
+
+const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
+{
+ /* Setup Length Hold */
+ { 70, 165, 30 }, /* PIO-Mode 0, [ns] */
+ { 50, 125, 20 }, /* PIO-Mode 1, [ns] */
+ { 30, 101, 15 }, /* PIO-Mode 2, [ns] */
+ { 30, 80, 10 }, /* PIO-Mode 3, [ns] */
+ { 25, 70, 10 }, /* PIO-Mode 4, [ns] */
+};
+
+static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
+
+#ifndef CFG_PIO_MODE
+#define CFG_PIO_MODE 0 /* use a relaxed default */
+#endif
+static int pio_mode = CFG_PIO_MODE;
+
+/* Make clock cycles and always round up */
+
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
+/* ------------------------------------------------------------------------- */
+
+/* Current I/O Device */
+static int curr_device = -1;
+
+/* Current offset for IDE0 / IDE1 bus access */
+ulong ide_bus_offset[CFG_IDE_MAXBUS] = {
+#if defined(CFG_ATA_IDE0_OFFSET)
+ CFG_ATA_IDE0_OFFSET,
+#endif
+#if defined(CFG_ATA_IDE1_OFFSET) && (CFG_IDE_MAXBUS > 1)
+ CFG_ATA_IDE1_OFFSET,
+#endif
+};
+
+#define ATA_CURR_BASE(dev) (CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)])
+
+static int ide_bus_ok[CFG_IDE_MAXBUS];
+
+static block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+static void ide_led (uchar led, uchar status);
+#else
+#define ide_led(a,b) /* dummy */
+#endif
+
+#ifdef CONFIG_IDE_RESET
+static void ide_reset (void);
+#else
+#define ide_reset() /* dummy */
+#endif
+
+static void ide_ident (block_dev_desc_t *dev_desc);
+static uchar ide_wait (int dev, ulong t);
+
+#define IDE_TIME_OUT 2000 /* 2 sec timeout */
+
+#define ATAPI_TIME_OUT 7000 /* 7 sec timeout (5 sec seems to work...) */
+
+#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
+
+static void __inline__ outb(int dev, int port, unsigned char val);
+static unsigned char __inline__ inb(int dev, int port);
+static void input_swap_data(int dev, ulong *sect_buf, int words);
+static void input_data(int dev, ulong *sect_buf, int words);
+static void output_data(int dev, ulong *sect_buf, int words);
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
+
+
+#ifdef CONFIG_ATAPI
+static void atapi_inquiry(block_dev_desc_t *dev_desc);
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer);
+#endif
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+static void set_pcmcia_timing (int pmode);
+#else
+#define set_pcmcia_timing(a) /* dummy */
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int rcode = 0;
+
+ switch (argc) {
+ case 0:
+ case 1:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ case 2:
+ if (strncmp(argv[1],"res",3) == 0) {
+ puts ("\nReset IDE"
+#ifdef CONFIG_IDE_8xx_DIRECT
+ " on PCMCIA " PCMCIA_SLOT_MSG
+#endif
+ ": ");
+
+ ide_init ();
+ return 0;
+ } else if (strncmp(argv[1],"inf",3) == 0) {
+ int i;
+
+ putc ('\n');
+
+ for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+ if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN)
+ continue; /* list only known devices */
+ printf ("IDE device %d: ", i);
+ dev_print(&ide_dev_desc[i]);
+ }
+ return 0;
+
+ } else if (strncmp(argv[1],"dev",3) == 0) {
+ if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) {
+ puts ("\nno IDE devices available\n");
+ return 1;
+ }
+ printf ("\nIDE device %d: ", curr_device);
+ dev_print(&ide_dev_desc[curr_device]);
+ return 0;
+ } else if (strncmp(argv[1],"part",4) == 0) {
+ int dev, ok;
+
+ for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) {
+ if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+ ++ok;
+ if (dev)
+ putc ('\n');
+ print_part(&ide_dev_desc[dev]);
+ }
+ }
+ if (!ok) {
+ puts ("\nno IDE devices available\n");
+ rcode ++;
+ }
+ return rcode;
+ }
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ case 3:
+ if (strncmp(argv[1],"dev",3) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ printf ("\nIDE device %d: ", dev);
+ if (dev >= CFG_IDE_MAXDEVICE) {
+ puts ("unknown device\n");
+ return 1;
+ }
+ dev_print(&ide_dev_desc[dev]);
+ /*ide_print (dev);*/
+
+ if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
+ return 1;
+ }
+
+ curr_device = dev;
+
+ puts ("... is now current device\n");
+
+ return 0;
+ } else if (strncmp(argv[1],"part",4) == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) {
+ print_part(&ide_dev_desc[dev]);
+ } else {
+ printf ("\nIDE device %d not available\n", dev);
+ rcode = 1;
+ }
+ return rcode;
+#if 0
+ } else if (strncmp(argv[1],"pio",4) == 0) {
+ int mode = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
+ puts ("\nSetting ");
+ pio_mode = mode;
+ ide_init ();
+ } else {
+ printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
+ mode, IDE_MAX_PIO_MODE);
+ }
+ return;
+#endif
+ }
+
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ default:
+ /* at least 4 args */
+
+ if (strcmp(argv[1],"read") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong blk = simple_strtoul(argv[3], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+
+ printf ("\nIDE read: device %d block # %ld, count %ld ... ",
+ curr_device, blk, cnt);
+
+ n = ide_dev_desc[curr_device].block_read (curr_device,
+ blk, cnt,
+ (ulong *)addr);
+ /* flush cache after read */
+ flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz);
+
+ printf ("%ld blocks read: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ if (n==cnt) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (strcmp(argv[1],"write") == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong blk = simple_strtoul(argv[3], NULL, 16);
+ ulong cnt = simple_strtoul(argv[4], NULL, 16);
+ ulong n;
+
+ printf ("\nIDE write: device %d block # %ld, count %ld ... ",
+ curr_device, blk, cnt);
+
+ n = ide_write (curr_device, blk, cnt, (ulong *)addr);
+
+ printf ("%ld blocks written: %s\n",
+ n, (n==cnt) ? "OK" : "ERROR");
+ if (n==cnt) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ rcode = 1;
+ }
+
+ return rcode;
+ }
+}
+
+int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev, part = 0;
+ ulong cnt;
+ ulong addr;
+ disk_partition_t info;
+ image_header_t *hdr;
+ int rcode = 0;
+
+ switch (argc) {
+ case 1:
+ addr = CFG_LOAD_ADDR;
+ boot_device = getenv ("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv ("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ default:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (!boot_device) {
+ puts ("\n** No boot device **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+
+ if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) {
+ printf ("\n** Device %d not available\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (*ep) {
+ if (*ep != ':') {
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+ part = simple_strtoul(++ep, NULL, 16);
+ }
+ if (get_partition_info (&ide_dev_desc[dev], part, &info)) {
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+ if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) {
+ printf ("\n** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n",
+ info.type);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ printf ("\nLoading from IDE device %d, partition %d: "
+ "Name: %.32s Type: %.32s\n",
+ dev, part, info.name, info.type);
+
+ PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
+ info.start, info.size, info.blksz);
+
+ if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ hdr = (image_header_t *)addr;
+
+ if (ntohl(hdr->ih_magic) == IH_MAGIC) {
+
+ print_image_hdr (hdr);
+
+ cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
+ cnt += info.blksz - 1;
+ cnt /= info.blksz;
+ cnt -= 1;
+ } else {
+ printf("\n** Bad Magic Number **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt,
+ (ulong *)(addr+info.blksz)) != cnt) {
+ printf ("** Read error on %d:%d\n", dev, part);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* 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 = 1;
+ }
+ return rcode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void ide_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+#endif
+ unsigned char c;
+ int i, bus;
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+ extern int pcmcia_on (void);
+
+ WATCHDOG_RESET();
+
+ /* initialize the PCMCIA IDE adapter card */
+ if (pcmcia_on())
+ return;
+ udelay (1000000); /* 1 s */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+ WATCHDOG_RESET();
+
+ /* Initialize PIO timing tables */
+ for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
+ pio_config_clk[i].t_setup = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
+ gd->bus_clk);
+ pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
+ gd->bus_clk);
+ pio_config_clk[i].t_hold = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
+ gd->bus_clk);
+ PRINTF ("PIO Mode %d: setup=%2d ns/%d clk"
+ " len=%3d ns/%d clk"
+ " hold=%2d ns/%d clk\n",
+ i,
+ pio_config_ns[i].t_setup, pio_config_clk[i].t_setup,
+ pio_config_ns[i].t_length, pio_config_clk[i].t_length,
+ pio_config_ns[i].t_hold, pio_config_clk[i].t_hold);
+ }
+
+ /* Reset the IDE just to be sure.
+ * Light LED's to show
+ */
+ ide_led ((LED_IDE1 | LED_IDE2), 1); /* LED's on */
+ ide_reset (); /* ATAPI Drives seems to need a proper IDE Reset */
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+ /* PCMCIA / IDE initialization for common mem space */
+ pcmp->pcmc_pgcrb = 0;
+#endif
+
+ /* start in PIO mode 0 - most relaxed timings */
+ pio_mode = 0;
+ set_pcmcia_timing (pio_mode);
+
+ /*
+ * Wait for IDE to get ready.
+ * According to spec, this can take up to 31 seconds!
+ */
+ for (bus=0; bus<CFG_IDE_MAXBUS; ++bus) {
+ int dev = bus * (CFG_IDE_MAXDEVICE / CFG_IDE_MAXBUS);
+
+ printf ("Bus %d: ", bus);
+
+ ide_bus_ok[bus] = 0;
+
+ /* Select device
+ */
+ udelay (100000); /* 100 ms */
+ outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
+ udelay (100000); /* 100 ms */
+
+ i = 0;
+ do {
+ udelay (10000); /* 10 ms */
+
+ c = inb (dev, ATA_STATUS);
+ i++;
+ if (i > (ATA_RESET_TIME * 100)) {
+ puts ("** Timeout **\n");
+ ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+ return;
+ }
+ if ((i >= 100) && ((i%100)==0)) {
+ putc ('.');
+ }
+ } while (c & ATA_STAT_BUSY);
+
+ if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
+ puts ("not available ");
+ PRINTF ("Status = 0x%02X ", c);
+#ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */
+ } else if ((c & ATA_STAT_READY) == 0) {
+ puts ("not available ");
+ PRINTF ("Status = 0x%02X ", c);
+#endif
+ } else {
+ puts ("OK ");
+ ide_bus_ok[bus] = 1;
+ }
+ WATCHDOG_RESET();
+ }
+ putc ('\n');
+
+ ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
+
+ curr_device = -1;
+ for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
+#ifdef CONFIG_IDE_LED
+ int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
+#endif
+ ide_dev_desc[i].if_type=IF_TYPE_IDE;
+ ide_dev_desc[i].dev=i;
+ ide_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+ ide_dev_desc[i].blksz=0;
+ ide_dev_desc[i].lba=0;
+ ide_dev_desc[i].block_read=ide_read;
+ if (!ide_bus_ok[IDE_BUS(i)])
+ continue;
+ ide_led (led, 1); /* LED on */
+ ide_ident(&ide_dev_desc[i]);
+ ide_led (led, 0); /* LED off */
+ dev_print(&ide_dev_desc[i]);
+/* ide_print (i); */
+ if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
+ init_part (&ide_dev_desc[i]); /* initialize partition type */
+ if (curr_device < 0)
+ curr_device = i;
+ }
+ }
+ WATCHDOG_RESET();
+}
+
+/* ------------------------------------------------------------------------- */
+
+block_dev_desc_t * ide_get_dev(int dev)
+{
+ return ((block_dev_desc_t *)&ide_dev_desc[dev]);
+}
+
+
+#ifdef CONFIG_IDE_8xx_DIRECT
+
+static void
+set_pcmcia_timing (int pmode)
+{
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
+ ulong timings;
+
+ PRINTF ("Set timing for PIO Mode %d\n", pmode);
+
+ timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold)
+ | PCMCIA_SST(pio_config_clk[pmode].t_setup)
+ | PCMCIA_SL (pio_config_clk[pmode].t_length)
+ ;
+
+ /* IDE 0
+ */
+ pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0;
+ pcmp->pcmc_por0 = CFG_PCMCIA_POR0
+#if (CFG_PCMCIA_POR0 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR0: %08x POR0: %08x\n", pcmp->pcmc_pbr0, pcmp->pcmc_por0);
+
+ pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1;
+ pcmp->pcmc_por1 = CFG_PCMCIA_POR1
+#if (CFG_PCMCIA_POR1 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR1: %08x POR1: %08x\n", pcmp->pcmc_pbr1, pcmp->pcmc_por1);
+
+ pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2;
+ pcmp->pcmc_por2 = CFG_PCMCIA_POR2
+#if (CFG_PCMCIA_POR2 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR2: %08x POR2: %08x\n", pcmp->pcmc_pbr2, pcmp->pcmc_por2);
+
+ pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3;
+ pcmp->pcmc_por3 = CFG_PCMCIA_POR3
+#if (CFG_PCMCIA_POR3 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR3: %08x POR3: %08x\n", pcmp->pcmc_pbr3, pcmp->pcmc_por3);
+
+ /* IDE 1
+ */
+ pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4;
+ pcmp->pcmc_por4 = CFG_PCMCIA_POR4
+#if (CFG_PCMCIA_POR4 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR4: %08x POR4: %08x\n", pcmp->pcmc_pbr4, pcmp->pcmc_por4);
+
+ pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5;
+ pcmp->pcmc_por5 = CFG_PCMCIA_POR5
+#if (CFG_PCMCIA_POR5 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR5: %08x POR5: %08x\n", pcmp->pcmc_pbr5, pcmp->pcmc_por5);
+
+ pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6;
+ pcmp->pcmc_por6 = CFG_PCMCIA_POR6
+#if (CFG_PCMCIA_POR6 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR6: %08x POR6: %08x\n", pcmp->pcmc_pbr6, pcmp->pcmc_por6);
+
+ pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7;
+ pcmp->pcmc_por7 = CFG_PCMCIA_POR7
+#if (CFG_PCMCIA_POR7 != 0)
+ | timings
+#endif
+ ;
+ PRINTF ("PBR7: %08x POR7: %08x\n", pcmp->pcmc_pbr7, pcmp->pcmc_por7);
+
+}
+
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+/* ------------------------------------------------------------------------- */
+
+static void __inline__
+outb(int dev, int port, unsigned char val)
+{
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ *((uchar *)(ATA_CURR_BASE(dev)+port)) = val;
+#if 0
+ printf ("OUTB: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+}
+
+static unsigned char __inline__
+inb(int dev, int port)
+{
+ uchar val;
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ val = *((uchar *)(ATA_CURR_BASE(dev)+port));
+#if 0
+ printf ("INB: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
+#endif
+ return (val);
+}
+
+__inline__ unsigned ld_le16(const volatile unsigned short *addr)
+{
+ unsigned val;
+
+ __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r"(val) : "r"(addr), "m"(*addr));
+ return val;
+}
+
+static void
+input_swap_data(int dev, ulong *sect_buf, int words)
+{
+ volatile ushort *pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ ushort *dbuf = (ushort *)sect_buf;
+
+ while (words--) {
+ *dbuf++ = ld_le16(pbuf);
+ *dbuf++ = ld_le16(pbuf);
+ }
+}
+
+static void
+output_data(int dev, ulong *sect_buf, int words)
+{
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+ while (words--) {
+ __asm__ volatile ("eieio");
+ *pbuf = *dbuf++;
+ __asm__ volatile ("eieio");
+ *pbuf = *dbuf++;
+ }
+}
+
+static void
+input_data(int dev, ulong *sect_buf, int words)
+{
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+ while (words--) {
+ __asm__ volatile ("eieio");
+ *dbuf++ = *pbuf;
+ __asm__ volatile ("eieio");
+ *dbuf++ = *pbuf;
+ }
+}
+
+/* -------------------------------------------------------------------------
+ */
+static void ide_ident (block_dev_desc_t *dev_desc)
+{
+ ulong iobuf[ATA_SECTORWORDS];
+ unsigned char c;
+ hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+#if 0
+ int mode, cycle_time;
+#endif
+ int device;
+ device=dev_desc->dev;
+ printf (" Device %d: ", device);
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+ /* Select device
+ */
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ dev_desc->if_type=IF_TYPE_IDE;
+#ifdef CONFIG_ATAPI
+ /* check signature */
+ if ((inb(device,ATA_SECT_CNT)==0x01) &&
+ (inb(device,ATA_SECT_NUM)==0x01) &&
+ (inb(device,ATA_CYL_LOW)==0x14) &&
+ (inb(device,ATA_CYL_HIGH)==0xEB)) {
+ /* ATAPI Signature found */
+ dev_desc->if_type=IF_TYPE_ATAPI;
+ /* Start Ident Command
+ */
+ outb (device, ATA_COMMAND, ATAPI_CMD_IDENT);
+ /*
+ * Wait for completion - ATAPI devices need more time
+ * to become ready
+ */
+ c = ide_wait (device, ATAPI_TIME_OUT);
+ }
+ else
+#endif
+ {
+ /* Start Ident Command
+ */
+ outb (device, ATA_COMMAND, ATA_CMD_IDENT);
+
+ /* Wait for completion
+ */
+ c = ide_wait (device, IDE_TIME_OUT);
+ }
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+
+ if (((c & ATA_STAT_DRQ) == 0) ||
+ ((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
+ dev_desc->type=DEV_TYPE_UNKNOWN;
+ return;
+ }
+
+ input_swap_data (device, iobuf, ATA_SECTORWORDS);
+
+ ident_cpy (dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
+ ident_cpy (dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
+ ident_cpy (dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
+
+ if ((iop->config & 0x0080)==0x0080)
+ dev_desc->removable = 1;
+ else
+ dev_desc->removable = 0;
+
+#if 0
+ /*
+ * Drive PIO mode autoselection
+ */
+ mode = iop->tPIO;
+
+ printf ("tPIO = 0x%02x = %d\n",mode, mode);
+ if (mode > 2) { /* 2 is maximum allowed tPIO value */
+ mode = 2;
+ PRINTF ("Override tPIO -> 2\n");
+ }
+ if (iop->field_valid & 2) { /* drive implements ATA2? */
+ PRINTF ("Drive implements ATA2\n");
+ if (iop->capability & 8) { /* drive supports use_iordy? */
+ cycle_time = iop->eide_pio_iordy;
+ } else {
+ cycle_time = iop->eide_pio;
+ }
+ PRINTF ("cycle time = %d\n", cycle_time);
+ mode = 4;
+ if (cycle_time > 120) mode = 3; /* 120 ns for PIO mode 4 */
+ if (cycle_time > 180) mode = 2; /* 180 ns for PIO mode 3 */
+ if (cycle_time > 240) mode = 1; /* 240 ns for PIO mode 4 */
+ if (cycle_time > 383) mode = 0; /* 383 ns for PIO mode 4 */
+ }
+ printf ("PIO mode to use: PIO %d\n", mode);
+#endif /* 0 */
+
+#ifdef CONFIG_ATAPI
+ if (dev_desc->if_type==IF_TYPE_ATAPI) {
+ atapi_inquiry(dev_desc);
+ return;
+ }
+#endif /* CONFIG_ATAPI */
+
+ /* swap shorts */
+ dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
+ /* assuming HD */
+ dev_desc->type=DEV_TYPE_HARDDISK;
+ dev_desc->blksz=ATA_BLOCKSIZE;
+ dev_desc->lun=0; /* just to fill something in... */
+
+#if 0 /* only used to test the powersaving mode,
+ * if enabled, the drive goes after 5 sec
+ * in standby mode */
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = ide_wait (device, IDE_TIME_OUT);
+ outb (device, ATA_SECT_CNT, 1);
+ outb (device, ATA_LBA_LOW, 0);
+ outb (device, ATA_LBA_MID, 0);
+ outb (device, ATA_LBA_HIGH, 0);
+ outb (device, ATA_DEV_HD, ATA_LBA |
+ ATA_DEVICE(device));
+ outb (device, ATA_COMMAND, 0xe3);
+ udelay (50);
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+ ulong n = 0;
+ unsigned char c;
+ unsigned char pwrsave=0; /* power save */
+
+ PRINTF ("ide_read dev %d start %lX, blocks %lX buffer at %lX\n",
+ device, blknr, blkcnt, (ulong)buffer);
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto IDE_READ_E;
+ }
+
+ /* first check if the drive is in Powersaving mode, if yes,
+ * increase the timeout value */
+ outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR);
+ udelay (50);
+
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto IDE_READ_E;
+ }
+ if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+ printf ("No Powersaving mode %X\n", c);
+ } else {
+ c = inb(device,ATA_SECT_CNT);
+ PRINTF("Powersaving %02X\n",c);
+ if(c==0)
+ pwrsave=1;
+ }
+
+
+ while (blkcnt-- > 0) {
+
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ break;
+ }
+
+ outb (device, ATA_SECT_CNT, 1);
+ outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+ outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+ outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+ outb (device, ATA_DEV_HD, ATA_LBA |
+ ATA_DEVICE(device) |
+ ((blknr >> 24) & 0xF) );
+ outb (device, ATA_COMMAND, ATA_CMD_READ);
+
+ udelay (50);
+
+ if(pwrsave) {
+ c = ide_wait (device, IDE_SPIN_UP_TIME_OUT); /* may take up to 4 sec */
+ pwrsave=0;
+ } else {
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+ }
+
+ if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+ printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+ device, blknr, c);
+ break;
+ }
+
+ input_data (device, buffer, ATA_SECTORWORDS);
+ (void) inb (device, ATA_STATUS); /* clear IRQ */
+
+ ++n;
+ ++blknr;
+ buffer += ATA_SECTORWORDS;
+ }
+IDE_READ_E:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+ ulong n = 0;
+ unsigned char c;
+
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+ while (blkcnt-- > 0) {
+
+ c = ide_wait (device, IDE_TIME_OUT);
+
+ if (c & ATA_STAT_BUSY) {
+ printf ("IDE read: device %d not ready\n", device);
+ goto WR_OUT;
+ }
+
+ outb (device, ATA_SECT_CNT, 1);
+ outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+ outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+ outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+ outb (device, ATA_DEV_HD, ATA_LBA |
+ ATA_DEVICE(device) |
+ ((blknr >> 24) & 0xF) );
+ outb (device, ATA_COMMAND, ATA_CMD_WRITE);
+
+ udelay (50);
+
+ c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
+
+ if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
+ printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
+ device, blknr, c);
+ goto WR_OUT;
+ }
+
+ output_data (device, buffer, ATA_SECTORWORDS);
+ c = inb (device, ATA_STATUS); /* clear IRQ */
+ ++n;
+ ++blknr;
+ buffer += ATA_SECTORWORDS;
+ }
+WR_OUT:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * copy src to dest, skipping leading and trailing blanks and null
+ * terminate the string
+ */
+static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
+{
+ int start,end;
+
+ start=0;
+ while (start<len) {
+ if (src[start]!=' ')
+ break;
+ start++;
+ }
+ end=len-1;
+ while (end>start) {
+ if (src[end]!=' ')
+ break;
+ end--;
+ }
+ for ( ; start<=end; start++) {
+ *dest++=src[start];
+ }
+ *dest='\0';
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Wait until Busy bit is off, or timeout (in ms)
+ * Return last status
+ */
+static uchar ide_wait (int dev, ulong t)
+{
+ ulong delay = 10 * t; /* poll every 100 us */
+ uchar c;
+
+ while ((c = inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
+ udelay (100);
+ if (delay-- == 0) {
+ break;
+ }
+ }
+ return (c);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_RESET
+extern void ide_set_reset(int idereset);
+
+static void ide_reset (void)
+{
+#if defined(CFG_PB_12V_ENABLE) || defined(CFG_PB_IDE_MOTOR)
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+ int i;
+
+ curr_device = -1;
+ for (i=0; i<CFG_IDE_MAXBUS; ++i)
+ ide_bus_ok[i] = 0;
+ for (i=0; i<CFG_IDE_MAXDEVICE; ++i)
+ ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+
+ ide_set_reset (1); /* assert reset */
+
+ WATCHDOG_RESET();
+
+#ifdef CFG_PB_12V_ENABLE
+ immr->im_cpm.cp_pbdat &= ~(CFG_PB_12V_ENABLE); /* 12V Enable output OFF */
+ immr->im_cpm.cp_pbpar &= ~(CFG_PB_12V_ENABLE);
+ immr->im_cpm.cp_pbodr &= ~(CFG_PB_12V_ENABLE);
+ immr->im_cpm.cp_pbdir |= CFG_PB_12V_ENABLE;
+
+ /* wait 500 ms for the voltage to stabilize
+ */
+ for (i=0; i<500; ++i) {
+ udelay (1000);
+ }
+
+ immr->im_cpm.cp_pbdat |= CFG_PB_12V_ENABLE; /* 12V Enable output ON */
+#endif /* CFG_PB_12V_ENABLE */
+
+#ifdef CFG_PB_IDE_MOTOR
+ /* configure IDE Motor voltage monitor pin as input */
+ immr->im_cpm.cp_pbpar &= ~(CFG_PB_IDE_MOTOR);
+ immr->im_cpm.cp_pbodr &= ~(CFG_PB_IDE_MOTOR);
+ immr->im_cpm.cp_pbdir &= ~(CFG_PB_IDE_MOTOR);
+
+ /* wait up to 1 s for the motor voltage to stabilize
+ */
+ for (i=0; i<1000; ++i) {
+ if ((immr->im_cpm.cp_pbdat & CFG_PB_IDE_MOTOR) != 0) {
+ break;
+ }
+ udelay (1000);
+ }
+
+ if (i == 1000) { /* Timeout */
+ printf ("\nWarning: 5V for IDE Motor missing\n");
+# ifdef CONFIG_STATUS_LED
+# ifdef STATUS_LED_YELLOW
+ status_led_set (STATUS_LED_YELLOW, STATUS_LED_ON );
+# endif
+# ifdef STATUS_LED_GREEN
+ status_led_set (STATUS_LED_GREEN, STATUS_LED_OFF);
+# endif
+# endif /* CONFIG_STATUS_LED */
+ }
+#endif /* CFG_PB_IDE_MOTOR */
+
+ WATCHDOG_RESET();
+
+ /* de-assert RESET signal */
+ ide_set_reset(0);
+
+ /* wait 250 ms */
+ for (i=0; i<250; ++i) {
+ udelay (1000);
+ }
+}
+
+#endif /* CONFIG_IDE_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_LED
+
+static uchar led_buffer = 0; /* Buffer for current LED status */
+
+static void ide_led (uchar led, uchar status)
+{
+ uchar *led_port = LED_PORT;
+
+ if (status) { /* switch LED on */
+ led_buffer |= led;
+ } else { /* switch LED off */
+ led_buffer &= ~led;
+ }
+
+ *led_port = led_buffer;
+}
+
+#endif /* CONFIG_IDE_LED */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATAPI
+/****************************************************************************
+ * ATAPI Support
+ */
+
+
+
+#undef ATAPI_DEBUG
+
+#ifdef ATAPI_DEBUG
+#define AT_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define AT_PRINTF(fmt,args...)
+#endif
+
+/* since ATAPI may use commands with not 4 bytes alligned length
+ * we have our own transfer functions, 2 bytes alligned */
+static void
+output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+ while (shorts--) {
+ __asm__ volatile ("eieio");
+ *pbuf = *dbuf++;
+ }
+}
+
+static void
+input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+ ushort *dbuf;
+ volatile ushort *pbuf;
+
+ pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
+ dbuf = (ushort *)sect_buf;
+ while (shorts--) {
+ __asm__ volatile ("eieio");
+ *dbuf++ = *pbuf;
+ }
+}
+
+/*
+ * Wait until (Status & mask) == res, or timeout (in ms)
+ * Return last status
+ * This is used since some ATAPI CD ROMs clears their Busy Bit first
+ * and then they set their DRQ Bit
+ */
+static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res)
+{
+ ulong delay = 10 * t; /* poll every 100 us */
+ uchar c;
+
+ c = inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */
+ while (((c = inb(dev, ATA_STATUS)) & mask)
+ != res) {
+ /* break if error occurs (doesn't make sense to wait more) */
+ if((c & ATA_STAT_ERR)==ATA_STAT_ERR)
+ break;
+ udelay (100);
+ if (delay-- == 0) {
+ break;
+ }
+ }
+ return (c);
+}
+
+/*
+ * issue an atapi command
+ */
+unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen)
+{
+ unsigned char c,err,mask,res;
+ int n;
+ ide_led (DEVICE_LED(device), 1); /* LED on */
+
+ /* Select device
+ */
+ mask = ATA_STAT_BUSY|ATA_STAT_DRQ;
+ res = 0;
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & mask) != res) {
+ printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c);
+ err=0xFF;
+ goto AI_OUT;
+ }
+ /* write taskfile */
+ outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
+ outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF));
+ outb (device, ATA_CYL_HIGH, (unsigned char)((buflen<<8) & 0xFF));
+ outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+ outb (device, ATA_COMMAND, ATAPI_CMD_PACKET);
+ udelay (50);
+
+ mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+ res = ATA_STAT_DRQ;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+
+ if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
+ printf ("ATTAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c);
+ err=0xFF;
+ goto AI_OUT;
+ }
+
+ output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */
+ /* ATAPI Command written wait for completition */
+ udelay (5000); /* device must set bsy */
+
+ mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
+ /* if no data wait for DRQ = 0 BSY = 0
+ * if data wait for DRQ = 1 BSY = 0 */
+ res=0;
+ if(buflen)
+ res = ATA_STAT_DRQ;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & mask) != res ) {
+ if (c & ATA_STAT_ERR) {
+ err=(inb(device,ATA_ERROR_REG))>>4;
+ AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c);
+ } else {
+ printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c);
+ err=0xFF;
+ }
+ goto AI_OUT;
+ }
+ n=inb(device, ATA_CYL_HIGH);
+ n<<=8;
+ n+=inb(device, ATA_CYL_LOW);
+ if(n>buflen) {
+ printf("ERROR, transfer bytes %d requested only %d\n",n,buflen);
+ err=0xff;
+ goto AI_OUT;
+ }
+ if((n==0)&&(buflen<0)) {
+ printf("ERROR, transfer bytes %d requested %d\n",n,buflen);
+ err=0xff;
+ goto AI_OUT;
+ }
+ if(n!=buflen) {
+ AT_PRINTF("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen);
+ }
+ if(n!=0) { /* data transfer */
+ AT_PRINTF("ATAPI_ISSUE: %d Bytes to transfer\n",n);
+ /* we transfer shorts */
+ n>>=1;
+ /* ok now decide if it is an in or output */
+ if ((inb(device, ATA_SECT_CNT)&0x02)==0) {
+ AT_PRINTF("Write to device\n");
+ output_data_shorts(device,(unsigned short *)buffer,n);
+ } else {
+ AT_PRINTF("Read from device @ %p shorts %d\n",buffer,n);
+ input_data_shorts(device,(unsigned short *)buffer,n);
+ }
+ }
+ udelay(5000); /* seems that some CD ROMs need this... */
+ mask = ATA_STAT_BUSY|ATA_STAT_ERR;
+ res=0;
+ c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
+ if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+ err=(inb(device,ATA_ERROR_REG) >> 4);
+ AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c);
+ } else {
+ err = 0;
+ }
+AI_OUT:
+ ide_led (DEVICE_LED(device), 0); /* LED off */
+ return (err);
+}
+
+/*
+ * sending the command to atapi_issue. If an status other than good
+ * returns, an request_sense will be issued
+ */
+
+#define ATAPI_DRIVE_NOT_READY 100
+#define ATAPI_UNIT_ATTN 10
+
+unsigned char atapi_issue_autoreq (int device,
+ unsigned char* ccb,
+ int ccblen,
+ unsigned char *buffer,
+ int buflen)
+{
+ unsigned char sense_data[18],sense_ccb[12];
+ unsigned char res,key,asc,ascq;
+ int notready,unitattn;
+
+ unitattn=ATAPI_UNIT_ATTN;
+ notready=ATAPI_DRIVE_NOT_READY;
+
+retry:
+ res= atapi_issue(device,ccb,ccblen,buffer,buflen);
+ if (res==0)
+ return (0); /* Ok */
+
+ if (res==0xFF)
+ return (0xFF); /* error */
+
+ AT_PRINTF("(auto_req)atapi_issue returned sense key %X\n",res);
+
+ memset(sense_ccb,0,sizeof(sense_ccb));
+ memset(sense_data,0,sizeof(sense_data));
+ sense_ccb[0]=ATAPI_CMD_REQ_SENSE;
+ sense_ccb[4]=18; /* allocation Legnth */
+
+ res=atapi_issue(device,sense_ccb,12,sense_data,18);
+ key=(sense_data[2]&0xF);
+ asc=(sense_data[12]);
+ ascq=(sense_data[13]);
+
+ AT_PRINTF("ATAPI_CMD_REQ_SENSE returned %x\n",res);
+ AT_PRINTF(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
+ sense_data[0],
+ key,
+ asc,
+ ascq);
+
+ if((key==0))
+ return 0; /* ok device ready */
+
+ if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */
+ if(unitattn-->0) {
+ udelay(200*1000);
+ goto retry;
+ }
+ printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN);
+ goto error;
+ }
+ if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */
+ if (notready-->0) {
+ udelay(200*1000);
+ goto retry;
+ }
+ printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY);
+ goto error;
+ }
+ if(asc==0x3a) {
+ AT_PRINTF("Media not present\n");
+ goto error;
+ }
+ printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+error:
+ AT_PRINTF ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
+ return (0xFF);
+}
+
+
+
+static void atapi_inquiry(block_dev_desc_t * dev_desc)
+{
+ unsigned char ccb[12]; /* Command descriptor block */
+ unsigned char iobuf[64]; /* temp buf */
+ unsigned char c;
+ int device;
+
+ device=dev_desc->dev;
+ dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */
+ dev_desc->block_read=atapi_read;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+
+ ccb[0]=ATAPI_CMD_INQUIRY;
+ ccb[4]=40; /* allocation Legnth */
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40);
+
+ AT_PRINTF("ATAPI_CMD_INQUIRY returned %x\n",c);
+ if (c!=0)
+ return;
+
+ /* copy device ident strings */
+ ident_cpy(dev_desc->vendor,&iobuf[8],8);
+ ident_cpy(dev_desc->product,&iobuf[16],16);
+ ident_cpy(dev_desc->revision,&iobuf[32],5);
+
+ dev_desc->lun=0;
+ dev_desc->lba=0;
+ dev_desc->blksz=0;
+ dev_desc->type=iobuf[0] & 0x1f;
+
+ if ((iobuf[1]&0x80)==0x80)
+ dev_desc->removable = 1;
+ else
+ dev_desc->removable = 0;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ ccb[0]=ATAPI_CMD_START_STOP;
+ ccb[4]=0x03; /* start */
+
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+ AT_PRINTF("ATAPI_CMD_START_STOP returned %x\n",c);
+ if (c!=0)
+ return;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0);
+
+ AT_PRINTF("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c);
+ if (c!=0)
+ return;
+
+ memset(ccb,0,sizeof(ccb));
+ memset(iobuf,0,sizeof(iobuf));
+ ccb[0]=ATAPI_CMD_READ_CAP;
+ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8);
+ AT_PRINTF("ATAPI_CMD_READ_CAP returned %x\n",c);
+ if (c!=0)
+ return;
+
+ AT_PRINTF("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
+ iobuf[0],iobuf[1],iobuf[2],iobuf[3],
+ iobuf[4],iobuf[5],iobuf[6],iobuf[7]);
+
+ dev_desc->lba =((unsigned long)iobuf[0]<<24) +
+ ((unsigned long)iobuf[1]<<16) +
+ ((unsigned long)iobuf[2]<< 8) +
+ ((unsigned long)iobuf[3]);
+ dev_desc->blksz=((unsigned long)iobuf[4]<<24) +
+ ((unsigned long)iobuf[5]<<16) +
+ ((unsigned long)iobuf[6]<< 8) +
+ ((unsigned long)iobuf[7]);
+ return;
+}
+
+
+/*
+ * atapi_read:
+ * we transfer only one block per command, since the multiple DRQ per
+ * command is not yet implemented
+ */
+#define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */
+#define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */
+#define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE /* max blocks */
+
+ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
+{
+ ulong n = 0;
+ unsigned char ccb[12]; /* Command descriptor block */
+ ulong cnt;
+
+ AT_PRINTF("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n",
+ device, blknr, blkcnt, (ulong)buffer);
+
+ do {
+ if (blkcnt>ATAPI_READ_MAX_BLOCK) {
+ cnt=ATAPI_READ_MAX_BLOCK;
+ } else {
+ cnt=blkcnt;
+ }
+ ccb[0]=ATAPI_CMD_READ_12;
+ ccb[1]=0; /* reserved */
+ ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */
+ ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /* */
+ ccb[4]=(unsigned char) (blknr>> 8) & 0xFF;
+ ccb[5]=(unsigned char) blknr & 0xFF; /* LSB Block */
+ ccb[6]=(unsigned char) (cnt >>24) & 0xFF; /* MSB Block count */
+ ccb[7]=(unsigned char) (cnt >>16) & 0xFF;
+ ccb[8]=(unsigned char) (cnt >> 8) & 0xFF;
+ ccb[9]=(unsigned char) cnt & 0xFF; /* LSB Block */
+ ccb[10]=0; /* reserved */
+ ccb[11]=0; /* reserved */
+
+ if (atapi_issue_autoreq(device,ccb,12,
+ (unsigned char *)buffer,
+ cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) {
+ return (n);
+ }
+ n+=cnt;
+ blkcnt-=cnt;
+ blknr+=cnt;
+ buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */
+ } while (blkcnt > 0);
+ return (n);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_ATAPI */
+
+#endif /* CONFIG_COMMANDS & CFG_CMD_IDE */
diff --git a/common/cmd_immap.c b/common/cmd_immap.c
new file mode 100644
index 0000000..443335b
--- /dev/null
+++ b/common/cmd_immap.c
@@ -0,0 +1,578 @@
+/*
+ * (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
+ */
+
+/*
+ * MPC8xx/MPC8260 Internal Memory Map Functions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <cmd_immap.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_IMMAP) && \
+ (defined(CONFIG_8xx) || defined(CONFIG_8260))
+
+#if defined(CONFIG_8xx)
+#include <asm/8xx_immap.h>
+#include <commproc.h>
+#elif defined(CONFIG_8260)
+#include <asm/immap_8260.h>
+#include <asm/cpm_8260.h>
+#include <asm/iopin_8260.h>
+#endif
+
+static void
+unimplemented ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ printf ("Sorry, but the '%s' command has not been implemented\n",
+ cmdtp->name);
+}
+
+int
+do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile sysconf8xx_t *sc = &immap->im_siu_conf;
+#elif defined(CONFIG_8260)
+ volatile sysconf8260_t *sc = &immap->im_siu_conf;
+#endif
+
+ printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr);
+#if defined(CONFIG_8xx)
+ printf ("SWT = %08x\n", sc->sc_swt);
+ printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask);
+ printf ("SIEL = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec);
+ printf ("TESR = %08x SDCR = %08x\n", sc->sc_tesr, sc->sc_sdcr);
+#elif defined(CONFIG_8260)
+ printf ("BCR = %08x\n", sc->sc_bcr);
+ printf ("P_ACR = %02x P_ALRH= %08x P_ALRL= %08x\n",
+ sc->sc_ppc_acr, sc->sc_ppc_alrh, sc->sc_ppc_alrl);
+ printf ("L_ACR = %02x L_ALRH= %08x L_ALRL= %08x\n",
+ sc->sc_lcl_acr, sc->sc_lcl_alrh, sc->sc_lcl_alrl);
+ printf ("PTESR1= %08x PTESR2= %08x\n", sc->sc_tescr1, sc->sc_tescr2);
+ printf ("LTESR1= %08x LTESR2= %08x\n", sc->sc_ltescr1, sc->sc_ltescr2);
+ printf ("PDTEA = %08x PDTEM = %02x\n", sc->sc_pdtea, sc->sc_pdtem);
+ printf ("LDTEA = %08x LDTEM = %02x\n", sc->sc_ldtea, sc->sc_ldtem);
+#endif
+ return 0;
+}
+
+int
+do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ int nbanks = 8;
+#elif defined(CONFIG_8260)
+ volatile memctl8260_t *memctl = &immap->im_memctl;
+ int nbanks = 12;
+#endif
+ volatile uint *p = &memctl->memc_br0;
+ int i;
+
+ for (i = 0; i < nbanks; i++, p += 2) {
+ if (i < 10) {
+ printf ("BR%d = %08x OR%d = %08x\n",
+ i, p[0], i, p[1]);
+ } else {
+ printf ("BR%d = %08x OR%d = %08x\n",
+ i, p[0], i, p[1]);
+ }
+ }
+
+ printf ("MAR = %08x", memctl->memc_mar);
+#if defined(CONFIG_8xx)
+ printf (" MCR = %08x\n", memctl->memc_mcr);
+#elif defined(CONFIG_8260)
+ printf ("\n");
+#endif
+ printf ("MAMR = %08x MBMR = %08x",
+ memctl->memc_mamr, memctl->memc_mbmr);
+#if defined(CONFIG_8xx)
+ printf ("\nMSTAT = %04x\n", memctl->memc_mstat);
+#elif defined(CONFIG_8260)
+ printf (" MCMR = %08x\n", memctl->memc_mcmr);
+#endif
+ printf ("MPTPR = %04x MDR = %08x\n",
+ memctl->memc_mptpr, memctl->memc_mdr);
+#if defined(CONFIG_8260)
+ printf ("PSDMR = %08x LSDMR = %08x\n",
+ memctl->memc_psdmr, memctl->memc_lsdmr);
+ printf ("PURT = %02x PSRT = %02x\n",
+ memctl->memc_purt, memctl->memc_psrt);
+ printf ("LURT = %02x LSRT = %02x\n",
+ memctl->memc_lurt, memctl->memc_lsrt);
+ printf ("IMMR = %08x\n", memctl->memc_immr);
+#endif
+ return 0;
+}
+
+int
+do_sitinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+#ifdef CONFIG_8260
+int
+do_icinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+#endif
+
+int
+do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+static int counter;
+
+static void
+header(void)
+{
+ char *data = "\
+ -------------------------------- --------------------------------\
+ 00000000001111111111222222222233 00000000001111111111222222222233\
+ 01234567890123456789012345678901 01234567890123456789012345678901\
+ -------------------------------- --------------------------------\
+ ";
+ int i;
+
+ if (counter % 2)
+ putc('\n');
+ counter = 0;
+
+ for (i = 0; i < 4; i++, data += 79)
+ printf("%.79s\n", data);
+}
+
+static void binary (char *label, uint value, int nbits)
+{
+ uint mask = 1 << (nbits - 1);
+ int i, second = (counter++ % 2);
+
+ if (second)
+ putc (' ');
+ puts (label);
+ for (i = 32 + 1; i != nbits; i--)
+ putc (' ');
+
+ while (mask != 0) {
+ if (value & mask)
+ putc ('1');
+ else
+ putc ('0');
+ mask >>= 1;
+ }
+
+ if (second)
+ putc ('\n');
+}
+
+#if defined(CONFIG_8xx)
+#define PA_NBITS 16
+#define PA_NB_ODR 8
+#define PB_NBITS 18
+#define PB_NB_ODR 16
+#define PC_NBITS 12
+#define PD_NBITS 13
+#elif defined(CONFIG_8260)
+#define PA_NBITS 32
+#define PA_NB_ODR 32
+#define PB_NBITS 28
+#define PB_NB_ODR 28
+#define PC_NBITS 32
+#define PD_NBITS 28
+#endif
+
+int
+do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile iop8xx_t *iop = &immap->im_ioport;
+ volatile ushort *l, *r;
+#elif defined(CONFIG_8260)
+ volatile iop8260_t *iop = &immap->im_ioport;
+ volatile uint *l, *r;
+#endif
+ volatile uint *R;
+
+ counter = 0;
+ header ();
+
+ /*
+ * Ports A & B
+ */
+
+#if defined(CONFIG_8xx)
+ l = &iop->iop_padir;
+ R = &immap->im_cpm.cp_pbdir;
+#elif defined(CONFIG_8260)
+ l = &iop->iop_pdira;
+ R = &iop->iop_pdirb;
+#endif
+ binary ("PA_DIR", *l++, PA_NBITS);
+ binary ("PB_DIR", *R++, PB_NBITS);
+ binary ("PA_PAR", *l++, PA_NBITS);
+ binary ("PB_PAR", *R++, PB_NBITS);
+#if defined(CONFIG_8260)
+ binary ("PA_SOR", *l++, PA_NBITS);
+ binary ("PB_SOR", *R++, PB_NBITS);
+#endif
+ binary ("PA_ODR", *l++, PA_NB_ODR);
+ binary ("PB_ODR", *R++, PB_NB_ODR);
+ binary ("PA_DAT", *l++, PA_NBITS);
+ binary ("PB_DAT", *R++, PB_NBITS);
+
+ header ();
+
+ /*
+ * Ports C & D
+ */
+
+#if defined(CONFIG_8xx)
+ l = &iop->iop_pcdir;
+ r = &iop->iop_pddir;
+#elif defined(CONFIG_8260)
+ l = &iop->iop_pdirc;
+ r = &iop->iop_pdird;
+#endif
+ binary ("PC_DIR", *l++, PC_NBITS);
+ binary ("PD_DIR", *r++, PD_NBITS);
+ binary ("PC_PAR", *l++, PC_NBITS);
+ binary ("PD_PAR", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+ binary ("PC_SO ", *l++, PC_NBITS);
+ binary (" ", 0, 0);
+ r++;
+#elif defined(CONFIG_8260)
+ binary ("PC_SOR", *l++, PC_NBITS);
+ binary ("PD_SOR", *r++, PD_NBITS);
+ binary ("PC_ODR", *l++, PC_NBITS);
+ binary ("PD_ODR", *r++, PD_NBITS);
+#endif
+ binary ("PC_DAT", *l++, PC_NBITS);
+ binary ("PD_DAT", *r++, PD_NBITS);
+#if defined(CONFIG_8xx)
+ binary ("PC_INT", *l++, PC_NBITS);
+#endif
+
+ header ();
+ return 0;
+}
+
+/*
+ * set the io pins
+ * this needs a clean up for smaller tighter code
+ * use *uint and set the address based on cmd + port
+ */
+int
+do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_8260)
+ uint rcode = 0;
+ static uint port = 0;
+ static uint pin = 0;
+ static uint value = 0;
+ static enum { DIR, PAR, SOR, ODR, DAT } cmd = DAT;
+ iopin_t iopin;
+
+ if (argc != 5) {
+ printf ("iopset PORT PIN CMD VALUE\n");
+ return 1;
+ }
+ port = argv[1][0] - 'A';
+ if (port > 3)
+ port -= 0x20;
+ if (port > 3)
+ rcode = 1;
+ pin = simple_strtol (argv[2], NULL, 10);
+ if (pin > 31)
+ rcode = 1;
+
+
+ switch (argv[3][0]) {
+ case 'd':
+ if (argv[3][1] == 'a')
+ cmd = DAT;
+ else if (argv[3][1] == 'i')
+ cmd = DIR;
+ else
+ rcode = 1;
+ break;
+ case 'p':
+ cmd = PAR;
+ break;
+ case 'o':
+ cmd = ODR;
+ break;
+ case 's':
+ cmd = SOR;
+ break;
+ default:
+ printf ("iopset: unknown command %s\n", argv[3]);
+ rcode = 1;
+ }
+ if (argv[4][0] == '1')
+ value = 1;
+ else if (argv[4][0] == '0')
+ value = 0;
+ else
+ rcode = 1;
+ if (rcode == 0) {
+ iopin.port = port;
+ iopin.pin = pin;
+ switch (cmd) {
+ case DIR:
+ if (value)
+ iopin_set_out (&iopin);
+ else
+ iopin_set_in (&iopin);
+ break;
+ case PAR:
+ if (value)
+ iopin_set_ded (&iopin);
+ else
+ iopin_set_gen (&iopin);
+ break;
+ case SOR:
+ if (value)
+ iopin_set_opt2 (&iopin);
+ else
+ iopin_set_opt1 (&iopin);
+ break;
+ case ODR:
+ if (value)
+ iopin_set_odr (&iopin);
+ else
+ iopin_set_act (&iopin);
+ break;
+ case DAT:
+ if (value)
+ iopin_set_high (&iopin);
+ else
+ iopin_set_low (&iopin);
+ break;
+ }
+
+ }
+ return rcode;
+#else
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+#endif
+}
+
+int
+do_dmainfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_fccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+static void prbrg (int n, uint val)
+{
+ uint extc = (val >> 14) & 3;
+ uint cd = (val & CPM_BRG_CD_MASK) >> 1;
+ uint div16 = (val & CPM_BRG_DIV16) != 0;
+
+#if defined(CONFIG_8xx)
+ DECLARE_GLOBAL_DATA_PTR;
+ ulong clock = gd->cpu_clk;
+#elif defined(CONFIG_8260)
+ DECLARE_GLOBAL_DATA_PTR;
+ ulong clock = gd->brg_clk;
+#endif
+
+ printf ("BRG%d:", n);
+
+ if (val & CPM_BRG_RST)
+ puts (" RESET");
+ else
+ puts (" ");
+
+ if (val & CPM_BRG_EN)
+ puts (" ENABLED");
+ else
+ puts (" DISABLED");
+
+ printf (" EXTC=%d", extc);
+
+ if (val & CPM_BRG_ATB)
+ puts (" ATB");
+ else
+ puts (" ");
+
+ printf (" DIVIDER=%4d", cd);
+ if (extc == 0 && cd != 0) {
+ uint baudrate;
+
+ if (div16)
+ baudrate = (clock / 16) / (cd + 1);
+ else
+ baudrate = clock / (cd + 1);
+
+ printf ("=%6d bps", baudrate);
+ } else {
+ puts (" ");
+ }
+
+ if (val & CPM_BRG_DIV16)
+ puts (" DIV16");
+ else
+ puts (" ");
+
+ putc ('\n');
+}
+
+int
+do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile cpm8xx_t *cp = &immap->im_cpm;
+ volatile uint *p = &cp->cp_brgc1;
+#elif defined(CONFIG_8260)
+ volatile uint *p = &immap->im_brgc1;
+#endif
+ int i = 1;
+
+ while (i <= 4)
+ prbrg (i++, *p++);
+
+#if defined(CONFIG_8260)
+ p = &immap->im_brgc5;
+ while (i <= 8)
+ prbrg (i++, *p++);
+#endif
+ return 0;
+}
+
+int
+do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+
+#if defined(CONFIG_8xx)
+ volatile i2c8xx_t *i2c = &immap->im_i2c;
+ volatile cpm8xx_t *cp = &immap->im_cpm;
+ volatile iic_t *iip = (iic_t *) & cp->cp_dparam[PROFF_IIC];
+#elif defined(CONFIG_8260)
+ volatile i2c8260_t *i2c = &immap->im_i2c;
+ volatile iic_t *iip;
+ uint dpaddr;
+
+ dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE]));
+ if (dpaddr == 0)
+ iip = NULL;
+ else
+ iip = (iic_t *) & immap->im_dprambase[dpaddr];
+#endif
+
+ printf ("I2MOD = %02x I2ADD = %02x\n", i2c->i2c_i2mod, i2c->i2c_i2add);
+ printf ("I2BRG = %02x I2COM = %02x\n", i2c->i2c_i2brg, i2c->i2c_i2com);
+ printf ("I2CER = %02x I2CMR = %02x\n", i2c->i2c_i2cer, i2c->i2c_i2cmr);
+
+ if (iip == NULL)
+ printf ("i2c parameter ram not allocated\n");
+ else {
+ printf ("RBASE = %08x TBASE = %08x\n",
+ iip->iic_rbase, iip->iic_tbase);
+ printf ("RFCR = %02x TFCR = %02x\n",
+ iip->iic_rfcr, iip->iic_tfcr);
+ printf ("MRBLR = %04x\n", iip->iic_mrblr);
+ printf ("RSTATE= %08x RDP = %08x\n",
+ iip->iic_rstate, iip->iic_rdp);
+ printf ("RBPTR = %04x RBC = %04x\n",
+ iip->iic_rbptr, iip->iic_rbc);
+ printf ("RXTMP = %08x\n", iip->iic_rxtmp);
+ printf ("TSTATE= %08x TDP = %08x\n",
+ iip->iic_tstate, iip->iic_tdp);
+ printf ("TBPTR = %04x TBC = %04x\n",
+ iip->iic_tbptr, iip->iic_tbc);
+ printf ("TXTMP = %08x\n", iip->iic_txtmp);
+ }
+ return 0;
+}
+
+int
+do_sccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_smcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_spiinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_muxinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_siinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+
+int
+do_mccinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unimplemented (cmdtp, flag, argc, argv);
+ return 0;
+}
+#endif /* CFG_CMD_IMMAP && (CONFIG_8xx || CONFIG_8260) */
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
new file mode 100644
index 0000000..fc1d9c4
--- /dev/null
+++ b/common/cmd_jffs2.c
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 2002
+ * 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_boot.h>
+#include <cmd_autoscript.h>
+#include <s_record.h>
+#include <net.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+#include <jffs2/jffs2.h>
+static int part_num=0;
+
+#ifndef CFG_JFFS_CUSTOM_PART
+
+static struct part_info part;
+
+struct part_info*
+jffs2_part_info(int part_num)
+{
+ extern flash_info_t flash_info[]; /* info for FLASH chips */
+ int i;
+
+ if(part_num==0){
+
+ if(part.usr_priv==(void*)1)
+ return ∂
+
+ memset(&part, 0, sizeof(part));
+
+#if defined(CFG_JFFS2_FIRST_SECTOR)
+ part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR];
+#else
+ part.offset = (unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+ /* Figure out flash partition size */
+ for (i = CFG_JFFS2_FIRST_BANK; i < CFG_JFFS2_NUM_BANKS+CFG_JFFS2_FIRST_BANK; i++)
+ part.size += flash_info[i].size;
+
+#if defined(CFG_JFFS2_FIRST_SECTOR) && (CFG_JFFS2_FIRST_SECTOR > 0)
+ part.size -=
+ flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] -
+ flash_info[CFG_JFFS2_FIRST_BANK].start[0];
+#endif
+
+ /* unused in current jffs2 loader */
+ part.erasesize = 0;
+
+ /* Mark the struct as ready */
+ part.usr_priv=(void*)1;
+
+ return ∂
+ }
+ return 0;
+}
+#endif /* ifndef CFG_JFFS_CUSTOM_PART */
+int
+do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *filename = "pImage";
+ ulong offset = CFG_LOAD_ADDR;
+ int size;
+ struct part_info *part;
+
+ if (argc == 2) {
+ filename = argv[1];
+ }
+ if (argc == 3) {
+ offset = simple_strtoul(argv[1], NULL, 16);
+ filename = argv[2];
+ }
+
+ if (0 != (part=jffs2_part_info(part_num))){
+
+ printf("### JFFS2 loading '%s' to 0x%lx\n", filename, offset);
+ size = jffs2_1pass_load((char *)offset, part, filename);
+
+ if (size > 0) {
+ char buf[10];
+ printf("### JFFS2 load complete: %d bytes loaded to 0x%lx\n",
+ size, offset);
+ sprintf(buf, "%x", size);
+ setenv("filesize", buf);
+ } else {
+ printf("### JFFS2 LOAD ERROR<%x> for %s!\n", size, filename);
+ }
+
+ return !(size > 0);
+ }
+ printf("Active partition not valid\n");
+ return 0;
+}
+
+int
+do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *filename = "/";
+ int ret;
+ struct part_info *part;
+
+ if (argc == 2)
+ filename = argv[1];
+
+ if (0 != (part=jffs2_part_info(part_num))){
+
+ ret = jffs2_1pass_ls(jffs2_part_info(part_num), filename);
+
+ return (ret == 1);
+ }
+ printf("Active partition not valid\n");
+ return 0;
+}
+
+int
+do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int ret;
+ struct part_info *part;
+
+ if (0 != (part=jffs2_part_info(part_num))){
+
+ ret = jffs2_1pass_info(jffs2_part_info(part_num));
+
+ return (ret == 1);
+ }
+ printf("Active partition not valid\n");
+ return 0;
+}
+
+int
+do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int tmp_part;
+
+ if (argc >= 2) {
+ tmp_part = simple_strtoul(argv[1], NULL, 16);
+ }else{
+ printf("Need partition number in argument list\n");
+ return 0;
+
+ }
+
+ if (jffs2_part_info(tmp_part)){
+ printf("Partiton changed to %d\n",tmp_part);
+ part_num=tmp_part;
+ return 0;
+ }
+
+ printf("Partition %d is not valid partiton\n",tmp_part);
+ return 0;
+
+}
+#endif /* CFG_CMD_JFFS2 */
diff --git a/common/cmd_pci.c b/common/cmd_pci.c
new file mode 100644
index 0000000..22e4b9a
--- /dev/null
+++ b/common/cmd_pci.c
@@ -0,0 +1,477 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Wolfgang Grandegger, DENX Software Engineering, wg@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
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <command.h>
+#include <cmd_boot.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <cmd_pci.h>
+#include <pci.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCI)
+
+extern int cmd_get_data_size(char* arg, int default_size);
+
+unsigned char ShortPCIListing = 1;
+
+/*
+ * Follows routines for the output of infos about devices on PCI bus.
+ */
+
+void pci_header_show(pci_dev_t dev);
+void pci_header_show_brief(pci_dev_t dev);
+
+/*
+ * Subroutine: pciinfo
+ *
+ * Description: Show information about devices on PCI bus.
+ * Depending on the define CFG_SHORT_PCI_LISTING
+ * the output will be more or less exhaustive.
+ *
+ * Inputs: bus_no the number of the bus to be scanned.
+ *
+ * Return: None
+ *
+ */
+void pciinfo(int BusNum, int ShortPCIListing)
+{
+ int Device;
+ int Function;
+ unsigned char HeaderType;
+ unsigned short VendorID;
+ pci_dev_t dev;
+
+ printf("Scanning PCI devices on bus %d\n", BusNum);
+
+ if (ShortPCIListing) {
+ printf("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
+ printf("_____________________________________________________________\n");
+ }
+
+ for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
+ HeaderType = 0;
+ VendorID = 0;
+ for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
+ /*
+ * If this is not a multi-function device, we skip the rest.
+ */
+ if (Function && !(HeaderType & 0x80))
+ break;
+
+ dev = PCI_BDF(BusNum, Device, Function);
+
+ pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
+ if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
+ continue;
+
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
+
+ if (ShortPCIListing)
+ {
+ printf("%02x.%02x.%02x ", BusNum, Device, Function);
+ pci_header_show_brief(dev);
+ }
+ else
+ {
+ printf("\nFound PCI device %02x.%02x.%02x:\n",
+ BusNum, Device, Function);
+ pci_header_show(dev);
+ }
+ }
+ }
+}
+
+char* pci_classes_str(u8 class)
+{
+ static char *pci_classes[] = {
+ "Build before PCI Rev2.0",
+ "Mass storage controller",
+ "Network controller ",
+ "Display controller ",
+ "Multimedia device ",
+ "Memory controller ",
+ "Bridge device ",
+ "Simple comm. controller",
+ "Base system peripheral ",
+ "Input device ",
+ "Docking station ",
+ "Processor ",
+ "Serial bus controller ",
+ "Reserved entry ",
+ "Does not fit any class "
+ };
+
+ if (class < (sizeof pci_classes / sizeof *pci_classes))
+ return pci_classes[(int) class];
+
+ return "??? ";
+}
+
+/*
+ * Subroutine: pci_header_show_brief
+ *
+ * Description: Reads and prints the header of the
+ * specified PCI device in short form.
+ *
+ * Inputs: dev Bus+Device+Function number
+ *
+ * Return: None
+ *
+ */
+void pci_header_show_brief(pci_dev_t dev)
+{
+ u16 vendor, device;
+ u8 class, subclass;
+
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+ pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
+ pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
+
+ printf("0x%.4x 0x%.4x %s 0x%.2x\n",
+ vendor, device,
+ pci_classes_str(class), subclass);
+}
+
+/*
+ * Subroutine: PCI_Header_Show
+ *
+ * Description: Reads the header of the specified PCI device.
+ *
+ * Inputs: BusDevFunc Bus+Device+Function number
+ *
+ * Return: None
+ *
+ */
+void pci_header_show(pci_dev_t dev)
+{
+ u8 _byte, header_type;
+ u16 _word;
+ u32 _dword;
+
+#define PRINT(msg, type, reg) \
+ pci_read_config_##type(dev, reg, &_##type); \
+ printf(msg, _##type)
+
+#define PRINT2(msg, type, reg, func) \
+ pci_read_config_##type(dev, reg, &_##type); \
+ printf(msg, _##type, func(_##type))
+
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ PRINT (" vendor ID = 0x%.4x\n", word, PCI_VENDOR_ID);
+ PRINT (" device ID = 0x%.4x\n", word, PCI_DEVICE_ID);
+ PRINT (" command register = 0x%.4x\n", word, PCI_COMMAND);
+ PRINT (" status register = 0x%.4x\n", word, PCI_STATUS);
+ PRINT (" revision ID = 0x%.2x\n", byte, PCI_REVISION_ID);
+ PRINT2(" class code = 0x%.2x (%s)\n", byte, PCI_CLASS_CODE,
+ pci_classes_str);
+ PRINT (" sub class code = 0x%.2x\n", byte, PCI_CLASS_SUB_CODE);
+ PRINT (" programming interface = 0x%.2x\n", byte, PCI_CLASS_PROG);
+ PRINT (" cache line = 0x%.2x\n", byte, PCI_CACHE_LINE_SIZE);
+ PRINT (" latency time = 0x%.2x\n", byte, PCI_LATENCY_TIMER);
+ PRINT (" header type = 0x%.2x\n", byte, PCI_HEADER_TYPE);
+ PRINT (" BIST = 0x%.2x\n", byte, PCI_BIST);
+ PRINT (" base address 0 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_0);
+ PRINT (" base address 1 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
+
+ if (header_type & 0x01) { /* PCI-to-PCI bridge */
+ PRINT (" primary bus number = 0x%.2x\n", byte, PCI_PRIMARY_BUS);
+ PRINT (" secondary bus number = 0x%.2x\n", byte, PCI_SECONDARY_BUS);
+ PRINT (" subordinate bus number = 0x%.2x\n", byte, PCI_SUBORDINATE_BUS);
+ PRINT (" secondary latency timer = 0x%.2x\n", byte, PCI_SEC_LATENCY_TIMER);
+ PRINT (" IO base = 0x%.2x\n", byte, PCI_IO_BASE);
+ PRINT (" IO limit = 0x%.2x\n", byte, PCI_IO_LIMIT);
+ PRINT (" secondary status = 0x%.4x\n", word, PCI_SEC_STATUS);
+ PRINT (" memory base = 0x%.4x\n", word, PCI_MEMORY_BASE);
+ PRINT (" memory limit = 0x%.4x\n", word, PCI_MEMORY_LIMIT);
+ PRINT (" prefetch memory base = 0x%.4x\n", word, PCI_PREF_MEMORY_BASE);
+ PRINT (" prefetch memory limit = 0x%.4x\n", word, PCI_PREF_MEMORY_LIMIT);
+ PRINT (" prefetch memory base upper = 0x%.8x\n", dword, PCI_PREF_BASE_UPPER32);
+ PRINT (" prefetch memory limit upper = 0x%.8x\n", dword, PCI_PREF_LIMIT_UPPER32);
+ PRINT (" IO base upper 16 bits = 0x%.4x\n", word, PCI_IO_BASE_UPPER16);
+ PRINT (" IO limit upper 16 bits = 0x%.4x\n", word, PCI_IO_LIMIT_UPPER16);
+ PRINT (" expansion ROM base address = 0x%.8x\n", dword, PCI_ROM_ADDRESS1);
+ PRINT (" interrupt line = 0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+ PRINT (" interrupt pin = 0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+ PRINT (" bridge control = 0x%.4x\n", word, PCI_BRIDGE_CONTROL);
+ } else { /* PCI device */
+ PRINT(" base address 2 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_2);
+ PRINT(" base address 3 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_3);
+ PRINT(" base address 4 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_4);
+ PRINT(" base address 5 = 0x%.8x\n", dword, PCI_BASE_ADDRESS_5);
+ PRINT(" cardBus CIS pointer = 0x%.8x\n", dword, PCI_CARDBUS_CIS);
+ PRINT(" sub system vendor ID = 0x%.4x\n", word, PCI_SUBSYSTEM_VENDOR_ID);
+ PRINT(" sub system ID = 0x%.4x\n", word, PCI_SUBSYSTEM_ID);
+ PRINT(" expansion ROM base address = 0x%.8x\n", dword, PCI_ROM_ADDRESS);
+ PRINT(" interrupt line = 0x%.2x\n", byte, PCI_INTERRUPT_LINE);
+ PRINT(" interrupt pin = 0x%.2x\n", byte, PCI_INTERRUPT_PIN);
+ PRINT(" min Grant = 0x%.2x\n", byte, PCI_MIN_GNT);
+ PRINT(" max Latency = 0x%.2x\n", byte, PCI_MAX_LAT);
+ }
+
+#undef PRINT
+#undef PRINT2
+}
+
+/* Convert the "bus.device.function" identifier into a number.
+ */
+static pci_dev_t get_pci_dev(char* name)
+{
+ char cnum[12];
+ int len, i, iold, n;
+ int bdfs[3] = {0,0,0};
+
+ len = strlen(name);
+ if (len > 8)
+ return -1;
+ for (i = 0, iold = 0, n = 0; i < len; i++) {
+ if (name[i] == '.') {
+ memcpy(cnum, &name[iold], i - iold);
+ cnum[i - iold] = '\0';
+ bdfs[n++] = simple_strtoul(cnum, NULL, 16);
+ iold = i + 1;
+ }
+ }
+ strcpy(cnum, &name[iold]);
+ if (n == 0)
+ n = 1;
+ bdfs[n] = simple_strtoul(cnum, NULL, 16);
+ return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
+}
+
+static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
+{
+#define DISP_LINE_LEN 16
+ ulong i, nbytes, linebytes;
+ int rc = 0;
+
+ if (length == 0)
+ length = 0x40 / size; /* Standard PCI configuration space */
+
+ /* Print the lines.
+ * once, and all accesses are with the specified bus width.
+ */
+ nbytes = length * size;
+ do {
+ uint val4;
+ ushort val2;
+ u_char val1;
+
+ printf("%08lx:", addr);
+ linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
+ for (i=0; i<linebytes; i+= size) {
+ if (size == 4) {
+ pci_read_config_dword(bdf, addr, &val4);
+ printf(" %08x", val4);
+ } else if (size == 2) {
+ pci_read_config_word(bdf, addr, &val2);
+ printf(" %04x", val2);
+ } else {
+ pci_read_config_byte(bdf, addr, &val1);
+ printf(" %02x", val1);
+ }
+ addr += size;
+ }
+ printf("\n");
+ nbytes -= linebytes;
+ if (ctrlc()) {
+ rc = 1;
+ break;
+ }
+ } while (nbytes > 0);
+
+ return (rc);
+}
+
+static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
+{
+ if (size == 4) {
+ pci_write_config_dword(bdf, addr, value);
+ }
+ else if (size == 2) {
+ ushort val = value & 0xffff;
+ pci_write_config_word(bdf, addr, val);
+ }
+ else {
+ u_char val = value & 0xff;
+ pci_write_config_byte(bdf, addr, val);
+ }
+ return 0;
+}
+
+static int
+pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
+{
+ ulong i;
+ int nbytes;
+ extern char console_buffer[];
+ uint val4;
+ ushort val2;
+ u_char val1;
+
+ /* 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) {
+ pci_read_config_dword(bdf, addr, &val4);
+ printf(" %08x", val4);
+ }
+ else if (size == 2) {
+ pci_read_config_word(bdf, addr, &val2);
+ printf(" %04x", val2);
+ }
+ else {
+ pci_read_config_byte(bdf, addr, &val1);
+ printf(" %02x", val1);
+ }
+
+ 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
+ pci_cfg_write (bdf, addr, size, i);
+ if (incrflag)
+ addr += size;
+ }
+ }
+ } while (nbytes);
+
+ return 0;
+}
+
+/* PCI Configuration Space access commands
+ *
+ * Syntax:
+ * pci display[.b, .w, .l] bus.device.function} [addr] [len]
+ * pci next[.b, .w, .l] bus.device.function [addr]
+ * pci modify[.b, .w, .l] bus.device.function [addr]
+ * pci write[.b, .w, .l] bus.device.function addr value
+ */
+int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ ulong addr = 0, value = 0, size = 0;
+ pci_dev_t bdf = 0;
+ char cmd = 's';
+
+ if (argc > 1)
+ cmd = argv[1][0];
+
+ switch (cmd) {
+ case 'd': /* display */
+ case 'n': /* next */
+ case 'm': /* modify */
+ case 'w': /* write */
+ /* Check for a size specification. */
+ size = cmd_get_data_size(argv[1], 4);
+ if (argc > 3)
+ addr = simple_strtoul(argv[3], NULL, 16);
+ if (argc > 4)
+ value = simple_strtoul(argv[4], NULL, 16);
+ case 'h': /* header */
+ if (argc < 3)
+ goto usage;
+ if ((bdf = get_pci_dev(argv[2])) == -1)
+ return 1;
+ break;
+ default: /* scan bus */
+ value = 1; /* short listing */
+ bdf = 0; /* bus number */
+ if (argc > 1) {
+ if (argv[argc-1][0] == 'l') {
+ value = 0;
+ argc--;
+ }
+ if (argc > 1)
+ bdf = simple_strtoul(argv[1], NULL, 16);
+ }
+ pciinfo(bdf, value);
+ return 0;
+ }
+
+ switch (argv[1][0]) {
+ case 'h': /* header */
+ pci_header_show(bdf);
+ return 0;
+ case 'd': /* display */
+ return pci_cfg_display(bdf, addr, size, value);
+ case 'n': /* next */
+ if (argc < 4)
+ goto usage;
+ return pci_cfg_modify(bdf, addr, size, value, 0);
+ case 'm': /* modify */
+ if (argc < 4)
+ goto usage;
+ return pci_cfg_modify(bdf, addr, size, value, 1);
+ case 'w': /* write */
+ if (argc < 5)
+ goto usage;
+ return pci_cfg_write(bdf, addr, size, value);
+ }
+
+ return 1;
+ usage:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_PCI) */
+
+#endif /* CONFIG_PCI */
diff --git a/common/cmd_pcmcia.c b/common/cmd_pcmcia.c
new file mode 100644
index 0000000..ccf21a9
--- /dev/null
+++ b/common/cmd_pcmcia.c
@@ -0,0 +1,2243 @@
+/*
+ * (C) Copyright 2000-2002
+ * 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
+ *
+ ********************************************************************
+ *
+ * Lots of code copied from:
+ *
+ * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
+ * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
+ *
+ * "The ExCA standard specifies that socket controllers should provide
+ * two IO and five memory windows per socket, which can be independently
+ * configured and positioned in the host address space and mapped to
+ * arbitrary segments of card address space. " - David A Hinds. 1999
+ *
+ * This controller does _not_ meet the ExCA standard.
+ *
+ * m8xx pcmcia controller brief info:
+ * + 8 windows (attrib, mem, i/o)
+ * + up to two slots (SLOT_A and SLOT_B)
+ * + inputpins, outputpins, event and mask registers.
+ * - no offset register. sigh.
+ *
+ * Because of the lacking offset register we must map the whole card.
+ * We assign each memory window PCMCIA_MEM_WIN_SIZE address space.
+ * Make sure there is (PCMCIA_MEM_WIN_SIZE * PCMCIA_MEM_WIN_NO
+ * * PCMCIA_SOCKETS_NO) bytes at PCMCIA_MEM_WIN_BASE.
+ * The i/o windows are dynamically allocated at PCMCIA_IO_WIN_BASE.
+ * They are maximum 64KByte each...
+ */
+
+/* #define DEBUG 1 */
+
+/*
+ * PCMCIA support
+ */
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <pcmcia.h>
+#include <cmd_pcmcia.h>
+#if defined(CONFIG_IDE_8xx_PCCARD) && defined(CONFIG_8xx)
+#include <mpc8xx.h>
+#endif
+#if defined(CONFIG_LWMON)
+#include <i2c.h>
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
+ ((CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD))
+
+int pcmcia_on (void);
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int pcmcia_off (void);
+static int hardware_disable(int slot);
+#endif
+static int hardware_enable (int slot);
+static int voltage_set(int slot, int vcc, int vpp);
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func);
+static void print_fixed (volatile uchar *p);
+static int identify (volatile uchar *p);
+static int check_ide_device (void);
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+static u_int m8xx_get_graycode(u_int size);
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* look up table for pgcrx registers */
+
+static u_int *pcmcia_pgcrx[2] = {
+ &((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcra,
+ &((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pgcrb,
+};
+
+#define PCMCIA_PGCRX(slot) (*pcmcia_pgcrx[slot])
+
+const char *indent = "\t ";
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+int do_pinit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int rcode = 0;
+
+ if (argc != 2) {
+ printf ("Usage: pinit {on | off}\n");
+ return 1;
+ }
+ if (strcmp(argv[1],"on") == 0) {
+ rcode = pcmcia_on ();
+ } else if (strcmp(argv[1],"off") == 0) {
+ rcode = pcmcia_off ();
+ } else {
+ printf ("Usage: pinit {on | off}\n");
+ return 1;
+ }
+
+ return rcode;
+}
+#endif /* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+# define CFG_PCMCIA_TIMING (PCMCIA_SHT(9) | PCMCIA_SST(3) | PCMCIA_SL(12))
+#else
+# define CFG_PCMCIA_TIMING (PCMCIA_SHT(2) | PCMCIA_SST(4) | PCMCIA_SL(9))
+#endif
+
+int pcmcia_on (void)
+{
+ int i;
+ u_long reg, base;
+ pcmcia_win_t *win;
+
+ debug ("Enable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+ /* intialize the fixed memory windows */
+ win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+ base = CFG_PCMCIA_MEM_ADDR;
+
+ if((reg = m8xx_get_graycode(CFG_PCMCIA_MEM_SIZE)) == -1) {
+ printf ("Cannot set window size to 0x%08x\n",
+ CFG_PCMCIA_MEM_SIZE);
+ return (1);
+ }
+
+ for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+ win->br = base;
+
+ switch (i) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+ case 0: { /* map attribute memory */
+ win->or = ( PCMCIA_BSIZE_64M
+ | PCMCIA_PPS_8
+ | PCMCIA_PRS_ATTR
+ | PCMCIA_SLOT_x
+ | PCMCIA_PV
+ | CFG_PCMCIA_TIMING );
+ break;
+ }
+
+ case 1: { /* map I/O window for data reg */
+ win->or = ( PCMCIA_BSIZE_1K
+ | PCMCIA_PPS_16
+ | PCMCIA_PRS_IO
+ | PCMCIA_SLOT_x
+ | PCMCIA_PV
+ | CFG_PCMCIA_TIMING );
+ break;
+ }
+
+ case 2: { /* map I/O window for command/ctrl reg block */
+ win->or = ( PCMCIA_BSIZE_1K
+ | PCMCIA_PPS_8
+ | PCMCIA_PRS_IO
+ | PCMCIA_SLOT_x
+ | PCMCIA_PV
+ | CFG_PCMCIA_TIMING );
+ break;
+ }
+#endif /* CONFIG_IDE_8xx_PCCARD */
+ default: /* set to not valid */
+ win->or = 0;
+ break;
+ }
+
+ debug ("MemWin %d: PBR 0x%08lX POR %08lX\n",
+ i, win->br, win->or);
+ base += CFG_PCMCIA_MEM_SIZE;
+ ++win;
+ }
+
+ /* turn off voltage */
+ if (voltage_set(_slot_, 0, 0))
+ return (1);
+
+ /* Enable external hardware */
+ if (hardware_enable(_slot_))
+ return (1);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+ if (check_ide_device())
+ return (1);
+#endif
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+
+static int pcmcia_off (void)
+{
+ int i;
+ pcmcia_win_t *win;
+
+ printf ("Disable PCMCIA " PCMCIA_SLOT_MSG "\n");
+
+ /* clear interrupt state, and disable interrupts */
+ ((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pscr = PCMCIA_MASK(_slot_);
+ ((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* turn off interrupt and disable CxOE */
+ PCMCIA_PGCRX(_slot_) = __MY_PCMCIA_GCRX_CXOE;
+
+ /* turn off memory windows */
+ win = (pcmcia_win_t *)(&((immap_t *)CFG_IMMR)->im_pcmcia.pcmc_pbr0);
+
+ for (i=0; i<PCMCIA_MEM_WIN_NO; ++i) {
+ /* disable memory window */
+ win->or = 0;
+ ++win;
+ }
+
+ /* turn off voltage */
+ voltage_set(_slot_, 0, 0);
+
+ /* disable external hardware */
+ printf ("Shutdown and Poweroff " PCMCIA_SLOT_MSG "\n");
+ hardware_disable(_slot_);
+ return 0;
+}
+
+#endif /* CFG_CMD_PCMCIA */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define MAX_TUPEL_SZ 512
+#define MAX_FEATURES 4
+
+static int check_ide_device (void)
+{
+ volatile uchar *ident = NULL;
+ volatile uchar *feature_p[MAX_FEATURES];
+ volatile uchar *p, *start;
+ int n_features = 0;
+ uchar func_id = ~0;
+ uchar code, len;
+ ushort config_base = 0;
+ int found = 0;
+ int i;
+
+ debug ("PCMCIA MEM: %08X\n", CFG_PCMCIA_MEM_ADDR);
+
+ start = p = (volatile uchar *) CFG_PCMCIA_MEM_ADDR;
+
+ while ((p - start) < MAX_TUPEL_SZ) {
+
+ code = *p; p += 2;
+
+ if (code == 0xFF) { /* End of chain */
+ break;
+ }
+
+ len = *p; p += 2;
+#if defined(DEBUG) && (DEBUG > 1)
+ { volatile uchar *q = p;
+ printf ("\nTuple code %02x length %d\n\tData:",
+ code, len);
+
+ for (i = 0; i < len; ++i) {
+ printf (" %02x", *q);
+ q+= 2;
+ }
+ }
+#endif /* DEBUG */
+ switch (code) {
+ case CISTPL_VERS_1:
+ ident = p + 4;
+ break;
+ case CISTPL_FUNCID:
+ /* Fix for broken SanDisk which may have 0x80 bit set */
+ func_id = *p & 0x7F;
+ break;
+ case CISTPL_FUNCE:
+ if (n_features < MAX_FEATURES)
+ feature_p[n_features++] = p;
+ break;
+ case CISTPL_CONFIG:
+ config_base = (*(p+6) << 8) + (*(p+4));
+ debug ("\n## Config_base = %04x ###\n", config_base);
+ default:
+ break;
+ }
+ p += 2 * len;
+ }
+
+ found = identify (ident);
+
+ if (func_id != ((uchar)~0)) {
+ print_funcid (func_id);
+
+ if (func_id == CISTPL_FUNCID_FIXED)
+ found = 1;
+ else
+ return (1); /* no disk drive */
+ }
+
+ for (i=0; i<n_features; ++i) {
+ print_fixed (feature_p[i]);
+ }
+
+ if (!found) {
+ printf ("unknown card type\n");
+ return (1);
+ }
+
+ /* set I/O area in config reg -> only valid for ARGOSY D5!!! */
+ *((uchar *)(CFG_PCMCIA_MEM_ADDR + config_base)) = 1;
+
+ return (0);
+}
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* board specific stuff: */
+/* voltage_set(), hardware_enable() and hardware_disable() */
+/* ---------------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------------- */
+/* RPX Boards from Embedded Planet */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
+
+/* The RPX boards seems to have it's bus monitor timeout set to 6*8 clocks.
+ * SYPCR is write once only, therefore must the slowest memory be faster
+ * than the bus monitor or we will get a machine check due to the bus timeout.
+ */
+
+#define PCMCIA_BOARD_MSG "RPX CLASSIC or RPX LITE"
+
+#undef PCMCIA_BMT_LIMIT
+#define PCMCIA_BMT_LIMIT (6*8)
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ u_long reg = 0;
+
+ switch(vcc) {
+ case 0: break;
+ case 33: reg |= BCSR1_PCVCTL4; break;
+ case 50: reg |= BCSR1_PCVCTL5; break;
+ default: return 1;
+ }
+
+ switch(vpp) {
+ case 0: break;
+ case 33:
+ case 50:
+ if(vcc == vpp)
+ reg |= BCSR1_PCVCTL6;
+ else
+ return 1;
+ break;
+ case 120:
+ reg |= BCSR1_PCVCTL7;
+ default: return 1;
+ }
+
+ if(vcc == 120)
+ return 1;
+
+ /* first, turn off all power */
+
+ *((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5
+ | BCSR1_PCVCTL6 | BCSR1_PCVCTL7);
+
+ /* enable new powersettings */
+
+ *((uint *)RPX_CSR_ADDR) |= reg;
+
+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+static int hardware_enable (int slot)
+{
+ return 0; /* No hardware to enable */
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ return 0; /* No hardware to disable */
+}
+#endif /* CFG_CMD_PCMCIA */
+#endif /* CONFIG_RPXCLASSIC */
+
+/* ---------------------------------------------------------------------------- */
+/* (F)ADS Boards from Motorola */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ADS) || defined(CONFIG_FADS)
+
+#ifdef CONFIG_ADS
+#define PCMCIA_BOARD_MSG "ADS"
+#define PCMCIA_GLITCHY_CD /* My ADS board needs this */
+#else
+#define PCMCIA_BOARD_MSG "FADS"
+#endif
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ u_long reg = 0;
+
+ switch(vpp) {
+ case 0: reg = 0; break;
+ case 50: reg = 1; break;
+ case 120: reg = 2; break;
+ default: return 1;
+ }
+
+ switch(vcc) {
+ case 0: reg = 0; break;
+#ifdef CONFIG_ADS
+ case 50: reg = BCSR1_PCCVCCON; break;
+#endif
+#ifdef CONFIG_FADS
+ case 33: reg = BCSR1_PCCVCC0 | BCSR1_PCCVCC1; break;
+ case 50: reg = BCSR1_PCCVCC1; break;
+#endif
+ default: return 1;
+ }
+
+ /* first, turn off all power */
+
+#ifdef CONFIG_ADS
+ *((uint *)BCSR1) |= BCSR1_PCCVCCON;
+#endif
+#ifdef CONFIG_FADS
+ *((uint *)BCSR1) &= ~(BCSR1_PCCVCC0 | BCSR1_PCCVCC1);
+#endif
+ *((uint *)BCSR1) &= ~BCSR1_PCCVPP_MASK;
+
+ /* enable new powersettings */
+
+#ifdef CONFIG_ADS
+ *((uint *)BCSR1) &= ~reg;
+#endif
+#ifdef CONFIG_FADS
+ *((uint *)BCSR1) |= reg;
+#endif
+
+ *((uint *)BCSR1) |= reg << 20;
+
+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+
+static int hardware_enable(int slot)
+{
+ *((uint *)BCSR1) &= ~BCSR1_PCCEN;
+ return 0;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ *((uint *)BCSR1) &= ~BCSR1_PCCEN;
+ return 0;
+}
+#endif /* CFG_CMD_PCMCIA */
+
+#endif /* (F)ADS */
+
+/* ---------------------------------------------------------------------------- */
+/* TQM8xxL Boards by TQ Components */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_TQM8xxL)
+
+#define PCMCIA_BOARD_MSG "TQM8xxL"
+
+
+static int hardware_enable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, mask;
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ udelay(10000);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /*
+ * Configure SIUMCR to enable PCMCIA port B
+ * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+ */
+ sysp->sc_siumcr &= ~SIUMCR_DBGC11; /* set DBGC to 00 */
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Port C pins for
+ * 5 Volts Enable and 3 Volts enable
+ */
+ immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+ immap->im_ioport.iop_pcso &= ~(0x0002 | 0x0004);
+ /* remove all power */
+
+ immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On.
+ */
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ reg = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ reg,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+ if ((reg & mask) == mask) {
+ immap->im_ioport.iop_pcdat |= 0x0004;
+ puts (" 5.0V card found: ");
+ } else {
+ immap->im_ioport.iop_pcdat |= 0x0002;
+ puts (" 3.3V card found: ");
+ }
+ immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
+#if 0
+ /* VCC switch error flag, PCMCIA slot INPACK_ pin */
+ cp->cp_pbdir &= ~(0x0020 | 0x0010);
+ cp->cp_pbpar &= ~(0x0020 | 0x0010);
+ udelay(500000);
+#endif
+ udelay(1000);
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+ /* remove all power */
+ immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+ /* Configure PCMCIA General Control Register */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(10000);
+
+ return (0);
+}
+#endif /* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("voltage_set: "
+ PCMCIA_BOARD_MSG
+ " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Port C pins for
+ * 5 Volts Enable and 3 Volts enable,
+ * Turn off all power
+ */
+ debug ("PCMCIA power OFF\n");
+ immap->im_ioport.iop_pcpar &= ~(0x0002 | 0x0004);
+ immap->im_ioport.iop_pcso &= ~(0x0002 | 0x0004);
+ immap->im_ioport.iop_pcdat &= ~(0x0002 | 0x0004);
+
+ reg = 0;
+ switch(vcc) {
+ case 0: break;
+ case 33: reg |= 0x0002; break;
+ case 50: reg |= 0x0004; break;
+ default: goto done;
+ }
+
+ /* Checking supported voltages */
+
+ debug ("PIPR: 0x%x --> %s\n",
+ pcmp->pcmc_pipr,
+ (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+ immap->im_ioport.iop_pcdat |= reg;
+ immap->im_ioport.iop_pcdir |= (0x0002 | 0x0004);
+ if (reg) {
+ debug ("PCMCIA powered at %sV\n",
+ (reg&0x0004) ? "5.0" : "3.3");
+ } else {
+ debug ("PCMCIA powered down\n");
+ }
+
+done:
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+ slot+'A');
+ return (0);
+}
+
+#endif /* TQM8xxL */
+
+
+/* ---------------------------------------------------------------------------- */
+/* LWMON Board */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LWMON)
+
+#define PCMCIA_BOARD_MSG "LWMON"
+
+/* #define's for MAX1604 Power Switch */
+#define MAX1604_OP_SUS 0x80
+#define MAX1604_VCCBON 0x40
+#define MAX1604_VCC_35 0x20
+#define MAX1604_VCCBHIZ 0x10
+#define MAX1604_VPPBON 0x08
+#define MAX1604_VPPBPBPGM 0x04
+#define MAX1604_VPPBHIZ 0x02
+/* reserved 0x01 */
+
+static int hardware_enable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, mask;
+ uchar val;
+
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ /* Switch on PCMCIA port in PIC register 0x60 */
+ reg = pic_read (0x60);
+ debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+ reg &= ~0x10;
+ /* reg |= 0x08; Vpp not needed */
+ pic_write (0x60, reg);
+#ifdef DEBUG
+ reg = pic_read (0x60);
+ printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+ udelay(10000);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /*
+ * Configure SIUMCR to enable PCMCIA port B
+ * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+ */
+ sysp->sc_siumcr &= ~SIUMCR_DBGC11; /* set DBGC to 00 */
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On.
+ */
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ reg = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ reg,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+ if ((reg & mask) == mask) {
+ val = 0; /* VCCB3/5 = 0 ==> use Vx = 5.0 V */
+ puts (" 5.0V card found: ");
+ } else {
+ val = MAX1604_VCC_35; /* VCCB3/5 = 1 ==> use Vy = 3.3 V */
+ puts (" 3.3V card found: ");
+ }
+
+ /* switch VCC on */
+ val |= MAX1604_OP_SUS | MAX1604_VCCBON;
+ i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+ udelay(500000);
+
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+ uchar val;
+
+ debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+ /* remove all power, put output in high impedance state */
+ val = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+ i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+ /* Configure PCMCIA General Control Register */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ /* Switch off PCMCIA port in PIC register 0x60 */
+ reg = pic_read (0x60);
+ debug ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+ reg |= 0x10;
+ reg &= ~0x08;
+ pic_write (0x60, reg);
+#ifdef DEBUG
+ reg = pic_read (0x60);
+ printf ("[%d] PIC read: reg_60 = 0x%02x\n", __LINE__, reg);
+#endif
+ udelay(10000);
+
+ return (0);
+}
+#endif /* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+ uchar val;
+
+ debug ("voltage_set: "
+ PCMCIA_BOARD_MSG
+ " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Turn off all power (switch to high impedance)
+ */
+ debug ("PCMCIA power OFF\n");
+ val = MAX1604_VCCBHIZ | MAX1604_VPPBHIZ;
+ i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
+ i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+
+ val = 0;
+ switch(vcc) {
+ case 0: break;
+ case 33: val = MAX1604_VCC_35; break;
+ case 50: break;
+ default: goto done;
+ }
+
+ /* Checking supported voltages */
+
+ debug ("PIPR: 0x%x --> %s\n",
+ pcmp->pcmc_pipr,
+ (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+ i2c_write (CFG_I2C_POWER_A_ADDR, 0, 0, &val, 1);
+ if (val) {
+ debug ("PCMCIA powered at %sV\n",
+ (val & MAX1604_VCC_35) ? "3.3" : "5.0");
+ } else {
+ debug ("PCMCIA powered down\n");
+ }
+
+done:
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+ slot+'A');
+ return (0);
+}
+
+#endif /* LWMON */
+
+/* ---------------------------------------------------------------------------- */
+/* GTH board by Corelatus AB */
+/* ---------------------------------------------------------------------------- */
+#if defined(CONFIG_GTH)
+
+#define PCMCIA_BOARD_MSG "GTH COMPACT FLASH"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{ /* Do nothing */
+ return 0;
+}
+
+static int hardware_enable (int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, mask;
+
+ debug ("hardware_enable: GTH Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x98000000) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ reg = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ reg,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return 0;
+}
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ return 0; /* No hardware to disable */
+}
+#endif /* CFG_CMD_PCMCIA */
+#endif /* CONFIG_GTH */
+
+/* ---------------------------------------------------------------------------- */
+/* ICU862 Boards by Cambridge Broadband Ltd. */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_ICU862)
+
+#define PCMCIA_BOARD_MSG "ICU862"
+
+static void cfg_port_B (void);
+
+static int hardware_enable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, pipr, mask;
+ int i;
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ udelay(10000);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /* Configure Port B for TPS2205 PC-Card Power-Interface Switch */
+ cfg_port_B ();
+
+ /*
+ * Configure SIUMCR to enable PCMCIA port B
+ * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+ */
+ sysp->sc_siumcr &= ~SIUMCR_DBGC11; /* set DBGC to 00 */
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+ */
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ pipr = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ pipr,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+
+ reg = cp->cp_pbdat;
+ if ((pipr & mask) == mask) {
+ reg |= (TPS2205_VPP_PGM | TPS2205_VPP_VCC | /* VAVPP => Hi-Z */
+ TPS2205_VCC3); /* 3V off */
+ reg &= ~(TPS2205_VCC5); /* 5V on */
+ puts (" 5.0V card found: ");
+ } else {
+ reg |= (TPS2205_VPP_PGM | TPS2205_VPP_VCC | /* VAVPP => Hi-Z */
+ TPS2205_VCC5); /* 5V off */
+ reg &= ~(TPS2205_VCC3); /* 3V on */
+ puts (" 3.3V card found: ");
+ }
+
+ debug ("\nPB DAT: %08x -> 3.3V %s 5.0V %s VPP_PGM %s VPP_VCC %s\n",
+ reg,
+ (reg & TPS2205_VCC3) ? "off" : "on",
+ (reg & TPS2205_VCC5) ? "off" : "on",
+ (reg & TPS2205_VPP_PGM) ? "off" : "on",
+ (reg & TPS2205_VPP_VCC) ? "off" : "on" );
+
+ cp->cp_pbdat = reg;
+
+ /* Wait 500 ms; use this to check for over-current */
+ for (i=0; i<5000; ++i) {
+ if ((cp->cp_pbdat & TPS2205_OC) == 0) {
+ printf (" *** Overcurrent - Safety shutdown ***\n");
+ cp->cp_pbdat &= ~(TPS2205_SHDN);
+ return (1);
+ }
+ udelay (100);
+ }
+
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+ /* Shut down */
+ cp->cp_pbdat &= ~(TPS2205_SHDN);
+
+ /* Configure PCMCIA General Control Register */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(10000);
+
+ return (0);
+}
+#endif /* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("voltage_set: "
+ PCMCIA_BOARD_MSG
+ " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+ immap = (immap_t *)CFG_IMMR;
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Port C pins for
+ * 5 Volts Enable and 3 Volts enable,
+ * Turn all power pins to Hi-Z
+ */
+ debug ("PCMCIA power OFF\n");
+ cfg_port_B (); /* Enables switch, but all in Hi-Z */
+
+ reg = cp->cp_pbdat;
+
+ switch(vcc) {
+ case 0: break; /* Switch off */
+ case 33: reg &= ~TPS2205_VCC3; break; /* Switch on 3.3V */
+ case 50: reg &= ~TPS2205_VCC5; break; /* Switch on 5.0V */
+ default: goto done;
+ }
+
+ /* Checking supported voltages */
+
+ debug ("PIPR: 0x%x --> %s\n",
+ pcmp->pcmc_pipr,
+ (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+ cp->cp_pbdat = reg;
+
+#ifdef DEBUG
+ {
+ char *s;
+
+ if ((reg & TPS2205_VCC3) == 0) {
+ s = "at 3.3V";
+ } else if ((reg & TPS2205_VCC5) == 0) {
+ s = "at 5.0V";
+ } else {
+ s = "down";
+ }
+ printf ("PCMCIA powered %s\n", s);
+ }
+#endif
+
+done:
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+ slot+'A');
+ return (0);
+}
+
+static void cfg_port_B (void)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ uint reg;
+
+ immap = (immap_t *)CFG_IMMR;
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /*
+ * Configure Port B for TPS2205 PC-Card Power-Interface Switch
+ *
+ * Switch off all voltages, assert shutdown
+ */
+ reg = cp->cp_pbdat;
+ reg |= (TPS2205_VPP_PGM | TPS2205_VPP_VCC | /* VAVPP => Hi-Z */
+ TPS2205_VCC3 | TPS2205_VCC5 | /* VAVCC => Hi-Z */
+ TPS2205_SHDN); /* enable switch */
+ cp->cp_pbdat = reg;
+
+ cp->cp_pbpar &= ~(TPS2205_INPUTS | TPS2205_OUTPUTS);
+
+ reg = cp->cp_pbdir & ~(TPS2205_INPUTS);
+ cp->cp_pbdir = reg | TPS2205_OUTPUTS;
+
+ debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+ cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif /* ICU862 */
+
+
+/* ---------------------------------------------------------------------------- */
+/* C2MON Boards by TTTech Computertechnik AG */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_C2MON)
+
+#define PCMCIA_BOARD_MSG "C2MON"
+
+static void cfg_ports (void);
+
+static int hardware_enable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, pipr, mask;
+ ushort sreg;
+ int i;
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ udelay(10000);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /* Configure Ports for TPS2211A PC-Card Power-Interface Switch */
+ cfg_ports ();
+
+ /*
+ * Configure SIUMCR to enable PCMCIA port B
+ * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+ */
+ sysp->sc_siumcr &= ~SIUMCR_DBGC11; /* set DBGC to 00 */
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z
+ */
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ pipr = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ pipr,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+
+ sreg = immap->im_ioport.iop_pcdat;
+ if ((pipr & mask) == mask) {
+ sreg |= (TPS2211_VPPD0 | TPS2211_VPPD1 | /* VAVPP => Hi-Z */
+ TPS2211_VCCD1); /* 5V on */
+ sreg &= ~(TPS2211_VCCD0); /* 3V off */
+ puts (" 5.0V card found: ");
+ } else {
+ sreg |= (TPS2211_VPPD0 | TPS2211_VPPD1 | /* VAVPP => Hi-Z */
+ TPS2211_VCCD0); /* 3V on */
+ sreg &= ~(TPS2211_VCCD1); /* 5V off */
+ puts (" 3.3V card found: ");
+ }
+
+ debug ("\nPC DAT: %04x -> 3.3V %s 5.0V %s\n",
+ sreg,
+ ( (sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) ? "on" : "off",
+ (!(sreg & TPS2211_VCCD0) && (sreg & TPS2211_VCCD1)) ? "on" : "off"
+ );
+
+ immap->im_ioport.iop_pcdat = sreg;
+
+ /* Wait 500 ms; use this to check for over-current */
+ for (i=0; i<5000; ++i) {
+ if ((cp->cp_pbdat & TPS2211_OC) == 0) {
+ printf (" *** Overcurrent - Safety shutdown ***\n");
+ immap->im_ioport.iop_pcdat &= ~(TPS2211_VCCD0|TPS2211_VCCD1);
+ return (1);
+ }
+ udelay (100);
+ }
+
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+ /* Configure PCMCIA General Control Register */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ /* ALl voltages off / Hi-Z */
+ immap->im_ioport.iop_pcdat |= (TPS2211_VPPD0 | TPS2211_VPPD1 |
+ TPS2211_VCCD0 | TPS2211_VCCD1 );
+
+ udelay(10000);
+
+ return (0);
+}
+#endif /* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+ ushort sreg;
+
+ debug ("voltage_set: "
+ PCMCIA_BOARD_MSG
+ " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+ immap = (immap_t *)CFG_IMMR;
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Port C pins for
+ * 5 Volts Enable and 3 Volts enable,
+ * Turn all power pins to Hi-Z
+ */
+ debug ("PCMCIA power OFF\n");
+ cfg_ports (); /* Enables switch, but all in Hi-Z */
+
+ sreg = immap->im_ioport.iop_pcdat;
+ sreg |= TPS2211_VPPD0 | TPS2211_VPPD1; /* VAVPP always Hi-Z */
+
+ switch(vcc) {
+ case 0: break; /* Switch off */
+ case 33: sreg |= TPS2211_VCCD0; /* Switch on 3.3V */
+ sreg &= ~TPS2211_VCCD1;
+ break;
+ case 50: sreg &= ~TPS2211_VCCD0; /* Switch on 5.0V */
+ sreg |= TPS2211_VCCD1;
+ break;
+ default: goto done;
+ }
+
+ /* Checking supported voltages */
+
+ debug ("PIPR: 0x%x --> %s\n",
+ pcmp->pcmc_pipr,
+ (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+ immap->im_ioport.iop_pcdat = sreg;
+
+#ifdef DEBUG
+ {
+ char *s;
+
+ if ((sreg & TPS2211_VCCD0) && !(sreg & TPS2211_VCCD1)) {
+ s = "at 3.3V";
+ } else if (!(sreg & TPS2211_VCCD0) && (sreg & TPS2211_VCCD1)) {
+ s = "at 5.0V";
+ } else {
+ s = "down";
+ }
+ printf ("PCMCIA powered %s\n", s);
+ }
+#endif
+
+done:
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+ slot+'A');
+ return (0);
+}
+
+static void cfg_ports (void)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ ushort sreg;
+
+ immap = (immap_t *)CFG_IMMR;
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /*
+ * Configure Port C for TPS2211 PC-Card Power-Interface Switch
+ *
+ * Switch off all voltages, assert shutdown
+ */
+ sreg = immap->im_ioport.iop_pcdat;
+ sreg |= (TPS2211_VPPD0 | TPS2211_VPPD1); /* VAVPP => Hi-Z */
+ sreg &= ~(TPS2211_VCCD0 | TPS2211_VCCD1); /* 3V and 5V off */
+ immap->im_ioport.iop_pcdat = sreg;
+
+ immap->im_ioport.iop_pcpar &= ~(TPS2211_OUTPUTS);
+ immap->im_ioport.iop_pcdir |= TPS2211_OUTPUTS;
+
+ debug ("Set Port C: PAR: %04x DIR: %04x DAT: %04x\n",
+ immap->im_ioport.iop_pcpar,
+ immap->im_ioport.iop_pcdir,
+ immap->im_ioport.iop_pcdat);
+
+ /*
+ * Configure Port B for TPS2211 PC-Card Power-Interface Switch
+ *
+ * Over-Current Input only
+ */
+ cp->cp_pbpar &= ~(TPS2211_INPUTS);
+ cp->cp_pbdir &= ~(TPS2211_INPUTS);
+
+ debug ("Set Port B: PAR: %08x DIR: %08x DAT: %08x\n",
+ cp->cp_pbpar, cp->cp_pbdir, cp->cp_pbdat);
+}
+
+#endif /* C2MON */
+
+/* ----------------------------------------------------------------------------
+ MBX board from Morotola
+ ---------------------------------------------------------------------------- */
+
+#if defined( CONFIG_MBX )
+#include <../board/mbx8xx/csr.h>
+
+/* A lot of this has been taken from the RPX code in this file it works from me.
+ I have added the voltage selection for the MBX board. */
+
+/* MBX voltage bit in control register #2 */
+#define CR2_VPP12 ((uchar)0x10)
+#define CR2_VPPVDD ((uchar)0x20)
+#define CR2_VDD5 ((uchar)0x40)
+#define CR2_VDD3 ((uchar)0x80)
+
+#define PCMCIA_BOARD_MSG "MBX860"
+
+static int voltage_set (int slot, int vcc, int vpp)
+{
+ uchar reg = 0;
+
+ debug ("voltage_set: PCMCIA_BOARD_MSG Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A' + slot, vcc / 10, vcc % 10, vpp / 10, vcc % 10);
+
+ switch (vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= CR2_VDD3;
+ break;
+ case 50:
+ reg |= CR2_VDD5;
+ break;
+ default:
+ return 1;
+ }
+
+ switch (vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if (vcc == vpp) {
+ reg |= CR2_VPPVDD;
+ } else {
+ return 1;
+ }
+ break;
+ case 120:
+ reg |= CR2_VPP12;
+ break;
+ default:
+ return 1;
+ }
+
+ /* first, turn off all power */
+ MBX_CSR2 &= ~(CR2_VDDSEL | CR2_VPPSEL);
+
+ /* enable new powersettings */
+ MBX_CSR2 |= reg;
+ debug ("MBX_CSR2 read = 0x%02x\n", MBX_CSR2);
+
+ return (0);
+}
+
+static int hardware_enable (int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, mask;
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n",
+ 'A' + slot);
+
+ udelay (10000);
+
+ immap = (immap_t *) CFG_IMMR;
+ sysp = (sysconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *) (&(((immap_t *) CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *) (&(((immap_t *) CFG_IMMR)->im_cpm));
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK (_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK (_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX (_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX (_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX (_slot_) = reg;
+ udelay (500);
+
+ /* remove all power */
+ voltage_set (slot, 0, 0);
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay (10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n", __LINE__, __FUNCTION__,
+ &(pcmp->pcmc_pipr), pcmp->pcmc_pipr);
+
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On.
+ */
+ mask = PCMCIA_VS1 (_slot_) | PCMCIA_VS2 (_slot_);
+ reg = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n", reg,
+ (reg & PCMCIA_VS1 (slot)) ? "n" : "ff",
+ (reg & PCMCIA_VS2 (slot)) ? "n" : "ff");
+
+ if ((reg & mask) == mask) {
+ voltage_set (_slot_, 50, 0);
+ printf (" 5.0V card found: ");
+ } else {
+ voltage_set (_slot_, 33, 0);
+ printf (" 3.3V card found: ");
+ }
+
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX (_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX (_slot_) = reg;
+
+ udelay (250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable (int slot)
+{
+ return 0; /* No hardware to disable */
+}
+#endif /* CFG_CMD_PCMCIA */
+#endif /* CONFIG_MBX */
+/* ---------------------------------------------------------------------------- */
+/* R360MPI Board */
+/* ---------------------------------------------------------------------------- */
+
+#if defined(CONFIG_R360MPI)
+
+#define PCMCIA_BOARD_MSG "R360MPI"
+
+
+static int hardware_enable(int slot)
+{
+ volatile immap_t *immap;
+ volatile cpm8xx_t *cp;
+ volatile pcmconf8xx_t *pcmp;
+ volatile sysconf8xx_t *sysp;
+ uint reg, mask;
+
+ debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ udelay(10000);
+
+ immap = (immap_t *)CFG_IMMR;
+ sysp = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ cp = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+ /*
+ * Configure SIUMCR to enable PCMCIA port B
+ * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+ */
+ sysp->sc_siumcr &= ~SIUMCR_DBGC11; /* set DBGC to 00 */
+
+ /* clear interrupt state, and disable interrupts */
+ pcmp->pcmc_pscr = PCMCIA_MASK(_slot_);
+ pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+ /* disable interrupts & DMA */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Ports A, B & C pins for
+ * 5 Volts Enable and 3 Volts enable
+ */
+ immap->im_ioport.iop_pcpar &= ~(0x0400);
+ immap->im_ioport.iop_pcso &= ~(0x0400);/*
+ immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+ immap->im_ioport.iop_papar &= ~(0x0200);/*
+ immap->im_ioport.iop_padir |= 0x0200;*/
+#if 0
+ immap->im_ioport.iop_pbpar &= ~(0xC000);
+ immap->im_ioport.iop_pbdir &= ~(0xC000);
+#endif
+ /* remove all power */
+
+ immap->im_ioport.iop_pcdat |= 0x0400;
+ immap->im_ioport.iop_padat |= 0x0200;
+
+ /*
+ * Make sure there is a card in the slot, then configure the interface.
+ */
+ udelay(10000);
+ debug ("[%d] %s: PIPR(%p)=0x%x\n",
+ __LINE__,__FUNCTION__,
+ &(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+ if (pcmp->pcmc_pipr & 0x00001800) {
+ printf (" No Card found\n");
+ return (1);
+ }
+
+ /*
+ * Power On.
+ */
+ mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+ reg = pcmp->pcmc_pipr;
+ debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+ reg,
+ (reg&PCMCIA_VS1(slot))?"n":"ff",
+ (reg&PCMCIA_VS2(slot))?"n":"ff");
+ if ((reg & mask) == mask) {
+ immap->im_ioport.iop_pcdat &= ~(0x4000);
+ puts (" 5.0V card found: ");
+ } else {
+ immap->im_ioport.iop_padat &= ~(0x0002);
+ puts (" 3.3V card found: ");
+ }
+ immap->im_ioport.iop_pcdir |= 0x0400;
+ immap->im_ioport.iop_padir |= 0x0200;
+#if 0
+ /* VCC switch error flag, PCMCIA slot INPACK_ pin */
+ cp->cp_pbdir &= ~(0x0020 | 0x0010);
+ cp->cp_pbpar &= ~(0x0020 | 0x0010);
+ udelay(500000);
+#endif
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(250000); /* some cards need >150 ms to come up :-( */
+
+ debug ("# hardware_enable done\n");
+
+ return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+
+ /* remove all power */
+ immap->im_ioport.iop_pcdat |= 0x0400;
+ immap->im_ioport.iop_padat |= 0x0200;
+
+ /* Configure PCMCIA General Control Register */
+ PCMCIA_PGCRX(_slot_) = 0;
+
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+
+ udelay(10000);
+
+ return (0);
+}
+#endif /* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ volatile immap_t *immap;
+ volatile pcmconf8xx_t *pcmp;
+ u_long reg;
+
+ debug ("voltage_set: "
+ PCMCIA_BOARD_MSG
+ " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+ 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+ immap = (immap_t *)CFG_IMMR;
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+ /*
+ * Disable PCMCIA buffers (isolate the interface)
+ * and assert RESET signal
+ */
+ debug ("Disable PCMCIA buffers and assert RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ /*
+ * Configure Ports A & C pins for
+ * 5 Volts Enable and 3 Volts enable,
+ * Turn off all power
+ */
+ debug ("PCMCIA power OFF\n");
+ immap->im_ioport.iop_pcpar &= ~(0x0400);
+ immap->im_ioport.iop_pcso &= ~(0x0400);/*
+ immap->im_ioport.iop_pcdir |= 0x0400;*/
+
+ immap->im_ioport.iop_papar &= ~(0x0200);/*
+ immap->im_ioport.iop_padir |= 0x0200;*/
+
+ immap->im_ioport.iop_pcdat |= 0x0400;
+ immap->im_ioport.iop_padat |= 0x0200;
+
+ reg = 0;
+ switch(vcc) {
+ case 0: break;
+ case 33: reg |= 0x0200; break;
+ case 50: reg |= 0x0400; break;
+ default: goto done;
+ }
+
+ /* Checking supported voltages */
+
+ debug ("PIPR: 0x%x --> %s\n",
+ pcmp->pcmc_pipr,
+ (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V");
+
+ if (reg & 0x0200)
+ immap->im_ioport.iop_pcdat &= !reg;
+ if (reg & 0x0400)
+ immap->im_ioport.iop_padat &= !reg;
+ immap->im_ioport.iop_pcdir |= 0x0200;
+ immap->im_ioport.iop_padir |= 0x0400;
+ if (reg) {
+ debug ("PCMCIA powered at %sV\n",
+ (reg&0x0400) ? "5.0" : "3.3");
+ } else {
+ debug ("PCMCIA powered down\n");
+ }
+
+done:
+ debug ("Enable PCMCIA buffers and stop RESET\n");
+ reg = PCMCIA_PGCRX(_slot_);
+ reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */
+ reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */
+ PCMCIA_PGCRX(_slot_) = reg;
+ udelay(500);
+
+ debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+ slot+'A');
+ return (0);
+}
+
+#endif /* R360MPI */
+
+
+/* ---------------------------------------------------------------------------- */
+/* End of Board Specific Stuff */
+/* ---------------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------------- */
+/* MPC8xx Specific Stuff - should go to MPC8xx directory */
+/* ---------------------------------------------------------------------------- */
+
+/*
+ * Search this table to see if the windowsize is
+ * supported...
+ */
+
+#define M8XX_SIZES_NO 32
+
+static const u_int m8xx_size_to_gray[M8XX_SIZES_NO] =
+{ 0x00000001, 0x00000002, 0x00000008, 0x00000004,
+ 0x00000080, 0x00000040, 0x00000010, 0x00000020,
+ 0x00008000, 0x00004000, 0x00001000, 0x00002000,
+ 0x00000100, 0x00000200, 0x00000800, 0x00000400,
+
+ 0x0fffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x01000000, 0x02000000, 0xffffffff, 0x04000000,
+ 0x00010000, 0x00020000, 0x00080000, 0x00040000,
+ 0x00800000, 0x00400000, 0x00100000, 0x00200000 };
+
+
+/* ---------------------------------------------------------------------------- */
+
+static u_int m8xx_get_graycode(u_int size)
+{
+ u_int k;
+
+ for (k = 0; k < M8XX_SIZES_NO; k++) {
+ if(m8xx_size_to_gray[k] == size)
+ break;
+ }
+
+ if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+ k = -1;
+
+ return k;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+static u_int m8xx_get_speed(u_int ns, u_int is_io)
+{
+ u_int reg, clocks, psst, psl, psht;
+
+ if(!ns) {
+
+ /*
+ * We get called with IO maps setup to 0ns
+ * if not specified by the user.
+ * They should be 255ns.
+ */
+
+ if(is_io)
+ ns = 255;
+ else
+ ns = 100; /* fast memory if 0 */
+ }
+
+ /*
+ * In PSST, PSL, PSHT fields we tell the controller
+ * timing parameters in CLKOUT clock cycles.
+ * CLKOUT is the same as GCLK2_50.
+ */
+
+/* how we want to adjust the timing - in percent */
+
+#define ADJ 180 /* 80 % longer accesstime - to be sure */
+
+ clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
+ clocks = (clocks * ADJ) / (100*1000);
+
+ if(clocks >= PCMCIA_BMT_LIMIT) {
+ DEBUG(0, "Max access time limit reached\n");
+ clocks = PCMCIA_BMT_LIMIT-1;
+ }
+
+ psst = clocks / 7; /* setup time */
+ psht = clocks / 7; /* hold time */
+ psl = (clocks * 5) / 7; /* strobe length */
+
+ psst += clocks - (psst + psht + psl);
+
+ reg = psst << 12;
+ reg |= psl << 7;
+ reg |= psht << 16;
+
+ return reg;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_funcid (int func)
+{
+ puts (indent);
+ switch (func) {
+ case CISTPL_FUNCID_MULTI:
+ puts (" Multi-Function");
+ break;
+ case CISTPL_FUNCID_MEMORY:
+ puts (" Memory");
+ break;
+ case CISTPL_FUNCID_SERIAL:
+ puts (" Serial Port");
+ break;
+ case CISTPL_FUNCID_PARALLEL:
+ puts (" Parallel Port");
+ break;
+ case CISTPL_FUNCID_FIXED:
+ puts (" Fixed Disk");
+ break;
+ case CISTPL_FUNCID_VIDEO:
+ puts (" Video Adapter");
+ break;
+ case CISTPL_FUNCID_NETWORK:
+ puts (" Network Adapter");
+ break;
+ case CISTPL_FUNCID_AIMS:
+ puts (" AIMS Card");
+ break;
+ case CISTPL_FUNCID_SCSI:
+ puts (" SCSI Adapter");
+ break;
+ default:
+ puts (" Unknown");
+ break;
+ }
+ puts (" Card\n");
+}
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+static void print_fixed (volatile uchar *p)
+{
+ if (p == NULL)
+ return;
+
+ puts(indent);
+
+ switch (*p) {
+ case CISTPL_FUNCE_IDE_IFACE:
+ { uchar iface = *(p+2);
+
+ puts ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+ puts (" interface ");
+ break;
+ }
+ case CISTPL_FUNCE_IDE_MASTER:
+ case CISTPL_FUNCE_IDE_SLAVE:
+ { uchar f1 = *(p+2);
+ uchar f2 = *(p+4);
+
+ puts ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+ if (f1 & CISTPL_IDE_UNIQUE)
+ puts (" [unique]");
+
+ puts ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+ if (f2 & CISTPL_IDE_HAS_SLEEP)
+ puts (" [sleep]");
+
+ if (f2 & CISTPL_IDE_HAS_STANDBY)
+ puts (" [standby]");
+
+ if (f2 & CISTPL_IDE_HAS_IDLE)
+ puts (" [idle]");
+
+ if (f2 & CISTPL_IDE_LOW_POWER)
+ puts (" [low power]");
+
+ if (f2 & CISTPL_IDE_REG_INHIBIT)
+ puts (" [reg inhibit]");
+
+ if (f2 & CISTPL_IDE_HAS_INDEX)
+ puts (" [index]");
+
+ if (f2 & CISTPL_IDE_IOIS16)
+ puts (" [IOis16]");
+
+ break;
+ }
+ }
+ putc ('\n');
+}
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#define MAX_IDENT_CHARS 64
+#define MAX_IDENT_FIELDS 4
+
+static uchar *known_cards[] = {
+ "ARGOSY PnPIDE D5",
+ NULL
+};
+
+static int identify (volatile uchar *p)
+{
+ uchar id_str[MAX_IDENT_CHARS];
+ uchar data;
+ uchar *t;
+ uchar **card;
+ int i, done;
+
+ if (p == NULL)
+ return (0); /* Don't know */
+
+ t = id_str;
+ done =0;
+
+ for (i=0; i<=4 && !done; ++i, p+=2) {
+ while ((data = *p) != '\0') {
+ if (data == 0xFF) {
+ done = 1;
+ break;
+ }
+ *t++ = data;
+ if (t == &id_str[MAX_IDENT_CHARS-1]) {
+ done = 1;
+ break;
+ }
+ p += 2;
+ }
+ if (!done)
+ *t++ = ' ';
+ }
+ *t = '\0';
+ while (--t > id_str) {
+ if (*t == ' ')
+ *t = '\0';
+ else
+ break;
+ }
+ puts (id_str);
+ putc ('\n');
+
+ for (card=known_cards; *card; ++card) {
+ debug ("## Compare against \"%s\"\n", *card);
+ if (strcmp(*card, id_str) == 0) { /* found! */
+ debug ("## CARD FOUND ##\n");
+ return (1);
+ }
+ }
+
+ return (0); /* don't know */
+}
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CFG_CMD_PCMCIA || (CFG_CMD_IDE && CONFIG_IDE_8xx_PCCARD) */
diff --git a/common/env_flash.c b/common/env_flash.c
new file mode 100644
index 0000000..1593d2c
--- /dev/null
+++ b/common/env_flash.c
@@ -0,0 +1,377 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.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
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+
+#if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_FLASH)) == (CFG_CMD_ENV|CFG_CMD_FLASH))
+#define CMD_SAVEENV
+#elif defined(CFG_ENV_ADDR_REDUND)
+#error Cannot use CFG_ENV_ADDR_REDUND without CFG_CMD_ENV & CFG_CMD_FLASH
+#endif
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE) && \
+ defined(CFG_ENV_ADDR_REDUND)
+#error CFG_ENV_ADDR_REDUND should not be used when CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
+#endif
+
+#if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND < CFG_ENV_SIZE)
+#error CFG_ENV_SIZE_REDUND should not be less then CFG_ENV_SIZE
+#endif
+
+#ifdef CONFIG_INFERNO
+# ifdef CFG_ENV_ADDR_REDUND
+#error CFG_ENV_ADDR_REDUND is not implemented for CONFIG_INFERNO
+# endif
+#endif
+
+char * env_name_spec = "Flash";
+
+#ifdef ENV_IS_EMBEDDED
+
+extern uchar environment[];
+env_t *env_ptr = (env_t *)(&environment[0]);
+
+#ifdef CMD_SAVEENV
+/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#else /* ! ENV_IS_EMBEDDED */
+
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#ifdef CMD_SAVEENV
+static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+#endif /* ENV_IS_EMBEDDED */
+
+#ifdef CFG_ENV_ADDR_REDUND
+static env_t *flash_addr_new = (env_t *)CFG_ENV_ADDR_REDUND;
+
+static ulong end_addr = CFG_ENV_ADDR + CFG_ENV_SIZE - 1;
+static ulong end_addr_new = CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1;
+
+static uchar active_flag = 1;
+static uchar obsolete_flag = 0;
+#endif
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+
+uchar env_get_char_spec (int index)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ return ( *((uchar *)(gd->env_addr + index)) );
+}
+
+#ifdef CFG_ENV_ADDR_REDUND
+
+int env_init(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int crc1_ok =
+ (crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
+ int crc2_ok =
+ (crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
+
+ uchar flag1 = flash_addr->flags;
+ uchar flag2 = flash_addr_new->flags;
+
+ ulong addr_default = (ulong)&default_environment[0];
+ ulong addr1 = (ulong)&(flash_addr->data);
+ ulong addr2 = (ulong)&(flash_addr_new->data);
+
+ if (crc1_ok && ! crc2_ok)
+ {
+ gd->env_addr = addr1;
+ gd->env_valid = 1;
+ }
+ else if (! crc1_ok && crc2_ok)
+ {
+ gd->env_addr = addr2;
+ gd->env_valid = 1;
+ }
+ else if (! crc1_ok && ! crc2_ok)
+ {
+ gd->env_addr = addr_default;
+ gd->env_valid = 0;
+ }
+ else if (flag1 == active_flag && flag2 == obsolete_flag)
+ {
+ gd->env_addr = addr1;
+ gd->env_valid = 1;
+ }
+ else if (flag1 == obsolete_flag && flag2 == active_flag)
+ {
+ gd->env_addr = addr2;
+ gd->env_valid = 1;
+ }
+ else if (flag1 == flag2)
+ {
+ gd->env_addr = addr1;
+ gd->env_valid = 2;
+ }
+ else if (flag1 == 0xFF)
+ {
+ gd->env_addr = addr1;
+ gd->env_valid = 2;
+ }
+ else if (flag2 == 0xFF)
+ {
+ gd->env_addr = addr2;
+ gd->env_valid = 2;
+ }
+
+ return (0);
+}
+
+#ifdef CMD_SAVEENV
+int saveenv(void)
+{
+ int rc = 1;
+
+ debug ("Protect off %08lX ... %08lX\n",
+ (ulong)flash_addr, end_addr);
+
+ if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
+ goto Done;
+ }
+
+ debug ("Protect off %08lX ... %08lX\n",
+ (ulong)flash_addr_new, end_addr_new);
+
+ if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
+ goto Done;
+ }
+
+ puts ("Erasing Flash...");
+ debug (" %08lX ... %08lX ...",
+ (ulong)flash_addr_new, end_addr_new);
+
+ if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
+ goto Done;
+ }
+
+ puts ("Writing to Flash... ");
+ debug (" %08lX ... %08lX ...",
+ (ulong)&(flash_addr_new->data),
+ sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
+ if (flash_write(env_ptr->data,
+ (ulong)&(flash_addr_new->data),
+ sizeof(env_ptr->data)) ||
+
+ flash_write((char *)&(env_ptr->crc),
+ (ulong)&(flash_addr_new->crc),
+ sizeof(env_ptr->crc)) ||
+
+ flash_write((char *)&obsolete_flag,
+ (ulong)&(flash_addr->flags),
+ sizeof(flash_addr->flags)) ||
+
+ flash_write((char *)&active_flag,
+ (ulong)&(flash_addr_new->flags),
+ sizeof(flash_addr_new->flags)))
+ {
+ flash_perror (rc);
+ goto Done;
+ }
+ puts ("done\n");
+
+ {
+ env_t * etmp = flash_addr;
+ ulong ltmp = end_addr;
+
+ flash_addr = flash_addr_new;
+ flash_addr_new = etmp;
+
+ end_addr = end_addr_new;
+ end_addr_new = ltmp;
+ }
+
+ rc = 0;
+Done:
+
+ /* try to re-protect */
+ (void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
+ (void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+
+ return rc;
+}
+#endif /* CMD_SAVEENV */
+
+#else /* ! CFG_ENV_ADDR_REDUND */
+
+int env_init(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+ gd->env_addr = (ulong)&(env_ptr->data);
+ gd->env_valid = 1;
+ } else {
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+ }
+
+ return (0);
+}
+
+#ifdef CMD_SAVEENV
+
+int saveenv(void)
+{
+ int len, rc;
+ ulong end_addr;
+ ulong flash_sect_addr;
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+ ulong flash_offset;
+ uchar env_buffer[CFG_ENV_SECT_SIZE];
+#else
+ uchar *env_buffer = (char *)env_ptr;
+#endif /* CFG_ENV_SECT_SIZE */
+ int rcode = 0;
+
+#if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
+
+ flash_offset = ((ulong)flash_addr) & (CFG_ENV_SECT_SIZE-1);
+ flash_sect_addr = ((ulong)flash_addr) & ~(CFG_ENV_SECT_SIZE-1);
+
+ debug ( "copy old content: "
+ "sect_addr: %08lX env_addr: %08lX offset: %08lX\n",
+ flash_sect_addr, (ulong)flash_addr, flash_offset);
+
+ /* copy old contents to temporary buffer */
+ memcpy (env_buffer, (void *)flash_sect_addr, CFG_ENV_SECT_SIZE);
+
+ /* copy current environment to temporary buffer */
+ memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
+ env_ptr,
+ CFG_ENV_SIZE);
+
+ len = CFG_ENV_SECT_SIZE;
+#else
+ flash_sect_addr = (ulong)flash_addr;
+ len = CFG_ENV_SIZE;
+#endif /* CFG_ENV_SECT_SIZE */
+
+#ifndef CONFIG_INFERNO
+ end_addr = flash_sect_addr + len - 1;
+#else
+ /* this is the last sector, and the size is hardcoded here */
+ /* otherwise we will get stack problems on loading 128 KB environment */
+ end_addr = flash_sect_addr + 0x20000 - 1;
+#endif
+
+ debug ("Protect off %08lX ... %08lX\n",
+ (ulong)flash_sect_addr, end_addr);
+
+ if (flash_sect_protect (0, flash_sect_addr, end_addr))
+ return 1;
+
+ puts ("Erasing Flash...");
+ if (flash_sect_erase (flash_sect_addr, end_addr))
+ return 1;
+
+ puts ("Writing to Flash... ");
+ rc = flash_write(env_buffer, flash_sect_addr, len);
+ if (rc != 0) {
+ flash_perror (rc);
+ rcode = 1;
+ } else {
+ puts ("done\n");
+ }
+
+ /* try to re-protect */
+ (void) flash_sect_protect (1, flash_sect_addr, end_addr);
+ return rcode;
+}
+
+#endif /* CMD_SAVEENV */
+
+#endif /* CFG_ENV_ADDR_REDUND */
+
+void env_relocate_spec (void)
+{
+#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
+#ifdef CFG_ENV_ADDR_REDUND
+ DECLARE_GLOBAL_DATA_PTR;
+
+ if (gd->env_addr != (ulong)&(flash_addr->data))
+ {
+ env_t * etmp = flash_addr;
+ ulong ltmp = end_addr;
+
+ flash_addr = flash_addr_new;
+ flash_addr_new = etmp;
+
+ end_addr = end_addr_new;
+ end_addr_new = ltmp;
+ }
+
+ if (flash_addr_new->flags != obsolete_flag &&
+ crc32(0, flash_addr_new->data, ENV_SIZE) ==
+ flash_addr_new->crc)
+ {
+ gd->env_valid = 2;
+ flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
+ flash_write((char *)&obsolete_flag,
+ (ulong)&(flash_addr_new->flags),
+ sizeof(flash_addr_new->flags));
+ flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+ }
+
+ if (flash_addr->flags != active_flag &&
+ (flash_addr->flags & active_flag) == active_flag)
+ {
+ gd->env_valid = 2;
+ flash_sect_protect (0, (ulong)flash_addr, end_addr);
+ flash_write((char *)&active_flag,
+ (ulong)&(flash_addr->flags),
+ sizeof(flash_addr->flags));
+ flash_sect_protect (1, (ulong)flash_addr, end_addr);
+ }
+
+ if (gd->env_valid == 2)
+ puts ("*** Warning - some problems detected "
+ "reading environment; recovered successfully\n\n");
+#endif /* CFG_ENV_ADDR_REDUND */
+ memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
+#endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
+}
+
+#endif /* CFG_ENV_IS_IN_FLASH) */
diff --git a/common/env_nvram.c b/common/env_nvram.c
new file mode 100644
index 0000000..fdfa4fc
--- /dev/null
+++ b/common/env_nvram.c
@@ -0,0 +1,138 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.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
+ */
+
+/*
+ * 09-18-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
+ *
+ * It might not be possible in all cases to use 'memcpy()' to copy
+ * the environment to NVRAM, as the NVRAM might not be mapped into
+ * the memory space. (I.e. this is the case for the BAB750). In those
+ * cases it might be possible to access the NVRAM using a different
+ * method. For example, the RTC on the BAB750 is accessible in IO
+ * space using its address and data registers. To enable usage of
+ * NVRAM in those cases I invented the functions 'nvram_read()' and
+ * 'nvram_write()', which will be activated upon the configuration
+ * #define CFG_NVRAM_ACCESS_ROUTINE. Note, that those functions are
+ * strongly dependent on the used HW, and must be redefined for each
+ * board that wants to use them.
+ */
+
+#include <common.h>
+
+#ifdef CFG_ENV_IS_IN_NVRAM /* Environment is in NVRAM */
+
+#include <command.h>
+#include <environment.h>
+#include <cmd_nvedit.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+extern void *nvram_read(void *dest, const long src, size_t count);
+extern void nvram_write(long dest, const void *src, size_t count);
+env_t *env_ptr = NULL;
+#else
+env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
+#endif
+
+char * env_name_spec = "NVRAM";
+
+extern uchar default_environment[];
+extern int default_environment_size;
+
+extern uchar (*env_get_char)(int);
+extern uchar env_get_char_memory (int index);
+
+
+uchar env_get_char_spec (int index)
+{
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+ uchar c;
+
+ nvram_read(&c, CFG_ENV_ADDR+index, 1);
+
+ return c;
+#else
+ DECLARE_GLOBAL_DATA_PTR;
+
+ return *((uchar *)(gd->env_addr + index));
+#endif
+}
+
+void env_relocate_spec (void)
+{
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+ nvram_read(env_ptr, CFG_ENV_ADDR, CFG_ENV_SIZE);
+#else
+ memcpy (env_ptr, (void*)CFG_ENV_ADDR, CFG_ENV_SIZE);
+#endif
+}
+
+int saveenv (void)
+{
+ int rcode = 0;
+
+#ifdef CFG_NVRAM_ACCESS_ROUTINE
+ nvram_write(CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE);
+#else
+ if (memcpy ((char *)CFG_ENV_ADDR, env_ptr, CFG_ENV_SIZE) == NULL)
+ rcode = 1 ;
+#endif
+ return rcode;
+}
+
+
+/************************************************************************
+ * Initialize Environment use
+ *
+ * We are still running from ROM, so data use is limited
+ */
+int env_init (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CFG_NVRAM_ACCESS_ROUTINE)
+ ulong crc;
+ uchar data[ENV_SIZE];
+ nvram_read (&crc, CFG_ENV_ADDR, sizeof(ulong));
+ nvram_read (data, CFG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
+
+ if (crc32(0, data, ENV_SIZE) == crc) {
+ gd->env_addr = (ulong)CFG_ENV_ADDR + sizeof(long);
+#else
+ if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
+ gd->env_addr = (ulong)&(env_ptr->data);
+#endif
+ gd->env_valid = 1;
+ } else {
+ gd->env_addr = (ulong)&default_environment[0];
+ gd->env_valid = 0;
+ }
+
+ return (0);
+}
+
+#endif /* CFG_ENV_IS_IN_NVRAM */
diff --git a/common/environment.c b/common/environment.c
new file mode 100644
index 0000000..74bfd62
--- /dev/null
+++ b/common/environment.c
@@ -0,0 +1,198 @@
+/*
+ * (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 <config.h>
+#include <environment.h>
+
+/*
+ * Handle HOSTS that have prepended
+ * crap on symbol names, not TARGETS.
+ */
+#if defined(__APPLE__)
+/* Leading underscore on symbols */
+# define SYM_CHAR "_"
+#else /* No leading character on symbols */
+# define SYM_CHAR
+#endif
+
+/*
+ * Generate embedded environment table
+ * inside U-Boot image, if needed.
+ */
+#if defined(ENV_IS_EMBEDDED)
+/*
+ * Only put the environment in it's own section when we are building
+ * U-Boot proper. The host based program "tools/envcrc" does not need
+ * a seperate section. Note that ENV_CRC is only defined when building
+ * U-Boot itself.
+ */
+#if (defined(CONFIG_FADS) || \
+ defined(CONFIG_HYMOD) || \
+ defined(CONFIG_ICU862) || \
+ defined(CONFIG_R360MPI) || \
+ defined(CONFIG_TQM8xxL) || \
+ defined(CONFIG_RRVISION) || \
+ defined(CONFIG_TRAB) ) && \
+ defined(ENV_CRC) /* Environment embedded in U-Boot .ppcenv section */
+/* XXX - This only works with GNU C */
+# define __PPCENV__ __attribute__ ((section(".ppcenv")))
+# define __PPCTEXT__ __attribute__ ((section(".text")))
+
+#elif defined(USE_HOSTCC) /* Native for 'tools/envcrc' */
+# define __PPCENV__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+# define __PPCTEXT__ /*XXX DO_NOT_DEL_THIS_COMMENT*/
+
+#else /* Environment is embedded in U-Boot's .text section */
+/* XXX - This only works with GNU C */
+# define __PPCENV__ __attribute__ ((section(".text")))
+# define __PPCTEXT__ __attribute__ ((section(".text")))
+#endif
+
+/*
+ * Macros to generate global absolutes.
+ */
+#define GEN_SYMNAME(str) SYM_CHAR #str
+#define GEN_VALUE(str) #str
+#define GEN_ABS(name, value) \
+ asm (".globl " GEN_SYMNAME(name)); \
+ asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+
+/*
+ * Check to see if we are building with a
+ * computed CRC. Otherwise define it as ~0.
+ */
+#if !defined(ENV_CRC)
+# define ENV_CRC ~0
+#endif
+
+env_t environment __PPCENV__ = {
+ ENV_CRC, /* CRC Sum */
+#ifdef CFG_REDUNDAND_ENVIRONMENT
+ 1, /* Flags: valid */
+#endif
+ {
+#if defined(CONFIG_BOOTARGS)
+ "bootargs=" CONFIG_BOOTARGS "\0"
+#endif
+#if defined(CONFIG_BOOTCOMMAND)
+ "bootcmd=" CONFIG_BOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_RAMBOOTCOMMAND)
+ "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_NFSBOOTCOMMAND)
+ "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+ "baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
+#endif
+#ifdef CONFIG_LOADS_ECHO
+ "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
+#endif
+#ifdef CONFIG_ETHADDR
+ "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
+#endif
+#ifdef CONFIG_ETH1ADDR
+ "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH2ADDR
+ "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
+#endif
+#ifdef CONFIG_ETHPRIME
+ "ethprime=" CONFIG_ETHPRIME "\0"
+#endif
+#ifdef CONFIG_IPADDR
+ "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
+#endif
+#ifdef CONFIG_SERVERIP
+ "serverip=" MK_STR(CONFIG_SERVERIP) "\0"
+#endif
+#ifdef CFG_AUTOLOAD
+ "autoload=" CFG_AUTOLOAD "\0"
+#endif
+#ifdef CONFIG_ROOTPATH
+ "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
+#endif
+#ifdef CONFIG_GATEWAYIP
+ "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
+#endif
+#ifdef CONFIG_NETMASK
+ "netmask=" MK_STR(CONFIG_NETMASK) "\0"
+#endif
+#ifdef CONFIG_HOSTNAME
+ "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
+#endif
+#ifdef CONFIG_BOOTFILE
+ "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
+#endif
+#ifdef CONFIG_LOADADDR
+ "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
+#endif
+#ifdef CONFIG_PREBOOT
+ "preboot=" CONFIG_PREBOOT "\0"
+#endif
+#ifdef CONFIG_CLOCKS_IN_MHZ
+ "clocks_in_mhz=" "1" "\0"
+#endif
+#ifdef CONFIG_EXTRA_ENV_SETTINGS
+ CONFIG_EXTRA_ENV_SETTINGS
+#endif
+ "\0" /* Term. env_t.data with 2 NULLs */
+ }
+};
+#ifdef CFG_ENV_ADDR_REDUND
+env_t redundand_environment __PPCENV__ = {
+ 0, /* CRC Sum: invalid */
+ 0, /* Flags: invalid */
+ {
+ "\0"
+ }
+};
+#endif /* CFG_ENV_ADDR_REDUND */
+
+/*
+ * These will end up in the .text section
+ * if the environment strings are embedded
+ * in the image. When this is used for
+ * tools/envcrc, they are placed in the
+ * .data/.sdata section.
+ *
+ */
+unsigned long env_size __PPCTEXT__ = sizeof(env_t);
+
+/*
+ * Add in absolutes.
+ */
+GEN_ABS(env_offset, CFG_ENV_OFFSET);
+
+#endif /* ENV_IS_EMBEDDED */
diff --git a/common/main.c b/common/main.c
new file mode 100644
index 0000000..014804b
--- /dev/null
+++ b/common/main.c
@@ -0,0 +1,817 @@
+/*
+ * (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
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <cmd_nvedit.h>
+#include <cmd_bootm.h>
+#include <malloc.h>
+#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
+#include <cmd_boot.h> /* for do_reset() prototype */
+#endif
+
+#ifdef CFG_HUSH_PARSER
+#include <hush.h>
+#endif
+
+#define MAX_DELAY_STOP_STR 32
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
+static int parse_line (char *, char *[]);
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+static int abortboot(int);
+#endif
+
+#undef DEBUG_PARSER
+
+char console_buffer[CFG_CBSIZE]; /* console I/O buffer */
+
+static char erase_seq[] = "\b \b"; /* erase sequence */
+static char tab_seq[] = " "; /* used to expand TABs */
+
+#ifdef CONFIG_BOOT_RETRY_TIME
+static uint64_t endtime = 0; /* must be set, default is instant timeout */
+static int retry_time = -1; /* -1 so can call readline before main_loop */
+#endif
+
+#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
+
+#ifndef CONFIG_BOOT_RETRY_MIN
+#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
+#endif
+
+#ifdef CONFIG_MODEM_SUPPORT
+int do_mdm_init = 0;
+extern void mdm_init(void); /* defined in board.c */
+#endif
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
+ * returns: 0 - no key string, allow autoboot
+ * 1 - got key string, abort
+ */
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+# if defined(CONFIG_AUTOBOOT_KEYED)
+static __inline__ int abortboot(int bootdelay)
+{
+ int abort = 0;
+ uint64_t etime = endtick(bootdelay);
+ struct
+ {
+ char* str;
+ u_int len;
+ int retry;
+ }
+ delaykey [] =
+ {
+ { str: getenv ("bootdelaykey"), retry: 1 },
+ { str: getenv ("bootdelaykey2"), retry: 1 },
+ { str: getenv ("bootstopkey"), retry: 0 },
+ { str: getenv ("bootstopkey2"), retry: 0 },
+ };
+
+ char presskey [MAX_DELAY_STOP_STR];
+ u_int presskey_len = 0;
+ u_int presskey_max = 0;
+ u_int i;
+
+# ifdef CONFIG_AUTOBOOT_PROMPT
+ printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_DELAY_STR
+ if (delaykey[0].str == NULL)
+ delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
+# endif
+# ifdef CONFIG_AUTOBOOT_DELAY_STR2
+ if (delaykey[1].str == NULL)
+ delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
+# endif
+# ifdef CONFIG_AUTOBOOT_STOP_STR
+ if (delaykey[2].str == NULL)
+ delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
+# endif
+# ifdef CONFIG_AUTOBOOT_STOP_STR2
+ if (delaykey[3].str == NULL)
+ delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
+# endif
+
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+ delaykey[i].len = delaykey[i].str == NULL ?
+ 0 : strlen (delaykey[i].str);
+ delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
+ MAX_DELAY_STOP_STR : delaykey[i].len;
+
+ presskey_max = presskey_max > delaykey[i].len ?
+ presskey_max : delaykey[i].len;
+
+# if DEBUG_BOOTKEYS
+ printf("%s key:<%s>\n",
+ delaykey[i].retry ? "delay" : "stop",
+ delaykey[i].str ? delaykey[i].str : "NULL");
+# endif
+ }
+
+ /* In order to keep up with incoming data, check timeout only
+ * when catch up.
+ */
+ while (!abort && get_ticks() <= etime) {
+ for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
+ if (delaykey[i].len > 0 &&
+ presskey_len >= delaykey[i].len &&
+ memcmp (presskey + presskey_len - delaykey[i].len,
+ delaykey[i].str,
+ delaykey[i].len) == 0) {
+# if DEBUG_BOOTKEYS
+ printf("got %skey\n",
+ delaykey[i].retry ? "delay" : "stop");
+# endif
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+ /* don't retry auto boot */
+ if (! delaykey[i].retry)
+ retry_time = -1;
+# endif
+ abort = 1;
+ }
+ }
+
+ if (tstc()) {
+ if (presskey_len < presskey_max) {
+ presskey [presskey_len ++] = getc();
+ }
+ else {
+ for (i = 0; i < presskey_max - 1; i ++)
+ presskey [i] = presskey [i + 1];
+
+ presskey [i] = getc();
+ }
+ }
+ }
+# if DEBUG_BOOTKEYS
+ if (!abort)
+ printf("key timeout\n");
+# endif
+
+ return abort;
+}
+
+# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
+
+static __inline__ int abortboot(int bootdelay)
+{
+ int abort = 0;
+
+ printf("Hit any key to stop autoboot: %2d ", bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+ /*
+ * Check if key already pressed
+ * Don't check if bootdelay < 0
+ */
+ if (bootdelay >= 0) {
+ if (tstc()) { /* we got a key press */
+ (void) getc(); /* consume input */
+ printf ("\b\b\b 0\n");
+ return 1; /* don't auto boot */
+ }
+ }
+#endif
+
+ while (bootdelay > 0) {
+ int i;
+
+ --bootdelay;
+ /* delay 100 * 10ms */
+ for (i=0; !abort && i<100; ++i) {
+ if (tstc()) { /* we got a key press */
+ abort = 1; /* don't auto boot */
+ bootdelay = 0; /* no more delay */
+ (void) getc(); /* consume input */
+ break;
+ }
+ udelay (10000);
+ }
+
+ printf ("\b\b\b%2d ", bootdelay);
+ }
+
+ putc ('\n');
+
+ return abort;
+}
+# endif /* CONFIG_AUTOBOOT_KEYED */
+#endif /* CONFIG_BOOTDELAY >= 0 */
+
+/****************************************************************************/
+
+void main_loop (void)
+{
+#ifndef CFG_HUSH_PARSER
+ static char lastcommand[CFG_CBSIZE] = { 0, };
+ int len;
+ int rc = 1;
+ int flag;
+#endif
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ char *s;
+ int bootdelay;
+#endif
+#ifdef CONFIG_PREBOOT
+ char *p;
+#endif
+
+#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
+ ulong bmp = 0; /* default bitmap */
+ extern int trab_vfd (ulong bitmap);
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (do_mdm_init)
+ bmp = 1; /* alternate bitmap */
+#endif
+ trab_vfd (bmp);
+#endif /* CONFIG_VFD && VFD_TEST_LOGO */
+
+#ifdef CONFIG_MODEM_SUPPORT
+ debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
+ if (do_mdm_init) {
+ uchar *str = strdup(getenv("mdm_cmd"));
+ setenv ("preboot", str); /* set or delete definition */
+ if (str != NULL)
+ free (str);
+ mdm_init(); /* wait for modem connection */
+ }
+#endif /* CONFIG_MODEM_SUPPORT */
+
+#ifdef CFG_HUSH_PARSER
+ u_boot_hush_start ();
+#endif
+
+#ifdef CONFIG_PREBOOT
+ if ((p = getenv ("preboot")) != NULL) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+ int prev = disable_ctrlc(1); /* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+ run_command (p, 0);
+# else
+ parse_string_outer(p, FLAG_PARSE_SEMICOLON |
+ FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+ disable_ctrlc(prev); /* restore Control C checking */
+# endif
+ }
+#endif /* CONFIG_PREBOOT */
+
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ s = getenv ("bootdelay");
+ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+
+#if 0
+ printf ("### main_loop entered:\n\n");
+#endif
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+ s = getenv ("bootretry");
+ if (s != NULL)
+ retry_time = (int)simple_strtoul(s, NULL, 10);
+ else
+ retry_time = CONFIG_BOOT_RETRY_TIME;
+ if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
+ retry_time = CONFIG_BOOT_RETRY_MIN;
+# endif /* CONFIG_BOOT_RETRY_TIME */
+
+ s = getenv ("bootcmd");
+ if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+ int prev = disable_ctrlc(1); /* disable Control C checking */
+# endif
+
+# ifndef CFG_HUSH_PARSER
+ run_command (s, 0);
+# else
+ parse_string_outer(s, FLAG_PARSE_SEMICOLON |
+ FLAG_EXIT_FROM_LOOP);
+# endif
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+ disable_ctrlc(prev); /* restore Control C checking */
+# endif
+ }
+#endif /* CONFIG_BOOTDELAY */
+
+ /*
+ * Main Loop for Monitor Command Processing
+ */
+#ifdef CFG_HUSH_PARSER
+ parse_file_outer();
+ /* This point is never reached */
+ for (;;);
+#else
+ for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ if (rc >= 0) {
+ /* Saw enough of a valid command to
+ * restart the timeout.
+ */
+ reset_cmd_timeout();
+ }
+#endif
+ len = readline (CFG_PROMPT);
+
+ flag = 0; /* assume no special flags for now */
+ if (len > 0)
+ strcpy (lastcommand, console_buffer);
+ else if (len == 0)
+ flag |= CMD_FLAG_REPEAT;
+#ifdef CONFIG_BOOT_RETRY_TIME
+ else if (len == -2) {
+ /* -2 means timed out, retry autoboot
+ */
+ printf("\nTimed out waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ /* Reinit board to run initialization code again */
+ do_reset (NULL, 0, 0, NULL);
+# else
+ return; /* retry autoboot */
+# endif
+ }
+#endif
+
+ if (len == -1)
+ printf ("<INTERRUPT>\n");
+ else
+ rc = run_command (lastcommand, flag);
+
+ if (rc <= 0) {
+ /* invalid command or not repeatable, forget it */
+ lastcommand[0] = 0;
+ }
+ }
+#endif /*CFG_HUSH_PARSER*/
+}
+
+/***************************************************************************
+ * reset command line timeout to retry_time seconds
+ */
+#ifdef CONFIG_BOOT_RETRY_TIME
+void reset_cmd_timeout(void)
+{
+ endtime = endtick(retry_time);
+}
+#endif
+
+/****************************************************************************/
+
+/*
+ * Prompt for input and read a line.
+ * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
+ * time out when time goes past endtime (timebase time in ticks).
+ * Return: number of read characters
+ * -1 if break
+ * -2 if timed out
+ */
+int readline (const char *const prompt)
+{
+ char *p = console_buffer;
+ int n = 0; /* buffer index */
+ int plen = 0; /* prompt length */
+ int col; /* output column cnt */
+ char c;
+
+ /* print prompt */
+ if (prompt) {
+ plen = strlen (prompt);
+ puts (prompt);
+ }
+ col = plen;
+
+ for (;;) {
+#ifdef CONFIG_BOOT_RETRY_TIME
+ while (!tstc()) { /* while no incoming data */
+ if (retry_time >= 0 && get_ticks() > endtime)
+ return (-2); /* timed out */
+ }
+#endif
+ WATCHDOG_RESET(); /* Trigger watchdog, if needed */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+ while (!tstc()) {
+ extern void show_activity(int arg);
+ show_activity(0);
+ }
+#endif
+ c = getc();
+
+ /*
+ * Special character handling
+ */
+ switch (c) {
+ case '\r': /* Enter */
+ case '\n':
+ *p = '\0';
+ puts ("\r\n");
+ return (p - console_buffer);
+
+ case 0x03: /* ^C - break */
+ console_buffer[0] = '\0'; /* discard input */
+ return (-1);
+
+ case 0x15: /* ^U - erase line */
+ while (col > plen) {
+ puts (erase_seq);
+ --col;
+ }
+ p = console_buffer;
+ n = 0;
+ continue;
+
+ case 0x17: /* ^W - erase word */
+ p=delete_char(console_buffer, p, &col, &n, plen);
+ while ((n > 0) && (*p != ' ')) {
+ p=delete_char(console_buffer, p, &col, &n, plen);
+ }
+ continue;
+
+ case 0x08: /* ^H - backspace */
+ case 0x7F: /* DEL - backspace */
+ p=delete_char(console_buffer, p, &col, &n, plen);
+ continue;
+
+ default:
+ /*
+ * Must be a normal character then
+ */
+ if (n < CFG_CBSIZE-2) {
+ if (c == '\t') { /* expand TABs */
+ puts (tab_seq+(col&07));
+ col += 8 - (col&07);
+ } else {
+ ++col; /* echo input */
+ putc (c);
+ }
+ *p++ = c;
+ ++n;
+ } else { /* Buffer full */
+ putc ('\a');
+ }
+ }
+ }
+}
+
+/****************************************************************************/
+
+static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+ char *s;
+
+ if (*np == 0) {
+ return (p);
+ }
+
+ if (*(--p) == '\t') { /* will retype the whole line */
+ while (*colp > plen) {
+ puts (erase_seq);
+ (*colp)--;
+ }
+ for (s=buffer; s<p; ++s) {
+ if (*s == '\t') {
+ puts (tab_seq+((*colp) & 07));
+ *colp += 8 - ((*colp) & 07);
+ } else {
+ ++(*colp);
+ putc (*s);
+ }
+ }
+ } else {
+ puts (erase_seq);
+ (*colp)--;
+ }
+ (*np)--;
+ return (p);
+}
+
+/****************************************************************************/
+
+int parse_line (char *line, char *argv[])
+{
+ int nargs = 0;
+
+#ifdef DEBUG_PARSER
+ printf ("parse_line: \"%s\"\n", line);
+#endif
+ while (nargs < CFG_MAXARGS) {
+
+ /* skip any white space */
+ while ((*line == ' ') || (*line == '\t')) {
+ ++line;
+ }
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+ }
+
+ argv[nargs++] = line; /* begin of argument string */
+
+ /* find end of string */
+ while (*line && (*line != ' ') && (*line != '\t')) {
+ ++line;
+ }
+
+ if (*line == '\0') { /* end of line, no more args */
+ argv[nargs] = NULL;
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+ }
+
+ *line++ = '\0'; /* terminate current arg */
+ }
+
+ printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
+
+#ifdef DEBUG_PARSER
+ printf ("parse_line: nargs=%d\n", nargs);
+#endif
+ return (nargs);
+}
+
+/****************************************************************************/
+
+static void process_macros (const char *input, char *output)
+{
+ char c, prev;
+ const char *varname_start = NULL;
+ int inputcnt = strlen (input);
+ int outputcnt = CFG_CBSIZE;
+ int state = 0; /* 0 = waiting for '$' */
+ /* 1 = waiting for '(' */
+ /* 2 = waiting for ')' */
+
+#ifdef DEBUG_PARSER
+ char *output_start = output;
+
+ printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
+#endif
+
+ prev = '\0'; /* previous character */
+
+ while (inputcnt && outputcnt) {
+ c = *input++;
+ inputcnt--;
+
+ /* remove one level of escape characters */
+ if ((c == '\\') && (prev != '\\')) {
+ if (inputcnt-- == 0)
+ break;
+ prev = c;
+ c = *input++;
+ }
+
+ switch (state) {
+ case 0: /* Waiting for (unescaped) $ */
+ if ((c == '$') && (prev != '\\')) {
+ state++;
+ } else {
+ *(output++) = c;
+ outputcnt--;
+ }
+ break;
+ case 1: /* Waiting for ( */
+ if (c == '(') {
+ state++;
+ varname_start = input;
+ } else {
+ state = 0;
+ *(output++) = '$';
+ outputcnt--;
+
+ if (outputcnt) {
+ *(output++) = c;
+ outputcnt--;
+ }
+ }
+ break;
+ case 2: /* Waiting for ) */
+ if (c == ')') {
+ int i;
+ char envname[CFG_CBSIZE], *envval;
+ int envcnt = input-varname_start-1; /* Varname # of chars */
+
+ /* Get the varname */
+ for (i = 0; i < envcnt; i++) {
+ envname[i] = varname_start[i];
+ }
+ envname[i] = 0;
+
+ /* Get its value */
+ envval = getenv (envname);
+
+ /* Copy into the line if it exists */
+ if (envval != NULL)
+ while ((*envval) && outputcnt) {
+ *(output++) = *(envval++);
+ outputcnt--;
+ }
+ /* Look for another '$' */
+ state = 0;
+ }
+ break;
+ }
+
+ prev = c;
+ }
+
+ if (outputcnt)
+ *output = 0;
+
+#ifdef DEBUG_PARSER
+ printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+ strlen(output_start), output_start);
+#endif
+}
+
+/****************************************************************************
+ * returns:
+ * 1 - command executed, repeatable
+ * 0 - command executed but not repeatable, interrupted commands are
+ * always considered not repeatable
+ * -1 - not executed (unrecognized, bootd recursion or too many args)
+ * (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
+ * considered unrecognized)
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+
+int run_command (const char *cmd, int flag)
+{
+ cmd_tbl_t *cmdtp;
+ char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
+ char *token; /* start of token in cmdbuf */
+ char *sep; /* end of token (separator) in cmdbuf */
+ char finaltoken[CFG_CBSIZE];
+ char *str = cmdbuf;
+ char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
+ int argc;
+ int repeatable = 1;
+
+#ifdef DEBUG_PARSER
+ printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
+ puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
+ puts ("\"\n");
+#endif
+
+ clear_ctrlc(); /* forget any previous Control C */
+
+ if (!cmd || !*cmd) {
+ return -1; /* empty command */
+ }
+
+ if (strlen(cmd) >= CFG_CBSIZE) {
+ puts ("## Command too long!\n");
+ return -1;
+ }
+
+ strcpy (cmdbuf, cmd);
+
+ /* Process separators and check for invalid
+ * repeatable commands
+ */
+
+#ifdef DEBUG_PARSER
+ printf ("[PROCESS_SEPARATORS] %s\n", cmd);
+#endif
+ while (*str) {
+
+ /*
+ * Find separator, or string end
+ * Allow simple escape of ';' by writing "\;"
+ */
+ for (sep = str; *sep; sep++) {
+ if ((*sep == ';') && /* separator */
+ ( sep != str) && /* past string start */
+ (*(sep-1) != '\\')) /* and NOT escaped */
+ break;
+ }
+
+ /*
+ * Limit the token to data between separators
+ */
+ token = str;
+ if (*sep) {
+ str = sep + 1; /* start of command for next pass */
+ *sep = '\0';
+ }
+ else
+ str = sep; /* no more commands for next pass */
+#ifdef DEBUG_PARSER
+ printf ("token: \"%s\"\n", token);
+#endif
+
+ /* find macros in this token and replace them */
+ process_macros (token, finaltoken);
+
+ /* Extract arguments */
+ argc = parse_line (finaltoken, argv);
+
+ /* Look up command in command table */
+ if ((cmdtp = find_cmd(argv[0])) == NULL) {
+ printf ("Unknown command '%s' - try 'help'\n", argv[0]);
+ return -1; /* give up after bad command */
+ }
+
+ /* found - check max args */
+ if (argc > cmdtp->maxargs) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return -1;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ if (cmdtp->cmd == do_bootd) {
+#ifdef DEBUG_PARSER
+ printf ("[%s]\n", finaltoken);
+#endif
+ if (flag & CMD_FLAG_BOOTD) {
+ printf ("'bootd' recursion detected\n");
+ return -1;
+ }
+ else
+ flag |= CMD_FLAG_BOOTD;
+ }
+#endif /* CFG_CMD_BOOTD */
+
+ /* OK - call function to do the command */
+ if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
+ return (-1);
+ }
+
+ repeatable &= cmdtp->repeatable;
+
+ /* Did the user stop this? */
+ if (had_ctrlc ())
+ return 0; /* if stopped then not repeatable */
+ }
+
+ return repeatable;
+}
+
+/****************************************************************************/
+
+#if (CONFIG_COMMANDS & CFG_CMD_RUN)
+int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int i;
+ int rcode = 1;
+
+ if (argc < 2) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+
+ for (i=1; i<argc; ++i) {
+#ifndef CFG_HUSH_PARSER
+ if (run_command (getenv (argv[i]), flag) != -1) ++rcode;
+#else
+ if (parse_string_outer(getenv (argv[i]),
+ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) == 0) ++rcode;
+#endif
+ }
+ return ((rcode == i) ? 0 : 1);
+}
+#endif
diff --git a/common/miiphyutil.c b/common/miiphyutil.c
new file mode 100644
index 0000000..6b2425f
--- /dev/null
+++ b/common/miiphyutil.c
@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <miiphy.h>
+
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+
+/*****************************************************************************
+ *
+ * Read the OUI, manufacture's model number, and revision number.
+ *
+ * OUI: 22 bits (unsigned int)
+ * Model: 6 bits (unsigned char)
+ * Revision: 4 bits (unsigned char)
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_info (unsigned char addr,
+ unsigned int *oui,
+ unsigned char *model, unsigned char *rev)
+{
+ unsigned int reg = 0;
+
+ /*
+ * Trick: we are reading two 16 registers into a 32 bit variable
+ * so we do a 16 read into the high order bits of the variable (big
+ * endian, you know), shift it down 16 bits, and the read the rest.
+ */
+ if (miiphy_read (addr, PHY_PHYIDR2, (unsigned short *) ®) != 0) {
+#ifdef DEBUG
+ printf ("PHY ID register 2 read failed\n");
+#endif
+ return (-1);
+ }
+ reg >>= 16;
+
+#ifdef DEBUG
+ printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg);
+#endif
+ if (reg == 0xFFFF) {
+ /* No physical device present at this address */
+ return (-1);
+ }
+
+ if (miiphy_read (addr, PHY_PHYIDR1, (unsigned short *) ®) != 0) {
+#ifdef DEBUG
+ printf ("PHY ID register 1 read failed\n");
+#endif
+ return (-1);
+ }
+#ifdef DEBUG
+ printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg);
+#endif
+ *oui = ( reg >> 10);
+ *model = (unsigned char) ((reg >> 4) & 0x0000003F);
+ *rev = (unsigned char) ( reg & 0x0000000F);
+ return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Reset the PHY.
+ * Returns:
+ * 0 on success
+ */
+int miiphy_reset (unsigned char addr)
+{
+ unsigned short reg;
+ int loop_cnt;
+
+ if (miiphy_write (addr, PHY_BMCR, 0x8000) != 0) {
+#ifdef DEBUG
+ printf ("PHY reset failed\n");
+#endif
+ return (-1);
+ }
+
+ /*
+ * Poll the control register for the reset bit to go to 0 (it is
+ * auto-clearing). This should happen within 0.5 seconds per the
+ * IEEE spec.
+ */
+ loop_cnt = 0;
+ reg = 0x8000;
+ while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) {
+ if (miiphy_read (addr, PHY_BMCR, ®) != 0) {
+# ifdef DEBUG
+ printf ("PHY status read failed\n");
+# endif
+ return (-1);
+ }
+ }
+ if ((reg & 0x8000) == 0) {
+ return (0);
+ } else {
+ printf ("PHY reset timed out\n");
+ return (-1);
+ }
+ return (0);
+}
+
+
+/*****************************************************************************
+ *
+ * Determine the ethernet speed (10/100).
+ */
+int miiphy_speed (unsigned char addr)
+{
+ unsigned short reg;
+
+ if (miiphy_read (addr, PHY_ANLPAR, ®)) {
+ printf ("PHY speed1 read failed, assuming 10bT\n");
+ return (_10BASET);
+ }
+
+ if ((reg & PHY_ANLPAR_100) != 0) {
+ return (_100BASET);
+ } else {
+ return (_10BASET);
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * Determine full/half duplex.
+ */
+int miiphy_duplex (unsigned char addr)
+{
+ unsigned short reg;
+
+ if (miiphy_read (addr, PHY_ANLPAR, ®)) {
+ printf ("PHY duplex read failed, assuming half duplex\n");
+ return (HALF);
+ }
+
+ if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) {
+ return (FULL);
+ } else {
+ return (HALF);
+ }
+}
+
+#endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */
diff --git a/common/soft_i2c.c b/common/soft_i2c.c
new file mode 100644
index 0000000..7777480
--- /dev/null
+++ b/common/soft_i2c.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2001, 2002
+ * 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
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren@cideas.com. It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ */
+
+#include <common.h>
+#ifdef CONFIG_MPC8260 /* only valid for MPC8260 */
+#include <ioports.h>
+#endif
+#include <i2c.h>
+
+#if defined(CONFIG_SOFT_I2C)
+
+/* #define DEBUG_I2C */
+
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define RETRIES 0
+
+
+#define I2C_ACK 0 /* PD_SDA level to ack a byte */
+#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
+
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt,args...) do { \
+ DECLARE_GLOBAL_DATA_PTR; \
+ if (gd->have_console) \
+ printf (fmt ,##args); \
+ } while (0)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+/*-----------------------------------------------------------------------
+ * Local functions
+ */
+static void send_reset (void);
+static void send_start (void);
+static void send_stop (void);
+static void send_ack (int);
+static int write_byte (uchar byte);
+static uchar read_byte (int);
+
+
+/*-----------------------------------------------------------------------
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state. Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(void)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+ int j;
+
+ I2C_ACTIVE;
+ I2C_SDA(1);
+ for(j = 0; j < 9; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ }
+ send_stop();
+ I2C_TRISTATE;
+}
+
+/*-----------------------------------------------------------------------
+ * START: High -> Low on SDA while SCL is High
+ */
+static void send_start(void)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_ACTIVE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_DELAY;
+}
+
+/*-----------------------------------------------------------------------
+ * STOP: Low -> High on SDA while SCL is High
+ */
+static void send_stop(void)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(0);
+ I2C_ACTIVE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_DELAY;
+ I2C_TRISTATE;
+}
+
+
+/*-----------------------------------------------------------------------
+ * ack should be I2C_ACK or I2C_NOACK
+ */
+static void send_ack(int ack)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+ I2C_ACTIVE;
+ I2C_SCL(0);
+ I2C_DELAY;
+
+ I2C_SDA(ack);
+
+ I2C_ACTIVE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ I2C_SCL(0);
+ I2C_DELAY;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Send 8 bits and look for an acknowledgement.
+ */
+static int write_byte(uchar data)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+ int j;
+ int nack;
+
+ I2C_ACTIVE;
+ for(j = 0; j < 8; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(data & 0x80);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+
+ data <<= 1;
+ }
+
+ /*
+ * Look for an <ACK>(negative logic) and return it.
+ */
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SDA(1);
+ I2C_TRISTATE;
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ I2C_DELAY;
+ nack = I2C_READ;
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_ACTIVE;
+
+ return(nack); /* not a nack is an ack */
+}
+
+
+/*-----------------------------------------------------------------------
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(int ack)
+{
+#ifdef CONFIG_MPC8260
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
+#endif
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+ int data;
+ int j;
+
+ /*
+ * Read 8 bits, MSB first.
+ */
+ I2C_TRISTATE;
+ data = 0;
+ for(j = 0; j < 8; j++) {
+ I2C_SCL(0);
+ I2C_DELAY;
+ I2C_SCL(1);
+ I2C_DELAY;
+ data <<= 1;
+ data |= I2C_READ;
+ I2C_DELAY;
+ }
+ send_ack(ack);
+
+ return(data);
+}
+
+/*=====================================================================*/
+/* Public Functions */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+void i2c_init (int speed, int slaveaddr)
+{
+#ifdef CONFIG_8xx
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+#endif
+
+#ifdef I2C_INIT
+ I2C_INIT;
+#endif
+ /*
+ * WARNING: Do NOT save speed in a static variable: if the
+ * I2C routines are called before RAM is initialized (to read
+ * the DIMM SPD, for instance), RAM won't be usable and your
+ * system will crash.
+ */
+ send_reset ();
+}
+
+/*-----------------------------------------------------------------------
+ * Probe to see if a chip is present. Also good for checking for the
+ * completion of EEPROM writes since the chip stops responding until
+ * the write completes (typically 10mSec).
+ */
+int i2c_probe(uchar addr)
+{
+ int rc;
+
+ send_start();
+ rc = write_byte ((addr << 1) | 1);
+ send_stop();
+
+ return (rc ? 1 : 0);
+}
+
+/*-----------------------------------------------------------------------
+ * Read bytes
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ int shift;
+ PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
+ chip, addr, alen, buffer, len);
+
+#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
+ * address and the extra bits end up in the "chip address"
+ * bit slots. This makes a 24WC08 (1Kbyte) chip look like
+ * four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to
+ * still be one byte because the extra address bits are
+ * hidden in the chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
+
+ PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
+ chip, addr);
+#endif
+
+ /*
+ * Do the addressing portion of a write cycle to set the
+ * chip's address pointer. If the address length is zero,
+ * don't do the normal write cycle to set the address pointer,
+ * there is no address pointer in this chip.
+ */
+ send_start();
+ if(alen > 0) {
+ if(write_byte(chip << 1)) { /* write cycle */
+ send_stop();
+ PRINTD("i2c_read, no chip responded %02X\n", chip);
+ return(1);
+ }
+ shift = (alen-1) * 8;
+ while(alen-- > 0) {
+ if(write_byte(addr >> shift)) {
+ PRINTD("i2c_read, address not <ACK>ed\n");
+ return(1);
+ }
+ shift -= 8;
+ }
+ send_stop(); /* reportedly some chips need a full stop */
+ send_start();
+ }
+ /*
+ * Send the chip address again, this time for a read cycle.
+ * Then read the data. On the last byte, we do a NACK instead
+ * of an ACK(len == 0) to terminate the read.
+ */
+ write_byte((chip << 1) | 1); /* read cycle */
+ while(len-- > 0) {
+ *buffer++ = read_byte(len == 0);
+ }
+ send_stop();
+ return(0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write bytes
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ int shift, failures = 0;
+
+ PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
+ chip, addr, alen, buffer, len);
+
+ send_start();
+ if(write_byte(chip << 1)) { /* write cycle */
+ send_stop();
+ PRINTD("i2c_write, no chip responded %02X\n", chip);
+ return(1);
+ }
+ shift = (alen-1) * 8;
+ while(alen-- > 0) {
+ if(write_byte(addr >> shift)) {
+ PRINTD("i2c_write, address not <ACK>ed\n");
+ return(1);
+ }
+ shift -= 8;
+ }
+
+ while(len-- > 0) {
+ if(write_byte(*buffer++)) {
+ failures++;
+ }
+ }
+ send_stop();
+ return(failures);
+}
+
+/*-----------------------------------------------------------------------
+ * Read a register
+ */
+uchar i2c_reg_read(uchar i2c_addr, uchar reg)
+{
+ char buf;
+
+ i2c_read(i2c_addr, reg, 1, &buf, 1);
+
+ return(buf);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a register
+ */
+void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
+{
+ i2c_write(i2c_addr, reg, 1, &val, 1);
+}
+
+
+#endif /* CONFIG_SOFT_I2C */