]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
Initial revision
authorwdenk <wdenk>
Sat, 17 Aug 2002 09:36:01 +0000 (09:36 +0000)
committerwdenk <wdenk>
Sat, 17 Aug 2002 09:36:01 +0000 (09:36 +0000)
89 files changed:
board/c2mon/flash.c [new file with mode: 0644]
board/cogent/dipsw.c [new file with mode: 0644]
board/cogent/flash.c [new file with mode: 0644]
board/cu824/flash.c [new file with mode: 0644]
board/eltec/mhpc/flash.c [new file with mode: 0644]
board/ep8260/flash.c [new file with mode: 0644]
board/ep8260/mii_phy.c [new file with mode: 0644]
board/esd/adciop/flash.c [new file with mode: 0644]
board/esd/common/flash.c [new file with mode: 0644]
board/esd/cpci405/flash.c [new file with mode: 0644]
board/esd/dasa_sim/cmd_dasa_sim.c [new file with mode: 0644]
board/esd/dasa_sim/flash.c [new file with mode: 0644]
board/esd/du405/flash.c [new file with mode: 0644]
board/esd/ocrtc/flash.c [new file with mode: 0644]
board/esd/pci405/flash.c [new file with mode: 0644]
board/esteem192e/flash.c [new file with mode: 0644]
board/etx094/flash.c [new file with mode: 0644]
board/evb64260/i2c.c [new file with mode: 0644]
board/evb64260/intel_flash.c [new file with mode: 0644]
board/fads/flash.c [new file with mode: 0644]
board/fads/lamp.c [new file with mode: 0644]
board/genietv/flash.c [new file with mode: 0644]
board/gth/ee_access.c [new file with mode: 0644]
board/gth/flash.c [new file with mode: 0644]
board/hermes/flash.c [new file with mode: 0644]
board/hymod/eeprom.c [new file with mode: 0644]
board/hymod/flash.c [new file with mode: 0644]
board/icu862/flash.c [new file with mode: 0644]
board/ip860/flash.c [new file with mode: 0644]
board/ivm/flash.c [new file with mode: 0644]
board/lantec/flash.c [new file with mode: 0644]
board/mbx8xx/flash.c [new file with mode: 0644]
board/mbx8xx/vpd.c [new file with mode: 0644]
board/mousse/flash.h [new file with mode: 0644]
board/mpc8260ads/flash.c [new file with mode: 0644]
board/mpl/common/flash.c [new file with mode: 0644]
board/mpl/common/isa.c [new file with mode: 0644]
board/mpl/common/kbd.c [new file with mode: 0644]
board/mpl/common/usb_uhci.c [new file with mode: 0644]
board/musenki/flash.c [new file with mode: 0644]
board/nx823/flash.c [new file with mode: 0644]
board/pcippc2/flash.c [new file with mode: 0644]
board/pcippc2/pcippc2.h [new file with mode: 0644]
board/pcippc2/pcippc2_fpga.c [new file with mode: 0644]
board/rpxsuper/flash.c [new file with mode: 0644]
board/rpxsuper/mii_phy.c [new file with mode: 0644]
board/rsdproto/flash.c [new file with mode: 0644]
board/siemens/CCM/flash.c [new file with mode: 0644]
board/siemens/IAD210/atm.c [new file with mode: 0644]
board/siemens/IAD210/flash.c [new file with mode: 0644]
board/siemens/SCM/flash.c [new file with mode: 0644]
board/siemens/pcu_e/flash.c [new file with mode: 0644]
board/sixnet/flash.c [new file with mode: 0644]
board/spd8xx/flash.c [new file with mode: 0644]
board/tqm8260/flash.c [new file with mode: 0644]
board/w7o/fsboot.c [new file with mode: 0644]
board/w7o/watchdog.c [new file with mode: 0644]
board/westel/amx860/flash.c [new file with mode: 0644]
common/docecc.c [new file with mode: 0644]
common/flash.c [new file with mode: 0644]
common/lists.c [new file with mode: 0644]
common/miiphybb.c [new file with mode: 0644]
common/s_record.c [new file with mode: 0644]
common/usb.c [new file with mode: 0644]
common/usb_kbd.c [new file with mode: 0644]
common/usb_storage.c [new file with mode: 0644]
cpu/74xx_7xx/traps.c [new file with mode: 0644]
cpu/mpc824x/drivers/epic/epic1.c [new file with mode: 0644]
cpu/mpc824x/traps.c [new file with mode: 0644]
cpu/mpc8260/ether_fcc.c [new file with mode: 0644]
cpu/mpc8260/traps.c [new file with mode: 0644]
cpu/mpc8xx/traps.c [new file with mode: 0644]
cpu/mpc8xx/upatch.c [new file with mode: 0644]
cpu/ppc4xx/miiphy.c [new file with mode: 0644]
cpu/ppc4xx/traps.c [new file with mode: 0644]
disk/part.c [new file with mode: 0644]
drivers/pci_indirect.c [new file with mode: 0644]
examples/eepro100_eeprom.c [new file with mode: 0644]
include/pcmcia.h [new file with mode: 0644]
include/syscall.h [new file with mode: 0644]
lib_generic/crc32.c [new file with mode: 0644]
lib_ppc/bat_rw.c [new file with mode: 0644]
lib_ppc/cache.c [new file with mode: 0644]
net/rarp.c [new file with mode: 0644]
rtc/ds1306.c [new file with mode: 0644]
rtc/m41t11.c [new file with mode: 0644]
rtc/m48t35ax.c [new file with mode: 0644]
rtc/mc146818.c [new file with mode: 0644]
rtc/mpc8xx.c [new file with mode: 0644]

diff --git a/board/c2mon/flash.c b/board/c2mon/flash.c
new file mode 100644 (file)
index 0000000..181f82a
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#ifndef        CFG_ENV_ADDR
+#define CFG_ENV_ADDR   (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#endif
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V;
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+                             &flash_info[1]);
+#endif
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+       while ((addr[0] & 0x00800080) != 0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/cogent/dipsw.c b/board/cogent/dipsw.c
new file mode 100644 (file)
index 0000000..d2027c9
--- /dev/null
@@ -0,0 +1,50 @@
+#include <common.h>
+#include <board/cogent/dipsw.h>
+
+unsigned char
+dipsw_raw(void)
+{
+    return cma_mb_reg_read(&((cma_mb_dipsw *)CMA_MB_DIPSW_BASE)->dip_val);
+}
+
+unsigned char
+dipsw_cooked(void)
+{
+    unsigned char val1, val2, mask1, mask2;
+
+    val1 = dipsw_raw();
+
+    /*
+     * we want to mirror the bits because the low bit is switch 1 and high
+     * bit is switch 8 and also invert them because 1=off and 0=on, according
+     * to manual.
+     *
+     * this makes the value more intuitive i.e.
+     * - left most, or high, or top, bit is left most switch (1);
+     * - right most, or low, or bottom, bit is right most switch (8)
+     * - a set bit means "on" and a clear bit means "off"
+     */
+
+    val2 = 0;
+    for (mask1 = 1 << 7, mask2 = 1; mask1 > 0; mask1 >>= 1, mask2 <<= 1)
+       if ((val1 & mask1) == 0)
+           val2 |= mask2;
+
+    return (val2);
+}
+
+void
+dipsw_init(void)
+{
+    unsigned char val, mask;
+
+    val = dipsw_cooked();
+
+    printf("|");
+    for (mask = 1 << 7; mask > 0; mask >>= 1)
+       if (val & mask)
+           printf("on |");
+       else
+           printf("off|");
+    printf("\n");
+}
diff --git a/board/cogent/flash.c b/board/cogent/flash.c
new file mode 100644 (file)
index 0000000..86da80e
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * (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 <board/cogent/flash.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+
+#if defined(CONFIG_CMA302)
+
+/*
+ * probe for the existence of flash at address "addr"
+ * 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
+ */
+static int
+c302f_probe_word(c302f_addr_t addr)
+{
+       /* reset the flash */
+       *addr = C302F_BNK_CMD_RST;
+
+       /* check the manufacturer id */
+       *addr = C302F_BNK_CMD_RD_ID;
+       if (*C302F_BNK_ADDR_MAN(addr) != C302F_BNK_RD_ID_MAN)
+               return 1;
+
+       /* check the device id */
+       *addr = C302F_BNK_CMD_RD_ID;
+       if (*C302F_BNK_ADDR_DEV(addr) != C302F_BNK_RD_ID_DEV)
+               return 2;
+
+#ifdef FLASH_DEBUG
+       {
+               int i;
+
+               printf("\nMaster Lock Config = 0x%08lx\n",
+                       *C302F_BNK_ADDR_CFGM(addr));
+               for (i = 0; i < C302F_BNK_NBLOCKS; i++)
+                       printf("Block %2d Lock Config = 0x%08lx\n",
+                               i, *C302F_BNK_ADDR_CFG(i, addr));
+       }
+#endif
+
+       /* reset the flash again */
+       *addr = C302F_BNK_CMD_RST;
+
+       return 0;
+}
+
+/*
+ * probe for Cogent CMA302 flash module at address "base" and store
+ * info for any found into flash_info entry "fip". Must find at least
+ * one bank.
+ */
+static void
+c302f_probe(flash_info_t *fip, c302f_addr_t base)
+{
+       c302f_addr_t addr, eaddr;
+       int nbanks;
+
+       fip->size = 0L;
+       fip->sector_count = 0;
+
+       addr = base;
+       eaddr = C302F_BNK_ADDR_BASE(addr, C302F_MAX_BANKS);
+       nbanks = 0;
+
+       while (addr < eaddr) {
+               c302f_addr_t addrw, eaddrw, addrb;
+               int i, osc, nsc;
+
+               addrw = addr;
+               eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
+
+               while (addrw < eaddrw)
+                       if (c302f_probe_word(addrw++) != 0)
+                               goto out;
+
+               /* bank exists - append info for this bank to *fip */
+               fip->flash_id = FLASH_MAN_INTEL|FLASH_28F008S5;
+               fip->size += C302F_BNK_SIZE;
+               osc = fip->sector_count;
+               fip->sector_count += C302F_BNK_NBLOCKS;
+               if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
+                       panic("Too many sectors in flash at address 0x%08lx\n",
+                               (unsigned long)base);
+
+               addrb = addr;
+               for (i = osc; i < nsc; i++) {
+                       fip->start[i] = (ulong)addrb;
+                       fip->protect[i] = 0;
+                       addrb = C302F_BNK_ADDR_NEXT_BLK(addrb);
+               }
+
+               addr = C302F_BNK_ADDR_NEXT_BNK(addr);
+               nbanks++;
+       }
+
+out:
+       if (nbanks == 0)
+               panic("ERROR: no flash found at address 0x%08lx\n",
+                       (unsigned long)base);
+}
+
+static void
+c302f_reset(flash_info_t *info, int sect)
+{
+       c302f_addr_t addrw, eaddrw;
+
+       addrw = (c302f_addr_t)info->start[sect];
+       eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
+
+       while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+               printf("  writing reset cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = C302F_BNK_CMD_RST;
+               addrw++;
+       }
+}
+
+static void
+c302f_erase_init(flash_info_t *info, int sect)
+{
+       c302f_addr_t addrw, saddrw, eaddrw;
+       int flag;
+
+#ifdef FLASH_DEBUG
+       printf("0x%08lx C302F_BNK_CMD_PROG\n", C302F_BNK_CMD_PROG);
+       printf("0x%08lx C302F_BNK_CMD_ERASE1\n", C302F_BNK_CMD_ERASE1);
+       printf("0x%08lx C302F_BNK_CMD_ERASE2\n", C302F_BNK_CMD_ERASE2);
+       printf("0x%08lx C302F_BNK_CMD_CLR_STAT\n", C302F_BNK_CMD_CLR_STAT);
+       printf("0x%08lx C302F_BNK_CMD_RST\n", C302F_BNK_CMD_RST);
+       printf("0x%08lx C302F_BNK_STAT_RDY\n", C302F_BNK_STAT_RDY);
+       printf("0x%08lx C302F_BNK_STAT_ERR\n", C302F_BNK_STAT_ERR);
+#endif
+
+       saddrw = (c302f_addr_t)info->start[sect];
+       eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+       printf("erasing sector %d, start addr = 0x%08lx "
+               "(bank next word addr = 0x%08lx)\n", sect,
+               (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+       /* Disable intrs which might cause a timeout here */
+       flag = disable_interrupts();
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+               printf("  writing erase cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = C302F_BNK_CMD_ERASE1;
+               *addrw = C302F_BNK_CMD_ERASE2;
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+}
+
+static int
+c302f_erase_poll(flash_info_t *info, int sect)
+{
+       c302f_addr_t addrw, saddrw, eaddrw;
+       int sectdone, haderr;
+
+       saddrw = (c302f_addr_t)info->start[sect];
+       eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
+
+       sectdone = 1;
+       haderr = 0;
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+               c302f_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+               printf("  checking status at addr "
+                       "0x%08lx [0x%08lx]\n",
+                       (unsigned long)addrw, stat);
+#endif
+               if ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY)
+                       sectdone = 0;
+               else if ((stat & C302F_BNK_STAT_ERR) != 0) {
+                       printf(" failed on sector %d "
+                               "(stat = 0x%08lx) at "
+                               "address 0x%08lx\n",
+                               sect, stat,
+                               (unsigned long)addrw);
+                       *addrw = C302F_BNK_CMD_CLR_STAT;
+                       haderr = 1;
+               }
+       }
+
+       if (haderr)
+               return (-1);
+       else
+               return (sectdone);
+}
+
+static int
+c302f_write_word(c302f_addr_t addr, c302f_word_t value)
+{
+       c302f_word_t stat;
+       ulong start;
+       int flag, retval;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = C302F_BNK_CMD_PROG;
+
+       *addr = value;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       retval = 0;
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       do {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       retval = 1;
+                       goto done;
+               }
+               stat = *addr;
+       } while ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY);
+
+       if ((stat & C302F_BNK_STAT_ERR) != 0) {
+               printf("flash program failed (stat = 0x%08lx) "
+                       "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+               *addr = C302F_BNK_CMD_CLR_STAT;
+               retval = 3;
+       }
+
+done:
+       /* reset to read mode */
+       *addr = C302F_BNK_CMD_RST;
+
+       return (retval);
+}
+
+#endif /* CONFIG_CMA302 */
+
+unsigned long
+flash_init(void)
+{
+       unsigned long total;
+       int i;
+       flash_info_t *fip;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       fip = &flash_info[0];
+       total = 0L;
+
+#if defined(CONFIG_CMA302)
+       c302f_probe(fip, (c302f_addr_t)CFG_FLASH_BASE);
+       total += fip->size;
+       fip++;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+       /* not yet ...
+       cmbf_probe(fip, (cmbf_addr_t)CMA_MB_FLASH_BASE);
+       total += fip->size;
+       fip++;
+       */
+#endif
+
+       /*
+        * protect monitor and environment sectors
+        */
+
+#if CFG_MONITOR_BASE == CFG_FLASH_BASE
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+       return total;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void
+flash_print_info(flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F008S5:    printf ("28F008S5\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 4) == 0)
+                       printf ("\n   ");
+               printf (" %2d - %08lX%s", i,
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+       int prot, sect, haderr;
+       ulong start, now, last;
+       void (*erase_init)(flash_info_t *, int);
+       int (*erase_poll)(flash_info_t *, int);
+       void (*reset)(flash_info_t *, int);
+       int rcode = 0;
+
+#ifdef FLASH_DEBUG
+       printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+               "  Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+               (info - flash_info) + 1);
+       flash_print_info(info);
+#endif
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       switch (info->flash_id) {
+
+#if defined(CONFIG_CMA302)
+       case FLASH_MAN_INTEL|FLASH_28F008S5:
+               erase_init = c302f_erase_init;
+               erase_poll = c302f_erase_poll;
+               reset = c302f_reset;
+               break;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+       case FLASH_MAN_INTEL|FLASH_28F800_B:
+       case FLASH_MAN_AMD|FLASH_AM29F800B:
+               /* not yet ...
+               erase_init = cmbf_erase_init;
+               erase_poll = cmbf_erase_poll;
+               reset = cmbf_reset;
+               break;
+               */
+#endif
+
+       default:
+               printf ("Flash type %08lx not supported - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf("- Warning: %d protected sector%s will not be erased!\n",
+                       prot, (prot > 1 ? "s" : ""));
+       }
+
+       start = get_timer (0);
+       last = 0;
+       haderr = 0;
+
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       ulong estart;
+                       int sectdone;
+
+                       (*erase_init)(info, sect);
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       estart = get_timer(start);
+
+                       do {
+                               now = get_timer(start);
+
+                               if (now - estart > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout (sect %d)\n", sect);
+                                       haderr = 1;
+                                       break;
+                               }
+
+#ifndef FLASH_DEBUG
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) { /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+#endif
+
+                               sectdone = (*erase_poll)(info, sect);
+
+                               if (sectdone < 0) {
+                                       haderr = 1;
+                                       break;
+                               }
+
+                       } while (!sectdone);
+
+                       if (haderr)
+                               break;
+               }
+       }
+
+       if (haderr > 0) {
+               printf (" failed\n");
+               rcode = 1;
+       }
+       else
+               printf (" done\n");
+
+       /* reset to read mode */
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       (*reset)(info, sect);
+               }
+       }
+       return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 3 - write error
+ */
+
+int
+write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+       ulong start, now, last;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       start = get_timer (0);
+       last = 0;
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+
+               /* show that we're waiting */
+               now = get_timer(start);
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 3 - write error
+ */
+static int
+write_word(flash_info_t *info, ulong dest, ulong data)
+{
+       int retval;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*(ulong *)dest & data) != data) {
+               return (2);
+       }
+
+       switch (info->flash_id) {
+
+#if defined(CONFIG_CMA302)
+       case FLASH_MAN_INTEL|FLASH_28F008S5:
+               retval = c302f_write_word((c302f_addr_t)dest, (c302f_word_t)data);
+               break;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+       case FLASH_MAN_INTEL|FLASH_28F800_B:
+       case FLASH_MAN_AMD|FLASH_AM29F800B:
+               /* not yet ...
+               retval = cmbf_write_word((cmbf_addr_t)dest, (cmbf_word_t)data);
+               */
+               retval = 3;
+               break;
+#endif
+
+       default:
+               printf ("Flash type %08lx not supported - aborted\n",
+                       info->flash_id);
+               retval = 3;
+               break;
+       }
+
+       return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/cu824/flash.c b/board/cu824/flash.c
new file mode 100644 (file)
index 0000000..0cec41e
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+#define FLASH_BANK_SIZE 0x800000
+#define MAIN_SECT_SIZE  0x40000
+#define PARAM_SECT_SIZE 0x8000
+
+#define BOARD_CTRL_REG 0xFE800013
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+static int write_data (flash_info_t *info, ulong dest, ulong *data);
+static void write_via_fpu(vu_long *addr, ulong *data);
+static __inline__ unsigned long get_msr(void);
+static __inline__ void set_msr(unsigned long msr);
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+/*---------------------------------------------------------------------*/
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init(void)
+{
+    int i, j;
+    ulong size = 0;
+    volatile unsigned char *bcr = (volatile unsigned char *)(BOARD_CTRL_REG);
+
+    DEBUGF("Write protect was: 0x%02X\n", *bcr);
+    *bcr &= 0x1;       /* FWPT must be 0  */
+    *bcr |= 0x6;       /* FWP0 = FWP1 = 1 */
+    DEBUGF("Write protect is:  0x%02X\n", *bcr);
+
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+       vu_long *addr = (vu_long *)(CFG_FLASH_BASE + i * FLASH_BANK_SIZE);
+
+       addr[0] = 0x00900090;
+
+       DEBUGF ("Flash bank # %d:\n"
+               "\tManuf. ID @ 0x%08lX: 0x%08lX\n"
+               "\tDevice ID @ 0x%08lX: 0x%08lX\n",
+               i,
+               (ulong)(&addr[0]), addr[0],
+               (ulong)(&addr[2]), addr[2]);
+
+       if ((addr[0] == addr[1]) && (addr[0] == INTEL_MANUFACT) &&
+           (addr[2] == addr[3]) && (addr[2] == INTEL_ID_28F160F3B))
+       {
+           flash_info[i].flash_id = (FLASH_MAN_INTEL & FLASH_VENDMASK) |
+                                    (INTEL_ID_28F160F3B & FLASH_TYPEMASK);
+       } else {
+           flash_info[i].flash_id = FLASH_UNKNOWN;
+           addr[0] = 0xFFFFFFFF;
+           goto Done;
+       }
+
+       DEBUGF ("flash_id = 0x%08lX\n", flash_info[i].flash_id);
+
+       addr[0] = 0xFFFFFFFF;
+
+       flash_info[i].size = FLASH_BANK_SIZE;
+       flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+       memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+       for (j = 0; j < flash_info[i].sector_count; j++) {
+               if (j <= 7) {
+                       flash_info[i].start[j] = CFG_FLASH_BASE +
+                                                i * FLASH_BANK_SIZE +
+                                                j * PARAM_SECT_SIZE;
+               } else {
+                       flash_info[i].start[j] = CFG_FLASH_BASE +
+                                                i * FLASH_BANK_SIZE +
+                                                (j - 7)*MAIN_SECT_SIZE;
+               }
+       }
+       size += flash_info[i].size;
+    }
+
+    /* Protect monitor and environment sectors
+     */
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + FLASH_BANK_SIZE
+    flash_protect(FLAG_PROTECT_SET,
+              CFG_MONITOR_BASE,
+              CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+              &flash_info[1]);
+#else
+    flash_protect(FLAG_PROTECT_SET,
+              CFG_MONITOR_BASE,
+              CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+              &flash_info[0]);
+#endif
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+#if CFG_ENV_ADDR >= CFG_FLASH_BASE + FLASH_BANK_SIZE
+    flash_protect(FLAG_PROTECT_SET,
+              CFG_ENV_ADDR,
+              CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+              &flash_info[1]);
+#else
+    flash_protect(FLAG_PROTECT_SET,
+              CFG_ENV_ADDR,
+              CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+              &flash_info[0]);
+#endif
+#endif
+
+Done:
+    return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+       int i;
+
+       switch ((i = info->flash_id & FLASH_VENDMASK)) {
+       case (FLASH_MAN_INTEL & FLASH_VENDMASK):
+               printf ("Intel: ");
+               break;
+       default:
+               printf ("Unknown Vendor 0x%04x ", i);
+               break;
+       }
+
+       switch ((i = info->flash_id & FLASH_TYPEMASK)) {
+       case (INTEL_ID_28F160F3B & FLASH_TYPEMASK):
+               printf ("28F160F3B (16Mbit)\n");
+               break;
+       default:
+               printf ("Unknown Chip Type 0x%04x\n", i);
+               goto Done;
+               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i = 0; i < info->sector_count; i++) {
+               if ((i % 5) == 0) {
+                       printf ("\n   ");
+               }
+               printf (" %08lX%s", info->start[i],
+                               info->protect[i] ? " (RO)" : "     ");
+       }
+       printf ("\n");
+
+Done:
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong start, now, last;
+
+       DEBUGF ("Erase flash bank %d sect %d ... %d\n",
+               info - &flash_info[0], s_first, s_last);
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) !=
+           (FLASH_MAN_INTEL & FLASH_VENDMASK)) {
+               printf ("Can erase only Intel flash types - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       vu_long *addr = (vu_long *)(info->start[sect]);
+
+                       DEBUGF ("Erase sect %d @ 0x%08lX\n",
+                               sect, (ulong)addr);
+
+                       /* Disable interrupts which might cause a timeout
+                        * here.
+                        */
+                       flag = disable_interrupts();
+
+                       addr[0] = 0x00500050;   /* clear status register */
+                       addr[0] = 0x00200020;   /* erase setup */
+                       addr[0] = 0x00D000D0;   /* erase confirm */
+
+                       addr[1] = 0x00500050;   /* clear status register */
+                       addr[1] = 0x00200020;   /* erase setup */
+                       addr[1] = 0x00D000D0;   /* erase confirm */
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while (((addr[0] & 0x00800080) != 0x00800080) ||
+                              ((addr[1] & 0x00800080) != 0x00800080) ) {
+                               if ((now=get_timer(start)) >
+                                          CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       addr[0] = 0x00B000B0; /* suspend erase */
+                                       addr[0] = 0x00FF00FF; /* to read mode  */
+                                       return 1;
+                               }
+
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {  /* every second  */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       addr[0] = 0x00FF00FF;
+               }
+       }
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define        FLASH_WIDTH     8       /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong wp, cp, msr;
+       int l, rc, i;
+       ulong data[2];
+       ulong *datah = &data[0];
+       ulong *datal = &data[1];
+
+       DEBUGF ("Flash write_buff: @ 0x%08lx, src 0x%08lx len %ld\n",
+               addr, (ulong)src, cnt);
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+
+       msr = get_msr();
+       set_msr(msr | MSR_FP);
+
+       wp = (addr & ~(FLASH_WIDTH-1)); /* get lower aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               *datah = *datal = 0;
+
+               for (i = 0, cp = wp; i < l; i++, cp++) {
+                       if (i >= 4) {
+                               *datah = (*datah << 8) |
+                                               ((*datal & 0xFF000000) >> 24);
+                       }
+
+                       *datal = (*datal << 8) | (*(uchar *)cp);
+               }
+               for (; i < FLASH_WIDTH && cnt > 0; ++i) {
+                       char tmp;
+
+                       tmp = *src;
+
+                       src++;
+
+                       if (i >= 4) {
+                               *datah = (*datah << 8) |
+                                               ((*datal & 0xFF000000) >> 24);
+                       }
+
+                       *datal = (*datal << 8) | tmp;
+
+                       --cnt; ++cp;
+               }
+
+               for (; cnt == 0 && i < FLASH_WIDTH; ++i, ++cp) {
+                       if (i >= 4) {
+                               *datah = (*datah << 8) |
+                                               ((*datal & 0xFF000000) >> 24);
+                       }
+
+                       *datal = (*datah << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       set_msr(msr);
+                       return (rc);
+               }
+
+               wp += FLASH_WIDTH;
+       }
+
+       /*
+        * handle FLASH_WIDTH aligned part
+        */
+       while (cnt >= FLASH_WIDTH) {
+               *datah = *(ulong *)src;
+               *datal = *(ulong *)(src + 4);
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       set_msr(msr);
+                       return (rc);
+               }
+               wp  += FLASH_WIDTH;
+               cnt -= FLASH_WIDTH;
+               src += FLASH_WIDTH;
+       }
+
+       if (cnt == 0) {
+               set_msr(msr);
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       *datah = *datal = 0;
+       for (i = 0, cp = wp; i < FLASH_WIDTH && cnt > 0; ++i, ++cp) {
+               char tmp;
+
+               tmp = *src;
+
+               src++;
+
+               if (i >= 4) {
+                       *datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
+               }
+
+               *datal = (*datal << 8) | tmp;
+
+               --cnt;
+       }
+
+       for (; i < FLASH_WIDTH; ++i, ++cp) {
+               if (i >= 4) {
+                       *datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
+               }
+
+               *datal = (*datal << 8) | (*(uchar *)cp);
+       }
+
+       rc = write_data(info, wp, data);
+       set_msr(msr);
+
+       return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong *data)
+{
+       vu_long *addr = (vu_long *)dest;
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if (((addr[0] & data[0]) != data[0]) ||
+           ((addr[1] & data[1]) != data[1]) ) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0] = 0x00400040;           /* write setup */
+       write_via_fpu(addr, data);
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       start = get_timer (0);
+
+       while (((addr[0] & 0x00800080) != 0x00800080) ||
+              ((addr[1] & 0x00800080) != 0x00800080) ) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       addr[0] = 0x00FF00FF;   /* restore read mode */
+                       return (1);
+               }
+       }
+
+       addr[0] = 0x00FF00FF;   /* restore read mode */
+
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void write_via_fpu(vu_long *addr, ulong *data)
+{
+       __asm__ __volatile__ ("lfd  1, 0(%0)" : : "r" (data));
+       __asm__ __volatile__ ("stfd 1, 0(%0)" : : "r" (addr));
+}
+/*-----------------------------------------------------------------------
+ */
+static __inline__ unsigned long get_msr(void)
+{
+    unsigned long msr;
+
+    __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
+    return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+    __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
+}
diff --git a/board/eltec/mhpc/flash.c b/board/eltec/mhpc/flash.c
new file mode 100644 (file)
index 0000000..58cfd70
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <linux/byteorder/swab.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+/* Board support for 1 or 2 flash devices */
+#undef FLASH_PORT_WIDTH32
+#define FLASH_PORT_WIDTH16
+
+#ifdef FLASH_PORT_WIDTH16
+#define FLASH_PORT_WIDTH               ushort
+#define FLASH_PORT_WIDTHV              vu_short
+#define SWAP(x)                         __swab16(x)
+#else
+#define FLASH_PORT_WIDTH               ulong
+#define FLASH_PORT_WIDTHV              vu_long
+#define SWAP(x)                         __swab32(x)
+#endif
+
+#define FPW    FLASH_PORT_WIDTH
+#define FPWV   FLASH_PORT_WIDTHV
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (FPW *addr, flash_info_t *info);
+static int   write_data (flash_info_t *info, ulong dest, FPW data);
+static void  flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+       size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       (void)flash_protect(FLAG_PROTECT_SET,
+                           CFG_FLASH_BASE,
+                           CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+                           &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+       return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000);
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+               case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+               default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+   case FLASH_28F640J5 :
+                               printf ("28F640J5 \n"); break;
+       default:                printf ("Unknown Chip Type=0x%lXh\n",
+                                       info->flash_id & FLASH_TYPEMASK); break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (FPW *addr, flash_info_t *info)
+{
+       FPW value;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x5555] = (FPW)0xAA00AA00;
+       addr[0x2AAA] = (FPW)0x55005500;
+       addr[0x5555] = (FPW)0x90009000;
+
+       value = SWAP(addr[0]);
+
+   switch (value) {
+   case (FPW)INTEL_MANUFACT:
+      info->flash_id = FLASH_MAN_INTEL;
+      break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               addr[0] = (FPW)0xFF00FF00;      /* restore read mode */
+               return (0);                           /* no or unknown flash    */
+       }
+
+   value = SWAP(addr[1]);                              /* device ID no swap !*/
+
+   switch (value) {
+   case (FPW)INTEL_ID_28F640J5 :
+        info->flash_id += FLASH_28F640J5 ;
+        info->sector_count = 64;
+        info->size = 0x00800000;
+        break;            /* => 8 MB     */
+
+        default:
+                info->flash_id = FLASH_UNKNOWN;
+               break;
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       addr[0] = (FPW)0xFF00FF00;      /* restore read mode */
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong type, start, now, last;
+       int rc = 0;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       type = (info->flash_id & FLASH_VENDMASK);
+       if ((type != FLASH_MAN_INTEL)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       FPWV *addr = (FPWV *)(info->start[sect]);
+                       FPW status;
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       *addr = (FPW)0x50005000;        /* clear status register */
+                       *addr = (FPW)0x20002000;        /* erase setup */
+                       *addr = (FPW)0xD000D000;        /* erase confirm */
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = (FPW)0xB000B000; /* suspend erase */
+                                       *addr = (FPW)0xFF00FF00; /* reset to read mode */
+                                       rc = 1;
+                                       break;
+                               }
+
+                               /* show that we're waiting */
+                       if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       *addr = (FPW)0xFF00FF00;        /* reset to read mode */
+                       printf (" done\n");
+               }
+       }
+       return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp;
+       FPW data;
+       int count, i, l, rc, port_width;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+/* get lower word aligned address */
+#ifdef FLASH_PORT_WIDTH16
+       wp = (addr & ~1);
+       port_width = 2;
+#else
+       wp = (addr & ~3);
+       port_width = 4;
+#endif
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<port_width && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<port_width; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += port_width;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       count = 0;
+       while (cnt >= port_width) {
+               data = 0;
+               for (i=0; i<port_width; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += port_width;
+               cnt -= port_width;
+               if ((wp & 0xfff) == 0)
+               {
+                       printf("%08lX",wp);
+                       printf("\x1b[8D");
+               }
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<port_width; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word or halfword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, FPW data)
+{
+       FPWV *addr = (FPWV *)dest;
+       ulong status;
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*addr & data) != data) {
+               printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = (FPW)0x40004000;                /* write setup */
+       *addr = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       start = get_timer (0);
+
+       while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       *addr = (FPW)0xFF00FF00;        /* restore read mode */
+                       return (1);
+               }
+       }
+
+       *addr = (FPW)0xFF00FF00;        /* restore read mode */
+
+       return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/board/ep8260/flash.c b/board/ep8260/flash.c
new file mode 100644 (file)
index 0000000..cae8a13
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Frank Panno <fpanno@delphintech.com>, Delphin Technology AG
+ *
+ * Flash Routines for AMD device AM29DL323DB on the EP8260 board.
+ *
+ * This file is based on board/tqm8260/flash.c.
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+
+#define V_ULONG(a)     (*(volatile unsigned long *)( a ))
+#define V_BYTE(a)      (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset(void)
+{
+  if( flash_info[0].flash_id != FLASH_UNKNOWN ) {
+    V_ULONG( flash_info[0].start[0] ) = 0x00F000F0;
+    V_ULONG( flash_info[0].start[0] + 4 ) = 0x00F000F0;
+  }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size( ulong baseaddr, flash_info_t *info )
+{
+  short i;
+  unsigned long flashtest_h, flashtest_l;
+
+  /* Write auto select command sequence and test FLASH answer */
+  V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA;
+  V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055;
+  V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090;
+  V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA;
+  V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055;
+  V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090;
+
+  flashtest_h = V_ULONG(baseaddr);             /* manufacturer ID         */
+  flashtest_l = V_ULONG(baseaddr + 4);
+
+  if ((int)flashtest_h == AMD_MANUFACT) {
+       info->flash_id = FLASH_MAN_AMD;
+  } else {
+       info->flash_id = FLASH_UNKNOWN;
+       info->sector_count = 0;
+       info->size = 0;
+       return (0);                             /* no or unknown flash     */
+  }
+
+  flashtest_h = V_ULONG(baseaddr + 8);         /* device ID               */
+  flashtest_l = V_ULONG(baseaddr + 12);
+  if (flashtest_h != flashtest_l) {
+    info->flash_id = FLASH_UNKNOWN;
+    return(0);
+  }
+  if (flashtest_h == AMD_ID_DL323B) {
+    info->flash_id += FLASH_AMDL323B;
+    info->sector_count = 71;
+    info->size = 0x01000000;                   /* 4 * 4 MB = 16 MB     */
+  } else {
+    info->flash_id = FLASH_UNKNOWN;
+    return(0);                                 /* no or unknown flash     */
+  }
+
+  /* set up sector start adress table (bottom sector type) */
+  for (i = 0; i < 8; i++) {
+    info->start[i] = baseaddr + (i * 0x00008000);
+  }
+  for (i = 8; i < info->sector_count; i++) {
+    info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000;
+  }
+
+  /* check for protected sectors */
+  for (i = 0; i < info->sector_count; i++) {
+    /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+    if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) ||
+        (V_ULONG( info->start[i] + 20 ) & 0x00010001)) {
+       info->protect[i] = 1;           /* D0 = 1 if protected */
+    } else {
+       info->protect[i] = 0;
+    }
+  }
+
+  flash_reset();
+  return(info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+    unsigned long size_b0 = 0;
+    int i;
+
+    /* Init: no FLASHes known */
+    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+       flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+    /* Static FLASH Bank configuration here (only one bank) */
+
+    size_b0 = flash_get_size(CFG_FLASH0_BASE, &flash_info[0]);
+    if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+       printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+               size_b0, size_b0>>20);
+    }
+
+    /*
+     * protect monitor and environment sectors
+     */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_MONITOR_BASE,
+                 CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                 &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_ENV_ADDR,
+                 CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+                 &flash_info[0]);
+#endif
+
+    return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+
+    if (info->flash_id == FLASH_UNKNOWN) {
+       printf ("missing or unknown FLASH type\n");
+       return;
+    }
+
+    switch ((info->flash_id >> 16) & 0xff) {
+    case FLASH_MAN_AMD:            printf ("AMD ");                break;
+    default:               printf ("Unknown Vendor ");     break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case FLASH_AMDL323B:       printf ("29DL323B (32 M, bottom sector)\n");
+                               break;
+    default:                   printf ("Unknown Chip Type\n");
+                               break;
+    }
+
+    printf ("  Size: %ld MB in %d Sectors\n",
+           info->size >> 20, info->sector_count);
+
+    printf ("  Sector Start Addresses:");
+    for (i=0; i<info->sector_count; ++i) {
+       if ((i % 5) == 0)
+         printf ("\n   ");
+       printf (" %08lX%s",
+               info->start[i],
+               info->protect[i] ? " (RO)" : "     "
+               );
+    }
+    printf ("\n");
+    return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect, l_sect;
+    ulong start, now, last;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+       if (info->flash_id == FLASH_UNKNOWN) {
+           printf ("- missing\n");
+       } else {
+           printf ("- no sectors to erase\n");
+       }
+       return 1;
+    }
+
+    prot = 0;
+    for (sect = s_first; sect <= s_last; sect++) {
+       if (info->protect[sect])
+           prot++;
+    }
+
+    if (prot) {
+       printf ("- Warning: %d protected sectors will not be erased!\n",
+               prot);
+    } else {
+       printf ("\n");
+    }
+
+    l_sect = -1;
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+    V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00800080;
+    V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+    V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+    V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00800080;
+    V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+    udelay (1000);
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last; sect++) {
+       if (info->protect[sect] == 0) { /* not protected */
+           V_ULONG( info->start[sect] ) = 0x00300030;
+           V_ULONG( info->start[sect] + 4 ) = 0x00300030;
+           l_sect = sect;
+       }
+    }
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* wait at least 80us - let's wait 1 ms */
+    udelay (1000);
+
+    /*
+     * We wait for the last triggered sector
+     */
+    if (l_sect < 0)
+      goto DONE;
+
+    start = get_timer (0);
+    last  = start;
+    while ((V_ULONG( info->start[l_sect] ) & 0x00800080) != 0x00800080 ||
+          (V_ULONG( info->start[l_sect] + 4 ) & 0x00800080) != 0x00800080)
+    {
+       if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+           printf ("Timeout\n");
+           return 1;
+       }
+       /* show that we're waiting */
+       if ((now - last) > 1000) {      /* every second */
+           serial_putc ('.');
+           last = now;
+       }
+    }
+
+    DONE:
+    /* reset to read mode */
+    flash_reset ();
+
+    printf (" done\n");
+    return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong dp;
+    static unsigned char bb[8];
+    int i, l, rc, cc = cnt;
+
+    dp = (addr & ~7);  /* get lower dword aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    if ((l = addr - dp) != 0) {
+       for (i = 0; i < 8; i++)
+           bb[i] = (i < l || (i-l) >= cc) ? V_BYTE(dp+i) : *src++;
+       if ((rc = write_dword(info, dp, bb)) != 0)
+       {
+           return (rc);
+       }
+       dp += 8;
+       cc -= 8 - l;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cc >= 8) {
+       if ((rc = write_dword(info, dp, src)) != 0) {
+           return (rc);
+       }
+       dp  += 8;
+       src += 8;
+       cc -= 8;
+    }
+
+    if (cc <= 0) {
+       return (0);
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    for (i = 0; i < 8; i++) {
+       bb[i] = (i < cc) ? *src++ : V_BYTE(dp+i);
+    }
+    return (write_dword(info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t *info, ulong dest, unsigned char * pdata)
+{
+    ulong start;
+    ulong cl = 0, ch =0;
+    int flag, i;
+
+    for (ch=0, i=0; i < 4; i++)
+       ch = (ch << 8) + *pdata++;      /* high word    */
+    for (cl=0, i=0; i < 4; i++)
+       cl = (cl << 8) + *pdata++;      /* low word     */
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*((vu_long *)dest) & ch)      != ch
+      ||(*((vu_long *)(dest + 4)) & cl)        != cl)
+    {
+       return (2);
+    }
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+    V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00A000A0;
+    V_ULONG( dest ) = ch;
+    V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+    V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+    V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00A000A0;
+    V_ULONG( dest + 4 ) = cl;
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* data polling for D7 */
+    start = get_timer (0);
+    while (((V_ULONG( dest ) & 0x00800080) != (ch & 0x00800080)) ||
+           ((V_ULONG( dest + 4 ) & 0x00800080) != (cl & 0x00800080))) {
+       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+           return (1);
+       }
+    }
+    return (0);
+}
diff --git a/board/ep8260/mii_phy.c b/board/ep8260/mii_phy.c
new file mode 100644 (file)
index 0000000..e3b7878
--- /dev/null
@@ -0,0 +1,108 @@
+#include <common.h>
+#include <mii_phy.h>
+#include "ep8260.h"
+
+#define MII_MDIO       0x01
+#define MII_MDCK       0x02
+#define MII_MDIR       0x04
+
+void
+mii_discover_phy(void)
+{
+    int known;
+    unsigned short phy_reg;
+    unsigned long phy_id;
+
+    known = 0;
+    printf("Discovering phy @ 0: ");
+    phy_id = mii_phy_read(2) << 16;
+    phy_id |= mii_phy_read(3);
+    if ((phy_id & 0xFFFFFC00) == 0x00137800) {
+       printf("Level One ");
+       if ((phy_id & 0x000003F0) == 0xE0) {
+           printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
+           known = 1;
+       }
+       else printf("unknown type\n");
+    }
+    else printf("unknown OUI = 0x%08lX\n", phy_id);
+
+    phy_reg = mii_phy_read(1);
+    if (!(phy_reg & 0x0004)) printf("Link is down\n");
+    if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
+    if (phy_reg & 0x0002) printf("Jabber condition detected\n");
+    if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
+
+    if (known) {
+       phy_reg = mii_phy_read(17);
+       if (phy_reg & 0x0400)
+           printf("Phy operating at %d MBit/s in %s-duplex mode\n",
+               phy_reg & 0x4000 ? 100 : 10,
+               phy_reg & 0x0200 ? "full" : "half");
+       else
+           printf("bad link!!\n");
+/*
+left  off: no link, green 100MBit, yellow 10MBit
+right off: no activity, green full-duplex, yellow half-duplex
+*/
+       mii_phy_write(20, 0x0452);
+    }
+}
+
+unsigned short
+mii_phy_read(unsigned short reg)
+{
+    int i;
+    unsigned short tmp, val = 0, adr = 0;
+    t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
+
+    tmp = 0x6002 | (adr << 7) | (reg << 2);
+    regs->bcsr4 = 0xC3;
+    for (i = 0; i < 64; i++) {
+        regs->bcsr4 ^= MII_MDCK;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+       if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       tmp <<= 1;
+    }
+    regs->bcsr4 |= MII_MDIR;
+    for (i = 0; i < 16; i++) {
+       val <<= 1;
+       regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
+       if (regs->bcsr4 & MII_MDIO) val |= 1;
+       regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
+    }
+    return val;
+}
+
+void
+mii_phy_write(unsigned short reg, unsigned short val)
+{
+    int i;
+    unsigned short tmp, adr = 0;
+    t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
+
+    tmp = 0x5002 | (adr << 7) | (reg << 2);
+    regs->bcsr4 = 0xC3;
+    for (i = 0; i < 64; i++) {
+       regs->bcsr4 ^= MII_MDCK;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+        if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       tmp <<= 1;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+       if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       val <<= 1;
+    }
+}
+
diff --git a/board/esd/adciop/flash.c b/board/esd/adciop/flash.c
new file mode 100644 (file)
index 0000000..46ae03b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
+                     FLASH_BASE0_PRELIM+size_b0-1,
+                     &flash_info[0]);
+
+       if (size_b1) {
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(FLASH_BASE0_PRELIM + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (FLASH_BASE0_PRELIM + size_b0, &flash_info[1]);
+
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             FLASH_BASE0_PRELIM+size_b0+size_b1-CFG_MONITOR_LEN,
+                             FLASH_BASE0_PRELIM+size_b0+size_b1-1,
+                             &flash_info[1]);
+                /* monitor protection OFF by default (one is enough) */
+                flash_protect(FLAG_PROTECT_CLEAR,
+                             FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
+                             FLASH_BASE0_PRELIM+size_b0-1,
+                             &flash_info[0]);
+       } else {
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
diff --git a/board/esd/common/flash.c b/board/esd/common/flash.c
new file mode 100644 (file)
index 0000000..78a1e0f
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+       short n;
+
+       /* set up sector start address table */
+        if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
+           for (i = 0; i < info->sector_count; i++)
+               info->start[i] = base + (i * 0x00010000);
+        } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
+               /* set sector offsets for bottom boot block type        */
+               for (i=0; i<8; ++i) {           /*  8 x 8k boot sectors */
+                       info->start[i] = base;
+                       base += 8 << 10;
+               }
+               while (i < info->sector_count) {        /* 64k regular sectors  */
+                       info->start[i] = base;
+                       base += 64 << 10;
+                       ++i;
+               }
+        } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
+               /* set sector offsets for top boot block type           */
+               base += info->size;
+               i = info->sector_count;
+               for (n=0; n<8; ++n) {           /*  8 x 8k boot sectors */
+                       base -= 8 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+               while (i > 0) {                 /* 64k regular sectors  */
+                       base -= 64 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+        } else {
+           if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+           } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+           }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+        int k;
+        int size;
+        int erased;
+        volatile unsigned long *flash;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 M, top sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 M, bottom sector)\n");
+                               break;
+       case FLASH_AMDL322T:    printf ("AM29DL322T (32 M, top sector)\n");
+                               break;
+       case FLASH_AMDL322B:    printf ("AM29DL322B (32 M, bottom sector)\n");
+                               break;
+       case FLASH_AMDL323T:    printf ("AM29DL323T (32 M, top sector)\n");
+                               break;
+       case FLASH_AMDL323B:    printf ("AM29DL323B (32 M, bottom sector)\n");
+                               break;
+       case FLASH_AM640U:      printf ("AM29LV640D (64 M, uniform sector)\n");
+                               break;
+       case FLASH_SST800A:     printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
+                               break;
+       case FLASH_SST160A:     printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+#ifdef CFG_FLASH_EMPTY_INFO
+                /*
+                 * Check if whole sector is erased
+                 */
+                if (i != (info->sector_count-1))
+                  size = info->start[i+1] - info->start[i];
+                else
+                  size = info->start[0] + info->size - info->start[i];
+                erased = 1;
+                flash = (volatile unsigned long *)info->start[i];
+                size = size >> 2;        /* divide by 4 for longword access */
+                for (k=0; k<size; k++)
+                  {
+                    if (*flash++ != 0xffffffff)
+                      {
+                        erased = 0;
+                        break;
+                      }
+                  }
+
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+                /* print empty and read-only info */
+               printf (" %08lX%s%s",
+                       info->start[i],
+                       erased ? " E" : "  ",
+                       info->protect[i] ? "RO " : "   ");
+#else
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+#endif
+
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       short n;
+       CFG_FLASH_WORD_SIZE value;
+       ulong base = (ulong)addr;
+        volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+       addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+       addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;
+
+       value = addr2[CFG_FLASH_READ0];
+
+       switch (value) {
+       case (CFG_FLASH_WORD_SIZE)AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (CFG_FLASH_WORD_SIZE)FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case (CFG_FLASH_WORD_SIZE)SST_MANUFACT:
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr2[CFG_FLASH_READ1];         /* device ID            */
+
+       switch (value) {
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 0.5 MB            */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 0.5 MB            */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322T:
+               info->flash_id += FLASH_AMDL322T;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322B:
+               info->flash_id += FLASH_AMDL322B;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323T:
+               info->flash_id += FLASH_AMDL323T;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323B:
+               info->flash_id += FLASH_AMDL323B;
+               info->sector_count = 71;
+               info->size = 0x00400000;  break;        /* => 4 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)AMD_ID_LV640U:
+               info->flash_id += FLASH_AM640U;
+               info->sector_count = 128;
+               info->size = 0x00800000;  break;        /* => 8 MB      */
+
+       case (CFG_FLASH_WORD_SIZE)SST_ID_xF800A:
+               info->flash_id += FLASH_SST800A;
+               info->sector_count = 16;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (CFG_FLASH_WORD_SIZE)SST_ID_xF160A:
+               info->flash_id += FLASH_SST160A;
+               info->sector_count = 32;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+        if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
+           for (i = 0; i < info->sector_count; i++)
+               info->start[i] = base + (i * 0x00010000);
+        } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
+               /* set sector offsets for bottom boot block type        */
+               for (i=0; i<8; ++i) {           /*  8 x 8k boot sectors */
+                       info->start[i] = base;
+                       base += 8 << 10;
+               }
+               while (i < info->sector_count) {        /* 64k regular sectors  */
+                       info->start[i] = base;
+                       base += 64 << 10;
+                       ++i;
+               }
+        } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+                  ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
+               /* set sector offsets for top boot block type           */
+               base += info->size;
+               i = info->sector_count;
+               for (n=0; n<8; ++n) {           /*  8 x 8k boot sectors */
+                       base -= 8 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+               while (i > 0) {                 /* 64k regular sectors  */
+                       base -= 64 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+        } else {
+           if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+           } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+           }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
+                if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
+                  info->protect[i] = 0;
+                else
+                  info->protect[i] = addr2[CFG_FLASH_READ2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr2 = (CFG_FLASH_WORD_SIZE *)info->start[0];
+               *addr2 = (CFG_FLASH_WORD_SIZE)0x00F000F0;       /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
+       volatile CFG_FLASH_WORD_SIZE *addr2;
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+        int i;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                   addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);
+                    if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+                        addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+                        addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+                        addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
+                        addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+                        addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+                        addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050;  /* block erase */
+                        for (i=0; i<50; i++)
+                          udelay(1000);  /* wait 1 ms */
+                    } else {
+                        if (sect == s_first) {
+                            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+                            addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+                            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
+                            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+                            addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+                        }
+                        addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030;  /* sector erase */
+                    }
+                   l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);
+       while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (CFG_FLASH_WORD_SIZE *)info->start[0];
+       addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0;      /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+        volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
+        volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;
+        volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;
+       ulong start;
+       int flag;
+        int i;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((volatile CFG_FLASH_WORD_SIZE *)dest) &
+             (CFG_FLASH_WORD_SIZE)data) != (CFG_FLASH_WORD_SIZE)data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+        for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)
+          {
+            addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+            addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+            addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;
+
+            dest2[i] = data2[i];
+
+            /* re-enable interrupts if necessary */
+            if (flag)
+              enable_interrupts();
+
+            /* data polling for D7 */
+            start = get_timer (0);
+            while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=
+                   (data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {
+              if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                return (1);
+              }
+            }
+          }
+
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/esd/cpci405/flash.c b/board/esd/cpci405/flash.c
new file mode 100644 (file)
index 0000000..70f7de4
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+       uint pbcr;
+       unsigned long base_b0, base_b1;
+       int size_val = 0;
+
+       /* Init: no FLASHes known */
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       base_b0 = FLASH_BASE0_PRELIM;
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                               size_b0, size_b0 << 20);
+       }
+
+       base_b1 = FLASH_BASE1_PRELIM;
+       size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+       /* Re-do sizing to get full correct info */
+
+       if (size_b1) {
+               mtdcr (ebccfga, pb0cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb0cr);
+               base_b1 = -size_b1;
+               switch (size_b1) {
+               case 1 << 20:
+                       size_val = 0;
+                       break;
+               case 2 << 20:
+                       size_val = 1;
+                       break;
+               case 4 << 20:
+                       size_val = 2;
+                       break;
+               case 8 << 20:
+                       size_val = 3;
+                       break;
+               case 16 << 20:
+                       size_val = 4;
+                       break;
+               default:
+                       size_val = 0;
+                       break;
+
+               }
+               pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*          printf("pb1cr = %x\n", pbcr); */
+       }
+
+       if (size_b0) {
+               mtdcr (ebccfga, pb1cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb1cr);
+               base_b0 = base_b1 - size_b0;
+               switch (size_b1) {
+               case 1 << 20:
+                       size_val = 0;
+                       break;
+               case 2 << 20:
+                       size_val = 1;
+                       break;
+               case 4 << 20:
+                       size_val = 2;
+                       break;
+               case 8 << 20:
+                       size_val = 3;
+                       break;
+               case 16 << 20:
+                       size_val = 4;
+                       break;
+               }
+               pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*            printf("pb0cr = %x\n", pbcr); */
+       }
+
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       flash_get_offsets (base_b0, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       flash_protect (FLAG_PROTECT_SET,
+                       base_b0 + size_b0 - CFG_MONITOR_LEN,
+                       base_b0 + size_b0 - 1, &flash_info[0]);
+
+       if (size_b1) {
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+               flash_get_offsets (base_b1, &flash_info[1]);
+
+               /* monitor protection ON by default */
+               flash_protect (FLAG_PROTECT_SET,
+                               base_b1 + size_b1 - CFG_MONITOR_LEN,
+                               base_b1 + size_b1 - 1, &flash_info[1]);
+               /* monitor protection OFF by default (one is enough) */
+               flash_protect (FLAG_PROTECT_CLEAR,
+                               base_b0 + size_b0 - CFG_MONITOR_LEN,
+                               base_b0 + size_b0 - 1, &flash_info[0]);
+       } else {
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
diff --git a/board/esd/dasa_sim/cmd_dasa_sim.c b/board/esd/dasa_sim/cmd_dasa_sim.c
new file mode 100644 (file)
index 0000000..4608da7
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <pci.h>
+
+#define OK 0
+#define ERROR (-1)
+
+#define TRUE 1
+#define FALSE 0
+
+
+extern u_long pci9054_iobase;
+
+
+/***************************************************************************
+ *
+ * Routines for PLX PCI9054 eeprom access
+ *
+ */
+
+static unsigned int PciEepromReadLongVPD(int offs)
+{
+  unsigned int value;
+  unsigned int ret;
+  int count;
+
+  pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x0003);
+  count = 0;
+
+  for (;;)
+    {
+      udelay(10 * 1000);
+      pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
+      if ((ret & 0x80000000) != 0)
+        {
+          break;
+        }
+      else
+        {
+          count++;
+          if (count > 10)
+            {
+              printf("\nTimeout: ret=%08x - Please try again!\n", ret);
+              break;
+            }
+        }
+    }
+
+  pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x50, &value);
+
+  return value;
+}
+
+
+static int PciEepromWriteLongVPD(int offs, unsigned int value)
+{
+  unsigned int ret;
+  int count;
+
+  pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x50, value);
+  pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x80000003);
+  count = 0;
+
+  for (;;)
+    {
+      udelay(10 * 1000);
+      pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
+      if ((ret & 0x80000000) == 0)
+        {
+          break;
+        }
+      else
+        {
+          count++;
+          if (count > 10)
+            {
+              printf("\nTimeout: ret=%08x - Please try again!\n", ret);
+              break;
+            }
+        }
+    }
+
+  return TRUE;
+}
+
+
+static void showPci9054(void)
+{
+  int val;
+  int l, i;
+
+  /* read 9054-values */
+  for (l=0; l<6; l++)
+    {
+      printf("%02x: ", l*0x10);
+      for (i=0; i<4; i++)
+        {
+         pci_read_config_dword(CFG_PCI9054_DEV_FN, l*16+i*4, &val);
+          printf("%08x ", val);
+        }
+      printf("\n");
+    }
+  printf("\n");
+
+  for (l=0; l<7; l++)
+    {
+      printf("%02x: ", l*0x10);
+      for (i=0; i<4; i++)
+        printf("%08x ", PciEepromReadLongVPD((i+l*4)*4));
+      printf("\n");
+    }
+  printf("\n");
+}
+
+
+static void updatePci9054(void)
+{
+  int val;
+
+  /*
+   * Set EEPROM write-protect register to 0
+   */
+  out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
+
+  /* Long Serial EEPROM Load Registers... */
+  val = PciEepromWriteLongVPD(0x00, 0x905410b5);
+  val = PciEepromWriteLongVPD(0x04, 0x09800001); /* other input controller */
+  val = PciEepromWriteLongVPD(0x08, 0x28140100);
+
+  val = PciEepromWriteLongVPD(0x0c, 0x00000000); /* MBOX0... */
+  val = PciEepromWriteLongVPD(0x10, 0x00000000);
+
+  /* las0: fpga access (0x0000.0000 ... 0x0003.ffff) */
+  val = PciEepromWriteLongVPD(0x14, 0xfffc0000); /* LAS0RR... */
+  val = PciEepromWriteLongVPD(0x18, 0x00000001); /* LAS0BA */
+
+  val = PciEepromWriteLongVPD(0x1c, 0x00200000); /* MARBR... */
+  val = PciEepromWriteLongVPD(0x20, 0x00300500); /* LMISC/BIGEND */
+
+  val = PciEepromWriteLongVPD(0x24, 0x00000000); /* EROMRR... */
+  val = PciEepromWriteLongVPD(0x28, 0x00000000); /* EROMBA */
+
+  val = PciEepromWriteLongVPD(0x2c, 0x43030000); /* LBRD0... */
+
+  val = PciEepromWriteLongVPD(0x30, 0x00000000); /* DMRR... */
+  val = PciEepromWriteLongVPD(0x34, 0x00000000);
+  val = PciEepromWriteLongVPD(0x38, 0x00000000);
+
+  val = PciEepromWriteLongVPD(0x3c, 0x00000000); /* DMPBAM... */
+  val = PciEepromWriteLongVPD(0x40, 0x00000000);
+
+  /* Extra Long Serial EEPROM Load Registers... */
+  val = PciEepromWriteLongVPD(0x44, 0x010212fe); /* PCISID... */
+
+  /* las1: 505-sram access (0x0004.0000 ... 0x001f.ffff) */
+  /* Offset to LAS1: Group 1: 0x00040000                 */
+  /*                 Group 2: 0x00080000                 */
+  /*                 Group 3: 0x000c0000                 */
+  val = PciEepromWriteLongVPD(0x48, 0xffe00000); /* LAS1RR */
+  val = PciEepromWriteLongVPD(0x4c, 0x00040001); /* LAS1BA */
+  val = PciEepromWriteLongVPD(0x50, 0x00000208); /* LBRD1 */ /* so wars bisher */
+
+  val = PciEepromWriteLongVPD(0x54, 0x00004c06); /* HotSwap... */
+
+  printf("Finished writing defaults into PLX PCI9054 EEPROM!\n");
+}
+
+
+static void clearPci9054(void)
+{
+  int val;
+
+  /*
+   * Set EEPROM write-protect register to 0
+   */
+  out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
+
+  /* Long Serial EEPROM Load Registers... */
+  val = PciEepromWriteLongVPD(0x00, 0xffffffff);
+  val = PciEepromWriteLongVPD(0x04, 0xffffffff); /* other input controller */
+
+  printf("Finished clearing PLX PCI9054 EEPROM!\n");
+}
+
+
+/* ------------------------------------------------------------------------- */
+int do_pci9054(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+  if (strcmp(argv[1], "info") == 0)
+    {
+      showPci9054();
+      return 0;
+    }
+
+  if (strcmp(argv[1], "update") == 0)
+    {
+      updatePci9054();
+      return 0;
+    }
+
+  if (strcmp(argv[1], "clear") == 0)
+    {
+      clearPci9054();
+      return 0;
+    }
+
+  printf("Usage:\n%s\n", cmdtp->usage);
+  return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/board/esd/dasa_sim/flash.c b/board/esd/dasa_sim/flash.c
new file mode 100644 (file)
index 0000000..2574eac
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0;
+        int i;
+        unsigned long base_b0;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+        /* Setup offsets */
+        flash_get_offsets (-size_b0, &flash_info[0]);
+
+        base_b0 = -size_b0;
+
+        /* Monitor protection ON by default */
+        (void)flash_protect(FLAG_PROTECT_SET,
+                            -CFG_MONITOR_LEN,
+                            0xffffffff,
+                            &flash_info[0]);
+
+        flash_info[0].size = size_b0;
+
+       return (size_b0);
+}
diff --git a/board/esd/du405/flash.c b/board/esd/du405/flash.c
new file mode 100644 (file)
index 0000000..97d8322
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+       uint pbcr;
+       unsigned long base_b0, base_b1;
+
+       /* Init: no FLASHes known */
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       base_b0 = FLASH_BASE0_PRELIM;
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0 << 20);
+       }
+
+       base_b1 = FLASH_BASE1_PRELIM;
+       size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+       /* Re-do sizing to get full correct info */
+
+       if (size_b1) {
+               mtdcr (ebccfga, pb0cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb0cr);
+               base_b1 = -size_b1;
+               pbcr = (pbcr & 0x0001ffff) | base_b1 |
+                               (((size_b1 / 1024 / 1024) - 1) << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*          printf("pb1cr = %x\n", pbcr); */
+       }
+
+       if (size_b0) {
+               mtdcr (ebccfga, pb1cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb1cr);
+               base_b0 = base_b1 - size_b0;
+               pbcr = (pbcr & 0x0001ffff) | base_b0 |
+                               (((size_b0 / 1024 / 1024) - 1) << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*            printf("pb0cr = %x\n", pbcr); */
+       }
+
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       flash_get_offsets (base_b0, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       flash_protect (FLAG_PROTECT_SET,
+                       base_b0 + size_b0 - CFG_MONITOR_LEN,
+                       base_b0 + size_b0 - 1, &flash_info[0]);
+
+       if (size_b1) {
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+               flash_get_offsets (base_b1, &flash_info[1]);
+
+               /* monitor protection ON by default */
+               flash_protect (FLAG_PROTECT_SET,
+                               base_b1 + size_b1 - CFG_MONITOR_LEN,
+                               base_b1 + size_b1 - 1, &flash_info[1]);
+               /* monitor protection OFF by default (one is enough) */
+               flash_protect (FLAG_PROTECT_CLEAR,
+                               base_b0 + size_b0 - CFG_MONITOR_LEN,
+                               base_b0 + size_b0 - 1, &flash_info[0]);
+       } else {
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
diff --git a/board/esd/ocrtc/flash.c b/board/esd/ocrtc/flash.c
new file mode 100644 (file)
index 0000000..90965ea
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+       uint pbcr;
+       unsigned long base_b0, base_b1;
+       int size_val = 0;
+
+       /* Init: no FLASHes known */
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       base_b0 = FLASH_BASE0_PRELIM;
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0 << 20);
+       }
+
+       base_b1 = FLASH_BASE1_PRELIM;
+       size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+       /* Re-do sizing to get full correct info */
+
+       if (size_b1) {
+               mtdcr (ebccfga, pb0cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb0cr);
+               base_b1 = -size_b1;
+               switch (size_b1) {
+               case 1 << 20:
+                       size_val = 0;
+                       break;
+               case 2 << 20:
+                       size_val = 1;
+                       break;
+               case 4 << 20:
+                       size_val = 2;
+                       break;
+               case 8 << 20:
+                       size_val = 3;
+                       break;
+               case 16 << 20:
+                       size_val = 4;
+                       break;
+               }
+               pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*          printf("pb1cr = %x\n", pbcr); */
+       }
+
+       if (size_b0) {
+               mtdcr (ebccfga, pb1cr);
+               pbcr = mfdcr (ebccfgd);
+               mtdcr (ebccfga, pb1cr);
+               base_b0 = base_b1 - size_b0;
+               switch (size_b1) {
+               case 1 << 20:
+                       size_val = 0;
+                       break;
+               case 2 << 20:
+                       size_val = 1;
+                       break;
+               case 4 << 20:
+                       size_val = 2;
+                       break;
+               case 8 << 20:
+                       size_val = 3;
+                       break;
+               case 16 << 20:
+                       size_val = 4;
+                       break;
+               }
+               pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+               mtdcr (ebccfgd, pbcr);
+               /*            printf("pb0cr = %x\n", pbcr); */
+       }
+
+       size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+       flash_get_offsets (base_b0, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       flash_protect (FLAG_PROTECT_SET,
+                       base_b0 + size_b0 - CFG_MONITOR_LEN,
+                       base_b0 + size_b0 - 1, &flash_info[0]);
+
+       if (size_b1) {
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+               flash_get_offsets (base_b1, &flash_info[1]);
+
+               /* monitor protection ON by default */
+               flash_protect (FLAG_PROTECT_SET,
+                               base_b1 + size_b1 - CFG_MONITOR_LEN,
+                               base_b1 + size_b1 - 1, &flash_info[1]);
+               /* monitor protection OFF by default (one is enough) */
+               flash_protect (FLAG_PROTECT_CLEAR,
+                               base_b0 + size_b0 - CFG_MONITOR_LEN,
+                               base_b0 + size_b0 - 1, &flash_info[0]);
+       } else {
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
diff --git a/board/esd/pci405/flash.c b/board/esd/pci405/flash.c
new file mode 100644 (file)
index 0000000..f904aff
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0;
+       int i;
+        uint pbcr;
+        unsigned long base_b0;
+       int size_val = 0;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+        /* Setup offsets */
+        flash_get_offsets (-size_b0, &flash_info[0]);
+
+        /* Re-do sizing to get full correct info */
+        mtdcr(ebccfga, pb0cr);
+        pbcr = mfdcr(ebccfgd);
+        mtdcr(ebccfga, pb0cr);
+        base_b0 = -size_b0;
+       switch (size_b0) {
+       case 1 << 20:
+               size_val = 0;
+               break;
+       case 2 << 20:
+               size_val = 1;
+               break;
+       case 4 << 20:
+               size_val = 2;
+               break;
+       case 8 << 20:
+               size_val = 3;
+               break;
+       case 16 << 20:
+               size_val = 4;
+               break;
+       }
+       pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+        mtdcr(ebccfgd, pbcr);
+
+        /* Monitor protection ON by default */
+        (void)flash_protect(FLAG_PROTECT_SET,
+                            -CFG_MONITOR_LEN,
+                            0xffffffff,
+                            &flash_info[0]);
+
+        flash_info[0].size = size_b0;
+
+       return (size_b0);
+}
diff --git a/board/esteem192e/flash.c b/board/esteem192e/flash.c
new file mode 100644 (file)
index 0000000..55845fa
--- /dev/null
@@ -0,0 +1,1096 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#ifdef CONFIG_FLASH_16BIT
+#define FLASH_WORD_SIZE        unsigned short
+#define        FLASH_ID_MASK   0xFFFF
+#else
+#define FLASH_WORD_SIZE unsigned long
+#define        FLASH_ID_MASK   0xFFFFFFFF
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info);
+#ifndef CONFIG_FLASH_16BIT
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+#else
+static int write_short (flash_info_t *info, ulong dest, ushort data);
+#endif
+/*int flash_write (uchar *, ulong, ulong); */
+/*flash_info_t *addr2info (ulong);   */
+
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE0_PRELIM,
+                                &flash_info[0]);
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE1_PRELIM,
+                                &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = CFG_FLASH_BASE | 0x00000801; /*  (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;*/
+
+       /* Re-do sizing to get full correct info */
+
+       size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)CFG_FLASH_BASE,
+                                &flash_info[0]);
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       (void)flash_protect(FLAG_PROTECT_SET,
+                           CFG_MONITOR_BASE,
+                           CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                           &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br1 = (CFG_FLASH_BASE | 0x00000801) + (size_b0 & BR_BA_MSK);
+                              /*((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V;*/
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               (void)flash_protect(FLAG_PROTECT_SET,
+                                   CFG_MONITOR_BASE,
+                                   CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                                   &flash_info[1]);
+#endif
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+             if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00008000;
+               info->start[3] = base + 0x0000C000;
+               info->start[4] = base + 0x00010000;
+               info->start[5] = base + 0x00014000;
+               info->start[6] = base + 0x00018000;
+               info->start[7] = base + 0x0001C000;
+               for (i = 8; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x000E0000;
+               }
+               }
+             else {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+              }
+#else
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00002000;
+               info->start[2] = base + 0x00004000;
+               info->start[3] = base + 0x00006000;
+               info->start[4] = base + 0x00008000;
+               info->start[5] = base + 0x0000A000;
+               info->start[6] = base + 0x0000C000;
+               info->start[7] = base + 0x0000E000;
+               for (i = 8; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00070000;
+               }
+              }
+             else {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+              }
+#endif
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+             if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               info->start[i--] = base + info->size - 0x00014000;
+               info->start[i--] = base + info->size - 0x00018000;
+               info->start[i--] = base + info->size - 0x0001C000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+
+               } else {
+
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+              }
+#else
+               info->start[i--] = base + info->size - 0x00002000;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000A000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x0000E000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+
+               } else {
+
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+              }
+#endif
+       }
+
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+       uchar *boottype;
+       uchar botboot[]=", bottom boot sect)\n";
+       uchar topboot[]=", top boot sector)\n";
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       if (info->flash_id & 0x0001 ) {
+       boottype = botboot;
+       } else {
+       boottype = topboot;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit%s",boottype);
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit%s",boottype);
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit%s",boottype);
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit%s",boottype);
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit%s",boottype);
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit%s",boottype);
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit%s",boottype);
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL800B:   printf ("INTEL28F800B (8 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL800T:   printf ("INTEL28F800T (8 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL160B:   printf ("INTEL28F160B (16 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL160T:   printf ("INTEL28F160T (16 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL320B:   printf ("INTEL28F320B (32 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL320T:   printf ("INTEL28F320T (32 Mbit%s",boottype);
+                               break;
+
+#if 0 /* enable when devices are available */
+
+       case FLASH_INTEL640B:   printf ("INTEL28F640B (64 Mbit%s",boottype);
+                               break;
+       case FLASH_INTEL640T:   printf ("INTEL28F640T (64 Mbit%s",boottype);
+                               break;
+#endif
+
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info)
+{
+       short i;
+       ulong base = (ulong)addr;
+       FLASH_WORD_SIZE value;
+
+       /* Write auto select command: read Manufacturer ID */
+
+
+#ifndef CONFIG_FLASH_16BIT
+
+       /*
+        * Note: if it is an AMD flash and the word at addr[0000]
+         * is 0x00890089 this routine will think it is an Intel
+         * flash device and may(most likely) cause trouble.
+        */
+
+       addr[0x0000] = 0x00900090;
+       if(addr[0x0000] != 0x00890089){
+               addr[0x0555] = 0x00AA00AA;
+               addr[0x02AA] = 0x00550055;
+               addr[0x0555] = 0x00900090;
+#else
+
+       /*
+        * Note: if it is an AMD flash and the word at addr[0000]
+         * is 0x0089 this routine will think it is an Intel
+         * flash device and may(most likely) cause trouble.
+        */
+
+       addr[0x0000] = 0x0090;
+
+       if(addr[0x0000] != 0x0089){
+               addr[0x0555] = 0x00AA;
+               addr[0x02AA] = 0x0055;
+               addr[0x0555] = 0x0090;
+#endif
+       }
+       value = addr[0];
+
+       switch (value) {
+       case (AMD_MANUFACT & FLASH_ID_MASK):
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (FUJ_MANUFACT & FLASH_ID_MASK):
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case (STM_MANUFACT & FLASH_ID_MASK):
+               info->flash_id = FLASH_MAN_STM;
+               break;
+       case (SST_MANUFACT & FLASH_ID_MASK):
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       case (INTEL_MANUFACT & FLASH_ID_MASK):
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+
+       case (AMD_ID_LV400T & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV400B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV800T & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (AMD_ID_LV800B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (AMD_ID_LV160T & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (AMD_ID_LV160B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case (AMD_ID_LV320T & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_LV320B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+
+       case (INTEL_ID_28F800B3T & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL800T;
+               info->sector_count = 23;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (INTEL_ID_28F800B3B & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL800B;
+               info->sector_count = 23;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (INTEL_ID_28F160B3T & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL160T;
+               info->sector_count = 39;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (INTEL_ID_28F160B3B & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL160B;
+               info->sector_count = 39;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL320T;
+               info->sector_count = 71;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 71;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+#if 0 /* enable when devices are available */
+       case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
+               info->flash_id += FLASH_INTEL320T;
+               info->sector_count = 135;
+               info->size = 0x01000000;
+               break;                          /* => 16 MB             */
+
+       case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 135;
+               info->size = 0x01000000;
+               break;                          /* => 16 MB             */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+             if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00008000;
+               info->start[3] = base + 0x0000C000;
+               info->start[4] = base + 0x00010000;
+               info->start[5] = base + 0x00014000;
+               info->start[6] = base + 0x00018000;
+               info->start[7] = base + 0x0001C000;
+               for (i = 8; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x000E0000;
+               }
+               }
+             else {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+              }
+#else
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00002000;
+               info->start[2] = base + 0x00004000;
+               info->start[3] = base + 0x00006000;
+               info->start[4] = base + 0x00008000;
+               info->start[5] = base + 0x0000A000;
+               info->start[6] = base + 0x0000C000;
+               info->start[7] = base + 0x0000E000;
+               for (i = 8; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00070000;
+               }
+              }
+             else {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+              }
+#endif
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+             if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               info->start[i--] = base + info->size - 0x00014000;
+               info->start[i--] = base + info->size - 0x00018000;
+               info->start[i--] = base + info->size - 0x0001C000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+
+               } else {
+
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+              }
+#else
+               info->start[i--] = base + info->size - 0x00002000;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000A000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x0000E000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+
+               } else {
+
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+              }
+#endif
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile FLASH_WORD_SIZE *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+               if( (info->flash_id & 0xFF00) == FLASH_MAN_INTEL){
+                  *addr = (0x00F000F0 & FLASH_ID_MASK);        /* reset bank */
+               } else {
+                  *addr = (0x00FF00FF & FLASH_ID_MASK);        /* reset bank */
+               }
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+
+       volatile FLASH_WORD_SIZE *addr=(volatile FLASH_WORD_SIZE*)(info->start[0]);
+       int flag, prot, sect, l_sect, barf;
+       ulong start, now, last;
+       int rcode = 0;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           ((info->flash_id > FLASH_AMD_COMP) &&
+             ( (info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL ) ) ){
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+    if(info->flash_id < FLASH_AMD_COMP) {
+#ifndef CONFIG_FLASH_16BIT
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+#else
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+       addr[0x0555] = 0x0080;
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+#endif
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (volatile FLASH_WORD_SIZE *)(info->start[sect]);
+                       addr[0] = (0x00300030 & FLASH_ID_MASK);
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (volatile FLASH_WORD_SIZE*)(info->start[l_sect]);
+       while ((addr[0] & (0x00800080&FLASH_ID_MASK)) !=
+                         (0x00800080&FLASH_ID_MASK)  )
+       {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       serial_putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+       addr[0] = (0x00F000F0 & FLASH_ID_MASK); /* reset bank */
+    } else {
+
+
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       barf = 0;
+#ifndef CONFIG_FLASH_16BIT
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00200020;
+                       addr[0] = 0x00D000D0;
+                       while(!(addr[0] & 0x00800080)); /* wait for error or finish */
+                       if( addr[0] & 0x003A003A) {     /* check for error */
+                               barf = addr[0] & 0x003A0000;
+                               if( barf ) {
+                                       barf >>=16;
+                               } else {
+                                       barf = addr[0] & 0x0000003A;
+                               }
+                       }
+#else
+                       addr = (vu_short*)(info->start[sect]);
+                       addr[0] = 0x0020;
+                       addr[0] = 0x00D0;
+                       while(!(addr[0] & 0x0080));     /* wait for error or finish */
+                       if( addr[0] & 0x003A)   /* check for error */
+                               barf = addr[0] & 0x003A;
+#endif
+                       if(barf) {
+                               printf("\nFlash error in sector at %lx\n",(unsigned long)addr);
+                               if(barf & 0x0002) printf("Block locked, not erased.\n");
+                               if((barf & 0x0030) == 0x0030)
+                                       printf("Command Sequence error.\n");
+                               if((barf & 0x0030) == 0x0020)
+                                       printf("Block Erase error.\n");
+                               if(barf & 0x0008) printf("Vpp Low error.\n");
+                               rcode = 1;
+                       } else printf(".");
+                       l_sect = sect;
+               }
+       addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+       addr[0] = (0x00FF00FF & FLASH_ID_MASK); /* reset bank */
+
+       }
+
+    }
+       printf (" done\n");
+       return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+#ifndef CONFIG_FLASH_16BIT
+       ulong cp, wp, data;
+       int l;
+#else
+       ulong cp, wp;
+       ushort data;
+#endif
+       int i, rc;
+
+#ifndef CONFIG_FLASH_16BIT
+
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+
+#else
+       wp = (addr & ~1);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start byte
+        */
+       if (addr - wp) {
+               data = 0;
+               data = (data << 8) | *src++;
+               --cnt;
+               if ((rc = write_short(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 2;
+       }
+
+       /*
+        * handle word aligned part
+        */
+/*     l = 0; used for debuging  */
+       while (cnt >= 2) {
+               data = 0;
+               for (i=0; i<2; ++i) {
+                       data = (data << 8) | *src++;
+               }
+
+/*             if(!l){
+                       printf("%x",data);
+                       l = 1;
+               }  used for debuging */
+
+               if ((rc = write_short(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 2;
+               cnt -= 2;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<2; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_short(info, wp, data));
+
+
+#endif
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+#ifndef CONFIG_FLASH_16BIT
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start,barf;
+       int flag;
+
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+     if(info->flash_id > FLASH_AMD_COMP) {
+       /* AMD stuff */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+     } else {
+       /* intel stuff */
+       *addr = 0x00400040;
+     }
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+
+     if(info->flash_id > FLASH_AMD_COMP) {
+
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+
+     } else {
+
+       while(!(addr[0] & 0x00800080)){         /* wait for error or finish */
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+       }
+
+       if( addr[0] & 0x003A003A) {     /* check for error */
+               barf = addr[0] & 0x003A0000;
+               if( barf ) {
+                       barf >>=16;
+               } else {
+                       barf = addr[0] & 0x0000003A;
+               }
+               printf("\nFlash write error at address %lx\n",(unsigned long)dest);
+               if(barf & 0x0002) printf("Block locked, not erased.\n");
+               if(barf & 0x0010) printf("Programming error.\n");
+               if(barf & 0x0008) printf("Vpp Low error.\n");
+               return(2);
+       }
+
+
+     }
+
+       return (0);
+
+}
+
+#else
+
+static int write_short (flash_info_t *info, ulong dest, ushort data)
+{
+       vu_short *addr = (vu_short*)(info->start[0]);
+       ulong start,barf;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_short *)dest) & data) != data) {
+               return (2);
+       }
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+     if(info->flash_id < FLASH_AMD_COMP) {
+       /* AMD stuff */
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+       addr[0x0555] = 0x00A0;
+     } else {
+       /* intel stuff */
+        *addr = 0x00D0;
+       *addr = 0x0040;
+     }
+       *((vu_short *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+
+     if(info->flash_id < FLASH_AMD_COMP) {
+          /* AMD stuff */
+       while ((*((vu_short *)dest) & 0x0080) != (data & 0x0080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+
+     } else {
+       /* intel stuff */
+       while(!(addr[0] & 0x0080)){     /* wait for error or finish */
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) return (1);
+       }
+
+       if( addr[0] & 0x003A) { /* check for error */
+               barf = addr[0] & 0x003A;
+               printf("\nFlash write error at address %lx\n",(unsigned long)dest);
+               if(barf & 0x0002) printf("Block locked, not erased.\n");
+               if(barf & 0x0010) printf("Programming error.\n");
+               if(barf & 0x0008) printf("Vpp Low error.\n");
+               return(2);
+       }
+       *addr = 0x00B0;
+       *addr = 0x0070;
+       while(!(addr[0] & 0x0080)){     /* wait for error or finish */
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) return (1);
+       }
+
+       *addr = 0x00FF;
+
+     }
+
+       return (0);
+
+}
+
+
+#endif
+
+/*-----------------------------------------------------------------------
+ */
+
diff --git a/board/etx094/flash.c b/board/etx094/flash.c
new file mode 100644 (file)
index 0000000..b3c620e
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+#ifdef CONFIG_FLASH_16BIT
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V | BR_PS_16; /* 16 Bit data port */
+#else
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+#endif
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+#ifdef CONFIG_FLASH_16BIT
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V | BR_PS_16;
+#else
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V;
+#endif
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+#endif
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00002000);
+               }
+               return;
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+#ifdef CONFIG_FLASH_16BIT
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+#else
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+#endif
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_SST200A:     printf ("39xF200A (2M = 128K x 16)\n");
+                               break;
+       case FLASH_SST400A:     printf ("39xF400A (4M = 256K x 16)\n");
+                               break;
+       case FLASH_SST800A:     printf ("39xF800A (8M = 512K x 16)\n");
+                               break;
+       case FLASH_STM800AB:    printf ("M29W800AB (8M = 512K x 16)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+#ifdef CONFIG_FLASH_16BIT
+       vu_short *s_addr = (vu_short*)addr;
+       s_addr[0x5555] = 0x00AA;
+       s_addr[0x2AAA] = 0x0055;
+       s_addr[0x5555] = 0x0090;
+       value = s_addr[0];
+       value = value|(value<<16);
+#else
+       addr[0x5555] = 0x00AA00AA;
+       addr[0x2AAA] = 0x00550055;
+       addr[0x5555] = 0x00900090;
+       value = addr[0];
+#endif
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case SST_MANUFACT:
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       case STM_MANUFACT:
+               info->flash_id = FLASH_MAN_STM;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+#ifdef CONFIG_FLASH_16BIT
+       value = s_addr[1];
+       value = value|(value<<16);
+#else
+       value = addr[1];                        /* device ID            */
+#endif
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+#ifdef CONFIG_FLASH_16BIT
+               info->sector_count = 19;
+               info->size = 0x00100000;        /* => 1 MB */
+#else
+               info->sector_count = 19;
+               info->size = 0x00200000;        /* => 2 MB      */
+#endif
+               break;
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+#ifdef CONFIG_FLASH_16BIT
+               info->sector_count = 35;
+               info->size = 0x00200000;        /* => 2 MB      */
+#else
+               info->sector_count = 35;
+               info->size = 0x00400000;        /* => 4 MB      */
+#endif
+
+               break;
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       case SST_ID_xF200A:
+               info->flash_id += FLASH_SST200A;
+               info->sector_count = 64;        /* 39xF200A ID ( 2M = 128K x 16 ) */
+               info->size = 0x00080000;
+               break;
+       case SST_ID_xF400A:
+               info->flash_id += FLASH_SST400A;
+               info->sector_count = 128;       /* 39xF400A ID ( 4M = 256K x 16 ) */
+               info->size = 0x00100000;
+               break;
+       case SST_ID_xF800A:
+               info->flash_id += FLASH_SST800A;
+               info->sector_count = 256;       /* 39xF800A ID ( 8M = 512K x 16 ) */
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+       case STM_ID_x800AB:
+               info->flash_id += FLASH_STM800AB;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00002000);
+               }
+       } else {        /* AMD and Fujitsu types */
+               /* set up sector start address table */
+               if (info->flash_id & FLASH_BTYPE) {
+                       /* set sector offsets for bottom boot block type        */
+#ifdef CONFIG_FLASH_16BIT
+
+                       info->start[0] = base + 0x00000000;
+                       info->start[1] = base + 0x00004000;
+                       info->start[2] = base + 0x00006000;
+                       info->start[3] = base + 0x00008000;
+                       for (i = 4; i < info->sector_count; i++) {
+                               info->start[i] = base + (i * 0x00010000) - 0x00030000;
+#else
+                       info->start[0] = base + 0x00000000;
+                       info->start[1] = base + 0x00008000;
+                       info->start[2] = base + 0x0000C000;
+                       info->start[3] = base + 0x00010000;
+                       for (i = 4; i < info->sector_count; i++) {
+                               info->start[i] = base + (i * 0x00020000) - 0x00060000;
+#endif
+                       }
+               } else {
+                       /* set sector offsets for top boot block type           */
+                       i = info->sector_count - 1;
+                       info->start[i--] = base + info->size - 0x00008000;
+                       info->start[i--] = base + info->size - 0x0000C000;
+                       info->start[i--] = base + info->size - 0x00010000;
+                       for (; i >= 0; i--) {
+                               info->start[i] = base + i * 0x00020000;
+                       }
+               }
+
+               /* check for protected sectors */
+               for (i = 0; i < info->sector_count; i++) {
+                       /* read sector protection at sector address:
+                        * (A7 .. A0) = 0x02
+                        * D0 = 1 if protected
+                        */
+#ifdef CONFIG_FLASH_16BIT
+                       s_addr = (volatile unsigned short *)(info->start[i]);
+                       info->protect[i] = s_addr[2] & 1;
+#else
+                       addr = (volatile unsigned long *)(info->start[i]);
+                       info->protect[i] = addr[2] & 1;
+#endif
+               }
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+#ifdef CONFIG_FLASH_16BIT
+               s_addr = (volatile unsigned short *)(info->start[0]);
+               *s_addr = 0x00F0;       /* reset bank */
+#else
+               addr = (volatile unsigned long *)info->start[0];
+               *addr = 0x00F000F0;     /* reset bank */
+#endif
+
+       }
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect;
+       ulong start, now, last;
+#ifdef CONFIG_FLASH_16BIT
+       vu_short *s_addr = (vu_short*)addr;
+#endif
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+/*#ifndef CONFIG_FLASH_16BIT
+       ulong type;
+       type = (info->flash_id & FLASH_VENDMASK);
+       if ((type != FLASH_MAN_SST) && (type != FLASH_MAN_STM)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return;
+       }
+#endif*/
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+#ifdef CONFIG_FLASH_16BIT
+                       vu_short *s_sect_addr = (vu_short*)(info->start[sect]);
+#else
+                       vu_long *sect_addr = (vu_long*)(info->start[sect]);
+#endif
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+#ifdef CONFIG_FLASH_16BIT
+
+                       /*printf("\ns_sect_addr=%x",s_sect_addr);*/
+                       s_addr[0x5555] = 0x00AA;
+                       s_addr[0x2AAA] = 0x0055;
+                       s_addr[0x5555] = 0x0080;
+                       s_addr[0x5555] = 0x00AA;
+                       s_addr[0x2AAA] = 0x0055;
+                       s_sect_addr[0] = 0x0030;
+#else
+                       addr[0x5555] = 0x00AA00AA;
+                       addr[0x2AAA] = 0x00550055;
+                       addr[0x5555] = 0x00800080;
+                       addr[0x5555] = 0x00AA00AA;
+                       addr[0x2AAA] = 0x00550055;
+                       sect_addr[0] = 0x00300030;
+#endif
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+#ifdef CONFIG_FLASH_16BIT
+                       while ((s_sect_addr[0] & 0x0080) != 0x0080) {
+#else
+                       while ((sect_addr[0] & 0x00800080) != 0x00800080) {
+#endif
+                               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       return 1;
+                               }
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+               }
+       }
+
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+#ifdef CONFIG_FLASH_16BIT
+       s_addr[0] = 0x00F0;     /* reset bank */
+#else
+       addr[0] = 0x00F000F0;   /* reset bank */
+#endif
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+
+#ifdef CONFIG_FLASH_16BIT
+       vu_short high_data;
+       vu_short low_data;
+       vu_short *s_addr = (vu_short*)addr;
+#endif
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+
+#ifdef CONFIG_FLASH_16BIT
+       /* Write the 16 higher-bits */
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       high_data = ((data>>16) & 0x0000ffff);
+
+       s_addr[0x5555] = 0x00AA;
+       s_addr[0x2AAA] = 0x0055;
+       s_addr[0x5555] = 0x00A0;
+
+       *((vu_short *)dest) = high_data;
+
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_short *)dest) & 0x0080) != (high_data & 0x0080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+
+
+       /* Write the 16 lower-bits */
+#endif
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+#ifdef CONFIG_FLASH_16BIT
+       dest += 0x2;
+       low_data = (data & 0x0000ffff);
+
+       s_addr[0x5555] = 0x00AA;
+       s_addr[0x2AAA] = 0x0055;
+       s_addr[0x5555] = 0x00A0;
+       *((vu_short *)dest) = low_data;
+
+#else
+       addr[0x5555] = 0x00AA00AA;
+       addr[0x2AAA] = 0x00550055;
+       addr[0x5555] = 0x00A000A0;
+       *((vu_long *)dest) = data;
+#endif
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+
+#ifdef CONFIG_FLASH_16BIT
+       while ((*((vu_short *)dest) & 0x0080) != (low_data & 0x0080)) {
+#else
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+#endif
+
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/evb64260/i2c.c b/board/evb64260/i2c.c
new file mode 100644 (file)
index 0000000..22cb809
--- /dev/null
@@ -0,0 +1,315 @@
+#include <common.h>
+#include <mpc8xx.h>
+#include <malloc.h>
+#include <galileo/gt64260R.h>
+#include <galileo/core.h>
+
+#define MAX_I2C_RETRYS     10
+#define I2C_DELAY          1000  /* Should be at least the # of MHz of Tclk */
+#undef DEBUG_I2C
+
+#ifdef DEBUG_I2C
+#define DP(x) x
+#else
+#define DP(x)
+#endif
+
+/* Assuming that there is only one master on the bus (us) */
+
+static void
+i2c_init(int speed, int slaveaddr)
+{
+       unsigned int n, m, freq, margin, power;
+       unsigned int actualFreq, actualN=0, actualM=0;
+       unsigned int control, status;
+       unsigned int minMargin = 0xffffffff;
+       unsigned int tclk = 125000000;
+
+       DP(puts("i2c_init\n"));
+
+       for(n = 0 ; n < 8 ; n++)
+       {
+               for(m = 0 ; m < 16 ; m++)
+               {
+                       power = 2<<n; /* power = 2^(n+1) */
+                       freq = tclk/(10*(m+1)*power);
+                       if (speed > freq)
+                               margin = speed - freq;
+                       else
+                               margin = freq - speed;
+                       if(margin < minMargin)
+                       {
+                               minMargin   = margin;
+                               actualFreq  = freq;
+                               actualN     = n;
+                               actualM     = m;
+                       }
+               }
+       }
+
+       DP(puts("setup i2c bus\n"));
+
+       /* Setup bus */
+
+       GT_REG_WRITE(I2C_SOFT_RESET, 0);
+
+       DP(puts("udelay...\n"));
+
+       udelay(I2C_DELAY);
+
+       DP(puts("set baudrate\n"));
+
+       GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN);
+       GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6));
+
+       udelay(I2C_DELAY * 10);
+
+       DP(puts("read control, baudrate\n"));
+
+       GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+       GT_REG_READ(I2C_CONTROL, &control);
+}
+
+static uchar
+i2c_start(void)
+{
+       unsigned int control, status;
+       int count = 0;
+
+       DP(puts("i2c_start\n"));
+
+       /* Set the start bit */
+
+       GT_REG_READ(I2C_CONTROL, &control);
+       control |= (0x1 << 5);
+       GT_REG_WRITE(I2C_CONTROL, control);
+
+       GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+
+       count = 0;
+       while ((status & 0xff) != 0x08) {
+               udelay(I2C_DELAY);
+               if (count > 20) {
+                       GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+                       return (status);
+               }
+               GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+               count++;
+       }
+
+       return (0);
+}
+
+static uchar
+i2c_select_device(uchar dev_addr, uchar read, int ten_bit)
+{
+       unsigned int status, data, bits = 7;
+       int count = 0;
+
+       DP(puts("i2c_select_device\n"));
+
+       /* Output slave address */
+
+       if (ten_bit) {
+               bits = 10;
+       }
+
+       data = (dev_addr << 1);
+       /* set the read bit */
+       data |= read;
+       GT_REG_WRITE(I2C_DATA, data);
+       /* assert the address */
+       RESET_REG_BITS(I2C_CONTROL, BIT3);
+
+       udelay(I2C_DELAY);
+
+       GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+       count = 0;
+       while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) {
+               udelay(I2C_DELAY);
+               if (count > 20) {
+                       GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+                       return(status);
+               }
+               GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+               count++;
+       }
+
+       if (bits == 10) {
+               printf("10 bit I2C addressing not yet implemented\n");
+               return (0xff);
+       }
+
+       return (0);
+}
+
+static uchar
+i2c_get_data(uchar* return_data, int len) {
+
+       unsigned int data, status;
+       int count = 0;
+
+       DP(puts("i2c_get_data\n"));
+
+       while (len) {
+
+               /* Get and return the data */
+
+               RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
+
+               udelay(I2C_DELAY * 5);
+
+               GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+               count++;
+               while ((status & 0xff) != 0x50) {
+                       udelay(I2C_DELAY);
+                       if(count > 2) {
+                               GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+                               return 0;
+                       }
+                       GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+                       count++;
+               }
+               GT_REG_READ(I2C_DATA, &data);
+               len--;
+               *return_data = (uchar)data;
+               return_data++;
+       }
+       RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3);
+       while ((status & 0xff) != 0x58) {
+               udelay(I2C_DELAY);
+               if(count > 200) {
+                       GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+                       return (status);
+               }
+               GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+               count++;
+       }
+       GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */
+
+       return (0);
+}
+
+static uchar
+i2c_write_data(unsigned int data, int len)
+{
+       unsigned int status;
+       int count = 0;
+
+       DP(puts("i2c_write_data\n"));
+
+       if (len > 4)
+               return -1;
+
+       while (len) {
+               /* Set and assert the data */
+
+               GT_REG_WRITE(I2C_DATA, (unsigned int)data);
+               RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
+
+               udelay(I2C_DELAY);
+
+               GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+               count++;
+               while ((status & 0xff) != 0x28) {
+                       udelay(I2C_DELAY);
+                       if(count > 20) {
+                               GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+                               return (status);
+                       }
+                       GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+                       count++;
+               }
+               len--;
+       }
+       GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4));
+       GT_REG_WRITE(I2C_CONTROL, (0x1 << 4));
+
+       udelay(I2C_DELAY * 10);
+
+       return (0);
+}
+
+static uchar
+i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit)
+{
+       uchar status;
+
+       DP(puts("i2c_set_dev_offset\n"));
+
+       status = i2c_select_device(dev_addr, 0, ten_bit);
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Failed to select device setting offset: 0x%02x\n",
+                      status);
+#endif
+               return status;
+       }
+
+       status = i2c_write_data(offset, 1);
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Failed to write data: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       return (0);
+}
+
+uchar
+i2c_read(uchar dev_addr, unsigned int offset, int len, uchar* data,
+        int ten_bit)
+{
+       uchar status = 0;
+       unsigned int i2cFreq = 400000;
+
+       DP(puts("i2c_read\n"));
+
+       i2c_init(i2cFreq,0);
+
+       status = i2c_start();
+
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Transaction start failed: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       status = i2c_set_dev_offset(dev_addr, 0, 0);
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Failed to set offset: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       i2c_init(i2cFreq,0);
+
+       status = i2c_start();
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Transaction restart failed: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       status = i2c_select_device(dev_addr, 1, ten_bit);
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Address not acknowledged: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       status = i2c_get_data(data, len);
+       if (status) {
+#ifdef DEBUG_I2C
+               printf("Data not recieved: 0x%02x\n", status);
+#endif
+               return status;
+       }
+
+       return 0;
+}
diff --git a/board/evb64260/intel_flash.c b/board/evb64260/intel_flash.c
new file mode 100644 (file)
index 0000000..ed6a2a0
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * (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
+ *
+ * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <galileo/gt64260R.h>
+#include <galileo/memory.h>
+#include "intel_flash.h"
+
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+static void
+bank_reset(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, eaddrw;
+
+       addrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+       while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+               printf("  writing reset cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = BANK_CMD_RST;
+               addrw++;
+       }
+}
+
+static void
+bank_erase_init(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, saddrw, eaddrw;
+       int flag;
+
+#ifdef FLASH_DEBUG
+       printf("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG);
+       printf("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
+       printf("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
+       printf("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
+       printf("0x%08x BANK_CMD_RST\n", BANK_CMD_RST);
+       printf("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY);
+       printf("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR);
+#endif
+
+       saddrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+       printf("erasing sector %d, start addr = 0x%08lx "
+               "(bank next word addr = 0x%08lx)\n", sect,
+               (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+       /* Disable intrs which might cause a timeout here */
+       flag = disable_interrupts();
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+               printf("  writing erase cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = BANK_CMD_ERASE1;
+               *addrw = BANK_CMD_ERASE2;
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+}
+
+static int
+bank_erase_poll(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, saddrw, eaddrw;
+       int sectdone, haderr;
+
+       saddrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+       sectdone = 1;
+       haderr = 0;
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+               bank_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+               printf("  checking status at addr "
+                       "0x%08x [0x%08x]\n",
+                       (unsigned long)addrw, stat);
+#endif
+               if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
+                       sectdone = 0;
+               else if ((stat & BANK_STAT_ERR) != 0) {
+                       printf(" failed on sector %d "
+                               "(stat = 0x%08x) at "
+                               "address 0x%p\n",
+                               sect, stat, addrw);
+                       *addrw = BANK_CMD_CLR_STAT;
+                       haderr = 1;
+               }
+       }
+
+       if (haderr)
+               return (-1);
+       else
+               return (sectdone);
+}
+
+int
+write_word_intel(bank_addr_t addr, bank_word_t value)
+{
+       bank_word_t stat;
+       ulong start;
+       int flag, retval;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = BANK_CMD_PROG;
+
+       *addr = value;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       retval = 0;
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       do {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       retval = 1;
+                       goto done;
+               }
+               stat = *addr;
+       } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
+
+       if ((stat & BANK_STAT_ERR) != 0) {
+               printf("flash program failed (stat = 0x%08lx) "
+                       "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+               *addr = BANK_CMD_CLR_STAT;
+               retval = 3;
+       }
+
+done:
+       /* reset to read mode */
+       *addr = BANK_CMD_RST;
+
+       return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int
+flash_erase_intel(flash_info_t *info, int s_first, int s_last)
+{
+       int prot, sect, haderr;
+       ulong start, now, last;
+
+#ifdef FLASH_DEBUG
+       printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+               "  Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+               (info - flash_info) + 1);
+       flash_print_info(info);
+#endif
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf("- Warning: %d protected sector%s will not be erased!\n",
+                       prot, (prot > 1 ? "s" : ""));
+       }
+
+       start = get_timer (0);
+       last = 0;
+       haderr = 0;
+
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       ulong estart;
+                       int sectdone;
+
+                       bank_erase_init(info, sect);
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       estart = get_timer(start);
+
+                       do {
+                               now = get_timer(start);
+
+                               if (now - estart > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout (sect %d)\n", sect);
+                                       haderr = 1;
+                                       break;
+                               }
+
+#ifndef FLASH_DEBUG
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) { /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+#endif
+
+                               sectdone = bank_erase_poll(info, sect);
+
+                               if (sectdone < 0) {
+                                       haderr = 1;
+                                       break;
+                               }
+
+                       } while (!sectdone);
+
+                       if (haderr)
+                               break;
+               }
+       }
+
+       if (haderr > 0)
+               printf (" failed\n");
+       else
+               printf (" done\n");
+
+       /* reset to read mode */
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       bank_reset(info, sect);
+               }
+       }
+       return haderr;
+}
diff --git a/board/fads/flash.c b/board/fads/flash.c
new file mode 100644 (file)
index 0000000..50b496e
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long total_size;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+       {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       total_size = 0;
+       size_b0 = 0xffffffff;
+
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+       {
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
+
+               if (flash_info[i].flash_id == FLASH_UNKNOWN)
+               {
+                       printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", i, size_b1, size_b1>>20);
+               }
+
+               /* Is this really needed ? - LP */
+               if (size_b1 > size_b0) {
+                       printf ("## ERROR: Bank %d (0x%08lx = %ld MB) > Bank %d (0x%08lx = %ld MB)\n",
+                               i, size_b1, size_b1>>20, i-1, size_b0, size_b0>>20);
+                       goto out_error;
+               }
+               size_b0 = size_b1;
+               total_size += size_b1;
+       }
+
+       /* Compute the Address Mask */
+       for (i=0; (total_size >> i) != 0; ++i) {};
+       i--;
+
+       if (total_size != (1 << i)) {
+               printf ("## WARNING: Total FLASH size (0x%08lx = %ld MB) is not a power of 2\n",
+                       total_size, total_size>>20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = ((((unsigned long)~1) << i) & OR_AM_MSK) | CFG_OR_TIMING_FLASH;
+       memctl->memc_br0 = CFG_BR0_PRELIM;
+
+       total_size = 0;
+
+       for (i=0; i < CFG_MAX_FLASH_BANKS && flash_info[i].size != 0; ++i)
+       {
+               /* Re-do sizing to get full correct info */
+               /* Why ? - LP */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
+
+               /* This is done by flash_get_size - LP */
+               /* flash_get_offsets (CFG_FLASH_BASE + total_size, &flash_info[i]); */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[i]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+                             &flash_info[i]);
+#endif
+
+               total_size += size_b1;
+       }
+
+       return (total_size);
+
+out_error:
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+       {
+               flash_info[i].flash_id          = FLASH_UNKNOWN;
+               flash_info[i].sector_count      = -1;
+               flash_info[i].size              = 0;
+       }
+
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+               /* set sector offsets for uniform sector type   */
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00040000);
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN)
+       {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK)
+       {
+               case FLASH_MAN_AMD:     printf ("AMD ");                break;
+               case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+               case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+               default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK)
+       {
+               case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+                       break;
+               case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                                       break;
+               default:                printf ("Unknown Chip Type\n");
+                                       break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+
+       for (i=0; i<info->sector_count; ++i)
+       {
+               if ((i % 5) == 0)
+               {
+                       printf ("\n   ");
+               }
+
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+       }
+
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+#if 0
+       ulong base = (ulong)addr;
+#endif
+       uchar value;
+
+       /* Write auto select command: read Manufacturer ID */
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x90909090;
+#endif
+
+       value = addr[0];
+
+       switch (value + (value << 16))
+       {
+               case AMD_MANUFACT:
+                       info->flash_id = FLASH_MAN_AMD;
+                       break;
+
+               case FUJ_MANUFACT:
+                       info->flash_id = FLASH_MAN_FUJ;
+                       break;
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       info->sector_count = 0;
+                       info->size = 0;
+                       break;
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value)
+       {
+               case AMD_ID_F040B:
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV400T:
+                       info->flash_id += FLASH_AM400T;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV400B:
+                       info->flash_id += FLASH_AM400B;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV800T:
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV800B:
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV160T:
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+
+               case AMD_ID_LV160B:
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+               case AMD_ID_LV320T:
+                       info->flash_id += FLASH_AM320T;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+
+               case AMD_ID_LV320B:
+                       info->flash_id += FLASH_AM320B;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+#endif
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       return (0);                     /* => no or unknown flash */
+
+       }
+
+#if 0
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+#else
+       flash_get_offsets ((ulong)addr, info);
+#endif
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++)
+       {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN)
+       {
+               addr = (volatile unsigned long *)info->start[0];
+#if 0
+               *addr = 0x00F000F0;     /* reset bank */
+#else
+               *addr = 0xF0F0F0F0;     /* reset bank */
+#endif
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x80808080;
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+#endif
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+#if 0
+                       addr[0] = 0x00300030;
+#else
+                       addr[0] = 0x30303030;
+#endif
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+#if 0
+       while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+       while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+       {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+#if 0
+       addr[0] = 0x00F000F0;   /* reset bank */
+#else
+       addr[0] = 0xF0F0F0F0;   /* reset bank */
+#endif
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+#if 0
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+       while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+       {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/fads/lamp.c b/board/fads/lamp.c
new file mode 100644 (file)
index 0000000..b121477
--- /dev/null
@@ -0,0 +1,42 @@
+#include <config.h>
+#include <common.h>
+
+void
+signal_delay(unsigned int n)
+{
+  while (n--);
+}
+
+void
+signal_on(void)
+{
+  *((volatile uint *)BCSR4) &= ~(1<<(31-3)); /* led on */
+}
+
+void
+signal_off(void)
+{
+  *((volatile uint *)BCSR4) |= (1<<(31-3)); /* led off */
+}
+
+void
+slow_blink(unsigned int n)
+{
+  while (n--) {
+    signal_on();
+    signal_delay(0x00400000);
+    signal_off();
+    signal_delay(0x00400000);
+  }
+}
+
+void
+fast_blink(unsigned int n)
+{
+  while (n--) {
+    signal_on();
+    signal_delay(0x00100000);
+    signal_off();
+    signal_delay(0x00100000);
+  }
+}
diff --git a/board/genietv/flash.c b/board/genietv/flash.c
new file mode 100644 (file)
index 0000000..2314a53
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+           flash_info[i].flash_id = FLASH_UNKNOWN;
+
+       /* Detect size */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       /* Setup offsets */
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* Monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+       size_b1 = 0 ;
+
+       flash_info[1].flash_id = FLASH_UNKNOWN;
+       flash_info[1].sector_count = -1;
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ * Fix this to support variable sector sizes
+*/
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+               /* set sector offsets for bottom boot block type        */
+               for (i = 0; i < info->sector_count; i++)
+                       info->start[i] = base + (i * 0x00010000);
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN)
+       {
+               puts ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK)
+       {
+               case FLASH_MAN_AMD:     printf ("AMD ");                break;
+               case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+               case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+               default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK)
+       {
+               case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+                       break;
+               case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                                       break;
+               case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                                       break;
+               case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                                       break;
+               default:                printf ("Unknown Chip Type\n");
+                                       break;
+       }
+
+       if (info->size >> 20) {
+           printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20,
+               info->sector_count);
+       } else {
+           printf ("  Size: %ld KB in %d Sectors\n",
+               info->size >> 10,
+               info->sector_count);
+       }
+
+       puts ("  Sector Start Addresses:");
+
+       for (i=0; i<info->sector_count; ++i)
+       {
+               if ((i % 5) == 0)
+               {
+                       puts ("\n   ");
+               }
+
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+       }
+
+       putc ('\n');
+       return;
+}
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       volatile unsigned char *caddr;
+       char value;
+
+       caddr = (volatile unsigned char *)addr ;
+
+       /* Write auto select command: read Manufacturer ID */
+
+#if 0
+       printf("Base address is: %08x\n", caddr);
+#endif
+
+       caddr[0x0555] = 0xAA;
+       caddr[0x02AA] = 0x55;
+       caddr[0x0555] = 0x90;
+
+       value = caddr[0];
+
+#if 0
+       printf("Manufact ID: %02x\n", value);
+#endif
+       switch (value)
+       {
+               case 0x01:
+               case AMD_MANUFACT:
+                       info->flash_id = FLASH_MAN_AMD;
+               break;
+
+               case FUJ_MANUFACT:
+                       info->flash_id = FLASH_MAN_FUJ;
+               break;
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       info->sector_count = 0;
+                       info->size = 0;
+                       break;
+       }
+
+       value = caddr[1];                       /* device ID            */
+#if 0
+       printf("Device ID: %02x\n", value);
+#endif
+       switch (value)
+       {
+               case AMD_ID_LV040B:
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00080000;
+                       break;                          /* => 512Kb             */
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       return (0);                     /* => no or unknown flash */
+
+       }
+
+       flash_get_offsets ((ulong)addr, &flash_info[0]);
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++)
+       {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               caddr = (volatile unsigned char *)(info->start[i]);
+               info->protect[i] = caddr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN)
+       {
+               caddr = (volatile unsigned char *)info->start[0];
+               *caddr = 0xF0;  /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       volatile unsigned char *addr = (volatile unsigned char *)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0xAA;
+       addr[0x02AA] = 0x55;
+       addr[0x0555] = 0x80;
+       addr[0x0555] = 0xAA;
+       addr[0x02AA] = 0x55;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (volatile unsigned char *)(info->start[sect]);
+                       addr[0] = 0x30;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (volatile unsigned char *)(info->start[l_sect]);
+
+       while ((addr[0] & 0xFF) != 0xFF)
+       {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned char *)info->start[0];
+
+       addr[0] = 0xF0; /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       volatile unsigned char *addr = (volatile unsigned char*)(info->start[0]),
+                               *cdest,*cdata;
+       ulong start;
+       int flag, count = 4 ;
+
+       cdest = (volatile unsigned char *)dest ;
+       cdata = (volatile unsigned char *)&data ;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+
+       while(count--)
+       {
+           /* Disable interrupts which might cause a timeout here */
+           flag = disable_interrupts();
+
+           addr[0x0555] = 0xAA;
+           addr[0x02AA] = 0x55;
+           addr[0x0555] = 0xA0;
+
+           *cdest = *cdata;
+
+           /* re-enable interrupts if necessary */
+           if (flag)
+               enable_interrupts();
+
+           /* data polling for D7 */
+           start = get_timer (0);
+           while ((*cdest ^ *cdata) & 0x80)
+           {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+           }
+
+           cdata++ ;
+           cdest++ ;
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/gth/ee_access.c b/board/gth/ee_access.c
new file mode 100644 (file)
index 0000000..716c90e
--- /dev/null
@@ -0,0 +1,335 @@
+/* Module for handling DALLAS DS2438, smart battery monitor
+   Chip can store up to 40 bytes of user data in EEPROM,
+   perform temp, voltage and current measurements.
+   Chip also contains a unique serial number.
+
+   Always read/write LSb first
+
+   For documentaion, see data sheet for DS2438, 2438.pdf
+
+   By Thomas.Lange@corelatus.com 001025 */
+
+#include <common.h>
+#include <config.h>
+#include <mpc8xx.h>
+
+#include <../board/gth/ee_dev.h>
+
+/* We dont have kernel functions */
+#define printk printf
+#define KERN_DEBUG
+#define KERN_ERR
+#define EIO 1
+
+static int Debug = 0;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * lookup table ripped from DS app note 17, understanding and using
+ * cyclic redundancy checks...
+ */
+
+static u8 crc_lookup[256] = {
+       0,      94,     188,    226,    97,     63,     221,    131,
+       194,    156,    126,    32,     163,    253,    31,     65,
+       157,    195,    33,     127,    252,    162,    64,     30,
+       95,     1,      227,    189,    62,     96,     130,    220,
+       35,     125,    159,    193,    66,     28,     254,    160,
+       225,    191,    93,     3,      128,    222,    60,     98,
+       190,    224,    2,      92,     223,    129,    99,     61,
+       124,    34,     192,    158,    29,     67,     161,    255,
+       70,     24,     250,    164,    39,     121,    155,    197,
+       132,    218,    56,     102,    229,    187,    89,     7,
+       219,    133,    103,    57,     186,    228,    6,      88,
+       25,     71,     165,    251,    120,    38,     196,    154,
+       101,    59,     217,    135,    4,      90,     184,    230,
+       167,    249,    27,     69,     198,    152,    122,    36,
+       248,    166,    68,     26,     153,    199,    37,     123,
+       58,     100,    134,    216,    91,     5,      231,    185,
+       140,    210,    48,     110,    237,    179,    81,     15,
+       78,     16,     242,    172,    47,     113,    147,    205,
+       17,     79,     173,    243,    112,    46,     204,    146,
+       211,    141,    111,    49,     178,    236,    14,     80,
+       175,    241,    19,     77,     206,    144,    114,    44,
+       109,    51,     209,    143,    12,     82,     176,    238,
+       50,     108,    142,    208,    83,     13,     239,    177,
+       240,    174,    76,     18,     145,    207,    45,     115,
+       202,    148,    118,    40,     171,    245,    23,     73,
+       8,      86,     180,    234,    105,    55,     213,    139,
+       87,     9,      235,    181,    54,     104,    138,    212,
+       149,    203,    41,     119,    244,    170,    72,     22,
+       233,    183,    85,     11,     136,    214,    52,     106,
+       43,     117,    151,    201,    74,     20,     246,    168,
+       116,    42,     200,    150,    21,     75,     169,    247,
+       182,    232,    10,     84,     215,    137,    107,    53
+};
+
+static u8 make_new_crc( u8 Old_crc, u8 New_value ){
+  /* Compute a new checksum with new byte, using previous checksum as input
+     See DS app note 17, understanding and using cyclic redundancy checks...
+     Also see DS2438, page 11 */
+  return( crc_lookup[Old_crc ^ New_value ]);
+}
+
+int ee_crc_ok( u8 *Buffer, int Len, u8 Crc ){
+  /* Check if the checksum for this buffer is correct */
+  u8 Curr_crc=0;
+  int i;
+  u8 *Curr_byte = Buffer;
+
+  for(i=0;i<Len;i++){
+    Curr_crc = make_new_crc( Curr_crc, *Curr_byte);
+    Curr_byte++;
+  }
+  E_DEBUG("Calculated CRC = 0x%x, read = 0x%x\n", Curr_crc, Crc);
+
+  if(Curr_crc == Crc){
+    /* Good */
+    return(TRUE);
+  }
+  printk(KERN_ERR"EE checksum error, Calculated CRC = 0x%x, read = 0x%x\n",
+       Curr_crc, Crc);
+  return(FALSE);
+}
+
+static void
+set_idle(void){
+  /* Send idle and keep start time
+     Continous 1 is idle */
+  WRITE_PORT(1);
+}
+
+static int
+do_reset(void){
+  /* Release reset and verify that chip responds with presence pulse */
+  int Retries = 0;
+  while(Retries<5){
+    udelay(RESET_LOW_TIME);
+
+    /* Send reset */
+    WRITE_PORT(0);
+    udelay(RESET_LOW_TIME);
+
+    /* Release reset */
+    WRITE_PORT(1);
+
+    /* Wait for EEPROM to drive output */
+    udelay(PRESENCE_TIMEOUT);
+    if(!READ_PORT){
+      /* Ok, EEPROM is driving a 0 */
+      E_DEBUG("Presence detected\n");
+      if(Retries){
+       E_DEBUG("Retries %d\n",Retries);
+      }
+      /* Make sure chip releases pin */
+      udelay(PRESENCE_LOW_TIME);
+      return 0;
+    }
+    Retries++;
+  }
+
+  printk(KERN_ERR"EEPROM did not respond when releasing reset\n");
+
+    /* Make sure chip releases pin */
+  udelay(PRESENCE_LOW_TIME);
+
+  /* Set to idle again */
+  set_idle();
+
+  return(-EIO);
+}
+
+static u8
+read_byte(void){
+  /* Read a single byte from EEPROM
+     Read LSb first */
+  int i;
+  int Value;
+  u8 Result=0;
+#ifndef CFG_IMMR
+  u32 Flags;
+#endif
+
+  E_DEBUG("Reading byte\n");
+
+  for(i=0;i<8;i++){
+    /* Small delay between pulses */
+    udelay(1);
+
+#ifndef CFG_IMMR
+    /* Disable irq */
+    save_flags(Flags);
+    cli();
+#endif
+
+    /* Pull down pin short time to start read
+       See page 26 in data sheet */
+
+    WRITE_PORT(0);
+    udelay(READ_LOW);
+    WRITE_PORT(1);
+
+    /* Wait for chip to drive pin */
+    udelay(READ_TIMEOUT);
+
+    Value = READ_PORT;
+    if(Value)
+      Value=1;
+
+#ifndef CFG_IMMR
+    /* Enable irq */
+    restore_flags(Flags);
+#endif
+
+    /* Wait for chip to release pin */
+    udelay(TOTAL_READ_LOW-READ_TIMEOUT);
+
+    /* LSb first */
+    Result|=Value<<i;
+  }
+
+  E_DEBUG("Read byte 0x%x\n",Result);
+
+  return(Result);
+}
+
+static void
+write_byte(u8 Byte){
+  /* Write a single byte to EEPROM
+     Write LSb first */
+  int i;
+  int Value;
+#ifndef CFG_IMMR
+  u32 Flags;
+#endif
+
+  E_DEBUG("Writing byte 0x%x\n",Byte);
+
+  for(i=0;i<8;i++){
+    /* Small delay between pulses */
+    udelay(1);
+    Value = Byte&1;
+
+#ifndef CFG_IMMR
+    /* Disable irq */
+    save_flags(Flags);
+    cli();
+#endif
+
+    /* Pull down pin short time for a 1, long time for a 0
+       See page 26 in data sheet */
+
+    WRITE_PORT(0);
+    if(Value){
+      /* Write a 1 */
+      udelay(WRITE_1_LOW);
+    }
+    else{
+      /* Write a 0 */
+      udelay(WRITE_0_LOW);
+    }
+
+    WRITE_PORT(1);
+
+#ifndef CFG_IMMR
+    /* Enable irq */
+    restore_flags(Flags);
+#endif
+
+    if(Value)
+      /* Wait for chip to read the 1 */
+      udelay(TOTAL_WRITE_LOW-WRITE_1_LOW);
+    Byte>>=1;
+  }
+}
+
+int ee_do_command( u8 *Tx, int Tx_len, u8 *Rx, int Rx_len, int Send_skip ){
+  /* Execute this command string, including
+     giving reset and setting to idle after command
+     if Rx_len is set, we read out data from EEPROM */
+  int i;
+
+  E_DEBUG("Command, Tx_len %d, Rx_len %d\n", Tx_len, Rx_len );
+
+  if(do_reset()){
+    /* Failed! */
+    return(-EIO);
+  }
+
+  if(Send_skip)
+    /* Always send SKIP_ROM first to tell chip we are sending a command,
+       except when we read out rom data for chip */
+    write_byte(SKIP_ROM);
+
+  /* Always have Tx data */
+  for(i=0;i<Tx_len;i++){
+    write_byte(Tx[i]);
+  }
+
+  if(Rx_len){
+    for(i=0;i<Rx_len;i++){
+      Rx[i]=read_byte();
+    }
+  }
+
+  set_idle();
+
+  E_DEBUG("Command done\n");
+
+  return(0);
+}
+
+int ee_init_data(void){
+  int i;
+  u8 Tx[10];
+  int tmp;
+  volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+  while(0){
+    tmp = 1-tmp;
+    if(tmp)
+      immap->im_ioport.iop_padat &= ~PA_FRONT_LED;
+    else
+      immap->im_ioport.iop_padat |= PA_FRONT_LED;
+    udelay(1);
+  }
+
+  /* Set port to open drain to be able to read data from
+     port without setting it to input */
+  PORT_B_PAR &= ~PB_EEPROM;
+  PORT_B_ODR |= PB_EEPROM;
+  SET_PORT_B_OUTPUT(PB_EEPROM);
+
+  /* Set idle mode */
+  set_idle();
+
+  /* Copy all User EEPROM data to scratchpad */
+  for(i=0;i<USER_PAGES;i++){
+    Tx[0]=RECALL_MEMORY;
+    Tx[1]=EE_USER_PAGE_0+i;
+    if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
+  }
+
+  /* Make sure chip doesnt store measurements in NVRAM */
+  Tx[0]=WRITE_SCRATCHPAD;
+  Tx[1]=0; /* Page */
+  Tx[2]=9;
+  if(ee_do_command(Tx,3,NULL,0,TRUE)) return(-EIO);
+
+  Tx[0]=COPY_SCRATCHPAD;
+  if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
+
+  /* FIXME check status bit instead
+     Could take 10 ms to store in EEPROM */
+  for(i=0;i<10;i++){
+    udelay(1000);
+  }
+
+  return(0);
+}
diff --git a/board/gth/flash.c b/board/gth/flash.c
new file mode 100644 (file)
index 0000000..562a349
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /*printf("faking");*/
+
+       return(0x1fffff);
+
+       /* Init: no FLASHes known */
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+       {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN)
+       {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+#if 0
+       if (FLASH_BASE1_PRELIM != 0x0) {
+         size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+         if (size_b1 > size_b0) {
+           printf ("## ERROR: Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+               size_b1, size_b1<<20,size_b0, size_b0<<20);
+
+           flash_info[0].flash_id      = FLASH_UNKNOWN;
+           flash_info[1].flash_id      = FLASH_UNKNOWN;
+           flash_info[0].sector_count  = -1;
+           flash_info[1].sector_count  = -1;
+           flash_info[0].size          = 0;
+           flash_info[1].size          = 0;
+           return (0);
+         }
+       } else {
+#endif
+         size_b1 = 0;
+
+         /* Remap FLASH according to real size */
+         memctl->memc_or0 = CFG_OR0_PRELIM;
+         memctl->memc_br0 = CFG_BR0_PRELIM;
+
+         /* Re-do sizing to get full correct info */
+         size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+         flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+         /* monitor protection ON by default */
+         (void)flash_protect(FLAG_PROTECT_SET,
+                           CFG_MONITOR_BASE,
+                           CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                           &flash_info[0]);
+#endif
+
+       if (size_b1)
+       {
+         /* memctl->memc_or1 = CFG_OR1_PRELIM;
+            memctl->memc_br1 = CFG_BR1_PRELIM; */
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                        &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               (void)flash_protect(FLAG_PROTECT_SET,
+                                   CFG_MONITOR_BASE,
+                                   CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                                   &flash_info[1]);
+#endif
+       }
+       else
+       {
+/*         memctl->memc_or1 = CFG_OR1_PRELIM;
+ FIXME     memctl->memc_br1 = CFG_BR1_PRELIM;  */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE)
+       {
+               /* set sector offsets for bottom boot block type        */
+               for (i = 0; i < info->sector_count; i++)
+               {
+                       info->start[i] = base + (i * 0x00040000);
+               }
+       }
+       else
+       {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               for (; i >= 0; i--)
+               {
+                       info->start[i] = base + i * 0x00040000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+
+#if 0
+       case FLASH_AM040B:
+               printf ("AM29F040B (4 Mbit, bottom boot sect)\n");
+               break;
+       case FLASH_AM040T:
+               printf ("AM29F040T (4 Mbit, top boot sect)\n");
+               break;
+#endif
+       case FLASH_AM400B:
+               printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+               break;
+       case FLASH_AM400T:
+               printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+               break;
+       case FLASH_AM800B:
+               printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+               break;
+       case FLASH_AM800T:
+               printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+               break;
+       case FLASH_AM160B:
+               printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+               break;
+       case FLASH_AM160T:
+               printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+               break;
+       case FLASH_AM320B:
+               printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+               break;
+       case FLASH_AM320T:
+               printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+               break;
+       default:
+               printf ("Unknown Chip Type\n");
+               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20,
+               info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+
+       for (i=0; i<info->sector_count; ++i)
+       {
+               if ((i % 5) == 0)
+               {
+                       printf ("\n   ");
+               }
+
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+       }
+
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+#if 0
+       ulong base = (ulong)addr;
+#endif
+       uchar value;
+
+       /* Write auto select command: read Manufacturer ID */
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x90909090;
+#endif
+
+       value = addr[0];
+
+       switch (value)
+       {
+               case AMD_MANUFACT:case 0x01:
+                       info->flash_id = FLASH_MAN_AMD;
+               break;
+
+               case FUJ_MANUFACT:
+                       info->flash_id = FLASH_MAN_FUJ;
+               break;
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       info->sector_count = 0;
+                       info->size = 0;
+                       break;
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value)
+       {
+#if 0
+               case AMD_ID_F040B:
+                       info->flash_id += FLASH_AM040B;
+                       info->sector_count = 8;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+#endif
+               case AMD_ID_LV400T:
+                       info->flash_id += FLASH_AM400T;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV400B:
+                       info->flash_id += FLASH_AM400B;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                          /* => 1 MB              */
+
+               case AMD_ID_LV800T:
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV800B:
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                          /* => 2 MB              */
+
+               case AMD_ID_LV160T:
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+
+               case AMD_ID_LV160B:
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+               case AMD_ID_LV320T:
+                       info->flash_id += FLASH_AM320T;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+
+               case AMD_ID_LV320B:
+                       info->flash_id += FLASH_AM320B;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                          /* => 8 MB              */
+#endif
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       return (0);                     /* => no or unknown flash */
+
+       }
+
+#if 0
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+#else
+       flash_get_offsets ((ulong)addr, &flash_info[0]);
+#endif
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++)
+       {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN)
+       {
+               addr = (volatile unsigned long *)info->start[0];
+#if 0
+               *addr = 0x00F000F0;     /* reset bank */
+#else
+               *addr = 0xF0F0F0F0;     /* reset bank */
+#endif
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x80808080;
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+#endif
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+#if 0
+                       addr[0] = 0x00300030;
+#else
+                       addr[0] = 0x30303030;
+#endif
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+#if 0
+       while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+       while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+       {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+#if 0
+       addr[0] = 0x00F000F0;   /* reset bank */
+#else
+       addr[0] = 0xF0F0F0F0;   /* reset bank */
+#endif
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+#if 0
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+       while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+       {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/hermes/flash.c b/board/hermes/flash.c
new file mode 100644 (file)
index 0000000..bb7635e
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_byte (flash_info_t *info, ulong dest, uchar data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size, size<<20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) |
+                               (memctl->memc_br0 & ~(BR_BA_MSK));
+
+       /* Re-do sizing to get full correct info */
+       size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+       flash_info[0].size = size;
+
+       return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       uchar value;
+       vu_char *caddr = (vu_char *)addr;
+       ulong base = (ulong)addr;
+
+
+       /* Write auto select command: read Manufacturer ID */
+       caddr[0x0AAA] = 0xAA;
+       caddr[0x0555] = 0x55;
+       caddr[0x0AAA] = 0x90;
+
+       value = caddr[0];
+       switch (value) {
+       case (AMD_MANUFACT & 0xFF):
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (FUJ_MANUFACT & 0xFF):
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = caddr[2];                       /* device ID            */
+
+       switch (value) {
+       case (AMD_ID_LV400T & 0xFF):
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 512 kB            */
+
+       case (AMD_ID_LV400B & 0xFF):
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 512 kB            */
+
+       case (AMD_ID_LV800T & 0xFF):
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV800B & 0xFF):
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV160T & 0xFF):
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (AMD_ID_LV160B & 0xFF):
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+#if 0  /* enable when device IDs are available */
+       case (AMD_ID_LV320T & 0xFF):
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (AMD_ID_LV320B & 0xFF):
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection: D0 = 1 if protected */
+               caddr = (volatile unsigned char *)(info->start[i]);
+               info->protect[i] = caddr[4] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               caddr = (vu_char *)info->start[0];
+
+               *caddr = 0xF0;  /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_char *addr = (vu_char*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0AAA] = 0xAA;
+       addr[0x0555] = 0x55;
+       addr[0x0AAA] = 0x80;
+       addr[0x0AAA] = 0xAA;
+       addr[0x0555] = 0x55;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_char*)(info->start[sect]);
+                       addr[0] = 0x30;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_char*)(info->start[l_sect]);
+       while ((addr[0] & 0x80) != 0x80) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (vu_char *)info->start[0];
+       addr[0] = 0xF0; /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       int rc;
+
+       while (cnt > 0) {
+               if ((rc = write_byte(info, addr++, *src++)) != 0) {
+                       return (rc);
+               }
+               --cnt;
+       }
+
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_byte (flash_info_t *info, ulong dest, uchar data)
+{
+       vu_char *addr = (vu_char*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_char *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0AAA] = 0xAA;
+       addr[0x0555] = 0x55;
+       addr[0x0AAA] = 0xA0;
+
+       *((vu_char *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/hymod/eeprom.c b/board/hymod/eeprom.c
new file mode 100644 (file)
index 0000000..9d50646
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * (C) Copyright 2001
+ * Murray Jensen, CSIRO Manufacturing Science and Technology,
+ * <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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 <mpc8260.h>
+
+/* imports from fetch.c */
+extern int fetch_and_parse(bd_t *, char *, ulong, int (*)(uchar *, uchar *));
+
+int
+eeprom_load(unsigned offset, hymod_eeprom_t *ep)
+{
+    uchar data[HYMOD_EEPROM_SIZE], *dp, *edp;
+    hymod_eehdr_t *hp;
+    ulong len, crc;
+
+    memset(ep, 0, sizeof *ep);
+    memset(data, 0, HYMOD_EEPROM_SIZE);
+    crc = 0;
+
+    hp = (hymod_eehdr_t *)data;
+    eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)hp, sizeof (*hp));
+    offset += sizeof (*hp);
+
+    if (hp->id != HYMOD_EEPROM_ID || hp->ver > HYMOD_EEPROM_VER ||
+      (len = hp->len) > HYMOD_EEPROM_MAXLEN)
+       return (0);
+
+    dp = (uchar *)(hp + 1); edp = dp + len;
+    eeprom_read(CFG_DEF_EEPROM_ADDR, offset, dp, len);
+    offset += len;
+
+    eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)&crc, sizeof (ulong));
+
+    if (crc32(0, data, edp - data) != crc)
+       return (0);
+
+    ep->ver = hp->ver;
+
+    for (;;) {
+       hymod_eerec_t *rp = (hymod_eerec_t *)dp;
+       ulong rtyp;
+       uchar rlen, *rdat;
+       uint rsiz;
+
+       if (rp->small.topbit == 0) {
+           rtyp = rp->small.type;
+           rlen = rp->small.len;
+           rdat = rp->small.data;
+           rsiz = offsetof(hymod_eerec_t, small.data) + rlen;
+       }
+       else if (rp->medium.nxtbit == 0) {
+           rtyp = rp->medium.type;
+           rlen = rp->medium.len;
+           rdat = rp->medium.data;
+           rsiz = offsetof(hymod_eerec_t, medium.data) + rlen;
+       }
+       else {
+           rtyp = rp->large.type;
+           rlen = rp->large.len;
+           rdat = rp->large.data;
+           rsiz = offsetof(hymod_eerec_t, large.data) + rlen;
+       }
+
+       if (rtyp == 0)
+           break;
+
+       dp += rsiz;
+       if (dp > edp)   /* error? */
+           break;
+
+       switch (rtyp) {
+
+       case HYMOD_EEREC_SERNO:         /* serial number */
+           if (rlen == sizeof (ulong))
+               memcpy(&ep->serno, rdat, sizeof (ulong));
+           break;
+
+       case HYMOD_EEREC_DATE:          /* date */
+           if (rlen == sizeof (hymod_date_t))
+               memcpy(&ep->date, rdat, sizeof (hymod_date_t));
+           break;
+
+       case HYMOD_EEREC_BATCH:         /* batch */
+           if (rlen <= HYMOD_MAX_BATCH)
+               memcpy(ep->batch, rdat, ep->batchlen = rlen);
+           break;
+
+       case HYMOD_EEREC_TYPE:          /* board type */
+           if (rlen == 1)
+               ep->bdtype = *rdat;
+           break;
+
+       case HYMOD_EEREC_REV:           /* board revision */
+           if (rlen == 1)
+               ep->bdrev = *rdat;
+           break;
+
+       case HYMOD_EEREC_SDRAM:         /* sdram size(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_SDRAM) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->sdramsz[i] = rdat[i];
+               ep->nsdram = rlen;
+           }
+           break;
+
+       case HYMOD_EEREC_FLASH:         /* flash size(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_FLASH) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->flashsz[i] = rdat[i];
+               ep->nflash = rlen;
+           }
+           break;
+
+       case HYMOD_EEREC_ZBT:           /* zbt ram size(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_ZBT) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->zbtsz[i] = rdat[i];
+               ep->nzbt = rlen;
+           }
+           break;
+
+       case HYMOD_EEREC_XLXTYP:        /* xilinx fpga type(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->xlx[i].type = rdat[i];
+               ep->nxlx = rlen;
+           }
+           break;
+
+       case HYMOD_EEREC_XLXSPD:        /* xilinx fpga speed(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->xlx[i].speed = rdat[i];
+           }
+           break;
+
+       case HYMOD_EEREC_XLXTMP:        /* xilinx fpga temperature(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->xlx[i].temp = rdat[i];
+           }
+           break;
+
+       case HYMOD_EEREC_XLXGRD:        /* xilinx fpga grade(s) */
+           if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+               int i;
+
+               for (i = 0; i < rlen; i++)
+                   ep->xlx[i].grade = rdat[i];
+           }
+           break;
+
+       case HYMOD_EEREC_CPUTYP:        /* CPU type */
+           if (rlen == 1)
+               ep->mpc.type = *rdat;
+           break;
+
+       case HYMOD_EEREC_CPUSPD:        /* CPU speed */
+           if (rlen == 1)
+               ep->mpc.cpuspd = *rdat;
+           break;
+
+       case HYMOD_EEREC_CPMSPD:        /* CPM speed */
+           if (rlen == 1)
+               ep->mpc.cpmspd = *rdat;
+           break;
+
+       case HYMOD_EEREC_BUSSPD:        /* bus speed */
+           if (rlen == 1)
+               ep->mpc.busspd = *rdat;
+           break;
+
+       case HYMOD_EEREC_HSTYPE:        /* high-speed serial chip type */
+           if (rlen == 1)
+               ep->hss.type = *rdat;
+           break;
+
+       case HYMOD_EEREC_HSCHIN:        /* high-speed serial input channels */
+           if (rlen == 1)
+               ep->hss.nchin = *rdat;
+           break;
+
+       case HYMOD_EEREC_HSCHOUT:       /* high-speed serial output channels */
+           if (rlen == 1)
+               ep->hss.nchout = *rdat;
+           break;
+
+       default:        /* ignore */
+           break;
+       }
+    }
+
+    return (1);
+}
+
+/* maps an ascii "name=value" into a binary eeprom data record */
+typedef
+    struct _eerec_map {
+       char *name;
+       uint type;
+       uchar *(*handler)(struct _eerec_map *, uchar *, uchar *, uchar *);
+       uint length;
+       uint maxlen;
+    }
+eerec_map_t;
+
+static uchar *
+uint_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+    uchar *eval;
+    union {
+       uchar cval[4];
+       ushort sval[2];
+       ulong lval;
+    } rdata;
+
+    rdata.lval = simple_strtol(value, (char **)&eval, 10);
+
+    if (eval == value || *eval != '\0') {
+       printf("%s record (%s) is not a valid uint\n", rp->name, value);
+       return (NULL);
+    }
+
+    if (dp + 2 + rp->length > edp) {
+       printf("can't fit %s record into eeprom\n", rp->name);
+       return (NULL);
+    }
+
+    *dp++ = rp->type;
+    *dp++ = rp->length;
+
+    switch (rp->length) {
+
+    case 1:
+       if (rdata.lval >= 256) {
+           printf("%s record value (%lu) out of range (0-255)\n",
+               rp->name, rdata.lval);
+           return (NULL);
+       }
+       *dp++ = rdata.cval[3];
+       break;
+
+    case 2:
+       if (rdata.lval >= 65536) {
+           printf("%s record value (%lu) out of range (0-65535)\n",
+               rp->name, rdata.lval);
+           return (NULL);
+       }
+       memcpy(dp, &rdata.sval[1], 2);
+       dp += 2;
+       break;
+
+    case 4:
+       memcpy(dp, &rdata.lval, 4);
+       dp += 4;
+       break;
+
+    default:
+       printf("huh? rp->length not 1, 2 or 4! (%d)\n", rp->length);
+       return (NULL);
+    }
+
+    return (dp);
+}
+
+static uchar *
+date_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+    hymod_date_t date;
+    uchar *p = value, *ep;
+
+    date.year = simple_strtol(p, (char **)&ep, 10);
+    if (ep == p || *ep++ != '-') {
+bad_date:
+       printf("%s record (%s) is not a valid date\n", rp->name, value);
+       return (NULL);
+    }
+
+    date.month = simple_strtol(p = ep, (char **)&ep, 10);
+    if (ep == p || *ep++ != '-' || date.month == 0 || date.month > 12)
+       goto bad_date;
+
+    date.day = simple_strtol(p = ep, (char **)&ep, 10);
+    if (ep == p || *ep != '\0' || date.day == 0 || date.day > 31)
+       goto bad_date;
+
+    if (dp + 2 + sizeof (hymod_date_t) > edp) {
+       printf("can't fit %s record into eeprom\n", rp->name);
+       return (NULL);
+    }
+
+    *dp++ = rp->type;
+    *dp++ = sizeof (hymod_date_t);
+    memcpy(dp, &date, sizeof (hymod_date_t));
+    dp += sizeof (hymod_date_t);
+
+    return (dp);
+}
+
+static uchar *
+string_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+    uint len;
+
+    if ((len = strlen(value)) > rp->maxlen) {
+       printf("%s record (%s) string is too long (%d>%d)\n",
+           rp->name, value, len, rp->maxlen);
+       return (NULL);
+    }
+
+    if (dp + 2 + len > edp) {
+       printf("can't fit %s record into eeprom\n", rp->name);
+       return (NULL);
+    }
+
+    *dp++ = rp->type;
+    *dp++ = len;
+    memcpy(dp, value, len);
+    dp += len;
+
+    return (dp);
+}
+
+static uchar *
+bytes_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+    uchar bytes[HYMOD_MAX_BYTES], nbytes = 0;
+    uchar *p = value, *ep;
+
+    for (;;) {
+
+       if (nbytes >= HYMOD_MAX_BYTES) {
+           printf("%s record (%s) byte array too long\n", rp->name, value);
+           return (NULL);
+       }
+
+       bytes[nbytes++] = simple_strtol(p, (char **)&ep, 10);
+
+       if (ep == p || (*ep != '\0' && *ep != ',')) {
+           printf("%s record (%s) byte array has invalid uint\n",
+               rp->name, value);
+           return (NULL);
+       }
+
+       if (*ep++ == '\0')
+           break;
+
+       p = ep;
+    }
+
+    if (dp + 2 + nbytes > edp) {
+       printf("can't fit %s record into eeprom\n", rp->name);
+       return (NULL);
+    }
+
+    *dp++ = rp->type;
+    *dp++ = nbytes;
+    memcpy(dp, bytes, nbytes);
+    dp += nbytes;
+
+    return (dp);
+}
+
+static eerec_map_t eerec_map[] = {
+   /* name       type                 handler         len max             */
+    { "serno",   HYMOD_EEREC_SERNO,   uint_handler,   4,  0               },
+    { "date",    HYMOD_EEREC_DATE,    date_handler,   4,  0               },
+    { "batch",   HYMOD_EEREC_BATCH,   string_handler, 0,  HYMOD_MAX_BATCH },
+    { "type",    HYMOD_EEREC_TYPE,    uint_handler,   1,  0               },
+    { "rev",     HYMOD_EEREC_REV,     uint_handler,   1,  0               },
+    { "sdram",   HYMOD_EEREC_SDRAM,   bytes_handler,  0,  HYMOD_MAX_SDRAM },
+    { "flash",   HYMOD_EEREC_FLASH,   bytes_handler,  0,  HYMOD_MAX_FLASH },
+    { "zbt",     HYMOD_EEREC_ZBT,     bytes_handler,  0,  HYMOD_MAX_ZBT   },
+    { "xlxtyp",  HYMOD_EEREC_XLXTYP,  bytes_handler,  0,  HYMOD_MAX_XLX   },
+    { "xlxspd",  HYMOD_EEREC_XLXSPD,  bytes_handler,  0,  HYMOD_MAX_XLX   },
+    { "xlxtmp",  HYMOD_EEREC_XLXTMP,  bytes_handler,  0,  HYMOD_MAX_XLX   },
+    { "xlxgrd",  HYMOD_EEREC_XLXGRD,  bytes_handler,  0,  HYMOD_MAX_XLX   },
+    { "cputyp",  HYMOD_EEREC_CPUTYP,  uint_handler,   1,  0               },
+    { "cpuspd",  HYMOD_EEREC_CPUSPD,  uint_handler,   1,  0               },
+    { "cpmspd",  HYMOD_EEREC_CPMSPD,  uint_handler,   1,  0               },
+    { "busspd",  HYMOD_EEREC_BUSSPD,  uint_handler,   1,  0               },
+    { "hstype",  HYMOD_EEREC_HSTYPE,  uint_handler,   1,  0               },
+    { "hschin",  HYMOD_EEREC_HSCHIN,  uint_handler,   1,  0               },
+    { "hschout", HYMOD_EEREC_HSCHOUT, uint_handler,   1,  0               },
+};
+
+static int neerecs = sizeof eerec_map / sizeof eerec_map[0];
+
+static uchar data[HYMOD_EEPROM_SIZE], *sdp, *dp, *edp;
+
+static int
+eeprom_fetch_callback(uchar *name, uchar *value)
+{
+    eerec_map_t *rp;
+
+    for (rp = eerec_map; rp < &eerec_map[neerecs]; rp++)
+       if (strcmp(name, rp->name) == 0)
+           break;
+
+    if (rp >= &eerec_map[neerecs])
+       return (0);
+
+    if ((dp = (*rp->handler)(rp, value, dp, edp)) == NULL)
+       return (0);
+
+    return (1);
+}
+
+int
+eeprom_fetch(unsigned offset, bd_t *bd, char *filename, ulong addr)
+{
+    hymod_eehdr_t *hp = (hymod_eehdr_t *)&data[0];
+    ulong crc;
+
+    hp->id = HYMOD_EEPROM_ID;
+    hp->ver = HYMOD_EEPROM_VER;
+
+    dp = sdp = (uchar *)(hp + 1);
+    edp = dp + HYMOD_EEPROM_MAXLEN;
+
+    if (fetch_and_parse(bd, filename, addr, eeprom_fetch_callback) == 0)
+       return (0);
+
+    hp->len = dp - sdp;
+
+    crc = crc32(0, data, dp - data);
+    memcpy(dp, &crc, sizeof (ulong));
+    dp += sizeof (ulong);
+
+    eeprom_write(CFG_DEF_EEPROM_ADDR, offset, data, dp - data);
+
+    return (1);
+}
+
+static char *type_vals[] = {
+    "NONE", "IO", "CLP", "DSP", "INPUT", "ALT-INPUT", "DISPLAY"
+};
+
+static char *xlxtyp_vals[] = {
+    "NONE", "XCV300E", "XCV400E", "XCV600E"
+};
+
+static char *xlxspd_vals[] = {
+    "NONE", "6", "7", "8"
+};
+
+static char *xlxtmp_vals[] = {
+    "NONE", "COM", "IND"
+};
+
+static char *xlxgrd_vals[] = {
+    "NONE", "NORMAL", "ENGSAMP"
+};
+
+static char *cputyp_vals[] = {
+    "NONE", "MPC8260"
+};
+
+static char *clk_vals[] = {
+    "NONE", "33", "66", "100", "133", "166", "200"
+};
+
+static char *hstype_vals[] = {
+    "NONE", "AMCC-S2064A"
+};
+
+static void
+print_mem(char *l, char *s, uchar n, uchar a[])
+{
+    if (n > 0) {
+       if (n == 1)
+           printf("%s%dMB %s", s, 1 << (a[0] - 20), l);
+       else {
+           ulong t = 0;
+           int i;
+
+           for (i = 0; i < n; i++)
+               t += 1 << (a[i] - 20);
+
+           printf("%s%luMB %s (%d banks:", s, t, l, n);
+
+           for (i = 0; i < n; i++)
+               printf("%dMB%s", 1 << (a[i] - 20), (i == n - 1) ? ")" : ",");
+       }
+    }
+    else
+       printf("%sNO %s", s, l);
+}
+
+void
+eeprom_print(hymod_eeprom_t *ep)
+{
+    int i;
+
+    printf("         Hymod %s board, rev %03d\n",
+       type_vals[ep->bdtype], ep->bdrev);
+
+    printf("         serial #: %010lu, date %04d-%02d-%02d",
+       ep->serno, ep->date.year, ep->date.month, ep->date.day);
+    if (ep->batchlen > 0)
+       printf(", batch \"%.*s\"", ep->batchlen, ep->batch);
+    puts("\n");
+
+    switch (ep->bdtype) {
+
+    case HYMOD_BDTYPE_IO:
+    case HYMOD_BDTYPE_CLP:
+    case HYMOD_BDTYPE_DSP:
+       printf("         Motorola %s CPU, speeds: %s/%s/%s",
+           cputyp_vals[ep->mpc.type], clk_vals[ep->mpc.cpuspd],
+           clk_vals[ep->mpc.cpmspd], clk_vals[ep->mpc.busspd]);
+
+       print_mem("SDRAM", ", ", ep->nsdram, ep->sdramsz);
+
+       print_mem("FLASH", ", ", ep->nflash, ep->flashsz);
+
+       puts("\n");
+
+       print_mem("ZBT", "         ", ep->nzbt, ep->zbtsz);
+
+       if (ep->nxlx > 0) {
+           hymod_xlx_t *xp;
+
+           if (ep->nxlx == 1) {
+               xp = &ep->xlx[0];
+               printf(", Xilinx %s FPGA (%s/%s/%s)",
+                   xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
+                   xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade]);
+           }
+           else {
+               printf(", %d Xilinx FPGAs (", ep->nxlx);
+               for (i = 0; i < ep->nxlx; i++) {
+                   xp = &ep->xlx[i];
+                   printf("%s[%s/%s/%s]%s",
+                       xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
+                       xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade],
+                       (i == ep->nxlx - 1) ? ")" : ", ");
+               }
+           }
+       }
+       else
+           puts(", NO FPGAs");
+
+       puts("\n");
+
+       if (ep->hss.type > 0)
+           printf("         High Speed Serial: %s, %d input%s, %d output%s\n",
+               hstype_vals[ep->hss.type],
+               ep->hss.nchin, (ep->hss.nchin == 1 ? "" : "s"),
+               ep->hss.nchout, (ep->hss.nchout == 1 ? "" : "s"));
+       break;
+
+    case HYMOD_BDTYPE_INPUT:
+    case HYMOD_BDTYPE_ALTINPUT:
+    case HYMOD_BDTYPE_DISPLAY:
+       break;
+
+    default:
+       /* crap! */
+       printf("         UNKNOWN BOARD TYPE: %d\n", ep->bdtype);
+       break;
+    }
+}
diff --git a/board/hymod/flash.c b/board/hymod/flash.c
new file mode 100644 (file)
index 0000000..ee052e3
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * (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
+ *
+ * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <board/hymod/flash.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];  /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+#if 0
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+#endif
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * probe for the existence of flash at bank word address "addr"
+ * 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
+ */
+static int
+bank_probe_word(bank_addr_t addr)
+{
+       int retval;
+
+       /* reset the flash */
+       *addr = BANK_CMD_RST;
+
+       /* check the manufacturer id */
+       *addr = BANK_CMD_RD_ID;
+       if (*BANK_ADDR_REG_MAN(addr) != BANK_RD_ID_MAN) {
+               retval = -1;
+               goto out;
+       }
+
+       /* check the device id */
+       *addr = BANK_CMD_RD_ID;
+       if (*BANK_ADDR_REG_DEV(addr) != BANK_RD_ID_DEV) {
+               retval = -2;
+               goto out;
+       }
+
+       retval = CFG_FLASH_TYPE;
+
+out:
+       /* reset the flash again */
+       *addr = BANK_CMD_RST;
+
+       return retval;
+}
+
+/*
+ * probe for flash banks at address "base" and store info for any found
+ * into flash_info entry "fip". Must find at least one bank.
+ */
+static void
+bank_probe(flash_info_t *fip, bank_addr_t base)
+{
+       bank_addr_t addr, eaddr;
+       int nbanks;
+
+       fip->flash_id = FLASH_UNKNOWN;
+       fip->size = 0L;
+       fip->sector_count = 0;
+
+       addr = base;
+       eaddr = BANK_ADDR_BASE(addr, MAX_BANKS);
+       nbanks = 0;
+
+       while (addr < eaddr) {
+               bank_addr_t addrw, eaddrw, addrb;
+               int i, osc, nsc, curtype = -1;
+
+               addrw = addr;
+               eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+               while (addrw < eaddrw) {
+                       int thistype;
+
+#ifdef FLASH_DEBUG
+                       printf("  probing for flash at addr 0x%08lx\n",
+                               (unsigned long)addrw);
+#endif
+                       if ((thistype = bank_probe_word(addrw++)) < 0)
+                               goto out;
+
+                       if (curtype < 0)
+                               curtype = thistype;
+                       else {
+                               if (thistype != curtype) {
+                                       printf("Differing flash type found!\n");
+                                       goto out;
+                               }
+                       }
+               }
+
+               if (curtype < 0)
+                       goto out;
+
+               /* bank exists - append info for this bank to *fip */
+               fip->flash_id = FLASH_MAN_INTEL|curtype;
+               fip->size += BANK_SIZE;
+               osc = fip->sector_count;
+               fip->sector_count += BANK_NBLOCKS;
+               if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
+                       panic("Too many sectors in flash at address 0x%08lx\n",
+                               (unsigned long)base);
+
+               addrb = addr;
+               for (i = osc; i < nsc; i++) {
+                       fip->start[i] = (ulong)addrb;
+                       fip->protect[i] = 0;
+                       addrb = BANK_ADDR_NEXT_BLK(addrb);
+               }
+
+               addr = BANK_ADDR_NEXT_BANK(addr);
+               nbanks++;
+       }
+
+out:
+       if (nbanks == 0)
+               panic("ERROR: no flash found at address 0x%08lx\n",
+                       (unsigned long)base);
+}
+
+static void
+bank_reset(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, eaddrw;
+
+       addrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+       while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+               printf("  writing reset cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = BANK_CMD_RST;
+               addrw++;
+       }
+}
+
+static void
+bank_erase_init(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, saddrw, eaddrw;
+       int flag;
+
+#ifdef FLASH_DEBUG
+       printf("0x%08lx BANK_CMD_PROG\n", BANK_CMD_PROG);
+       printf("0x%08lx BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
+       printf("0x%08lx BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
+       printf("0x%08lx BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
+       printf("0x%08lx BANK_CMD_RST\n", BANK_CMD_RST);
+       printf("0x%08lx BANK_STAT_RDY\n", BANK_STAT_RDY);
+       printf("0x%08lx BANK_STAT_ERR\n", BANK_STAT_ERR);
+#endif
+
+       saddrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+       printf("erasing sector %d, start addr = 0x%08lx "
+               "(bank next word addr = 0x%08lx)\n", sect,
+               (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+       /* Disable intrs which might cause a timeout here */
+       flag = disable_interrupts();
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+               printf("  writing erase cmd to addr 0x%08lx\n",
+                       (unsigned long)addrw);
+#endif
+               *addrw = BANK_CMD_ERASE1;
+               *addrw = BANK_CMD_ERASE2;
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+}
+
+static int
+bank_erase_poll(flash_info_t *info, int sect)
+{
+       bank_addr_t addrw, saddrw, eaddrw;
+       int sectdone, haderr;
+
+       saddrw = (bank_addr_t)info->start[sect];
+       eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+       sectdone = 1;
+       haderr = 0;
+
+       for (addrw = saddrw; addrw < eaddrw; addrw++) {
+               bank_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+               printf("  checking status at addr "
+                       "0x%08lx [0x%08lx]\n",
+                       (unsigned long)addrw, stat);
+#endif
+               if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
+                       sectdone = 0;
+               else if ((stat & BANK_STAT_ERR) != 0) {
+                       printf(" failed on sector %d "
+                               "(stat = 0x%08lx) at "
+                               "address 0x%08lx\n",
+                               sect, stat,
+                               (unsigned long)addrw);
+                       *addrw = BANK_CMD_CLR_STAT;
+                       haderr = 1;
+               }
+       }
+
+       if (haderr)
+               return (-1);
+       else
+               return (sectdone);
+}
+
+static int
+bank_write_word(bank_addr_t addr, bank_word_t value)
+{
+       bank_word_t stat;
+       ulong start;
+       int flag, retval;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = BANK_CMD_PROG;
+
+       *addr = value;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       retval = 0;
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       do {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       retval = 1;
+                       goto done;
+               }
+               stat = *addr;
+       } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
+
+       if ((stat & BANK_STAT_ERR) != 0) {
+               printf("flash program failed (stat = 0x%08lx) "
+                       "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+               *addr = BANK_CMD_CLR_STAT;
+               retval = 3;
+       }
+
+done:
+       /* reset to read mode */
+       *addr = BANK_CMD_RST;
+
+       return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long
+flash_init(void)
+{
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       bank_probe(&flash_info[0], (bank_addr_t)CFG_FLASH_BASE);
+
+       /*
+        * protect monitor and environment sectors
+        */
+
+#if CFG_MONITOR_BASE == CFG_FLASH_BASE
+       (void)flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#if defined(CFG_FLASH_ENV_ADDR)
+       (void)flash_protect(FLAG_PROTECT_SET,
+                     CFG_FLASH_ENV_ADDR,
+#if defined(CFG_FLASH_ENV_BUF)
+                     CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_BUF - 1,
+#else
+                     CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1,
+#endif
+                     &flash_info[0]);
+#endif
+
+       return flash_info[0].size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+#if 0
+static void
+flash_get_offsets(ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+}
+#endif /* 0 */
+
+/*-----------------------------------------------------------------------
+ */
+void
+flash_print_info(flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F320J5:    printf ("28F320J5 (32 Mbit, 2 x 16bit)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+#if 0
+static ulong
+flash_get_size(vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start adress table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+#endif /* 0 */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+       int prot, sect, haderr;
+       ulong start, now, last;
+       int rcode = 0;
+
+#ifdef FLASH_DEBUG
+       printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+               "  Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+               (info - flash_info) + 1);
+       flash_print_info(info);
+#endif
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf("- Warning: %d protected sector%s will not be erased!\n",
+                       prot, (prot > 1 ? "s" : ""));
+       }
+
+       start = get_timer (0);
+       last = 0;
+       haderr = 0;
+
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       ulong estart;
+                       int sectdone;
+
+                       bank_erase_init(info, sect);
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       estart = get_timer(start);
+
+                       do {
+                               now = get_timer(start);
+
+                               if (now - estart > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout (sect %d)\n", sect);
+                                       haderr = 1;
+                                       rcode = 1;
+                                       break;
+                               }
+
+#ifndef FLASH_DEBUG
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) { /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+#endif
+
+                               sectdone = bank_erase_poll(info, sect);
+
+                               if (sectdone < 0) {
+                                       haderr = 1;
+                                       rcode = 1;
+                                       break;
+                               }
+
+                       } while (!sectdone);
+
+                       if (haderr)
+                               break;
+               }
+       }
+
+       if (haderr > 0)
+               printf (" failed\n");
+       else
+               printf (" done\n");
+
+       /* reset to read mode */
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       bank_reset(info, sect);
+               }
+       }
+       return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int
+write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int
+write_word(flash_info_t *info, ulong dest, ulong data)
+{
+       int retval;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*(ulong *)dest & data) != data) {
+               return (2);
+       }
+
+       retval = bank_write_word((bank_addr_t)dest, (bank_word_t)data);
+
+       return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/icu862/flash.c b/board/icu862/flash.c
new file mode 100644 (file)
index 0000000..79e7cc2
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0,
+                       size_b0 >> 20);
+       }
+
+       if (FLASH_BASE1_PRELIM != 0x0) {
+               size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+               if (size_b1 > size_b0) {
+                       printf ("## ERROR: Bank 1 (0x%08lx = %ld MB)"
+                               " > Bank 0 (0x%08lx = %ld MB)\n",
+                               size_b1, size_b1 >> 20,
+                               size_b0, size_b0 >> 20);
+
+                       flash_info[0].flash_id  = FLASH_UNKNOWN;
+                       flash_info[1].flash_id  = FLASH_UNKNOWN;
+                       flash_info[0].sector_count      = -1;
+                       flash_info[1].sector_count      = -1;
+                       flash_info[0].size              = 0;
+                       flash_info[1].size              = 0;
+                       return (0);
+               }
+       } else {
+               size_b1 = 0;
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       /* ICU862 Board has only one Flash Bank */
+       flash_info[1].flash_id = FLASH_UNKNOWN;
+       flash_info[1].sector_count = -1;
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) ||
+               ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM033C)) {
+               /* set sector offsets for uniform sector type   */
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00040000);
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               puts ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     puts ("AMD ");          break;
+       case FLASH_MAN_FUJ:     puts ("FUJITSU ");      break;
+       case FLASH_MAN_BM:      puts ("BRIGHT MICRO "); break;
+       default:                puts ("Unknown Vendor "); break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM040:       puts ("29F040/29LV040 (4 Mbit, uniform sectors)\n");
+                               break;
+       case FLASH_AM400B:      puts ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      puts ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      puts ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      puts ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      puts ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      puts ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      puts ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      puts ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM033C:      puts ("AM29LV033C (32 Mbit)\n");
+                               break;
+       default:                puts ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       puts ("  Sector Start Addresses:");
+
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0) {
+                       puts ("\n   ");
+               }
+
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+
+       puts ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+#if 0
+       ulong base = (ulong)addr;
+#endif
+       uchar value;
+
+       /* Write auto select command: read Manufacturer ID */
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x90909090;
+#endif
+
+       value = addr[0];
+
+       switch (value + (value << 16)) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               break;
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_F040B:
+               info->flash_id += FLASH_AM040;
+               info->sector_count = 8;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       case AMD_ID_LV033C:
+               info->flash_id += FLASH_AM033C;
+               info->sector_count = 64;
+               info->size = 0x01000000;
+               break;                          /* => 16Mb              */
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+#if 0
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+#else
+       flash_get_offsets ((ulong)addr, &flash_info[0]);
+#endif
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+#if 1
+               /* We don't know why it happens, but on ICU Board       *
+                * for AMD29033C flash we need to resend the command of *
+                * reading flash protection for upper 8 Mb of flash     */
+               if ( i == 32 ) {
+                       addr[0x0555] = 0xAAAAAAAA;
+                       addr[0x02AA] = 0x55555555;
+                       addr[0x0555] = 0x90909090;
+               }
+#endif
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+#if 0
+               *addr = 0x00F000F0;     /* reset bank */
+#else
+               *addr = 0xF0F0F0F0;     /* reset bank */
+#endif
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       puts ("- missing\n");
+               } else {
+                       puts ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               puts ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               puts ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0x80808080;
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+#endif
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+#if 0
+                       addr[0] = 0x00300030;
+#else
+                       addr[0] = 0x30303030;
+#endif
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+#if 0
+       while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+       while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+       {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       puts ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+#if 0
+       addr[0] = 0x00F000F0;   /* reset bank */
+#else
+       addr[0] = 0xF0F0F0F0;   /* reset bank */
+#endif
+
+       puts (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+#if 0
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+#else
+       addr[0x0555] = 0xAAAAAAAA;
+       addr[0x02AA] = 0x55555555;
+       addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+#if 0
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+       while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+       {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/ip860/flash.c b/board/ip860/flash.c
new file mode 100644 (file)
index 0000000..4b0ea9b
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t        *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t    *memctl = &immap->im_memctl;
+       volatile ip860_bcsr_t   *bcsr   = (ip860_bcsr_t *)BCSR_BASE;
+       unsigned long size;
+       int i;
+
+       /* Init: enable write,
+        * or we cannot even write flash commands
+        */
+       bcsr->bd_ctrl |= BD_CTRL_FLWE;
+
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size = flash_get_size((vu_long *)FLASH_BASE, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size, size<<20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+       memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
+                               (memctl->memc_br1 & ~(BR_BA_MSK));
+
+       /* Re-do sizing to get full correct info */
+       size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+       return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* all possible flash types
+        * (28F016SV, 28F160S3, 28F320S3)
+        * have the same erase block size: 64 kB per chip,
+        * of 128 kB per bank
+        */
+
+       /* set up sector start address table */
+       for (i = 0; i < info->sector_count; i++) {
+               info->start[i] = base;
+               base += 0x00020000;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_INTEL:   printf ("Intel ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F016SV:    printf ("28F016SV (16 Mbit, 32 x 64k)\n");
+                               break;
+       case FLASH_28F160S3:    printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
+                               break;
+       case FLASH_28F320S3:    printf ("28F320S3 (32 Mbit, 64 x 512K)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+       /* Write "Intelligent Identifier" command: read Manufacturer ID */
+       *addr = 0x90909090;
+
+       value = addr[0];
+       switch (value) {
+       case (MT_MANUFACT & 0x00FF00FF):        /* MT or => Intel */
+       case (INTEL_ALT_MANU & 0x00FF00FF):
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case (INTEL_ID_28F016S):
+               info->flash_id += FLASH_28F016SV;
+               info->sector_count = 32;
+               info->size = 0x00400000;
+               break;                          /* => 2x2 MB            */
+
+       case (INTEL_ID_28F160S3):
+               info->flash_id += FLASH_28F160S3;
+               info->sector_count = 32;
+               info->size = 0x00400000;
+               break;                          /* => 2x2 MB            */
+
+       case (INTEL_ID_28F320S3):
+               info->flash_id += FLASH_28F320S3;
+               info->sector_count = 64;
+               info->size = 0x00800000;
+               break;                          /* => 2x4 MB            */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+       for (i = 0; i < info->sector_count; i++) {
+               info->start[i] = base + (i * 0x00020000);
+               /* don't know how to check sector protection */
+               info->protect[i] = 0;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (vu_long *)info->start[0];
+
+               *addr = 0xFFFFFF;       /* reset bank to read array mode */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       vu_long *addr = (vu_long *)(info->start[sect]);
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       /* Single Block Erase Command */
+                       *addr = 0x20202020;
+                       /* Confirm */
+                       *addr = 0xD0D0D0D0;
+                       /* Resume Command, as per errata update */
+                       *addr = 0xD0D0D0D0;
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while ((*addr & 0x00800080) != 0x00800080) {
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = 0xFFFFFFFF;     /* reset bank */
+                                       return 1;
+                               }
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       /* reset to read mode */
+                       *addr = 0xFFFFFFFF;
+               }
+       }
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long *)dest;
+       ulong start, csr;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*addr & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       /* Write Command */
+       *addr = 0x10101010;
+
+       /* Write Data */
+       *addr = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       flag  = 0;
+       while (((csr = *addr) & 0x00800080) != 0x00800080) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       flag = 1;
+                       break;
+               }
+       }
+       if (csr & 0x00400040) {
+printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
+               flag = 1;
+       }
+
+       /* Clear Status Registers Command */
+       *addr = 0x50505050;
+       /* Reset to read array mode */
+       *addr = 0xFFFFFFFF;
+
+       return (flag);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/ivm/flash.c b/board/ivm/flash.c
new file mode 100644 (file)
index 0000000..b5453df
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0: "
+                       "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+                       flash_info[0].flash_id,
+                       size_b0, size_b0<<20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
+                               BR_MS_GPCM | BR_PS_16 | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_MT:
+           if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + ((i-3) * 0x00020000);
+               }
+           } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+           }
+           return;
+
+       case FLASH_MAN_SST:
+           for (i = 0; i < info->sector_count; i++) {
+               info->start[i] = base + (i * 0x00002000);
+           }
+           return;
+
+       case FLASH_MAN_AMD:
+       case FLASH_MAN_FUJ:
+
+           /* set up sector start address table */
+           if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+           } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+           }
+           return;
+       default:
+           printf ("Don't know sector ofsets for flash type 0x%lx\n",
+               info->flash_id);
+           return;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("Fujitsu ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       case FLASH_MAN_MT:      printf ("MT ");                 break;
+       case FLASH_MAN_INTEL:   printf ("Intel ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_SST200A:     printf ("39xF200A (2M = 128K x 16)\n");
+                               break;
+       case FLASH_SST400A:     printf ("39xF400A (4M = 256K x 16)\n");
+                               break;
+       case FLASH_SST800A:     printf ("39xF800A (8M = 512K x 16)\n");
+                               break;
+       case FLASH_STM800AB:    printf ("M29W800AB (8M = 512K x 16)\n");
+                               break;
+       case FLASH_28F008S5:    printf ("28F008S5 (1M = 64K x 16)\n");
+                               break;
+       case FLASH_28F400_T:    printf ("28F400B3 (4Mbit, top boot sector)\n");
+                               break;
+       case FLASH_28F400_B:    printf ("28F400B3 (4Mbit, bottom boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       if (info->size >= (1 << 20)) {
+               i = 20;
+       } else {
+               i = 10;
+       }
+       printf ("  Size: %ld %cB in %d Sectors\n",
+               info->size >> i,
+               (i == 20) ? 'M' : 'k',
+               info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       ushort value;
+       vu_short *saddr = (vu_short *)addr;
+
+       /* Read Manufacturer ID */
+       saddr[0] = 0x0090;
+       value = saddr[0];
+
+       switch (value) {
+       case (AMD_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (FUJ_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case (SST_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       case (STM_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_STM;
+               break;
+       case (MT_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_MT;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               saddr[0] = 0x00FF;              /* restore read mode */
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = saddr[1];                       /* device ID            */
+
+       switch (value) {
+       case (AMD_ID_LV400T & 0xFFFF):
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV400B & 0xFFFF):
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (AMD_ID_LV800T & 0xFFFF):
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (AMD_ID_LV800B & 0xFFFF):
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (AMD_ID_LV160T & 0xFFFF):
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (AMD_ID_LV160B & 0xFFFF):
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case (AMD_ID_LV320T & 0xFFFF):
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_LV320B & 0xFFFF):
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       case (SST_ID_xF200A & 0xFFFF):
+               info->flash_id += FLASH_SST200A;
+               info->sector_count = 64;        /* 39xF200A ID ( 2M = 128K x 16 ) */
+               info->size = 0x00080000;
+               break;
+       case (SST_ID_xF400A & 0xFFFF):
+               info->flash_id += FLASH_SST400A;
+               info->sector_count = 128;       /* 39xF400A ID ( 4M = 256K x 16 ) */
+               info->size = 0x00100000;
+               break;
+       case (SST_ID_xF800A & 0xFFFF):
+               info->flash_id += FLASH_SST800A;
+               info->sector_count = 256;       /* 39xF800A ID ( 8M = 512K x 16 ) */
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+       case (STM_ID_x800AB & 0xFFFF):
+               info->flash_id += FLASH_STM800AB;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+       case (MT_ID_28F400_T & 0xFFFF):
+               info->flash_id += FLASH_28F400_T;
+               info->sector_count = 7;
+               info->size = 0x00080000;
+               break;                          /* => 512 kB            */
+       case (MT_ID_28F400_B & 0xFFFF):
+               info->flash_id += FLASH_28F400_B;
+               info->sector_count = 7;
+               info->size = 0x00080000;
+               break;                          /* => 512 kB            */
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               saddr[0] = 0x00FF;              /* restore read mode */
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       saddr[0] = 0x00FF;              /* restore read mode */
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MT) {
+               printf ("Can erase only MT flash types - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       vu_short *addr = (vu_short *)(info->start[sect]);
+                       unsigned short status;
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       *addr = 0x0050; /* clear status register */
+                       *addr = 0x0020; /* erase setup */
+                       *addr = 0x00D0; /* erase confirm */
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while (((status = *addr) & 0x0080) != 0x0080) {
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = 0x00FF; /* reset to read mode */
+                                       return 1;
+                               }
+
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       *addr = 0x00FF; /* reset to read mode */
+               }
+       }
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define        FLASH_WIDTH     2       /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+
+       wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<FLASH_WIDTH && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += FLASH_WIDTH;
+       }
+
+       /*
+        * handle FLASH_WIDTH aligned part
+        */
+       while (cnt >= FLASH_WIDTH) {
+               data = 0;
+               for (i=0; i<FLASH_WIDTH; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += FLASH_WIDTH;
+               cnt -= FLASH_WIDTH;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<FLASH_WIDTH; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_short *addr = (vu_short *)dest;
+       ushort sdata = (ushort)data;
+       ushort status;
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*addr & sdata) != sdata) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = 0x0040;         /* write setup */
+       *addr = sdata;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       start = get_timer (0);
+
+       while (((status = *addr) & 0x0080) != 0x0080) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       *addr = 0x00FF; /* restore read mode */
+                       return (1);
+               }
+       }
+
+       *addr = 0x00FF;         /* restore read mode */
+
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/lantec/flash.c b/board/lantec/flash.c
new file mode 100644 (file)
index 0000000..df58510
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Derived from ../tqm8xx/flash.c
+ * [Torsten Stevens, FHG IMS; Bruno Achauer, Exet AG]
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0: "
+                       "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+                       flash_info[0].flash_id,
+                       size_b0, size_b0<<20);
+       }
+
+       DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE5_PRELIM);
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE5_PRELIM, &flash_info[1]);
+
+       DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       DEBUGF ("## Before remap: "
+               "BR0: 0x%08x    OR0: 0x%08x    "
+               "BR1: 0x%08x    OR1: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0,
+               memctl->memc_br1, memctl->memc_or1);
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
+                               BR_MS_GPCM | BR_PS_32 | BR_V;
+
+       DEBUGF("## BR0: 0x%08x    OR0: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0);
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or5 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br5 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_PS_32 | BR_V;
+
+               DEBUGF("## BR5: 0x%08x    OR5: 0x%08x\n",
+                       memctl->memc_br5, memctl->memc_or5);
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_info[1].size = size_b1;
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                             &flash_info[1]);
+#endif
+       } else {
+               memctl->memc_br5 = 0;           /* invalidate bank */
+               memctl->memc_or5 = 0;           /* invalidate bank */
+
+               DEBUGF("## DISABLE BR5: 0x%08x    OR5: 0x%08x\n",
+                       memctl->memc_br5, memctl->memc_or5);
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+               flash_info[1].size = 0;
+       }
+
+       DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+       while ((addr[0] & 0x00800080) != 0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/mbx8xx/flash.c b/board/mbx8xx/flash.c
new file mode 100644 (file)
index 0000000..e1aa47b
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AM290[48]0B devices
+ *
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+#include "vpd.h"
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+    unsigned long size, totsize;
+    int i;
+    ulong addr;
+
+    /* Init: no FLASHes known */
+    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+       flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+    totsize = 0;
+    addr = 0xfc000000;
+    for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+       size = flash_get_size((vu_long *)addr, &flash_info[i]);
+       if (flash_info[i].flash_id == FLASH_UNKNOWN)
+         break;
+       totsize += size;
+       addr += size;
+    }
+
+    addr = 0xfe000000;
+    for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+
+       size = flash_get_size((vu_long *)addr, &flash_info[i]);
+       if (flash_info[i].flash_id == FLASH_UNKNOWN)
+         break;
+       totsize += size;
+       addr += size;
+    }
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+    /* monitor protection ON by default */
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_MONITOR_BASE,
+                 CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                 &flash_info[0]);
+#endif
+
+    return (totsize);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+
+    if (info->flash_id == FLASH_UNKNOWN) {
+       printf ("missing or unknown FLASH type\n");
+       return;
+    }
+
+    switch (info->flash_id >> 16) {
+    case 0x1:
+       printf ("AMD ");
+       break;
+    default:
+       printf ("Unknown Vendor ");
+       break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case AMD_ID_F040B:
+       printf ("AM29F040B (4 Mbit)\n");
+       break;
+    case AMD_ID_F080B:
+       printf ("AM29F080B (8 Mbit)\n");
+       break;
+    case AMD_ID_F016D:
+       printf ("AM29F016D (16 Mbit)\n");
+       break;
+    default:
+       printf ("Unknown Chip Type\n");
+       break;
+    }
+
+    printf ("  Size: %ld MB in %d Sectors\n",
+           info->size >> 20, info->sector_count);
+
+    printf ("  Sector Start Addresses:");
+    for (i=0; i<info->sector_count; ++i) {
+       if ((i % 5) == 0)
+         printf ("\n   ");
+       printf (" %08lX%s",
+               info->start[i],
+               info->protect[i] ? " (RO)" : "     "
+               );
+    }
+    printf ("\n");
+    return;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+    short i;
+    ulong vendor, devid;
+    ulong base = (ulong)addr;
+
+    /* Write auto select command: read Manufacturer ID */
+    addr[0x0555] = 0xAAAAAAAA;
+    addr[0x02AA] = 0x55555555;
+    addr[0x0555] = 0x90909090;
+
+    vendor = addr[0];
+    devid = addr[1] & 0xff;
+
+    /* only support AMD */
+    if (vendor != 0x01010101) {
+       return 0;
+    }
+
+    vendor &= 0xf;
+    devid &= 0xff;
+
+    if (devid == AMD_ID_F040B) {
+       info->flash_id     = vendor << 16 | devid;
+       info->sector_count = 8;
+       info->size         = info->sector_count * 0x10000;
+    }
+    else if (devid == AMD_ID_F080B) {
+       info->flash_id     = vendor << 16 | devid;
+       info->sector_count = 16;
+       info->size         = 4 * info->sector_count * 0x10000;
+    }
+    else if (devid == AMD_ID_F016D) {
+       info->flash_id     = vendor << 16 | devid;
+       info->sector_count = 32;
+       info->size         = 4 * info->sector_count * 0x10000;
+    }
+    else {
+       printf ("## Unknown Flash Type: %08lx\n", devid);
+       return 0;
+    }
+
+    /* check for protected sectors */
+    for (i = 0; i < info->sector_count; i++) {
+       /* sector base address */
+       info->start[i] = base + i * (info->size / info->sector_count);
+       /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+       /* D0 = 1 if protected */
+       addr = (volatile unsigned long *)(info->start[i]);
+       info->protect[i] = addr[2] & 1;
+    }
+
+    /*
+     * Prevent writes to uninitialized FLASH.
+     */
+    if (info->flash_id != FLASH_UNKNOWN) {
+       addr = (vu_long *)info->start[0];
+       addr[0] = 0xF0; /* reset bank */
+    }
+
+    return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    vu_long *addr = (vu_long*)(info->start[0]);
+    int flag, prot, sect, l_sect;
+    ulong start, now, last;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+       if (info->flash_id == FLASH_UNKNOWN) {
+           printf ("- missing\n");
+       } else {
+           printf ("- no sectors to erase\n");
+       }
+       return 1;
+    }
+
+    prot = 0;
+    for (sect = s_first; sect <= s_last; sect++) {
+       if (info->protect[sect]) {
+           prot++;
+       }
+    }
+
+    if (prot) {
+       printf ("- Warning: %d protected sectors will not be erased!\n",
+               prot);
+    } else {
+       printf ("\n");
+    }
+
+    l_sect = -1;
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    addr[0x0555] = 0XAAAAAAAA;
+    addr[0x02AA] = 0x55555555;
+    addr[0x0555] = 0x80808080;
+    addr[0x0555] = 0XAAAAAAAA;
+    addr[0x02AA] = 0x55555555;
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last; sect++) {
+       if (info->protect[sect] == 0) { /* not protected */
+           addr = (vu_long*)(info->start[sect]);
+           addr[0] = 0x30303030;
+           l_sect = sect;
+       }
+    }
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* wait at least 80us - let's wait 1 ms */
+    udelay (1000);
+
+    /*
+     * We wait for the last triggered sector
+     */
+    if (l_sect < 0)
+      goto DONE;
+
+    start = get_timer (0);
+    last  = start;
+    addr = (vu_long*)(info->start[l_sect]);
+    while ((addr[0] & 0x80808080) != 0x80808080) {
+       if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+           printf ("Timeout\n");
+           return 1;
+       }
+       /* show that we're waiting */
+       if ((now - last) > 1000) {      /* every second */
+           serial_putc ('.');
+           last = now;
+       }
+    }
+
+    DONE:
+    /* reset to read mode */
+    addr = (volatile unsigned long *)info->start[0];
+    addr[0] = 0xF0F0F0F0;      /* reset bank */
+
+    printf (" done\n");
+    return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp, data;
+    int i, l, rc;
+
+    wp = (addr & ~3);  /* get lower word aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    if ((l = addr - wp) != 0) {
+       data = 0;
+       for (i=0, cp=wp; i<l; ++i, ++cp) {
+           data = (data << 8) | (*(uchar *)cp);
+       }
+       for (; i<4 && cnt>0; ++i) {
+           data = (data << 8) | *src++;
+           --cnt;
+           ++cp;
+       }
+       for (; cnt==0 && i<4; ++i, ++cp) {
+           data = (data << 8) | (*(uchar *)cp);
+       }
+
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       wp += 4;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 4) {
+       data = 0;
+       for (i=0; i<4; ++i) {
+           data = (data << 8) | *src++;
+       }
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       wp  += 4;
+       cnt -= 4;
+    }
+
+    if (cnt == 0) {
+       return (0);
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+       data = (data << 8) | *src++;
+       --cnt;
+    }
+    for (; i<4; ++i, ++cp) {
+       data = (data << 8) | (*(uchar *)cp);
+    }
+
+    return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+    vu_long *addr = (vu_long*)(info->start[0]);
+    ulong start;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*((vu_long *)dest) & data) != data) {
+       return (2);
+    }
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    addr[0x0555] = 0xAAAAAAAA;
+    addr[0x02AA] = 0x55555555;
+    addr[0x0555] = 0xA0A0A0A0;
+
+    *((vu_long *)dest) = data;
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* data polling for D7 */
+    start = get_timer (0);
+    while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
+       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+           return (1);
+       }
+    }
+    return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/mbx8xx/vpd.c b/board/mbx8xx/vpd.c
new file mode 100644 (file)
index 0000000..6f88352
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Code in faintly related to linux/arch/ppc/8xx_io:
+ * MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * This file implements functions to read the MBX's Vital Product Data
+ * (VPD). I can't use the more general i2c code in mpc8xx/... since I need
+ * the VPD at a time where there is no RAM available yet. Hence the VPD is
+ * read into a special area in the DPRAM (see config_MBX.h::CFG_DPRAMVPD).
+ *
+ * -----------------------------------------------------------------
+ * 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>
+#ifdef CONFIG_8xx
+#include <commproc.h>
+#endif
+#include "vpd.h"
+
+/* Location of receive/transmit buffer descriptors
+ * Allocate one transmit bd and one receive bd.
+ * IIC_BD_FREE points to free bd space which we'll use as tx buffer.
+ */
+#define IIC_BD_TX1     (BD_IIC_START + 0*sizeof(cbd_t))
+#define IIC_BD_TX2     (BD_IIC_START + 1*sizeof(cbd_t))
+#define IIC_BD_RX      (BD_IIC_START + 2*sizeof(cbd_t))
+#define IIC_BD_FREE    (BD_IIC_START + 3*sizeof(cbd_t))
+
+/* FIXME -- replace 0x2000 with offsetof */
+#define VPD_P ((vpd_t *)(CFG_IMMR + 0x2000 + CFG_DPRAMVPD))
+
+/* transmit/receive buffers */
+#define IIC_RX_LENGTH 128
+
+#define WITH_MICROCODE_PATCH
+
+vpd_packet_t * vpd_find_packet(u_char ident)
+{
+    vpd_packet_t *packet;
+    vpd_t *vpd = VPD_P;
+
+    packet = (vpd_packet_t *)&vpd->packets;
+    while ((packet->identifier != ident) && packet->identifier != 0xFF)
+    {
+       packet = (vpd_packet_t *)((char *)packet + packet->size + 2);
+    }
+    return packet;
+}
+
+void vpd_init(void)
+{
+    volatile immap_t  *im = (immap_t *)CFG_IMMR;
+    volatile cpm8xx_t *cp = &(im->im_cpm);
+    volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
+    volatile iic_t *iip;
+#ifdef WITH_MICROCODE_PATCH
+    ulong reloc = 0;
+#endif
+
+    iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+    /*
+     * kludge: when running from flash, no microcode patch can be
+     * installed. However, the DPMEM usually contains non-zero
+     * garbage at the relocatable patch base location, so lets clear
+     * it now. This way the rest of the code can support the microcode
+     * patch dynamically.
+     */
+    if ((ulong)vpd_init & 0xff000000)
+      iip->iic_rpbase = 0;
+
+#ifdef WITH_MICROCODE_PATCH
+    /* Check for and use a microcode relocation patch. */
+    if ((reloc = iip->iic_rpbase))
+      iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+    /* Initialize Port B IIC pins */
+    cp->cp_pbpar |= 0x00000030;
+    cp->cp_pbdir |= 0x00000030;
+    cp->cp_pbodr |= 0x00000030;
+
+    i2c->i2c_i2mod = 0x04;  /* filter clock */
+    i2c->i2c_i2add = 0x34;     /* select an arbitrary (unique) address */
+    i2c->i2c_i2brg = 0x07;  /* make clock run maximum slow     */
+    i2c->i2c_i2cmr = 0x00;  /* disable interrupts */
+    i2c->i2c_i2cer = 0x1f;  /* clear events */
+    i2c->i2c_i2com = 0x01;  /* configure i2c to work as master */
+
+    if (vpd_read(0xa4, (uchar*)VPD_P, VPD_EEPROM_SIZE, 0) != VPD_EEPROM_SIZE)
+    {
+       hang();
+    }
+}
+
+
+/* Read from I2C.
+ * This is a two step process.  First, we send the "dummy" write
+ * to set the device offset for the read.  Second, we perform
+ * the read operation.
+ */
+int vpd_read(uint iic_device, uchar *buf, int count, int offset)
+{
+    volatile immap_t  *im = (immap_t *)CFG_IMMR;
+    volatile cpm8xx_t *cp = &(im->im_cpm);
+    volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
+    volatile iic_t *iip;
+    volatile cbd_t *tbdf1, *tbdf2, *rbdf;
+    uchar *tb;
+    uchar event;
+#ifdef WITH_MICROCODE_PATCH
+    ulong reloc = 0;
+#endif
+
+    iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+#ifdef WITH_MICROCODE_PATCH
+    /* Check for and use a microcode relocation patch. */
+    if ((reloc = iip->iic_rpbase))
+      iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+    tbdf1 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX1];
+    tbdf2 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX2];
+    rbdf  = (cbd_t *)&cp->cp_dpmem[IIC_BD_RX];
+
+    /* Send a "dummy write" operation.  This is a write request with
+     * only the offset sent, followed by another start condition.
+     * This will ensure we start reading from the first location
+     * of the EEPROM.
+     */
+    tb = (uchar*)&cp->cp_dpmem[IIC_BD_FREE];
+    tb[0] = iic_device & 0xfe; /* device address */
+    tb[1] = offset;            /* offset */
+    tbdf1->cbd_bufaddr = (uint)tb;
+    tbdf1->cbd_datlen = 2;
+    tbdf1->cbd_sc = 0x8400;
+
+    tb += 2;
+    tb[0] = iic_device | 1;    /* device address */
+    tbdf2->cbd_bufaddr = (uint)tb;
+    tbdf2->cbd_datlen = count+1;
+    tbdf2->cbd_sc = 0xbc00;
+
+    rbdf->cbd_bufaddr = (uint)buf;
+    rbdf->cbd_datlen = 0;
+    rbdf->cbd_sc = 0xb000;
+
+    iip->iic_tbase = IIC_BD_TX1;
+    iip->iic_tbptr = IIC_BD_TX1;
+    iip->iic_rbase = IIC_BD_RX;
+    iip->iic_rbptr = IIC_BD_RX;
+    iip->iic_rfcr = 0x15;
+    iip->iic_tfcr = 0x15;
+    iip->iic_mrblr = count;
+    iip->iic_rstate = 0;
+    iip->iic_tstate = 0;
+
+    i2c->i2c_i2cer = 0x1f;  /* clear event mask */
+    i2c->i2c_i2mod |= 1;    /* enable iic operation */
+    i2c->i2c_i2com |= 0x80;    /* start master */
+
+    /* wait for IIC transfer */
+    do {
+       __asm__ volatile ("eieio");
+       event = i2c->i2c_i2cer;
+    } while (event == 0);
+
+    if ((event & 0x10) || (event & 0x04)) {
+       count = -1;
+       goto bailout;
+    }
+
+bailout:
+    i2c->i2c_i2mod &= ~1;   /* turn off iic operation */
+    i2c->i2c_i2cer = 0x1f;  /* clear event mask */
+
+    return count;
+}
diff --git a/board/mousse/flash.h b/board/mousse/flash.h
new file mode 100644 (file)
index 0000000..b7e4619
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef        FLASH_LIB_H
+#define        FLASH_LIB_H
+
+#include <common.h>
+
+/* PIO operations max */
+#define        FLASH_PROGRAM_POLLS             100000
+
+/* 10 Seconds default */
+#define        FLASH_ERASE_SECTOR_TIMEOUT      (10*1000 /*SEC*/ )
+
+/* Flash device info structure */
+typedef struct flash_dev_s {
+    char        name[24];               /* Bank Name */
+    int                bank;                   /* Bank 0 or 1 */
+    unsigned int base;                 /* Base address */
+    int                sectors;                /* Sector count */
+    int                lgSectorSize;           /* Log2(usable bytes/sector) */
+    int                vendorID;               /* Expected vendor ID */
+    int                deviceID;               /* Expected device ID */
+    int                found;                  /* Set if found by flashLibInit */
+    int                swap;                   /* Set for bank 1 if byte swap req'd */
+} flash_dev_t;
+
+#define FLASH_MAX_POS(dev) \
+       ((dev)->sectors << (dev)->lgSectorSize)
+
+#define FLASH_SECTOR_POS(dev, sector) \
+       ((sector) << (dev)->lgSectorSize)
+
+/* AMD 29F040 */
+#define FLASH0_BANK                    0
+#define FLASH0_VENDOR_ID               0x01
+#define FLASH0_DEVICE_ID               0x49
+
+/* AMD29LV160DB */
+#define FLASH1_BANK                    1
+#define FLASH1_VENDOR_ID               0x0001
+#define FLASH1_DEVICE_ID               0x2249
+
+extern flash_dev_t                     flashDev[];
+extern int                             flashDevCount;
+
+/*
+ * Device pointers
+ *
+ * These must be kept in sync with the table in flashLib.c.
+ */
+#define FLASH_DEV_BANK0_SA0            (&flashDev[0])
+#define FLASH_DEV_BANK0_SA1            (&flashDev[1])
+#define FLASH_DEV_BANK0_SA2            (&flashDev[2])
+#define FLASH_DEV_BANK0_LOW            (&flashDev[3]) /* 960K */
+#define FLASH_DEV_BANK0_BOOT           (&flashDev[4]) /* PLCC */
+#define FLASH_DEV_BANK0_HIGH           (&flashDev[5]) /* 512K PLCC shadow */
+
+unsigned long flash_init(void);
+int flashEraseSector(flash_dev_t *dev, int sector);
+int flashErase(flash_dev_t *dev);
+int flashRead(flash_dev_t *dev, int pos, char *buf, int len);
+int flashWrite(flash_dev_t *dev, int pos, char *buf, int len);
+int flashWritable(flash_dev_t *dev, int pos, int len);
+int flashDiag(flash_dev_t *dev);
+int flashDiagAll(void);
+
+ulong flash_get_size (vu_long *addr, flash_info_t *info);
+void flash_print_info  (flash_info_t *info);
+int  flash_erase (flash_info_t *info, int s_first, int s_last);
+int  write_buff  (flash_info_t *info, uchar *src, ulong addr, ulong cnt);
+
+/*
+ * Flash info indices.
+ */
+#define FLASH_BANK_KERNEL 0
+#define FLASH_BANK_BOOT   1
+#define FLASH_BANK_AUX    2
+#define FIRST_SECTOR      0
+
+#endif /* !FLASH_LIB_H */
diff --git a/board/mpc8260ads/flash.c b/board/mpc8260ads/flash.c
new file mode 100644 (file)
index 0000000..ec6a3b3
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001, Stuart Hughes, Lineo Inc, stuarth@lineo.com
+ * Add support the Sharp chips on the mpc8260ads.
+ * I started with board/ip860/flash.c and made changes I found in
+ * the MTD project by David Schleef.
+ *
+ * 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>
+
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static int clear_block_lock_bit(vu_long * addr);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+#ifndef CONFIG_MPC8260ADS
+       volatile immap_t        *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t    *memctl = &immap->im_memctl;
+       volatile ip860_bcsr_t   *bcsr   = (ip860_bcsr_t *)BCSR_BASE;
+#endif
+       unsigned long size;
+       int i;
+
+       /* Init: enable write,
+        * or we cannot even write flash commands
+        */
+#ifndef CONFIG_MPC8260ADS
+       bcsr->bd_ctrl |= BD_CTRL_FLWE;
+#endif
+
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+
+               /* set the default sector offset */
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size = flash_get_size((vu_long *)FLASH_BASE, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size, size<<20);
+       }
+#ifndef CONFIG_MPC8260ADS
+       /* Remap FLASH according to real size */
+       memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+       memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
+                               (memctl->memc_br1 & ~(BR_BA_MSK));
+#endif
+
+       /* Re-do sizing to get full correct info */
+       size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+       return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_INTEL:   printf ("Intel ");              break;
+       case FLASH_MAN_SHARP:   printf ("Sharp ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F016SV:    printf ("28F016SV (16 Mbit, 32 x 64k)\n");
+                               break;
+       case FLASH_28F160S3:    printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
+                               break;
+       case FLASH_28F320S3:    printf ("28F320S3 (32 Mbit, 64 x 512K)\n");
+                               break;
+       case FLASH_LH28F016SCT: printf ("28F016SC (16 Mbit, 32 x 64K)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+       ulong sector_offset;
+
+       /* Write "Intelligent Identifier" command: read Manufacturer ID */
+       *addr = 0x90909090;
+
+       value = addr[0] & 0x00FF00FF;
+       switch (value) {
+       case MT_MANUFACT:       /* SHARP, MT or => Intel */
+       case INTEL_ALT_MANU:
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+       default:
+               printf("unknown manufacturer: %x\n", (unsigned int)value);
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case (INTEL_ID_28F016S):
+               info->flash_id += FLASH_28F016SV;
+               info->sector_count = 32;
+               info->size = 0x00400000;
+               sector_offset = 0x20000;
+               break;                          /* => 2x2 MB            */
+
+       case (INTEL_ID_28F160S3):
+               info->flash_id += FLASH_28F160S3;
+               info->sector_count = 32;
+               info->size = 0x00400000;
+               sector_offset = 0x20000;
+               break;                          /* => 2x2 MB            */
+
+       case (INTEL_ID_28F320S3):
+               info->flash_id += FLASH_28F320S3;
+               info->sector_count = 64;
+               info->size = 0x00800000;
+               sector_offset = 0x20000;
+               break;                          /* => 2x4 MB            */
+
+       case SHARP_ID_28F016SCL:
+       case SHARP_ID_28F016SCZ:
+               info->flash_id      = FLASH_MAN_SHARP | FLASH_LH28F016SCT;
+               info->sector_count  = 32;
+               info->size          = 0x00800000;
+               sector_offset = 0x40000;
+               break;                          /* => 4x2 MB            */
+
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+       for (i = 0; i < info->sector_count; i++) {
+               info->start[i] = base;
+               base += sector_offset;
+               /* don't know how to check sector protection */
+               info->protect[i] = 0;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (vu_long *)info->start[0];
+
+               *addr = 0xFFFFFF;       /* reset bank to read array mode */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if (    ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL)
+            && ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_SHARP) ) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       /* Make Sure Block Lock Bit is not set. */
+       if(clear_block_lock_bit((vu_long *)(info->start[s_first]))){
+               return 1;
+       }
+
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       vu_long *addr = (vu_long *)(info->start[sect]);
+
+                       last = start = get_timer (0);
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       /* Reset Array */
+                       *addr = 0xffffffff;
+                       /* Clear Status Register */
+                       *addr = 0x50505050;
+                       /* Single Block Erase Command */
+                       *addr = 0x20202020;
+                       /* Confirm */
+                       *addr = 0xD0D0D0D0;
+
+                       if((info->flash_id & FLASH_TYPEMASK) != FLASH_LH28F016SCT) {
+                           /* Resume Command, as per errata update */
+                           *addr = 0xD0D0D0D0;
+                       }
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+                       while ((*addr & 0x80808080) != 0x80808080) {
+                               if(*addr & 0x20202020){
+                                       printf("Error in Block Erase - Lock Bit may be set!\n");
+                                       printf("Status Register = 0x%X\n", (uint)*addr);
+                                       *addr = 0xFFFFFFFF;     /* reset bank */
+                                       return 1;
+                               }
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = 0xFFFFFFFF;     /* reset bank */
+                                       return 1;
+                               }
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       /* reset to read mode */
+                       *addr = 0xFFFFFFFF;
+               }
+       }
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long *)dest;
+       ulong start, csr;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*addr & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       /* Write Command */
+       *addr = 0x10101010;
+
+       /* Write Data */
+       *addr = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       flag  = 0;
+       while (((csr = *addr) & 0x80808080) != 0x80808080) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       flag = 1;
+                       break;
+               }
+       }
+       if (csr & 0x40404040) {
+               printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
+               flag = 1;
+       }
+
+       /* Clear Status Registers Command */
+       *addr = 0x50505050;
+       /* Reset to read array mode */
+       *addr = 0xFFFFFFFF;
+
+       return (flag);
+}
+
+/*-----------------------------------------------------------------------
+ * Clear Block Lock Bit, returns:
+ * 0 - OK
+ * 1 - Timeout
+ */
+
+static int clear_block_lock_bit(vu_long  * addr)
+{
+       ulong start, now;
+
+       /* Reset Array */
+       *addr = 0xffffffff;
+       /* Clear Status Register */
+       *addr = 0x50505050;
+
+       *addr = 0x60606060;
+       *addr = 0xd0d0d0d0;
+
+       start = get_timer (0);
+       while(*addr != 0x80808080){
+               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout on clearing Block Lock Bit\n");
+                       *addr = 0xFFFFFFFF;     /* reset bank */
+                       return 1;
+               }
+       }
+       return 0;
+}
diff --git a/board/mpl/common/flash.c b/board/mpl/common/flash.c
new file mode 100644 (file)
index 0000000..f0c541b
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Modified 4/5/2001
+ * Wait for completion of each sector erase command issued
+ * 4/5/2001
+ * Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
+ */
+
+/*
+ * Modified 3/7/2001
+ * - adopted for pip405, Denis Peter, MPL AG Switzerland
+ * TODO:
+ * clean-up
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+#ifdef CONFIG_PIP405
+#include "../pip405/pip405.h"
+#endif
+#ifdef CONFIG_MIP405
+#include "../mip405/mip405.h"
+#endif
+#include "common_util.h"
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt);
+
+
+#ifdef CONFIG_ADCIOP
+#define ADDR0           0x0aa9
+#define ADDR1           0x0556
+#define FLASH_WORD_SIZE unsigned char
+#endif
+
+#ifdef CONFIG_CPCI405
+#define ADDR0           0x5555
+#define ADDR1           0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#ifdef CONFIG_PIP405
+#define ADDR0           0x5555
+#define ADDR1           0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#ifdef CONFIG_MIP405
+#define ADDR0           0x5555
+#define ADDR1           0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#define FALSE           0
+#define TRUE            1
+
+/*-----------------------------------------------------------------------
+ */
+
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+  unsigned long pbcr;
+  unsigned long base_b0, base_b1;
+  unsigned char rc;
+
+  rc=switch_cs(FALSE); /* map Flash High */
+
+       if(rc)
+               printf("(MPS Boot) ");
+       else
+               printf("(Flash Boot) ");
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+       /* Only one bank */
+       if (CFG_MAX_FLASH_BANKS == 1)
+         {
+           /* Setup offsets */
+                       /*  flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]); */
+           /* Monitor protection ON by default */
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+                   flash_protect(FLAG_PROTECT_SET,
+                               CFG_MONITOR_BASE,
+                               CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                               &flash_info[0]);
+#endif
+           size_b1 = 0 ;
+           flash_info[0].size = size_b0;
+         }
+
+       /* 2 banks */
+       else
+         {
+           size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+           /* Re-do sizing to get full correct info */
+
+           if (size_b1)
+             {
+               mtdcr(ebccfga, pb0cr);
+               pbcr = mfdcr(ebccfgd);
+               mtdcr(ebccfga, pb0cr);
+               base_b1 = -size_b1;
+               pbcr = (pbcr & 0x0001ffff) | base_b1 | (((size_b1/1024/1024)-1)<<17);
+               mtdcr(ebccfgd, pbcr);
+               /*          printf("pb1cr = %x\n", pbcr); */
+             }
+
+           if (size_b0)
+             {
+               mtdcr(ebccfga, pb1cr);
+               pbcr = mfdcr(ebccfgd);
+               mtdcr(ebccfga, pb1cr);
+               base_b0 = base_b1 - size_b0;
+               pbcr = (pbcr & 0x0001ffff) | base_b0 | (((size_b0/1024/1024)-1)<<17);
+               mtdcr(ebccfgd, pbcr);
+               /*            printf("pb0cr = %x\n", pbcr); */
+             }
+
+           size_b0 = flash_get_size((vu_long *)base_b0, &flash_info[0]);
+
+           flash_get_offsets (base_b0, &flash_info[0]);
+
+           /* monitor protection ON by default */
+           (void)flash_protect(FLAG_PROTECT_SET,
+                               base_b0+size_b0-CFG_MONITOR_LEN,
+                               base_b0+size_b0-1,
+                               &flash_info[0]);
+
+           if (size_b1) {
+             /* Re-do sizing to get full correct info */
+             size_b1 = flash_get_size((vu_long *)base_b1, &flash_info[1]);
+
+             flash_get_offsets (base_b1, &flash_info[1]);
+
+             /* monitor protection ON by default */
+             (void)flash_protect(FLAG_PROTECT_SET,
+                                 base_b1+size_b1-CFG_MONITOR_LEN,
+                                 base_b1+size_b1-1,
+                                 &flash_info[1]);
+             /* monitor protection OFF by default (one is enough) */
+             (void)flash_protect(FLAG_PROTECT_CLEAR,
+                                 base_b0+size_b0-CFG_MONITOR_LEN,
+                                 base_b0+size_b0-1,
+                                 &flash_info[0]);
+           } else {
+             flash_info[1].flash_id = FLASH_UNKNOWN;
+             flash_info[1].sector_count = -1;
+           }
+
+           flash_info[0].size = size_b0;
+           flash_info[1].size = size_b1;
+         }/* else 2 banks */
+       switch_cs(rc); /* switch mode back */
+       return (size_b0 + size_b1);
+}
+
+
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       return;
+}
+#if 0
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+  if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+           (info->flash_id  == FLASH_AM040)){
+               for (i = 0; i < info->sector_count; i++)
+                       info->start[i] = base + (i * 0x00010000);
+  }
+  else {
+               if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+               }
+           } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00004000;
+               info->start[i--] = base + info->size - 0x00006000;
+               info->start[i--] = base + info->size - 0x00008000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00010000;
+               }
+           }
+       }
+}
+
+#endif
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+    int k;
+       int size;
+    int erased;
+    volatile unsigned long *flash;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_INTEL:   printf ("Intel ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM040:       printf ("AM29F040 (512 Kbit, uniform sector size)\n");
+                               break;
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_SST800A:     printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
+                               break;
+       case FLASH_SST160A:     printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
+                               break;
+       case FLASH_INTEL320T:   printf ("TE28F320C3 (32 Mbit, top sector size)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld KB in %d Sectors\n",
+               info->size >> 10, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+       /*
+     * Check if whole sector is erased
+     */
+               if (i != (info->sector_count-1))
+       size = info->start[i+1] - info->start[i];
+               else
+      size = info->start[0] + info->size - info->start[i];
+    erased = 1;
+    flash = (volatile unsigned long *)info->start[i];
+    size = size >> 2;        /* divide by 4 for longword access */
+    for (k=0; k<size; k++)
+    {
+       if (*flash++ != 0xffffffff)
+                       {
+                               erased = 0;
+                               break;
+                       }
+               }
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+#if 0 /* test-only */
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+#else
+               printf (" %08lX%s%s",
+                       info->start[i],
+                       erased ? " E" : "  ",
+                       info->protect[i] ? "RO " : "   "
+#endif
+               );
+       }
+       printf ("\n");
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       FLASH_WORD_SIZE value;
+       ulong base = (ulong)addr;
+       volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+       addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+       addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
+
+       value = addr2[0];
+       /*      printf("flash_get_size value: %x\n",value); */
+       switch (value) {
+       case (FLASH_WORD_SIZE)AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (FLASH_WORD_SIZE)FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case (FLASH_WORD_SIZE)INTEL_MANUFACT:
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+       case (FLASH_WORD_SIZE)SST_MANUFACT:
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+       value = addr2[1];                       /* device ID            */
+       /*      printf("Device value %x\n",value); */
+       switch (value) {
+       case (FLASH_WORD_SIZE)AMD_ID_F040B:
+               info->flash_id += FLASH_AM040;
+               info->sector_count = 8;
+               info->size = 0x0080000; /* => 512 ko */
+               break;
+       case (FLASH_WORD_SIZE)AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 0.5 MB            */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00080000;
+               break;                          /* => 0.5 MB            */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+#if 0  /* enable when device IDs are available */
+       case (FLASH_WORD_SIZE)AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case (FLASH_WORD_SIZE)AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#endif
+       case (FLASH_WORD_SIZE)SST_ID_xF800A:
+               info->flash_id += FLASH_SST800A;
+               info->sector_count = 16;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+       case (FLASH_WORD_SIZE)INTEL_ID_28F320C3T:
+               info->flash_id += FLASH_INTEL320T;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+
+       case (FLASH_WORD_SIZE)SST_ID_xF160A:
+               info->flash_id += FLASH_SST160A;
+               info->sector_count = 32;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+  if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+           (info->flash_id  == FLASH_AM040)){
+               for (i = 0; i < info->sector_count; i++)
+                       info->start[i] = base + (i * 0x00010000);
+  } else {
+               if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00004000;
+               info->start[2] = base + 0x00006000;
+               info->start[3] = base + 0x00008000;
+               for (i = 4; i < info->sector_count; i++)
+                       info->start[i] = base + (i * 0x00010000) - 0x00030000;
+         }
+         else {
+                       /* set sector offsets for top boot block type           */
+                       i = info->sector_count - 1;
+                       if(info->sector_count==71) {
+
+                               info->start[i--] = base + info->size - 0x00002000;
+                               info->start[i--] = base + info->size - 0x00004000;
+                               info->start[i--] = base + info->size - 0x00006000;
+                               info->start[i--] = base + info->size - 0x00008000;
+                               info->start[i--] = base + info->size - 0x0000A000;
+                               info->start[i--] = base + info->size - 0x0000C000;
+                               info->start[i--] = base + info->size - 0x0000E000;
+                               for (; i >= 0; i--)
+                                       info->start[i] = base + i * 0x000010000;
+                       }
+                       else {
+                               info->start[i--] = base + info->size - 0x00004000;
+                               info->start[i--] = base + info->size - 0x00006000;
+                               info->start[i--] = base + info->size - 0x00008000;
+                               for (; i >= 0; i--)
+                                       info->start[i] = base + i * 0x00010000;
+                       }
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+       info->protect[i] = 0;
+      else
+        info->protect[i] = addr2[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+#if 0 /* test-only */
+#ifdef CONFIG_ADCIOP
+               addr2 = (volatile unsigned char *)info->start[0];
+                addr2[ADDR0] = 0xAA;
+                addr2[ADDR1] = 0x55;
+                addr2[ADDR0] = 0xF0;  /* reset bank */
+#else
+               addr2 = (FLASH_WORD_SIZE *)info->start[0];
+               *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
+#endif
+#else /* test-only */
+               addr2 = (FLASH_WORD_SIZE *)info->start[0];
+               *addr2 = (FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */
+#endif /* test-only */
+       }
+       return (info->size);
+}
+
+int wait_for_DQ7(flash_info_t *info, int sect)
+{
+       ulong start, now, last;
+       volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
+
+       start = get_timer (0);
+    last  = start;
+    while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
+        if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+            printf ("Timeout\n");
+            return -1;
+        }
+        /* show that we're waiting */
+        if ((now - last) > 1000) {  /* every second */
+                               putc ('.');
+            last = now;
+        }
+    }
+       return 0;
+}
+
+int intel_wait_for_DQ7(flash_info_t *info, int sect)
+{
+       ulong start, now, last;
+       volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
+
+               start = get_timer (0);
+    last  = start;
+    while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
+        if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+            printf ("Timeout\n");
+            return -1;
+        }
+        /* show that we're waiting */
+        if ((now - last) > 1000) {  /* every second */
+                               putc ('.');
+            last = now;
+        }
+    }
+    addr[0]=(FLASH_WORD_SIZE)0x00500050;
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
+       volatile FLASH_WORD_SIZE *addr2;
+       int flag, prot, sect, l_sect;
+       int i;
+
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("Can't erase unknown flash type - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
+                       /*  printf("Erasing sector %p\n", addr2); */ /* CLH */
+           if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+                               addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                               addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                               addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
+                               addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                               addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                               addr2[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
+                               for (i=0; i<50; i++)
+                                       udelay(1000);  /* wait 1 ms */
+                   wait_for_DQ7(info, sect);
+                 }
+                 else {
+                       if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+                                       addr2[0] = (FLASH_WORD_SIZE)0x00600060;  /* unlock sector */
+                                       addr2[0] = (FLASH_WORD_SIZE)0x00D000D0;  /* sector erase */
+                           intel_wait_for_DQ7(info, sect);
+                                       addr2[0] = (FLASH_WORD_SIZE)0x00200020;  /* sector erase */
+                                       addr2[0] = (FLASH_WORD_SIZE)0x00D000D0;  /* sector erase */
+                           intel_wait_for_DQ7(info, sect);
+                               }
+                               else {
+                                       addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                                       addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                                       addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
+                                       addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                                       addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                                       addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
+                           wait_for_DQ7(info, sect);
+                               }
+                }
+                l_sect = sect;
+                   /*
+                    * Wait for each sector to complete, it's more
+                    * reliable.  According to AMD Spec, you must
+                    * issue all erase commands within a specified
+                    * timeout.  This has been seen to fail, especially
+                    * if printf()s are included (for debug)!!
+                    */
+                /*   wait_for_DQ7(info, sect); */
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+#if 0
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+       wait_for_DQ7(info, l_sect);
+
+DONE:
+#endif
+       /* reset to read mode */
+       addr = (FLASH_WORD_SIZE *)info->start[0];
+       addr[0] = (FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt)
+{
+       int i;
+       volatile FLASH_WORD_SIZE *addr2;
+       long c;
+       c= (long)cnt;
+       for(i=info->sector_count-1;i>0;i--)
+       {
+               if(addr>=info->start[i])
+                       break;
+       }
+       do {
+               addr2 = (FLASH_WORD_SIZE *)(info->start[i]);
+               addr2[0] = (FLASH_WORD_SIZE)0x00600060;  /* unlock sector setup */
+               addr2[0] = (FLASH_WORD_SIZE)0x00D000D0;  /* unlock sector */
+               intel_wait_for_DQ7(info, i);
+               i++;
+               c-=(info->start[i]-info->start[i-1]);
+       }while(c>0);
+
+
+}
+
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+               unlock_intel_sectors(info,addr,cnt);
+       }
+       wp = (addr & ~3);       /* get lower word aligned address */
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               if((wp % 0x10000)==0)
+                       printf("."); /* show Progress */
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+       rc=write_word(info, wp, data);
+       return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static FLASH_WORD_SIZE *read_val = (FLASH_WORD_SIZE *)0x200000;
+
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)(info->start[0]);
+       volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
+       volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
+       ulong start;
+       int flag;
+       int i;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((volatile FLASH_WORD_SIZE *)dest) &
+               (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+       for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
+       {
+               if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+                       /* intel style writting */
+                       dest2[i] = (FLASH_WORD_SIZE)0x00500050;
+                       dest2[i] = (FLASH_WORD_SIZE)0x00400040;
+                       *read_val++ = data2[i];
+                       dest2[i] = data2[i];
+                       if (flag)
+                               enable_interrupts();
+                       /* data polling for D7 */
+                       start = get_timer (0);
+                       udelay(10);
+                       while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080)
+                       {
+                               if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
+                                       return (1);
+                       }
+                       dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
+                       udelay(10);
+                       dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
+                       if(dest2[i]!=data2[i])
+                               printf("Error at %p 0x%04X != 0x%04X\n",&dest2[i],dest2[i],data2[i]);
+               }
+               else {
+                       addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                       addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                       addr2[ADDR0] = (FLASH_WORD_SIZE)0x00A000A0;
+                       dest2[i] = data2[i];
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+                       /* data polling for D7 */
+                       start = get_timer (0);
+                       while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) !=
+                               (data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
+                               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                                       return (1);
+                               }
+                       }
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/mpl/common/isa.c b/board/mpl/common/isa.c
new file mode 100644 (file)
index 0000000..40731fc
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * 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
+ *
+ *
+ * TODO: clean-up
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <devices.h>
+#include "isa.h"
+#include "piix4_pci.h"
+#include "kbd.h"
+#include "video.h"
+
+extern int drv_isa_kbd_init (void);
+
+#undef ISA_DEBUG
+
+#ifdef ISA_DEBUG
+#define        PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#ifndef        TRUE
+#define TRUE            1
+#endif
+#ifndef FALSE
+#define FALSE           0
+#endif
+
+
+
+/* fdc (logical device 0) */
+const SIO_LOGDEV_TABLE sio_fdc[] = {
+       {0x60, 3},                      /* set IO to FDPort (3F0) */
+       {0x61, 0xF0},           /* set IO to FDPort (3F0) */
+       {0x70, 06},                     /* set IRQ 6 for FDPort */
+       {0x74, 02},                     /* set DMA 2 for FDPort */
+       {0xF0, 0x05},           /* set to PS2 type */
+       {0xF1, 0x00},     /* default value */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+/* paralell port (logical device 3) */
+const SIO_LOGDEV_TABLE sio_pport[] = {
+       {0x60, 3},                      /* set IO to PPort (378) */
+       {0x61, 0x78},           /* set IO to PPort (378) */
+       {0x70, 07},                     /* set IRQ 7 for PPort */
+       {0xF1, 00},                     /* set PPort to normal */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+/* paralell port (logical device 3) Floppy assigned to lpt */
+const SIO_LOGDEV_TABLE sio_pport_fdc[] = {
+       {0x60, 3},                      /* set IO to PPort (378) */
+       {0x61, 0x78},           /* set IO to PPort (378) */
+       {0x70, 07},                     /* set IRQ 7 for PPort */
+       {0xF1, 02},                     /* set PPort to Floppy */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+/* uart 1 (logical device 4) */
+const SIO_LOGDEV_TABLE sio_com1[] = {
+       {0x60, 3},                      /* set IO to COM1 (3F8) */
+       {0x61, 0xF8},           /* set IO to COM1 (3F8) */
+       {0x70, 04},                     /* set IRQ 4 for COM1 */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+/* uart 2 (logical device 5) */
+const SIO_LOGDEV_TABLE sio_com2[] = {
+       {0x60, 2},                      /* set IO to COM2 (2F8) */
+       {0x61, 0xF8},           /* set IO to COM2 (2F8) */
+       {0x70, 03},                     /* set IRQ 3 for COM2 */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+
+/* keyboard controller (logical device 7) */
+const SIO_LOGDEV_TABLE sio_keyboard[] = {
+       {0x70, 1},                      /* set IRQ 1 for keyboard */
+       {0x72, 12},                     /* set IRQ 12 for mouse */
+       {0xF0, 0},                      /* disable Port92 (this is a PowerPC!!) */
+       {0x30, 1},                      /* and activate the device */
+       {0xFF, 0}                               /* end of device table */
+};
+
+
+/*******************************************************************************
+* Config SuperIO FDC37C672
+********************************************************************************/
+unsigned char open_cfg_super_IO(int address)
+{
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,0x55); /* open config */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,0x20); /* set address to DEV ID */
+       if(in8(CFG_ISA_IO_BASE_ADDRESS | address | 0x1)==0x40) /* ok Device ID is correct */
+               return TRUE;
+       else
+               return FALSE;
+}
+
+void close_cfg_super_IO(int address)
+{
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,0xAA); /* close config */
+}
+
+
+unsigned char read_cfg_super_IO(int address, unsigned char function, unsigned char regaddr)
+{
+       /* assuming config reg is open */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
+       return in8(CFG_ISA_IO_BASE_ADDRESS | address | 1);
+}
+
+void write_cfg_super_IO(int address, unsigned char function, unsigned char regaddr, unsigned char data)
+{
+       /* assuming config reg is open */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
+       out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,data); /* writes the data */
+}
+
+void isa_write_table(SIO_LOGDEV_TABLE *ldt,unsigned char ldev)
+{
+       while (ldt->index != 0xFF) {
+               write_cfg_super_IO(SIO_CFG_PORT, ldev, ldt->index, ldt->val);
+               ldt++;
+       } /* endwhile */
+}
+
+void isa_sio_loadtable(void)
+{
+       unsigned char *s = getenv("floppy");
+       /* setup Floppy device 0*/
+       isa_write_table((SIO_LOGDEV_TABLE *)&sio_fdc,0);
+       /* setup parallel port device 3 */
+       if(s && !strncmp(s, "lpt", 3)) {
+               printf("SIO:   Floppy assigned to LPT\n");
+               /* floppy is assigned to the LPT */
+               isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport_fdc,3);
+       }
+       else {
+               /*printf("Floppy assigned to internal port\n");*/
+               isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport,3);
+       }
+       /* setup Com1 port device 4 */
+       isa_write_table((SIO_LOGDEV_TABLE *)&sio_com1,4);
+       /* setup Com2 port device 5 */
+       isa_write_table((SIO_LOGDEV_TABLE *)&sio_com2,5);
+       /* setup keyboards device 7 */
+       isa_write_table((SIO_LOGDEV_TABLE *)&sio_keyboard,7);
+}
+
+
+void isa_sio_setup(void)
+{
+       if(open_cfg_super_IO(SIO_CFG_PORT)==TRUE)
+       {
+               isa_sio_loadtable();
+               close_cfg_super_IO(0x3F0);
+       }
+}
+
+
+
+/******************************************************************************
+ * IRQ Controller
+ * we use the Vector mode
+ */
+
+struct isa_irq_action {
+        interrupt_handler_t *handler;
+        void *arg;
+        int count;
+};
+
+static struct isa_irq_action isa_irqs[16];
+
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_imr1    (unsigned char)cached_irq_mask
+#define cached_imr2    (unsigned char)(cached_irq_mask>>8)
+#define IMR_1          CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_OCW1
+#define IMR_2          CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_OCW1
+#define ICW1_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW1
+#define ICW1_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW1
+#define ICW2_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW2
+#define ICW2_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW2
+#define ICW3_1 ICW2_1
+#define ICW3_2 ICW2_2
+#define ICW4_1 ICW2_1
+#define ICW4_2 ICW2_2
+#define ISR_1          ICW1_1
+#define ISR_2          ICW1_2
+
+
+void disable_8259A_irq(unsigned int irq)
+{
+       unsigned int mask = 1 << irq;
+
+       cached_irq_mask |= mask;
+       if (irq & 8)
+               out8(IMR_2,cached_imr2);
+       else
+               out8(IMR_1,cached_imr1);
+}
+
+void enable_8259A_irq(unsigned int irq)
+{
+       unsigned int mask = ~(1 << irq);
+
+       cached_irq_mask &= mask;
+       if (irq & 8)
+               out8(IMR_2,cached_imr2);
+       else
+               out8(IMR_1,cached_imr1);
+}
+/*
+int i8259A_irq_pending(unsigned int irq)
+{
+       unsigned int mask = 1<<irq;
+       int ret;
+
+       if (irq < 8)
+               ret = inb(0x20) & mask;
+       else
+               ret = inb(0xA0) & (mask >> 8);
+       spin_unlock_irqrestore(&i8259A_lock, flags);
+
+       return ret;
+}
+*/
+
+/*
+ * This function assumes to be called rarely. Switching between
+ * 8259A registers is slow.
+ */
+int i8259A_irq_real(unsigned int irq)
+{
+       int value;
+       int irqmask = 1<<irq;
+
+       if (irq < 8) {
+               out8(ISR_1,0x0B);               /* ISR register */
+               value = in8(ISR_1) & irqmask;
+               out8(ISR_1,0x0A);               /* back to the IRR register */
+               return value;
+       }
+       out8(ISR_2,0x0B);               /* ISR register */
+       value = in8(ISR_2) & (irqmask >> 8);
+       out8(ISR_2,0x0A);               /* back to the IRR register */
+       return value;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void mask_and_ack_8259A(unsigned int irq)
+{
+       unsigned int irqmask = 1 << irq;
+       unsigned int temp_irqmask = cached_irq_mask;
+       /*
+        * Lightweight spurious IRQ detection. We do not want
+        * to overdo spurious IRQ handling - it's usually a sign
+        * of hardware problems, so we only do the checks we can
+        * do without slowing down good hardware unnecesserily.
+        *
+        * Note that IRQ7 and IRQ15 (the two spurious IRQs
+        * usually resulting from the 8259A-1|2 PICs) occur
+        * even if the IRQ is masked in the 8259A. Thus we
+        * can check spurious 8259A IRQs without doing the
+        * quite slow i8259A_irq_real() call for every IRQ.
+        * This does not cover 100% of spurious interrupts,
+        * but should be enough to warn the user that there
+        * is something bad going on ...
+        */
+       if (temp_irqmask & irqmask)
+               goto spurious_8259A_irq;
+       temp_irqmask |= irqmask;
+
+handle_real_irq:
+       if (irq & 8) {
+               in8(IMR_2);             /* DUMMY - (do we need this?) */
+               out8(IMR_2,(unsigned char)(temp_irqmask>>8));
+               out8(ISR_2,0x60+(irq&7));/* 'Specific EOI' to slave */
+               out8(ISR_1,0x62);       /* 'Specific EOI' to master-IRQ2 */
+               out8(IMR_2,cached_imr2); /* turn it on again */
+       } else {
+               in8(IMR_1);             /* DUMMY - (do we need this?) */
+               out8(IMR_1,(unsigned char)temp_irqmask);
+               out8(ISR_1,0x60+irq);   /* 'Specific EOI' to master */
+               out8(IMR_1,cached_imr1); /* turn it on again */
+       }
+
+       return;
+
+spurious_8259A_irq:
+       /*
+        * this is the slow path - should happen rarely.
+        */
+       if (i8259A_irq_real(irq))
+               /*
+                * oops, the IRQ _is_ in service according to the
+                * 8259A - not spurious, go handle it.
+                */
+               goto handle_real_irq;
+
+       {
+               static int spurious_irq_mask;
+               /*
+                * At this point we can be sure the IRQ is spurious,
+                * lets ACK and report it. [once per IRQ]
+                */
+               if (!(spurious_irq_mask & irqmask)) {
+                       PRINTF("spurious 8259A interrupt: IRQ%d.\n", irq);
+                       spurious_irq_mask |= irqmask;
+               }
+               /* irq_err_count++; */
+               /*
+                * Theoretically we do not have to handle this IRQ,
+                * but in Linux this does not cause problems and is
+                * simpler for us.
+                */
+               goto handle_real_irq;
+       }
+}
+
+void init_8259A(void)
+{
+       out8(IMR_1,0xff);       /* mask all of 8259A-1 */
+       out8(IMR_2,0xff);       /* mask all of 8259A-2 */
+
+       out8(ICW1_1,0x11);      /* ICW1: select 8259A-1 init */
+       out8(ICW2_1,0x20 + 0);  /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+       out8(ICW3_1,0x04);      /* 8259A-1 (the master) has a slave on IR2 */
+       out8(ICW4_1,0x01);      /* master expects normal EOI */
+       out8(ICW1_2,0x11);      /* ICW2: select 8259A-2 init */
+       out8(ICW2_2,0x20 + 8);  /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+       out8(ICW3_2,0x02);      /* 8259A-2 is a slave on master's IR2 */
+       out8(ICW4_2,0x01);      /* (slave's support for AEOI in flat mode
+                                   is to be investigated) */
+       udelay(10000);          /* wait for 8259A to initialize */
+       out8(IMR_1,cached_imr1);        /* restore master IRQ mask */
+       udelay(10000);          /* wait for 8259A to initialize */
+       out8(IMR_2,cached_imr2);        /* restore slave IRQ mask */
+}
+
+
+#define PCI_INT_ACK_ADDR 0xEED00000
+
+int handle_isa_int(void)
+{
+       unsigned long irqack;
+       unsigned char isr1,isr2,irq;
+       /* first we acknokledge the int via the PCI bus */
+       irqack=in32(PCI_INT_ACK_ADDR);
+       /* now we get the ISRs */
+       isr2=in8(ISR_2);
+       isr1=in8(ISR_1);
+       irq=(unsigned char)irqack;
+       if((irq==7)&&((isr1&0x80)==0)) {
+               PRINTF("IRQ7 detected but not in ISR\n");
+       }
+       else {
+               /* we should handle cascaded interrupts here also */
+               /* printf("ISA Irq %d\n",irq); */
+               isa_irqs[irq].count++;
+       if (isa_irqs[irq].handler != NULL)
+               (*isa_irqs[irq].handler)(isa_irqs[irq].arg);      /* call isr */
+       else
+       {
+       PRINTF ("bogus interrupt vector 0x%x\n", irq);
+       }
+       }
+       /* issue EOI instruction to clear the IRQ */
+       mask_and_ack_8259A(irq);
+       return 0;
+}
+
+
+
+/******************************************************************
+ * Install and free an ISA interrupt handler.
+ */
+
+void isa_irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+  if (isa_irqs[vec].handler != NULL) {
+   printf ("ISA Interrupt vector %d: handler 0x%x replacing 0x%x\n",
+           vec, (uint)handler, (uint)isa_irqs[vec].handler);
+  }
+  isa_irqs[vec].handler = handler;
+  isa_irqs[vec].arg     = arg;
+  enable_8259A_irq(vec);
+       PRINTF ("Install ISA IRQ %d ==> %p, @ %p mask=%04x\n", vec, handler, &isa_irqs[vec].handler,cached_irq_mask);
+
+}
+
+void isa_irq_free_handler(int vec)
+{
+       disable_8259A_irq(vec);
+  isa_irqs[vec].handler = NULL;
+  isa_irqs[vec].arg     = NULL;
+       printf ("Free ISA IRQ %d mask=%04x\n", vec, cached_irq_mask);
+
+}
+
+/****************************************************************************/
+void isa_init_irq_contr(void)
+{
+       int i;
+       /* disable all Interrupts */
+       /* first write icws controller 1 */
+       for(i=0;i<16;i++)
+       {
+               isa_irqs[i].handler=NULL;
+               isa_irqs[i].arg=NULL;
+               isa_irqs[i].count=0;
+       }
+       init_8259A();
+       out8(IMR_2,0xFF);
+}
+
+
+/******************************************************************
+ * Init the ISA bus and devices.
+ */
+
+
+int isa_init(void)
+{
+       isa_sio_setup();
+       drv_isa_kbd_init();
+       return 0;
+}
+
+
+
diff --git a/board/mpl/common/kbd.c b/board/mpl/common/kbd.c
new file mode 100644 (file)
index 0000000..5b87cdb
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Source partly derived from:
+ * linux/drivers/char/pc_keyb.c
+ *
+ *
+ */
+#include <common.h>
+#include <asm/processor.h>
+#include <devices.h>
+#include "isa.h"
+#include "kbd.h"
+
+
+unsigned char kbd_read_status(void);
+unsigned char kbd_read_input(void);
+void kbd_send_data(unsigned char data);
+void disable_8259A_irq(unsigned int irq);
+void enable_8259A_irq(unsigned int irq);
+
+/* used only by send_data - set by keyboard_interrupt */
+
+
+#undef KBG_DEBUG
+
+#ifdef KBG_DEBUG
+#define        PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#define KBD_STAT_KOBF          0x01
+#define KBD_STAT_IBF           0x02
+#define KBD_STAT_SYS           0x04
+#define KBD_STAT_CD                    0x08
+#define KBD_STAT_LOCK          0x10
+#define KBD_STAT_MOBF          0x20
+#define KBD_STAT_TI_OUT        0x40
+#define KBD_STAT_PARERR        0x80
+
+#define KBD_INIT_TIMEOUT 1000          /* Timeout in ms for initializing the keyboard */
+#define KBC_TIMEOUT 250                        /* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 2000               /* Timeout in ms for keyboard command acknowledge */
+/*
+ *     Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE                     0x20    /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE                    0x60    /* Write mode bits */
+#define KBD_CCMD_GET_VERSION           0xA1    /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7    /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE          0xA8    /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE                    0xA9    /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST                     0xAA    /* Controller self test */
+#define KBD_CCMD_KBD_TEST                              0xAB    /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE           0xAD    /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE                    0xAE    /* Keyboard interface enable */
+#define KBD_CCMD_WRITE_AUX_OBUF        0xD3    /* Write to output buffer as if
+                                          initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE           0xD4    /* Write the following byte to the mouse */
+
+/*
+ *     Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS                               0xED    /* Set keyboard leds */
+#define KBD_CMD_SET_RATE                               0xF3    /* Set typematic rate */
+#define KBD_CMD_ENABLE                                 0xF4    /* Enable scanning */
+#define KBD_CMD_DISABLE                                        0xF5    /* Disable scanning */
+#define KBD_CMD_RESET                                          0xFF    /* Reset */
+
+/*
+ *     Keyboard Replies
+ */
+
+#define KBD_REPLY_POR                                          0xAA    /* Power on reset */
+#define KBD_REPLY_ACK                                          0xFA    /* Command ACK */
+#define KBD_REPLY_RESEND                               0xFE    /* Command NACK, send the cmd again */
+
+/*
+ *     Status Register Bits
+ */
+
+#define KBD_STAT_OBF                                           0x01    /* Keyboard output buffer full */
+#define KBD_STAT_IBF                                           0x02    /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST                              0x04    /* Self test successful */
+#define KBD_STAT_CMD                                           0x08    /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED                              0x10    /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF                     0x20    /* Mouse output buffer full */
+#define KBD_STAT_GTO                                           0x40    /* General receive/xmit timeout */
+#define KBD_STAT_PERR                                  0x80    /* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ *     Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT                               0x01    /* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT                     0x02    /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS                                           0x04    /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK                    0x08    /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD           0x10    /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20    /* Disable mouse interface */
+#define KBD_MODE_KCC                                           0x40    /* Scan code conversion to PC format */
+#define KBD_MODE_RFU                                           0x80
+
+
+#define KDB_DATA_PORT                  0x60
+#define KDB_COMMAND_PORT       0x64
+
+#define        LED_SCR         0x01    /* scroll lock led */
+#define        LED_CAP         0x04    /* caps lock led */
+#define        LED_NUM         0x02    /* num lock led */
+
+#define        KBD_BUFFER_LEN 0x20  /* size of the keyboardbuffer */
+
+
+
+
+static volatile char kbd_buffer[KBD_BUFFER_LEN];
+static volatile int in_pointer = 0;
+static volatile int out_pointer = 0;
+
+
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+static unsigned char shift = 0;
+static unsigned char ctrl = 0;
+static unsigned char alt = 0;
+static unsigned char e0 = 0;
+static unsigned char leds = 0;
+
+#define DEVNAME "kbd"
+
+/* Simple translation table for the keys */
+
+static unsigned char kbd_plain_xlate[] = {
+       0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t',        /* 0x00 - 0x0f */
+        'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's',        /* 0x10 - 0x1f */
+        'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v',        /* 0x20 - 0x2f */
+        'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
+        '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
+       '\r',0xff,0xff
+       };
+
+static unsigned char kbd_shift_xlate[] = {
+       0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t',        /* 0x00 - 0x0f */
+        'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S',        /* 0x10 - 0x1f */
+        'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V',        /* 0x20 - 0x2f */
+        'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
+        '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
+       '\r',0xff,0xff
+       };
+
+static unsigned char kbd_ctrl_xlate[] = {
+       0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t',        /* 0x00 - 0x0f */
+       0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13,        /* 0x10 - 0x1f */
+       0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16,        /* 0x20 - 0x2f */
+       0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,        /* 0x30 - 0x3f */
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1',        /* 0x40 - 0x4f */
+        '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,  /* 0x50 - 0x5F */
+       '\r',0xff,0xff
+       };
+
+/******************************************************************
+ * Init
+ ******************************************************************/
+int isa_kbd_init(void)
+{
+       char* result;
+       result=kbd_initialize();
+       if(result==NULL) {
+               PRINTF("AT Keyboard initialized\n");
+               irq_install_handler(25, (interrupt_handler_t *)handle_isa_int, NULL);
+               isa_irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
+               return (1);
+       }
+       else {
+               printf("%s\n",result);
+               return (-1);
+       }
+}
+
+#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+       return (0);
+}
+#endif
+
+int drv_isa_kbd_init (void)
+{
+       int error;
+       device_t kbddev ;
+       char *stdinname  = getenv ("stdin");
+
+       if(isa_kbd_init()==-1)
+               return -1;
+       memset (&kbddev, 0, sizeof(kbddev));
+       strcpy(kbddev.name, DEVNAME);
+       kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+       kbddev.putc = NULL ;
+       kbddev.puts = NULL ;
+       kbddev.getc = kbd_getc ;
+       kbddev.tstc = kbd_testc ;
+
+       error = device_register (&kbddev);
+       if(error==0) {
+               /* check if this is the standard input device */
+               if(strcmp(stdinname,DEVNAME)==0) {
+                       /* reassign the console */
+                       if(overwrite_console()) {
+                               return 1;
+                       }
+                       error=console_assign(stdin,DEVNAME);
+                       if(error==0)
+                               return 1;
+                       else
+                               return error;
+               }
+               return 1;
+       }
+       return error;
+}
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+void kbd_put_queue(char data)
+{
+       if((in_pointer+1)==KBD_BUFFER_LEN) {
+               if(out_pointer==0) {
+                       return; /* buffer full */
+               } else{
+                       in_pointer=0;
+               }
+       } else {
+               if((in_pointer+1)==out_pointer)
+                       return; /* buffer full */
+               in_pointer++;
+       }
+       kbd_buffer[in_pointer]=data;
+       return;
+}
+
+/* test if a character is in the queue */
+int kbd_testc(void)
+{
+       if(in_pointer==out_pointer)
+               return(0); /* no data */
+       else
+               return(1);
+}
+/* gets the character from the queue */
+int kbd_getc(void)
+{
+       char c;
+       while(in_pointer==out_pointer);
+       if((out_pointer+1)==KBD_BUFFER_LEN)
+               out_pointer=0;
+       else
+               out_pointer++;
+       c=kbd_buffer[out_pointer];
+       return (int)c;
+
+}
+
+
+/* set LEDs */
+
+void kbd_set_leds(void)
+{
+       if(caps_lock==0)
+               leds&=~LED_CAP; /* switch caps_lock off */
+       else
+               leds|=LED_CAP; /* switch on LED */
+       if(num_lock==0)
+               leds&=~LED_NUM; /* switch LED off */
+       else
+               leds|=LED_NUM;  /* switch on LED */
+       if(scroll_lock==0)
+               leds&=~LED_SCR; /* switch LED off */
+       else
+               leds|=LED_SCR; /* switch on LED */
+       kbd_send_data(KBD_CMD_SET_LEDS);
+       kbd_send_data(leds);
+}
+
+
+void handle_keyboard_event(unsigned char scancode)
+{
+       unsigned char keycode;
+
+       /*  Convert scancode to keycode */
+       PRINTF("scancode %x\n",scancode);
+       if(scancode==0xe0) {
+               e0=1; /* special charakters */
+               return;
+       }
+       if(e0==1) {
+               e0=0; /* delete flag */
+               if(!(   ((scancode&0x7F)==0x38)|| /* the right ctrl key */
+                                       ((scancode&0x7F)==0x1D)|| /* the right alt key */
+                                       ((scancode&0x7F)==0x35)||       /* the right '/' key */
+                                       ((scancode&0x7F)==0x1C) ))  /* the right enter key */
+                       /* we swallow unknown e0 codes */
+                       return;
+       }
+       /* special cntrl keys */
+       switch(scancode)
+       {
+               case 0x2A:
+               case 0x36: /* shift pressed */
+                       shift=1;
+                       return; /* do nothing else */
+               case 0xAA:
+               case 0xB6: /* shift released */
+                       shift=0;
+                       return; /* do nothing else */
+               case 0x38: /* alt pressed */
+                       alt=1;
+                       return; /* do nothing else */
+               case 0xB8: /* alt released */
+                       alt=0;
+                       return; /* do nothing else */
+               case 0x1d: /* ctrl pressed */
+                       ctrl=1;
+                       return; /* do nothing else */
+               case 0x9d: /* ctrl released */
+                       ctrl=0;
+                       return; /* do nothing else */
+               case 0x46: /* scrollock pressed */
+                       scroll_lock=~scroll_lock;
+                       kbd_set_leds();
+                       return; /* do nothing else */
+               case 0x3A: /* capslock pressed */
+                       caps_lock=~caps_lock;
+                       kbd_set_leds();
+                       return;
+               case 0x45: /* numlock pressed */
+                       num_lock=~num_lock;
+                       kbd_set_leds();
+                       return;
+               case 0xC6: /* scroll lock released */
+               case 0xC5: /* num lock released */
+               case 0xBA: /* caps lock released */
+                       return; /* just swallow */
+       }
+       if((scancode&0x80)==0x80) /* key released */
+               return;
+       /* now, decide which table we need */
+       if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
+               PRINTF("unkown scancode %X\n",scancode);
+               return; /* swallow it */
+       }
+       /* setup plain code first */
+       keycode=kbd_plain_xlate[scancode];
+       if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
+               if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+                       PRINTF("unkown caps-locked scancode %X\n",scancode);
+                       return; /* swallow it */
+               }
+               keycode=kbd_shift_xlate[scancode];
+               if(keycode<'A') { /* we only want the alphas capital */
+                       keycode=kbd_plain_xlate[scancode];
+               }
+       }
+       if(shift==1) { /* shift overwrites caps_lock */
+               if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+                       PRINTF("unkown shifted scancode %X\n",scancode);
+                       return; /* swallow it */
+               }
+               keycode=kbd_shift_xlate[scancode];
+       }
+       if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
+               if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
+                       PRINTF("unkown ctrl scancode %X\n",scancode);
+                       return; /* swallow it */
+               }
+               keycode=kbd_ctrl_xlate[scancode];
+       }
+       /* check if valid keycode */
+       if(keycode==0xff) {
+               PRINTF("unkown scancode %X\n",scancode);
+               return; /* swallow unknown codes */
+       }
+
+       kbd_put_queue(keycode);
+       PRINTF("%x\n",keycode);
+}
+
+/*
+ * This reads the keyboard status port, and does the
+ * appropriate action.
+ *
+ */
+unsigned char handle_kbd_event(void)
+{
+       unsigned char status = kbd_read_status();
+       unsigned int work = 10000;
+
+       while ((--work > 0) && (status & KBD_STAT_OBF)) {
+               unsigned char scancode;
+
+               scancode = kbd_read_input();
+
+               /* Error bytes must be ignored to make the
+                  Synaptics touchpads compaq use work */
+               /* Ignore error bytes */
+               if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
+               {
+                       if (status & KBD_STAT_MOUSE_OBF)
+                               ; /* not supported: handle_mouse_event(scancode); */
+                       else
+                               handle_keyboard_event(scancode);
+               }
+               status = kbd_read_status();
+       }
+       if (!work)
+               PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
+       return status;
+}
+
+
+
+/******************************************************************************
+ * Lowlevel Part of keyboard section
+ */
+unsigned char kbd_read_status(void)
+{
+       return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
+}
+
+unsigned char kbd_read_input(void)
+{
+       return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
+}
+
+void kbd_write_command(unsigned char cmd)
+{
+       out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
+}
+
+void kbd_write_output(unsigned char data)
+{
+       out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
+}
+
+int kbd_read_data(void)
+{
+       int val;
+       unsigned char status;
+
+       val=-1;
+       status = kbd_read_status();
+       if (status & KBD_STAT_OBF) {
+               val = kbd_read_input();
+               if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+                       val = -2;
+       }
+       return val;
+}
+
+int kbd_wait_for_input(void)
+{
+       unsigned long timeout;
+       int val;
+
+       timeout = KBD_TIMEOUT;
+       val=kbd_read_data();
+       while(val < 0)
+       {
+               if(timeout--==0)
+                       return -1;
+               udelay(1000);
+               val=kbd_read_data();
+       }
+       return val;
+}
+
+
+int kb_wait(void)
+{
+       unsigned long timeout = KBC_TIMEOUT * 10;
+
+       do {
+               unsigned char status = handle_kbd_event();
+               if (!(status & KBD_STAT_IBF))
+                       return 0; /* ok */
+               udelay(1000);
+               timeout--;
+       } while (timeout);
+       return 1;
+}
+
+void kbd_write_command_w(int data)
+{
+       if(kb_wait())
+               PRINTF("timeout in kbd_write_command_w\n");
+       kbd_write_command(data);
+}
+
+void kbd_write_output_w(int data)
+{
+       if(kb_wait())
+               PRINTF("timeout in kbd_write_output_w\n");
+       kbd_write_output(data);
+}
+
+void kbd_send_data(unsigned char data)
+{
+       unsigned char status;
+       disable_8259A_irq(1); /* disable interrupt */
+       kbd_write_output_w(data);
+       status = kbd_wait_for_input();
+       if (status == KBD_REPLY_ACK)
+               enable_8259A_irq(1); /* enable interrupt */
+}
+
+
+char * kbd_initialize(void)
+{
+       int status;
+
+       in_pointer = 0; /* delete in Buffer */
+       out_pointer = 0;
+       /*
+        * Test the keyboard interface.
+        * This seems to be the only way to get it going.
+        * If the test is successful a x55 is placed in the input buffer.
+        */
+       kbd_write_command_w(KBD_CCMD_SELF_TEST);
+       if (kbd_wait_for_input() != 0x55)
+               return "Kbd:   failed self test";
+       /*
+        * Perform a keyboard interface test.  This causes the controller
+        * to test the keyboard clock and data lines.  The results of the
+        * test are placed in the input buffer.
+        */
+       kbd_write_command_w(KBD_CCMD_KBD_TEST);
+       if (kbd_wait_for_input() != 0x00)
+               return "Kbd:   interface failed self test";
+       /*
+        * Enable the keyboard by allowing the keyboard clock to run.
+        */
+       kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
+       status = kbd_wait_for_input();
+       /*
+        * Reset keyboard. If the read times out
+        * then the assumption is that no keyboard is
+        * plugged into the machine.
+        * This defaults the keyboard to scan-code set 2.
+        *
+        * Set up to try again if the keyboard asks for RESEND.
+        */
+       do {
+               kbd_write_output_w(KBD_CMD_RESET);
+               status = kbd_wait_for_input();
+               if (status == KBD_REPLY_ACK)
+                       break;
+               if (status != KBD_REPLY_RESEND)
+               {
+                       PRINTF("status: %X\n",status);
+                       return "Kbd:   reset failed, no ACK";
+               }
+       } while (1);
+       if (kbd_wait_for_input() != KBD_REPLY_POR)
+               return "Kbd:   reset failed, no POR";
+
+       /*
+        * Set keyboard controller mode. During this, the keyboard should be
+        * in the disabled state.
+        *
+        * Set up to try again if the keyboard asks for RESEND.
+        */
+       do {
+               kbd_write_output_w(KBD_CMD_DISABLE);
+               status = kbd_wait_for_input();
+               if (status == KBD_REPLY_ACK)
+                       break;
+               if (status != KBD_REPLY_RESEND)
+                       return "Kbd:   disable keyboard: no ACK";
+       } while (1);
+
+       kbd_write_command_w(KBD_CCMD_WRITE_MODE);
+       kbd_write_output_w(KBD_MODE_KBD_INT
+                             | KBD_MODE_SYS
+                             | KBD_MODE_DISABLE_MOUSE
+                             | KBD_MODE_KCC);
+
+       /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+       kbd_write_command_w(KBD_CCMD_READ_MODE);
+       if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+               /*
+                * If the controller does not support conversion,
+                * Set the keyboard to scan-code set 1.
+                */
+               kbd_write_output_w(0xF0);
+               kbd_wait_for_input();
+               kbd_write_output_w(0x01);
+               kbd_wait_for_input();
+       }
+       kbd_write_output_w(KBD_CMD_ENABLE);
+       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+               return "Kbd:   enable keyboard: no ACK";
+
+       /*
+        * Finally, set the typematic rate to maximum.
+        */
+       kbd_write_output_w(KBD_CMD_SET_RATE);
+       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+               return "Kbd:   Set rate: no ACK";
+       kbd_write_output_w(0x00);
+       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+               return "Kbd:   Set rate: no ACK";
+       return NULL;
+}
+
+void kbd_interrupt(void)
+{
+       handle_kbd_event();
+}
+
+
+
+/* eof */
+
diff --git a/board/mpl/common/usb_uhci.c b/board/mpl/common/usb_uhci.c
new file mode 100644 (file)
index 0000000..83624a9
--- /dev/null
@@ -0,0 +1,1152 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * 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
+ *
+ * Note: Part of this code has been derived from linux
+ *
+ */
+
+/**********************************************************************
+ * How it works:
+ * -------------
+ * The framelist / Transfer descriptor / Queue Heads are similar like
+ * in the linux usb_uhci.c.
+ *
+ * During initialization, the following skeleton is allocated in init_skel:
+ *
+ *         framespecific           |           common chain
+ *
+ * framelist[]
+ * [  0 ]-----> TD ---------\
+ * [  1 ]-----> TD ----------> TD ------> QH -------> QH -------> QH ---> NULL
+ *   ...        TD ---------/
+ * [1023]-----> TD --------/
+ *
+ *              ^^             ^^         ^^          ^^          ^^
+ *              7 TDs for      1 TD for   Start of    Start of    End Chain
+ *              INT (2-128ms)  1ms-INT    CTRL Chain  BULK Chain
+ *
+ *
+ * Since this is a bootloader, the isochronous transfer descriptor have been removed.
+ *
+ * Interrupt Transfers.
+ * --------------------
+ * For Interupt transfers USB_MAX_TEMP_INT_TD Transfer descriptor are available. They
+ * will be inserted after the appropriate (depending the interval setting) skeleton TD.
+ * If an interrupt has been detected the dev->irqhandler is called. The status and number
+ * of transfered bytes is stored in dev->irq_status resp. dev->irq_act_len. If the
+ * dev->irqhandler returns 0, the interrupt TD is removed and disabled. If an 1 is returned,
+ * the interrupt TD will be reactivated.
+ *
+ * Control Transfers
+ * -----------------
+ * Control Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_cntrl queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ * Bulk Transfers
+ * --------------
+ * Bulk Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_bulk queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ *
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#ifdef CONFIG_USB_UHCI
+
+#include <usb.h>
+#include "usb_uhci.h"
+
+#define USB_MAX_TEMP_TD      128  /* number of temporary TDs for bulk and control transfers */
+#define USB_MAX_TEMP_INT_TD  32   /* number of temporary TDs for Interrupt transfers */
+
+
+#undef USB_UHCI_DEBUG
+
+#ifdef USB_UHCI_DEBUG
+#define        USB_UHCI_PRINTF(fmt,args...)    printf (fmt ,##args)
+#else
+#define USB_UHCI_PRINTF(fmt,args...)
+#endif
+
+
+static int irqvec = -1;            /* irq vector, if -1 uhci is stopped / reseted */
+unsigned int usb_base_addr;       /* base address */
+
+static uhci_td_t td_int[8];        /* Interrupt Transfer descriptors */
+static uhci_qh_t qh_cntrl;         /* control Queue Head */
+static uhci_qh_t qh_bulk;          /*  bulk Queue Head */
+static uhci_qh_t qh_end;           /* end Queue Head */
+static uhci_td_t td_last;          /* last TD (linked with end chain) */
+
+/* temporary tds */
+static uhci_td_t tmp_td[USB_MAX_TEMP_TD];          /* temporary bulk/control td's  */
+static uhci_td_t tmp_int_td[USB_MAX_TEMP_INT_TD];  /* temporary interrupt td's  */
+
+static unsigned long framelist[1024] __attribute__ ((aligned (0x1000))); /* frame list */
+
+static struct virt_root_hub rh;   /* struct for root hub */
+
+/**********************************************************************
+ * some forward decleration
+ */
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+                                               void *buffer, int transfer_len,struct devrequest *setup);
+
+/* fill a td with the approproiate data. Link, status, info and buffer
+ * are used by the USB controller itselfes, dev is used to identify the
+ * "connected" device
+ */
+void usb_fill_td(uhci_td_t* td,unsigned long link,unsigned long status,
+                                       unsigned long info, unsigned long buffer, unsigned long dev)
+{
+       td->link=swap_32(link);
+       td->status=swap_32(status);
+       td->info=swap_32(info);
+       td->buffer=swap_32(buffer);
+       td->dev_ptr=dev;
+}
+
+/* fill a qh with the approproiate data. Head and element are used by the USB controller
+ * itselfes. As soon as a valid dev_ptr is filled, a td chain is connected to the qh.
+ * Please note, that after completion of the td chain, the entry element is removed /
+ * marked invalid by the USB controller.
+ */
+void usb_fill_qh(uhci_qh_t* qh,unsigned long head,unsigned long element)
+{
+       qh->head=swap_32(head);
+       qh->element=swap_32(element);
+       qh->dev_ptr=0L;
+}
+
+/* get the status of a td->status
+ */
+unsigned long usb_uhci_td_stat(unsigned long status)
+{
+       unsigned long result=0;
+       result |= (status & TD_CTRL_NAK)      ? USB_ST_NAK_REC : 0;
+       result |= (status & TD_CTRL_STALLED)  ? USB_ST_STALLED : 0;
+       result |= (status & TD_CTRL_DBUFERR)  ? USB_ST_BUF_ERR : 0;
+       result |= (status & TD_CTRL_BABBLE)   ? USB_ST_BABBLE_DET : 0;
+       result |= (status & TD_CTRL_CRCTIMEO) ? USB_ST_CRC_ERR : 0;
+       result |= (status & TD_CTRL_BITSTUFF) ? USB_ST_BIT_ERR : 0;
+       result |= (status & TD_CTRL_ACTIVE)   ? USB_ST_NOT_PROC : 0;
+       return result;
+}
+
+/* get the status and the transfered len of a td chain.
+ * called from the completion handler
+ */
+int usb_get_td_status(uhci_td_t *td,struct usb_device *dev)
+{
+       unsigned long temp,info;
+       unsigned long stat;
+       uhci_td_t *mytd=td;
+
+       if(dev->devnum==rh.devnum)
+               return 0;
+       dev->act_len=0;
+       stat=0;
+       do {
+               temp=swap_32((unsigned long)mytd->status);
+               stat=usb_uhci_td_stat(temp);
+               info=swap_32((unsigned long)mytd->info);
+               if(((info & 0xff)!= USB_PID_SETUP) &&
+                               (((info >> 21) & 0x7ff)!= 0x7ff) &&
+                               (temp & 0x7FF)!=0x7ff)
+               {  /* if not setup and not null data pack */
+                       dev->act_len+=(temp & 0x7FF) + 1; /* the transfered len is act_len + 1 */
+               }
+               if(stat) {           /* status no ok */
+                       dev->status=stat;
+                       return -1;
+               }
+               temp=swap_32((unsigned long)mytd->link);
+               mytd=(uhci_td_t *)(temp & 0xfffffff0);
+       }while((temp & 0x1)==0); /* process all TDs */
+       dev->status=stat;
+       return 0; /* Ok */
+}
+
+
+/*-------------------------------------------------------------------
+ *                         LOW LEVEL STUFF
+ *          assembles QHs und TDs for control, bulk and iso
+ *-------------------------------------------------------------------*/
+
+/* Submits a control message. That is a Setup, Data and Status transfer.
+ * Routine does not wait for completion.
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                                                                               int transfer_len,struct devrequest *setup)
+{
+       unsigned long destination, status;
+       int maxsze = usb_maxpacket(dev, pipe);
+       unsigned long dataptr;
+       int len;
+       int pktsze;
+       int i=0;
+
+       if (!maxsze) {
+               USB_UHCI_PRINTF("uhci_submit_control_urb: pipesize for pipe %lx is zero\n", pipe);
+               return -1;
+       }
+       if(((pipe>>8)&0x7f)==rh.devnum) {
+               /* this is the root hub -> redirect it */
+               return uhci_submit_rh_msg(dev,pipe,buffer,transfer_len,setup);
+       }
+       USB_UHCI_PRINTF("uhci_submit_control start len %x, maxsize %x\n",transfer_len,maxsze);
+       /* The "pipe" thing contains the destination in bits 8--18 */
+       destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* Setup stage */
+       /* 3 errors */
+       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+       /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD); */
+       /*  Build the TD for the control request, try forever, 8 bytes of data */
+       usb_fill_td(&tmp_td[i],UHCI_PTR_TERM ,status, destination | (7 << 21),(unsigned long)setup,(unsigned long)dev);
+#if 0
+       {
+               char *sp=(char *)setup;
+               printf("SETUP to pipe %lx: %x %x %x %x %x %x %x %x\n", pipe,
+                   sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+       }
+#endif
+       dataptr = (unsigned long)buffer;
+       len=transfer_len;
+
+       /* If direction is "send", change the frame from SETUP (0x2D)
+          to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+       destination = (pipe & PIPE_DEVEP_MASK) | ((pipe & USB_DIR_IN)==0 ? USB_PID_OUT : USB_PID_IN);
+       while (len > 0) {
+               /* data stage */
+               pktsze = len;
+               i++;
+               if (pktsze > maxsze)
+                       pktsze = maxsze;
+               destination ^= 1 << TD_TOKEN_TOGGLE;    /* toggle DATA0/1 */
+               usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, destination | ((pktsze - 1) << 21),dataptr,(unsigned long)dev);   /* Status, pktsze bytes of data */
+               tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+
+               dataptr += pktsze;
+               len -= pktsze;
+       }
+
+       /*  Build the final TD for control status */
+       /* It's only IN if the pipe is out AND we aren't expecting data */
+
+       destination &= ~UHCI_PID;
+       if (((pipe & USB_DIR_IN)==0) || (transfer_len == 0))
+               destination |= USB_PID_IN;
+       else
+               destination |= USB_PID_OUT;
+       destination |= 1 << TD_TOKEN_TOGGLE;    /* End in Data1 */
+       i++;
+       status &=~TD_CTRL_SPD;
+       /* no limit on errors on final packet , 0 bytes of data */
+       usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),0,(unsigned long)dev);
+       tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);    /* queue status td */
+       /*      usb_show_td(i+1);*/
+       USB_UHCI_PRINTF("uhci_submit_control end (%d tmp_tds used)\n",i);
+       /* first mark the control QH element terminated */
+       qh_cntrl.element=0xffffffffL;
+       /* set qh active */
+       qh_cntrl.dev_ptr=(unsigned long)dev;
+       /* fill in tmp_td_chain */
+       qh_cntrl.element=swap_32((unsigned long)&tmp_td[0]);
+       return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Prepare TDs for bulk transfers.
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len)
+{
+       unsigned long destination, status,info;
+       unsigned long dataptr;
+       int maxsze = usb_maxpacket(dev, pipe);
+       int len;
+       int i=0;
+
+       if(transfer_len < 0) {
+               printf("Negative transfer length in submit_bulk\n");
+               return -1;
+       }
+       if (!maxsze)
+               return -1;
+       /* The "pipe" thing contains the destination in bits 8--18. */
+       destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+       /* 3 errors */
+       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+       /*      ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); */
+       /* Build the TDs for the bulk request */
+       len = transfer_len;
+       dataptr = (unsigned long)buffer;
+       do {
+               int pktsze = len;
+               if (pktsze > maxsze)
+                       pktsze = maxsze;
+               /* pktsze bytes of data  */
+               info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+                       (usb_gettoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+               if((len-pktsze)==0)
+                       status |= TD_CTRL_IOC;  /* last one generates INT */
+
+               usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, info,dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */
+               if(i>0)
+                       tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+               i++;
+               dataptr += pktsze;
+               len -= pktsze;
+               usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+       } while (len > 0);
+       /* first mark the bulk QH element terminated */
+       qh_bulk.element=0xffffffffL;
+       /* set qh active */
+       qh_bulk.dev_ptr=(unsigned long)dev;
+       /* fill in tmp_td_chain */
+       qh_bulk.element=swap_32((unsigned long)&tmp_td[0]);
+       return 0;
+}
+
+
+/* search a free interrupt td
+ */
+uhci_td_t *uhci_alloc_int_td(void)
+{
+       int i;
+       for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+               if(tmp_int_td[i].dev_ptr==0) /* no device assigned -> free TD */
+                       return &tmp_int_td[i];
+       }
+       return NULL;
+}
+
+#if 0
+void uhci_show_temp_int_td(void)
+{
+       int i;
+       for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+               if((tmp_int_td[i].dev_ptr&0x01)!=0x1L) /* no device assigned -> free TD */
+                       printf("temp_td %d is assigned to dev %lx\n",i,tmp_int_td[i].dev_ptr);
+       }
+       printf("all others temp_tds are free\n");
+}
+#endif
+/*-------------------------------------------------------------------
+ * submits USB interrupt (ie. polling ;-)
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, int interval)
+{
+       int nint, n;
+       unsigned long status, destination;
+       unsigned long info,tmp;
+       uhci_td_t *mytd;
+       if (interval < 0 || interval >= 256)
+               return -1;
+
+       if (interval == 0)
+               nint = 0;
+       else {
+               for (nint = 0, n = 1; nint <= 8; nint++, n += n)        /* round interval down to 2^n */
+                {
+                       if(interval < n) {
+                               interval = n / 2;
+                               break;
+                       }
+               }
+               nint--;
+       }
+
+       USB_UHCI_PRINTF("Rounded interval to %i, chain  %i\n", interval, nint);
+       mytd=uhci_alloc_int_td();
+       if(mytd==NULL) {
+               printf("No free INT TDs found\n");
+               return -1;
+       }
+       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27);
+/*             (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+*/
+
+       destination =(pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe) | (((transfer_len - 1) & 0x7ff) << 21);
+
+       info = destination | (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
+       tmp = swap_32(td_int[nint].link);
+       usb_fill_td(mytd,tmp,status, info,(unsigned long)buffer,(unsigned long)dev);
+       /* Link it */
+       tmp = swap_32((unsigned long)mytd);
+       td_int[nint].link=tmp;
+
+       usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+       return 0;
+}
+
+/**********************************************************************
+ * Low Level functions
+ */
+
+
+void reset_hc(void)
+{
+
+       /* Global reset for 100ms */
+       out16r( usb_base_addr + USBPORTSC1,0x0204);
+       out16r( usb_base_addr + USBPORTSC2,0x0204);
+       out16r( usb_base_addr + USBCMD,USBCMD_GRESET | USBCMD_RS);
+       /* Turn off all interrupts */
+       out16r(usb_base_addr + USBINTR,0);
+       wait_ms(50);
+       out16r( usb_base_addr + USBCMD,0);
+       wait_ms(10);
+}
+
+void start_hc(void)
+{
+       int timeout = 1000;
+
+       while(in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) {
+               if (!--timeout) {
+                       printf("USBCMD_HCRESET timed out!\n");
+                       break;
+               }
+       }
+       /* Turn on all interrupts */
+       out16r(usb_base_addr + USBINTR,USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
+       /* Start at frame 0 */
+       out16r(usb_base_addr + USBFRNUM,0);
+       /* set Framebuffer base address */
+       out32r(usb_base_addr+USBFLBASEADD,(unsigned long)&framelist);
+       /* Run and mark it configured with a 64-byte max packet */
+       out16r(usb_base_addr + USBCMD,USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
+}
+
+/* Initialize the skeleton
+ */
+void usb_init_skel(void)
+{
+       unsigned long temp;
+       int n;
+
+       for(n=0;n<USB_MAX_TEMP_INT_TD;n++)
+               tmp_int_td[n].dev_ptr=0L; /* no devices connected */
+       /* last td */
+       usb_fill_td(&td_last,UHCI_PTR_TERM,TD_CTRL_IOC ,0,0,0L);
+  /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */
+       /* End Queue Header */
+       usb_fill_qh(&qh_end,UHCI_PTR_TERM,(unsigned long)&td_last);
+       /* Bulk Queue Header */
+       temp=(unsigned long)&qh_end;
+       usb_fill_qh(&qh_bulk,temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+       /* Control Queue Header */
+       temp=(unsigned long)&qh_bulk;
+       usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+       /* 1ms Interrupt td */
+       temp=(unsigned long)&qh_cntrl;
+       usb_fill_td(&td_int[0],temp | UHCI_PTR_QH,0,0,0,0L);
+       temp=(unsigned long)&td_int[0];
+       for(n=1; n<8; n++)
+               usb_fill_td(&td_int[n],temp,0,0,0,0L);
+       for (n = 0; n < 1024; n++) {
+       /* link all framelist pointers to one of the interrupts */
+               int m, o;
+               if ((n&127)==127)
+                       framelist[n]= swap_32((unsigned long)&td_int[0]);
+               else
+                       for (o = 1, m = 2; m <= 128; o++, m += m)
+                               if ((n & (m - 1)) == ((m - 1) / 2))
+                                               framelist[n]= swap_32((unsigned long)&td_int[o]);
+       }
+}
+
+/* check the common skeleton for completed transfers, and update the status
+ * of the "connected" device. Called from the IRQ routine.
+ */
+void usb_check_skel(void)
+{
+       struct usb_device *dev;
+       /* start with the control qh */
+       if(qh_cntrl.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+       {
+               dev=(struct usb_device *)qh_cntrl.dev_ptr;
+               usb_get_td_status(&tmp_td[0],dev); /* update status */
+               if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+                       qh_cntrl.dev_ptr=0;
+               }
+       }
+       /* now process the bulk */
+       if(qh_bulk.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+       {
+               dev=(struct usb_device *)qh_bulk.dev_ptr;
+               usb_get_td_status(&tmp_td[0],dev); /* update status */
+               if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+                       qh_bulk.dev_ptr=0;
+               }
+       }
+}
+
+/* check the interrupt chain, ubdate the status of the appropriate device,
+ * call the appropriate irqhandler and reactivate the TD if the irqhandler
+ * returns with 1
+ */
+void usb_check_int_chain(void)
+{
+       int i,res;
+       unsigned long link,status;
+       struct usb_device *dev;
+       uhci_td_t *td,*prevtd;
+
+       for(i=0;i<8;i++) {
+               prevtd=&td_int[i]; /* the first previous td is the skeleton td */
+               link=swap_32(td_int[i].link) & 0xfffffff0; /* next in chain */
+               td=(uhci_td_t *)link; /* assign it */
+               /* all interrupt TDs are finally linked to the td_int[0].
+                * so we process all until we find the td_int[0].
+                * if int0 chain points to a QH, we're also done
+          */
+               while(((i>0) && (link != (unsigned long)&td_int[0])) ||
+                                       ((i==0) && !(swap_32(td->link) &  UHCI_PTR_QH)))
+               {
+                       /* check if a device is assigned with this td */
+                       status=swap_32(td->status);
+                       if((td->dev_ptr!=0L) && !(status & TD_CTRL_ACTIVE)) {
+                               /* td is not active and a device is assigned -> call irqhandler */
+                               dev=(struct usb_device *)td->dev_ptr;
+                               dev->irq_act_len=((status & 0x7FF)==0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */
+                               dev->irq_status=usb_uhci_td_stat(status); /* get status */
+                               res=dev->irq_handle(dev); /* call irqhandler */
+                               if(res==1) {
+                                       /* reactivate */
+                                       status|=TD_CTRL_ACTIVE;
+                                       td->status=swap_32(status);
+                                       prevtd=td; /* previous td = this td */
+                               }
+                               else {
+                                       prevtd->link=td->link; /* link previous td directly to the nex td -> unlinked */
+                                       /* remove device pointer */
+                                       td->dev_ptr=0L;
+                               }
+                       } /* if we call the irq handler */
+                       link=swap_32(td->link) & 0xfffffff0; /* next in chain */
+                       td=(uhci_td_t *)link; /* assign it */
+               } /* process all td in this int chain */
+       } /* next interrupt chain */
+}
+
+
+/* usb interrupt service routine.
+ */
+void handle_usb_interrupt(void)
+{
+       unsigned short status;
+
+       /*
+        * Read the interrupt status, and write it back to clear the
+        * interrupt cause
+        */
+
+       status = in16r(usb_base_addr + USBSTS);
+
+       if (!status)            /* shared interrupt, not mine */
+               return;
+       if (status != 1) {
+               /* remove host controller halted state */
+               if ((status&0x20) && ((in16r(usb_base_addr+USBCMD) && USBCMD_RS)==0)) {
+                       out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD));
+               }
+       }
+       usb_check_int_chain(); /* call interrupt handlers for int tds */
+       usb_check_skel(); /* call completion handler for common transfer routines */
+       out16r(usb_base_addr+USBSTS,status);
+}
+
+
+/* init uhci
+ */
+int usb_lowlevel_init(void)
+{
+       unsigned char temp;
+       int     busdevfunc;
+
+       busdevfunc=pci_find_device(USB_UHCI_VEND_ID,USB_UHCI_DEV_ID,0); /* get PCI Device ID */
+       if(busdevfunc==-1) {
+               printf("Error USB UHCI (%04X,%04X) not found\n",USB_UHCI_VEND_ID,USB_UHCI_DEV_ID);
+               return -1;
+       }
+       pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp);
+       irqvec = temp;
+       irq_free_handler(irqvec);
+       USB_UHCI_PRINTF("Interrupt Line = %d, is %d\n",irqvec);
+       pci_read_config_byte(busdevfunc,PCI_INTERRUPT_PIN,&temp);
+       USB_UHCI_PRINTF("Interrupt Pin = %ld\n",temp);
+       pci_read_config_dword(busdevfunc,PCI_BASE_ADDRESS_4,&usb_base_addr);
+       USB_UHCI_PRINTF("IO Base Address = 0x%lx\n",usb_base_addr);
+       usb_base_addr&=0xFFFFFFF0;
+       usb_base_addr+=CFG_ISA_IO_BASE_ADDRESS;
+       rh.devnum = 0;
+       usb_init_skel();
+       reset_hc();
+       start_hc();
+       irq_install_handler(irqvec, (interrupt_handler_t *)handle_usb_interrupt, NULL);
+       return 0;
+}
+
+/* stop uhci
+ */
+int usb_lowlevel_stop(void)
+{
+       if(irqvec==-1)
+               return 1;
+       irq_free_handler(irqvec);
+       reset_hc();
+       irqvec=-1;
+       return 0;
+}
+
+/*******************************************************************************************
+ * Virtual Root Hub
+ * Since the uhci does not have a real HUB, we simulate one ;-)
+ */
+#undef USB_RH_DEBUG
+
+#ifdef USB_RH_DEBUG
+#define        USB_RH_PRINTF(fmt,args...)      printf (fmt ,##args)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex);
+static void usb_display_Req(unsigned short req);
+#else
+#define USB_RH_PRINTF(fmt,args...)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex) {}
+static void usb_display_Req(unsigned short req) {}
+#endif
+
+static unsigned char root_hub_dev_des[] =
+{
+       0x12,                   /*  __u8  bLength; */
+       0x01,                   /*  __u8  bDescriptorType; Device */
+       0x00,                   /*  __u16 bcdUSB; v1.0 */
+       0x01,
+       0x09,                   /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  bDeviceSubClass; */
+       0x00,                   /*  __u8  bDeviceProtocol; */
+       0x08,                   /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,                   /*  __u16 idVendor; */
+       0x00,
+       0x00,                   /*  __u16 idProduct; */
+       0x00,
+       0x00,                   /*  __u16 bcdDevice; */
+       0x00,
+       0x01,                   /*  __u8  iManufacturer; */
+       0x00,                   /*  __u8  iProduct; */
+       0x00,                   /*  __u8  iSerialNumber; */
+       0x01                    /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static unsigned char root_hub_config_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x02,                   /*  __u8  bDescriptorType; Configuration */
+       0x19,                   /*  __u16 wTotalLength; */
+       0x00,
+       0x01,                   /*  __u8  bNumInterfaces; */
+       0x01,                   /*  __u8  bConfigurationValue; */
+       0x00,                   /*  __u8  iConfiguration; */
+       0x40,                   /*  __u8  bmAttributes;
+                                  Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+       0x00,                   /*  __u8  MaxPower; */
+
+     /* interface */
+       0x09,                   /*  __u8  if_bLength; */
+       0x04,                   /*  __u8  if_bDescriptorType; Interface */
+       0x00,                   /*  __u8  if_bInterfaceNumber; */
+       0x00,                   /*  __u8  if_bAlternateSetting; */
+       0x01,                   /*  __u8  if_bNumEndpoints; */
+       0x09,                   /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  if_bInterfaceSubClass; */
+       0x00,                   /*  __u8  if_bInterfaceProtocol; */
+       0x00,                   /*  __u8  if_iInterface; */
+
+     /* endpoint */
+       0x07,                   /*  __u8  ep_bLength; */
+       0x05,                   /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,                   /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,                   /*  __u8  ep_bmAttributes; Interrupt */
+       0x08,                   /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+       0x00,
+       0xff                    /*  __u8  ep_bInterval; 255 ms */
+};
+
+
+static unsigned char root_hub_hub_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
+       0x02,                   /*  __u8  bNbrPorts; */
+       0x00,                   /* __u16  wHubCharacteristics; */
+       0x00,
+       0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
+       0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+       0x04,                   /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       0x09,                   /*  __u8  lang ID */
+       0x04,                   /*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+       28,                     /*  __u8  bLength; */
+       0x03,                   /*  __u8  bDescriptorType; String-descriptor */
+       'U',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'H',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'C',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'I',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'R',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'o',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       't',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       ' ',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'H',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'u',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+       'b',                    /*  __u8  Unicode */
+       0,                              /*  __u8  Unicode */
+};
+
+
+/*
+ * Root Hub Control Pipe (interrupt Pipes are not supported)
+ */
+
+
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len,struct devrequest *cmd)
+{
+       void *data = buffer;
+       int leni = transfer_len;
+       int len = 0;
+       int status = 0;
+       int stat = 0;
+       int i;
+
+       unsigned short cstatus;
+
+       unsigned short bmRType_bReq;
+       unsigned short wValue;
+       unsigned short wIndex;
+       unsigned short wLength;
+
+       if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+               printf("Root-Hub submit IRQ: NOT implemented\n");
+#if 0
+               uhci->rh.urb = urb;
+               uhci->rh.send = 1;
+               uhci->rh.interval = urb->interval;
+               rh_init_int_timer (urb);
+#endif
+               return 0;
+       }
+       bmRType_bReq = cmd->requesttype | cmd->request << 8;
+       wValue = swap_16(cmd->value);
+       wIndex = swap_16(cmd->index);
+       wLength = swap_16(cmd->length);
+       usb_display_Req(bmRType_bReq);
+       for (i = 0; i < 8; i++)
+               rh.c_p_r[i] = 0;
+       USB_RH_PRINTF("Root-Hub: adr: %2x cmd(%1x): %02x%02x %04x %04x %04x\n",
+            dev->devnum, 8, cmd->requesttype,cmd->request, wValue, wIndex, wLength);
+
+       switch (bmRType_bReq) {
+               /* Request Destination:
+                  without flags: Device,
+                  RH_INTERFACE: interface,
+                  RH_ENDPOINT: endpoint,
+                  RH_CLASS means HUB here,
+                  RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+                */
+
+       case RH_GET_STATUS:
+               *(unsigned short *) data = swap_16(1);
+               len=2;
+               break;
+       case RH_GET_STATUS | RH_INTERFACE:
+               *(unsigned short *) data = swap_16(0);
+               len=2;
+               break;
+       case RH_GET_STATUS | RH_ENDPOINT:
+               *(unsigned short *) data = swap_16(0);
+               len=2;
+               break;
+       case RH_GET_STATUS | RH_CLASS:
+               *(unsigned long *) data = swap_32(0);
+               len=4;
+               break;  /* hub power ** */
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+
+               status = in16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1));
+               cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+                       ((status & USBPORTSC_PEC) >> (3 - 1)) |
+                       (rh.c_p_r[wIndex - 1] << (0 + 4));
+               status = (status & USBPORTSC_CCS) |
+                       ((status & USBPORTSC_PE) >> (2 - 1)) |
+                       ((status & USBPORTSC_SUSP) >> (12 - 2)) |
+                       ((status & USBPORTSC_PR) >> (9 - 4)) |
+                       (1 << 8) |      /* power on ** */
+                       ((status & USBPORTSC_LSDA) << (-8 + 9));
+
+               *(unsigned short *) data = swap_16(status);
+               *(unsigned short *) (data + 2) = swap_16(cstatus);
+               len=4;
+               break;
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               switch (wValue) {
+               case (RH_ENDPOINT_STALL):
+                       len=0;
+                       break;
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               switch (wValue) {
+               case (RH_C_HUB_OVER_CURRENT):
+                       len=0;  /* hub power over current ** */
+                       break;
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               usb_display_wValue(wValue,wIndex);
+               switch (wValue) {
+               case (RH_PORT_ENABLE):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) & ~USBPORTSC_PE;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_PORT_SUSPEND):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) & ~USBPORTSC_SUSP;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_PORT_POWER):
+                       len=0;  /* port power ** */
+                       break;
+               case (RH_C_PORT_CONNECTION):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) | USBPORTSC_CSC;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_C_PORT_ENABLE):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) | USBPORTSC_PEC;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+                       len=0;
+                       break;
+               case (RH_C_PORT_OVER_CURRENT):
+                       len=0;
+                       break;
+               case (RH_C_PORT_RESET):
+                       rh.c_p_r[wIndex - 1] = 0;
+                       len=0;
+                       break;
+               }
+               break;
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               usb_display_wValue(wValue,wIndex);
+               switch (wValue) {
+               case (RH_PORT_SUSPEND):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) | USBPORTSC_SUSP;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_PORT_RESET):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) | USBPORTSC_PR;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       wait_ms(10);
+                       status = (status & 0xfff5) & ~USBPORTSC_PR;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       udelay(10);
+                       status = (status & 0xfff5) | USBPORTSC_PE;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       wait_ms(10);
+                       status = (status & 0xfff5) | 0xa;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               case (RH_PORT_POWER):
+                       len=0;  /* port power ** */
+                       break;
+               case (RH_PORT_ENABLE):
+                       status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+                       status = (status & 0xfff5) | USBPORTSC_PE;
+                       out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+                       len=0;
+                       break;
+               }
+               break;
+
+       case RH_SET_ADDRESS:
+               rh.devnum = wValue;
+               len=0;
+               break;
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+               case (0x01):    /* device descriptor */
+                       i=sizeof(root_hub_config_des);
+                       status=i > wLength ? wLength : i;
+                       len = leni > status ? status : leni;
+                       memcpy (data, root_hub_dev_des, len);
+                       break;
+               case (0x02):    /* configuration descriptor */
+                       i=sizeof(root_hub_config_des);
+                       status=i > wLength ? wLength : i;
+                       len = leni > status ? status : leni;
+                       memcpy (data, root_hub_config_des, len);
+                       break;
+               case (0x03):    /*string descriptors */
+                       if(wValue==0x0300) {
+                               i=sizeof(root_hub_str_index0);
+                               status = i > wLength ? wLength : i;
+                               len = leni > status ? status : leni;
+                               memcpy (data, root_hub_str_index0, len);
+                               break;
+                       }
+                       if(wValue==0x0301) {
+                               i=sizeof(root_hub_str_index1);
+                               status = i > wLength ? wLength : i;
+                               len = leni > status ? status : leni;
+                               memcpy (data, root_hub_str_index1, len);
+                               break;
+                       }
+                       stat = USB_ST_STALLED;
+               }
+               break;
+
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               root_hub_hub_des[2] = 2;
+               i=sizeof(root_hub_hub_des);
+               status= i > wLength ? wLength : i;
+               len = leni > status ? status : leni;
+               memcpy (data, root_hub_hub_des, len);
+               break;
+       case RH_GET_CONFIGURATION:
+               *(unsigned char *) data = 0x01;
+               len = 1;
+               break;
+       case RH_SET_CONFIGURATION:
+               len=0;
+               break;
+       default:
+               stat = USB_ST_STALLED;
+       }
+       USB_RH_PRINTF("Root-Hub stat %lx port1: %x port2: %x\n\n",stat,
+            in16r(usb_base_addr + USBPORTSC1), in16r(usb_base_addr + USBPORTSC2));
+       dev->act_len=len;
+       dev->status=stat;
+       return stat;
+
+}
+
+/********************************************************************************
+ * Some Debug Routines
+ */
+
+#ifdef USB_RH_DEBUG
+
+static void usb_display_Req(unsigned short req)
+{
+       USB_RH_PRINTF("- Root-Hub Request: ");
+       switch (req) {
+       case RH_GET_STATUS:
+               USB_RH_PRINTF("Get Status ");
+               break;
+       case RH_GET_STATUS | RH_INTERFACE:
+               USB_RH_PRINTF("Get Status Interface ");
+               break;
+       case RH_GET_STATUS | RH_ENDPOINT:
+               USB_RH_PRINTF("Get Status Endpoint ");
+               break;
+       case RH_GET_STATUS | RH_CLASS:
+               USB_RH_PRINTF("Get Status Class");
+               break;  /* hub power ** */
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+               USB_RH_PRINTF("Get Status Class Others");
+               break;
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               USB_RH_PRINTF("Clear Feature Endpoint ");
+               break;
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               USB_RH_PRINTF("Clear Feature Class ");
+               break;
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               USB_RH_PRINTF("Clear Feature Other Class ");
+               break;
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               USB_RH_PRINTF("Set Feature Other Class ");
+               break;
+       case RH_SET_ADDRESS:
+               USB_RH_PRINTF("Set Address ");
+               break;
+       case RH_GET_DESCRIPTOR:
+               USB_RH_PRINTF("Get Descriptor ");
+               break;
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               USB_RH_PRINTF("Get Descriptor Class ");
+               break;
+       case RH_GET_CONFIGURATION:
+               USB_RH_PRINTF("Get Configuration ");
+               break;
+       case RH_SET_CONFIGURATION:
+               USB_RH_PRINTF("Get Configuration ");
+               break;
+       default:
+               USB_RH_PRINTF("****UNKNOWN**** 0x%04X ",req);
+       }
+       USB_RH_PRINTF("\n");
+
+}
+
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex)
+{
+       switch (wValue) {
+               case (RH_PORT_ENABLE):
+                       USB_RH_PRINTF("Root-Hub: Enable Port %d\n",wIndex);
+                       break;
+               case (RH_PORT_SUSPEND):
+                       USB_RH_PRINTF("Root-Hub: Suspend Port %d\n",wIndex);
+                       break;
+               case (RH_PORT_POWER):
+                       USB_RH_PRINTF("Root-Hub: Port Power %d\n",wIndex);
+                       break;
+               case (RH_C_PORT_CONNECTION):
+                       USB_RH_PRINTF("Root-Hub: C Port Connection Port %d\n",wIndex);
+                       break;
+               case (RH_C_PORT_ENABLE):
+                       USB_RH_PRINTF("Root-Hub: C Port Enable Port %d\n",wIndex);
+                       break;
+               case (RH_C_PORT_SUSPEND):
+                       USB_RH_PRINTF("Root-Hub: C Port Suspend Port %d\n",wIndex);
+                       break;
+               case (RH_C_PORT_OVER_CURRENT):
+                       USB_RH_PRINTF("Root-Hub: C Port Over Current Port %d\n",wIndex);
+                       break;
+               case (RH_C_PORT_RESET):
+                       USB_RH_PRINTF("Root-Hub: C Port reset Port %d\n",wIndex);
+                       break;
+               default:
+                       USB_RH_PRINTF("Root-Hub: unknown %x %x\n",wValue,wIndex);
+                       break;
+       }
+}
+
+#endif
+
+
+
+#ifdef USB_UHCI_DEBUG
+
+static int usb_display_td(uhci_td_t *td)
+{
+       unsigned long tmp;
+       int valid;
+
+       printf("TD at %p:\n",td);
+
+       tmp=swap_32(td->link);
+       printf("Link points to 0x%08lX, %s first, %s, %s\n",tmp&0xfffffff0,
+               ((tmp & 0x4)==0x4) ? "Depth" : "Breath",
+               ((tmp & 0x2)==0x2) ? "QH" : "TD",
+               ((tmp & 0x1)==0x1) ? "invalid" : "valid");
+       valid=((tmp & 0x1)==0x0);
+       tmp=swap_32(td->status);
+       printf("     %s %ld Errors %s %s %s \n     %s %s %s %s %s %s\n     Len 0x%lX\n",
+               (((tmp>>29)&0x1)==0x1) ? "SPD Enable" : "SPD Disable",
+               ((tmp>>28)&0x3),
+               (((tmp>>26)&0x1)==0x1) ? "Low Speed" : "Full Speed",
+               (((tmp>>25)&0x1)==0x1) ? "ISO " : "",
+               (((tmp>>24)&0x1)==0x1) ? "IOC " : "",
+               (((tmp>>23)&0x1)==0x1) ? "Active " : "Inactive ",
+               (((tmp>>22)&0x1)==0x1) ? "Stalled" : "",
+               (((tmp>>21)&0x1)==0x1) ? "Data Buffer Error" : "",
+               (((tmp>>20)&0x1)==0x1) ? "Babble" : "",
+               (((tmp>>19)&0x1)==0x1) ? "NAK" : "",
+               (((tmp>>18)&0x1)==0x1) ? "Bitstuff Error" : "",
+               (tmp&0x7ff));
+       tmp=swap_32(td->info);
+       printf("     MaxLen 0x%lX\n",((tmp>>21)&0x7FF));
+       printf("     %s Endpoint 0x%lX Dev Addr 0x%lX PID 0x%lX\n",((tmp>>19)&0x1)==0x1 ? "TOGGLE" : "",
+               ((tmp>>15)&0xF),((tmp>>8)&0x7F),tmp&0xFF);
+       tmp=swap_32(td->buffer);
+       printf("     Buffer 0x%08lX\n",tmp);
+       printf("     DEV %08lX\n",td->dev_ptr);
+       return valid;
+}
+
+
+void usb_show_td(int max)
+{
+       int i;
+       if(max>0) {
+               for(i=0;i<max;i++) {
+                       usb_display_td(&tmp_td[i]);
+               }
+       }
+       else {
+               i=0;
+               do {
+                       printf("tmp_td[%d]\n",i);
+               }while(usb_display_td(&tmp_td[i++]));
+       }
+}
+
+
+#endif
+#endif /* CONFIG_USB_UHCI */
+
+/* EOF */
diff --git a/board/musenki/flash.c b/board/musenki/flash.c
new file mode 100644 (file)
index 0000000..a0a038f
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_char *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, uchar *dest, uchar data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+
+
+/*
+ * don't ask.  its stupid, but more than one soul has had to live with this mistake
+ * "swaptab[i]" is the value of "i" with the bits reversed.
+ */
+
+#define  MUSENKI_BROKEN_FLASH 1
+
+#ifdef MUSENKI_BROKEN_FLASH
+unsigned char swaptab[256] = {
+  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+#define BS(b)     (swaptab[b])
+
+#else
+
+#define BS(b)     (b)
+
+#endif
+
+#define BYTEME(x) ((x) & 0xFF)
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",CFG_FLASH_BASE0_PRELIM);
+
+       size_b0 = flash_get_size((vu_char *)CFG_FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0: "
+                       "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+                       flash_info[0].flash_id,
+                       size_b0, size_b0<<20);
+       }
+
+       DEBUGF("## Get flash bank 2 size @ 0x%08x\n",CFG_FLASH_BASE1_PRELIM);
+       size_b1 = flash_get_size((vu_char *)CFG_FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       DEBUGF("protect monitor %x @ %x\n", CFG_MONITOR_BASE, CFG_MONITOR_LEN);
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       DEBUGF("protect environtment %x @ %x\n", CFG_ENV_ADDR, CFG_ENV_SECT_SIZE);
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               flash_info[1].size = size_b1;
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                             &flash_info[1]);
+#endif
+       } else {
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+               flash_info[1].size = 0;
+       }
+
+       DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_INTEL:
+           for (i = 0; i < info->sector_count; i++) {
+               info->start[i] = base;
+               base += 0x00020000;             /* 128k per bank */
+           }
+           return;
+
+       default:
+           printf ("Don't know sector ofsets for flash type 0x%lx\n", info->flash_id);
+           return;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("Fujitsu ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       case FLASH_MAN_INTEL:   printf ("Intel ");              break;
+       case FLASH_MAN_MT:      printf ("MT ");                 break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F320J3A:   printf ("28F320J3A (32Mbit = 128K x 32)\n");
+                               break;
+       case FLASH_28F640J3A:   printf ("28F640J3A (64Mbit = 128K x 64)\n");
+                               break;
+       case FLASH_28F128J3A:   printf ("28F128J3A (128Mbit = 128K x 128)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       if (info->size >= (1 << 20)) {
+               i = 20;
+       } else {
+               i = 10;
+       }
+       printf ("  Size: %ld %cB in %d Sectors\n",
+               info->size >> i,
+               (i == 20) ? 'M' : 'k',
+               info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_char *addr, flash_info_t *info)
+{
+       vu_char manuf, device;
+
+       addr[0] = BS(0x90);
+       manuf = BS(addr[0]);
+       DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (vu_char *)addr, manuf);
+
+       switch (manuf) {
+       case BYTEME(AMD_MANUFACT):
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case BYTEME(FUJ_MANUFACT):
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       case BYTEME(SST_MANUFACT):
+               info->flash_id = FLASH_MAN_SST;
+               break;
+       case BYTEME(STM_MANUFACT):
+               info->flash_id = FLASH_MAN_STM;
+               break;
+       case BYTEME(INTEL_MANUFACT):
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               addr[0] = BS(0xFF);             /* restore read mode, (yes, BS is a NOP) */
+               return 0;                       /* no or unknown flash  */
+       }
+
+       device = BS(addr[2]);                   /* device ID            */
+
+       DEBUGF("Device ID @ 0x%08x: 0x%08x\n", (&addr[1]), device);
+
+       switch (device) {
+       case BYTEME(INTEL_ID_28F320J3A):
+               info->flash_id += FLASH_28F320J3A;
+               info->sector_count = 32;
+               info->size = 0x00400000;
+               break;                          /* =>  4 MB             */
+
+       case BYTEME(INTEL_ID_28F640J3A):
+               info->flash_id += FLASH_28F640J3A;
+               info->sector_count = 64;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case BYTEME(INTEL_ID_28F128J3A):
+               info->flash_id += FLASH_28F128J3A;
+               info->sector_count = 128;
+               info->size = 0x01000000;
+               break;                          /* => 16 MB             */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               addr[0] = BS(0xFF);             /* restore read mode (yes, a NOP) */
+               return 0;                       /* => no or unknown flash */
+
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       addr[0] = BS(0xFF);             /* restore read mode */
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+               printf ("Can erase only Intel flash types - aborted\n");
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n", prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       vu_char *addr = (vu_char *)(info->start[sect]);
+                       unsigned long status;
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       *addr = BS(0x50);       /* clear status register */
+                       *addr = BS(0x20);       /* erase setup */
+                       *addr = BS(0xD0);       /* erase confirm */
+
+                       /* re-enable interrupts if necessary */
+                       if (flag) {
+                               enable_interrupts();
+                       }
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = BS(0xB0); /* suspend erase        */
+                                       *addr = BS(0xFF); /* reset to read mode */
+                                       return 1;
+                               }
+
+                               /* show that we're waiting */
+                               if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       *addr = BS(0xFF);       /* reset to read mode */
+               }
+       }
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define        FLASH_WIDTH     1       /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       uchar *wp = (uchar *)addr;
+       int rc;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+
+       while (cnt > 0) {
+               if ((rc = write_data(info, wp, *src)) != 0) {
+                       return rc;
+               }
+               wp++;
+               src++;
+               cnt--;
+       }
+
+       return cnt;
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, uchar *dest, uchar data)
+{
+       vu_char *addr = (vu_char *)dest;
+       ulong status;
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((BS(*addr) & data) != data) {
+               return 2;
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = BS(0x40);               /* write setup */
+       *addr = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag) {
+               enable_interrupts();
+       }
+
+       start = get_timer (0);
+
+       while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       *addr = BS(0xFF);       /* restore read mode */
+                       return 1;
+               }
+       }
+
+       *addr = BS(0xFF);       /* restore read mode */
+
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/nx823/flash.c b/board/nx823/flash.c
new file mode 100644 (file)
index 0000000..616a13f
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * (C) Copyright 2001
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+extern u_long  *my_sernum;             /* from nx823.c */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET       0x01
+#define FLAG_PROTECT_CLEAR     0x02
+
+/* Board support for 1 or 2 flash devices */
+#undef FLASH_PORT_WIDTH32
+#define FLASH_PORT_WIDTH16
+
+#ifdef FLASH_PORT_WIDTH16
+#define FLASH_PORT_WIDTH               ushort
+#define FLASH_PORT_WIDTHV              vu_short
+#else
+#define FLASH_PORT_WIDTH               ulong
+#define FLASH_PORT_WIDTHV              vu_long
+#endif
+
+#define FPW            FLASH_PORT_WIDTH
+#define FPWV   FLASH_PORT_WIDTHV
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (FPW *addr, flash_info_t *info);
+static int   write_data (flash_info_t *info, ulong dest, FPW data);
+static void  flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+       size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       (void)flash_protect(FLAG_PROTECT_SET,
+                           CFG_FLASH_BASE,
+                           CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+                           &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+       return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000);
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+               case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+               default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+   case FLASH_28F320J3A:
+                               printf ("28F320J3A\n"); break;
+   case FLASH_28F640J3A:
+                               printf ("28F640J3A\n"); break;
+   case FLASH_28F128J3A:
+                               printf ("28F128J3A\n"); break;
+       default:                printf ("Unknown Chip Type\n"); break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (FPW *addr, flash_info_t *info)
+{
+       FPW value;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x5555] = (FPW)0x00AA00AA;
+       addr[0x2AAA] = (FPW)0x00550055;
+       addr[0x5555] = (FPW)0x00900090;
+
+       value = addr[0];
+
+   switch (value) {
+   case (FPW)INTEL_MANUFACT:
+      info->flash_id = FLASH_MAN_INTEL;
+      break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               addr[0] = (FPW)0x00FF00FF;      /* restore read mode */
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+   switch (value) {
+   case (FPW)INTEL_ID_28F320J3A:
+      info->flash_id += FLASH_28F320J3A;
+      info->sector_count = 32;
+      info->size = 0x00400000;
+      break;            /* => 4 MB     */
+
+   case (FPW)INTEL_ID_28F640J3A:
+      info->flash_id += FLASH_28F640J3A;
+      info->sector_count = 64;
+      info->size = 0x00800000;
+      break;            /* => 8 MB     */
+
+   case (FPW)INTEL_ID_28F128J3A:
+      info->flash_id += FLASH_28F128J3A;
+      info->sector_count = 128;
+      info->size = 0x01000000;
+      break;            /* => 16 MB     */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               break;
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       addr[0] = (FPW)0x00FF00FF;      /* restore read mode */
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       int flag, prot, sect;
+       ulong type, start, now, last;
+       int rcode = 0;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       type = (info->flash_id & FLASH_VENDMASK);
+       if ((type != FLASH_MAN_INTEL)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer (0);
+       last  = start;
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       FPWV *addr = (FPWV *)(info->start[sect]);
+                       FPW status;
+
+                       /* Disable interrupts which might cause a timeout here */
+                       flag = disable_interrupts();
+
+                       *addr = (FPW)0x00500050;        /* clear status register */
+                       *addr = (FPW)0x00200020;        /* erase setup */
+                       *addr = (FPW)0x00D000D0;        /* erase confirm */
+
+                       /* re-enable interrupts if necessary */
+                       if (flag)
+                               enable_interrupts();
+
+                       /* wait at least 80us - let's wait 1 ms */
+                       udelay (1000);
+
+                       while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
+                               if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                                       printf ("Timeout\n");
+                                       *addr = (FPW)0x00B000B0; /* suspend erase         */
+                                       *addr = (FPW)0x00FF00FF; /* reset to read mode */
+                                       rcode = 1;
+                                       break;
+                               }
+
+                               /* show that we're waiting */
+                       if ((now - last) > 1000) {      /* every second */
+                                       putc ('.');
+                                       last = now;
+                               }
+                       }
+
+                       *addr = (FPW)0x00FF00FF;        /* reset to read mode */
+                       printf (" done\n");
+               }
+       }
+       return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp;
+       FPW data;
+       int count, i, l, rc, port_width;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return 4;
+       }
+/* get lower word aligned address */
+#ifdef FLASH_PORT_WIDTH16
+       wp = (addr & ~1);
+       port_width = 2;
+#else
+       wp = (addr & ~3);
+       port_width = 4;
+#endif
+
+       /* save sernum if needed */
+       if (addr >= CFG_FLASH_SN_SECTOR && addr < CFG_FLASH_SN_BASE)
+       {
+               u_long dest = CFG_FLASH_SN_BASE;
+               u_short *sn = (u_short *)my_sernum;
+
+               printf("(saving sernum)");
+               for (i=0; i<4; i++)
+               {
+                       if ((rc = write_data(info, dest, sn[i])) != 0) {
+                               return (rc);
+                       }
+                       dest += port_width;
+               }
+       }
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<port_width && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<port_width; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += port_width;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       count = 0;
+       while (cnt >= port_width) {
+               data = 0;
+               for (i=0; i<port_width; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += port_width;
+               cnt -= port_width;
+               if (count++ > 0x800)
+               {
+                       putc('.');
+                       count = 0;
+               }
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<port_width; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word or halfword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, FPW data)
+{
+       FPWV *addr = (FPWV *)dest;
+       ulong status;
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*addr & data) != data) {
+               printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       *addr = (FPW)0x00400040;                /* write setup */
+       *addr = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       start = get_timer (0);
+
+       while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       *addr = (FPW)0x00FF00FF;        /* restore read mode */
+                       return (1);
+               }
+       }
+
+       *addr = (FPW)0x00FF00FF;        /* restore read mode */
+
+       return (0);
+}
+
diff --git a/board/pcippc2/flash.c b/board/pcippc2/flash.c
new file mode 100644 (file)
index 0000000..20f4d03
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (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
+ */
+
+#include <config.h>
+#include <common.h>
+#include <flash.h>
+#include <asm/io.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS];
+
+static ulong flash_get_size (ulong addr, flash_info_t *info);
+static int flash_get_offsets (ulong base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (ulong addr);
+
+unsigned long flash_init (void)
+{
+       unsigned int i;
+       unsigned long flash_size = 0;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+               flash_info[i].sector_count = 0;
+               flash_info[i].size = 0;
+       }
+
+       DEBUGF("\n## Get flash size @ 0x%08x\n", CFG_FLASH_BASE);
+
+       flash_size = flash_get_size (CFG_FLASH_BASE, flash_info);
+
+       DEBUGF("## Flash bank size: %08lx\n", flash_size);
+
+       if (flash_size) {
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
+    CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+                             &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+                             &flash_info[0]);
+#endif
+
+       } else {
+               puts ("Warning: the BOOT Flash is not initialised !");
+       }
+
+       return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (ulong addr, flash_info_t *info)
+{
+       short i;
+       uchar value;
+
+       /* Write auto select command: read Manufacturer ID */
+       out8(addr + 0x0555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x02AA, 0x55);
+       iobarrier_rw();
+       out8(addr + 0x0555, 0x90);
+       iobarrier_rw();
+
+       value = in8(addr);
+       iobarrier_rw();
+
+       DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
+
+       switch (value | (value << 16)) {
+               case AMD_MANUFACT:
+                       info->flash_id = FLASH_MAN_AMD;
+                       break;
+
+               case FUJ_MANUFACT:
+                       info->flash_id = FLASH_MAN_FUJ;
+                       break;
+
+               case STM_MANUFACT:
+                       info->flash_id = FLASH_MAN_STM;
+                       break;
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       info->sector_count = 0;
+                       info->size = 0;
+                       flash_reset (addr);
+                       return 0;
+       }
+
+       value = in8(addr + 1);                  /* device ID            */
+       iobarrier_rw();
+
+       DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
+
+       switch (value) {
+               case AMD_ID_F040B:
+                       DEBUGF("Am29F040B\n");
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00080000;
+                       break;                  /* => 512 kB            */
+
+               case AMD_ID_LV040B:
+                       DEBUGF("Am29LV040B\n");
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00080000;
+                       break;                  /* => 512 kB            */
+
+               case AMD_ID_LV400T:
+                       DEBUGF("Am29LV400T\n");
+                       info->flash_id += FLASH_AM400T;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                  /* => 1 MB              */
+
+               case AMD_ID_LV400B:
+                       DEBUGF("Am29LV400B\n");
+                       info->flash_id += FLASH_AM400B;
+                       info->sector_count = 11;
+                       info->size = 0x00100000;
+                       break;                  /* => 1 MB              */
+
+               case AMD_ID_LV800T:
+                       DEBUGF("Am29LV800T\n");
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                  /* => 2 MB              */
+
+               case AMD_ID_LV800B:
+                       DEBUGF("Am29LV400B\n");
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00200000;
+                       break;                  /* => 2 MB              */
+
+               case AMD_ID_LV160T:
+                       DEBUGF("Am29LV160T\n");
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                  /* => 4 MB              */
+
+               case AMD_ID_LV160B:
+                       DEBUGF("Am29LV160B\n");
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00400000;
+                       break;                  /* => 4 MB              */
+
+               case AMD_ID_LV320T:
+                       DEBUGF("Am29LV320T\n");
+                       info->flash_id += FLASH_AM320T;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                  /* => 8 MB              */
+
+#if 0
+               /* Has the same ID as AMD_ID_LV320T, to be fixed */
+               case AMD_ID_LV320B:
+                       DEBUGF("Am29LV320B\n");
+                       info->flash_id += FLASH_AM320B;
+                       info->sector_count = 67;
+                       info->size = 0x00800000;
+                       break;                  /* => 8 MB              */
+#endif
+
+               case AMD_ID_LV033C:
+                       DEBUGF("Am29LV033C\n");
+                       info->flash_id += FLASH_AM033C;
+                       info->sector_count = 64;
+                       info->size = 0x01000000;
+                       break;                  /* => 16Mb              */
+
+               case STM_ID_F040B:
+                       DEBUGF("M29F040B\n");
+                       info->flash_id += FLASH_AM040;
+                       info->sector_count = 8;
+                       info->size = 0x00080000;
+                       break;                  /* => 512 kB            */
+
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       flash_reset (addr);
+                       return (0);             /* => no or unknown flash */
+
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       if (! flash_get_offsets (addr, info)) {
+               flash_reset (addr);
+               return 0;
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               value = in8(info->start[i] + 2);
+               iobarrier_rw();
+               info->protect[i] = (value & 1) != 0;
+       }
+
+       /*
+        * Reset bank to read mode
+        */
+       flash_reset (addr);
+
+       return (info->size);
+}
+
+static int flash_get_offsets (ulong base, flash_info_t *info)
+{
+       unsigned int i;
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+               case FLASH_AM040:
+                       /* set sector offsets for uniform sector type   */
+                       for (i = 0; i < info->sector_count; i++) {
+                               info->start[i] = base + i * info->size /
+                                                           info->sector_count;
+                       }
+                       break;
+               default:
+                       return 0;
+       }
+
+       return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       volatile ulong addr = info->start[0];
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if (s_first < 0 || s_first > s_last) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       out8(addr + 0x555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x2AA, 0x55);
+       iobarrier_rw();
+       out8(addr + 0x555, 0x80);
+       iobarrier_rw();
+       out8(addr + 0x555, 0xAA);
+       iobarrier_rw();
+       out8(addr + 0x2AA, 0x55);
+       iobarrier_rw();
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = info->start[sect];
+                       out8(addr, 0x30);
+                       iobarrier_rw();
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = info->start[l_sect];
+
+       DEBUGF ("Start erase timeout: %d\n", CFG_FLASH_ERASE_TOUT);
+
+       while ((in8(addr) & 0x80) != 0x80) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       flash_reset (info->start[0]);
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+               iobarrier_rw();
+       }
+
+DONE:
+       /* reset to read mode */
+       flash_reset (info->start[0]);
+
+       printf (" done\n");
+       return 0;
+}
+
+/*
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       volatile ulong addr = info->start[0];
+       ulong start;
+       int i;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((in32(dest) & data) != data) {
+               return (2);
+       }
+
+       /* write each byte out */
+       for (i = 0; i < 4; i++) {
+               char *data_ch = (char *)&data;
+               int flag = disable_interrupts();
+
+               out8(addr + 0x555, 0xAA);
+               iobarrier_rw();
+               out8(addr + 0x2AA, 0x55);
+               iobarrier_rw();
+               out8(addr + 0x555, 0xA0);
+               iobarrier_rw();
+               out8(dest+i, data_ch[i]);
+               iobarrier_rw();
+
+               /* re-enable interrupts if necessary */
+               if (flag)
+                       enable_interrupts();
+
+               /* data polling for D7 */
+               start = get_timer (0);
+               while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
+                       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                               flash_reset (addr);
+                               return (1);
+                       }
+                       iobarrier_rw();
+               }
+       }
+
+       flash_reset (addr);
+       return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (ulong addr)
+{
+       out8(addr, 0xF0);       /* reset bank */
+       iobarrier_rw();
+}
+
+void flash_print_info (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+       case FLASH_MAN_STM:     printf ("SGS THOMSON ");        break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+                               break;
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       if (info->size % 0x100000 == 0) {
+               printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size / 0x100000, info->sector_count);
+       } else if (info->size % 0x400 == 0) {
+               printf ("  Size: %ld KB in %d Sectors\n",
+                       info->size / 0x400, info->sector_count);
+       } else {
+               printf ("  Size: %ld B in %d Sectors\n",
+                       info->size, info->sector_count);
+       }
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+}
diff --git a/board/pcippc2/pcippc2.h b/board/pcippc2/pcippc2.h
new file mode 100644 (file)
index 0000000..6e9e2ff
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * (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
+ */
+
+#ifndef _PCIPPC2_H_
+#define _PCIPPC2_H_
+
+#include <config.h>
+#include <common.h>
+
+#include "hardware.h"
+
+#define FPGA(r, p)     (pcippc2_fpga0_phys + HW_FPGA0_##r##_##p)
+#define UART(r)                (pcippc2_fpga0_phys + HW_FPGA0_UART1 + NS16550_##r * 4)
+#define RTC(r)         (pcippc2_fpga1_phys + HW_FPGA1_RTC + r)
+
+extern u32             pcippc2_fpga0_phys;
+extern u32             pcippc2_fpga1_phys;
+
+extern u32     pcippc2_sdram_size              (void);
+
+extern void    pcippc2_fpga_init               (void);
+
+extern void    cpc710_pci_init                 (void);
+extern void    cpc710_pci_enable_timeout       (void);
+
+extern unsigned long
+               cpc710_ram_init                 (void);
+
+#endif
diff --git a/board/pcippc2/pcippc2_fpga.c b/board/pcippc2/pcippc2_fpga.c
new file mode 100644 (file)
index 0000000..7f6739d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * (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
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+
+#include "pci.h"
+
+#include "hardware.h"
+#include "pcippc2.h"
+
+u32            pcippc2_fpga0_phys;
+u32            pcippc2_fpga1_phys;
+
+void pcippc2_fpga_init (void)
+{
+  pci_dev_t            bdf = pci_find_device(FPGA_VENDOR_ID, FPGA_DEVICE_ID, 0);
+  unsigned int         addr;
+  u16                  cmd;
+
+  if (bdf == -1)
+  {
+    puts("Unable to find FPGA !\n");
+    hang();
+  }
+
+  pci_read_config_word(bdf, PCI_COMMAND, &cmd);
+  if ((cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) != (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))
+  {
+    puts("FPGA is not configured !\n");
+    hang();
+  }
+
+  pci_read_config_dword(bdf, PCI_BASE_ADDRESS_0, &addr);
+  if (addr & 0x1)
+  {
+      /* IO space
+       */
+    pcippc2_fpga0_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
+  }
+  else
+  {
+      /* Memory space
+       */
+    pcippc2_fpga0_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
+  }
+
+  pci_read_config_dword(bdf, PCI_BASE_ADDRESS_1, &addr);
+  if (addr & 0x1)
+  {
+      /* IO space
+       */
+    pcippc2_fpga1_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
+  }
+  else
+  {
+      /* Memory space
+       */
+    pcippc2_fpga1_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
+  }
+
+    /* Interrupts are not used
+     */
+  out32(FPGA(INT, INTR_MASK), 0xffffffff);
+  iobarrier_rw();
+}
diff --git a/board/rpxsuper/flash.c b/board/rpxsuper/flash.c
new file mode 100644 (file)
index 0000000..0c298ba
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD 29F080B devices
+ * Added support for 64bit and AMD 29DL323B
+ *
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+#include <asm/io.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+#define RD_SWP32(x) in_le32((volatile u32*)x)
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+    unsigned long size;
+    int i;
+
+    /* Init: no FLASHes known */
+    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+       flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+    /* for now, only support the 4 MB Flash SIMM */
+    size = flash_get_size((vu_long *)CFG_FLASH0_BASE, &flash_info[0]);
+
+    /*
+     * protect monitor and environment sectors
+     */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_MONITOR_BASE,
+                 CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                 &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_ENV_ADDR,
+                 CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+                 &flash_info[0]);
+#endif
+
+    return /*size*/ (CFG_FLASH0_SIZE * 1024 * 1024);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+
+    if (info->flash_id == FLASH_UNKNOWN) {
+       printf ("missing or unknown FLASH type\n");
+       return;
+    }
+
+    switch (info->flash_id & FLASH_VENDMASK) {
+    case (AMD_MANUFACT & FLASH_VENDMASK):
+       printf ("AMD ");
+       break;
+    case (FUJ_MANUFACT & FLASH_VENDMASK):
+       printf ("FUJITSU ");
+       break;
+    case (SST_MANUFACT & FLASH_VENDMASK):
+       printf ("SST ");
+       break;
+    default:
+       printf ("Unknown Vendor ");
+       break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case (AMD_ID_DL323B & FLASH_TYPEMASK):
+       printf("AM29DL323B (32 MBit)\n");
+       break;
+    default:
+       printf ("Unknown Chip Type\n");
+       break;
+    }
+
+    printf ("  Size: %ld MB in %d Sectors\n",
+           info->size >> 20, info->sector_count);
+
+    printf ("  Sector Start Addresses:");
+    for (i = 0; i < info->sector_count; ++i) {
+       if ((i % 5) == 0) printf ("\n   ");
+       printf (" %08lX%s",
+               info->start[i],
+               info->protect[i] ? " (RO)" : "     "
+               );
+    }
+    printf ("\n");
+    return;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+    short i;
+    vu_long vendor[2], devid[2];
+    ulong base = (ulong)addr;
+
+    /* Reset and Write auto select command: read Manufacturer ID */
+    addr[0] = 0xf0f0f0f0;
+    addr[2 * 0x0555] = 0xAAAAAAAA;
+    addr[2 * 0x02AA] = 0x55555555;
+    addr[2 * 0x0555] = 0x90909090;
+    addr[1] = 0xf0f0f0f0;
+    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+    addr[2 * 0x02AA + 1] = 0x55555555;
+    addr[2 * 0x0555 + 1] = 0x90909090;
+    udelay (1000);
+
+    vendor[0] = RD_SWP32(&addr[0]);
+    vendor[1] = RD_SWP32(&addr[1]);
+    if (vendor[0] != vendor[1] || vendor[0] != AMD_MANUFACT) {
+       info->size = 0;
+       goto out;
+    }
+
+    devid[0] = RD_SWP32(&addr[2]);
+    devid[1] = RD_SWP32(&addr[3]);
+
+    if (devid[0] == AMD_ID_DL323B) {
+       /*
+       * we have 2 Banks
+       * Bank 1 (23 Sectors): 0-7=8kbyte, 8-22=64kbyte
+       * Bank 2 (48 Sectors): 23-70=64kbyte
+       */
+       info->flash_id     = (AMD_MANUFACT & FLASH_VENDMASK) |
+                             (AMD_ID_DL323B & FLASH_TYPEMASK);
+       info->sector_count = 71;
+       info->size         = 4 * (8 * 8 + 63 * 64) * 1024;
+    }
+    else {
+       info->size = 0;
+       goto out;
+    }
+
+    /* set up sector start address table */
+    for (i = 0; i < 8; i++) {
+        info->start[i] = base + (i * 0x8000);
+    }
+    for (i = 8; i < info->sector_count; i++) {
+        info->start[i] = base + (i * 0x40000) + 8 * 0x8000 - 8 * 0x40000;
+    }
+
+    /* check for protected sectors */
+    for (i = 0; i < info->sector_count; i++) {
+        /* read sector protection at sector address */
+       addr = (volatile unsigned long *)(info->start[i]);
+        addr[2 * 0x0555] = 0xAAAAAAAA;
+       addr[2 * 0x02AA] = 0x55555555;
+       addr[2 * 0x0555] = 0x90909090;
+       addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+       addr[2 * 0x02AA + 1] = 0x55555555;
+       addr[2 * 0x0555 + 1] = 0x90909090;
+       udelay (1000);
+       base = RD_SWP32(&addr[4]);
+       base |= RD_SWP32(&addr[5]);
+       info->protect[i] = base & 0x00010001 ? 1 : 0;
+    }
+    addr = (vu_long*)info->start[0];
+
+out:
+    /* reset command */
+    addr[0] = 0xf0f0f0f0;
+    addr[1] = 0xf0f0f0f0;
+
+    return info->size;
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    vu_long *addr = (vu_long*)(info->start[0]);
+    int flag, prot, sect, l_sect;
+    ulong start, now, last;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+       if (info->flash_id == FLASH_UNKNOWN) {
+           printf ("- missing\n");
+       } else {
+           printf ("- no sectors to erase\n");
+       }
+       return 1;
+    }
+
+    prot = 0;
+    for (sect = s_first; sect <= s_last; sect++) {
+       if (info->protect[sect]) {
+           prot++;
+       }
+    }
+
+    if (prot) {
+       printf ("- Warning: %d protected sectors will not be erased!\n",
+               prot);
+    } else {
+       printf ("\n");
+    }
+
+    l_sect = -1;
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    addr[2 * 0x0555] = 0xAAAAAAAA;
+    addr[2 * 0x02AA] = 0x55555555;
+    addr[2 * 0x0555] = 0x80808080;
+    addr[2 * 0x0555] = 0xAAAAAAAA;
+    addr[2 * 0x02AA] = 0x55555555;
+    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+    addr[2 * 0x02AA + 1] = 0x55555555;
+    addr[2 * 0x0555 + 1] = 0x80808080;
+    addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+    addr[2 * 0x02AA + 1] = 0x55555555;
+    udelay (100);
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last; sect++) {
+       if (info->protect[sect] == 0) { /* not protected */
+           addr = (vu_long*)(info->start[sect]);
+           addr[0] = 0x30303030;
+           addr[1] = 0x30303030;
+           l_sect = sect;
+       }
+    }
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* wait at least 80us - let's wait 1 ms */
+    udelay (1000);
+
+    /*
+     * We wait for the last triggered sector
+     */
+    if (l_sect < 0)
+      goto DONE;
+
+    start = get_timer (0);
+    last  = start;
+    addr = (vu_long*)(info->start[l_sect]);
+    while (    (addr[0] & 0x80808080) != 0x80808080 ||
+               (addr[1] & 0x80808080) != 0x80808080) {
+       if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+           printf ("Timeout\n");
+           return 1;
+       }
+       /* show that we're waiting */
+       if ((now - last) > 1000) {      /* every second */
+           serial_putc ('.');
+           last = now;
+       }
+    }
+
+    DONE:
+    /* reset to read mode */
+    addr = (volatile unsigned long *)info->start[0];
+    addr[0] = 0xF0F0F0F0;      /* reset bank */
+    addr[1] = 0xF0F0F0F0;      /* reset bank */
+
+    printf (" done\n");
+    return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp, data;
+    int i, l, rc;
+
+    wp = (addr & ~3);  /* get lower word aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    if ((l = addr - wp) != 0) {
+       data = 0;
+       for (i=0, cp=wp; i<l; ++i, ++cp) {
+           data = (data << 8) | (*(uchar *)cp);
+       }
+       for (; i<4 && cnt>0; ++i) {
+           data = (data << 8) | *src++;
+           --cnt;
+           ++cp;
+       }
+       for (; cnt==0 && i<4; ++i, ++cp) {
+           data = (data << 8) | (*(uchar *)cp);
+       }
+
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       wp += 4;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 4) {
+       data = 0;
+       for (i=0; i<4; ++i) {
+           data = (data << 8) | *src++;
+       }
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       wp  += 4;
+       cnt -= 4;
+    }
+
+    if (cnt == 0) {
+       return (0);
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+       data = (data << 8) | *src++;
+       --cnt;
+    }
+    for (; i<4; ++i, ++cp) {
+       data = (data << 8) | (*(uchar *)cp);
+    }
+
+    return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+    vu_long *addr = (vu_long*)(info->start[0]);
+    ulong start;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*((vu_long *)dest) & data) != data) {
+       return (2);
+    }
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    if ((dest & 0x00000004) == 0) {
+        addr[2 * 0x0555] = 0xAAAAAAAA;
+       addr[2 * 0x02AA] = 0x55555555;
+        addr[2 * 0x0555] = 0xA0A0A0A0;
+    }
+    else {
+        addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+       addr[2 * 0x02AA + 1] = 0x55555555;
+        addr[2 * 0x0555 + 1] = 0xA0A0A0A0;
+    }
+
+    *((vu_long *)dest) = data;
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+    /* data polling for D7 */
+    start = get_timer (0);
+    while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
+       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+           return (1);
+       }
+    }
+    return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/rpxsuper/mii_phy.c b/board/rpxsuper/mii_phy.c
new file mode 100644 (file)
index 0000000..319f959
--- /dev/null
@@ -0,0 +1,108 @@
+#include <common.h>
+#include <mii_phy.h>
+#include "rpxsuper.h"
+
+#define MII_MDIO       0x01
+#define MII_MDCK       0x02
+#define MII_MDIR       0x04
+
+void
+mii_discover_phy(void)
+{
+    int known;
+    unsigned short phy_reg;
+    unsigned long phy_id;
+
+    known = 0;
+    printf("Discovering phy @ 0: ");
+    phy_id = mii_phy_read(2) << 16;
+    phy_id |= mii_phy_read(3);
+    if ((phy_id & 0xFFFFFC00) == 0x00137800) {
+       printf("Level One ");
+       if ((phy_id & 0x000003F0) == 0xE0) {
+           printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
+           known = 1;
+       }
+       else printf("unknown type\n");
+    }
+    else printf("unknown OUI = 0x%08lX\n", phy_id);
+
+    phy_reg = mii_phy_read(1);
+    if (!(phy_reg & 0x0004)) printf("Link is down\n");
+    if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
+    if (phy_reg & 0x0002) printf("Jabber condition detected\n");
+    if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
+
+    if (known) {
+       phy_reg = mii_phy_read(17);
+       if (phy_reg & 0x0400)
+           printf("Phy operating at %d MBit/s in %s-duplex mode\n",
+               phy_reg & 0x4000 ? 100 : 10,
+               phy_reg & 0x0200 ? "full" : "half");
+       else
+           printf("bad link!!\n");
+/*
+left  off: no link, green 100MBit, yellow 10MBit
+right off: no activity, green full-duplex, yellow half-duplex
+*/
+       mii_phy_write(20, 0x0452);
+    }
+}
+
+unsigned short
+mii_phy_read(unsigned short reg)
+{
+    int i;
+    unsigned short tmp, val = 0, adr = 0;
+    t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
+
+    tmp = 0x6002 | (adr << 7) | (reg << 2);
+    regs->bcsr4 = 0xC3;
+    for (i = 0; i < 64; i++) {
+        regs->bcsr4 ^= MII_MDCK;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+       if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       tmp <<= 1;
+    }
+    regs->bcsr4 |= MII_MDIR;
+    for (i = 0; i < 16; i++) {
+       val <<= 1;
+       regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
+       if (regs->bcsr4 & MII_MDIO) val |= 1;
+       regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
+    }
+    return val;
+}
+
+void
+mii_phy_write(unsigned short reg, unsigned short val)
+{
+    int i;
+    unsigned short tmp, adr = 0;
+    t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
+
+    tmp = 0x5002 | (adr << 7) | (reg << 2);
+    regs->bcsr4 = 0xC3;
+    for (i = 0; i < 64; i++) {
+       regs->bcsr4 ^= MII_MDCK;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+        if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       tmp <<= 1;
+    }
+    for (i = 0; i < 16; i++) {
+       regs->bcsr4 &= ~MII_MDCK;
+       if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
+       else regs->bcsr4 &= ~MII_MDIO;
+       regs->bcsr4 |= MII_MDCK;
+       val <<= 1;
+    }
+}
+
diff --git a/board/rsdproto/flash.c b/board/rsdproto/flash.c
new file mode 100644 (file)
index 0000000..654012f
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AM290[48]0B devices
+ *
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+
+/* flash hardware ids */
+#define VENDOR_AMD     0x0001
+#define AMD_29DL323C_B 0x2253
+
+/* Define this to include autoselect sequence in flash_init(). Does NOT
+ * work when executing from flash itself, so this should be turned
+ * on only when debugging the RAM version.
+ */
+#undef WITH_AUTOSELECT
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if 1
+#define D(x)
+#else
+#define D(x) printf x
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static unsigned char write_ull(flash_info_t *info,
+                              unsigned long address,
+                              volatile unsigned long long data);
+
+/* from flash_asm.S */
+extern void ull_write(unsigned long long volatile *address,
+                      unsigned long long volatile *data);
+extern void ull_read(unsigned long long volatile *address,
+                     unsigned long long volatile *data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+    int i;
+    ulong addr;
+
+#ifdef WITH_AUTOSELECT
+       {
+               unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
+               unsigned long long f_command, vendor, device;
+               /* Perform Autoselect */
+               f_command       = 0x00AA00AA00AA00AAULL;
+               ull_write(&f_addr[0x555], &f_command);
+               f_command       = 0x0055005500550055ULL;
+               ull_write(&f_addr[0x2AA], &f_command);
+               f_command       = 0x0090009000900090ULL;
+               ull_write(&f_addr[0x555], &f_command);
+               ull_read(&f_addr[0], &vendor);
+               vendor &= 0xffff;
+               ull_read(&f_addr[1], &device);
+               device &= 0xffff;
+               f_command       = 0x00F000F000F000F0ULL;
+               ull_write(&f_addr[0x555], &f_command);
+               if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
+                 return 0;
+       }
+#endif
+
+    /* Init: no FLASHes known */
+    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+    }
+
+       /* 1st bank: 8 x 32 KB sectors */
+       flash_info[0].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
+       flash_info[0].sector_count = 8;
+       flash_info[0].size = flash_info[0].sector_count * 32 * 1024;
+       addr = PHYS_FLASH;
+    for(i = 0; i < flash_info[0].sector_count; i++) {
+               flash_info[0].start[i] = addr;
+               addr += flash_info[0].size / flash_info[0].sector_count;
+       }
+       /* 1st bank: 63 x 256 KB sectors */
+       flash_info[1].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
+       flash_info[1].sector_count = 63;
+       flash_info[1].size = flash_info[1].sector_count * 256 * 1024;
+    for(i = 0; i < flash_info[1].sector_count; i++) {
+               flash_info[1].start[i] = addr;
+               addr += flash_info[1].size / flash_info[1].sector_count;
+       }
+
+       /*
+        * protect monitor and environment sectors
+        */
+
+#if CFG_MONITOR_BASE >= PHYS_FLASH
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[1]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+                     &flash_info[0]);
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+                     &flash_info[1]);
+#endif
+
+    return flash_info[0].size + flash_info[1].size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i;
+
+    if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+    }
+
+    switch (info->flash_id >> 16) {
+    case VENDOR_AMD:
+               printf ("AMD ");
+               break;
+    default:
+               printf ("Unknown Vendor ");
+               break;
+    }
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case AMD_29DL323C_B:
+               printf ("AM29DL323CB (32 Mbit)\n");
+               break;
+    default:
+               printf ("Unknown Chip Type\n");
+               break;
+    }
+
+    printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size >> 20, info->sector_count);
+
+    printf ("  Sector Start Addresses:");
+    for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                 printf ("\n   ");
+               printf (" %08lX%s",
+                               info->start[i],
+                               info->protect[i] ? " (RO)" : "     "
+                               );
+    }
+    printf ("\n");
+    return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect, l_sect;
+    ulong start;
+       unsigned long long volatile *f_addr;
+       unsigned long long volatile f_command;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+    }
+
+    prot = 0;
+    for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+    }
+    if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                               prot);
+    } else {
+               printf ("\n");
+    }
+
+       f_addr  = (unsigned long long *)info->start[0];
+       f_command       = 0x00AA00AA00AA00AAULL;
+       ull_write(&f_addr[0x555], &f_command);
+       f_command       = 0x0055005500550055ULL;
+       ull_write(&f_addr[0x2AA], &f_command);
+       f_command       = 0x0080008000800080ULL;
+       ull_write(&f_addr[0x555], &f_command);
+       f_command       = 0x00AA00AA00AA00AAULL;
+       ull_write(&f_addr[0x555], &f_command);
+       f_command       = 0x0055005500550055ULL;
+       ull_write(&f_addr[0x2AA], &f_command);
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    /* Start erase on unprotected sectors */
+    for (l_sect = -1, sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+
+                       f_addr  =
+                         (unsigned long long *)(info->start[sect]);
+                       f_command       = 0x0030003000300030ULL;
+                       ull_write(f_addr, &f_command);
+                       l_sect = sect;
+               }
+    }
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+      enable_interrupts();
+
+       start = get_timer (0);
+       do
+       {
+               if (get_timer(start) > CFG_FLASH_ERASE_TOUT)
+               {       /* write reset command, command address is unimportant */
+                       /* this command turns the flash back to read mode     */
+                       f_addr =
+                         (unsigned long long *)(info->start[l_sect]);
+                       f_command       = 0x00F000F000F000F0ULL;
+                       ull_write(f_addr, &f_command);
+                       printf (" timeout\n");
+                       return 1;
+        }
+       } while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
+
+    printf (" done\n");
+    return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    unsigned long cp, wp;
+       unsigned long long data;
+    int i, l, rc;
+
+    wp = (addr & ~7);  /* get lower long long aligned address */
+
+    /*
+     * handle unaligned start bytes
+     */
+    if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<8 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<8; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_ull(info, wp, data)) != 0) {
+                       return rc;
+               }
+               wp += 4;
+    }
+
+    /*
+     * handle long long aligned part
+     */
+    while (cnt >= 8) {
+               data = 0;
+               for (i=0; i<8; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_ull(info, wp, data)) != 0) {
+                       return rc;
+               }
+               wp  += 8;
+               cnt -= 8;
+    }
+
+    if (cnt == 0) {
+               return ERR_OK;
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+    }
+    for (; i<8; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+    }
+
+    return write_ull(info, wp, data);
+}
+
+/*---------------------------------------------------------------------------
+*
+* FUNCTION NAME:  write_ull
+*
+* DESCRIPTION:   writes 8 bytes to flash
+*
+* EXTERNAL EFFECT: nothing
+*
+* PARAMETERS:   32 bit long pointer to address, 64 bit long pointer to data
+*
+* RETURNS:     0 if OK, 1 if timeout, 4 if parameter error
+*--------------------------------------------------------------------------*/
+
+static unsigned char write_ull(flash_info_t *info,
+                                                          unsigned long address,
+                                                          volatile unsigned long long data)
+{
+       static unsigned long long f_command;
+       static unsigned long long *f_addr;
+       ulong start;
+
+       /* address muss be 8-aligned! */
+       if (address & 0x7)
+         return ERR_ALIGN;
+
+       f_addr  = (unsigned long long *)info->start[0];
+       f_command       = 0x00AA00AA00AA00AAULL;
+       ull_write(&f_addr[0x555], &f_command);
+       f_command       = 0x0055005500550055ULL;
+       ull_write(&f_addr[0x2AA], &f_command);
+       f_command       = 0x00A000A000A000A0ULL;
+       ull_write(&f_addr[0x555], &f_command);
+
+       f_addr  = (unsigned long long *)address;
+       f_command       = data;
+       ull_write(f_addr, &f_command);
+
+       start = get_timer (0);
+       do
+       {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
+               {
+                       /* write reset command, command address is unimportant */
+                       /* this command turns the flash back to read mode     */
+                       f_addr  = (unsigned long long *)info->start[0];
+                       f_command       = 0x00F000F000F000F0ULL;
+                       ull_write(f_addr, &f_command);
+                       return ERR_TIMOUT;
+               }
+       } while(*((unsigned long long *)address) != data);
+
+       return 0;
+}
diff --git a/board/siemens/CCM/flash.c b/board/siemens/CCM/flash.c
new file mode 100644 (file)
index 0000000..e56114f
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                   BR_MS_GPCM | BR_V;
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+#endif
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+       flash_info[0].size = size_b0;
+       flash_info[1].size = size_b1;
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       switch (value) {
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+       while ((addr[0] & 0x00800080) != 0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/siemens/IAD210/atm.c b/board/siemens/IAD210/atm.c
new file mode 100644 (file)
index 0000000..c77e359
--- /dev/null
@@ -0,0 +1,653 @@
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#include "atm.h"
+#include <linux/stddef.h>
+
+#define SYNC __asm__("sync")
+#define ALIGN(p, a) ((char *)(((uint32)(p)+(a)-1) & ~((uint32)(a)-1)))
+
+#define FALSE  1
+#define TRUE   0
+#define OK     0
+#define ERROR -1
+
+struct atm_connection_t g_conn[NUM_CONNECTIONS] =
+{
+  { NULL, 10, NULL, 10,  NULL, NULL, NULL, NULL }, /* OAM  */
+};
+
+struct atm_driver_t g_atm =
+{
+  FALSE,   /* loaded */
+  FALSE,   /* started */
+  NULL,    /* csram */
+  0,       /* csram_size */
+  NULL,    /* am_top */
+  NULL,    /* ap_top */
+  NULL,    /* int_reload_ptr */
+  NULL,    /* int_serv_ptr */
+  NULL,    /* rbd_base_ptr */
+  NULL,    /* tbd_base_ptr */
+  0        /* linerate */
+};
+
+char csram[1024]; /* more than enough for doing nothing*/
+
+int    atmLoad(void);
+void   atmUnload(void);
+int    atmMemInit(void);
+void   atmIntInit(void);
+void   atmApcInit(void);
+void   atmAmtInit(void);
+void   atmCpmInit(void);
+void   atmUtpInit(void);
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmLoad
+ *
+ * DESCRIPTION: Basic ATM initialization.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmLoad()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+
+  timers->cpmt_tgcr &=  0x0FFF; SYNC;             /* Disable Timer 4 */
+  immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
+  iop->iop_pdpar &= 0x3FFF; SYNC;                 /* Disable SAR and UTOPIA */
+
+  if ( atmMemInit() != OK ) return ERROR;
+
+  atmIntInit();
+  atmApcInit();
+  atmAmtInit();
+  atmCpmInit();
+  atmUtpInit();
+
+  g_atm.loaded = TRUE;
+
+  return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUnload
+ *
+ * DESCRIPTION: Disables ATM and UTOPIA.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmUnload()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+
+  timers->cpmt_tgcr &=  0x0FFF; SYNC;             /* Disable Timer 4 */
+  immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC;  /* Disable SCC4 */
+  iop->iop_pdpar &= 0x3FFF; SYNC;                 /* Disable SAR and UTOPIA */
+  g_atm.loaded = FALSE;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmMemInit
+ *
+ * DESCRIPTION:
+ *
+ * The ATM driver uses the following resources:
+ *
+ * A. Memory in DPRAM to hold
+ *
+ *     1/ CT          = Connection Table ( RCT & TCT )
+ *     2/ TCTE        = Transmit Connection Table Extension
+ *     3/ MPHYPT      = Multi-PHY Pointing Table
+ *     4/ APCP        = APC Parameter Table
+ *     5/ APCT_PRIO_1 = APC Table ( priority 1 for AAL1/2 )
+ *     6/ APCT_PRIO_2 = APC Table ( priority 2 for VBR )
+ *     7/ APCT_PRIO_3 = APC Table ( priority 3 for UBR )
+ *     8/ TQ          = Transmit Queue
+ *     9/ AM          = Address Matching Table
+ *    10/ AP          = Address Pointing Table
+ *
+ * B. Memory in cache safe RAM to hold
+ *
+ *     1/ INT         = Interrupt Queue
+ *     2/ RBD         = Receive Buffer Descriptors
+ *     3/ TBD         = Transmit Buffer Descriptors
+ *
+ * This function
+ * 1. clears the ATM DPRAM area,
+ * 2. Allocates and clears cache safe memory,
+ * 3. Initializes 'g_conn'.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmMemInit()
+{
+  int i;
+  unsigned immr = CFG_IMMR;
+  int total_num_rbd = 0;
+  int total_num_tbd = 0;
+
+  memset((char *)CFG_IMMR + 0x2000 + ATM_DPRAM_BEGIN, 0x00, ATM_DPRAM_SIZE);
+
+  g_atm.csram_size = NUM_INT_ENTRIES * SIZE_OF_INT_ENTRY;
+
+  for ( i = 0; i < NUM_CONNECTIONS; ++i ) {
+    total_num_rbd += g_conn[i].num_rbd;
+    total_num_tbd += g_conn[i].num_tbd;
+  }
+
+  g_atm.csram_size += total_num_rbd * SIZE_OF_RBD + total_num_tbd * SIZE_OF_TBD + 4;
+
+  g_atm.csram = &csram[0];
+  memset(&(g_atm.csram), 0x00, g_atm.csram_size);
+
+  g_atm.int_reload_ptr = (uint32 *)ALIGN(g_atm.csram, 4);
+  g_atm.rbd_base_ptr = (struct atm_bd_t *)(g_atm.int_reload_ptr + NUM_INT_ENTRIES);
+  g_atm.tbd_base_ptr = (struct atm_bd_t *)(g_atm.rbd_base_ptr + total_num_rbd);
+
+  g_conn[0].rbd_ptr = g_atm.rbd_base_ptr;
+  g_conn[0].tbd_ptr = g_atm.tbd_base_ptr;
+  g_conn[0].ct_ptr = CT_PTR(immr);
+  g_conn[0].tcte_ptr = TCTE_PTR(immr);
+
+  return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmIntInit
+ *
+ * DESCRIPTION:
+ *
+ * Initialization of the MPC860 ESAR Interrupt Queue.
+ * This function
+ * - clears all entries in the INT,
+ * - sets the WRAP bit of the last INT entry,
+ * - initializes the 'int_serv_ptr' attribuut of the AtmDriver structure
+ *   to the first INT entry.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * - The INT resides in external cache safe memory.
+ * - The base address of the INT is stored in g_atm.int_reload_ptr.
+ * - The number of entries in the INT is given by NUM_INT_ENTRIES.
+ * - The INTBASE field in SAR Parameter RAM is set by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmIntInit()
+{
+  int i;
+  for ( i = 0; i < NUM_INT_ENTRIES - 1; ++i) g_atm.int_reload_ptr[i] = 0;
+  g_atm.int_reload_ptr[i] = INT_WRAP;
+  g_atm.int_serv_ptr = g_atm.int_reload_ptr;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmApcInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the following ATM Pace Controller related
+ * data structures:
+ *
+ * - 1 MPHY Pointing Table (contains only one entry)
+ * - 3 APC Parameter Tables (one PHY with 3 priorities)
+ * - 3 APC Tables (one table for each priority)
+ * - 1 Transmit Queue (one transmit queue per PHY)
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmApcInit()
+{
+  int i;
+  /* unsigned immr = CFG_IMMR; */
+  uint16 * mphypt_ptr = MPHYPT_PTR(CFG_IMMR);
+  struct apc_params_t * apcp_ptr = APCP_PTR(CFG_IMMR);
+  uint16 * apct_prio1_ptr = APCT1_PTR(CFG_IMMR);
+  uint16 * tq_ptr = TQ_PTR(CFG_IMMR);
+  /***************************************************/
+  /* Initialize MPHY Pointing Table (only one entry) */
+  /***************************************************/
+  *mphypt_ptr = APCP_BASE;
+
+  /********************************************/
+  /* Initialize APC parameters for priority 1 */
+  /********************************************/
+  apcp_ptr->apct_base1 = APCT_PRIO_1_BASE;
+  apcp_ptr->apct_end1  =  APCT_PRIO_1_BASE + NUM_APCT_PRIO_1_ENTRIES * 2;
+  apcp_ptr->apct_ptr1  =  APCT_PRIO_1_BASE;
+  apcp_ptr->apct_sptr1 = APCT_PRIO_1_BASE;
+  apcp_ptr->etqbase    = TQ_BASE;
+  apcp_ptr->etqend     =  TQ_BASE + ( NUM_TQ_ENTRIES - 1 ) * 2;
+  apcp_ptr->etqaptr    = TQ_BASE;
+  apcp_ptr->etqtptr    = TQ_BASE;
+  apcp_ptr->apc_mi     = 8;
+  apcp_ptr->ncits      = 0x0100;   /* NCITS = 1 */
+  apcp_ptr->apcnt      = 0;
+  apcp_ptr->reserved1  = 0;
+  apcp_ptr->eapcst     = 0x2009;  /* LAST, ESAR, MPHY */
+  apcp_ptr->ptp_counter = 0;
+  apcp_ptr->ptp_txch   = 0;
+  apcp_ptr->reserved2  = 0;
+
+
+  /***************************************************/
+  /* Initialize APC Tables with empty slots (0xFFFF) */
+  /***************************************************/
+  for ( i = 0; i < NUM_APCT_PRIO_1_ENTRIES; ++i ) *(apct_prio1_ptr++) = 0xFFFF;
+
+  /************************/
+  /* Clear Transmit Queue */
+  /************************/
+  for ( i = 0; i < NUM_TQ_ENTRIES; ++i ) *(tq_ptr++) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmAmtInit
+ *
+ * DESCRIPTION:
+ *
+ * This function clears the first entry in the Address Matching Table and
+ * lets the first entry in the Address Pointing table point to the first
+ * entry in the TCT table (i.e. the raw cell channel).
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * The values for the AMBASE, AMEND and APBASE registers in SAR parameter
+ * RAM are initialized by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmAmtInit()
+{
+  unsigned immr = CFG_IMMR;
+
+  g_atm.am_top = AM_PTR(immr);
+  g_atm.ap_top = AP_PTR(immr);
+
+  *(g_atm.ap_top--) = CT_BASE;
+  *(g_atm.am_top--) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmCpmInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the Utopia Interface Parameter RAM Map
+ * (SCC4, ATM Protocol) of the Communication Processor Modudule.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmCpmInit()
+{
+  unsigned immr = CFG_IMMR;
+
+  memset((char *)immr + 0x3F00, 0x00, 0xC0);
+
+  /*-----------------------------------------------------------------*/
+  /* RBDBASE - Receive buffer descriptors base address               */
+  /* The RBDs reside in cache safe external memory.                  */
+  /*-----------------------------------------------------------------*/
+  *RBDBASE(immr) = (uint32)g_atm.rbd_base_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* SRFCR - SAR receive function code                               */
+  /* 0-2 rsvd = 000                                                  */
+  /* 3-4 BO   = 11  Byte ordering (big endian).                      */
+  /* 5-7 FC   = 000 Value driven on the address type signals AT[1-3] */
+  /*                when the SDMA channel accesses memory.           */
+  /*-----------------------------------------------------------------*/
+  *SRFCR(immr) = 0x18;
+
+  /*-----------------------------------------------------------------*/
+  /* SRSTATE - SAR receive status                                    */
+  /* 0 EXT  = 0 Extended mode off.                                   */
+  /* 1 ACP  = 0 Valid only if EXT = 1.                               */
+  /* 2 EC   = 0 Standard 53-byte ATM cell.                           */
+  /* 3 SNC  = 0 In sync. Must be set to 0 during initialization.     */
+  /* 4 ESAR = 1 Enhanced SAR functionality enabled.                  */
+  /* 5 MCF  = 1 Management Cell Filter active.                       */
+  /* 6 SER  = 0 UTOPIA mode.                                         */
+  /* 7 MPY  = 1 Multiple PHY mode.                                   */
+  /*-----------------------------------------------------------------*/
+  *SRSTATE(immr) = 0x0D;
+
+  /*-----------------------------------------------------------------*/
+  /* MRBLR - Maximum receive buffer length register.                 */
+  /* Must be cleared for ATM operation (see also SMRBLR).            */
+  /*-----------------------------------------------------------------*/
+  *MRBLR(immr) = 0;
+
+  /*-----------------------------------------------------------------*/
+  /* RSTATE - SCC internal receive state parameters                  */
+  /* The first byte must be initialized with the value of SRFCR.     */
+  /*-----------------------------------------------------------------*/
+  *RSTATE(immr) = (uint32)(*SRFCR(immr)) << 24;
+
+  /*-----------------------------------------------------------------*/
+  /* STFCR - SAR transmit function code                              */
+  /* 0-2 rsvd = 000                                                  */
+  /* 3-4 BO   = 11  Byte ordering (big endian).                      */
+  /* 5-7 FC   = 000 Value driven on the address type signals AT[1-3] */
+  /*                when the SDMA channel accesses memory.           */
+  /*-----------------------------------------------------------------*/
+  *STFCR(immr) = 0x18;
+
+  /*-----------------------------------------------------------------*/
+  /* SRSTATE - SAR transmit status                                   */
+  /* 0 EXT  = 0 : Extended mode off                                  */
+  /* 1 rsvd = 0 :                                                    */
+  /* 2 EC   = 0 : Standard 53-byte ATM cell                          */
+  /* 3 rsvd = 0 :                                                    */
+  /* 4 ESAR = 1 : Enhanced SAR functionality enabled                 */
+  /* 5 rsvd = 0 :                                                    */
+  /* 6 SER  = 0 : UTOPIA mode                                        */
+  /* 7 MPY  = 1 : Multiple PHY mode                                  */
+  /*-----------------------------------------------------------------*/
+  *STSTATE(immr) = 0x09;
+
+  /*-----------------------------------------------------------------*/
+  /* TBDBASE - Transmit buffer descriptors base address              */
+  /* The TBDs reside in cache safe external memory.                  */
+  /*-----------------------------------------------------------------*/
+  *TBDBASE(immr) = (uint32)g_atm.tbd_base_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* TSTATE - SCC internal transmit state parameters                 */
+  /* The first byte must be initialized with the value of STFCR.     */
+  /*-----------------------------------------------------------------*/
+  *TSTATE(immr) = (uint32)(*STFCR(immr)) << 24;
+
+  /*-----------------------------------------------------------------*/
+  /* CTBASE - Connection table base address                          */
+  /* Offset from the beginning of DPRAM (64-byte aligned).           */
+  /*-----------------------------------------------------------------*/
+  *CTBASE(immr) = CT_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* INTBASE - Interrupt queue base pointer.                         */
+  /* The interrupt queue resides in cache safe external memory.      */
+  /*-----------------------------------------------------------------*/
+  *INTBASE(immr) = (uint32)g_atm.int_reload_ptr;
+
+  /*-----------------------------------------------------------------*/
+  /* INTPTR - Pointer into interrupt queue.                          */
+  /* Initialize to INTBASE.                                          */
+  /*-----------------------------------------------------------------*/
+  *INTPTR(immr) = *INTBASE(immr);
+
+  /*-----------------------------------------------------------------*/
+  /* C_MASK - Constant mask for CRC32                                */
+  /* Must be initialized to 0xDEBB20E3.                              */
+  /*-----------------------------------------------------------------*/
+  *C_MASK(immr) = 0xDEBB20E3;
+
+  /*-----------------------------------------------------------------*/
+  /* INT_ICNT - Interrupt threshold value                            */
+  /*-----------------------------------------------------------------*/
+  *INT_ICNT(immr) = 1;
+
+  /*-----------------------------------------------------------------*/
+  /* INT_CNT - Interrupt counter                                     */
+  /* Initalize to INT_ICNT. Decremented for each interrupt entry     */
+  /* reported in the interrupt queue. On zero an interrupt is        */
+  /* signaled to the host by setting the GINT bit in the event       */
+  /* register. The counter is reinitialized with INT_ICNT.           */
+  /*-----------------------------------------------------------------*/
+  *INT_CNT(immr) = *INT_ICNT(immr);
+
+  /*-----------------------------------------------------------------*/
+  /* SMRBLR - SAR maximum receive buffer length register.            */
+  /* Must be a multiple of 48 bytes. Common for all ATM connections. */
+  /*-----------------------------------------------------------------*/
+  *SMRBLR(immr) = SAR_RXB_SIZE;
+
+  /*-----------------------------------------------------------------*/
+  /* APCST - APC status register.                                    */
+  /* 0     rsvd 0                                                    */
+  /* 1-2   CSER 11  Initialize with the same value as NSER.          */
+  /* 3-4   NSER 11  Next serial or UTOPIA channel.                   */
+  /* 5-7   rsvd 000                                                  */
+  /* 8-10  rsvd 000                                                  */
+  /* 11    rsvd 0                                                    */
+  /* 12    ESAR 1   UTOPIA Level 2 MPHY enabled.                     */
+  /* 13    DIS  0   APC disable. Must be initiazed to 0.             */
+  /* 14    PL2  0   Not used.                                        */
+  /* 15    MPY  1   Multiple PHY mode on.                            */
+  /*-----------------------------------------------------------------*/
+  *APCST(immr) = 0x7809;
+
+  /*-----------------------------------------------------------------*/
+  /* APCPTR - Pointer to the APC parameter table                     */
+  /* In MPHY master mode this parameter points to the MPHY pointing  */
+  /* table. 2-byte aligned.                                          */
+  /*-----------------------------------------------------------------*/
+  *APCPTR(immr) = MPHYPT_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* HMASK - Header mask                                             */
+  /* Each incoming cell is masked with HMASK before being compared   */
+  /* to the entries in the address matching table.                   */
+  /*-----------------------------------------------------------------*/
+  *HMASK(immr) = AM_HMASK;
+
+  /*-----------------------------------------------------------------*/
+  /* AMBASE - Address matching table base address                    */
+  /*-----------------------------------------------------------------*/
+  *AMBASE(immr) = AM_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* AMEND - Address matching table end address                      */
+  /*-----------------------------------------------------------------*/
+  *AMEND(immr) = AM_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* APBASE - Address pointing table base address                    */
+  /*-----------------------------------------------------------------*/
+  *APBASE(immr) = AP_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* MPHYST - MPHY status register                                   */
+  /* 0-1   rsvd  00                                                  */
+  /* 2-6   NMPHY 00000 1 PHY                                         */
+  /* 7-9   rsvd  000                                                 */
+  /* 10-14 CMPHY 00000 Initialize with same value as NMPHY           */
+  /*-----------------------------------------------------------------*/
+  *MPHYST(immr) = 0x0000;
+
+  /*-----------------------------------------------------------------*/
+  /* TCTEBASE - Transmit connection table extension base address     */
+  /* Offset from the beginning of DPRAM (32-byte aligned).           */
+  /*-----------------------------------------------------------------*/
+  *TCTEBASE(immr) = TCTE_BASE;
+
+  /*-----------------------------------------------------------------*/
+  /* Clear not used registers.                                       */
+  /*-----------------------------------------------------------------*/
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUtpInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the ATM interface for
+ *
+ * - UTOPIA mode
+ * - muxed bus
+ * - master operation
+ * - multi PHY (because of a bug in the MPC860P rev. E.0)
+ * - internal clock = SYSCLK / 2
+ *
+ * EXTERNAL EFFECTS:
+ *
+ * After calling this function, the MPC860ESAR UTOPIA bus is
+ * active and uses the following ports/pins:
+ *
+ * Port    Pin  Signal   Description
+ * ------  ---  -------  -------------------------------------------
+ * PB[15]  R17  TxClav   Transmit cell available input/output signal
+ * PC[15]  D16  RxClav   Receive cell available input/output signal
+ * PD[15]  U17  UTPB[0]  UTOPIA bus bit 0 input/output signal
+ * PD[14]  V19  UTPB[1]  UTOPIA bus bit 1 input/output signal
+ * PD[13]  V18  UTPB[2]  UTOPIA bus bit 2 input/output signal
+ * PD[12]  R16  UTPB[3]  UTOPIA bus bit 3 input/output signal
+ * PD[11]  T16  RXENB    Receive enable input/output signal
+ * PD[10]  W18  TXENB    Transmit enable input/output signal
+ * PD[9]   V17  UTPCLK   UTOPIA clock input/output signal
+ * PD[7]   T15  UTPB[4]  UTOPIA bus bit 4 input/output signal
+ * PD[6]   V16  UTPB[5]  UTOPIA bus bit 5 input/output signal
+ * PD[5]   U15  UTPB[6]  UTOPIA bus bit 6 input/output signal
+ * PD[4]   U16  UTPB[7]  UTOPIA bus bit 7 input/output signal
+ * PD[3]   W16  SOC      Start of cell input/output signal
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARK:
+ *
+ * The ATM parameters and data structures must be configured before
+ * initializing the UTOPIA port. The UTOPIA port activates immediately
+ * upon initialization, and if its associated data structures are not
+ * initialized, the CPM will lock up.
+ *
+ ****************************************************************************/
+void atmUtpInit()
+{
+  volatile immap_t       *immap  = (immap_t *)CFG_IMMR;
+  volatile iop8xx_t      *iop    = &immap->im_ioport;
+  volatile car8xx_t     *car    = &immap->im_clkrst;
+  volatile cpm8xx_t     *cpm    = &immap->im_cpm;
+  int flag;
+
+  flag = disable_interrupts();
+
+  /*-----------------------------------------------------------------*/
+  /* SCCR - System Clock Control Register                            */
+  /*                                                                 */
+  /* The UTOPIA clock can be selected to be internal clock or        */
+  /* external clock (selected by the UTOPIA mode register).          */
+  /* In case of internal clock, the UTOPIA clock is derived from     */
+  /* the system frequency divided by two dividers.                   */
+  /* Bits 27-31 of the SCCR register are defined to control the      */
+  /* UTOPIA clock.                                                   */
+  /*                                                                 */
+  /* SCCR[27:29] DFUTP  Division factor. Divide the system clock     */
+  /*                    by 2^DFUTP.                                  */
+  /* SCCR[30:31] DFAUTP Additional division factor. Divide the       */
+  /*                    system clock by the following value:         */
+  /*                    00 = divide by 1                             */
+  /*                    00 = divide by 3                             */
+  /*                    10 = divide by 5                             */
+  /*                    11 = divide by 7                             */
+  /*                                                                 */
+  /* Note that the UTOPIA clock must be programmed as to operate     */
+  /* within the range SYSCLK/10 .. 50Mhz.                            */
+  /*-----------------------------------------------------------------*/
+  car->car_sccr &= 0xFFFFFFE0;
+  car->car_sccr |= 0x00000008; /* UTPCLK = SYSCLK / 4 */
+
+  /*-----------------------------------------------------------------*/
+  /* RCCR - RISC Controller Configuration Register                   */
+  /*                                                                 */
+  /* RCCR[8]     DR1M IDMA Request 0 Mode                            */
+  /*                  0 = edge sensitive                             */
+  /*                  1 = level sensitive                            */
+  /* RCCR[9]     DR0M IDMA Request 0 Mode                            */
+  /*                  0 = edge sensitive                             */
+  /*                  1 = level sensitive                            */
+  /* RCCR[10:11] DRQP IDMA Request Priority                          */
+  /*                  00 = IDMA req. have more prio. than SCCs       */
+  /*                  01 = IDMA req. have less prio. then SCCs       */
+  /*                  10 = IDMA requests have the lowest prio.       */
+  /*                  11 = reserved                                  */
+  /*                                                                 */
+  /* The RCCR[DR0M] and RCCR[DR1M] bits must be set to enable UTOPIA */
+  /* operation. Also, program RCCR[DPQP] to 01 to give SCC transfers */
+  /* higher priority.                                                */
+  /*-----------------------------------------------------------------*/
+  cpm->cp_rccr &= 0xFF0F;
+  cpm->cp_rccr |= 0x00D0;
+
+  /*-----------------------------------------------------------------*/
+  /* Port B - TxClav Signal                                          */
+  /*-----------------------------------------------------------------*/
+  cpm->cp_pbpar |= 0x00010000; /* PBPAR[15] = 1 */
+  cpm->cp_pbdir &= 0xFFFEFFFF; /* PBDIR[15] = 0 */
+
+  /*-----------------------------------------------------------------*/
+  /* UTOPIA Mode Register                                            */
+  /*                                                                 */
+  /* - muxed bus (master operation only)                             */
+  /* - multi PHY (because of a bug in the MPC860P rev.E.0)           */
+  /* - internal clock                                                */
+  /* - no loopback                                                   */
+  /* - do no activate statistical counters                           */
+  /*-----------------------------------------------------------------*/
+  iop->utmode = 0x00000004; SYNC;
+
+  /*-----------------------------------------------------------------*/
+  /* Port D - UTOPIA Data and Control Signals                        */
+  /*                                                                 */
+  /* 15-12 UTPB[0:3] UTOPIA bus bit 0 - 3 input/output signals       */
+  /* 11    RXENB     UTOPIA receive enable input/output signal       */
+  /* 10    TXENB     UTOPIA transmit enable input/output signal      */
+  /* 9     TUPCLK    UTOPIA clock input/output signal                */
+  /* 8     MII-MDC   Used by MII in simult. MII and UTOPIA operation */
+  /* 7-4   UTPB[4:7] UTOPIA bus bit 4 - 7 input/output signals       */
+  /* 3     SOC       UTOPIA Start of cell input/output signal        */
+  /* 2               Reserved                                        */
+  /* 1               Enable UTOPIA mode                              */
+  /* 0               Enable SAR                                      */
+  /*-----------------------------------------------------------------*/
+  iop->iop_pdpar |= 0xDF7F; SYNC;
+  iop->iop_pddir &= 0x2080; SYNC;
+
+  /*-----------------------------------------------------------------*/
+  /* Port C - RxClav Signal                                          */
+  /*-----------------------------------------------------------------*/
+  iop->iop_pcpar  |= 0x0001; /* PCPAR[15] = 1 */
+  iop->iop_pcdir  &= 0xFFFE; /* PCDIR[15] = 0 */
+  iop->iop_pcso   &= 0xFFFE; /* PCSO[15]  = 0 */
+
+  if (flag)
+    enable_interrupts();
+}
diff --git a/board/siemens/IAD210/flash.c b/board/siemens/IAD210/flash.c
new file mode 100644 (file)
index 0000000..1ed5262
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * (C) Copyright 2000, 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
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+  volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+  volatile memctl8xx_t *memctl = &immap->im_memctl;
+  unsigned long size;
+  int i;
+
+  /* Init: no FLASHes known */
+  for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+    flash_info[i].flash_id = FLASH_UNKNOWN;
+  }
+
+  /* Static FLASH Bank configuration here - FIXME XXX */
+
+  size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+  if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+    printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size, size<<20);
+  }
+
+
+  /* Remap FLASH according to real size */
+  memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+  memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+  /* Re-do sizing to get full correct info */
+  size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+  flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+  flash_info[0].size = size;
+
+  return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+  int i;
+
+  /* set up sector start address table */
+  if (info->flash_id & FLASH_BTYPE) {
+    /* set sector offsets for bottom boot block type   */
+    info->start[0] = base + 0x00000000;
+    info->start[1] = base + 0x00008000;
+    info->start[2] = base + 0x0000C000;
+    info->start[3] = base + 0x00010000;
+    for (i = 4; i < info->sector_count; i++) {
+      info->start[i] = base + (i * 0x00020000) - 0x00060000;
+    }
+  } else {
+    /* set sector offsets for top boot block type              */
+    i = info->sector_count - 1;
+    info->start[i--] = base + info->size - 0x00008000;
+    info->start[i--] = base + info->size - 0x0000C000;
+    info->start[i--] = base + info->size - 0x00010000;
+    for (; i >= 0; i--) {
+      info->start[i] = base + i * 0x00020000;
+    }
+  }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+  int i;
+
+  if (info->flash_id == FLASH_UNKNOWN) {
+    printf ("missing or unknown FLASH type\n");
+    return;
+  }
+
+  switch (info->flash_id & FLASH_VENDMASK) {
+  case FLASH_MAN_AMD:  printf ("AMD ");                break;
+  case FLASH_MAN_FUJ:  printf ("FUJITSU ");            break;
+  default:             printf ("Unknown Vendor ");     break;
+  }
+
+  switch (info->flash_id & FLASH_TYPEMASK) {
+  case FLASH_AM400B:   printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM400T:   printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM800B:   printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM800T:   printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM160B:   printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM160T:   printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+    break;
+  case FLASH_AM320B:   printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+    break;
+  case FLASH_AM320T:   printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+    break;
+  default:             printf ("Unknown Chip Type\n");
+    break;
+  }
+
+  printf ("  Size: %ld MB in %d Sectors\n",
+          info->size >> 20, info->sector_count);
+
+  printf ("  Sector Start Addresses:");
+  for (i=0; i<info->sector_count; ++i) {
+    if ((i % 5) == 0)
+      printf ("\n   ");
+    printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+            );
+  }
+  printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+  short i;
+  ulong value;
+  ulong base = (ulong)addr;
+
+
+  /* Write auto select command: read Manufacturer ID */
+  addr[0x0555] = 0x00AA00AA;
+  addr[0x02AA] = 0x00550055;
+  addr[0x0555] = 0x00900090;
+
+  value = addr[0];
+
+  switch (value) {
+  case AMD_MANUFACT:
+    info->flash_id = FLASH_MAN_AMD;
+    break;
+  case FUJ_MANUFACT:
+    info->flash_id = FLASH_MAN_FUJ;
+    break;
+  default:
+    info->flash_id = FLASH_UNKNOWN;
+    info->sector_count = 0;
+    info->size = 0;
+    return (0);                        /* no or unknown flash  */
+  }
+
+  value = addr[1];                     /* device ID            */
+
+  switch (value) {
+  case AMD_ID_LV400T:
+    info->flash_id += FLASH_AM400T;
+    info->sector_count = 11;
+    info->size = 0x00100000;
+    break;                             /* => 1 MB              */
+
+  case AMD_ID_LV400B:
+    info->flash_id += FLASH_AM400B;
+    info->sector_count = 11;
+    info->size = 0x00100000;
+    break;                             /* => 1 MB              */
+
+  case AMD_ID_LV800T:
+    info->flash_id += FLASH_AM800T;
+    info->sector_count = 19;
+    info->size = 0x00200000;
+    break;                             /* => 2 MB              */
+
+  case AMD_ID_LV800B:
+    info->flash_id += FLASH_AM800B;
+    info->sector_count = 19;
+    info->size = 0x00200000;
+    break;                             /* => 2 MB              */
+
+  case AMD_ID_LV160T:
+    info->flash_id += FLASH_AM160T;
+    info->sector_count = 35;
+    info->size = 0x00400000;
+    break;                             /* => 4 MB              */
+
+  case AMD_ID_LV160B:
+    info->flash_id += FLASH_AM160B;
+    info->sector_count = 35;
+    info->size = 0x00400000;
+    break;                             /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+  case AMD_ID_LV320T:
+    info->flash_id += FLASH_AM320T;
+    info->sector_count = 67;
+    info->size = 0x00800000;
+    break;                             /* => 8 MB              */
+
+  case AMD_ID_LV320B:
+    info->flash_id += FLASH_AM320B;
+    info->sector_count = 67;
+    info->size = 0x00800000;
+    break;                             /* => 8 MB              */
+#endif
+  default:
+    info->flash_id = FLASH_UNKNOWN;
+    return (0);                        /* => no or unknown flash */
+
+  }
+
+  /* set up sector start address table */
+  if (info->flash_id & FLASH_BTYPE) {
+    /* set sector offsets for bottom boot block type   */
+    info->start[0] = base + 0x00000000;
+    info->start[1] = base + 0x00008000;
+    info->start[2] = base + 0x0000C000;
+    info->start[3] = base + 0x00010000;
+    for (i = 4; i < info->sector_count; i++) {
+      info->start[i] = base + (i * 0x00020000) - 0x00060000;
+    }
+  } else {
+    /* set sector offsets for top boot block type              */
+    i = info->sector_count - 1;
+    info->start[i--] = base + info->size - 0x00008000;
+    info->start[i--] = base + info->size - 0x0000C000;
+    info->start[i--] = base + info->size - 0x00010000;
+    for (; i >= 0; i--) {
+      info->start[i] = base + i * 0x00020000;
+    }
+  }
+
+  /* check for protected sectors */
+  for (i = 0; i < info->sector_count; i++) {
+    /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+    /* D0 = 1 if protected */
+    addr = (volatile unsigned long *)(info->start[i]);
+    info->protect[i] = addr[2] & 1;
+  }
+
+  /*
+   * Prevent writes to uninitialized FLASH.
+   */
+  if (info->flash_id != FLASH_UNKNOWN) {
+    addr = (volatile unsigned long *)info->start[0];
+
+    *addr = 0x00F000F0;        /* reset bank */
+  }
+
+  return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+  vu_long *addr = (vu_long*)(info->start[0]);
+  int flag, prot, sect, l_sect;
+  ulong start, now, last;
+
+  if ((s_first < 0) || (s_first > s_last)) {
+    if (info->flash_id == FLASH_UNKNOWN) {
+      printf ("- missing\n");
+    } else {
+      printf ("- no sectors to erase\n");
+    }
+    return 1;
+  }
+
+  if ((info->flash_id == FLASH_UNKNOWN) ||
+      (info->flash_id > FLASH_AMD_COMP)) {
+    printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+    return 1;
+  }
+
+  prot = 0;
+  for (sect=s_first; sect<=s_last; ++sect) {
+    if (info->protect[sect]) {
+      prot++;
+    }
+  }
+
+  if (prot) {
+    printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+  } else {
+    printf ("\n");
+  }
+
+  l_sect = -1;
+
+  /* Disable interrupts which might cause a timeout here */
+  flag = disable_interrupts();
+
+  addr[0x0555] = 0x00AA00AA;
+  addr[0x02AA] = 0x00550055;
+  addr[0x0555] = 0x00800080;
+  addr[0x0555] = 0x00AA00AA;
+  addr[0x02AA] = 0x00550055;
+
+  /* Start erase on unprotected sectors */
+  for (sect = s_first; sect<=s_last; sect++) {
+    if (info->protect[sect] == 0) {    /* not protected */
+      addr = (vu_long*)(info->start[sect]);
+      addr[0] = 0x00300030;
+      l_sect = sect;
+    }
+  }
+
+  /* re-enable interrupts if necessary */
+  if (flag)
+    enable_interrupts();
+
+  /* wait at least 80us - let's wait 1 ms */
+  udelay (1000);
+
+  /*
+   * We wait for the last triggered sector
+   */
+  if (l_sect < 0)
+    goto DONE;
+
+  start = get_timer (0);
+  last  = start;
+  addr = (vu_long*)(info->start[l_sect]);
+  while ((addr[0] & 0x00800080) != 0x00800080) {
+    if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+      printf ("Timeout\n");
+      return 1;
+    }
+    /* show that we're waiting */
+    if ((now - last) > 1000) { /* every second */
+      putc ('.');
+      last = now;
+    }
+  }
+
+ DONE:
+  /* reset to read mode */
+  addr = (volatile unsigned long *)info->start[0];
+  addr[0] = 0x00F000F0;        /* reset bank */
+
+  printf (" done\n");
+  return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+  ulong cp, wp, data;
+  int i, l, rc;
+
+  wp = (addr & ~3);    /* get lower word aligned address */
+
+  /*
+   * handle unaligned start bytes
+   */
+  if ((l = addr - wp) != 0) {
+    data = 0;
+    for (i=0, cp=wp; i<l; ++i, ++cp) {
+      data = (data << 8) | (*(uchar *)cp);
+    }
+    for (; i<4 && cnt>0; ++i) {
+      data = (data << 8) | *src++;
+      --cnt;
+      ++cp;
+    }
+    for (; cnt==0 && i<4; ++i, ++cp) {
+      data = (data << 8) | (*(uchar *)cp);
+    }
+
+    if ((rc = write_word(info, wp, data)) != 0) {
+      return (rc);
+    }
+    wp += 4;
+  }
+
+  /*
+   * handle word aligned part
+   */
+  while (cnt >= 4) {
+    data = 0;
+    for (i=0; i<4; ++i) {
+      data = (data << 8) | *src++;
+    }
+    if ((rc = write_word(info, wp, data)) != 0) {
+      return (rc);
+    }
+    wp  += 4;
+    cnt -= 4;
+  }
+
+  if (cnt == 0) {
+    return (0);
+  }
+
+  /*
+   * handle unaligned tail bytes
+   */
+  data = 0;
+  for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+    data = (data << 8) | *src++;
+    --cnt;
+  }
+  for (; i<4; ++i, ++cp) {
+    data = (data << 8) | (*(uchar *)cp);
+  }
+
+  return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+  vu_long *addr = (vu_long*)(info->start[0]);
+  ulong start;
+  int flag;
+
+  /* Check if Flash is (sufficiently) erased */
+  if ((*((vu_long *)dest) & data) != data) {
+    return (2);
+  }
+  /* Disable interrupts which might cause a timeout here */
+  flag = disable_interrupts();
+
+  addr[0x0555] = 0x00AA00AA;
+  addr[0x02AA] = 0x00550055;
+  addr[0x0555] = 0x00A000A0;
+
+  *((vu_long *)dest) = data;
+
+  /* re-enable interrupts if necessary */
+  if (flag)
+    enable_interrupts();
+
+  /* data polling for D7 */
+  start = get_timer (0);
+  while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+    if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+      return (1);
+    }
+  }
+  return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/siemens/SCM/flash.c b/board/siemens/SCM/flash.c
new file mode 100644 (file)
index 0000000..dd7a4cc
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD devices on the TQM8260 board
+ *
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+
+#define V_ULONG(a)     (*(volatile unsigned long *)( a ))
+#define V_BYTE(a)      (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset (void)
+{
+       if (flash_info[0].flash_id != FLASH_UNKNOWN) {
+               V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
+               V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size (ulong baseaddr, flash_info_t * info)
+{
+       short i;
+       unsigned long flashtest_h, flashtest_l;
+
+       /* Write auto select command sequence and test FLASH answer */
+       V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
+       V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
+
+       flashtest_h = V_ULONG (baseaddr);       /* manufacturer ID     */
+       flashtest_l = V_ULONG (baseaddr + 4);
+
+       switch ((int) flashtest_h) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash     */
+       }
+
+       flashtest_h = V_ULONG (baseaddr + 8);   /* device ID           */
+       flashtest_l = V_ULONG (baseaddr + 12);
+       if (flashtest_h != flashtest_l) {
+               info->flash_id = FLASH_UNKNOWN;
+       } else {
+               switch (flashtest_h) {
+               case AMD_ID_LV800T:
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00400000;
+                       break;                  /* 4 * 1 MB = 4 MB  */
+               case AMD_ID_LV800B:
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00400000;
+                       break;                  /* 4 * 1 MB = 4 MB  */
+               case AMD_ID_LV160T:
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00800000;
+                       break;                  /* 4 * 2 MB = 8 MB  */
+               case AMD_ID_LV160B:
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00800000;
+                       break;                  /* 4 * 2 MB = 8 MB  */
+               case AMD_ID_DL322T:
+                       info->flash_id += FLASH_AMDL322T;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL322B:
+                       info->flash_id += FLASH_AMDL322B;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL323T:
+                       info->flash_id += FLASH_AMDL323T;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL323B:
+                       info->flash_id += FLASH_AMDL323B;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_LV640U:
+                       info->flash_id += FLASH_AM640U;
+                       info->sector_count = 128;
+                       info->size = 0x02000000;
+                       break;                  /* 4 * 8 MB = 32 MB */
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       return (0);             /* no or unknown flash     */
+               }
+       }
+
+       if (flashtest_h == AMD_ID_LV640U) {
+
+               /* set up sector start adress table (uniform sector type) */
+               for (i = 0; i < info->sector_count; i++)
+                       info->start[i] = baseaddr + (i * 0x00040000);
+
+       } else if (info->flash_id & FLASH_BTYPE) {
+
+               /* set up sector start adress table (bottom sector type) */
+               info->start[0] = baseaddr + 0x00000000;
+               info->start[1] = baseaddr + 0x00010000;
+               info->start[2] = baseaddr + 0x00018000;
+               info->start[3] = baseaddr + 0x00020000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
+               }
+
+       } else {
+
+               /* set up sector start adress table (top sector type) */
+               i = info->sector_count - 1;
+               info->start[i--] = baseaddr + info->size - 0x00010000;
+               info->start[i--] = baseaddr + info->size - 0x00018000;
+               info->start[i--] = baseaddr + info->size - 0x00020000;
+               for (; i >= 0; i--) {
+                       info->start[i] = baseaddr + i * 0x00040000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
+                       (V_ULONG (info->start[i] + 20) & 0x00010001)) {
+                       info->protect[i] = 1;   /* D0 = 1 if protected */
+               } else {
+                       info->protect[i] = 0;
+               }
+       }
+
+       flash_reset ();
+       return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+       unsigned long size_b0 = 0;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here (only one bank) */
+
+       size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]);
+       if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                               size_b0, size_b0 >> 20);
+       }
+
+       /*
+        * protect monitor and environment sectors
+        */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_MONITOR_BASE,
+                      CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_ENV_ADDR,
+                      CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+#endif
+
+       return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:
+               printf ("AMD ");
+               break;
+       case FLASH_MAN_FUJ:
+               printf ("FUJITSU ");
+               break;
+       default:
+               printf ("Unknown Vendor ");
+               break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM800T:
+               printf ("29LV800T (8 M, top sector)\n");
+               break;
+       case FLASH_AM800B:
+               printf ("29LV800T (8 M, bottom sector)\n");
+               break;
+       case FLASH_AM160T:
+               printf ("29LV160T (16 M, top sector)\n");
+               break;
+       case FLASH_AM160B:
+               printf ("29LV160B (16 M, bottom sector)\n");
+               break;
+       case FLASH_AMDL322T:
+               printf ("29DL322T (32 M, top sector)\n");
+               break;
+       case FLASH_AMDL322B:
+               printf ("29DL322B (32 M, bottom sector)\n");
+               break;
+       case FLASH_AMDL323T:
+               printf ("29DL323T (32 M, top sector)\n");
+               break;
+       case FLASH_AMDL323B:
+               printf ("29DL323B (32 M, bottom sector)\n");
+               break;
+       case FLASH_AM640U:
+               printf ("29LV640D (64 M, uniform sector)\n");
+               break;
+       default:
+               printf ("Unknown Chip Type\n");
+               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i = 0; i < info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       prot = 0;
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect])
+                       prot++;
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts ();
+
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       udelay (1000);
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       V_ULONG (info->start[sect]) = 0x00300030;
+                       V_ULONG (info->start[sect] + 4) = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts ();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last = start;
+       while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
+              (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
+       {
+               if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       serial_putc ('.');
+                       last = now;
+               }
+       }
+
+  DONE:
+       /* reset to read mode */
+       flash_reset ();
+
+       printf (" done\n");
+       return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+       ulong dp;
+       static unsigned char bb[8];
+       int i, l, rc, cc = cnt;
+
+       dp = (addr & ~7);               /* get lower dword aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - dp) != 0) {
+               for (i = 0; i < 8; i++)
+                       bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
+               if ((rc = write_dword (info, dp, bb)) != 0) {
+                       return (rc);
+               }
+               dp += 8;
+               cc -= 8 - l;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cc >= 8) {
+               if ((rc = write_dword (info, dp, src)) != 0) {
+                       return (rc);
+               }
+               dp += 8;
+               src += 8;
+               cc -= 8;
+       }
+
+       if (cc <= 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       for (i = 0; i < 8; i++) {
+               bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
+       }
+       return (write_dword (info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
+{
+       ulong start, cl, ch;
+       int flag, i;
+
+       for (ch = 0, i = 0; i < 4; i++)
+               ch = (ch << 8) + *pdata++;      /* high word    */
+       for (cl = 0, i = 0; i < 4; i++)
+               cl = (cl << 8) + *pdata++;      /* low word */
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *) dest) & ch) != ch
+               || (*((vu_long *) (dest + 4)) & cl) != cl) {
+               return (2);
+       }
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts ();
+
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
+       V_ULONG (dest) = ch;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
+       V_ULONG (dest + 4) = cl;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts ();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
+                  ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
+               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
diff --git a/board/siemens/pcu_e/flash.c b/board/siemens/pcu_e/flash.c
new file mode 100644 (file)
index 0000000..b8c0df7
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ *
+ * The PCU E uses an address map where flash banks are aligned top
+ * down, so that the "first" flash bank ends at top of memory, and
+ * the monitor entry point is at address (0xFFF00100). The second
+ * flash bank is mapped immediately below bank 0.
+ *
+ * This is NOT in conformance to the "official" memory map!
+ *
+ */
+
+#define PCU_MONITOR_BASE   ( (flash_info[0].start[0] + flash_info[0].size - 1) \
+                          - (0xFFFFFFFF - CFG_MONITOR_BASE) )
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long base, size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       /*
+        * Warning:
+        *
+        * Since the PCU E memory map assigns flash banks top down,
+        * we swap the numbering later if both banks are equipped,
+        * so they look like a contiguous area of memory.
+        */
+       DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+       DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE6_PRELIM);
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE6_PRELIM, &flash_info[1]);
+
+       DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n", size_b0, size_b1);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+
+       DEBUGF ("## Before remap: "
+               "BR0: 0x%08x    OR0: 0x%08x    "
+               "BR6: 0x%08x    OR6: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0,
+               memctl->memc_br6, memctl->memc_or6);
+
+       /* Remap FLASH according to real size */
+       base = 0 - size_b0;
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+       memctl->memc_br0 = (base & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+       DEBUGF("## BR0: 0x%08x    OR0: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0);
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)base, &flash_info[0]);
+       base = 0 - size_b0;
+
+       flash_info[0].size = size_b0;
+
+       flash_get_offsets (base, &flash_info[0]);
+
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     PCU_MONITOR_BASE,
+                     PCU_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               flash_info_t tmp_info;
+
+               memctl->memc_or6 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+               memctl->memc_br6 = ((base - size_b1) & BR_BA_MSK) |
+                                   BR_PS_16 | BR_MS_GPCM | BR_V;
+
+               DEBUGF("## New BR6: 0x%08x    OR6: 0x%08x\n",
+                       memctl->memc_br6, memctl->memc_or6);
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(base - size_b1),
+                                         &flash_info[1]);
+               base -= size_b1;
+
+               flash_get_offsets (base, &flash_info[1]);
+
+               flash_info[1].size = size_b1;
+
+#ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                             &flash_info[1]);
+#endif
+               /*
+                * Swap bank numbers so that addresses are in ascending order
+                */
+               tmp_info = flash_info[0];
+               flash_info[0] = flash_info[1];
+               flash_info[1] = tmp_info;
+       } else {
+               memctl->memc_br1 = 0;           /* invalidate bank */
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+       }
+
+
+       DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+       short n;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               return;
+       }
+
+       if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD) {
+               return;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AMDL322T:
+       case FLASH_AMDL323T:
+       case FLASH_AMDL324T:
+               /* set sector offsets for top boot block type           */
+
+               base += info->size;
+               i = info->sector_count;
+               for (n=0; n<8; ++n) {           /*  8 x 8k boot sectors */
+                       base -= 8 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+               while (i > 0) {                 /* 64k regular sectors  */
+                       base -= 64 << 10;
+                       --i;
+                       info->start[i] = base;
+               }
+               return;
+       case FLASH_AMDL322B:
+       case FLASH_AMDL323B:
+       case FLASH_AMDL324B:
+               /* set sector offsets for bottom boot block type        */
+               for (i=0; i<8; ++i) {           /*  8 x 8k boot sectors */
+                       info->start[i] = base;
+                       base += 8 << 10;
+               }
+               while (base < info->size) {     /* 64k regular sectors  */
+                       info->start[i] = base;
+                       base += 64 << 10;
+                       ++i;
+               }
+               return;
+       case FLASH_AMDL640:
+               /* set sector offsets for dual boot block type          */
+               for (i=0; i<8; ++i) {           /*  8 x 8k boot sectors */
+                       info->start[i] = base;
+                       base += 8 << 10;
+               }
+               n = info->sector_count - 8;
+               while (i < n) {                 /* 64k regular sectors  */
+                       info->start[i] = base;
+                       base += 64 << 10;
+                       ++i;
+               }
+               while (i < info->sector_count) { /* 8 x 8k boot sectors */
+                       info->start[i] = base;
+                       base += 8 << 10;
+                       ++i;
+               }
+               return;
+       default:
+               return;
+       }
+       /* NOTREACHED */
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AMDL322B:    printf ("AM29DL322B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AMDL322T:    printf ("AM29DL322T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AMDL323B:    printf ("AM29DL323B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AMDL323T:    printf ("AM29DL323T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AMDL324B:    printf ("AM29DL324B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AMDL324T:    printf ("AM29DL324T (32 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AMDL640:     printf ("AM29DL640D (64 Mbit, dual boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type 0x%lX\n",
+                                       info->flash_id);
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ushort value;
+       vu_short *saddr = (vu_short *)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+       saddr[0x0555] = 0x00AA;
+       saddr[0x02AA] = 0x0055;
+       saddr[0x0555] = 0x0090;
+
+       value = saddr[0];
+
+       DEBUGF("Manuf. ID @ 0x%08lx: 0x%04x\n", (ulong)addr, value);
+
+       switch (value) {
+       case (AMD_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case (FUJ_MANUFACT & 0xFFFF):
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               DEBUGF("Unknown Manufacturer ID\n");
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = saddr[1];                       /* device ID            */
+
+       DEBUGF("Device ID @ 0x%08lx: 0x%04x\n", (ulong)(&addr[1]), value);
+
+       switch (value) {
+
+       case (AMD_ID_DL322T & 0xFFFF):
+               info->flash_id += FLASH_AMDL322T;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_DL322B & 0xFFFF):
+               info->flash_id += FLASH_AMDL322B;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_DL323T & 0xFFFF):
+               info->flash_id += FLASH_AMDL323T;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_DL323B & 0xFFFF):
+               info->flash_id += FLASH_AMDL323B;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_DL324T & 0xFFFF):
+               info->flash_id += FLASH_AMDL324T;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+
+       case (AMD_ID_DL324B & 0xFFFF):
+               info->flash_id += FLASH_AMDL324B;
+               info->sector_count = 71;
+               info->size = 0x00400000;
+               break;                          /* => 8 MB              */
+       case (AMD_ID_DL640  & 0xFFFF):
+               info->flash_id += FLASH_AMDL640;
+               info->sector_count = 142;
+               info->size = 0x00800000;
+               break;
+       default:
+               DEBUGF("Unknown Device ID\n");
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+
+       }
+
+       flash_get_offsets ((ulong)addr, info);
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+#if 0
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               saddr = (vu_short *)(info->start[i]);
+               info->protect[i] = saddr[2] & 1;
+#else
+               info->protect[i] =0;
+#endif
+       }
+
+       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+               printf ("** ERROR: sector count %d > max (%d) **\n",
+                       info->sector_count, CFG_MAX_FLASH_SECT);
+               info->sector_count = CFG_MAX_FLASH_SECT;
+       }
+
+       saddr = (vu_short *)info->start[0];
+       *saddr = 0x00F0;        /* restore read mode */
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_short *addr = (vu_short*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+       addr[0x0555] = 0x0080;
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_short*)(info->start[sect]);
+                       addr[0] = 0x0030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_short*)(info->start[l_sect]);
+       while ((addr[0] & 0x0080) != 0x0080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (vu_short *)info->start[0];
+       addr[0] = 0x00F0;       /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+#define FLASH_WIDTH    2       /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<FLASH_WIDTH && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += FLASH_WIDTH;
+       }
+
+       /*
+        * handle FLASH_WIDTH aligned part
+        */
+       while (cnt >= FLASH_WIDTH) {
+               data = 0;
+               for (i=0; i<FLASH_WIDTH; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_data(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += FLASH_WIDTH;
+               cnt -= FLASH_WIDTH;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<FLASH_WIDTH; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_short *addr  = (vu_short*)(info->start[0]);
+       vu_short *sdest = (vu_short *)dest;
+       ushort sdata = (ushort)data;
+       ushort sval;
+       ulong start, passed;
+       int flag, rc;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*sdest & sdata) != sdata) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA;
+       addr[0x02AA] = 0x0055;
+       addr[0x0555] = 0x00A0;
+
+#ifdef WORKAROUND_FOR_BROKEN_HARDWARE
+       /* work around the timeout bugs */
+       udelay(20);
+#endif
+
+       *sdest = sdata;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       rc = 0;
+       /* data polling for D7 */
+       start = get_timer (0);
+
+       for (passed=0; passed < CFG_FLASH_WRITE_TOUT; passed=get_timer(start)) {
+
+               sval = *sdest;
+
+               if ((sval & 0x0080) == (sdata & 0x0080))
+                       break;
+
+               if ((sval & 0x0020) == 0)       /* DQ5: Timeout? */
+                       continue;
+
+               sval = *sdest;
+
+               if ((sval & 0x0080) != (sdata & 0x0080))
+                       rc = 1;
+
+               break;
+       }
+
+       if (rc) {
+           DEBUGF ("Program cycle failed @ addr 0x%08lX: val %04X data %04X\n",
+                dest, sval, sdata);
+       }
+
+       if (passed >= CFG_FLASH_WRITE_TOUT) {
+               DEBUGF ("Timeout @ addr 0x%08lX: val %04X data %04X\n",
+                       dest, sval, sdata);
+               rc = 1;
+       }
+
+       /* reset to read mode */
+       addr = (vu_short *)info->start[0];
+       addr[0] = 0x00F0;       /* reset bank */
+
+       return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/sixnet/flash.c b/board/sixnet/flash.c
new file mode 100644 (file)
index 0000000..c201875
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
+ *        has nothing to do with the flash chip being 8-bit or 16-bit.
+ */
+#ifdef CONFIG_FLASH_16BIT
+typedef unsigned short FLASH_PORT_WIDTH;
+typedef volatile unsigned short FLASH_PORT_WIDTHV;
+#define        FLASH_ID_MASK   0xFFFF
+#else
+typedef unsigned long FLASH_PORT_WIDTH;
+typedef volatile unsigned long FLASH_PORT_WIDTHV;
+#define        FLASH_ID_MASK   0xFFFFFFFF
+#endif
+
+#define FPW    FLASH_PORT_WIDTH
+#define FPWV   FLASH_PORT_WIDTHV
+
+#define ORMASK(size) ((-size) & OR_AM_MSK)
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size(FPWV *addr, flash_info_t *info);
+static void flash_reset(flash_info_t *info);
+static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
+static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
+static void flash_get_offsets(ulong base, flash_info_t *info);
+#ifdef CFG_FLASH_PROTECTION
+static void flash_sync_real_protect(flash_info_t *info);
+#endif
+
+/*-----------------------------------------------------------------------
+ * flash_init()
+ *
+ * sets up flash_info and returns size of FLASH (bytes)
+ */
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       size_b = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size_b;
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",size_b);
+       }
+
+       /* Remap FLASH according to real size, so only at proper address */
+       memctl->memc_or0 = (memctl->memc_or0 & ~OR_AM_MSK) | ORMASK(size_b);
+
+       /* Do this again (was done already in flast_get_size), just
+        * in case we move it when remap the FLASH.
+        */
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#ifdef CFG_FLASH_PROTECTION
+       /* read the hardware protection status (if any) into the
+        * protection array in flash_info.
+        */
+       flash_sync_real_protect(&flash_info[0]);
+#endif
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+       return (size_b);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_reset(flash_info_t *info)
+{
+       FPWV *base = (FPWV *)(info->start[0]);
+
+       /* Put FLASH back in read mode */
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+               *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
+       else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
+               *base = (FPW)0x00F000F0;        /* AMD Read Mode */
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
+           && (info->flash_id & FLASH_BTYPE)) {
+               int bootsect_size;      /* number of bytes/boot sector  */
+               int sect_size;          /* number of bytes/regular sector */
+
+               bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+               sect_size =     0x00010000 * (sizeof(FPW)/2);
+
+               /* set sector offsets for bottom boot block type        */
+               for (i = 0; i < 8; ++i) {
+                       info->start[i] = base + (i * bootsect_size);
+               }
+               for (i = 8; i < info->sector_count; i++) {
+                       info->start[i] = base + ((i - 7) * sect_size);
+               }
+       }
+       else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
+                && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
+
+               int sect_size;          /* number of bytes/sector */
+
+               sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+               /* set up sector start address table (uniform sector type) */
+               for( i = 0; i < info->sector_count; i++ )
+                       info->start[i] = base + (i * sect_size);
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_print_info (flash_info_t *info)
+{
+       int i;
+       uchar *boottype;
+       uchar *bootletter;
+       uchar *fmt;
+       uchar botbootletter[] = "B";
+       uchar topbootletter[] = "T";
+       uchar botboottype[] = "bottom boot sector";
+       uchar topboottype[] = "top boot sector";
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       /* check for top or bottom boot, if it applies */
+       if (info->flash_id & FLASH_BTYPE) {
+               boottype = botboottype;
+               bootletter = botbootletter;
+       }
+       else {
+               boottype = topboottype;
+               bootletter = topbootletter;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM640U:
+               fmt = "29LV641D (64 Mbit, uniform sectors)\n";
+               break;
+        case FLASH_28F800C3B:
+        case FLASH_28F800C3T:
+               fmt = "28F800C3%s (8 Mbit, %s)\n";
+               break;
+       case FLASH_INTEL800B:
+       case FLASH_INTEL800T:
+               fmt = "28F800B3%s (8 Mbit, %s)\n";
+               break;
+        case FLASH_28F160C3B:
+        case FLASH_28F160C3T:
+               fmt = "28F160C3%s (16 Mbit, %s)\n";
+               break;
+       case FLASH_INTEL160B:
+       case FLASH_INTEL160T:
+               fmt = "28F160B3%s (16 Mbit, %s)\n";
+               break;
+        case FLASH_28F320C3B:
+        case FLASH_28F320C3T:
+               fmt = "28F320C3%s (32 Mbit, %s)\n";
+               break;
+       case FLASH_INTEL320B:
+       case FLASH_INTEL320T:
+               fmt = "28F320B3%s (32 Mbit, %s)\n";
+               break;
+        case FLASH_28F640C3B:
+        case FLASH_28F640C3T:
+               fmt = "28F640C3%s (64 Mbit, %s)\n";
+               break;
+       case FLASH_INTEL640B:
+       case FLASH_INTEL640T:
+               fmt = "28F640B3%s (64 Mbit, %s)\n";
+               break;
+       default:
+               fmt = "Unknown Chip Type\n";
+               break;
+       }
+
+       printf (fmt, bootletter, boottype);
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20,
+               info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0) {
+                       printf ("\n   ");
+               }
+
+               printf (" %08lX%s", info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+       }
+
+       printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+ulong flash_get_size (FPWV *addr, flash_info_t *info)
+{
+       /* Write auto select command: read Manufacturer ID */
+
+       /* Write auto select command sequence and test FLASH answer */
+       addr[0x0555] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
+       addr[0x02AA] = (FPW)0x00550055; /* for AMD, Intel ignores this */
+       addr[0x0555] = (FPW)0x00900090; /* selects Intel or AMD */
+
+       /* The manufacturer codes are only 1 byte, so just use 1 byte.
+        * This works for any bus width and any FLASH device width.
+        */
+       switch (addr[0] & 0xff) {
+
+       case (uchar)AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+
+       case (uchar)INTEL_MANUFACT:
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               break;
+       }
+
+       /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
+       if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) {
+
+       case (FPW)AMD_ID_LV640U:        /* 29LV640 and 29LV641 have same ID */
+               info->flash_id += FLASH_AM640U;
+               info->sector_count = 128;
+               info->size = 0x00800000 * (sizeof(FPW)/2);
+               break;                          /* => 8 or 16 MB        */
+
+       case (FPW)INTEL_ID_28F800C3B:
+               info->flash_id += FLASH_28F800C3B;
+               info->sector_count = 23;
+               info->size = 0x00100000 * (sizeof(FPW)/2);
+               break;                          /* => 1 or 2 MB         */
+
+       case (FPW)INTEL_ID_28F800B3B:
+               info->flash_id += FLASH_INTEL800B;
+               info->sector_count = 23;
+               info->size = 0x00100000 * (sizeof(FPW)/2);
+               break;                          /* => 1 or 2 MB         */
+
+       case (FPW)INTEL_ID_28F160C3B:
+               info->flash_id += FLASH_28F160C3B;
+               info->sector_count = 39;
+               info->size = 0x00200000 * (sizeof(FPW)/2);
+               break;                          /* => 2 or 4 MB         */
+
+       case (FPW)INTEL_ID_28F160B3B:
+               info->flash_id += FLASH_INTEL160B;
+               info->sector_count = 39;
+               info->size = 0x00200000 * (sizeof(FPW)/2);
+               break;                          /* => 2 or 4 MB         */
+
+       case (FPW)INTEL_ID_28F320C3B:
+               info->flash_id += FLASH_28F320C3B;
+               info->sector_count = 71;
+               info->size = 0x00400000 * (sizeof(FPW)/2);
+               break;                          /* => 4 or 8 MB         */
+
+       case (FPW)INTEL_ID_28F320B3B:
+               info->flash_id += FLASH_INTEL320B;
+               info->sector_count = 71;
+               info->size = 0x00400000 * (sizeof(FPW)/2);
+               break;                          /* => 4 or 8 MB         */
+
+       case (FPW)INTEL_ID_28F640C3B:
+               info->flash_id += FLASH_28F640C3B;
+               info->sector_count = 135;
+               info->size = 0x00800000 * (sizeof(FPW)/2);
+               break;                          /* => 8 or 16 MB        */
+
+       case (FPW)INTEL_ID_28F640B3B:
+               info->flash_id += FLASH_INTEL640B;
+               info->sector_count = 135;
+               info->size = 0x00800000 * (sizeof(FPW)/2);
+               break;                          /* => 8 or 16 MB        */
+
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* => no or unknown flash */
+       }
+
+       flash_get_offsets((ulong)addr, info);
+
+       /* Put FLASH back in read mode */
+       flash_reset(info);
+
+       return (info->size);
+}
+
+#ifdef CFG_FLASH_PROTECTION
+/*-----------------------------------------------------------------------
+ */
+
+static void flash_sync_real_protect(flash_info_t *info)
+{
+    FPWV *addr = (FPWV *)(info->start[0]);
+    FPWV *sect;
+    int i;
+
+    switch (info->flash_id & FLASH_TYPEMASK) {
+    case FLASH_28F800C3B:
+    case FLASH_28F800C3T:
+    case FLASH_28F160C3B:
+    case FLASH_28F160C3T:
+    case FLASH_28F320C3B:
+    case FLASH_28F320C3T:
+    case FLASH_28F640C3B:
+    case FLASH_28F640C3T:
+       /* check for protected sectors */
+       *addr = (FPW)0x00900090;
+       for (i = 0; i < info->sector_count; i++) {
+           /* read sector protection at sector address, (A7 .. A0) = 0x02.
+            * D0 = 1 for each device if protected.
+            * If at least one device is protected the sector is marked
+            * protected, but mixed protected and  unprotected devices
+            * within a sector should never happen.
+            */
+           sect = (FPWV *)(info->start[i]);
+           info->protect[i] = (sect[2] & (FPW)(0x00010001)) ? 1 : 0;
+       }
+
+       /* Put FLASH back in read mode */
+       flash_reset(info);
+       break;
+
+    case FLASH_AM640U:
+    default:
+       /* no hardware protect that we support */
+       break;
+    }
+}
+#endif
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       FPWV *addr;
+       int flag, prot, sect;
+       int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
+       ulong start, now, last;
+       int rcode = 0;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_INTEL800B:
+       case FLASH_INTEL160B:
+       case FLASH_INTEL320B:
+       case FLASH_INTEL640B:
+       case FLASH_28F800C3B:
+       case FLASH_28F160C3B:
+       case FLASH_28F320C3B:
+       case FLASH_28F640C3B:
+       case FLASH_AM640U:
+               break;
+       case FLASH_UNKNOWN:
+       default:
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       start = get_timer(0);
+       last  = start;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
+
+               if (info->protect[sect] != 0)   /* protected, skip it */
+                       continue;
+
+               /* Disable interrupts which might cause a timeout here */
+               flag = disable_interrupts();
+
+               addr = (FPWV *)(info->start[sect]);
+               if (intel) {
+                       *addr = (FPW)0x00500050; /* clear status register */
+                       *addr = (FPW)0x00200020; /* erase setup */
+                       *addr = (FPW)0x00D000D0; /* erase confirm */
+               }
+               else {
+                       /* must be AMD style if not Intel */
+                       FPWV *base;             /* first address in bank */
+
+                       base = (FPWV *)(info->start[0]);
+                       base[0x0555] = (FPW)0x00AA00AA; /* unlock */
+                       base[0x02AA] = (FPW)0x00550055; /* unlock */
+                       base[0x0555] = (FPW)0x00800080; /* erase mode */
+                       base[0x0555] = (FPW)0x00AA00AA; /* unlock */
+                       base[0x02AA] = (FPW)0x00550055; /* unlock */
+                       *addr = (FPW)0x00300030;        /* erase sector */
+               }
+
+               /* re-enable interrupts if necessary */
+               if (flag)
+                       enable_interrupts();
+
+               /* wait at least 50us for AMD, 80us for Intel.
+                * Let's wait 1 ms.
+                */
+               udelay (1000);
+
+               while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
+                       if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                               printf ("Timeout\n");
+
+                               if (intel) {
+                                       /* suspend erase        */
+                                       *addr = (FPW)0x00B000B0;
+                               }
+
+                               flash_reset(info);      /* reset to read mode */
+                               rcode = 1;              /* failed */
+                               break;
+                       }
+
+                       /* show that we're waiting */
+                       if ((now - last) > 1000) {      /* every second */
+                               putc ('.');
+                               last = now;
+                       }
+               }
+
+               flash_reset(info);      /* reset to read mode   */
+       }
+
+       printf (" done\n");
+       return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
+    int bytes;   /* number of bytes to program in current word         */
+    int left;    /* number of bytes left to program                    */
+    int i, res;
+
+    for (left = cnt, res = 0;
+        left > 0 && res == 0;
+        addr += sizeof(data), left -= sizeof(data) - bytes) {
+
+        bytes = addr & (sizeof(data) - 1);
+        addr &= ~(sizeof(data) - 1);
+
+       /* combine source and destination data so can program
+        * an entire word of 16 or 32 bits
+        */
+        for (i = 0; i < sizeof(data); i++) {
+            data <<= 8;
+            if (i < bytes || i - bytes >= left )
+               data += *((uchar *)addr + i);
+           else
+               data += *src++;
+       }
+
+       /* write one word to the flash */
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:
+               res = write_word_amd(info, (FPWV *)addr, data);
+               break;
+       case FLASH_MAN_INTEL:
+               res = write_word_intel(info, (FPWV *)addr, data);
+               break;
+       default:
+               /* unknown flash type, error! */
+               printf ("missing or unknown FLASH type\n");
+               res = 1;        /* not really a timeout, but gives error */
+               break;
+       }
+    }
+
+    return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for AMD FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
+{
+    ulong start;
+    int flag;
+    int res = 0;       /* result, assume success       */
+    FPWV *base;                /* first address in flash bank  */
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*dest & data) != data) {
+       return (2);
+    }
+
+
+    base = (FPWV *)(info->start[0]);
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    base[0x0555] = (FPW)0x00AA00AA;    /* unlock */
+    base[0x02AA] = (FPW)0x00550055;    /* unlock */
+    base[0x0555] = (FPW)0x00A000A0;    /* selects program mode */
+
+    *dest = data;              /* start programming the data   */
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+       enable_interrupts();
+
+    start = get_timer (0);
+
+    /* data polling for D7 */
+    while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
+       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+           *dest = (FPW)0x00F000F0;    /* reset bank */
+           res = 1;
+       }
+    }
+
+    return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for Intel FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
+{
+    ulong start;
+    int flag;
+    int res = 0;       /* result, assume success       */
+
+    /* Check if Flash is (sufficiently) erased */
+    if ((*dest & data) != data) {
+       return (2);
+    }
+
+    /* Disable interrupts which might cause a timeout here */
+    flag = disable_interrupts();
+
+    *dest = (FPW)0x00500050;   /* clear status register        */
+    *dest = (FPW)0x00FF00FF;   /* make sure in read mode       */
+    *dest = (FPW)0x00400040;   /* program setup                */
+
+    *dest = data;              /* start programming the data   */
+
+    /* re-enable interrupts if necessary */
+    if (flag)
+       enable_interrupts();
+
+    start = get_timer (0);
+
+    while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
+       if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+           *dest = (FPW)0x00B000B0;    /* Suspend program      */
+           res = 1;
+       }
+    }
+
+    if (res == 0 && (*dest & (FPW)0x00100010))
+       res = 1;        /* write failed, time out error is close enough */
+
+    *dest = (FPW)0x00500050;   /* clear status register        */
+    *dest = (FPW)0x00FF00FF;   /* make sure in read mode       */
+
+    return (res);
+}
+
+#ifdef CFG_FLASH_PROTECTION
+/*-----------------------------------------------------------------------
+ */
+int flash_real_protect (flash_info_t * info, long sector, int prot)
+{
+       int rcode = 0;          /* assume success */
+       FPWV *addr;             /* address of sector */
+       FPW value;
+
+       addr = (FPWV *) (info->start[sector]);
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F800C3B:
+       case FLASH_28F800C3T:
+       case FLASH_28F160C3B:
+       case FLASH_28F160C3T:
+       case FLASH_28F320C3B:
+       case FLASH_28F320C3T:
+       case FLASH_28F640C3B:
+       case FLASH_28F640C3T:
+               flash_reset (info);             /* make sure in read mode */
+               *addr = (FPW) 0x00600060L;      /* lock command setup */
+               if (prot)
+                       *addr = (FPW) 0x00010001L;      /* lock sector */
+               else
+                       *addr = (FPW) 0x00D000D0L;      /* unlock sector */
+               flash_reset (info);             /* reset to read mode */
+
+               /* now see if it really is locked/unlocked as requested */
+               *addr = (FPW) 0x00900090;
+               /* read sector protection at sector address, (A7 .. A0) = 0x02.
+                * D0 = 1 for each device if protected.
+                * If at least one device is protected the sector is marked
+                * protected, but return failure. Mixed protected and
+                * unprotected devices within a sector should never happen.
+                */
+               value = addr[2] & (FPW) 0x00010001;
+               if (value == 0)
+                       info->protect[sector] = 0;
+               else if (value == (FPW) 0x00010001)
+                       info->protect[sector] = 1;
+               else {
+                       /* error, mixed protected and unprotected */
+                       rcode = 1;
+                       info->protect[sector] = 1;
+               }
+               if (info->protect[sector] != prot)
+                       rcode = 1;      /* failed to protect/unprotect as requested */
+
+               /* reload all protection bits from hardware for now */
+               flash_sync_real_protect (info);
+               break;
+
+       case FLASH_AM640U:
+       default:
+               /* no hardware protect that we support */
+               info->protect[sector] = prot;
+               break;
+       }
+
+       return rcode;
+}
+#endif
diff --git a/board/spd8xx/flash.c b/board/spd8xx/flash.c
new file mode 100644 (file)
index 0000000..8c0bb4f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * (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 <mpc8xx.h>
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       /* All Speech Design board memory (DRAM and EPROM) initialisation is
+       done in dram_init().
+       The caller of ths function here expects the total size and will hang,
+       if we give here back 0. So we return the EPROM size. */
+
+       return (1024 * 1024); /* 1 MB */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_print_info (flash_info_t *info)
+{
+       printf("no FLASH memory in MPC823TS board\n");
+       return;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       return 1;
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/board/tqm8260/flash.c b/board/tqm8260/flash.c
new file mode 100644 (file)
index 0000000..dd7a4cc
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD devices on the TQM8260 board
+ *
+ *--------------------------------------------------------------------
+ * 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 <mpc8xx.h>
+
+#define V_ULONG(a)     (*(volatile unsigned long *)( a ))
+#define V_BYTE(a)      (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset (void)
+{
+       if (flash_info[0].flash_id != FLASH_UNKNOWN) {
+               V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
+               V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size (ulong baseaddr, flash_info_t * info)
+{
+       short i;
+       unsigned long flashtest_h, flashtest_l;
+
+       /* Write auto select command sequence and test FLASH answer */
+       V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
+       V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
+       V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
+
+       flashtest_h = V_ULONG (baseaddr);       /* manufacturer ID     */
+       flashtest_l = V_ULONG (baseaddr + 4);
+
+       switch ((int) flashtest_h) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash     */
+       }
+
+       flashtest_h = V_ULONG (baseaddr + 8);   /* device ID           */
+       flashtest_l = V_ULONG (baseaddr + 12);
+       if (flashtest_h != flashtest_l) {
+               info->flash_id = FLASH_UNKNOWN;
+       } else {
+               switch (flashtest_h) {
+               case AMD_ID_LV800T:
+                       info->flash_id += FLASH_AM800T;
+                       info->sector_count = 19;
+                       info->size = 0x00400000;
+                       break;                  /* 4 * 1 MB = 4 MB  */
+               case AMD_ID_LV800B:
+                       info->flash_id += FLASH_AM800B;
+                       info->sector_count = 19;
+                       info->size = 0x00400000;
+                       break;                  /* 4 * 1 MB = 4 MB  */
+               case AMD_ID_LV160T:
+                       info->flash_id += FLASH_AM160T;
+                       info->sector_count = 35;
+                       info->size = 0x00800000;
+                       break;                  /* 4 * 2 MB = 8 MB  */
+               case AMD_ID_LV160B:
+                       info->flash_id += FLASH_AM160B;
+                       info->sector_count = 35;
+                       info->size = 0x00800000;
+                       break;                  /* 4 * 2 MB = 8 MB  */
+               case AMD_ID_DL322T:
+                       info->flash_id += FLASH_AMDL322T;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL322B:
+                       info->flash_id += FLASH_AMDL322B;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL323T:
+                       info->flash_id += FLASH_AMDL323T;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_DL323B:
+                       info->flash_id += FLASH_AMDL323B;
+                       info->sector_count = 71;
+                       info->size = 0x01000000;
+                       break;                  /* 4 * 4 MB = 16 MB */
+               case AMD_ID_LV640U:
+                       info->flash_id += FLASH_AM640U;
+                       info->sector_count = 128;
+                       info->size = 0x02000000;
+                       break;                  /* 4 * 8 MB = 32 MB */
+               default:
+                       info->flash_id = FLASH_UNKNOWN;
+                       return (0);             /* no or unknown flash     */
+               }
+       }
+
+       if (flashtest_h == AMD_ID_LV640U) {
+
+               /* set up sector start adress table (uniform sector type) */
+               for (i = 0; i < info->sector_count; i++)
+                       info->start[i] = baseaddr + (i * 0x00040000);
+
+       } else if (info->flash_id & FLASH_BTYPE) {
+
+               /* set up sector start adress table (bottom sector type) */
+               info->start[0] = baseaddr + 0x00000000;
+               info->start[1] = baseaddr + 0x00010000;
+               info->start[2] = baseaddr + 0x00018000;
+               info->start[3] = baseaddr + 0x00020000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
+               }
+
+       } else {
+
+               /* set up sector start adress table (top sector type) */
+               i = info->sector_count - 1;
+               info->start[i--] = baseaddr + info->size - 0x00010000;
+               info->start[i--] = baseaddr + info->size - 0x00018000;
+               info->start[i--] = baseaddr + info->size - 0x00020000;
+               for (; i >= 0; i--) {
+                       info->start[i] = baseaddr + i * 0x00040000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
+                       (V_ULONG (info->start[i] + 20) & 0x00010001)) {
+                       info->protect[i] = 1;   /* D0 = 1 if protected */
+               } else {
+                       info->protect[i] = 0;
+               }
+       }
+
+       flash_reset ();
+       return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+       unsigned long size_b0 = 0;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here (only one bank) */
+
+       size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]);
+       if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                               size_b0, size_b0 >> 20);
+       }
+
+       /*
+        * protect monitor and environment sectors
+        */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_MONITOR_BASE,
+                      CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_ENV_ADDR,
+                      CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+#endif
+
+       return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:
+               printf ("AMD ");
+               break;
+       case FLASH_MAN_FUJ:
+               printf ("FUJITSU ");
+               break;
+       default:
+               printf ("Unknown Vendor ");
+               break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM800T:
+               printf ("29LV800T (8 M, top sector)\n");
+               break;
+       case FLASH_AM800B:
+               printf ("29LV800T (8 M, bottom sector)\n");
+               break;
+       case FLASH_AM160T:
+               printf ("29LV160T (16 M, top sector)\n");
+               break;
+       case FLASH_AM160B:
+               printf ("29LV160B (16 M, bottom sector)\n");
+               break;
+       case FLASH_AMDL322T:
+               printf ("29DL322T (32 M, top sector)\n");
+               break;
+       case FLASH_AMDL322B:
+               printf ("29DL322B (32 M, bottom sector)\n");
+               break;
+       case FLASH_AMDL323T:
+               printf ("29DL323T (32 M, top sector)\n");
+               break;
+       case FLASH_AMDL323B:
+               printf ("29DL323B (32 M, bottom sector)\n");
+               break;
+       case FLASH_AM640U:
+               printf ("29LV640D (64 M, uniform sector)\n");
+               break;
+       default:
+               printf ("Unknown Chip Type\n");
+               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+                       info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i = 0; i < info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+       return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       prot = 0;
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect])
+                       prot++;
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts ();
+
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       udelay (1000);
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect <= s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       V_ULONG (info->start[sect]) = 0x00300030;
+                       V_ULONG (info->start[sect] + 4) = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts ();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last = start;
+       while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
+              (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
+       {
+               if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       serial_putc ('.');
+                       last = now;
+               }
+       }
+
+  DONE:
+       /* reset to read mode */
+       flash_reset ();
+
+       printf (" done\n");
+       return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+       ulong dp;
+       static unsigned char bb[8];
+       int i, l, rc, cc = cnt;
+
+       dp = (addr & ~7);               /* get lower dword aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - dp) != 0) {
+               for (i = 0; i < 8; i++)
+                       bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
+               if ((rc = write_dword (info, dp, bb)) != 0) {
+                       return (rc);
+               }
+               dp += 8;
+               cc -= 8 - l;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cc >= 8) {
+               if ((rc = write_dword (info, dp, src)) != 0) {
+                       return (rc);
+               }
+               dp += 8;
+               src += 8;
+               cc -= 8;
+       }
+
+       if (cc <= 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       for (i = 0; i < 8; i++) {
+               bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
+       }
+       return (write_dword (info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
+{
+       ulong start, cl, ch;
+       int flag, i;
+
+       for (ch = 0, i = 0; i < 4; i++)
+               ch = (ch << 8) + *pdata++;      /* high word    */
+       for (cl = 0, i = 0; i < 4; i++)
+               cl = (cl << 8) + *pdata++;      /* low word */
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *) dest) & ch) != ch
+               || (*((vu_long *) (dest + 4)) & cl) != cl) {
+               return (2);
+       }
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts ();
+
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
+       V_ULONG (dest) = ch;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+       V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+       V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
+       V_ULONG (dest + 4) = cl;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts ();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
+                  ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
+               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
diff --git a/board/w7o/fsboot.c b/board/w7o/fsboot.c
new file mode 100644 (file)
index 0000000..800583d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * (C) Copyright 2001
+ * Wave 7 Optics, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <cmd_elf.h>
+
+/*
+ * FIXME: Add code to test image and it's header.
+ */
+static int
+image_check(ulong addr)
+{
+    return valid_elf_image(addr);
+}
+
+void
+init_fsboot(void)
+{
+    char  *envp;
+    ulong loadaddr;
+    ulong testaddr;
+    ulong alt_loadaddr;
+    char buf[9];
+
+    /*
+     * Get test image address
+     */
+    if ((envp = getenv("testaddr")) != NULL)
+       testaddr = simple_strtoul(envp, NULL, 16);
+    else
+       testaddr = -1;
+
+    /*
+     * Are we going to test boot and image?
+     */
+    if ((testaddr != -1) && image_check(testaddr)) {
+
+       /* Set alt_loadaddr */
+       alt_loadaddr = testaddr;
+       sprintf(buf, "%lX", alt_loadaddr);
+       setenv("alt_loadaddr", buf);
+
+       /* Clear test_addr */
+       setenv("testaddr", NULL);
+
+       /*
+        * Save current environment with alt_loadaddr,
+        * and cleared testaddr.
+        */
+       saveenv();
+
+       /*
+        * Setup temporary loadaddr to alt_loadaddr
+        * XXX - DO NOT SAVE ENVIRONMENT!
+        */
+       loadaddr = alt_loadaddr;
+       sprintf(buf, "%lX", loadaddr);
+       setenv("loadaddr", buf);
+
+    } else { /* Normal boot */
+       setenv("alt_loadaddr", NULL);           /* Clear alt_loadaddr */
+       setenv("testaddr", NULL);               /* Clear testaddr */
+       saveenv();
+    }
+
+    return;
+}
+
diff --git a/board/w7o/watchdog.c b/board/w7o/watchdog.c
new file mode 100644 (file)
index 0000000..3fca5d3
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (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
+ */
+
+/*
+ * W7O board level hardware watchdog.
+ */
+#include <common.h>
+#include <config.h>
+
+#ifdef CONFIG_HW_WATCHDOG
+#include <watchdog.h>
+
+void hw_watchdog_reset(void)
+{
+    volatile ushort *hwd = (ushort *)(CFG_W7O_EBC_PB7CR & 0xfff00000);
+
+    /*
+     * Read the LMG's hwd register and toggle the
+     * watchdog bit to reset it.   On the LMC, just
+     * reading it is enough, but toggling the bit
+     * doen't hurt either.
+     */
+    *hwd = *hwd ^ 0x8000;
+
+} /* hw_watchdog_reset() */
+
+#endif /* CONFIG_HW_WATCHDOG */
+
diff --git a/board/westel/amx860/flash.c b/board/westel/amx860/flash.c
new file mode 100644 (file)
index 0000000..28238c1
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips        */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef  CFG_ENV_ADDR
+#  define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef  CFG_ENV_SIZE
+#  define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef  CFG_ENV_SECT_SIZE
+#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+       volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
+       volatile memctl8xx_t *memctl = &immap->im_memctl;
+       unsigned long size_b0, size_b1;
+       int i;
+
+       /* Init: no FLASHes known */
+       for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+               flash_info[i].flash_id = FLASH_UNKNOWN;
+       }
+
+       /* Static FLASH Bank configuration here - FIXME XXX */
+
+       DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+       size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+       if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+               printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+                       size_b0, size_b0<<20);
+       }
+
+#if defined(FLASH_BASE1_PRELIM) && (FLASH_BASE1_PRELIM != 0)
+       DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM);
+
+       size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+       if (size_b1 > size_b0) {
+               printf ("## ERROR: "
+                       "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+                       size_b1, size_b1<<20,
+                       size_b0, size_b0<<20
+               );
+               flash_info[0].flash_id  = FLASH_UNKNOWN;
+               flash_info[1].flash_id  = FLASH_UNKNOWN;
+               flash_info[0].sector_count      = -1;
+               flash_info[1].sector_count      = -1;
+               flash_info[0].size              = 0;
+               flash_info[1].size              = 0;
+               return (0);
+       }
+#else
+       size_b1 = 0;
+#endif /* FLASH_BASE1_PRELIM */
+
+       DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       DEBUGF ("## Before remap: "
+               "BR0: 0x%08x    OR0: 0x%08x    "
+               "BR1: 0x%08x    OR1: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0,
+               memctl->memc_br1, memctl->memc_or1);
+
+       /* Remap FLASH according to real size */
+       memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+       memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+       DEBUGF("## BR0: 0x%08x    OR0: 0x%08x\n",
+               memctl->memc_br0, memctl->memc_or0);
+
+       /* Re-do sizing to get full correct info */
+       size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+       flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                     &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                     &flash_info[0]);
+#endif
+
+       if (size_b1) {
+               memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & OR_AM_MSK);
+               memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+                                  BR_MS_GPCM | BR_V;
+
+               DEBUGF("## BR1: 0x%08x    OR1: 0x%08x\n",
+                       memctl->memc_br1, memctl->memc_or1);
+
+               /* Re-do sizing to get full correct info */
+               size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+                                         &flash_info[1]);
+
+               flash_info[1].size = size_b1;
+
+               flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+# if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+               /* monitor protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_MONITOR_BASE,
+                             CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+                             &flash_info[1]);
+# endif
+
+# ifdef CFG_ENV_IS_IN_FLASH
+               /* ENV protection ON by default */
+               flash_protect(FLAG_PROTECT_SET,
+                             CFG_ENV_ADDR,
+                             CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+                             &flash_info[1]);
+#endif
+       } else {
+#ifndef CONFIG_AMX_RAM_EXT
+               memctl->memc_br1 = 0;           /* invalidate bank */
+               memctl->memc_or1 = 0;           /* invalidate bank */
+#endif
+
+               DEBUGF("## DISABLE BR1: 0x%08x    OR1: 0x%08x\n",
+                       memctl->memc_br1, memctl->memc_or1);
+
+               flash_info[1].flash_id = FLASH_UNKNOWN;
+               flash_info[1].sector_count = -1;
+               flash_info[1].size = 0;
+       }
+
+       DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+       return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+       int i;
+
+       /* set up sector start address table */
+       if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+               /* set sector offsets for uniform sector type   */
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00040000);
+               }
+       } else if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+       int i;
+
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+       default:                printf ("Unknown Vendor ");     break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+                               break;
+       case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+                               break;
+       case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+                               break;
+       case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+                               break;
+       default:                printf ("Unknown Chip Type\n");
+                               break;
+       }
+
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
+
+       printf ("  Sector Start Addresses:");
+       for (i=0; i<info->sector_count; ++i) {
+               if ((i % 5) == 0)
+                       printf ("\n   ");
+               printf (" %08lX%s",
+                       info->start[i],
+                       info->protect[i] ? " (RO)" : "     "
+               );
+       }
+       printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+       short i;
+       ulong value;
+       ulong base = (ulong)addr;
+
+       /* Write auto select command: read Manufacturer ID */
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00900090;
+
+       value = addr[0];
+
+       DEBUGF("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
+
+       switch (value) {
+       case AMD_MANUFACT:
+               info->flash_id = FLASH_MAN_AMD;
+               break;
+       case FUJ_MANUFACT:
+               info->flash_id = FLASH_MAN_FUJ;
+               break;
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               return (0);                     /* no or unknown flash  */
+       }
+
+       value = addr[1];                        /* device ID            */
+
+       DEBUGF("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
+
+       switch (value) {
+       case AMD_ID_F040B:
+               info->flash_id += FLASH_AM040;
+               info->sector_count = 8;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV400T:
+               info->flash_id += FLASH_AM400T;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV400B:
+               info->flash_id += FLASH_AM400B;
+               info->sector_count = 11;
+               info->size = 0x00100000;
+               break;                          /* => 1 MB              */
+
+       case AMD_ID_LV800T:
+               info->flash_id += FLASH_AM800T;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV800B:
+               info->flash_id += FLASH_AM800B;
+               info->sector_count = 19;
+               info->size = 0x00200000;
+               break;                          /* => 2 MB              */
+
+       case AMD_ID_LV160T:
+               info->flash_id += FLASH_AM160T;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+
+       case AMD_ID_LV160B:
+               info->flash_id += FLASH_AM160B;
+               info->sector_count = 35;
+               info->size = 0x00400000;
+               break;                          /* => 4 MB              */
+#if 0  /* enable when device IDs are available */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 67;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+#endif
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+       }
+
+       /* set up sector start address table */
+       if (info->flash_id & FLASH_BTYPE) {
+               /* set sector offsets for bottom boot block type        */
+               info->start[0] = base + 0x00000000;
+               info->start[1] = base + 0x00008000;
+               info->start[2] = base + 0x0000C000;
+               info->start[3] = base + 0x00010000;
+               for (i = 4; i < info->sector_count; i++) {
+                       info->start[i] = base + (i * 0x00020000) - 0x00060000;
+               }
+       } else {
+               /* set sector offsets for top boot block type           */
+               i = info->sector_count - 1;
+               info->start[i--] = base + info->size - 0x00008000;
+               info->start[i--] = base + info->size - 0x0000C000;
+               info->start[i--] = base + info->size - 0x00010000;
+               for (; i >= 0; i--) {
+                       info->start[i] = base + i * 0x00020000;
+               }
+       }
+
+       /* check for protected sectors */
+       for (i = 0; i < info->sector_count; i++) {
+               /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+               /* D0 = 1 if protected */
+               addr = (volatile unsigned long *)(info->start[i]);
+               info->protect[i] = addr[2] & 1;
+       }
+
+       /*
+        * Prevent writes to uninitialized FLASH.
+        */
+       if (info->flash_id != FLASH_UNKNOWN) {
+               addr = (volatile unsigned long *)info->start[0];
+
+               *addr = 0x00F000F0;     /* reset bank */
+       }
+
+       return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       int flag, prot, sect, l_sect;
+       ulong start, now, last;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
+
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
+
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
+
+       l_sect = -1;
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00800080;
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect<=s_last; sect++) {
+               if (info->protect[sect] == 0) { /* not protected */
+                       addr = (vu_long*)(info->start[sect]);
+                       addr[0] = 0x00300030;
+                       l_sect = sect;
+               }
+       }
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* wait at least 80us - let's wait 1 ms */
+       udelay (1000);
+
+       /*
+        * We wait for the last triggered sector
+        */
+       if (l_sect < 0)
+               goto DONE;
+
+       start = get_timer (0);
+       last  = start;
+       addr = (vu_long*)(info->start[l_sect]);
+       while ((addr[0] & 0x00800080) != 0x00800080) {
+               if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+                       printf ("Timeout\n");
+                       return 1;
+               }
+               /* show that we're waiting */
+               if ((now - last) > 1000) {      /* every second */
+                       putc ('.');
+                       last = now;
+               }
+       }
+
+DONE:
+       /* reset to read mode */
+       addr = (volatile unsigned long *)info->start[0];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       printf (" done\n");
+       return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+       ulong cp, wp, data;
+       int i, l, rc;
+
+       wp = (addr & ~3);       /* get lower word aligned address */
+
+       /*
+        * handle unaligned start bytes
+        */
+       if ((l = addr - wp) != 0) {
+               data = 0;
+               for (i=0, cp=wp; i<l; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+               for (; i<4 && cnt>0; ++i) {
+                       data = (data << 8) | *src++;
+                       --cnt;
+                       ++cp;
+               }
+               for (; cnt==0 && i<4; ++i, ++cp) {
+                       data = (data << 8) | (*(uchar *)cp);
+               }
+
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp += 4;
+       }
+
+       /*
+        * handle word aligned part
+        */
+       while (cnt >= 4) {
+               data = 0;
+               for (i=0; i<4; ++i) {
+                       data = (data << 8) | *src++;
+               }
+               if ((rc = write_word(info, wp, data)) != 0) {
+                       return (rc);
+               }
+               wp  += 4;
+               cnt -= 4;
+       }
+
+       if (cnt == 0) {
+               return (0);
+       }
+
+       /*
+        * handle unaligned tail bytes
+        */
+       data = 0;
+       for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+               data = (data << 8) | *src++;
+               --cnt;
+       }
+       for (; i<4; ++i, ++cp) {
+               data = (data << 8) | (*(uchar *)cp);
+       }
+
+       return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+       vu_long *addr = (vu_long*)(info->start[0]);
+       ulong start;
+       int flag;
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*((vu_long *)dest) & data) != data) {
+               return (2);
+       }
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       addr[0x0555] = 0x00AA00AA;
+       addr[0x02AA] = 0x00550055;
+       addr[0x0555] = 0x00A000A0;
+
+       *((vu_long *)dest) = data;
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       /* data polling for D7 */
+       start = get_timer (0);
+       while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+               if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/common/docecc.c b/common/docecc.c
new file mode 100644 (file)
index 0000000..09e8233
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * ECC algorithm for M-systems disk on chip. We use the excellent Reed
+ * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
+ * GNU GPL License. The rest is simply to convert the disk on chip
+ * syndrom into a standard syndom.
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
+ *
+ * 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 <common.h>
+#include <malloc.h>
+
+#include <linux/mtd/doc2000.h>
+
+#undef ECC_DEBUG
+#undef PSYCHO_DEBUG
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* need to undef it (from asm/termbits.h) */
+#undef B0
+
+#define MM 10 /* Symbol size in bits */
+#define KK (1023-4) /* Number of data symbols per block */
+#define B0 510 /* First root of generator polynomial, alpha form */
+#define PRIM 1 /* power of alpha used to generate roots of generator poly */
+#define        NN ((1 << MM) - 1)
+
+typedef unsigned short dtype;
+
+/* 1+x^3+x^10 */
+static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+
+/* This defines the type used to store an element of the Galois Field
+ * used by the code. Make sure this is something larger than a char if
+ * if anything larger than GF(256) is used.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium.
+ */
+typedef int gf;
+
+/* No legal value in index form represents zero, so
+ * we need a special value for this purpose
+ */
+#define A0     (NN)
+
+/* Compute x % NN, where NN is 2**MM - 1,
+ * without a slow divide
+ */
+static inline gf
+modnn(int x)
+{
+  while (x >= NN) {
+    x -= NN;
+    x = (x >> MM) + (x & NN);
+  }
+  return x;
+}
+
+#define        CLEAR(a,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = 0;\
+}
+
+#define        COPY(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define        COPYDOWN(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define Ldec 1
+
+/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
+   lookup tables:  index->polynomial form   alpha_to[] contains j=alpha**i;
+                   polynomial form -> index form  index_of[j=alpha**i] = i
+   alpha=2 is the primitive element of GF(2**m)
+   HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
+        Let @ represent the primitive element commonly called "alpha" that
+   is the root of the primitive polynomial p(x). Then in GF(2^m), for any
+   0 <= i <= 2^m-2,
+        @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
+   of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
+   example the polynomial representation of @^5 would be given by the binary
+   representation of the integer "alpha_to[5]".
+                   Similarily, index_of[] can be used as follows:
+        As above, let @ represent the primitive element of GF(2^m) that is
+   the root of the primitive polynomial p(x). In order to find the power
+   of @ (alpha) that has the polynomial representation
+        a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+   we consider the integer "i" whose binary representation with a(0) being LSB
+   and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
+   "index_of[i]". Now, @^index_of[i] is that element whose polynomial
+    representation is (a(0),a(1),a(2),...,a(m-1)).
+   NOTE:
+        The element alpha_to[2^m-1] = 0 always signifying that the
+   representation of "@^infinity" = 0 is (0,0,0,...,0).
+        Similarily, the element index_of[0] = A0 always signifying
+   that the power of alpha which has the polynomial representation
+   (0,0,...,0) is "infinity".
+
+*/
+
+static void
+generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
+{
+  register int i, mask;
+
+  mask = 1;
+  Alpha_to[MM] = 0;
+  for (i = 0; i < MM; i++) {
+    Alpha_to[i] = mask;
+    Index_of[Alpha_to[i]] = i;
+    /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
+    if (Pp[i] != 0)
+      Alpha_to[MM] ^= mask;    /* Bit-wise EXOR operation */
+    mask <<= 1;        /* single left-shift */
+  }
+  Index_of[Alpha_to[MM]] = MM;
+  /*
+   * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
+   * poly-repr of @^i shifted left one-bit and accounting for any @^MM
+   * term that may occur when poly-repr of @^i is shifted.
+   */
+  mask >>= 1;
+  for (i = MM + 1; i < NN; i++) {
+    if (Alpha_to[i - 1] >= mask)
+      Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
+    else
+      Alpha_to[i] = Alpha_to[i - 1] << 1;
+    Index_of[Alpha_to[i]] = i;
+  }
+  Index_of[0] = A0;
+  Alpha_to[NN] = 0;
+}
+
+/*
+ * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
+ * of the feedback shift register after having processed the data and
+ * the ECC.
+ *
+ * Return number of symbols corrected, or -1 if codeword is illegal
+ * or uncorrectable. If eras_pos is non-null, the detected error locations
+ * are written back. NOTE! This array must be at least NN-KK elements long.
+ * The corrected data are written in eras_val[]. They must be xor with the data
+ * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
+ *
+ * First "no_eras" erasures are declared by the calling program. Then, the
+ * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
+ * If the number of channel errors is not greater than "t_after_eras" the
+ * transmitted codeword will be recovered. Details of algorithm can be found
+ * in R. Blahut's "Theory ... of Error-Correcting Codes".
+
+ * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
+ * will result. The decoder *could* check for this condition, but it would involve
+ * extra time on every decoding operation.
+ * */
+static int
+eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
+            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
+            int no_eras)
+{
+  int deg_lambda, el, deg_omega;
+  int i, j, r,k;
+  gf u,q,tmp,num1,num2,den,discr_r;
+  gf lambda[NN-KK + 1], s[NN-KK + 1];  /* Err+Eras Locator poly
+                                        * and syndrome poly */
+  gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
+  gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
+  int syn_error, count;
+
+  syn_error = 0;
+  for(i=0;i<NN-KK;i++)
+      syn_error |= bb[i];
+
+  if (!syn_error) {
+    /* if remainder is zero, data[] is a codeword and there are no
+     * errors to correct. So return data[] unmodified
+     */
+    count = 0;
+    goto finish;
+  }
+
+  for(i=1;i<=NN-KK;i++){
+    s[i] = bb[0];
+  }
+  for(j=1;j<NN-KK;j++){
+    if(bb[j] == 0)
+      continue;
+    tmp = Index_of[bb[j]];
+
+    for(i=1;i<=NN-KK;i++)
+      s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
+  }
+
+  /* undo the feedback register implicit multiplication and convert
+     syndromes to index form */
+
+  for(i=1;i<=NN-KK;i++) {
+      tmp = Index_of[s[i]];
+      if (tmp != A0)
+          tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
+      s[i] = tmp;
+  }
+
+  CLEAR(&lambda[1],NN-KK);
+  lambda[0] = 1;
+
+  if (no_eras > 0) {
+    /* Init lambda to be the erasure locator polynomial */
+    lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
+    for (i = 1; i < no_eras; i++) {
+      u = modnn(PRIM*eras_pos[i]);
+      for (j = i+1; j > 0; j--) {
+       tmp = Index_of[lambda[j - 1]];
+       if(tmp != A0)
+         lambda[j] ^= Alpha_to[modnn(u + tmp)];
+      }
+    }
+#ifdef ECC_DEBUG
+    /* Test code that verifies the erasure locator polynomial just constructed
+       Needed only for decoder debugging. */
+
+    /* find roots of the erasure location polynomial */
+    for(i=1;i<=no_eras;i++)
+      reg[i] = Index_of[lambda[i]];
+    count = 0;
+    for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+      q = 1;
+      for (j = 1; j <= no_eras; j++)
+       if (reg[j] != A0) {
+         reg[j] = modnn(reg[j] + j);
+         q ^= Alpha_to[reg[j]];
+       }
+      if (q != 0)
+       continue;
+      /* store root and error location number indices */
+      root[count] = i;
+      loc[count] = k;
+      count++;
+    }
+    if (count != no_eras) {
+      printf("\n lambda(x) is WRONG\n");
+      count = -1;
+      goto finish;
+    }
+#ifdef PSYCHO_DEBUG
+    printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+    for (i = 0; i < count; i++)
+      printf("%d ", loc[i]);
+    printf("\n");
+#endif
+#endif
+  }
+  for(i=0;i<NN-KK+1;i++)
+    b[i] = Index_of[lambda[i]];
+
+  /*
+   * Begin Berlekamp-Massey algorithm to determine error+erasure
+   * locator polynomial
+   */
+  r = no_eras;
+  el = no_eras;
+  while (++r <= NN-KK) {       /* r is the step number */
+    /* Compute discrepancy at the r-th step in poly-form */
+    discr_r = 0;
+    for (i = 0; i < r; i++){
+      if ((lambda[i] != 0) && (s[r - i] != A0)) {
+       discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
+      }
+    }
+    discr_r = Index_of[discr_r];       /* Index form */
+    if (discr_r == A0) {
+      /* 2 lines below: B(x) <-- x*B(x) */
+      COPYDOWN(&b[1],b,NN-KK);
+      b[0] = A0;
+    } else {
+      /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
+      t[0] = lambda[0];
+      for (i = 0 ; i < NN-KK; i++) {
+       if(b[i] != A0)
+         t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
+       else
+         t[i+1] = lambda[i+1];
+      }
+      if (2 * el <= r + no_eras - 1) {
+       el = r + no_eras - el;
+       /*
+        * 2 lines below: B(x) <-- inv(discr_r) *
+        * lambda(x)
+        */
+       for (i = 0; i <= NN-KK; i++)
+         b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
+      } else {
+       /* 2 lines below: B(x) <-- x*B(x) */
+       COPYDOWN(&b[1],b,NN-KK);
+       b[0] = A0;
+      }
+      COPY(lambda,t,NN-KK+1);
+    }
+  }
+
+  /* Convert lambda to index form and compute deg(lambda(x)) */
+  deg_lambda = 0;
+  for(i=0;i<NN-KK+1;i++){
+    lambda[i] = Index_of[lambda[i]];
+    if(lambda[i] != A0)
+      deg_lambda = i;
+  }
+  /*
+   * Find roots of the error+erasure locator polynomial by Chien
+   * Search
+   */
+  COPY(&reg[1],&lambda[1],NN-KK);
+  count = 0;           /* Number of roots of lambda(x) */
+  for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+    q = 1;
+    for (j = deg_lambda; j > 0; j--){
+      if (reg[j] != A0) {
+       reg[j] = modnn(reg[j] + j);
+       q ^= Alpha_to[reg[j]];
+      }
+    }
+    if (q != 0)
+      continue;
+    /* store root (index-form) and error location number */
+    root[count] = i;
+    loc[count] = k;
+    /* If we've already found max possible roots,
+     * abort the search to save time
+     */
+    if(++count == deg_lambda)
+      break;
+  }
+  if (deg_lambda != count) {
+    /*
+     * deg(lambda) unequal to number of roots => uncorrectable
+     * error detected
+     */
+    count = -1;
+    goto finish;
+  }
+  /*
+   * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+   * x**(NN-KK)). in index form. Also find deg(omega).
+   */
+  deg_omega = 0;
+  for (i = 0; i < NN-KK;i++){
+    tmp = 0;
+    j = (deg_lambda < i) ? deg_lambda : i;
+    for(;j >= 0; j--){
+      if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
+       tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
+    }
+    if(tmp != 0)
+      deg_omega = i;
+    omega[i] = Index_of[tmp];
+  }
+  omega[NN-KK] = A0;
+
+  /*
+   * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+   * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
+   */
+  for (j = count-1; j >=0; j--) {
+    num1 = 0;
+    for (i = deg_omega; i >= 0; i--) {
+      if (omega[i] != A0)
+       num1  ^= Alpha_to[modnn(omega[i] + i * root[j])];
+    }
+    num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
+    den = 0;
+
+    /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+    for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
+      if(lambda[i+1] != A0)
+       den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
+    }
+    if (den == 0) {
+#ifdef ECC_DEBUG
+      printf("\n ERROR: denominator = 0\n");
+#endif
+      /* Convert to dual- basis */
+      count = -1;
+      goto finish;
+    }
+    /* Apply error to data */
+    if (num1 != 0) {
+        eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
+    } else {
+        eras_val[j] = 0;
+    }
+  }
+ finish:
+  for(i=0;i<count;i++)
+      eras_pos[i] = loc[i];
+  return count;
+}
+
+/***************************************************************************/
+/* The DOC specific code begins here */
+
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA MM bits words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
+
+/*
+ * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
+ * content of the feedback shift register applyied to the sector and
+ * the ECC. Return the number of errors corrected (and correct them in
+ * sector), or -1 if error
+ */
+int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
+{
+    int parity, i, nb_errors;
+    gf bb[NN - KK + 1];
+    gf error_val[NN-KK];
+    int error_pos[NN-KK], pos, bitpos, index, val;
+    dtype *Alpha_to, *Index_of;
+
+    /* init log and exp tables here to save memory. However, it is slower */
+    Alpha_to = malloc((NN + 1) * sizeof(dtype));
+    if (!Alpha_to)
+        return -1;
+
+    Index_of = malloc((NN + 1) * sizeof(dtype));
+    if (!Index_of) {
+        free(Alpha_to);
+        return -1;
+    }
+
+    generate_gf(Alpha_to, Index_of);
+
+    parity = ecc1[1];
+
+    bb[0] =  (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
+    bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
+    bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
+    bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
+
+    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
+                            error_val, error_pos, 0);
+    if (nb_errors <= 0)
+        goto the_end;
+
+    /* correct the errors */
+    for(i=0;i<nb_errors;i++) {
+        pos = error_pos[i];
+        if (pos >= NB_DATA && pos < KK) {
+            nb_errors = -1;
+            goto the_end;
+        }
+        if (pos < NB_DATA) {
+            /* extract bit position (MSB first) */
+            pos = 10 * (NB_DATA - 1 - pos) - 6;
+            /* now correct the following 10 bits. At most two bytes
+               can be modified since pos is even */
+            index = (pos >> 3) ^ 1;
+            bitpos = pos & 7;
+            if ((index >= 0 && index < SECTOR_SIZE) ||
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] >> (2 + bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+            index = ((pos >> 3) + 1) ^ 1;
+            bitpos = (bitpos + 10) & 7;
+            if (bitpos == 0)
+                bitpos = 8;
+            if ((index >= 0 && index < SECTOR_SIZE) ||
+                index == (SECTOR_SIZE + 1)) {
+                val = error_val[i] << (8 - bitpos);
+                parity ^= val;
+                if (index < SECTOR_SIZE)
+                    sector[index] ^= val;
+            }
+        }
+    }
+
+    /* use parity to test extra errors */
+    if ((parity & 0xff) != 0)
+        nb_errors = -1;
+
+ the_end:
+    free(Alpha_to);
+    free(Index_of);
+    return nb_errors;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
diff --git a/common/flash.c b/common/flash.c
new file mode 100644 (file)
index 0000000..fa8942b
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * (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 <flash.h>
+
+#if !defined(CFG_NO_FLASH)
+
+extern flash_info_t  flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+       ulong b_end = info->start[0] + info->size - 1;  /* bank end address */
+       short s_end = info->sector_count - 1;   /* index of last sector */
+       int i;
+
+       /* Do nothing if input data is bad. */
+       if (info->sector_count == 0 || info->size == 0 || to < from) {
+               return;
+       }
+
+       /* There is nothing to do if we have no data about the flash
+        * or the protect range and flash range don't overlap.
+        */
+       if (info->flash_id == FLASH_UNKNOWN ||
+           to < info->start[0] || from > b_end) {
+               return;
+       }
+
+       for (i=0; i<info->sector_count; ++i) {
+               ulong end;              /* last address in current sect */
+
+               end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+               /* Update protection if any part of the sector
+                * is in the specified range.
+                */
+               if (from <= end && to >= info->start[i]) {
+                       if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CFG_FLASH_PROTECTION)
+                               flash_real_protect(info, i, 0);
+#else
+                               info->protect[i] = 0;
+#endif /* CFG_FLASH_PROTECTION */
+                       }
+                       else if (flag & FLAG_PROTECT_SET) {
+#if defined(CFG_FLASH_PROTECTION)
+                               flash_real_protect(info, i, 1);
+#else
+                               info->protect[i] = 1;
+#endif /* CFG_FLASH_PROTECTION */
+                       }
+               }
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+       flash_info_t *info;
+       int i;
+
+       for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
+               if (info->flash_id != FLASH_UNKNOWN &&
+                   addr >= info->start[0] &&
+                   /* WARNING - The '- 1' is needed if the flash
+                    * is at the end of the address space, since
+                    * info->start[0] + info->size wraps back to 0.
+                    * Please don't change this unless you understand this.
+                    */
+                   addr <= info->start[0] + info->size - 1) {
+                       return (info);
+               }
+       }
+#endif /* CONFIG_SPD823TS */
+
+       return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK          0 - OK
+ * ERR_TIMOUT      1 - write timeout
+ * ERR_NOT_ERASED  2 - Flash not erased
+ * ERR_PROTECTED   4 - target range includes protected sectors
+ * ERR_INVAL       8 - target address not in Flash memory
+ * ERR_ALIGN       16 - target address not aligned on boundary
+ *                     (only some targets require alignment)
+ */
+int
+flash_write (uchar *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+       return (ERR_TIMOUT);    /* any other error codes are possible as well */
+#else
+       int i;
+       ulong         end        = addr + cnt - 1;
+       flash_info_t *info_first = addr2info (addr);
+       flash_info_t *info_last  = addr2info (end );
+       flash_info_t *info;
+
+       if (cnt == 0) {
+               return (ERR_OK);
+       }
+
+       if (!info_first || !info_last) {
+               return (ERR_INVAL);
+       }
+
+       for (info = info_first; info <= info_last; ++info) {
+               ulong b_end = info->start[0] + info->size;      /* bank end addr */
+               short s_end = info->sector_count - 1;
+               for (i=0; i<info->sector_count; ++i) {
+                       ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+                       if ((end >= info->start[i]) && (addr < e_addr) &&
+                           (info->protect[i] != 0) ) {
+                               return (ERR_PROTECTED);
+                       }
+               }
+       }
+
+       /* finally write data to flash */
+       for (info = info_first; info <= info_last && cnt>0; ++info) {
+               ulong len;
+
+               len = info->start[0] + info->size - addr;
+               if (len > cnt)
+                       len = cnt;
+               if ((i = write_buff(info, src, addr, len)) != 0) {
+                       return (i);
+               }
+               cnt  -= len;
+               addr += len;
+               src  += len;
+       }
+       return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_perror (int err)
+{
+       switch (err) {
+       case ERR_OK:
+               break;
+       case ERR_TIMOUT:
+               puts ("Timeout writing to Flash\n");
+               break;
+       case ERR_NOT_ERASED:
+               puts ("Flash not Erased\n");
+               break;
+       case ERR_PROTECTED:
+               puts ("Can't write to protected Flash sectors\n");
+               break;
+       case ERR_INVAL:
+               puts ("Outside available Flash\n");
+               break;
+       case ERR_ALIGN:
+               puts ("Start and/or end address not on sector boundary\n");
+               break;
+       case ERR_UNKNOWN_FLASH_VENDOR:
+               puts ("Unknown Vendor of Flash\n");
+               break;
+       case ERR_UNKNOWN_FLASH_TYPE:
+               puts ("Unknown Type of Flash\n");
+               break;
+       case ERR_PROG_ERROR:
+               puts ("General Flash Programming Error\n");
+               break;
+       default:
+               printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
+               break;
+       }
+}
+
+/*-----------------------------------------------------------------------
+ */
+#endif /* !CFG_NO_FLASH */
diff --git a/common/lists.c b/common/lists.c
new file mode 100644 (file)
index 0000000..3f117b5
--- /dev/null
@@ -0,0 +1,734 @@
+#include <common.h>
+#include <malloc.h>
+#include <lists.h>
+
+#define MAX(a,b)       (((a)>(b)) ? (a) : (b))
+#define MIN(a,b)       (((a)<(b)) ? (a) : (b))
+#define CAT4CHARS(a,b,c,d)     ((a<<24) | (b<<16) | (c<<8) | d)
+
+/* increase list size by 10% every time it is full */
+#define kDefaultAllocationPercentIncrease      10
+
+/* always increase list size by 4 items when it is full */
+#define kDefaultAllocationminNumItemsIncrease  4
+
+/*
+ * how many items to expand the list by when it becomes full
+ * = current listSize (in items) + (hiword percent of list size) + loword
+ */
+#define NUMITEMSPERALLOC(list) MAX(((*list)->listSize * \
+                                   ((*list)->percentIncrease + 100)) / 100, \
+                                   (*list)->minNumItemsIncrease )
+
+#define ITEMPTR(list,item)     &(((char *)&(*list)->itemList)[(*(list))->itemSize * (item)])
+
+#define LIST_SIGNATURE         CAT4CHARS('L', 'I', 'S', 'T');
+
+#define calloc(size,num)       malloc(size*num)
+
+/********************************************************************/
+
+Handle NewHandle (unsigned int numBytes)
+{
+       void *memPtr;
+       HandleRecord *hanPtr;
+
+       memPtr = calloc (numBytes, 1);
+       hanPtr = (HandleRecord *) calloc (sizeof (HandleRecord), 1);
+       if (hanPtr && (memPtr || numBytes == 0)) {
+               hanPtr->ptr = memPtr;
+               hanPtr->size = numBytes;
+               return (Handle) hanPtr;
+       } else {
+               free (memPtr);
+               free (hanPtr);
+               return NULL;
+       }
+}
+/********************************************************************/
+
+void DisposeHandle (Handle handle)
+{
+       if (handle) {
+               free (*handle);
+               free ((void *) handle);
+       }
+}
+/********************************************************************/
+
+unsigned int GetHandleSize (Handle handle)
+{
+       return ((HandleRecord *) handle)->size;
+}
+/********************************************************************/
+
+int SetHandleSize (Handle handle, unsigned int newSize)
+{
+       HandleRecord *hanRecPtr = (HandleRecord *) handle;
+       void *newPtr, *oldPtr;
+       unsigned int oldSize;
+
+
+       oldPtr = hanRecPtr->ptr;
+       oldSize = hanRecPtr->size;
+
+       if (oldSize == newSize)
+               return 1;
+
+       if (oldPtr == NULL) {
+               newPtr = malloc (newSize);
+       } else {
+               newPtr = realloc (oldPtr, newSize);
+       }
+       if (newPtr || (newSize == 0)) {
+               hanRecPtr->ptr = newPtr;
+               hanRecPtr->size = newSize;
+               if (newSize > oldSize)
+                       memset ((char *) newPtr + oldSize, 0, newSize - oldSize);
+               return 1;
+       } else
+               return 0;
+}
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/*  Used to compare list elements by their raw data contents */
+static int ListMemBlockCmp (void *a, void *b, int size)
+{
+       return memcmp (a, b, size);
+}
+
+/***************************************************************************/
+
+/*
+ * Binary search numElements of size elementSize in array for a match
+ * to the. item. Return the index of the element that matches
+ * (0 - numElements - 1). If no match is found return the -i-1 where
+ * i is the index (0 - numElements) where the item should be placed.
+ * (*theCmp)(a,b) should return <0 if a<b, 0 if a==b, >0 if a>b.
+ *
+ * This function is like the C-Library function bsearch() except that
+ * this function returns the index where the item should be placed if
+ * it is not found.
+ */
+int BinSearch ( void *array, int numElements, int elementSize,
+               void *itemPtr, CompareFunction compareFunction)
+{
+       int low, high, mid, cmp;
+       void *arrayItemPtr;
+
+       for (low = 0, high = numElements - 1, mid = 0, cmp = -1; low <= high;) {
+               mid = (low + high) >> 1;
+
+               arrayItemPtr = (void *) (((char *) array) + (mid * elementSize));
+               cmp = compareFunction
+                       ? compareFunction (itemPtr, arrayItemPtr)
+                       : ListMemBlockCmp (itemPtr, arrayItemPtr, elementSize);
+               if (cmp == 0) {
+                       return mid;
+               } else if (cmp < 0) {
+                       high = mid - 1;
+               } else {
+                       low = mid + 1;
+               }
+       }
+       if (cmp > 0)
+               mid++;
+
+       return -mid - 1;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************************************************************/
+
+/*
+ * If numNewItems == 0 then expand the list by the number of items
+ * indicated by its allocation policy.
+ * If numNewItems > 0 then expand the list by exactly the number of
+ * items indicated.
+ * If numNewItems < 0 then expand the list by the absolute value of
+ * numNewItems plus the number of items indicated by its allocation
+ * policy.
+ * Returns 1 for success, 0 if out of memory
+*/
+static int ExpandListSpace (list_t list, int numNewItems)
+{
+       if (numNewItems == 0) {
+               numNewItems = NUMITEMSPERALLOC (list);
+       } else if (numNewItems < 0) {
+               numNewItems = (-numNewItems) + NUMITEMSPERALLOC (list);
+       }
+
+       if (SetHandleSize ((Handle) list,
+                          sizeof (ListStruct) +
+                          ((*list)->listSize +
+                          numNewItems) * (*list)->itemSize)) {
+               (*list)->listSize += numNewItems;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/*
+ * This function reallocate the list, minus any currently unused
+ * portion of its allotted memory.
+ */
+void ListCompact (list_t list)
+{
+
+       if (!SetHandleSize ((Handle) list,
+                           sizeof (ListStruct) +
+                           (*list)->numItems * (*list)->itemSize)) {
+               return;
+       }
+
+       (*list)->listSize = (*list)->numItems;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+list_t ListCreate (int elementSize)
+{
+       list_t list;
+
+       list = (list_t) (NewHandle (sizeof (ListStruct)));  /* create empty list */
+       if (list) {
+               (*list)->signature = LIST_SIGNATURE;
+               (*list)->numItems = 0;
+               (*list)->listSize = 0;
+               (*list)->itemSize = elementSize;
+               (*list)->percentIncrease = kDefaultAllocationPercentIncrease;
+               (*list)->minNumItemsIncrease =
+                               kDefaultAllocationminNumItemsIncrease;
+       }
+
+       return list;
+}
+
+/*******************************/
+
+void ListSetAllocationPolicy (list_t list, int minItemsPerAlloc,
+                             int percentIncreasePerAlloc)
+{
+       (*list)->percentIncrease = percentIncreasePerAlloc;
+       (*list)->minNumItemsIncrease = minItemsPerAlloc;
+}
+
+/*******************************/
+
+void ListDispose (list_t list)
+{
+       DisposeHandle ((Handle) list);
+}
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+void ListDisposePtrList (list_t list)
+{
+       int index;
+       int numItems;
+
+       if (list) {
+               numItems = ListNumItems (list);
+
+               for (index = 1; index <= numItems; index++)
+                       free (*(void **) ListGetPtrToItem (list, index));
+
+               ListDispose (list);
+       }
+}
+
+/*******************************/
+
+/*
+ * keeps memory, resets the number of items to 0
+ */
+void ListClear (list_t list)
+{
+       if (!list)
+               return;
+       (*list)->numItems = 0;
+}
+
+/*******************************/
+
+/*
+ * copy is only as large as necessary
+ */
+list_t ListCopy (list_t originalList)
+{
+       list_t tempList = NULL;
+       int numItems;
+
+       if (!originalList)
+               return NULL;
+
+       tempList = ListCreate ((*originalList)->itemSize);
+       if (tempList) {
+               numItems = ListNumItems (originalList);
+
+               if (!SetHandleSize ((Handle) tempList,
+                                   sizeof (ListStruct) +
+                                   numItems * (*tempList)->itemSize)) {
+                       ListDispose (tempList);
+                       return NULL;
+               }
+
+               (*tempList)->numItems = (*originalList)->numItems;
+               (*tempList)->listSize = (*originalList)->numItems;
+               (*tempList)->itemSize = (*originalList)->itemSize;
+               (*tempList)->percentIncrease = (*originalList)->percentIncrease;
+               (*tempList)->minNumItemsIncrease =
+                               (*originalList)->minNumItemsIncrease;
+
+               memcpy (ITEMPTR (tempList, 0), ITEMPTR (originalList, 0),
+                               numItems * (*tempList)->itemSize);
+       }
+
+       return tempList;
+}
+
+/********************************/
+
+/*
+ * list1 = list1 + list2
+ */
+int ListAppend (list_t list1, list_t list2)
+{
+       int numItemsL1, numItemsL2;
+
+       if (!list2)
+               return 1;
+
+       if (!list1)
+               return 0;
+       if ((*list1)->itemSize != (*list2)->itemSize)
+               return 0;
+
+       numItemsL1 = ListNumItems (list1);
+       numItemsL2 = ListNumItems (list2);
+
+       if (numItemsL2 == 0)
+               return 1;
+
+       if (!SetHandleSize ((Handle) list1,
+                           sizeof (ListStruct) + (numItemsL1 + numItemsL2) *
+                                       (*list1)->itemSize)) {
+               return 0;
+       }
+
+       (*list1)->numItems = numItemsL1 + numItemsL2;
+       (*list1)->listSize = numItemsL1 + numItemsL2;
+
+       memmove (ITEMPTR (list1, numItemsL1),
+                ITEMPTR (list2, 0),
+                numItemsL2 * (*list2)->itemSize);
+
+       return 1;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+/*
+ * returns 1 if the item is inserted, returns 0 if out of memory or
+ * bad arguments were passed.
+ */
+int ListInsertItem (list_t list, void *ptrToItem, int itemPosition)
+{
+       return ListInsertItems (list, ptrToItem, itemPosition, 1);
+}
+
+/*******************************/
+
+int ListInsertItems (list_t list, void *ptrToItems, int firstItemPosition,
+                    int numItemsToInsert)
+{
+       int numItems = (*list)->numItems;
+
+       if (firstItemPosition == numItems + 1)
+               firstItemPosition = LIST_END;
+       else if (firstItemPosition > numItems)
+               return 0;
+
+       if ((*list)->numItems >= (*list)->listSize) {
+               if (!ExpandListSpace (list, -numItemsToInsert))
+                       return 0;
+       }
+
+       if (firstItemPosition == LIST_START) {
+               if (numItems == 0) {
+                       /* special case for empty list */
+                       firstItemPosition = LIST_END;
+               } else {
+                       firstItemPosition = 1;
+               }
+       }
+
+       if (firstItemPosition == LIST_END) {    /* add at the end of the list */
+               if (ptrToItems)
+                       memcpy (ITEMPTR (list, numItems), ptrToItems,
+                                       (*list)->itemSize * numItemsToInsert);
+               else
+                       memset (ITEMPTR (list, numItems), 0,
+                                       (*list)->itemSize * numItemsToInsert);
+
+               (*list)->numItems += numItemsToInsert;
+       } else {                                        /* move part of list up to make room for new item */
+               memmove (ITEMPTR (list, firstItemPosition - 1 + numItemsToInsert),
+                        ITEMPTR (list, firstItemPosition - 1),
+                        (numItems + 1 - firstItemPosition) * (*list)->itemSize);
+
+               if (ptrToItems)
+                       memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
+                                        (*list)->itemSize * numItemsToInsert);
+               else
+                       memset (ITEMPTR (list, firstItemPosition - 1), 0,
+                                       (*list)->itemSize * numItemsToInsert);
+
+               (*list)->numItems += numItemsToInsert;
+       }
+
+       return 1;
+}
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/*******************************/
+
+int ListEqual (list_t list1, list_t list2)
+{
+       if (list1 == list2)
+               return 1;
+
+       if (list1 == NULL || list2 == NULL)
+               return 0;
+
+       if ((*list1)->itemSize == (*list1)->itemSize) {
+           if ((*list1)->numItems == (*list2)->numItems) {
+               return (memcmp (ITEMPTR (list1, 0), ITEMPTR (list2, 0),
+                               (*list1)->itemSize * (*list1)->numItems) == 0);
+           }
+       }
+
+       return 0;
+}
+
+/*******************************/
+
+/*
+ * The item pointed to by ptrToItem is copied over the current item
+ * at itemPosition
+ */
+void ListReplaceItem (list_t list, void *ptrToItem, int itemPosition)
+{
+       ListReplaceItems (list, ptrToItem, itemPosition, 1);
+}
+
+/*******************************/
+
+/*
+ * The item pointed to by ptrToItems is copied over the current item
+ * at itemPosition
+ */
+void ListReplaceItems ( list_t list, void *ptrToItems,
+                       int firstItemPosition, int numItemsToReplace)
+{
+
+       if (firstItemPosition == LIST_END)
+               firstItemPosition = (*list)->numItems;
+       else if (firstItemPosition == LIST_START)
+               firstItemPosition = 1;
+
+       memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
+                        (*list)->itemSize * numItemsToReplace);
+}
+
+/*******************************/
+
+void ListGetItem (list_t list, void *itemDestination, int itemPosition)
+{
+       ListGetItems (list, itemDestination, itemPosition, 1);
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+#if defined(CFG_ALL_LIST_FUNCTIONS) || defined(CFG_DEVICE_DEREGISTER)
+
+void ListRemoveItem (list_t list, void *itemDestination, int itemPosition)
+{
+       ListRemoveItems (list, itemDestination, itemPosition, 1);
+}
+
+/*******************************/
+
+void ListRemoveItems (list_t list, void *itemsDestination,
+                     int firstItemPosition, int numItemsToRemove)
+{
+       int firstItemAfterChunk, numToMove;
+
+       if (firstItemPosition == LIST_START)
+               firstItemPosition = 1;
+       else if (firstItemPosition == LIST_END)
+               firstItemPosition = (*list)->numItems;
+
+       if (itemsDestination != NULL)
+               memcpy (itemsDestination, ITEMPTR (list, firstItemPosition - 1),
+                               (*list)->itemSize * numItemsToRemove);
+
+       firstItemAfterChunk = firstItemPosition + numItemsToRemove;
+       numToMove = (*list)->numItems - (firstItemAfterChunk - 1);
+
+       if (numToMove > 0) {
+               /*
+                * move part of list down to cover hole left by removed item
+                */
+               memmove (ITEMPTR (list, firstItemPosition - 1),
+                                ITEMPTR (list, firstItemAfterChunk - 1),
+                                (*list)->itemSize * numToMove);
+       }
+
+       (*list)->numItems -= numItemsToRemove;
+}
+#endif /* CFG_ALL_LIST_FUNCTIONS || CFG_DEVICE_DEREGISTER */
+
+/*******************************/
+
+void ListGetItems (list_t list, void *itemsDestination,
+                  int firstItemPosition, int numItemsToGet)
+{
+
+       if (firstItemPosition == LIST_START)
+               firstItemPosition = 1;
+       else if (firstItemPosition == LIST_END)
+               firstItemPosition = (*list)->numItems;
+
+       memcpy (itemsDestination,
+               ITEMPTR (list, firstItemPosition - 1),
+               (*list)->itemSize * numItemsToGet);
+}
+
+/*******************************/
+
+/*
+ * Returns a pointer to the item at itemPosition. returns null if an
+ * errors occurred.
+ */
+void *ListGetPtrToItem (list_t list, int itemPosition)
+{
+       if (itemPosition == LIST_START)
+               itemPosition = 1;
+       else if (itemPosition == LIST_END)
+               itemPosition = (*list)->numItems;
+
+       return ITEMPTR (list, itemPosition - 1);
+}
+
+/*******************************/
+
+/*
+ * returns a pointer the lists data (abstraction violation for
+ * optimization)
+ */
+void *ListGetDataPtr (list_t list)
+{
+       return &((*list)->itemList[0]);
+}
+
+/********************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+int ListApplyToEach (list_t list, int ascending,
+                    ListApplicationFunc funcToApply,
+                    void *callbackData)
+{
+       int result = 0, index;
+
+       if (!list || !funcToApply)
+               goto Error;
+
+       if (ascending) {
+               for (index = 1; index <= ListNumItems (list); index++) {
+                       result = funcToApply (index,
+                                             ListGetPtrToItem (list, index),
+                                             callbackData);
+                       if (result < 0)
+                               goto Error;
+               }
+       } else {
+               for (index = ListNumItems (list);
+                    index > 0 && index <= ListNumItems (list);
+                    index--) {
+                       result = funcToApply (index,
+                                             ListGetPtrToItem (list, index),
+                                             callbackData);
+                       if (result < 0)
+                               goto Error;
+               }
+       }
+
+Error:
+       return result;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/********************************/
+
+int ListGetItemSize (list_t list)
+{
+       return (*list)->itemSize;
+}
+
+/********************************/
+
+int ListNumItems (list_t list)
+{
+       return (*list)->numItems;
+}
+
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+void ListRemoveDuplicates (list_t list, CompareFunction compareFunction)
+{
+       int numItems, index, startIndexForFind, duplicatesIndex;
+
+       numItems = ListNumItems (list);
+
+       for (index = 1; index < numItems; index++) {
+               startIndexForFind = index + 1;
+               while (startIndexForFind <= numItems) {
+                       duplicatesIndex =
+                               ListFindItem (list,
+                                             ListGetPtrToItem (list, index),
+                                             startIndexForFind,
+                                             compareFunction);
+                       if (duplicatesIndex > 0) {
+                               ListRemoveItem (list, NULL, duplicatesIndex);
+                               numItems--;
+                               startIndexForFind = duplicatesIndex;
+                       } else {
+                               break;
+                       }
+               }
+       }
+}
+
+/*******************************/
+
+
+/*******************************/
+
+int ListFindItem (list_t list, void *ptrToItem, int startingPosition,
+                 CompareFunction compareFunction)
+{
+       int numItems, size, index, cmp;
+       void *listItemPtr;
+
+       if ((numItems = (*list)->numItems) == 0)
+               return 0;
+
+       size = (*list)->itemSize;
+
+       if (startingPosition == LIST_START)
+               startingPosition = 1;
+       else if (startingPosition == LIST_END)
+               startingPosition = numItems;
+
+       for (index = startingPosition; index <= numItems; index++) {
+               listItemPtr = ITEMPTR (list, index - 1);
+               cmp = compareFunction
+                       ? compareFunction (ptrToItem, listItemPtr)
+                       : ListMemBlockCmp (ptrToItem, listItemPtr, size);
+               if (cmp == 0)
+                       return index;
+       }
+
+       return 0;
+}
+
+/*******************************/
+
+int ShortCompare (void *a, void *b)
+{
+       if (*(short *) a < *(short *) b)
+               return -1;
+       if (*(short *) a > *(short *) b)
+               return 1;
+       return 0;
+}
+
+/*******************************/
+
+int IntCompare (void *a, void *b)
+{
+       if (*(int *) a < *(int *) b)
+               return -1;
+       if (*(int *) a > *(int *) b)
+               return 1;
+       return 0;
+}
+
+/*******************************/
+
+int CStringCompare (void *a, void *b)
+{
+       return strcmp (*(char **) a, *(char **) b);
+}
+
+/*******************************/
+
+
+int ListBinSearch (list_t list, void *ptrToItem,
+                  CompareFunction compareFunction)
+{
+       int index;
+
+       index = BinSearch (ITEMPTR (list, 0),
+                          (int) (*list)->numItems,
+                          (int) (*list)->itemSize, ptrToItem,
+                          compareFunction);
+
+       if (index >= 0)
+               index++;                        /* lists start from 1 */
+       else
+               index = 0;                      /* item not found */
+
+       return index;
+}
+
+/**************************************************************************/
+
+/*
+ * Reserves memory for numItems in the list. If it succeeds then
+ * numItems items can be inserted without possibility of an out of
+ * memory error (useful to simplify error recovery in complex
+ * functions). Returns 1 if success, 0 if out of memory.
+ */
+int ListPreAllocate (list_t list, int numItems)
+{
+       if ((*list)->listSize - (*list)->numItems < numItems) {
+               return ExpandListSpace (list,
+                                       numItems - ((*list)->listSize -
+                                               (*list)->numItems));
+       } else {
+               return 1;       /* enough items are already pre-allocated */
+       }
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
diff --git a/common/miiphybb.c b/common/miiphybb.c
new file mode 100644 (file)
index 0000000..dfc1992
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * (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 <ioports.h>
+#include <ppc_asm.tmpl>
+
+#ifdef CONFIG_BITBANGMII
+
+
+/*****************************************************************************
+ *
+ * Utility to send the preamble, address, and register (common to read
+ * and write).
+ */
+static void miiphy_pre(char          read,
+                      unsigned char  addr,
+                      unsigned char  reg)
+{
+  int   j;     /* counter */
+  volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+  /*
+   * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
+   * The IEEE spec says this is a PHY optional requirement.  The AMD
+   * 79C874 requires one after power up and one after a MII communications
+   * error.  This means that we are doing more preambles than we need,
+   * but it is safer and will be much more robust.
+   */
+
+  MDIO_ACTIVE;
+  MDIO(1);
+  for(j = 0; j < 32; j++)
+  {
+    MDC(0);
+    MIIDELAY;
+    MDC(1);
+    MIIDELAY;
+  }
+
+  /* send the start bit (01) and the read opcode (10) or write (10) */
+  MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
+  MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
+  MDC(0); MDIO(read);  MIIDELAY; MDC(1); MIIDELAY;
+  MDC(0); MDIO(!read); MIIDELAY; MDC(1); MIIDELAY;
+
+  /* send the PHY address */
+  for(j = 0; j < 5; j++)
+  {
+    MDC(0);
+    if((addr & 0x10) == 0)
+    {
+      MDIO(0);
+    }
+    else
+    {
+      MDIO(1);
+    }
+    MIIDELAY;
+    MDC(1);
+    MIIDELAY;
+    addr <<= 1;
+  }
+
+  /* send the register address */
+  for(j = 0; j < 5; j++)
+  {
+    MDC(0);
+    if((reg & 0x10) == 0)
+    {
+      MDIO(0);
+    }
+    else
+    {
+      MDIO(1);
+    }
+    MIIDELAY;
+    MDC(1);
+    MIIDELAY;
+    reg <<= 1;
+  }
+}
+
+
+/*****************************************************************************
+ *
+ * Read a MII PHY register.
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_read(unsigned char  addr,
+               unsigned char  reg,
+               unsigned short *value)
+{
+  short rdreg; /* register working value */
+  int   j;     /* counter */
+  volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+  miiphy_pre(1, addr, reg);
+
+  /* tri-state our MDIO I/O pin so we can read */
+  MDC(0);
+  MDIO_TRISTATE;
+  MIIDELAY;
+  MDC(1);
+  MIIDELAY;
+
+  /* check the turnaround bit: the PHY should be driving it to zero */
+  if(MDIO_READ != 0)
+  {
+    /* printf("PHY didn't drive TA low\n"); */
+    for(j = 0; j < 32; j++)
+    {
+      MDC(0);
+      MIIDELAY;
+      MDC(1);
+      MIIDELAY;
+    }
+    return(-1);
+  }
+
+  MDC(0);
+  MIIDELAY;
+
+  /* read 16 bits of register data, MSB first */
+  rdreg = 0;
+  for(j = 0; j < 16; j++)
+  {
+    MDC(1);
+    MIIDELAY;
+    rdreg <<= 1;
+    rdreg |= MDIO_READ;
+    MDC(0);
+    MIIDELAY;
+  }
+
+  MDC(1);
+  MIIDELAY;
+  MDC(0);
+  MIIDELAY;
+  MDC(1);
+  MIIDELAY;
+
+  *value = rdreg;
+
+#ifdef DEBUG
+  printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
+#endif
+
+  return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * Write a MII PHY register.
+ *
+ * Returns:
+ *   0 on success
+ */
+int miiphy_write(unsigned char  addr,
+                unsigned char  reg,
+                unsigned short value)
+{
+  int   j;     /* counter */
+  volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+  miiphy_pre(0, addr, reg);
+
+  /* send the turnaround (10) */
+  MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
+  MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
+
+  /* write 16 bits of register data, MSB first */
+  for(j = 0; j < 16; j++)
+  {
+    MDC(0);
+    if((value & 0x00008000) == 0)
+    {
+      MDIO(0);
+    }
+    else
+    {
+      MDIO(1);
+    }
+    MIIDELAY;
+    MDC(1);
+    MIIDELAY;
+    value <<= 1;
+  }
+
+  /*
+   * Tri-state the MDIO line.
+   */
+  MDIO_TRISTATE;
+  MDC(0);
+  MIIDELAY;
+  MDC(1);
+  MIIDELAY;
+
+  return 0;
+}
+
+#endif /* CONFIG_BITBANGMII */
+
diff --git a/common/s_record.c b/common/s_record.c
new file mode 100644 (file)
index 0000000..c52bf1b
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * (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 <s_record.h>
+
+static int hex1_bin (char  c);
+static int hex2_bin (char *s);
+
+int srec_decode (char *input, int *count, ulong *addr, char *data)
+{
+       int     i;
+       int     v;                              /* conversion buffer    */
+       int     srec_type;                      /* S-Record type        */
+       unsigned char chksum;                   /* buffer for checksum  */
+
+       chksum = 0;
+
+       /* skip anything before 'S', and the 'S' itself.
+        * Return error if not found
+        */
+
+       for (; *input; ++input) {
+               if (*input == 'S') {            /* skip 'S' */
+                       ++input;
+                       break;
+               }
+       }
+       if (*input == '\0') {                   /* no more data?        */
+               return (SREC_EMPTY);
+       }
+
+       v = *input++;                           /* record type          */
+
+       if ((*count = hex2_bin(input)) < 0) {
+               return (SREC_E_NOSREC);
+       }
+
+       chksum += *count;
+       input  += 2;
+
+       switch (v) {                            /* record type          */
+
+       case '0':                               /* start record         */
+               srec_type = SREC_START;         /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       case '1':
+               srec_type = SREC_DATA2;         /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       case '2':
+               srec_type = SREC_DATA3;         /* 3 byte addr field    */
+               *count   -= 4;                  /* - checksum and addr  */
+               break;
+       case '3':                               /* data record with a   */
+               srec_type = SREC_DATA4;         /* 4 byte addr field    */
+               *count   -= 5;                  /* - checksum and addr  */
+               break;
+/***   case '4'  ***/
+       case '5':                       /* count record, addr field contains */
+               srec_type = SREC_COUNT; /* a 2 byte record counter      */
+               *count    = 0;                  /* no data              */
+               break;
+/***   case '6' -- not used  ***/
+       case '7':                               /* end record with a    */
+               srec_type = SREC_END4;          /* 4 byte addr field    */
+               *count   -= 5;                  /* - checksum and addr  */
+               break;
+       case '8':                               /* end record with a    */
+               srec_type = SREC_END3;          /* 3 byte addr field    */
+               *count   -= 4;                  /* - checksum and addr  */
+               break;
+       case '9':                               /* end record with a    */
+               srec_type = SREC_END2;          /* 2 byte addr field    */
+               *count   -= 3;                  /* - checksum and addr  */
+               break;
+       default:
+               return (SREC_E_BADTYPE);
+       }
+
+       /* read address field */
+       *addr = 0;
+
+       switch (v) {
+       case '3':                               /* 4 byte addr field    */
+       case '7':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+               /* FALL THRU */
+       case '2':                               /* 3 byte addr field    */
+       case '8':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+               /* FALL THRU */
+       case '0':                               /* 2 byte addr field    */
+       case '1':
+       case '5':
+       case '9':
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               *addr <<= 8;
+               *addr  += v;
+               chksum += v;
+               input  += 2;
+
+               break;
+       default:
+               return (SREC_E_BADTYPE);
+       }
+
+       /* convert data and calculate checksum */
+       for (i=0; i < *count; ++i) {
+               if ((v = hex2_bin(input)) < 0) {
+                       return (SREC_E_NOSREC);
+               }
+               data[i] = v;
+               chksum += v;
+               input  += 2;
+       }
+
+       /* read anc check checksum */
+       if ((v = hex2_bin(input)) < 0) {
+               return (SREC_E_NOSREC);
+       }
+
+       if ((unsigned char)v != (unsigned char)~chksum) {
+               return (SREC_E_BADCHKS);
+       }
+
+       return (srec_type);
+}
+
+static int hex1_bin (char c)
+{
+       if (c >= '0' && c <= '9')
+               return (c - '0');
+       if (c >= 'a' && c <= 'f')
+               return (c + 10 - 'a');
+       if (c >= 'A' && c <= 'F')
+               return (c + 10 - 'A');
+       return (-1);
+}
+
+static int hex2_bin (char *s)
+{
+       int i, j;
+
+       if ((i = hex1_bin(*s++)) < 0) {
+               return (-1);
+       }
+       if ((j = hex1_bin(*s)) < 0) {
+               return (-1);
+       }
+
+       return ((i<<4) + j);
+}
diff --git a/common/usb.c b/common/usb.c
new file mode 100644 (file)
index 0000000..a5b29a5
--- /dev/null
@@ -0,0 +1,1066 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Most of this source has been derived from the Linux USB
+ * project.
+ *
+ * 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
+ *
+ */
+
+
+/*
+ * How it works:
+ *
+ * Since this is a bootloader, the devices will not be automatic
+ * (re)configured on hotplug, but after a restart of the USB the
+ * device should work.
+ *
+ * For each transfer (except "Interrupt") we wait for completion.
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+
+#include <usb.h>
+#ifdef CONFIG_4xx
+#include <405gp_pci.h>
+#endif
+
+
+
+#undef USB_DEBUG
+
+#ifdef USB_DEBUG
+#define        USB_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_PRINTF(fmt,args...)
+#endif
+
+static struct usb_device usb_dev[USB_MAX_DEVICE];
+static int dev_index;
+static int running;
+static int asynch_allowed;
+static struct devrequest setup_packet;
+
+/**********************************************************************
+ * some forward declerations...
+ */
+void usb_scan_devices(void);
+
+int usb_hub_probe(struct usb_device *dev, int ifnum);
+void usb_hub_reset(void);
+
+/***********************************************************************
+ * wait_ms
+ */
+
+void __inline__ wait_ms(unsigned long ms)
+{
+       while(ms-->0)
+               udelay(1000);
+}
+/***************************************************************************
+ * Init USB Device
+ */
+
+int usb_init(void)
+{
+       int result;
+
+       running=0;
+       dev_index=0;
+       asynch_allowed=1;
+       usb_hub_reset();
+       /* init low_level USB */
+       printf("USB:   ");
+       result = usb_lowlevel_init();
+       /* if lowlevel init is OK, scan the bus for devices i.e. search HUBs and configure them */
+       if(result==0) {
+               printf("scanning bus for devices... ");
+               running=1;
+               usb_scan_devices();
+               return 0;
+       }
+       else {
+               printf("Error, couldn't init Lowlevel part\n");
+               return -1;
+       }
+}
+
+/******************************************************************************
+ * Stop USB this stops the LowLevel Part and deregisters USB devices.
+ */
+int usb_stop(void)
+{
+       asynch_allowed=1;
+       usb_hub_reset();
+       return usb_lowlevel_stop();
+}
+
+/*
+ * disables the asynch behaviour of the control message. This is used for data
+ * transfers that uses the exclusiv access to the control and bulk messages.
+ */
+void usb_disable_asynch(int disable)
+{
+       asynch_allowed=!disable;
+}
+
+
+/*-------------------------------------------------------------------
+ * Message wrappers.
+ *
+ */
+
+/*
+ * submits an Interrupt Message
+ */
+int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+                       void *buffer,int transfer_len, int interval)
+{
+       return submit_int_msg(dev,pipe,buffer,transfer_len,interval);
+}
+
+/*
+ * submits a control message and waits for comletion (at least timeout * 1ms)
+ * If timeout is 0, we don't wait for completion (used as example to set and
+ * clear keyboards LEDs). For data transfers, (storage transfers) we don't
+ * allow control messages with 0 timeout, by previousely resetting the flag
+ * asynch_allowed (usb_disable_asynch(1)).
+ * returns the transfered length if OK or -1 if error. The transfered length
+ * and the current status are stored in the dev->act_len and dev->status.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+                       unsigned char request, unsigned char requesttype,
+                       unsigned short value, unsigned short index,
+                       void *data, unsigned short size, int timeout)
+{
+       if((timeout==0)&&(!asynch_allowed)) /* request for a asynch control pipe is not allowed */
+               return -1;
+       /* set setup command */
+       setup_packet.requesttype = requesttype;
+       setup_packet.request = request;
+       setup_packet.value = swap_16(value);
+       setup_packet.index = swap_16(index);
+       setup_packet.length = swap_16(size);
+       USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X\n",
+               request,requesttype,value,index,size);
+       dev->status=USB_ST_NOT_PROC; /*not yet processed */
+
+       submit_control_msg(dev,pipe,data,size,&setup_packet);
+       if(timeout==0) {
+               return (int)size;
+       }
+       while(timeout--) {
+               if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+                       break;
+               wait_ms(1);
+       }
+       if(dev->status==0)
+               return dev->act_len;
+       else {
+               return -1;
+       }
+}
+
+/*-------------------------------------------------------------------
+ * submits bulk message, and waits for completion. returns 0 if Ok or
+ * -1 if Error.
+ * synchronous behavior
+ */
+int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
+                       void *data, int len, int *actual_length, int timeout)
+{
+       if (len < 0)
+               return -1;
+       dev->status=USB_ST_NOT_PROC; /*not yet processed */
+       submit_bulk_msg(dev,pipe,data,len);
+       while(timeout--) {
+               if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+                       break;
+               wait_ms(1);
+       }
+       *actual_length=dev->act_len;
+       if(dev->status==0)
+               return 0;
+       else
+               return -1;
+}
+
+
+/*-------------------------------------------------------------------
+ * Max Packet stuff
+ */
+
+/*
+ * returns the max packet size, depending on the pipe direction and
+ * the configurations values
+ */
+int usb_maxpacket(struct usb_device *dev,unsigned long pipe)
+{
+       if((pipe & USB_DIR_IN)==0) /* direction is out -> use emaxpacket out */
+               return(dev->epmaxpacketout[((pipe>>15) & 0xf)]);
+       else
+               return(dev->epmaxpacketin[((pipe>>15) & 0xf)]);
+}
+
+/*
+ * set the max packed value of all endpoints in the given configuration
+ */
+int usb_set_maxpacket(struct usb_device *dev)
+{
+       int i,ii,b;
+       struct usb_endpoint_descriptor *ep;
+
+       for(i=0; i<dev->config.bNumInterfaces;i++) {
+               for(ii=0; ii<dev->config.if_desc[i].bNumEndpoints; ii++) {
+                       ep=&dev->config.if_desc[i].ep_desc[ii];
+                       b=ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+                       if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_CONTROL) {        /* Control => bidirectional */
+                               dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+                               dev->epmaxpacketin [b] = ep->wMaxPacketSize;
+                               USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",b,dev->epmaxpacketin[b]);
+                       }
+                       else {
+                               if ((ep->bEndpointAddress & 0x80)==0) { /* OUT Endpoint */
+                                       if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
+                                               dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+                                               USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",b,dev->epmaxpacketout[b]);
+                                       }
+                               }
+                               else  { /* IN Endpoint */
+                                       if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
+                                               dev->epmaxpacketin[b] = ep->wMaxPacketSize;
+                                               USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",b,dev->epmaxpacketin[b]);
+                                       }
+                               } /* if out */
+                       } /* if control */
+               } /* for each endpoint */
+       }
+       return 0;
+}
+
+/*******************************************************************************
+ * Parse the config, located in buffer, and fills the dev->config structure.
+ * Note that all little/big endian swapping are done automatically.
+ */
+int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno)
+{
+       struct usb_descriptor_header *head;
+       int index,ifno,epno;
+       ifno=-1;
+       epno=-1;
+
+       dev->configno=cfgno;
+       head =(struct usb_descriptor_header *)&buffer[0];
+       if(head->bDescriptorType!=USB_DT_CONFIG) {
+               printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
+               return -1;
+       }
+       memcpy(&dev->config,buffer,buffer[0]);
+       dev->config.wTotalLength=swap_16(dev->config.wTotalLength);
+       dev->config.no_of_if=0;
+
+       index=dev->config.bLength;
+       /* Ok the first entry must be a configuration entry, now process the others */
+       head=(struct usb_descriptor_header *)&buffer[index];
+       while(index+1 < dev->config.wTotalLength) {
+               switch(head->bDescriptorType) {
+                       case USB_DT_INTERFACE:
+                               ifno=dev->config.no_of_if;
+                               dev->config.no_of_if++; /* found an interface desc, increase numbers */
+                               memcpy(&dev->config.if_desc[ifno],&buffer[index],buffer[index]); /* copy new desc */
+                               dev->config.if_desc[ifno].no_of_ep=0;
+
+                               break;
+                       case USB_DT_ENDPOINT:
+                               epno=dev->config.if_desc[ifno].no_of_ep;
+                               dev->config.if_desc[ifno].no_of_ep++; /* found an endpoint */
+                               memcpy(&dev->config.if_desc[ifno].ep_desc[epno],&buffer[index],buffer[index]);
+                               dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize
+                                       =swap_16(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize);
+                               USB_PRINTF("if %d, ep %d\n",ifno,epno);
+                               break;
+                       default:
+                               if(head->bLength==0)
+                                       return 1;
+                               USB_PRINTF("unknown Description Type : %x\n",head->bDescriptorType);
+                               {
+                                       int i;
+                                       unsigned char *ch;
+                                       ch=(unsigned char *)head;
+                                       for(i=0;i<head->bLength; i++)
+                                               USB_PRINTF("%02X ",*ch++);
+                                       USB_PRINTF("\n\n\n");
+                               }
+                               break;
+               }
+               index+=head->bLength;
+               head=(struct usb_descriptor_header *)&buffer[index];
+       }
+       return 1;
+}
+
+/***********************************************************************
+ * Clears an endpoint
+ * endp: endpoint number in bits 0-3;
+ * direction flag in bit 7 (1 = IN, 0 = OUT)
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+       int result;
+       unsigned short status;
+       int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
+
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
+
+       /* don't clear if failed */
+       if (result < 0)
+               return result;
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
+               &status, sizeof(status), USB_CNTL_TIMEOUT * 3);
+       if (result < 0)
+               return result;
+       USB_PRINTF("usb_clear_halt: status 0x%x\n",status);
+       if (status & 1)
+               return -1;              /* still halted */
+       usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+       /* toggle is reset on clear */
+       usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+       return 0;
+}
+
+
+/**********************************************************************
+ * get_descriptor type
+ */
+int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+{
+       int res;
+       res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+                       (type << 8) + index, 0,
+                       buf, size, USB_CNTL_TIMEOUT);
+       return res;
+}
+
+/**********************************************************************
+ * gets configuration cfgno and store it in the buffer
+ */
+int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cfgno)
+{
+       int result;
+       unsigned int tmp;
+       struct usb_config_descriptor *config;
+
+
+       config=(struct usb_config_descriptor *)&buffer[0];
+       result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
+       if (result < 8) {
+               if (result < 0)
+                       printf("unable to get descriptor, error %lX\n",dev->status);
+               else
+                       printf("config descriptor too short (expected %i, got %i)\n",8,result);
+               return -1;
+       }
+       tmp=swap_16(config->wTotalLength);
+
+       result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp);
+       USB_PRINTF("get_conf_no %d Result %d, wLength %d\n",cfgno,result,tmp);
+       return result;
+}
+
+/********************************************************************
+ * set address of a device to the value in dev->devnum.
+ * This can only be done by addressing the device via the default address (0)
+ */
+int usb_set_address(struct usb_device *dev)
+{
+       int res;
+
+       USB_PRINTF("set address %d\n",dev->devnum);
+       res=usb_control_msg(dev, usb_snddefctrl(dev),
+               USB_REQ_SET_ADDRESS, 0,
+               (dev->devnum),0,
+               NULL,0, USB_CNTL_TIMEOUT);
+       return res;
+}
+
+/********************************************************************
+ * set interface number to interface
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+       struct usb_interface_descriptor *if_face = NULL;
+       int ret, i;
+
+       for (i=0; i<dev->config.bNumInterfaces; i++) {
+               if (dev->config.if_desc[i].bInterfaceNumber == interface) {
+                       if_face = &dev->config.if_desc[i];
+                       break;
+               }
+       }
+       if (!if_face) {
+               printf("selecting invalid interface %d", interface);
+               return -1;
+       }
+
+       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+           USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
+           interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0)
+               return ret;
+
+       if_face->act_altsetting = (unsigned char)alternate;
+       usb_set_maxpacket(dev);
+       return 0;
+}
+
+/********************************************************************
+ * set configuration number to configuration
+ */
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+       int res;
+       USB_PRINTF("set configuration %d\n",configuration);
+       /* set setup command */
+       res=usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+               USB_REQ_SET_CONFIGURATION, 0,
+               configuration,0,
+               NULL,0, USB_CNTL_TIMEOUT);
+       if(res==0) {
+               dev->toggle[0] = 0;
+               dev->toggle[1] = 0;
+               return 0;
+       }
+       else
+               return -1;
+}
+
+/********************************************************************
+ * set protocol to protocol
+ */
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * set idle
+ */
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get report
+ */
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get class descriptor
+ */
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+               unsigned char type, unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+               (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get string index in buffer
+ */
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+               (USB_DT_STRING << 8) + index, langid, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * usb_string:
+ * Get string index and translate it to ascii.
+ * returns string length (> 0) or error (< 0)
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+
+       unsigned char mybuf[256];
+       unsigned char *tbuf;
+       int err;
+       unsigned int u, idx;
+
+       if (size <= 0 || !buf || !index)
+               return -1;
+       buf[0] = 0;
+       tbuf=&mybuf[0];
+
+       /* get langid for strings if it's not yet known */
+       if (!dev->have_langid) {
+               err = usb_get_string(dev, 0, 0, tbuf, 4);
+               if (err < 0) {
+                       USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status);
+                       return -1;
+               } else if (tbuf[0] < 4) {
+                       USB_PRINTF("string descriptor 0 too short\n");
+                       return -1;
+               } else {
+                       dev->have_langid = -1;
+                       dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+                               /* always use the first langid listed */
+                       USB_PRINTF("USB device number %d default language ID 0x%x\n",
+                               dev->devnum, dev->string_langid);
+               }
+       }
+       /* Just ask for a maximum length string and then take the length
+        * that was returned. */
+       err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
+       if (err < 0)
+               return err;
+       u=tbuf[0];
+       USB_PRINTF("Strn Len %d, index %d\n",u,index);
+       err = usb_get_string(dev, dev->string_langid, index, tbuf, u);
+       if (err < 0)
+               return err;
+       size--;         /* leave room for trailing NULL char in output buffer */
+       for (idx = 0, u = 2; u < err; u += 2) {
+               if (idx >= size)
+                       break;
+               if (tbuf[u+1])                  /* high byte */
+                       buf[idx++] = '?';  /* non-ASCII character */
+               else
+                       buf[idx++] = tbuf[u];
+       }
+       buf[idx] = 0;
+       err = idx;
+       return err;
+}
+
+
+/********************************************************************
+ * USB device handling:
+ * the USB device are static allocated [USB_MAX_DEVICE].
+ */
+
+
+/* returns a pointer to the device with the index [index].
+ * if the device is not assigned (dev->devnum==-1) returns NULL
+ */
+struct usb_device * usb_get_dev_index(int index)
+{
+       if(usb_dev[index].devnum==-1)
+               return NULL;
+       else
+               return &usb_dev[index];
+}
+
+
+/* returns a pointer of a new device structure or NULL, if
+ * no device struct is available
+ */
+struct usb_device * usb_alloc_new_device(void)
+{
+       int i;
+       USB_PRINTF("New Device %d\n",dev_index);
+       if(dev_index==USB_MAX_DEVICE) {
+               printf("ERROR, to many USB Devices max=%d\n",USB_MAX_DEVICE);
+               return NULL;
+       }
+       usb_dev[dev_index].devnum=dev_index+1; /* default Address is 0, real addresses start with 1 */
+       usb_dev[dev_index].maxchild=0;
+       for(i=0;i<USB_MAXCHILDREN;i++)
+               usb_dev[dev_index].children[i]=NULL;
+       usb_dev[dev_index].parent=NULL;
+       dev_index++;
+       return &usb_dev[dev_index-1];
+}
+
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+       int addr, err;
+       int tmp;
+       unsigned char tmpbuf[256];
+
+       dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
+       dev->maxpacketsize = 0;         /* Default to 8 byte max packet size */
+       dev->epmaxpacketin [0] = 8;
+       dev->epmaxpacketout[0] = 8;
+
+       /* We still haven't set the Address yet */
+       addr = dev->devnum;
+       dev->devnum = 0;
+       err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+       if (err < 8) {
+               printf("\n      USB device not responding, giving up (status=%lX)\n",dev->status);
+               return 1;
+       }
+       dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
+       dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+       switch (dev->descriptor.bMaxPacketSize0) {
+               case 8: dev->maxpacketsize = 0; break;
+               case 16: dev->maxpacketsize = 1; break;
+               case 32: dev->maxpacketsize = 2; break;
+               case 64: dev->maxpacketsize = 3; break;
+       }
+       dev->devnum = addr;
+
+       err = usb_set_address(dev); /* set address */
+
+       if (err < 0) {
+               printf("\n      USB device not accepting new address (error=%lX)\n", dev->status);
+               return 1;
+       }
+
+       wait_ms(10);    /* Let the SET_ADDRESS settle */
+
+       tmp = sizeof(dev->descriptor);
+
+       err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
+       if (err < tmp) {
+               if (err < 0)
+                       printf("unable to get device descriptor (error=%d)\n",err);
+               else
+                       printf("USB device descriptor short read (expected %i, got %i)\n",tmp,err);
+               return 1;
+       }
+       /* correct le values */
+       dev->descriptor.bcdUSB=swap_16(dev->descriptor.bcdUSB);
+       dev->descriptor.idVendor=swap_16(dev->descriptor.idVendor);
+       dev->descriptor.idProduct=swap_16(dev->descriptor.idProduct);
+       dev->descriptor.bcdDevice=swap_16(dev->descriptor.bcdDevice);
+       /* only support for one config for now */
+       usb_get_configuration_no(dev,&tmpbuf[0],0);
+       usb_parse_config(dev,&tmpbuf[0],0);
+       usb_set_maxpacket(dev);
+       /* we set the default configuration here */
+       if (usb_set_configuration(dev, dev->config.bConfigurationValue)) {
+               printf("failed to set default configuration len %d, status %lX\n",dev->act_len,dev->status);
+               return -1;
+       }
+       USB_PRINTF("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+               dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+       memset(dev->mf, 0, sizeof(dev->mf));
+       memset(dev->prod, 0, sizeof(dev->prod));
+       memset(dev->serial, 0, sizeof(dev->serial));
+       if (dev->descriptor.iManufacturer)
+               usb_string(dev, dev->descriptor.iManufacturer, dev->mf, sizeof(dev->mf));
+       if (dev->descriptor.iProduct)
+               usb_string(dev, dev->descriptor.iProduct, dev->prod, sizeof(dev->prod));
+       if (dev->descriptor.iSerialNumber)
+               usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial));
+       USB_PRINTF("Manufacturer %s\n", dev->mf);
+       USB_PRINTF("Product      %s\n", dev->prod);
+       USB_PRINTF("SerialNumber %s\n", dev->serial);
+       /* now prode if the device is a hub */
+       usb_hub_probe(dev,0);
+       return 0;
+}
+
+/* build device Tree  */
+void usb_scan_devices(void)
+{
+       int i;
+       struct usb_device *dev;
+
+       /* first make all devices unknown */
+       for(i=0;i<USB_MAX_DEVICE;i++) {
+               memset(&usb_dev[i],0,sizeof(struct usb_device));
+               usb_dev[i].devnum=-1;
+       }
+       dev_index=0;
+       /* device 0 is always present (root hub, so let it analyze) */
+       dev=usb_alloc_new_device();
+       usb_new_device(dev);
+       printf("%d USB Devices found\n",dev_index);
+       /* insert "driver" if possible */
+#ifdef CONFIG_USB_KEYBOARD
+       drv_usb_kbd_init();
+       USB_PRINTF("scan end\n");
+#endif
+}
+
+
+/****************************************************************************
+ * HUB "Driver"
+ * Probes device for being a hub and configurate it
+ */
+
+#undef USB_HUB_DEBUG
+
+#ifdef USB_HUB_DEBUG
+#define        USB_HUB_PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define USB_HUB_PRINTF(fmt,args...)
+#endif
+
+
+static struct usb_hub_device hub_dev[USB_MAX_HUB];
+static int usb_hub_index;
+
+
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+               USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+               USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_hub_feature(struct usb_device *dev, int feature)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+                       data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+                       data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+
+static void usb_hub_power_on(struct usb_hub_device *hub)
+{
+       int i;
+       struct usb_device *dev;
+
+       dev=hub->pusb_dev;
+       /* Enable power to the ports */
+       USB_HUB_PRINTF("enabling power on all ports\n");
+       for (i = 0; i < dev->maxchild; i++) {
+               usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+               USB_HUB_PRINTF("port %d returns %lX\n",i+1,dev->status);
+               wait_ms(hub->desc.bPwrOn2PwrGood * 2);
+       }
+}
+
+void usb_hub_reset(void)
+{
+       usb_hub_index=0;
+}
+
+struct usb_hub_device *usb_hub_allocate(void)
+{
+       if(usb_hub_index<USB_MAX_HUB) {
+               return &hub_dev[usb_hub_index++];
+       }
+       printf("ERROR: USB_MAX_HUB (%d) reached\n",USB_MAX_HUB);
+       return NULL;
+}
+
+#define MAX_TRIES 5
+
+void usb_hub_port_connect_change(struct usb_device *dev, int port)
+{
+       struct usb_device *usb;
+       struct usb_port_status portsts;
+       unsigned short portstatus, portchange;
+       int tries;
+
+       /* Check status */
+       if (usb_get_port_status(dev, port + 1, &portsts)<0) {
+               USB_HUB_PRINTF("get_port_status failed\n");
+               return;
+       }
+
+       portstatus = swap_16(portsts.wPortStatus);
+       portchange = swap_16(portsts.wPortChange);
+       USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange,
+               portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+
+       /* Clear the connection change status */
+       usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+       /* Disconnect any existing devices under this port */
+       if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+            (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) {
+               USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
+               /* Return now if nothing is connected */
+               if (!(portstatus & USB_PORT_STAT_CONNECTION))
+                       return;
+       }
+       wait_ms(200);
+
+       /* Reset the port */
+
+       for(tries=0;tries<MAX_TRIES;tries++) {
+
+               usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
+               wait_ms(200);
+
+               if (usb_get_port_status(dev, port + 1, &portsts)<0) {
+                       USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status);
+                       return;
+               }
+               portstatus = swap_16(portsts.wPortStatus);
+               portchange = swap_16(portsts.wPortChange);
+               USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus ,portchange,
+                       portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+               USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d  USB_PORT_STAT_ENABLE %d\n",
+                       (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
+                       (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
+                       (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
+               if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+                   !(portstatus & USB_PORT_STAT_CONNECTION))
+                       return;
+
+               if (portstatus & USB_PORT_STAT_ENABLE)
+                       break;
+
+               wait_ms(200);
+       }
+
+       if (tries==MAX_TRIES) {
+               USB_HUB_PRINTF("Cannot enable port %i after %i retries, disabling port.\n", port+1, MAX_TRIES);
+               USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
+               return;
+       }
+
+       usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
+       wait_ms(200);
+
+       /* Allocate a new device struct for it */
+       usb=usb_alloc_new_device();
+       usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+
+       dev->children[port] = usb;
+       usb->parent=dev;
+       /* Run it through the hoops (find a driver, etc) */
+       if (usb_new_device(usb)) {
+               /* Woops, disable the port */
+               USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
+               usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+       }
+}
+
+
+int usb_hub_configure(struct usb_device *dev)
+{
+       unsigned char buffer[256], *bitmap;
+       struct usb_hub_descriptor *descriptor;
+       struct usb_hub_status *hubsts;
+       int i;
+       struct usb_hub_device *hub;
+
+       /* "allocate" Hub device */
+       hub=usb_hub_allocate();
+       if(hub==NULL)
+               return -1;
+       hub->pusb_dev=dev;
+       /* Get the the hub descriptor */
+       if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
+               USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor, giving up %lX\n",dev->status);
+               return -1;
+       }
+       descriptor = (struct usb_hub_descriptor *)buffer;
+       if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
+               USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor 2nd giving up %lX\n",dev->status);
+               return -1;
+       }
+       memcpy((unsigned char *)&hub->desc,buffer,descriptor->bLength);
+       /* adjust 16bit values */
+       hub->desc.wHubCharacteristics=swap_16(descriptor->wHubCharacteristics);
+       /* set the bitmap */
+       bitmap=(unsigned char *)&hub->desc.DeviceRemovable[0];
+       memset(bitmap,0xff,(USB_MAXCHILDREN+1+7)/8); /* devices not removable by default */
+       bitmap=(unsigned char *)&hub->desc.PortPowerCtrlMask[0];
+       memset(bitmap,0xff,(USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
+       for(i=0;i<((hub->desc.bNbrPorts + 1 + 7)/8);i++) {
+               hub->desc.DeviceRemovable[i]=descriptor->DeviceRemovable[i];
+       }
+       for(i=0;i<((hub->desc.bNbrPorts + 1 + 7)/8);i++) {
+               hub->desc.DeviceRemovable[i]=descriptor->PortPowerCtrlMask[i];
+       }
+       dev->maxchild = descriptor->bNbrPorts;
+       USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
+
+       switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
+               case 0x00:
+                       USB_HUB_PRINTF("ganged power switching\n");
+                       break;
+               case 0x01:
+                       USB_HUB_PRINTF("individual port power switching\n");
+                       break;
+               case 0x02:
+               case 0x03:
+                       USB_HUB_PRINTF("unknown reserved power switching mode\n");
+                       break;
+       }
+
+       if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
+               USB_HUB_PRINTF("part of a compound device\n");
+       else
+               USB_HUB_PRINTF("standalone hub\n");
+
+       switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
+               case 0x00:
+                       USB_HUB_PRINTF("global over-current protection\n");
+                       break;
+               case 0x08:
+                       USB_HUB_PRINTF("individual port over-current protection\n");
+                       break;
+               case 0x10:
+               case 0x18:
+                       USB_HUB_PRINTF("no over-current protection\n");
+      break;
+       }
+       USB_HUB_PRINTF("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2);
+       USB_HUB_PRINTF("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent);
+       for (i = 0; i < dev->maxchild; i++)
+               USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
+                       hub->desc.DeviceRemovable[(i + 1)/8] & (1 << ((i + 1)%8)) ? " not" : "");
+       if (usb_get_hub_status(dev, buffer) < 0) {
+               USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",dev->status);
+               return -1;
+       }
+       hubsts = (struct usb_hub_status *)buffer;
+       USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
+               swap_16(hubsts->wHubStatus),swap_16(hubsts->wHubChange));
+       USB_HUB_PRINTF("local power source is %s\n",
+               (swap_16(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+       USB_HUB_PRINTF("%sover-current condition exists\n",
+               (swap_16(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+       usb_hub_power_on(hub);
+       for (i = 0; i < dev->maxchild; i++) {
+               struct usb_port_status portsts;
+               unsigned short portstatus, portchange;
+
+               if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
+                       USB_HUB_PRINTF("get_port_status failed\n");
+                       continue;
+               }
+               portstatus = swap_16(portsts.wPortStatus);
+               portchange = swap_16(portsts.wPortChange);
+               USB_HUB_PRINTF("Port %d Status %X Change %X\n",i+1,portstatus,portchange);
+               if (portchange & USB_PORT_STAT_C_CONNECTION) {
+                       USB_HUB_PRINTF("port %d connection change\n", i + 1);
+                       usb_hub_port_connect_change(dev, i);
+               }
+               if (portchange & USB_PORT_STAT_C_ENABLE) {
+                       USB_HUB_PRINTF("port %d enable change, status %x\n", i + 1, portstatus);
+                       usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+
+                       /* EM interference sometimes causes bad shielded USB devices to
+                        * be shutdown by the hub, this hack enables them again.
+                        * Works at least with mouse driver */
+                       if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+                               (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
+                               USB_HUB_PRINTF("already running port %i disabled by hub (EMI?), re-enabling...\n",
+                                       i + 1);
+                                       usb_hub_port_connect_change(dev, i);
+                       }
+               }
+               if (portstatus & USB_PORT_STAT_SUSPEND) {
+                       USB_HUB_PRINTF("port %d suspend change\n", i + 1);
+                       usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_SUSPEND);
+               }
+
+               if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+                       USB_HUB_PRINTF("port %d over-current change\n", i + 1);
+                       usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+                       usb_hub_power_on(hub);
+               }
+
+               if (portchange & USB_PORT_STAT_C_RESET) {
+                       USB_HUB_PRINTF("port %d reset change\n", i + 1);
+                       usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+               }
+       } /* end for i all ports */
+
+       return 0;
+}
+
+int usb_hub_probe(struct usb_device *dev, int ifnum)
+{
+       struct usb_interface_descriptor *iface;
+       struct usb_endpoint_descriptor *ep;
+       int ret;
+
+       iface = &dev->config.if_desc[ifnum];
+       /* Is it a hub? */
+       if (iface->bInterfaceClass != USB_CLASS_HUB)
+               return 0;
+       /* Some hubs have a subclass of 1, which AFAICT according to the */
+       /*  specs is not defined, but it works */
+       if ((iface->bInterfaceSubClass != 0) &&
+           (iface->bInterfaceSubClass != 1))
+               return 0;
+       /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+       if (iface->bNumEndpoints != 1)
+               return 0;
+       ep = &iface->ep_desc[0];
+       /* Output endpoint? Curiousier and curiousier.. */
+       if (!(ep->bEndpointAddress & USB_DIR_IN))
+               return 0;
+       /* If it's not an interrupt endpoint, we'd better punt! */
+       if ((ep->bmAttributes & 3) != 3)
+               return 0;
+       /* We found a hub */
+       USB_HUB_PRINTF("USB hub found\n");
+       ret=usb_hub_configure(dev);
+       return ret;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_USB) */
+
+/* EOF */
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
new file mode 100644 (file)
index 0000000..ad7e610
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Part of this source has been derived from the Linux USB
+ * project.
+ *
+ * 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 <devices.h>
+
+#ifdef CONFIG_USB_KEYBOARD
+
+#include <usb.h>
+
+#undef USB_KBD_DEBUG
+/*
+ * if overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+       return (0);
+}
+#endif
+
+#ifdef USB_KBD_DEBUG
+#define        USB_KBD_PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define USB_KBD_PRINTF(fmt,args...)
+#endif
+
+
+#define REPEAT_RATE  40/4 /* 40msec -> 25cps */
+#define REPEAT_DELAY 10 /* 10 x REAPEAT_RATE = 400msec */
+
+#define NUM_LOCK       0x53
+#define CAPS_LOCK 0x39
+#define SCROLL_LOCK 0x47
+
+
+/* Modifier bits */
+#define LEFT_CNTR              0
+#define LEFT_SHIFT     1
+#define LEFT_ALT               2
+#define LEFT_GUI               3
+#define RIGHT_CNTR     4
+#define RIGHT_SHIFT    5
+#define RIGHT_ALT              6
+#define RIGHT_GUI              7
+
+#define USB_KBD_BUFFER_LEN 0x20  /* size of the keyboardbuffer */
+
+static volatile char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
+static volatile int usb_in_pointer = 0;
+static volatile int usb_out_pointer = 0;
+
+unsigned char new[8];
+unsigned char old[8];
+int repeat_delay;
+#define DEVNAME "usbkbd"
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+
+static unsigned char leds __attribute__ ((aligned (0x4)));
+
+static unsigned char usb_kbd_numkey[] = {
+        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0','\r',0x1b,'\b','\t',' ', '-',
+        '=', '[', ']','\\', '#', ';', '\'', '`', ',', '.', '/'
+};
+static unsigned char usb_kbd_numkey_shifted[] = {
+        '!', '@', '#', '$', '%', '^', '&', '*', '(', ')','\r',0x1b,'\b','\t',' ', '_',
+        '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'
+};
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+static void usb_kbd_put_queue(char data)
+{
+       if((usb_in_pointer+1)==USB_KBD_BUFFER_LEN) {
+               if(usb_out_pointer==0) {
+                       return; /* buffer full */
+               } else{
+                       usb_in_pointer=0;
+               }
+       } else {
+               if((usb_in_pointer+1)==usb_out_pointer)
+                       return; /* buffer full */
+               usb_in_pointer++;
+       }
+       usb_kbd_buffer[usb_in_pointer]=data;
+       return;
+}
+
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+       if(usb_in_pointer==usb_out_pointer)
+               return(0); /* no data */
+       else
+               return(1);
+}
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+       char c;
+       while(usb_in_pointer==usb_out_pointer);
+       if((usb_out_pointer+1)==USB_KBD_BUFFER_LEN)
+               usb_out_pointer=0;
+       else
+               usb_out_pointer++;
+       c=usb_kbd_buffer[usb_out_pointer];
+       return (int)c;
+
+}
+
+/* forward decleration */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+
+/* search for keyboard and register it if found */
+int drv_usb_kbd_init(void)
+{
+       int error,i,index;
+       device_t usb_kbd_dev,*old_dev;
+       struct usb_device *dev;
+       char *stdinname  = getenv ("stdin");
+
+       usb_in_pointer=0;
+       usb_out_pointer=0;
+       /* scan all USB Devices */
+       for(i=0;i<USB_MAX_DEVICE;i++) {
+               dev=usb_get_dev_index(i); /* get device */
+               if(dev->devnum!=-1) {
+                       if(usb_kbd_probe(dev,0)==1) { /* Ok, we found a keyboard */
+                               /* check, if it is already registered */
+                               USB_KBD_PRINTF("USB KBD found set up device.\n");
+                               for (index=1; index<=ListNumItems(devlist); index++) {
+                                       old_dev = ListGetPtrToItem(devlist, index);
+                                       if(strcmp(old_dev->name,DEVNAME)==0) {
+                                               /* ok, already registered, just return ok */
+                                               USB_KBD_PRINTF("USB KBD is already registered.\n");
+                                               return 1;
+                                       }
+                               }
+                               /* register the keyboard */
+                               USB_KBD_PRINTF("USB KBD register.\n");
+                               memset (&usb_kbd_dev, 0, sizeof(device_t));
+                               strcpy(usb_kbd_dev.name, DEVNAME);
+                               usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+                               usb_kbd_dev.putc = NULL;
+                               usb_kbd_dev.puts = NULL;
+                               usb_kbd_dev.getc = usb_kbd_getc;
+                               usb_kbd_dev.tstc = usb_kbd_testc;
+                               error = device_register (&usb_kbd_dev);
+                               if(error==0) {
+                                       /* check if this is the standard input device */
+                                       if(strcmp(stdinname,DEVNAME)==0) {
+                                               /* reassign the console */
+                                               if(overwrite_console()) {
+                                                       return 1;
+                                               }
+                                               error=console_assign(stdin,DEVNAME);
+                                               if(error==0)
+                                                       return 1;
+                                               else
+                                                       return error;
+                                       }
+                                       return 1;
+                               }
+                               return error;
+                       }
+               }
+       }
+       /* no USB Keyboard found */
+       return -1;
+}
+
+
+/* deregistering the keyboard */
+int usb_kbd_deregister(void)
+{
+       return device_deregister(DEVNAME);
+}
+
+/**************************************************************************
+ * Low Level drivers
+ */
+
+/* set the LEDs. Since this is used in the irq routine, the control job
+   is issued with a timeout of 0. This means, that the job is queued without
+   waiting for job completion */
+
+static void usb_kbd_setled(struct usb_device *dev)
+{
+       struct usb_interface_descriptor *iface;
+       iface = &dev->config.if_desc[0];
+       leds=0;
+       if(scroll_lock!=0)
+               leds|=1;
+       leds<<=1;
+       if(caps_lock!=0)
+               leds|=1;
+       leds<<=1;
+       if(num_lock!=0)
+               leds|=1;
+       usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0x200, iface->bInterfaceNumber,(void *)&leds, 1, 0);
+
+}
+
+
+#define CAPITAL_MASK 0x20
+/* Translate the scancode in ASCII */
+static int usb_kbd_translate(unsigned char scancode,unsigned char modifier,int pressed)
+{
+       unsigned char keycode;
+
+       if(pressed==0) {
+               /* key released */
+               repeat_delay=0;
+               return 0;
+       }
+       if(pressed==2) {
+               repeat_delay++;
+               if(repeat_delay<REPEAT_DELAY)
+                       return 0;
+               repeat_delay=REPEAT_DELAY;
+       }
+       keycode=0;
+       if((scancode>3) && (scancode<0x1d)) { /* alpha numeric values */
+               keycode=scancode-4 + 0x61;
+               if(caps_lock)
+                       keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+               if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) {
+                       if(keycode & CAPITAL_MASK)
+                               keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+                       else
+                               keycode|=CAPITAL_MASK; /* switch to non capital Letters */
+               }
+       }
+       if((scancode>0x1d) && (scancode<0x3A)) {
+               if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0))  /* shifted */
+                       keycode=usb_kbd_numkey_shifted[scancode-0x1e];
+               else /* non shifted */
+                       keycode=usb_kbd_numkey[scancode-0x1e];
+       }
+       if(pressed==1) {
+               if(scancode==NUM_LOCK) {
+                       num_lock=~num_lock;
+                       return 1;
+               }
+               if(scancode==CAPS_LOCK) {
+                       caps_lock=~caps_lock;
+                       return 1;
+               }
+               if(scancode==SCROLL_LOCK) {
+                       scroll_lock=~scroll_lock;
+                       return 1;
+               }
+       }
+       if(keycode!=0) {
+               USB_KBD_PRINTF("%c",keycode);
+               usb_kbd_put_queue(keycode);
+       }
+       return 0;
+}
+
+/* Interrupt service routine */
+static int usb_kbd_irq(struct usb_device *dev)
+{
+       int i,res;
+
+       if((dev->irq_status!=0)||(dev->irq_act_len!=8))
+       {
+               USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",dev->irq_status,dev->irq_act_len);
+               return 1;
+       }
+       res=0;
+       for (i = 2; i < 8; i++) {
+               if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) {
+                       res|=usb_kbd_translate(old[i],new[0],0);
+               }
+               if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) {
+                       res|=usb_kbd_translate(new[i],new[0],1);
+               }
+       }
+       if((new[2]>3) && (old[2]==new[2])) /* still pressed */
+               res|=usb_kbd_translate(new[2],new[0],2);
+       if(res==1)
+               usb_kbd_setled(dev);
+       memcpy(&old[0],&new[0], 8);
+       return 1; /* install IRQ Handler again */
+}
+
+/* probes the USB device dev for keyboard type */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+{
+       struct usb_interface_descriptor *iface;
+       struct usb_endpoint_descriptor *ep;
+       int pipe,maxp;
+
+       if (dev->descriptor.bNumConfigurations != 1) return 0;
+       iface = &dev->config.if_desc[ifnum];
+
+       if (iface->bInterfaceClass != 3) return 0;
+       if (iface->bInterfaceSubClass != 1) return 0;
+       if (iface->bInterfaceProtocol != 1) return 0;
+       if (iface->bNumEndpoints != 1) return 0;
+
+       ep = &iface->ep_desc[0];
+
+       if (!(ep->bEndpointAddress & 0x80)) return 0;
+       if ((ep->bmAttributes & 3) != 3) return 0;
+       USB_KBD_PRINTF("USB KBD found set protocol...\n");
+       /* ok, we found a USB Keyboard, install it */
+       /* usb_kbd_get_hid_desc(dev); */
+       usb_set_protocol(dev, iface->bInterfaceNumber, 0);
+       USB_KBD_PRINTF("USB KBD found set idle...\n");
+       usb_set_idle(dev, iface->bInterfaceNumber, REPEAT_RATE, 0);
+       memset(&new[0], 0, 8);
+       memset(&old[0], 0, 8);
+       repeat_delay=0;
+       pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe);
+       dev->irq_handle=usb_kbd_irq;
+       USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
+       usb_submit_int_msg(dev,pipe,&new[0], maxp > 8 ? 8 : maxp,ep->bInterval);
+       return 1;
+}
+
+
+#if 0
+struct usb_hid_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType; /* 0x21 for HID */
+       unsigned short bcdHID; /* release number */
+       unsigned char  bCountryCode;
+       unsigned char  bNumDescriptors;
+       unsigned char  bReportDescriptorType;
+       unsigned short wDescriptorLength;
+} __attribute__ ((packed));
+
+/*
+ * We parse each description item into this structure. Short items data
+ * values are expanded to 32-bit signed int, long items contain a pointer
+ * into the data area.
+ */
+
+struct hid_item {
+       unsigned char format;
+       unsigned char size;
+       unsigned char type;
+       unsigned char tag;
+       union {
+           unsigned char   u8;
+           char            s8;
+           unsigned short  u16;
+           short           s16;
+           unsigned long   u32;
+           long            s32;
+           unsigned char  *longdata;
+       } data;
+};
+
+/*
+ * HID report item format
+ */
+
+#define HID_ITEM_FORMAT_SHORT  0
+#define HID_ITEM_FORMAT_LONG   1
+
+/*
+ * Special tag indicating long items
+ */
+
+#define HID_ITEM_TAG_LONG      15
+
+
+
+static struct usb_hid_descriptor usb_kbd_hid_desc;
+
+void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
+{
+       printf("USB_HID_DESC:\n");
+       printf("  bLenght               0x%x\n",hid->bLength);
+       printf("  bcdHID                0x%x\n",hid->bcdHID);
+       printf("  bCountryCode          %d\n",hid->bCountryCode);
+       printf("  bNumDescriptors       0x%x\n",hid->bNumDescriptors);
+       printf("  bReportDescriptorType 0x%x\n",hid->bReportDescriptorType);
+       printf("  wDescriptorLength     0x%x\n",hid->wDescriptorLength);
+}
+
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static int fetch_item(unsigned char *start,unsigned char *end, struct hid_item *item)
+{
+       if((end - start) > 0) {
+               unsigned char b = *start++;
+               item->type = (b >> 2) & 3;
+               item->tag  = (b >> 4) & 15;
+               if (item->tag == HID_ITEM_TAG_LONG) {
+                       item->format = HID_ITEM_FORMAT_LONG;
+                       if ((end - start) >= 2) {
+                               item->size = *start++;
+                               item->tag  = *start++;
+                               if ((end - start) >= item->size) {
+                                       item->data.longdata = start;
+                                       start += item->size;
+                                       return item->size;
+                               }
+                       }
+               } else {
+                       item->format = HID_ITEM_FORMAT_SHORT;
+                       item->size = b & 3;
+                       switch (item->size) {
+                               case 0:
+                                       return item->size;
+                               case 1:
+                                       if ((end - start) >= 1) {
+                                               item->data.u8 = *start++;
+                                               return item->size;
+                                       }
+                                       break;
+                               case 2:
+                                       if ((end - start) >= 2) {
+                                               item->data.u16 = swap_16((unsigned short *)start);
+                                               start+=2;
+                                               return item->size;
+                                       }
+                               case 3:
+                                       item->size++;
+                                       if ((end - start) >= 4) {
+                                               item->data.u32 = swap_32((unsigned long *)start);
+                                               start+=4;
+                                               return item->size;
+                                       }
+                       }
+               }
+       }
+       return -1;
+}
+
+/*
+ * HID report descriptor item type (prefix bit 2,3)
+ */
+
+#define HID_ITEM_TYPE_MAIN             0
+#define HID_ITEM_TYPE_GLOBAL           1
+#define HID_ITEM_TYPE_LOCAL            2
+#define HID_ITEM_TYPE_RESERVED         3
+/*
+ * HID report descriptor main item tags
+ */
+
+#define HID_MAIN_ITEM_TAG_INPUT                        8
+#define HID_MAIN_ITEM_TAG_OUTPUT               9
+#define HID_MAIN_ITEM_TAG_FEATURE              11
+#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION     10
+#define HID_MAIN_ITEM_TAG_END_COLLECTION       12
+/*
+ * HID report descriptor main item contents
+ */
+
+#define HID_MAIN_ITEM_CONSTANT         0x001
+#define HID_MAIN_ITEM_VARIABLE         0x002
+#define HID_MAIN_ITEM_RELATIVE         0x004
+#define HID_MAIN_ITEM_WRAP             0x008
+#define HID_MAIN_ITEM_NONLINEAR                0x010
+#define HID_MAIN_ITEM_NO_PREFERRED     0x020
+#define HID_MAIN_ITEM_NULL_STATE       0x040
+#define HID_MAIN_ITEM_VOLATILE         0x080
+#define HID_MAIN_ITEM_BUFFERED_BYTE    0x100
+
+/*
+ * HID report descriptor collection item types
+ */
+
+#define HID_COLLECTION_PHYSICAL                0
+#define HID_COLLECTION_APPLICATION     1
+#define HID_COLLECTION_LOGICAL         2
+/*
+ * HID report descriptor global item tags
+ */
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE         0
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM    1
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM    2
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM   3
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM   4
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT      5
+#define HID_GLOBAL_ITEM_TAG_UNIT               6
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE                7
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID          8
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT       9
+#define HID_GLOBAL_ITEM_TAG_PUSH               10
+#define HID_GLOBAL_ITEM_TAG_POP                        11
+
+/*
+ * HID report descriptor local item tags
+ */
+
+#define HID_LOCAL_ITEM_TAG_USAGE               0
+#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM       1
+#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM       2
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX    3
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM  4
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM  5
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX                7
+#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM      8
+#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM      9
+#define HID_LOCAL_ITEM_TAG_DELIMITER           10
+
+
+
+static void usb_kbd_show_item(struct hid_item *item)
+{
+       switch(item->type) {
+               case HID_ITEM_TYPE_MAIN:
+                       switch(item->tag) {
+                               case HID_MAIN_ITEM_TAG_INPUT:
+                                       printf("Main Input");
+                                       break;
+                               case HID_MAIN_ITEM_TAG_OUTPUT:
+                                       printf("Main Output");
+                                       break;
+                               case HID_MAIN_ITEM_TAG_FEATURE:
+                                       printf("Main Feature");
+                                       break;
+                               case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+                                       printf("Main Begin Collection");
+                                       break;
+                               case HID_MAIN_ITEM_TAG_END_COLLECTION:
+                                       printf("Main End Collection");
+                                       break;
+                               default:
+                                       printf("Main reserved %d",item->tag);
+                                       break;
+                       }
+                       break;
+               case HID_ITEM_TYPE_GLOBAL:
+                       switch(item->tag) {
+                               case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+                                       printf("- Global Usage Page");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+                                       printf("- Global Logical Minimum");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+                                       printf("- Global Logical Maximum");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+                                       printf("- Global physical Minimum");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+                                       printf("- Global physical Maximum");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+                                       printf("- Global Unit Exponent");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_UNIT:
+                                       printf("- Global Unit");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+                                       printf("- Global Report Size");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+                                       printf("- Global Report ID");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+                                       printf("- Global Report Count");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_PUSH:
+                                       printf("- Global Push");
+                                       break;
+                               case HID_GLOBAL_ITEM_TAG_POP:
+                                       printf("- Global Pop");
+                                       break;
+                               default:
+                                       printf("- Global reserved %d",item->tag);
+                                       break;
+                       }
+                       break;
+               case HID_ITEM_TYPE_LOCAL:
+                       switch(item->tag) {
+                               case HID_LOCAL_ITEM_TAG_USAGE:
+                                       printf("-- Local Usage");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+                                       printf("-- Local Usage Minimum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+                                       printf("-- Local Usage Maximum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
+                                       printf("-- Local Designator Index");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
+                                       printf("-- Local Designator Minimum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
+                                       printf("-- Local Designator Maximum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_STRING_INDEX:
+                                       printf("-- Local String Index");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
+                                       printf("-- Local String Minimum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
+                                       printf("-- Local String Maximum");
+                                       break;
+                               case HID_LOCAL_ITEM_TAG_DELIMITER:
+                                       printf("-- Local Delimiter");
+                                       break;
+                               default:
+                                       printf("-- Local reserved %d",item->tag);
+                                       break;
+                       }
+                       break;
+               default:
+                       printf("--- reserved %d",item->type);
+                       break;
+       }
+       switch(item->size) {
+               case 1:
+                       printf("  %d",item->data.u8);
+                       break;
+               case 2:
+                       printf("  %d",item->data.u16);
+                       break;
+               case 4:
+                       printf("  %ld",item->data.u32);
+                       break;
+       }
+       printf("\n");
+}
+
+
+
+static int usb_kbd_get_hid_desc(struct usb_device *dev)
+{
+       unsigned char buffer[256];
+       struct usb_descriptor_header *head;
+       struct usb_config_descriptor *config;
+       int index,len,i;
+       unsigned char *start, *end;
+       struct hid_item item;
+
+       if(usb_get_configuration_no(dev,&buffer[0],0)==-1)
+               return -1;
+       head =(struct usb_descriptor_header *)&buffer[0];
+       if(head->bDescriptorType!=USB_DT_CONFIG) {
+               printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
+               return -1;
+       }
+       index=head->bLength;
+       config=(struct usb_config_descriptor *)&buffer[0];
+       len=swap_16(config->wTotalLength);
+       /* Ok the first entry must be a configuration entry, now process the others */
+       head=(struct usb_descriptor_header *)&buffer[index];
+       while(index+1 < len) {
+               if(head->bDescriptorType==USB_DT_HID) {
+                       printf("HID desc found\n");
+                       memcpy(&usb_kbd_hid_desc,&buffer[index],buffer[index]);
+                       usb_kbd_hid_desc.bcdHID=swap_16(usb_kbd_hid_desc.bcdHID);
+                       usb_kbd_hid_desc.wDescriptorLength=swap_16(usb_kbd_hid_desc.wDescriptorLength);
+                       usb_kbd_display_hid(&usb_kbd_hid_desc);
+                       len=0;
+                       break;
+               }
+               index+=head->bLength;
+               head=(struct usb_descriptor_header *)&buffer[index];
+       }
+       if(len>0)
+               return -1;
+       len=usb_kbd_hid_desc.wDescriptorLength;
+       if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) {
+               printf("reading report descriptor failed\n");
+               return -1;
+       }
+       printf(" report descriptor (size %u, read %d)\n", len, index);
+       start=&buffer[0];
+       end=&buffer[len];
+       i=0;
+       do {
+               index=fetch_item(start,end,&item);
+               i+=index;
+               i++;
+               if(index>=0)
+                       usb_kbd_show_item(&item);
+
+               start+=index;
+               start++;
+       } while(index>=0);
+
+}
+
+
+#endif
+
+#endif /* CONFIG_USB_KEYBOARD */
+
+/* eof */
+
diff --git a/common/usb_storage.c b/common/usb_storage.c
new file mode 100644 (file)
index 0000000..b134721
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Most of this source has been derived from the Linux USB
+ * project.
+ *
+ * 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
+ *
+ */
+
+/* Note:
+ * Currently only the CBI transport protocoll has been implemented, and it
+ * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
+ * transport protocoll may work as well.
+ */
+
+
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+#include <usb.h>
+
+#ifdef CONFIG_USB_STORAGE
+
+#undef USB_STOR_DEBUG
+
+#ifdef USB_STOR_DEBUG
+#define        USB_STOR_PRINTF(fmt,args...)    printf (fmt ,##args)
+#else
+#define USB_STOR_PRINTF(fmt,args...)
+#endif
+
+#include <scsi.h>
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+unsigned char us_direction[256/8] = {
+       0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+       0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+static unsigned char usb_stor_buf[512];
+static ccb usb_ccb;
+
+/*
+ * CBI style
+ */
+
+#define US_CBI_ADSC            0
+
+
+#define USB_MAX_STOR_DEV 5
+static int usb_max_devs; /* number of highest available usb device */
+
+static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
+
+struct us_data;
+typedef int (*trans_cmnd)(ccb*, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+
+struct us_data {
+       struct usb_device       *pusb_dev;       /* this usb_device */
+       unsigned int            flags;           /* from filter initially */
+       unsigned char           ifnum;           /* interface number */
+       unsigned char           ep_in;           /* in endpoint */
+       unsigned char           ep_out;          /* out ....... */
+       unsigned char           ep_int;          /* interrupt . */
+       unsigned char           subclass;        /* as in overview */
+       unsigned char           protocol;        /* .............. */
+       unsigned char           attention_done;  /* force attn on first cmd */
+       unsigned short  ip_data;         /* interrupt data */
+       int                                                     action;          /* what to do */
+       int                                                     ip_wanted; /* needed */
+       int                                                     *irq_handle;     /* for USB int requests */
+       unsigned int            irqpipe;         /* pipe for release_irq */
+       unsigned char           irqmaxp;        /* max packed for irq Pipe */
+       unsigned char   irqinterval; /* Intervall for IRQ Pipe */
+       ccb                                                     *srb;            /* current srb */
+       trans_reset                     transport_reset; /* reset routine */
+       trans_cmnd                      transport; /* transport routine */
+};
+
+static struct us_data usb_stor[USB_MAX_STOR_DEV];
+
+
+
+#define USB_STOR_TRANSPORT_GOOD    0
+#define USB_STOR_TRANSPORT_FAILED -1
+#define USB_STOR_TRANSPORT_ERROR  -2
+
+
+
+
+
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *us, block_dev_desc_t *dev_desc);
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss);
+unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer);
+struct usb_device * usb_get_dev_index(int index);
+void uhci_show_temp_int_td(void);
+
+block_dev_desc_t *usb_stor_get_dev(int index)
+{
+       return &usb_dev_desc[index];
+}
+
+
+void usb_show_progress(void)
+{
+       printf(".");
+}
+
+/*********************************************************************************
+ * (re)-scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_stor_scan(int mode)
+{
+       unsigned char i;
+       struct usb_device *dev;
+
+       if(mode==1) {
+               printf("scanning bus for storage devices...\n");
+       }
+       usb_disable_asynch(1); /* asynch transfer not allowed */
+
+       for(i=0;i<USB_MAX_STOR_DEV;i++) {
+               memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t));
+               usb_dev_desc[i].target=0xff;
+               usb_dev_desc[i].if_type=IF_TYPE_USB;
+               usb_dev_desc[i].dev=i;
+               usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+               usb_dev_desc[i].block_read=usb_stor_read;
+       }
+       usb_max_devs=0;
+       for(i=0;i<USB_MAX_DEVICE;i++) {
+               dev=usb_get_dev_index(i); /* get device */
+               USB_STOR_PRINTF("i=%d\n",i);
+               if(dev==NULL) {
+                       break; /* no more devices avaiable */
+               }
+               if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */
+                       /* get info and fill it in */
+
+                       if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) {
+                               if(mode==1) {
+                                       printf ("  Device %d: ", usb_max_devs);
+                                       dev_print(&usb_dev_desc[usb_max_devs]);
+                               } /* if mode */
+                               usb_max_devs++;
+                       } /* if get info ok */
+               } /* if storage device */
+               if(usb_max_devs==USB_MAX_STOR_DEV) {
+                       printf("max USB Storage Device reached: %d stopping\n",usb_max_devs);
+                       break;
+               }
+       } /* for */
+       usb_disable_asynch(0); /* asynch transfer allowed */
+       if(usb_max_devs>0)
+               return 0;
+       else
+               return-1;
+}
+
+static int usb_stor_irq(struct usb_device *dev)
+{
+       struct us_data *us;
+       us=(struct us_data *)dev->privptr;
+
+       if(us->ip_wanted) {
+               us->ip_wanted=0;
+       }
+       return 0;
+}
+
+
+#ifdef USB_STOR_DEBUG
+
+static void usb_show_srb(ccb * pccb)
+{
+       int i;
+       printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen);
+       for(i=0;i<12;i++) {
+               printf("%02X ",pccb->cmd[i]);
+       }
+       printf("\n");
+}
+
+static void display_int_status(unsigned long tmp)
+{
+       printf("Status: %s %s %s %s %s %s %s\n",
+               (tmp & USB_ST_ACTIVE) ? "Active" : "",
+               (tmp & USB_ST_STALLED) ? "Stalled" : "",
+               (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
+               (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
+               (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
+               (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
+               (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
+}
+#endif
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+{
+       int max_size;
+       int this_xfer;
+       int result;
+       int partial;
+       int maxtry;
+       int stat;
+
+       /* determine the maximum packet size for these transfers */
+       max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
+
+       /* while we have data left to transfer */
+       while (length) {
+
+               /* calculate how long this will be -- maximum or a remainder */
+               this_xfer = length > max_size ? max_size : length;
+               length -= this_xfer;
+
+               /* setup the retry counter */
+               maxtry = 10;
+
+               /* set up the transfer loop */
+               do {
+                       /* transfer the data */
+                       USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n",
+                                 (unsigned int)buf, this_xfer, 11 - maxtry);
+                       result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+                                             this_xfer, &partial, USB_CNTL_TIMEOUT*5);
+                       USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n",
+                                 result, partial, this_xfer);
+                       if(us->pusb_dev->status!=0) {
+                               /* if we stall, we need to clear it before we go on */
+#ifdef USB_STOR_DEBUG
+                               display_int_status(us->pusb_dev->status);
+#endif
+                               if (us->pusb_dev->status & USB_ST_STALLED) {
+                                       USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe);
+                                       stat = us->pusb_dev->status;
+                                       usb_clear_halt(us->pusb_dev, pipe);
+                                       us->pusb_dev->status=stat;
+                                       if(this_xfer == partial) {
+                                               USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status);
+                                               return 0;
+                                       }
+                                       else
+                                               return result;
+                               }
+                               if (us->pusb_dev->status & USB_ST_NAK_REC) {
+                                       USB_STOR_PRINTF("Device NAKed bulk_msg\n");
+                                       return result;
+                               }
+                               if(this_xfer == partial) {
+                                       USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status);
+                                       return 0;
+                               }
+                               /* if our try counter reaches 0, bail out */
+                               USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial);
+                               if (!maxtry--)
+                                               return result;
+                       }
+                       /* update to show what data was transferred */
+                       this_xfer -= partial;
+                       buf += partial;
+                       /* continue until this transfer is done */
+               } while ( this_xfer );
+       }
+
+       /* if we get here, we're done and successful */
+       return 0;
+}
+
+/* FIXME: this reset function doesn't really reset the port, and it
+ * should. Actually it should probably do what it's doing here, and
+ * reset the port physically
+ */
+static int usb_stor_CB_reset(struct us_data *us)
+{
+       unsigned char cmd[12];
+       int result;
+
+       USB_STOR_PRINTF("CB_reset\n");
+       memset(cmd, 0xFF, sizeof(cmd));
+       cmd[0] = SCSI_SEND_DIAG;
+       cmd[1] = 4;
+       result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+                                US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                                0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5);
+
+       /* long wait for reset */
+       wait_ms(1500);
+       USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status);
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+       USB_STOR_PRINTF("CB_reset done\n");
+       return 0;
+}
+
+/* FIXME: we also need a CBI_command which sets up the completion
+ * interrupt, and waits for it
+ */
+int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
+{
+       int result;
+       int dir_in,retry;
+       unsigned int pipe;
+       unsigned long status;
+
+       retry=5;
+               dir_in=US_DIRECTION(srb->cmd[0]);
+
+               if(dir_in)
+                       pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+               else
+                       pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+       while(retry--) {
+               USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);
+#ifdef USB_STOR_DEBUG
+               usb_show_srb(srb);
+#endif
+               /* let's send the command via the control pipe */
+               result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+                                        US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                                        0, us->ifnum,
+                                        srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5);
+               USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status);
+               /* check the return code for the command */
+               if (result < 0) {
+                       if(us->pusb_dev->status & USB_ST_STALLED) {
+                               status=us->pusb_dev->status;
+                               USB_STOR_PRINTF(" stall during command found, clear pipe\n");
+                               usb_clear_halt(us->pusb_dev,  usb_sndctrlpipe(us->pusb_dev,0));
+                               us->pusb_dev->status=status;
+                       }
+                       USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status);
+                       return result;
+               }
+               /* transfer the data payload for this command, if one exists*/
+
+               USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen);
+               if (srb->datalen) {
+                       result = us_one_transfer(us, pipe, srb->pdata,srb->datalen);
+                       USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len);
+                       if(!(us->pusb_dev->status & USB_ST_NAK_REC))
+                               break;
+               } /* if (srb->datalen) */
+               else
+                       break;
+       }
+       /* return result */
+
+       return result;
+}
+
+
+int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
+{
+       int timeout;
+
+       us->ip_wanted=1;
+       submit_int_msg(us->pusb_dev,us->irqpipe,
+                       (void *)&us->ip_data,us->irqmaxp ,us->irqinterval);
+  timeout=1000;
+  while(timeout--) {
+       if((volatile int *)us->ip_wanted==0)
+                       break;
+               wait_ms(10);
+       }
+       if (us->ip_wanted) {
+               printf("       Did not get interrupt on CBI\n");
+               us->ip_wanted = 0;
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+       USB_STOR_PRINTF("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data,us->pusb_dev->irq_act_len,us->pusb_dev->irq_status);
+       /* UFI gives us ASC and ASCQ, like a request sense */
+       if (us->subclass == US_SC_UFI) {
+               if (srb->cmd[0] == SCSI_REQ_SENSE ||
+                   srb->cmd[0] == SCSI_INQUIRY)
+                       return USB_STOR_TRANSPORT_GOOD; /* Good */
+               else
+                       if (us->ip_data)
+                               return USB_STOR_TRANSPORT_FAILED;
+                       else
+                               return USB_STOR_TRANSPORT_GOOD;
+       }
+       /* otherwise, we interpret the data normally */
+       switch (us->ip_data) {
+               case 0x0001:
+                       return USB_STOR_TRANSPORT_GOOD;
+               case 0x0002:
+                       return USB_STOR_TRANSPORT_FAILED;
+               default:
+                       return USB_STOR_TRANSPORT_ERROR;
+       } /* switch */
+       return USB_STOR_TRANSPORT_ERROR;
+}
+
+#define USB_TRANSPORT_UNKNOWN_RETRY 5
+#define USB_TRANSPORT_NOT_READY_RETRY 10
+
+int usb_stor_CB_transport(ccb *srb, struct us_data *us)
+{
+       int result,status;
+       ccb *psrb;
+       ccb reqsrb;
+       int retry,notready;
+
+       psrb=&reqsrb;
+       status=USB_STOR_TRANSPORT_GOOD;
+       retry=0;
+       notready=0;
+       /* issue the command */
+do_retry:
+       result=usb_stor_CB_comdat(srb,us);
+       USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status);
+       /* if this is an CBI Protocol, get IRQ */
+       if(us->protocol==US_PR_CBI) {
+               status=usb_stor_CBI_get_status(srb,us);
+               /* if the status is error, report it */
+               if(status==USB_STOR_TRANSPORT_ERROR) {
+                       USB_STOR_PRINTF(" USB CBI Command Error\n");
+                       return status;
+               }
+               srb->sense_buf[12]=(unsigned char)(us->ip_data>>8);
+               srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff);
+               if(!us->ip_data) {
+               /* if the status is good, report it */
+                       if(status==USB_STOR_TRANSPORT_GOOD) {
+                               USB_STOR_PRINTF(" USB CBI Command Good\n");
+                               return status;
+                       }
+               }
+       }
+       /* do we have to issue an auto request? */
+       /* HERE we have to check the result */
+       if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+               USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status);
+               us->transport_reset(us);
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+       if((us->protocol==US_PR_CBI) &&
+                       ((srb->cmd[0]==SCSI_REQ_SENSE) ||
+                       (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */
+               USB_STOR_PRINTF("No auto request and good\n");
+               return USB_STOR_TRANSPORT_GOOD;
+       }
+       /* issue an request_sense */
+       memset(&psrb->cmd[0],0,12);
+       psrb->cmd[0]=SCSI_REQ_SENSE;
+       psrb->cmd[1]=srb->lun<<5;
+       psrb->cmd[4]=18;
+       psrb->datalen=18;
+       psrb->pdata=&srb->sense_buf[0];
+       psrb->cmdlen=12;
+       /* issue the command */
+       result=usb_stor_CB_comdat(psrb,us);
+       USB_STOR_PRINTF("auto request returned %d\n",result);
+       /* if this is an CBI Protocol, get IRQ */
+       if(us->protocol==US_PR_CBI) {
+               status=usb_stor_CBI_get_status(psrb,us);
+       }
+       if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) {
+               USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status);
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+       USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+       /* Check the auto request result */
+       if((srb->sense_buf[2]==0) &&
+                (srb->sense_buf[12]==0) &&
+                (srb->sense_buf[13]==0)) /* ok, no sense */
+               return USB_STOR_TRANSPORT_GOOD;
+       /* Check the auto request result */
+       switch(srb->sense_buf[2]) {
+               case 0x01: /* Recovered Error */
+                       return USB_STOR_TRANSPORT_GOOD;
+                       break;
+               case 0x02: /* Not Ready */
+                       if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
+                               printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n",
+                                       srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+                               return USB_STOR_TRANSPORT_FAILED;
+                       }
+                       else {
+                               wait_ms(100);
+                               goto do_retry;
+                       }
+                       break;
+               default:
+                       if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
+                               printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
+                                       srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+                               return USB_STOR_TRANSPORT_FAILED;
+                       }
+                       else
+                               goto do_retry;
+                       break;
+       }
+       return USB_STOR_TRANSPORT_FAILED;
+}
+
+
+
+static int usb_inquiry(ccb *srb,struct us_data *ss)
+{
+       int retry,i;
+       retry=3;
+       do {
+               memset(&srb->cmd[0],0,12);
+               srb->cmd[0]=SCSI_INQUIRY;
+               srb->cmd[1]=srb->lun<<5;
+               srb->cmd[4]=36;
+               srb->datalen=36;
+               srb->cmdlen=12;
+               i=ss->transport(srb,ss);
+               USB_STOR_PRINTF("inquiry returns %d\n",i);
+               if(i==0)
+                       break;
+       }while(retry--);
+       if(!retry) {
+               printf("error in inquiry\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int usb_request_sense(ccb *srb,struct us_data *ss)
+{
+       char *ptr;
+       return 0;
+       ptr=srb->pdata;
+       memset(&srb->cmd[0],0,12);
+       srb->cmd[0]=SCSI_REQ_SENSE;
+       srb->cmd[1]=srb->lun<<5;
+       srb->cmd[4]=18;
+       srb->datalen=18;
+       srb->pdata=&srb->sense_buf[0];
+       srb->cmdlen=12;
+       ss->transport(srb,ss);
+       USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+       srb->pdata=ptr;
+       return 0;
+}
+
+static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
+{
+       int retries=10;
+       do {
+               memset(&srb->cmd[0],0,12);
+               srb->cmd[0]=SCSI_TST_U_RDY;
+               srb->cmd[1]=srb->lun<<5;
+               srb->datalen=0;
+               srb->cmdlen=12;
+               if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD)
+               {
+                       return 0;
+               }
+       } while(retries--);
+       return -1;
+}
+
+static int usb_read_capacity(ccb *srb,struct us_data *ss)
+{
+       int retry;
+       retry=2; /* retries */
+       do {
+               memset(&srb->cmd[0],0,12);
+               srb->cmd[0]=SCSI_RD_CAPAC;
+               srb->cmd[1]=srb->lun<<5;
+               srb->datalen=8;
+               srb->cmdlen=12;
+               if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {
+                       return 0;
+               }
+       }while(retry--);
+       return -1;
+}
+
+static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigned short blocks)
+{
+       memset(&srb->cmd[0],0,12);
+       srb->cmd[0]=SCSI_READ10;
+       srb->cmd[1]=srb->lun<<5;
+       srb->cmd[2]=((unsigned char) (start>>24))&0xff;
+       srb->cmd[3]=((unsigned char) (start>>16))&0xff;
+       srb->cmd[4]=((unsigned char) (start>>8))&0xff;
+       srb->cmd[5]=((unsigned char) (start))&0xff;
+       srb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
+       srb->cmd[8]=(unsigned char) blocks & 0xff;
+       srb->cmdlen=12;
+       USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks);
+       return ss->transport(srb,ss);
+}
+
+
+#define USB_MAX_READ_BLK 20
+
+unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer)
+{
+       unsigned long start,blks, buf_addr;
+       unsigned short smallblks;
+       struct usb_device *dev;
+       int retry,i;
+       ccb *srb=&usb_ccb;
+       device&=0xff;
+       /* Setup  device
+        */
+       USB_STOR_PRINTF("\nusb_read: dev %d \n",device);
+       dev=NULL;
+       for(i=0;i<USB_MAX_DEVICE;i++) {
+               dev=usb_get_dev_index(i);
+               if(dev==NULL) {
+                       return 0;
+               }
+               if(dev->devnum==usb_dev_desc[device].target)
+                       break;
+       }
+
+       usb_disable_asynch(1); /* asynch transfer not allowed */
+       srb->lun=usb_dev_desc[device].lun;
+       buf_addr=(unsigned long)buffer;
+       start=blknr;
+       blks=blkcnt;
+       if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) {
+               printf("Device NOT ready\n   Request Sense returned %02X %02X %02X\n",
+                       srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+               return 0;
+       }
+       USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr);
+       do {
+               retry=2;
+               srb->pdata=(unsigned char *)buf_addr;
+               if(blks>USB_MAX_READ_BLK) {
+                       smallblks=USB_MAX_READ_BLK;
+               }
+               else {
+                       smallblks=(unsigned short) blks;
+               }
+retry_it:
+               if(smallblks==USB_MAX_READ_BLK)
+                       usb_show_progress();
+               srb->datalen=usb_dev_desc[device].blksz * smallblks;
+               srb->pdata=(unsigned char *)buf_addr;
+               if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) {
+                       USB_STOR_PRINTF("Read ERROR\n");
+                       usb_request_sense(srb,(struct us_data *)dev->privptr);
+                       if(retry--)
+                               goto retry_it;
+                       blkcnt-=blks;
+                       break;
+               }
+               start+=smallblks;
+               blks-=smallblks;
+               buf_addr+=srb->datalen;
+       } while(blks!=0);
+       USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+       usb_disable_asynch(0); /* asynch transfer allowed */
+       if(blkcnt>=USB_MAX_READ_BLK)
+               printf("\n");
+       return(blkcnt);
+}
+
+
+/* Probe to see if a new device is actually a Storage device */
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss)
+{
+       struct usb_interface_descriptor *iface;
+       int i;
+       unsigned int flags = 0;
+
+       int protocol = 0;
+       int subclass = 0;
+
+
+       memset(ss, 0, sizeof(struct us_data));
+
+       /* let's examine the device now */
+       iface = &dev->config.if_desc[ifnum];
+
+#if 0
+       /* this is the place to patch some storage devices */
+       USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct);
+       if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) {
+               USB_STOR_PRINTF("patched for E-USB\n");
+               protocol = US_PR_CB;
+               subclass = US_SC_UFI;       /* an assumption */
+       }
+#endif
+
+       if (dev->descriptor.bDeviceClass != 0 ||
+                       iface->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+                       iface->bInterfaceSubClass < US_SC_MIN ||
+                       iface->bInterfaceSubClass > US_SC_MAX) {
+               /* if it's not a mass storage, we go no further */
+               return 0;
+       }
+
+       /* At this point, we know we've got a live one */
+       USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n");
+
+       /* Initialize the us_data structure with some useful info */
+       ss->flags = flags;
+       ss->ifnum = ifnum;
+       ss->pusb_dev = dev;
+       ss->attention_done = 0;
+
+       /* If the device has subclass and protocol, then use that.  Otherwise,
+        * take data from the specific interface.
+        */
+       if (subclass) {
+               ss->subclass = subclass;
+               ss->protocol = protocol;
+       } else {
+               ss->subclass = iface->bInterfaceSubClass;
+               ss->protocol = iface->bInterfaceProtocol;
+       }
+
+       /* set the handler pointers based on the protocol */
+       USB_STOR_PRINTF("Transport: ");
+       switch (ss->protocol) {
+       case US_PR_CB:
+               USB_STOR_PRINTF("Control/Bulk\n");
+               ss->transport = usb_stor_CB_transport;
+               ss->transport_reset = usb_stor_CB_reset;
+               break;
+
+       case US_PR_CBI:
+               USB_STOR_PRINTF("Control/Bulk/Interrupt\n");
+               ss->transport = usb_stor_CB_transport;
+               ss->transport_reset = usb_stor_CB_reset;
+               break;
+       default:
+               printf("USB Starage Transport unknown / not yet implemented\n");
+               return 0;
+               break;
+       }
+
+       /*
+        * We are expecting a minimum of 2 endpoints - in and out (bulk).
+        * An optional interrupt is OK (necessary for CBI protocol).
+        * We will ignore any others.
+        */
+       for (i = 0; i < iface->bNumEndpoints; i++) {
+               /* is it an BULK endpoint? */
+               if ((iface->ep_desc[i].bmAttributes &  USB_ENDPOINT_XFERTYPE_MASK)
+                   == USB_ENDPOINT_XFER_BULK) {
+                       if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+                               ss->ep_in = iface->ep_desc[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                       else
+                               ss->ep_out = iface->ep_desc[i].bEndpointAddress &
+                                       USB_ENDPOINT_NUMBER_MASK;
+               }
+
+               /* is it an interrupt endpoint? */
+               if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                   == USB_ENDPOINT_XFER_INT) {
+                       ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+                               USB_ENDPOINT_NUMBER_MASK;
+                       ss->irqinterval = iface->ep_desc[i].bInterval;
+               }
+       }
+       USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",
+                 ss->ep_in, ss->ep_out, ss->ep_int);
+
+       /* Do some basic sanity checks, and bail if we find a problem */
+       if (usb_set_interface(dev, iface->bInterfaceNumber, 0) ||
+           !ss->ep_in || !ss->ep_out ||
+           (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+               USB_STOR_PRINTF("Problems with device\n");
+               return 0;
+       }
+       /* set class specific stuff */
+       /* We only handle certain protocols.  Currently, this is
+        * the only one.
+        */
+       if (ss->subclass != US_SC_UFI) {
+               printf("Sorry, protocol %d not yet supported.\n",ss->subclass);
+               return 0;
+       }
+       if(ss->ep_int) /* we had found an interrupt endpoint, prepare irq pipe */
+       {
+               /* set up the IRQ pipe and handler */
+
+               ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
+               ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+               ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
+               dev->irq_handle=usb_stor_irq;
+               dev->privptr=(void *)ss;
+       }
+       return 1;
+}
+
+int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc)
+{
+       unsigned char perq,modi;
+       unsigned long cap[2];
+       unsigned long *capacity,*blksz;
+       ccb *pccb=&usb_ccb;
+
+       ss->transport_reset(ss);
+       pccb->pdata=usb_stor_buf;
+
+       dev_desc->target=dev->devnum;
+       pccb->lun=dev_desc->lun;
+       USB_STOR_PRINTF(" address %d\n",dev_desc->target);
+
+       if(usb_inquiry(pccb,ss))
+               return -1;
+       perq=usb_stor_buf[0];
+       modi=usb_stor_buf[1];
+       if((perq & 0x1f)==0x1f) {
+               return 0; /* skip unknown devices */
+       }
+       if((modi&0x80)==0x80) {/* drive is removable */
+               dev_desc->removable=1;
+       }
+       memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
+       memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
+       memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
+       dev_desc->vendor[8]=0;
+       dev_desc->product[16]=0;
+       dev_desc->revision[4]=0;
+       USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]);
+       if(usb_test_unit_ready(pccb,ss)) {
+               printf("Device NOT ready\n   Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]);
+               if(dev_desc->removable==1) {
+                       dev_desc->type=perq;
+                       return 1;
+               }
+               else
+                       return 0;
+       }
+       pccb->pdata=(unsigned char *)&cap[0];
+       memset(pccb->pdata,0,8);
+       if(usb_read_capacity(pccb,ss)!=0) {
+               printf("READ_CAP ERROR\n");
+               cap[0]=2880;
+               cap[1]=0x200;
+       }
+       USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
+#if 0
+       if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */
+               cap[0]>>=16;
+#endif
+       cap[0]+=1;
+       capacity=&cap[0];
+       blksz=&cap[1];
+       USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
+       dev_desc->lba=*capacity;
+       dev_desc->blksz=*blksz;
+       dev_desc->type=perq;
+       USB_STOR_PRINTF(" address %d\n",dev_desc->target);
+       USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+
+       init_part(dev_desc);
+
+       USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+       return 1;
+}
+
+#endif
+#endif /* CONFIG_USB_STORAGE */
+
+
+
diff --git a/cpu/74xx_7xx/traps.c b/cpu/74xx_7xx/traps.c
new file mode 100644 (file)
index 0000000..26db097
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM     0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void
+show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+              " %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP:"
+              " %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                       "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+               "       eieio\n"                \
+               "       li %0,0\n"              \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:     li %0,-1\n"             \
+               "       b 2b\n"                 \
+               ".section __ex_table,\"a\"\n"   \
+               "       .align 2\n"             \
+               "       .long 1b,3b\n"          \
+               ".text"                         \
+               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/cpu/mpc824x/drivers/epic/epic1.c b/cpu/mpc824x/drivers/epic/epic1.c
new file mode 100644 (file)
index 0000000..362e129
--- /dev/null
@@ -0,0 +1,513 @@
+/**************************************************
+ *
+ * copyright @ motorola, 1999
+ *
+ *************************************************/
+#include <mpc824x.h>
+#include <common.h>
+#include "epic.h"
+
+
+#define PRINT(format, args...) printf(format , ## args)
+
+typedef void (*VOIDFUNCPTR)  (void);  /* ptr to function returning void */
+struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
+    {
+    { EPIC_EX_INT0_VEC_REG,  "External Direct/Serial Source 0"},
+    { EPIC_EX_INT1_VEC_REG,  "External Direct/Serial Source 1"},
+    { EPIC_EX_INT2_VEC_REG,  "External Direct/Serial Source 2"},
+    { EPIC_EX_INT3_VEC_REG,  "External Direct/Serial Source 3"},
+    { EPIC_EX_INT4_VEC_REG,  "External Direct/Serial Source 4"},
+
+    { EPIC_SR_INT5_VEC_REG,  "External Serial Source 5"},
+    { EPIC_SR_INT6_VEC_REG,  "External Serial Source 6"},
+    { EPIC_SR_INT7_VEC_REG,  "External Serial Source 7"},
+    { EPIC_SR_INT8_VEC_REG,  "External Serial Source 8"},
+    { EPIC_SR_INT9_VEC_REG,  "External Serial Source 9"},
+    { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
+    { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
+    { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
+    { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
+    { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
+    { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
+
+    { EPIC_I2C_INT_VEC_REG,  "Internal I2C Source"},
+    { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
+    { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
+    { EPIC_MSG_INT_VEC_REG,  "Internal Message Source"},
+    };
+
+VOIDFUNCPTR intVecTbl[MAXVEC];    /* Interrupt vector table */
+
+
+/****************************************************************************
+*  epicInit - Initialize the EPIC registers
+*
+*  This routine resets the Global Configuration Register, thus it:
+*     -  Disables all interrupts
+*     -  Sets epic registers to reset values
+*     -  Sets the value of the Processor Current Task Priority to the
+*        highest priority (0xF).
+*  epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
+*  Through or 8259 compatible mode).
+*
+*  If IRQType (input) is Direct IRQs:
+*     - IRQType is written to the SIE bit of the EPIC Interrupt
+*       Configuration register (ICR).
+*     - clkRatio is ignored.
+*  If IRQType is Serial IRQs:
+*     - both IRQType and clkRatio will be written to the ICR register
+*/
+
+void epicInit
+    (
+    unsigned int IRQType,      /* Direct or Serial */
+    unsigned int clkRatio      /* Clk Ratio for Serial IRQs */
+    )
+    {
+    ULONG tmp;
+
+    tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
+    tmp |= 0xa0000000;                  /* Set the Global Conf. register */
+    sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
+    sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
+    tmp = sysEUMBBARRead(EPIC_INT_CONF_REG);    /* Read interrupt conf. reg */
+
+    if (IRQType == EPIC_DIRECT_IRQ)             /* direct mode */
+        sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
+    else                                        /* Serial mode */
+        {
+        tmp = (clkRatio << 28) | 0x08000000;    /* Set clock ratio */
+        sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
+        }
+
+    while (epicIntAck() != 0xff);       /* Clear all pending interrupts */
+}
+
+/****************************************************************************
+ *  epicIntEnable - Enable an interrupt source
+ *
+ *  This routine clears the mask bit of an external, an internal or
+ *  a Timer register to enable the interrupt.
+ *
+ *  RETURNS:  None
+ */
+void epicIntEnable
+    (
+    int intVec        /* Interrupt Vector Number */
+    )
+    {
+    ULONG tmp;
+    ULONG srAddr;
+
+    srAddr = SrcVecTable[intVec].srcAddr;  /* Retrieve src Vec/Prio register */
+    tmp = sysEUMBBARRead(srAddr);
+    tmp &= 0x7fffffff;             /* Clear the mask bit */
+    sysEUMBBARWrite(srAddr, tmp);
+    return;
+    }
+
+/****************************************************************************
+ *  epicIntDisable - Disable an interrupt source
+ *
+ *  This routine sets the mask bit of an external, an internal or
+ *  a Timer register to disable the interrupt.
+ *
+ *  RETURNS:  OK or ERROR
+ *
+ */
+
+void epicIntDisable
+    (
+    int intVec        /* Interrupt vector number */
+    )
+    {
+
+    ULONG tmp, srAddr;
+
+    srAddr = SrcVecTable[intVec].srcAddr;
+    tmp = sysEUMBBARRead(srAddr);
+    tmp |= 0x80000000;                      /* Set the mask bit */
+    sysEUMBBARWrite(srAddr, tmp);
+    return;
+    }
+
+/****************************************************************************
+ * epicIntSourceConfig - Set properties of an interrupt source
+ *
+ * This function sets interrupt properites (Polarity, Sense, Interrupt
+ * Prority, and Interrupt Vector) of an Interrupt Source.  The properties
+ * can be set when the current source is not in-request or in-service,
+ * which is determined by the Activity bit.  This routine return ERROR
+ * if the the Activity bit is 1 (in-request or in-service).
+ *
+ * This function assumes that the Source Vector/Priority register (input)
+ * is a valid address.
+ *
+ * RETURNS:  OK or ERROR
+ */
+
+int epicIntSourceConfig
+    (
+    int   Vect,                         /* interrupt source vector number */
+    int   Polarity,                     /* interrupt source polarity */
+    int   Sense,                        /* interrupt source Sense */
+    int   Prio                          /* interrupt source priority */
+    )
+
+    {
+    ULONG tmp, newVal;
+    ULONG actBit, srAddr;
+
+    srAddr = SrcVecTable[Vect].srcAddr;
+    tmp = sysEUMBBARRead(srAddr);
+    actBit = (tmp & 40000000) >> 30;    /* retrieve activity bit - bit 30 */
+    if (actBit == 1)
+        return ERROR;
+
+    tmp &= 0xff30ff00;     /* Erase previously set P,S,Prio,Vector bits */
+    newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
+    sysEUMBBARWrite(srAddr, tmp | newVal );
+    return (OK);
+    }
+
+/****************************************************************************
+ * epicIntAck - acknowledge an interrupt
+ *
+ * This function reads the Interrupt acknowldge register and return
+ * the vector number of the highest pending interrupt.
+ *
+ * RETURNS: Interrupt Vector number.
+ */
+
+unsigned int epicIntAck(void)
+{
+    return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
+}
+
+/****************************************************************************
+ * epicEOI - signal an end of interrupt
+ *
+ * This function writes 0x0 to the EOI register to signal end of interrupt.
+ * It is usually called after an interrupt routine is served.
+ *
+ * RETURNS: None
+ */
+
+void epicEOI(void)
+    {
+    sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
+    }
+
+/****************************************************************************
+ *  epicCurTaskPrioSet - sets the priority of the Processor Current Task
+ *
+ *  This function should be called after epicInit() to lower the priority
+ *  of the processor current task.
+ *
+ *  RETURNS:  OK or ERROR
+ */
+
+int epicCurTaskPrioSet
+    (
+    int prioNum                 /* New priority value */
+    )
+    {
+
+    if ( (prioNum < 0) || (prioNum > 0xF))
+        return ERROR;
+    sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
+    return OK;
+    }
+
+
+/************************************************************************
+ * function: epicIntTaskGet
+ *
+ * description: Get value of processor current interrupt task priority register
+ *
+ * note:
+ ***********************************************************************/
+unsigned char epicIntTaskGet()
+{
+  /* get the interrupt task priority register */
+    ULONG reg;
+    unsigned char rec;
+
+    reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
+    rec = ( reg & 0x0F );
+    return rec;
+}
+
+
+/**************************************************************
+ * function: epicISR
+ *
+ * description: EPIC service routine called by the core exception
+ *              at 0x500
+ *
+ * note:
+ **************************************************************/
+unsigned int epicISR(void)
+{
+   return 0;
+}
+
+
+/************************************************************
+ * function: epicModeGet
+ *
+ * description: query EPIC mode, return 0 if pass through mode
+ *                               return 1 if mixed mode
+ *
+ * note:
+ *************************************************************/
+unsigned int epicModeGet(void)
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_GLOBAL_REG );
+    return (( val & 0x20000000 ) >> 29);
+}
+
+
+/*********************************************
+ * function: epicConfigGet
+ *
+ * description: Get the EPIC interrupt Configuration
+ *              return 0 if not error, otherwise return 1
+ *
+ * note:
+ ********************************************/
+void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_INT_CONF_REG );
+    *clkRatio = ( val & 0x70000000 ) >> 28;
+    *serEnable = ( val & 0x8000000 ) >> 27;
+}
+
+
+/*******************************************************************
+ *  sysEUMBBARRead - Read a 32-bit EUMBBAR register
+ *
+ *  This routine reads the content of a register in the Embedded
+ *  Utilities Memory Block, and swaps to big endian before returning
+ *  the value.
+ *
+ *  RETURNS:  The content of the specified EUMBBAR register.
+ */
+
+ULONG sysEUMBBARRead
+    (
+    ULONG regNum
+    )
+    {
+    ULONG temp;
+
+    temp = *(ULONG *) (CFG_EUMB_ADDR + regNum);
+    return ( LONGSWAP(temp));
+    }
+
+/*******************************************************************
+ *  sysEUMBBARWrite - Write a 32-bit EUMBBAR register
+ *
+ *  This routine swaps the value to little endian then writes it to
+ *  a register in the Embedded Utilities Memory Block address space.
+ *
+ *  RETURNS: N/A
+ */
+
+void sysEUMBBARWrite
+    (
+    ULONG regNum,               /* EUMBBAR register address */
+    ULONG regVal                /* Value to be written */
+    )
+    {
+
+    *(ULONG *) (CFG_EUMB_ADDR + regNum) = LONGSWAP(regVal);
+    return ;
+    }
+
+
+/********************************************************
+ * function: epicVendorId
+ *
+ * description: return the EPIC Vendor Identification
+ *              register:
+ *
+ *              siliccon version, device id, and vendor id
+ *
+ * note:
+ ********************************************************/
+void epicVendorId
+   (
+    unsigned int *step,
+    unsigned int *devId,
+    unsigned int *venId
+   )
+   {
+    ULONG val;
+    val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
+    *step  = ( val & 0x00FF0000 ) >> 16;
+    *devId = ( val & 0x0000FF00 ) >> 8;
+    *venId = ( val & 0x000000FF );
+    }
+
+/**************************************************
+ * function: epicFeatures
+ *
+ * description: return the number of IRQ supported,
+ *              number of CPU, and the version of the
+ *              OpenEPIC
+ *
+ * note:
+ *************************************************/
+void epicFeatures
+    (
+    unsigned int *noIRQs,
+    unsigned int *noCPUs,
+    unsigned int *verId
+    )
+    {
+    ULONG val;
+
+    val = sysEUMBBARRead( EPIC_FEATURES_REG );
+    *noIRQs  = ( val & 0x07FF0000 ) >> 16;
+    *noCPUs  = ( val & 0x00001F00 ) >> 8;
+    *verId   = ( val & 0x000000FF );
+}
+
+
+/*********************************************************
+ * function: epciTmFrequncySet
+ *
+ * description: Set the timer frequency reporting register
+ ********************************************************/
+void epicTmFrequencySet( unsigned int frq )
+{
+    sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
+}
+
+/*******************************************************
+ * function: epicTmFrequncyGet
+ *
+ * description: Get the current value of the Timer Frequency
+ * Reporting register
+ *
+ ******************************************************/
+unsigned int epicTmFrequencyGet(void)
+{
+    return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
+}
+
+
+/****************************************************
+ * function: epicTmBaseSet
+ *
+ * description: Set the #n global timer base count register
+ *              return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ****************************************************/
+unsigned int epicTmBaseSet
+    (
+    ULONG srcAddr,         /* Address of the Timer Base register */
+    unsigned int cnt,    /* Base count */
+    unsigned int inhibit   /* 1 - count inhibit */
+    )
+{
+
+    unsigned int val = 0x80000000;
+    /* First inhibit counting the timer */
+    sysEUMBBARWrite(srcAddr, val) ;
+
+    /* set the new value */
+    val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
+    sysEUMBBARWrite(srcAddr, val) ;
+    return 0;
+}
+
+/***********************************************************************
+ * function: epicTmBaseGet
+ *
+ * description: Get the current value of the global timer base count register
+ *              return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ***********************************************************************/
+unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
+{
+    *val = sysEUMBBARRead( srcAddr );
+    *val = *val & 0x7fffffff;
+    return 0;
+}
+
+/***********************************************************
+ * function: epicTmCountGet
+ *
+ * description: Get the value of a given global timer
+ *              current count register
+ *              return 0 if no error, otherwise return 1
+ * note:
+ **********************************************************/
+unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
+{
+    *val = sysEUMBBARRead( srcAddr );
+    *val = *val & 0x7fffffff;
+    return 0;
+}
+
+
+
+/***********************************************************
+ * function: epicTmInhibit
+ *
+ * description: Stop counting of a given global timer
+ *              return 0 if no error, otherwise return 1
+ *
+ * note:
+ ***********************************************************/
+unsigned int epicTmInhibit( unsigned int srcAddr )
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( srcAddr );
+    val |= 0x80000000;
+    sysEUMBBARWrite( srcAddr, val );
+    return 0;
+}
+
+/******************************************************************
+ * function: epicTmEnable
+ *
+ * description: Enable counting of a given global timer
+ *              return 0 if no error, otherwise return 1
+ *
+ * note:
+ *****************************************************************/
+unsigned int epicTmEnable( ULONG srcAddr )
+{
+    ULONG val;
+
+    val = sysEUMBBARRead( srcAddr );
+    val &= 0x7fffffff;
+    sysEUMBBARWrite( srcAddr, val );
+    return 0;
+}
+
+void epicSourcePrint(int Vect)
+    {
+    ULONG srcVal;
+
+    srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
+    PRINT("%s\n", SrcVecTable[Vect].srcName);
+    PRINT("Address   = 0x%lx\n", SrcVecTable[Vect].srcAddr);
+    PRINT("Vector    = %ld\n", (srcVal & 0x000000FF) );
+    PRINT("Mask      = %ld\n", srcVal >> 31);
+    PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
+    PRINT("Polarity  = %ld\n", (srcVal & 0x00800000) >> 23);
+    PRINT("Sense     = %ld\n", (srcVal & 0x00400000) >> 22);
+    PRINT("Priority  = %ld\n", (srcVal & 0x000F0000) >> 16);
+    }
diff --git a/cpu/mpc824x/traps.c b/cpu/mpc824x/traps.c
new file mode 100644 (file)
index 0000000..11f51c2
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM     0x00400000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                       "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+               "       eieio\n"                \
+               "       li %0,0\n"              \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:     li %0,-1\n"             \
+               "       b 2b\n"                 \
+               ".section __ex_table,\"a\"\n"   \
+               "       .align 2\n"             \
+               "       .long 1b,3b\n"          \
+               ".text"                         \
+               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/cpu/mpc8260/ether_fcc.c b/cpu/mpc8260/ether_fcc.c
new file mode 100644 (file)
index 0000000..01ddf5c
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * MPC8260 FCC Fast Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@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
+ */
+
+/*
+ * MPC8260 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ *    config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <net.h>
+#include <command.h>
+#include <config.h>
+
+#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET)
+
+/*---------------------------------------------------------------------*/
+#if (CONFIG_ETHER_INDEX == 1)
+
+#define PROFF_ENET             PROFF_FCC1
+#define CPM_CR_ENET_SBLOCK     CPM_CR_FCC1_SBLOCK
+#define CPM_CR_ENET_SBLOCK     CPM_CR_FCC1_SBLOCK
+#define CPM_CR_ENET_PAGE       CPM_CR_FCC1_PAGE
+
+/*---------------------------------------------------------------------*/
+#elif (CONFIG_ETHER_INDEX == 2)
+
+#define PROFF_ENET             PROFF_FCC2
+#define CPM_CR_ENET_SBLOCK     CPM_CR_FCC2_SBLOCK
+#define CPM_CR_ENET_PAGE       CPM_CR_FCC2_PAGE
+
+/*---------------------------------------------------------------------*/
+#elif (CONFIG_ETHER_INDEX == 3)
+
+#define PROFF_ENET             PROFF_FCC3
+#define CPM_CR_ENET_SBLOCK     CPM_CR_FCC3_SBLOCK
+#define CPM_CR_ENET_PAGE       CPM_CR_FCC3_PAGE
+
+/*---------------------------------------------------------------------*/
+#else
+#error "FCC Ethernet not correctly defined"
+#endif
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size.  Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE         1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE         1518
+#define PKT_MINBUF_SIZE         64
+
+/* Maximum input buffer size.  Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE         1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+#ifdef __GNUC__
+static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
+#else
+#error "txbuf must be 64-bit aligned"
+#endif
+
+static uint rxIdx;     /* index of the current RX buffer */
+static uint txIdx;     /* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+    cbd_t rxbd[PKTBUFSRX];
+    cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/*  Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+int eth_send(volatile void *packet, int length)
+{
+    int i;
+    int result = 0;
+
+    if (length <= 0) {
+       printf("fec: bad packet size: %d\n", length);
+       goto out;
+    }
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+       if (i >= TOUT_LOOP) {
+           printf("fec: tx buffer not ready\n");
+           goto out;
+       }
+    }
+
+    rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
+    rtx.txbd[txIdx].cbd_datlen = length;
+    rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
+                              BD_ENET_TX_WRAP);
+
+    for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+       if (i >= TOUT_LOOP) {
+           printf("fec: tx error\n");
+           goto out;
+       }
+    }
+
+#ifdef ET_DEBUG
+    printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
+#endif
+
+    /* return only status bits */
+    result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+out:
+    return result;
+}
+
+int eth_rx(void)
+{
+    int length;
+
+    for (;;)
+    {
+       if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+           length = -1;
+           break;     /* nothing received - leave for() loop */
+       }
+       length = rtx.rxbd[rxIdx].cbd_datlen;
+
+       if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
+           printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+       }
+       else {
+           /* Pass the packet up to the protocol layers. */
+           NetReceive(NetRxPackets[rxIdx], length - 4);
+       }
+
+
+       /* Give the buffer back to the FCC. */
+       rtx.rxbd[rxIdx].cbd_datlen = 0;
+
+       /* wrap around buffer index when necessary */
+       if ((rxIdx + 1) >= PKTBUFSRX) {
+           rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+           rxIdx = 0;
+       }
+       else {
+           rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+           rxIdx++;
+       }
+    }
+    return length;
+}
+
+
+int eth_init(bd_t *bis)
+{
+    int i;
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+    volatile cpm8260_t *cp = &(immr->im_cpm);
+    fcc_enet_t *pram_ptr;
+    unsigned long mem_addr;
+
+#if 0
+    mii_discover_phy();
+#endif
+
+    /* 28.9 - (1-2): ioports have been set up already */
+
+    /* 28.9 - (3): connect FCC's tx and rx clocks */
+    immr->im_cpmux.cmx_uar = 0;
+    immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~CFG_CMXFCR_MASK) |
+                                                       CFG_CMXFCR_VALUE;
+
+    /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr =
+      FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+    /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC;
+
+    /* 28.9 - (6): FDSR: Ethernet Syn */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fdsr = 0xD555;
+
+    /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+    rxIdx = 0;
+    txIdx = 0;
+
+    /* Setup Receiver Buffer Descriptors */
+    for (i = 0; i < PKTBUFSRX; i++)
+    {
+      rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+      rtx.rxbd[i].cbd_datlen = 0;
+      rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+    }
+    rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+    /* Setup Ethernet Transmitter Buffer Descriptors */
+    for (i = 0; i < TX_BUF_CNT; i++)
+    {
+      rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+      rtx.txbd[i].cbd_datlen = 0;
+      rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+    }
+    rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+    /* 28.9 - (7): initialise parameter ram */
+    pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
+
+    /* clear whole structure to make sure all reserved fields are zero */
+    memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+    /*
+     * common Parameter RAM area
+     *
+     * Allocate space in the reserved FCC area of DPRAM for the
+     * internal buffers.  No one uses this space (yet), so we
+     * can do this.  Later, we will add resource management for
+     * this area.
+     */
+    mem_addr = CPM_FCC_SPECIAL_BASE + ((CONFIG_ETHER_INDEX-1) * 64);
+    pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+    pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+    /*
+     * Set maximum bytes per receive buffer.
+     * It must be a multiple of 32.
+     */
+    pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+    pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+                                      CFG_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+    pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+                                      CFG_CPMFCR_RAMTYPE) << 24;
+    pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+
+    /* protocol-specific area */
+    pram_ptr->fen_cmask = 0xdebb20e3;  /* CRC mask */
+    pram_ptr->fen_cpres = 0xffffffff;  /* CRC preset */
+    pram_ptr->fen_retlim = 15;         /* Retry limit threshold */
+    pram_ptr->fen_mflr = PKT_MAXBUF_SIZE;   /* maximum frame length register */
+    /*
+     * Set Ethernet station address.
+     *
+     * This is supplied in the board information structure, so we
+     * copy that into the controller.
+     * So, far we have only been given one Ethernet address. We make
+     * it unique by setting a few bits in the upper byte of the
+     * non-static part of the address.
+     */
+#define ea bis->bi_enetaddr
+    pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+    pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+    pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+    pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+    /* pad pointer. use tiptr since we don't need a specific padding char */
+    pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+    pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE;     /* maximum DMA1 length */
+    pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE;     /* maximum DMA2 length */
+    pram_ptr->fen_rfthr = 1;
+    pram_ptr->fen_rfcnt = 1;
+#if 0
+    printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
+       pram_ptr->fen_genfcc.fcc_rbase);
+    printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
+       pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+    /* 28.9 - (8): clear out events in FCCE */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fcce = ~0x0;
+
+    /* 28.9 - (9): FCCM: mask all events */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fccm = 0;
+
+    /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+    /* 28.9 - (13)
+     *
+     * Let's re-initialize the channel now.  We have to do it later
+     * than the manual describes because we have just now finished
+     * the BD initialization.
+     */
+    cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
+                           CPM_CR_ENET_SBLOCK,
+                           0x0c,
+                           CPM_CR_INIT_TRX) | CPM_CR_FLG;
+    do {
+       __asm__ __volatile__ ("eieio");
+    } while (cp->cp_cpcr & CPM_CR_FLG);
+
+    /* 28.9 - (14): enable tx/rx in gfmr */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+    return 1;
+}
+
+void eth_halt(void)
+{
+    volatile immap_t *immr = (immap_t *)CFG_IMMR;
+
+    /* write GFMR: disable tx/rx */
+    immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr &=
+                                               ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+}
+
+#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET */
diff --git a/cpu/mpc8260/traps.c b/cpu/mpc8260/traps.c
new file mode 100644 (file)
index 0000000..a7f6f7e
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM     0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                       "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+               "       eieio\n"                \
+               "       li %0,0\n"              \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:     li %0,-1\n"             \
+               "       b 2b\n"                 \
+               ".section __ex_table,\"a\"\n"   \
+               "       .align 2\n"             \
+               "       .long 1b,3b\n"          \
+               ".text"                         \
+               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/cpu/mpc8xx/traps.c b/cpu/mpc8xx/traps.c
new file mode 100644 (file)
index 0000000..c432be6
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM     0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                       "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+  printf("Debugger trap at @ %lx\n", regs->nip );
+  show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+  do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+               "       eieio\n"                \
+               "       li %0,0\n"              \
+               "2:\n"                          \
+               ".section .fixup,\"ax\"\n"      \
+               "3:     li %0,-1\n"             \
+               "       b 2b\n"                 \
+               ".section __ex_table,\"a\"\n"   \
+               "       .align 2\n"             \
+               "       .long 1b,3b\n"          \
+               ".text"                         \
+               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/cpu/mpc8xx/upatch.c b/cpu/mpc8xx/upatch.c
new file mode 100644 (file)
index 0000000..99bdf53
--- /dev/null
@@ -0,0 +1,102 @@
+#include <common.h>
+#include <commproc.h>
+
+#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH)
+
+static void UcodeCopy (volatile cpm8xx_t *cpm);
+
+void cpm_load_patch (volatile immap_t *immr)
+{
+       immr->im_cpm.cp_rccr &= ~0x0003;        /* Disable microcode program area */
+
+       UcodeCopy ((cpm8xx_t *)&immr->im_cpm);  /* Copy ucode patch to DPRAM   */
+#ifdef CFG_SPI_UCODE_PATCH
+    {
+       volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
+       /* Activate the microcode per the instructions in the microcode manual */
+       /* NOTE:  We're only relocating the SPI parameters (not I2C).          */
+       immr->im_cpm.cp_cpmcr1 = 0x802a;        /* Write Trap register 1 value */
+       immr->im_cpm.cp_cpmcr2 = 0x8028;        /* Write Trap register 2 value */
+       spi->spi_rpbase = CFG_SPI_DPMEM_OFFSET; /* Where to relocte SPI params */
+    }
+#endif
+
+#ifdef CFG_I2C_UCODE_PATCH
+    {
+       volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
+       /* Activate the microcode per the instructions in the microcode manual */
+       /* NOTE:  We're only relocating the I2C parameters (not SPI).          */
+       immr->im_cpm.cp_cpmcr3 = 0x802e;        /* Write Trap register 3 value */
+       immr->im_cpm.cp_cpmcr4 = 0x802c;        /* Write Trap register 4 value */
+       iip->iic_rpbase = CFG_I2C_DPMEM_OFFSET; /* Where to relocte I2C params */
+    }
+#endif
+
+       /*
+         * Enable DPRAM microcode to execute from the first 512 bytes
+         * and a 256 byte extension of DPRAM.
+        */
+       immr->im_cpm.cp_rccr |= 0x0001;
+}
+
+static ulong patch_2000[] = {
+       0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
+       0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
+       0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
+       0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
+       0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
+       0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
+       0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
+       0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
+       0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
+       0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
+       0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
+       0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
+       0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
+       0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
+       0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
+       0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
+       0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
+       0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
+       0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
+       0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
+       0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
+       0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
+       0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
+       0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
+       0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
+       0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
+       0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
+       0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
+       0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
+       0x7FBDB081, 0x5F8147F8,
+};
+
+static ulong patch_2F00[] = {
+       0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
+       0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
+       0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
+       0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
+       0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
+       0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
+       0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
+       0x19797937, 0x69350000,
+};
+
+static void UcodeCopy (volatile cpm8xx_t *cpm)
+{
+       vu_long *p;
+       int i;
+
+       p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
+       for (i=0; i < sizeof(patch_2000)/4; ++i) {
+               p[i] = patch_2000[i];
+       }
+
+       p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
+       for (i=0; i < sizeof(patch_2F00)/4; ++i) {
+               p[i] = patch_2F00[i];
+       }
+}
+
+#endif /* CFG_I2C_UCODE_PATCH, CFG_SPI_UCODE_PATCH */
diff --git a/cpu/ppc4xx/miiphy.c b/cpu/ppc4xx/miiphy.c
new file mode 100644 (file)
index 0000000..51ba471
--- /dev/null
@@ -0,0 +1,182 @@
+/*-----------------------------------------------------------------------------+
+  |
+  |       This source code has been made available to you by IBM on an AS-IS
+  |       basis.  Anyone receiving this source is licensed under IBM
+  |       copyrights to use it in any way he or she deems fit, including
+  |       copying it, modifying it, compiling it, and redistributing it either
+  |       with or without modifications.  No license under IBM patents or
+  |       patent applications is to be implied by the copyright license.
+  |
+  |       Any user of this software should understand that IBM cannot provide
+  |       technical support for this software and will not be responsible for
+  |       any consequences resulting from the use of this software.
+  |
+  |       Any person who transfers this source code or any derivative work
+  |       must include the IBM copyright notice, this paragraph, and the
+  |       preceding two paragraphs in the transferred software.
+  |
+  |       COPYRIGHT   I B M   CORPORATION 1995
+  |       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M
+  +-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+  |
+  |  File Name:  miiphy.c
+  |
+  |  Function:   This module has utilities for accessing the MII PHY through
+  |           the EMAC3 macro.
+  |
+  |  Author:     Mark Wisner
+  |
+  |  Change Activity-
+  |
+  |  Date        Description of Change                                       BY
+  |  ---------   ---------------------                                       ---
+  |  05-May-99   Created                                                     MKW
+  |  01-Jul-99   Changed clock setting of sta_reg from 66Mhz to 50Mhz to
+  |              better match OPB speed. Also modified delay times.               JWB
+  |  29-Jul-99   Added Full duplex support                                   MKW
+  |  24-Aug-99   Removed printf from dp83843_duplex()                      JWB
+  |  19-Jul-00   Ported to esd cpci405                                       sr
+  |
+  +-----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <405gp_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+
+#if defined(CONFIG_405GP) || defined(CONFIG_440)
+
+
+/***********************************************************/
+/* Dump out to the screen PHY regs                         */
+/***********************************************************/
+
+void miiphy_dump (unsigned char addr)
+{
+       unsigned long i;
+       unsigned short data;
+
+
+       for (i = 0; i < 0x1A; i++) {
+               if (miiphy_read (addr, i, &data)) {
+                       printf ("read error for reg %lx\n", i);
+                       return;
+               }
+               printf ("Phy reg %lx ==> %4x\n", i, data);
+
+               /* jump to the next set of regs */
+               if (i == 0x07)
+                       i = 0x0f;
+
+       } /* end for loop */
+} /* end dump */
+
+
+
+/***********************************************************/
+/* read a phy reg and return the value with a rc           */
+/***********************************************************/
+
+int miiphy_read (unsigned char addr, unsigned char reg,
+                                unsigned short *value)
+{
+       unsigned long sta_reg;          /* STA scratch area */
+       unsigned long i;
+
+       /* see if it is ready for 1000 nsec */
+       i = 0;
+
+       /* see if it is ready for  sec */
+       while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
+               udelay (7);
+               if (i > 5) {
+                       printf ("read err 1\n");
+                       return -1;
+               }
+               i++;
+       }
+       sta_reg = reg;                          /* reg address */
+       /* set clock (50Mhz) and read flags */
+       sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ;
+       sta_reg = sta_reg | (addr << 5);        /* Phy address */
+
+       out32 (EMAC_STACR, sta_reg);
+#if 0  /* test-only */
+       printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg);      /* test-only */
+#endif
+
+       sta_reg = in32 (EMAC_STACR);
+       i = 0;
+       while ((sta_reg & EMAC_STACR_OC) == 0) {
+               udelay (7);
+               if (i > 5) {
+                       printf ("read err 2\n");
+                       return -1;
+               }
+               i++;
+               sta_reg = in32 (EMAC_STACR);
+       }
+       if ((sta_reg & EMAC_STACR_PHYE) != 0) {
+               printf ("read err 3\n");
+               printf ("a2: read: EMAC_STACR=0x%0lx, i=%d\n",
+                       sta_reg, (int) i);      /* test-only */
+               return -1;
+       }
+
+       *value = *(short *) (&sta_reg);
+       return 0;
+
+
+} /* phy_read */
+
+
+/***********************************************************/
+/* write a phy reg and return the value with a rc           */
+/***********************************************************/
+
+int miiphy_write (unsigned char addr, unsigned char reg,
+                 unsigned short value)
+{
+       unsigned long sta_reg;          /* STA scratch area */
+       unsigned long i;
+
+       /* see if it is ready for 1000 nsec */
+       i = 0;
+
+       while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
+               if (i > 5)
+                       return -1;
+               udelay (7);
+               i++;
+       }
+       sta_reg = 0;
+       sta_reg = reg;                          /* reg address */
+       /* set clock (50Mhz) and read flags */
+       sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ;
+       sta_reg = sta_reg | ((unsigned long) addr << 5);        /* Phy address */
+       memcpy (&sta_reg, &value, 2);   /* put in data */
+
+       out32 (EMAC_STACR, sta_reg);
+
+       /* wait for completion */
+       i = 0;
+       sta_reg = in32 (EMAC_STACR);
+       while ((sta_reg & EMAC_STACR_OC) == 0) {
+               udelay (7);
+               if (i > 5)
+                       return -1;
+               i++;
+               sta_reg = in32 (EMAC_STACR);
+       }
+
+       if ((sta_reg & EMAC_STACR_PHYE) != 0)
+               return -1;
+       return 0;
+
+} /* phy_read */
+
+#endif /* CONFIG_405GP */
diff --git a/cpu/ppc4xx/traps.c b/cpu/ppc4xx/traps.c
new file mode 100644 (file)
index 0000000..85f2ea4
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (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
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+ */
+#define END_OF_MEM     0x00400000
+
+
+static __inline__ void set_tsr(unsigned long val)
+{
+#if defined(CONFIG_440)
+       asm volatile("mtspr 0x150, %0" : : "r" (val));
+#else
+       asm volatile("mttsr %0" : : "r" (val));
+#endif
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+       unsigned long val;
+
+#if defined(CONFIG_440)
+       asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+#else
+       asm volatile("mfesr %0" : "=r" (val) :);
+#endif
+       return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+       int cnt = 0;
+       unsigned long i;
+
+       printf("Call backtrace: ");
+       while (sp) {
+               if ((uint)sp > END_OF_MEM)
+                       break;
+
+               i = sp[1];
+               if (cnt++ % 7 == 0)
+                       printf("\n");
+               printf("%08lX ", i);
+               if (cnt > 32) break;
+               sp = (unsigned long *)*sp;
+       }
+       printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       int i;
+
+       printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+              regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+       printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+              regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+              regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+              regs->msr&MSR_IR ? 1 : 0,
+              regs->msr&MSR_DR ? 1 : 0);
+
+       printf("\n");
+       for (i = 0;  i < 32;  i++) {
+               if ((i % 8) == 0)
+               {
+                       printf("GPR%02d: ", i);
+               }
+
+               printf("%08lX ", regs->gpr[i]);
+               if ((i % 8) == 7)
+               {
+                       printf("\n");
+               }
+       }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+       unsigned long fixup;
+
+       /* Probing PCI using config cycles cause this exception
+        * when a device is not present.  Catch it and return to
+        * the PCI exception handler.
+        */
+       if ((fixup = search_exception_table(regs->nip)) != 0) {
+               regs->nip = fixup;
+               return;
+       }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       printf("Machine check in kernel mode.\n");
+       printf("Caused by (from msr): ");
+       printf("regs %p ",regs);
+       switch( regs->msr & 0x0000F000)
+       {
+       case (1<<12) :
+               printf("Machine check signal - probably due to mm fault\n"
+                      "with mmu off\n");
+               break;
+       case (1<<13) :
+               printf("Transfer error ack signal\n");
+               break;
+       case (1<<14) :
+               printf("Data parity signal\n");
+               break;
+       case (1<<15) :
+               printf("Address parity signal\n");
+               break;
+       default:
+               printf("Unknown values in msr\n");
+       }
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       show_regs(regs);
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+        long esr_val;
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       show_regs(regs);
+
+        esr_val = get_esr();
+        if( esr_val & ESR_PIL )
+               printf( "** Illegal Instruction **\n" );
+        else if( esr_val & ESR_PPR )
+               printf( "** Privileged Instruction **\n" );
+        else if( esr_val & ESR_PTR )
+               printf( "** Trap Instruction **\n" );
+
+       print_backtrace((unsigned long *)regs->gpr[1]);
+       panic("Program Check Exception");
+}
+
+void
+PITException(struct pt_regs *regs)
+{
+        /*
+         * Reset PIT interrupt
+         */
+        set_tsr(0x08000000);
+
+        /*
+         * Call timer_interrupt routine in interrupts.c
+         */
+        timer_interrupt(NULL);
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+       if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+               return;
+#endif
+
+       printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+              regs->nip, regs->msr, regs->trap);
+       _exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+       printf("Debugger trap at @ %lx\n", regs->nip );
+       show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+       do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading.  If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+       int     retval;
+
+       __asm__ __volatile__(                   \
+               "1:     lwz %0,0(%1)\n"         \
+                                               "       eieio\n"                \
+                                               "       li %0,0\n"              \
+                                               "2:\n"                          \
+                                               ".section .fixup,\"ax\"\n"      \
+                                               "3:     li %0,-1\n"             \
+                                               "       b 2b\n"                 \
+                                               ".section __ex_table,\"a\"\n"   \
+                                               "       .align 2\n"             \
+                                               "       .long 1b,3b\n"          \
+                                               ".text"                         \
+                                               : "=r" (retval) : "r"(addr));
+
+       return (retval);
+#endif
+       return 0;
+}
diff --git a/disk/part.c b/disk/part.c
new file mode 100644 (file)
index 0000000..99fe0db
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <cmd_disk.h>
+
+#undef PART_DEBUG
+
+#ifdef PART_DEBUG
+#define        PRINTF(fmt,args...)     printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)
+
+/* ------------------------------------------------------------------------- */
+/*
+ * reports device info to the user
+ */
+void dev_print (block_dev_desc_t *dev_desc)
+{
+       ulong lba512; /* number of blocks if 512bytes block size */
+
+       if (dev_desc->type==DEV_TYPE_UNKNOWN) {
+               puts ("not available\n");
+               return;
+       }
+       if (dev_desc->if_type==IF_TYPE_SCSI)  {
+               printf ("(%d:%d) ", dev_desc->target,dev_desc->lun);
+       }
+       if (dev_desc->if_type==IF_TYPE_IDE) {
+               printf ("Model: %s Firm: %s Ser#: %s\n",
+                       dev_desc->vendor,
+                       dev_desc->revision,
+                       dev_desc->product);
+       } else {
+               printf ("Vendor: %s Prod.: %s Rev: %s\n",
+                       dev_desc->vendor,
+                       dev_desc->product,
+                       dev_desc->revision);
+       }
+       puts ("            Type: ");
+       if (dev_desc->removable)
+               puts ("Removable ");
+       switch (dev_desc->type & 0x1F) {
+               case DEV_TYPE_HARDDISK: puts ("Hard Disk");
+                                       break;
+               case DEV_TYPE_CDROM:    puts ("CD ROM");
+                                       break;
+               case DEV_TYPE_OPDISK:   puts ("Optical Device");
+                                       break;
+               case DEV_TYPE_TAPE:     puts ("Tape");
+                                       break;
+               default:                printf ("# %02X #", dev_desc->type & 0x1F);
+                                       break;
+       }
+       puts ("\n");
+       if ((dev_desc->lba * dev_desc->blksz)>0L) {
+               ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
+
+               lba512 = (dev_desc->lba * (dev_desc->blksz/512));
+
+               mb = (10 * lba512) / 2048;      /* 2048 = (1024 * 1024) / 512 MB */
+               /* round to 1 digit */
+               mb_quot = mb / 10;
+               mb_rem  = mb - (10 * mb_quot);
+
+               gb = mb / 1024;
+               gb_quot = gb / 10;
+               gb_rem  = gb - (10 * gb_quot);
+
+               printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
+                       mb_quot, mb_rem,
+                       gb_quot, gb_rem,
+                       dev_desc->lba,
+                       dev_desc->blksz);
+       } else {
+               puts ("            Capacity: not available\n");
+       }
+}
+
+
+
+#if defined(CONFIG_MAC_PARTITION) || \
+    defined(CONFIG_DOS_PARTITION) || \
+    defined(CONFIG_ISO_PARTITION)
+
+void init_part (block_dev_desc_t * dev_desc)
+{
+#ifdef CONFIG_ISO_PARTITION
+       if (test_part_iso(dev_desc) == 0) {
+               dev_desc->part_type = PART_TYPE_ISO;
+               return;
+       }
+#endif
+
+#ifdef CONFIG_MAC_PARTITION
+       if (test_part_mac(dev_desc) == 0) {
+               dev_desc->part_type = PART_TYPE_MAC;
+               return;
+       }
+#endif
+
+#ifdef CONFIG_DOS_PARTITION
+       if (test_part_dos(dev_desc) == 0) {
+               dev_desc->part_type = PART_TYPE_DOS;
+               return;
+       }
+#endif
+}
+
+
+int get_partition_info (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
+{
+               switch (dev_desc->part_type) {
+#ifdef CONFIG_MAC_PARTITION
+       case PART_TYPE_MAC:
+               if (get_partition_info_mac(dev_desc,part,info) == 0) {
+                       PRINTF ("## Valid MAC partition found ##\n");
+                       return (0);
+               }
+               break;
+#endif
+
+#ifdef CONFIG_DOS_PARTITION
+       case PART_TYPE_DOS:
+               if (get_partition_info_dos(dev_desc,part,info) == 0) {
+                       PRINTF ("## Valid DOS partition found ##\n");
+                       return (0);
+               }
+               break;
+#endif
+
+#ifdef CONFIG_ISO_PARTITION
+       case PART_TYPE_ISO:
+               if (get_partition_info_iso(dev_desc,part,info) == 0) {
+                       PRINTF ("## Valid ISO boot partition found ##\n");
+                       return (0);
+               }
+               break;
+#endif
+       default:
+               break;
+       }
+       return (-1);
+}
+
+static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
+{
+       puts ("\nPartition Map for ");
+       switch (dev_desc->if_type) {
+               case IF_TYPE_IDE:       puts ("IDE");
+                                       break;
+               case IF_TYPE_SCSI:      puts ("SCSI");
+                                       break;
+               case IF_TYPE_ATAPI:     puts ("ATAPI");
+                                       break;
+               case IF_TYPE_USB:       puts ("USB");
+                                       break;
+               case IF_TYPE_DOC:       puts ("DOC");
+                                       break;
+               default:                puts ("UNKNOWN");
+                                       break;
+       }
+       printf (" device %d  --   Partition Type: %s\n\n",
+                       dev_desc->dev, type);
+}
+
+void print_part (block_dev_desc_t * dev_desc)
+{
+
+               switch (dev_desc->part_type) {
+#ifdef CONFIG_MAC_PARTITION
+       case PART_TYPE_MAC:
+               PRINTF ("## Testing for valid MAC partition ##\n");
+               print_part_header ("MAC", dev_desc);
+               print_part_mac (dev_desc);
+               return;
+#endif
+#ifdef CONFIG_DOS_PARTITION
+       case PART_TYPE_DOS:
+               PRINTF ("## Testing for valid DOS partition ##\n");
+               print_part_header ("DOS", dev_desc);
+               print_part_dos (dev_desc);
+               return;
+#endif
+
+#ifdef CONFIG_ISO_PARTITION
+       case PART_TYPE_ISO:
+               PRINTF ("## Testing for valid ISO Boot partition ##\n");
+               print_part_header ("ISO", dev_desc);
+               print_part_iso (dev_desc);
+               return;
+#endif
+       }
+       puts ("## Unknown partition table\n");
+}
+
+
+#else  /* neither MAC nor DOS nor ISO partition configured */
+# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION nor CONFIG_ISO_PARTITION configured!
+#endif
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_IDE) || CONFIG_COMMANDS & CFG_CMD_SCSI) */
diff --git a/drivers/pci_indirect.c b/drivers/pci_indirect.c
new file mode 100644 (file)
index 0000000..cb76ef2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op)  *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#define INDIRECT_PCI_OP(rw, size, type, op, mask)                       \
+static int                                                              \
+indirect_##rw##_config_##size(struct pci_controller *hose,              \
+                             pci_dev_t dev, int offset, type val)       \
+{                                                                       \
+       out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000);    \
+       cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \
+       return 0;                                                        \
+}
+
+#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask)               \
+static int                                                              \
+indirect_##rw##_config_##size(struct pci_controller *hose,              \
+                             pci_dev_t dev, int offset, type val)       \
+{                                                                       \
+       unsigned int msr = mfmsr();                                      \
+       mtmsr(msr & ~(MSR_EE | MSR_CE));                                 \
+       out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000);    \
+       cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \
+       out_le32(hose->cfg_addr, 0x00000000);                            \
+       mtmsr(msr);                                                      \
+       return 0;                                                        \
+}
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+#ifdef CONFIG_405GP
+INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
+#else
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+       pci_set_ops(hose,
+                   indirect_read_config_byte,
+                   indirect_read_config_word,
+                   indirect_read_config_dword,
+                   indirect_write_config_byte,
+                   indirect_write_config_word,
+                   indirect_write_config_dword);
+
+       hose->cfg_addr = (unsigned int *) cfg_addr;
+       hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif
diff --git a/examples/eepro100_eeprom.c b/examples/eepro100_eeprom.c
new file mode 100644 (file)
index 0000000..656b238
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1998-2001 by Donald Becker.
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Contact the author for use under other terms.
+ *
+ * This program must be compiled with "-O"!
+ * See the bottom of this file for the suggested compile-command.
+ *
+ * The author may be reached as becker@scyld.com, or C/O
+ *  Scyld Computing Corporation
+ *  410 Severn Ave., Suite 210
+ *  Annapolis MD 21403
+ *
+ * Common-sense licensing statement: Using any portion of this program in
+ * your own program means that you must give credit to the original author
+ * and release the resulting code under the GPL.
+ */
+
+#define _PPC_STRING_H_         /* avoid unnecessary str/mem functions */
+#define _LINUX_STRING_H_       /* avoid unnecessary str/mem functions */
+
+#include <common.h>
+#include <syscall.h>
+
+static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr);
+
+int eepro100_eeprom(void)
+{
+       int ret = 0;
+
+       unsigned char hwaddr1[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x05 };
+       unsigned char hwaddr2[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x06 };
+
+#if defined(CONFIG_OXC)
+       ret |= reset_eeprom(0x80000000, hwaddr1);
+       ret |= reset_eeprom(0x81000000, hwaddr2);
+#endif
+
+       return ret;
+}
+
+/* Default EEPROM for i82559 */
+static unsigned short default_eeprom[64] = {
+       0x0100, 0x0302, 0x0504, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0x40c0, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
+};
+
+static unsigned short eeprom[256];
+
+static int eeprom_size = 64;
+static int eeprom_addr_size = 6;
+
+static int debug = 0;
+
+static inline unsigned short swap16(unsigned short x)
+{
+       return (((x & 0xff) << 8) | ((x & 0xff00) >> 8));
+}
+
+static inline void outw(short data, long addr)
+{
+       *(volatile short *)(addr) = swap16(data);
+}
+
+static inline short inw(long addr)
+{
+       return swap16(*(volatile short *)(addr));
+}
+
+static inline void *memcpy(void *dst, const void *src, unsigned int len)
+{
+       void * ret = dst;
+       while (len-- > 0) *((char *)dst)++ = *((char *)src)++;
+       return ret;
+}
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD   (5)
+#define EE_READ_CMD            (6)
+#define EE_ERASE_CMD   (7)
+
+/* Serial EEPROM section. */
+#define EE_SHIFT_CLK   0x01    /* EEPROM shift clock. */
+#define EE_CS                  0x02    /* EEPROM chip select. */
+#define EE_DATA_WRITE  0x04    /* EEPROM chip data in. */
+#define EE_DATA_READ   0x08    /* EEPROM chip data out. */
+#define EE_ENB                 (0x4800 | EE_CS)
+#define EE_WRITE_0             0x4802
+#define EE_WRITE_1             0x4806
+#define EE_OFFSET              14
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay(ee_addr)  inw(ee_addr)
+
+/* Wait for the EEPROM to finish the previous operation. */
+static int eeprom_busy_poll(long ee_ioaddr)
+{
+       int i;
+       outw(EE_ENB, ee_ioaddr);
+       for (i = 0; i < 10000; i++)                     /* Typical 2000 ticks */
+               if (inw(ee_ioaddr) & EE_DATA_READ)
+                       break;
+       return i;
+}
+
+/* This executes a generic EEPROM command, typically a write or write enable.
+   It returns the data output from the EEPROM, and thus may also be used for
+   reads. */
+static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
+{
+       unsigned retval = 0;
+       long ee_addr = ioaddr + EE_OFFSET;
+
+       if (debug > 1)
+               mon_printf(" EEPROM op 0x%x: ", cmd);
+
+       outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
+
+       /* Shift the command bits out. */
+       do {
+               short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+               outw(dataval, ee_addr);
+               eeprom_delay(ee_addr);
+               if (debug > 2)
+                       mon_printf("%X", inw(ee_addr) & 15);
+               outw(dataval | EE_SHIFT_CLK, ee_addr);
+               eeprom_delay(ee_addr);
+               retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
+       } while (--cmd_len >= 0);
+#if 0
+       outw(EE_ENB, ee_addr);
+#endif
+       /* Terminate the EEPROM access. */
+       outw(EE_ENB & ~EE_CS, ee_addr);
+       if (debug > 1)
+               mon_printf(" EEPROM result is 0x%5.5x.\n", retval);
+       return retval;
+}
+
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+       return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location)
+               << 16 , 3 + addr_len + 16) & 0xffff;
+}
+
+static void write_eeprom(long ioaddr, int index, int value, int addr_len)
+{
+       long ee_ioaddr = ioaddr + EE_OFFSET;
+       int i;
+
+       /* Poll for previous op finished. */
+       eeprom_busy_poll(ee_ioaddr);                    /* Typical 0 ticks */
+       /* Enable programming modes. */
+       do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len);
+       /* Do the actual write. */
+       do_eeprom_cmd(ioaddr,
+                                 (((EE_WRITE_CMD<<addr_len) | index)<<16) | (value & 0xffff),
+                                 3 + addr_len + 16);
+       /* Poll for write finished. */
+       i = eeprom_busy_poll(ee_ioaddr);                        /* Typical 2000 ticks */
+       if (debug)
+               mon_printf(" Write finished after %d ticks.\n", i);
+       /* Disable programming. This command is not instantaneous, so we check
+          for busy before the next op. */
+       do_eeprom_cmd(ioaddr, (0x40 << (addr_len-4)), 3 + addr_len);
+       eeprom_busy_poll(ee_ioaddr);
+}
+
+static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr)
+{
+       unsigned short checksum = 0;
+       int size_test;
+       int i;
+
+       mon_printf("Resetting i82559 EEPROM @ 0x%08x ... ", ioaddr);
+
+       size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27);
+       eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6;
+       eeprom_size = 1 << eeprom_addr_size;
+
+       memcpy(eeprom, default_eeprom, sizeof default_eeprom);
+
+       for (i = 0; i < 3; i++)
+               eeprom[i] = (hwaddr[i*2+1]<<8) + hwaddr[i*2];
+
+       /* Recalculate the checksum. */
+       for (i = 0; i < eeprom_size - 1; i++)
+               checksum += eeprom[i];
+       eeprom[i] = 0xBABA - checksum;
+
+       for (i = 0; i < eeprom_size; i++)
+               write_eeprom(ioaddr, i, eeprom[i], eeprom_addr_size);
+
+       for (i = 0; i < eeprom_size; i++)
+               if (read_eeprom(ioaddr, i, eeprom_addr_size) != eeprom[i]) {
+                       mon_printf("failed\n");
+                       return 1;
+               }
+
+       mon_printf("done\n");
+       return 0;
+}
+
diff --git a/include/pcmcia.h b/include/pcmcia.h
new file mode 100644 (file)
index 0000000..ee2c63c
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * (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
+ */
+
+#ifndef _PCMCIA_H
+#define _PCMCIA_H
+
+#include <common.h>
+#include <config.h>
+
+/*
+ * Allow configuration to select PCMCIA slot,
+ * or try to generate a useful default
+ */
+#if ( CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
+    ((CONFIG_COMMANDS & CFG_CMD_IDE) && \
+       (defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) ) )
+
+#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
+
+                                       /* The RPX series use SLOT_B    */
+#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_ADS)              /* The ADS  board use SLOT_A    */
+# define CONFIG_PCMCIA_SLOT_A
+#elif defined(CONFIG_FADS)             /* The FADS series are a mess   */
+# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
+#  define CONFIG_PCMCIA_SLOT_A
+# else
+#  define CONFIG_PCMCIA_SLOT_B
+# endif
+#elif defined(CONFIG_TQM8xxL)
+# define       CONFIG_PCMCIA_SLOT_B    /* The TQM8xxL use SLOT_B       */
+#elif defined(CONFIG_SPD823TS)         /* The SPD8xx  use SLOT_B       */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)  /* The IVM* use SLOT_A  */
+# define CONFIG_PCMCIA_SLOT_A
+#elif defined(CONFIG_LWMON)            /* The LWMON  use SLOT_B        */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_ICU862)           /* The ICU862 use SLOT_B        */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_C2MON)            /* The C2MON  use SLOT_B        */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_R360MPI)          /* The R360MPI use SLOT_B       */
+# define CONFIG_PCMCIA_SLOT_B
+#else
+# error "PCMCIA Slot not configured"
+#endif
+
+#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
+
+/* Make sure exactly one slot is defined - we support only one for now */
+#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
+#error Neither CONFIG_PCMCIA_SLOT_A nor CONFIG_PCMCIA_SLOT_B configured
+#endif
+#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
+#error Both CONFIG_PCMCIA_SLOT_A and CONFIG_PCMCIA_SLOT_B configured
+#endif
+
+#define PCMCIA_SOCKETS_NO      1
+#define PCMCIA_MEM_WIN_NO      4
+#define PCMCIA_IO_WIN_NO       2
+
+/* define _slot_ to be able to optimize macros */
+#ifdef CONFIG_PCMCIA_SLOT_A
+# define _slot_                        0
+# define PCMCIA_SLOT_MSG       "slot A"
+# define PCMCIA_SLOT_x         PCMCIA_PSLOT_A
+#else
+# define _slot_                        1
+# define PCMCIA_SLOT_MSG       "slot B"
+# define PCMCIA_SLOT_x         PCMCIA_PSLOT_B
+#endif
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET       PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE          PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET       PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE          PCMCIA_GCRX_CXOE
+#endif
+
+/*
+ * This structure is used to address each window in the PCMCIA controller.
+ *
+ * Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly
+ * after pcmcia_win_t[n]...
+ */
+
+typedef struct {
+       ulong   br;
+       ulong   or;
+} pcmcia_win_t;
+
+/*
+ * Definitions for PCMCIA control registers to operate in IDE mode
+ *
+ * All timing related setup (PCMCIA_SHT, PCMCIA_SST, PCMCIA_SL)
+ * to be done later (depending on CPU clock)
+ */
+
+/* Window 0:
+ *     Base: 0xFE100000        CS1
+ *     Port Size:     2 Bytes
+ *     Port Size:    16 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR0                0xFE100000
+#define CFG_PCMCIA_POR0            (   PCMCIA_BSIZE_2  \
+                           |   PCMCIA_PPS_16   \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 1:
+ *     Base: 0xFE100080        CS1
+ *     Port Size:     8 Bytes
+ *     Port Size:     8 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR1                0xFE100080
+#define CFG_PCMCIA_POR1            (   PCMCIA_BSIZE_8  \
+                           |   PCMCIA_PPS_8    \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 2:
+ *     Base: 0xFE100100        CS2
+ *     Port Size:     8 Bytes
+ *     Port Size:     8 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR2                0xFE100100
+#define CFG_PCMCIA_POR2            (   PCMCIA_BSIZE_8  \
+                           |   PCMCIA_PPS_8    \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 3:
+ *     not used
+ */
+#define CFG_PCMCIA_PBR3                0
+#define CFG_PCMCIA_POR3                0
+
+/* Window 4:
+ *     Base: 0xFE100C00        CS1
+ *     Port Size:     2 Bytes
+ *     Port Size:    16 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR4                0xFE100C00
+#define CFG_PCMCIA_POR4            (   PCMCIA_BSIZE_2  \
+                           |   PCMCIA_PPS_16   \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 5:
+ *     Base: 0xFE100C80        CS1
+ *     Port Size:     8 Bytes
+ *     Port Size:     8 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR5                0xFE100C80
+#define CFG_PCMCIA_POR5            (   PCMCIA_BSIZE_8  \
+                           |   PCMCIA_PPS_8    \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 6:
+ *     Base: 0xFE100D00        CS2
+ *     Port Size:     8 Bytes
+ *     Port Size:     8 Bit
+ *     Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR6                0xFE100D00
+#define CFG_PCMCIA_POR6            (   PCMCIA_BSIZE_8  \
+                           |   PCMCIA_PPS_8    \
+                           |   PCMCIA_PRS_MEM  \
+                           |   PCMCIA_SLOT_x   \
+                           |   PCMCIA_PV       \
+                           )
+
+/* Window 7:
+ *     not used
+ */
+#define CFG_PCMCIA_PBR7                0
+#define CFG_PCMCIA_POR7                0
+
+/**********************************************************************/
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL            0x00
+#define CISTPL_DEVICE          0x01
+#define CISTPL_LONGLINK_CB     0x02
+#define CISTPL_INDIRECT                0x03
+#define CISTPL_CONFIG_CB       0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC    0x06
+#define CISTPL_BAR             0x07
+#define CISTPL_PWR_MGMNT       0x08
+#define CISTPL_EXTDEVICE       0x09
+#define CISTPL_CHECKSUM                0x10
+#define CISTPL_LONGLINK_A      0x11
+#define CISTPL_LONGLINK_C      0x12
+#define CISTPL_LINKTARGET      0x13
+#define CISTPL_NO_LINK         0x14
+#define CISTPL_VERS_1          0x15
+#define CISTPL_ALTSTR          0x16
+#define CISTPL_DEVICE_A                0x17
+#define CISTPL_JEDEC_C         0x18
+#define CISTPL_JEDEC_A         0x19
+#define CISTPL_CONFIG          0x1a
+#define CISTPL_CFTABLE_ENTRY   0x1b
+#define CISTPL_DEVICE_OC       0x1c
+#define CISTPL_DEVICE_OA       0x1d
+#define CISTPL_DEVICE_GEO      0x1e
+#define CISTPL_DEVICE_GEO_A    0x1f
+#define CISTPL_MANFID          0x20
+#define CISTPL_FUNCID          0x21
+#define CISTPL_FUNCE           0x22
+#define CISTPL_SWIL            0x23
+#define CISTPL_END             0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI    0x00
+#define CISTPL_FUNCID_MEMORY   0x01
+#define CISTPL_FUNCID_SERIAL   0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED    0x04
+#define CISTPL_FUNCID_VIDEO    0x05
+#define CISTPL_FUNCID_NETWORK  0x06
+#define CISTPL_FUNCID_AIMS     0x07
+#define CISTPL_FUNCID_SCSI     0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE   0x01
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER        0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON     0x04
+#define CISTPL_IDE_UNIQUE      0x08
+#define CISTPL_IDE_DUAL                0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP   0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE    0x04
+#define CISTPL_IDE_LOW_POWER   0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX   0x20
+#define CISTPL_IDE_IOIS16      0x40
+
+#endif /* CFG_CMD_PCMCIA || CFG_CMD_IDE && (CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT) */
+
+#endif /* _PCMCIA_H */
diff --git a/include/syscall.h b/include/syscall.h
new file mode 100644 (file)
index 0000000..f80d550
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __MON_SYS_CALL_H__
+#define __MON_SYS_CALL_H__
+
+#ifndef __ASSEMBLY__
+
+#include <common.h>
+
+/* These are declarations of system calls available in C code */
+int  mon_getc(void);
+int  mon_tstc(void);
+void mon_putc(const char);
+void mon_puts(const char*);
+void mon_printf(const char* fmt, ...);
+void mon_install_hdlr(int, interrupt_handler_t*, void*);
+void mon_free_hdlr(int);
+void *mon_malloc(size_t);
+void mon_free(void*);
+
+#endif    /* ifndef __ASSEMBLY__ */
+
+#define NR_SYSCALLS            9        /* number of syscalls */
+
+/*
+ * Make sure these functions are in the same order as they
+ * appear in the "examples/syscall.S" file !!!
+ */
+#define SYSCALL_GETC           0
+#define SYSCALL_TSTC           1
+#define SYSCALL_PUTC           2
+#define SYSCALL_PUTS           3
+#define SYSCALL_PRINTF         4
+#define SYSCALL_INSTALL_HDLR   5
+#define SYSCALL_FREE_HDLR      6
+#define SYSCALL_MALLOC         7
+#define SYSCALL_FREE           8
+
+#endif
diff --git a/lib_generic/crc32.c b/lib_generic/crc32.c
new file mode 100644 (file)
index 0000000..2de39c7
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef USE_HOSTCC     /* Shut down "ANSI does not permit..." warnings */
+#include <common.h>    /* to get command definitions like CFG_CMD_JFFS2 */
+#endif
+
+#include "zlib.h"
+
+#define local static
+#define ZEXPORT        /* empty */
+unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uLong c;
+  int n, k;
+  uLong poly;            /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = c;
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+#endif
+
+#if 0
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uLongf *)crc_table;
+}
+#endif
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+    uLong crc;
+    const Bytef *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+/* No ones complement version. JFFS2 (and other things ?)
+ * don't use ones compliment in their CRC calculations.
+ */
+uLong ZEXPORT crc32_no_comp(uLong crc, const Bytef *buf, uInt len)
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+
+    return crc;
+}
+
+#endif /* CFG_CMD_JFFS2 */
diff --git a/lib_ppc/bat_rw.c b/lib_ppc/bat_rw.c
new file mode 100644 (file)
index 0000000..912efa7
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+
+int write_bat (ppc_bat_t bat, unsigned long upper, unsigned long lower)
+{
+       switch (bat) {
+       case IBAT0:
+               mtspr (IBAT0L, lower);
+               mtspr (IBAT0U, upper);
+               break;
+
+       case IBAT1:
+               mtspr (IBAT1L, lower);
+               mtspr (IBAT1U, upper);
+               break;
+
+       case IBAT2:
+               mtspr (IBAT2L, lower);
+               mtspr (IBAT2U, upper);
+               break;
+
+       case IBAT3:
+               mtspr (IBAT3L, lower);
+               mtspr (IBAT3U, upper);
+               break;
+
+       case DBAT0:
+               mtspr (DBAT0L, lower);
+               mtspr (DBAT0U, upper);
+               break;
+
+       case DBAT1:
+               mtspr (DBAT1L, lower);
+               mtspr (DBAT1U, upper);
+               break;
+
+       case DBAT2:
+               mtspr (DBAT2L, lower);
+               mtspr (DBAT2U, upper);
+               break;
+
+       case DBAT3:
+               mtspr (DBAT3L, lower);
+               mtspr (DBAT3U, upper);
+               break;
+
+       default:
+               return (-1);
+       }
+
+       return (0);
+}
+
+int read_bat (ppc_bat_t bat, unsigned long *upper, unsigned long *lower)
+{
+       unsigned long register u;
+       unsigned long register l;
+
+       switch (bat) {
+       case IBAT0:
+               l = mfspr (IBAT0L);
+               u = mfspr (IBAT0U);
+               break;
+
+       case IBAT1:
+               l = mfspr (IBAT1L);
+               u = mfspr (IBAT1U);
+               break;
+
+       case IBAT2:
+               l = mfspr (IBAT2L);
+               u = mfspr (IBAT2U);
+               break;
+
+       case IBAT3:
+               l = mfspr (IBAT3L);
+               u = mfspr (IBAT3U);
+               break;
+
+       case DBAT0:
+               l = mfspr (DBAT0L);
+               u = mfspr (DBAT0U);
+               break;
+
+       case DBAT1:
+               l = mfspr (DBAT1L);
+               u = mfspr (DBAT1U);
+               break;
+
+       case DBAT2:
+               l = mfspr (DBAT2L);
+               u = mfspr (DBAT2U);
+               break;
+
+       case DBAT3:
+               l = mfspr (DBAT3L);
+               u = mfspr (DBAT3U);
+               break;
+
+       default:
+               return (-1);
+       }
+
+       *upper = u;
+       *lower = l;
+
+       return (0);
+}
diff --git a/lib_ppc/cache.c b/lib_ppc/cache.c
new file mode 100644 (file)
index 0000000..bec092e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * (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
+ */
+
+#include <common.h>
+
+void flush_cache (ulong start_addr, ulong size)
+{
+       ulong addr, end_addr = start_addr + size;
+
+       if (CFG_CACHELINE_SIZE) {
+               addr = start_addr & (CFG_CACHELINE_SIZE - 1);
+               for (addr = start_addr;
+                    addr < end_addr;
+                    addr += CFG_CACHELINE_SIZE) {
+                       asm ("dcbst 0,%0": :"r" (addr));
+               }
+               asm ("sync");   /* Wait for all dcbst to complete on bus */
+
+               for (addr = start_addr;
+                    addr < end_addr;
+                    addr += CFG_CACHELINE_SIZE) {
+                       asm ("icbi 0,%0": :"r" (addr));
+               }
+       }
+       asm ("sync");           /* Always flush prefetch queue in any case */
+       asm ("isync");
+}
diff --git a/net/rarp.c b/net/rarp.c
new file mode 100644 (file)
index 0000000..279e650
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * (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
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "bootp.h"
+#include "rarp.h"
+#include "tftp.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+#define TIMEOUT                5               /* Seconds before trying BOOTP again */
+#ifndef        CONFIG_NET_RETRY_COUNT
+# define TIMEOUT_COUNT 5               /* # of timeouts before giving up  */
+#else
+# define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT)
+#endif
+
+
+int            RarpTry;
+
+/*
+ *     Handle a RARP received packet.
+ */
+static void
+RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
+{
+#ifdef DEBUG
+       printf("Got good RARP\n");
+#endif
+       TftpStart ();
+}
+
+
+/*
+ *     Timeout on BOOTP request.
+ */
+static void
+RarpTimeout(void)
+{
+       if (RarpTry >= TIMEOUT_COUNT) {
+               puts ("\nRetry count exceeded; starting again\n");
+               NetStartAgain ();
+       } else {
+               NetSetTimeout (TIMEOUT * CFG_HZ, RarpTimeout);
+               RarpRequest ();
+       }
+}
+
+
+void
+RarpRequest (void)
+{
+       int i;
+       volatile uchar *pkt;
+       ARP_t * rarp;
+
+       printf("RARP broadcast %d\n", ++RarpTry);
+       pkt = NetTxPacket;
+
+       NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+       pkt += ETHER_HDR_SIZE;
+
+       rarp = (ARP_t *)pkt;
+
+       rarp->ar_hrd = ARP_ETHER;
+       rarp->ar_pro = PROT_IP;
+       rarp->ar_hln = 6;
+       rarp->ar_pln = 4;
+       rarp->ar_op  = RARPOP_REQUEST;
+       memcpy (&rarp->ar_data[0],  NetOurEther, 6);    /* source ET addr */
+       memcpy (&rarp->ar_data[6],  &NetOurIP,   4);    /* source IP addr */
+       memcpy (&rarp->ar_data[10], NetOurEther, 6);    /* dest ET addr = source ET addr ??*/
+       /* dest. IP addr set to broadcast */
+       for (i = 0; i <= 3; i++) {
+               rarp->ar_data[16 + i] = 0xff;
+       }
+
+       NetSendPacket(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+
+       NetSetTimeout(TIMEOUT * CFG_HZ, RarpTimeout);
+       NetSetHandler(RarpHandler);
+}
+
+#endif /* CFG_CMD_NET */
diff --git a/rtc/ds1306.c b/rtc/ds1306.c
new file mode 100644 (file)
index 0000000..9c11c60
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * (C) Copyright 2002 SIXNET, dge@sixnetio.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
+ */
+
+/*
+ * Date & Time support for DS1306 RTC using software SPI
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_DS1306) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static unsigned int bin2bcd(unsigned int n);
+static unsigned char bcd2bin(unsigned char c);
+static void soft_spi_send(unsigned char n);
+static unsigned char soft_spi_read(void);
+static void init_spi(void);
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define        PB_SPISCK       0x00000002      /* PB 30 */
+#define PB_SPIMOSI     0x00000004      /* PB 29 */
+#define PB_SPIMISO     0x00000008      /* PB 28 */
+#define PB_SPI_CE      0x00010000      /* PB 15 */
+
+/* ------------------------------------------------------------------------- */
+
+/* read clock time from DS1306 and return it in *tmp */
+void rtc_get(struct rtc_time *tmp)
+{
+    volatile immap_t *immap = (immap_t *)CFG_IMMR;
+    unsigned char spi_byte;    /* Data Byte */
+
+    init_spi();                /* set port B for software SPI */
+
+    /* Now we can enable the DS1306 RTC */
+    immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+    udelay(10);
+
+    /* Shift out the address (0) of the time in the Clock Chip */
+    soft_spi_send(0);
+
+    /* Put the clock readings into the rtc_time structure */
+    tmp->tm_sec = bcd2bin(soft_spi_read());    /* Read seconds */
+    tmp->tm_min = bcd2bin(soft_spi_read());    /* Read minutes */
+
+    /* Hours are trickier */
+    spi_byte = soft_spi_read();        /* Read Hours into temporary value */
+    if (spi_byte & 0x40) {
+       /* 12 hour mode bit is set (time is in 1-12 format) */
+       if (spi_byte & 0x20) {
+           /* since PM we add 11 to get 0-23 for hours */
+           tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) + 11;
+       }
+       else {
+           /* since AM we subtract 1 to get 0-23 for hours */
+           tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) - 1;
+       }
+    }
+    else {
+       /* Otherwise, 0-23 hour format */
+       tmp->tm_hour = (bcd2bin(spi_byte & 0x3F));
+    }
+
+    soft_spi_read();           /* Read and discard Day of week */
+    tmp->tm_mday = bcd2bin(soft_spi_read());   /* Read Day of the Month */
+    tmp->tm_mon = bcd2bin(soft_spi_read());    /* Read Month */
+
+    /* Read Year and convert to this century */
+    tmp->tm_year = bcd2bin(soft_spi_read()) + 2000;
+
+    /* Now we can disable the DS1306 RTC */
+    immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;      /* Disable DS1306 Chip */
+    udelay(10);
+
+    GregorianDay(tmp);         /* Determine the day of week */
+
+    debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+         tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+         tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* set clock time in DS1306 RTC and in MPC8xx RTC */
+void rtc_set(struct rtc_time *tmp)
+{
+    volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+    init_spi();                /* set port B for software SPI */
+
+    /* Now we can enable the DS1306 RTC */
+    immap->im_cpm.cp_pbdat |= PB_SPI_CE;       /* Enable DS1306 Chip */
+    udelay(10);
+
+    /* First disable write protect in the clock chip control register */
+    soft_spi_send(0x8F);       /* send address of the control register */
+    soft_spi_send(0x00);       /* send control register contents */
+
+    /* Now disable the DS1306 to terminate the write */
+    immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
+    udelay(10);
+
+    /* Now enable the DS1306 to initiate a new write */
+    immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+    udelay(10);
+
+    /* Next, send the address of the clock time write registers */
+    soft_spi_send(0x80);       /* send address of the first time register */
+
+    /* Use Burst Mode to send all of the time data to the clock */
+    bin2bcd(tmp->tm_sec);
+    soft_spi_send(bin2bcd(tmp->tm_sec));       /* Send Seconds */
+    soft_spi_send(bin2bcd(tmp->tm_min));       /* Send Minutes */
+    soft_spi_send(bin2bcd(tmp->tm_hour));      /* Send Hour */
+    soft_spi_send(bin2bcd(tmp->tm_wday));      /* Send Day of the Week */
+    soft_spi_send(bin2bcd(tmp->tm_mday));      /* Send Day of Month */
+    soft_spi_send(bin2bcd(tmp->tm_mon));       /* Send Month */
+    soft_spi_send(bin2bcd(tmp->tm_year - 2000));       /* Send Year */
+
+    /* Now we can disable the Clock chip to terminate the burst write */
+    immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;      /* Disable DS1306 Chip */
+    udelay(10);
+
+    /* Now we can enable the Clock chip to initiate a new write */
+    immap->im_cpm.cp_pbdat |= PB_SPI_CE;       /* Enable DS1306 Chip */
+    udelay(10);
+
+    /* First we Enable write protect in the clock chip control register */
+    soft_spi_send(0x8F);       /* send address of the control register */
+    soft_spi_send(0x40);       /* send out Control Register contents */
+
+    /* Now disable the DS1306 */
+    immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;      /*  Disable DS1306 Chip */
+    udelay(10);
+
+    /* Set standard MPC8xx clock to the same time so Linux will
+     * see the time even if it doesn't have a DS1306 clock driver.
+     * This helps with experimenting with standard kernels.
+     */
+    {
+       ulong tim;
+
+       tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
+                    tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       immap->im_sitk.sitk_rtck = KAPWR_KEY;
+       immap->im_sit.sit_rtc = tim;
+    }
+
+    debug("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+         tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+         tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_reset(void)
+{
+    return;                    /* nothing to do */
+}
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned char bcd2bin(unsigned char n)
+{
+    return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned int bin2bcd(unsigned int n)
+{
+    return (((n / 10) << 4) | (n % 10));
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Initialize Port B for software SPI */
+static void init_spi(void) {
+    volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+    /* Force output pins to begin at logic 0 */
+    immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
+
+    /* Set these 3 signals as outputs */
+    immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
+
+    immap->im_cpm.cp_pbdir &= ~PB_SPIMISO;     /* Make MISO pin an input */
+    udelay(10);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
+static void soft_spi_send(unsigned char n)
+{
+    volatile immap_t *immap = (immap_t *)CFG_IMMR;
+    unsigned char bitpos;      /* bit position to receive */
+    unsigned char i;           /* Loop Control */
+
+    /* bit position to send, start with most significant bit */
+    bitpos = 0x80;
+
+    /* Send 8 bits to software SPI */
+    for (i = 0; i < 8; i++) {  /* Loop for 8 bits */
+       immap->im_cpm.cp_pbdat |= PB_SPISCK;    /* Raise SCK */
+
+       if (n & bitpos)
+           immap->im_cpm.cp_pbdat |= PB_SPIMOSI;       /* Set MOSI to 1 */
+       else
+           immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI;      /* Set MOSI to 0 */
+       udelay(10);
+
+       immap->im_cpm.cp_pbdat &= ~PB_SPISCK;   /* Lower SCK */
+       udelay(10);
+
+       bitpos >>= 1;           /* Shift for next bit position */
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
+static unsigned char soft_spi_read(void)
+{
+    volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+    unsigned char spi_byte = 0;        /* Return value, assume success */
+    unsigned char bitpos;      /* bit position to receive */
+    unsigned char i;           /* Loop Control */
+
+    /* bit position to receive, start with most significant bit */
+    bitpos = 0x80;
+
+    /* Read 8 bits here */
+    for (i = 0; i < 8; i++) {  /* Do 8 bits in loop */
+       immap->im_cpm.cp_pbdat |= PB_SPISCK;    /* Raise SCK */
+       udelay(10);
+       if (immap->im_cpm.cp_pbdat & PB_SPIMISO)        /* Get a bit of data */
+           spi_byte |= bitpos; /* Set data accordingly */
+       immap->im_cpm.cp_pbdat &= ~PB_SPISCK;   /* Lower SCK */
+       udelay(10);
+       bitpos >>= 1;           /* Shift for next bit position */
+    }
+
+    return spi_byte;           /* Return the byte read */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif
diff --git a/rtc/m41t11.c b/rtc/m41t11.c
new file mode 100644 (file)
index 0000000..30a101c
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * (C) Copyright 2002
+ * Andrew May, Viasat Inc, amay@viasat.com
+ *
+ * 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
+ */
+
+/*
+ * M41T11 Serial Access Timekeeper(R) SRAM
+ * can you believe a trademark on that?
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+       I Don't have an example config file but this
+       is what should be done.
+
+#define CONFIG_RTC_M41T11 1
+#define CFG_I2C_RTC_ADDR 0x68
+#if 0
+#define CFG_M41T11_EXT_CENTURY_DATA
+#else
+#define CFG_M41T11_BASE_YEAR 2000
+#endif
+*/
+
+#if defined(CONFIG_RTC_M41T11) && defined(CFG_I2C_RTC_ADDR) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+#define DEBUG 1
+
+static unsigned bcd2bin (uchar n)
+{
+       return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+       return (((n / 10) << 4) | (n % 10));
+}
+
+
+/* ------------------------------------------------------------------------- */
+/*
+  these are simple defines for the chip local to here so they aren't too
+  verbose
+  DAY/DATE aren't nice but that is how they are on the data sheet
+*/
+#define RTC_SEC_ADDR       0x0
+#define RTC_MIN_ADDR       0x1
+#define RTC_HOUR_ADDR      0x2
+#define RTC_DAY_ADDR       0x3
+#define RTC_DATE_ADDR      0x4
+#define RTC_MONTH_ADDR     0x5
+#define RTC_YEARS_ADDR     0x6
+
+#define RTC_REG_CNT        7
+
+#define RTC_CONTROL_ADDR   0x7
+
+
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+
+#define REG_CNT            (RTC_REG_CNT+1)
+
+/*
+  you only get 00-99 for the year we will asume you
+  want from the year 2000 if you don't set the config
+*/
+#ifndef CFG_M41T11_BASE_YEAR
+#define CFG_M41T11_BASE_YEAR 2000
+#endif
+
+#else
+/* we will store extra year info in byte 9*/
+#define M41T11_YEAR_DATA   0x8
+#define M41T11_YEAR_SIZE   1
+#define REG_CNT            (RTC_REG_CNT+1+M41T11_YEAR_SIZE)
+#endif
+
+#define M41T11_STORAGE_SZ  (64-REG_CNT)
+
+void rtc_get (struct rtc_time *tmp)
+{
+        uchar data[RTC_REG_CNT];
+
+        i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+
+        if( data[RTC_SEC_ADDR] & 0x80 ){
+                printf( "m41t11 RTC Clock stopped!!!\n" );
+        }
+       tmp->tm_sec  = bcd2bin (data[RTC_SEC_ADDR]  & 0x7F);
+       tmp->tm_min  = bcd2bin (data[RTC_MIN_ADDR]  & 0x7F);
+       tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F);
+       tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F);
+       tmp->tm_mon  = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F);
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+        tmp->tm_year = CFG_M41T11_BASE_YEAR
+                + bcd2bin(data[RTC_YEARS_ADDR])
+                + ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
+#else
+        {
+                unsigned char cent;
+                i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+                if( !(data[RTC_HOUR_ADDR] & 0x80) ){
+                        printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
+                }
+                if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){
+                        /*century flip store off new year*/
+                        cent += 1;
+                        i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+                }
+                tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
+        }
+#endif
+       tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR]  & 0x07);
+       tmp->tm_yday = 0;
+       tmp->tm_isdst= 0;
+
+       debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+        uchar data[RTC_REG_CNT];
+
+       debug ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       data[RTC_SEC_ADDR]    = bin2bcd(tmp->tm_sec) &  0x7F;/*just in case*/
+       data[RTC_MIN_ADDR]    = bin2bcd(tmp->tm_min);
+       data[RTC_HOUR_ADDR]   = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/
+       data[RTC_DATE_ADDR]   = bin2bcd(tmp->tm_mday) & 0x3F;
+       data[RTC_MONTH_ADDR]  = bin2bcd(tmp->tm_mon);
+       data[RTC_DAY_ADDR]    = bin2bcd(tmp->tm_wday) & 0x07;
+
+        data[RTC_HOUR_ADDR]   |= 0x80;/*we will always use CEB*/
+
+        data[RTC_YEARS_ADDR]  = bin2bcd(tmp->tm_year%100);/*same thing either way*/
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+        if( ((tmp->tm_year - CFG_M41T11_BASE_YEAR) > 200) ||
+            (tmp->tm_year < CFG_M41T11_BASE_YEAR) ){
+                printf( "m41t11 RTC setting year out of range!!need recompile\n" );
+        }
+        data[RTC_HOUR_ADDR] |= (tmp->tm_year - CFG_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
+#else
+        {
+                unsigned char cent;
+                cent = tmp->tm_year ? tmp->tm_year / 100 : 0;
+                data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0;
+                i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
+        }
+#endif
+        i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+}
+
+void rtc_reset (void)
+{
+        unsigned char val;
+       /* clear all control & status registers */
+        i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
+        val = val & 0x7F;/*make sure we are running*/
+        i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
+
+        i2c_read(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+        val = val & 0x3F;/*turn off freq test keep calibration*/
+        i2c_write(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+}
+
+int rtc_store(int addr, unsigned char* data, int size)
+{
+        /*don't let things wrap onto the time on a write*/
+        if( (addr+size) >= M41T11_STORAGE_SZ )
+                return 1;
+        return i2c_write( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+}
+
+int rtc_recall(int addr, unsigned char* data, int size)
+{
+        return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+}
+
+#endif /* CONFIG_RTC_M41T11 && CFG_I2C_RTC_ADDR && CFG_CMD_DATE */
diff --git a/rtc/m48t35ax.c b/rtc/m48t35ax.c
new file mode 100644 (file)
index 0000000..6c38a53
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * (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
+ */
+
+/*
+ * Date & Time support for ST Electronics M48T35Ax RTC
+ */
+
+/*#define       DEBUG */
+
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <config.h>
+
+#if defined(CONFIG_RTC_M48T35A) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static uchar rtc_read  (uchar reg);
+static void  rtc_write (uchar reg, uchar val);
+static uchar bin2bcd   (unsigned int n);
+static unsigned bcd2bin(uchar c);
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+       uchar sec, min, hour, cent_day, date, month, year;
+       uchar ccr;                      /* Clock control register */
+
+       /* Lock RTC for read using clock control register */
+       ccr = rtc_read(0);
+       ccr = ccr | 0x40;
+       rtc_write(0, ccr);
+
+       sec     = rtc_read (0x1);
+       min     = rtc_read (0x2);
+       hour    = rtc_read (0x3);
+       cent_day= rtc_read (0x4);
+       date    = rtc_read (0x5);
+       month   = rtc_read (0x6);
+       year    = rtc_read (0x7);
+
+       /* UNLock RTC */
+       ccr = rtc_read(0);
+       ccr = ccr & 0xBF;
+       rtc_write(0, ccr);
+
+       debug ( "Get RTC year: %02x month: %02x date: %02x cent_day: %02x "
+               "hr: %02x min: %02x sec: %02x\n",
+               year, month, date, cent_day,
+               hour, min, sec );
+
+       tmp->tm_sec  = bcd2bin (sec  & 0x7F);
+       tmp->tm_min  = bcd2bin (min  & 0x7F);
+       tmp->tm_hour = bcd2bin (hour & 0x3F);
+       tmp->tm_mday = bcd2bin (date & 0x3F);
+       tmp->tm_mon  = bcd2bin (month & 0x1F);
+       tmp->tm_year = bcd2bin (year) + ((cent_day & 0x10) ? 2000 : 1900);
+       tmp->tm_wday = bcd2bin (cent_day & 0x07);
+       tmp->tm_yday = 0;
+       tmp->tm_isdst= 0;
+
+       debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+       uchar ccr;                      /* Clock control register */
+       uchar century;
+
+       debug ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       /* Lock RTC for write using clock control register */
+       ccr = rtc_read(0);
+       ccr = ccr | 0x80;
+       rtc_write(0, ccr);
+
+       rtc_write (0x07, bin2bcd(tmp->tm_year % 100));
+       rtc_write (0x06, bin2bcd(tmp->tm_mon));
+       rtc_write (0x05, bin2bcd(tmp->tm_mday));
+
+       century = ((tmp->tm_year >= 2000) ? 0x10 : 0) | 0x20;
+       rtc_write (0x04, bin2bcd(tmp->tm_wday) | century);
+
+       rtc_write (0x03, bin2bcd(tmp->tm_hour));
+       rtc_write (0x02, bin2bcd(tmp->tm_min ));
+       rtc_write (0x01, bin2bcd(tmp->tm_sec ));
+
+       /* UNLock RTC */
+       ccr = rtc_read(0);
+       ccr = ccr & 0x7F;
+       rtc_write(0, ccr);
+}
+
+void rtc_reset (void)
+{
+       uchar val;
+
+       /* Clear all clock control registers */
+       rtc_write (0x0, 0x80);          /* No Read Lock or calibration */
+
+       /* Clear stop bit */
+       val = rtc_read (0x1);
+       val &= 0x7f;
+       rtc_write(0x1, val);
+
+       /* Enable century / disable frequency test */
+       val = rtc_read (0x4);
+       val = (val & 0xBF) | 0x20;
+       rtc_write(0x4, val);
+
+       /* Clear write lock */
+       rtc_write(0x0, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read (uchar reg)
+{
+       uchar val;
+       val = *(unsigned char *)
+               ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg);
+       return val;
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+       *(unsigned char *)
+               ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg) = val;
+}
+
+static unsigned bcd2bin (uchar n)
+{
+       return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+       return (((n / 10) << 4) | (n % 10));
+}
+
+#endif /* CONFIG_RTC_M48T35A && CFG_CMD_DATE */
diff --git a/rtc/mc146818.c b/rtc/mc146818.c
new file mode 100644 (file)
index 0000000..1d65808
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter MPL AG Switzerland. d.peter@mpl.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for the MC146818 (PIXX4) RTC
+ */
+
+/*#define      DEBUG*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_MC146818) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static uchar rtc_read  (uchar reg);
+static void  rtc_write (uchar reg, uchar val);
+static uchar bin2bcd   (unsigned int n);
+static unsigned bcd2bin(uchar c);
+
+#define RTC_PORT_MC146818              CFG_ISA_IO_BASE_ADDRESS +  0x70
+#define RTC_SECONDS            0x00
+#define RTC_SECONDS_ALARM      0x01
+#define RTC_MINUTES                            0x02
+#define RTC_MINUTES_ALARM      0x03
+#define RTC_HOURS                                      0x04
+#define RTC_HOURS_ALARM                0x05
+#define RTC_DAY_OF_WEEK                0x06
+#define RTC_DATE_OF_MONTH      0x07
+#define RTC_MONTH                                      0x08
+#define RTC_YEAR                                               0x09
+#define RTC_CONFIG_A                           0x0A
+#define RTC_CONFIG_B                           0x0B
+#define RTC_CONFIG_C                           0x0C
+#define RTC_CONFIG_D                           0x0D
+
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+       uchar sec, min, hour, mday, wday, mon, year;
+  /* here check if rtc can be accessed */
+       while((rtc_read(RTC_CONFIG_A)&0x80)==0x80);
+       sec             = rtc_read (RTC_SECONDS);
+       min             = rtc_read (RTC_MINUTES);
+       hour    = rtc_read (RTC_HOURS);
+       mday    = rtc_read (RTC_DATE_OF_MONTH);
+       wday    = rtc_read (RTC_DAY_OF_WEEK);
+       mon             = rtc_read (RTC_MONTH);
+       year    = rtc_read (RTC_YEAR);
+#ifdef RTC_DEBUG
+       printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+               "hr: %02x min: %02x sec: %02x\n",
+               year, mon_cent, mday, wday,
+               hour, min, sec );
+       printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n",
+               rtc_read (RTC_CONFIG_D) & 0x3F,
+               rtc_read (RTC_HOURS_ALARM),
+               rtc_read (RTC_MINUTES_ALARM),
+               rtc_read (RTC_SECONDS_ALARM) );
+#endif
+       tmp->tm_sec  = bcd2bin (sec  & 0x7F);
+       tmp->tm_min  = bcd2bin (min  & 0x7F);
+       tmp->tm_hour = bcd2bin (hour & 0x3F);
+       tmp->tm_mday = bcd2bin (mday & 0x3F);
+       tmp->tm_mon  = bcd2bin (mon & 0x1F);
+       tmp->tm_year = bcd2bin (year);
+       tmp->tm_wday = bcd2bin (wday & 0x07);
+       if(tmp->tm_year<70)
+               tmp->tm_year+=2000;
+       else
+               tmp->tm_year+=1900;
+       tmp->tm_yday = 0;
+       tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+       printf ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+#ifdef RTC_DEBUG
+       printf ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+       rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
+
+       rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100));
+       rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon));
+
+       rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
+       rtc_write (RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
+       rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour));
+       rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min ));
+       rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
+       rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+
+}
+
+void rtc_reset (void)
+{
+       rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
+       rtc_write(RTC_CONFIG_A,0x20); /* Normal OP */
+       rtc_write(RTC_CONFIG_B,0x00);
+       rtc_write(RTC_CONFIG_B,0x00);
+       rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CFG_RTC_REG_BASE_ADDR
+/*
+ * use direct memory access
+ */
+static uchar rtc_read (uchar reg)
+{
+       return(in8(CFG_RTC_REG_BASE_ADDR+reg));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+       out8(CFG_RTC_REG_BASE_ADDR+reg, val);
+}
+#else
+static uchar rtc_read (uchar reg)
+{
+       out8(RTC_PORT_MC146818,reg);
+       return(in8(RTC_PORT_MC146818+1));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+       out8(RTC_PORT_MC146818,reg);
+       out8(RTC_PORT_MC146818+1,val);
+}
+#endif
+
+static unsigned bcd2bin (uchar n)
+{
+       return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+       return (((n / 10) << 4) | (n % 10));
+}
+
+#endif /* CONFIG_RTC_MC146818 && CFG_CMD_DATE */
diff --git a/rtc/mpc8xx.c b/rtc/mpc8xx.c
new file mode 100644 (file)
index 0000000..830e56e
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for internal RTC of MPC8xx
+ */
+
+/*#define      DEBUG*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_MPC8xx) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+       ulong tim;
+
+       tim = immr->im_sit.sit_rtc;
+
+       to_tm (tim, tmp);
+
+       debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+       volatile immap_t *immr = (immap_t *)CFG_IMMR;
+       ulong tim;
+
+       debug ( "Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
+                     tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       immr->im_sitk.sitk_rtck = KAPWR_KEY;
+       immr->im_sit.sit_rtc = tim;
+}
+
+void rtc_reset (void)
+{
+       return; /* nothing to do */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_RTC_MPC8xx && CFG_CMD_DATE */