Das U-Boot: Universal Boot Loader
authorwdenk <wdenk>
Sun, 3 Nov 2002 00:30:25 +0000 (00:30 +0000)
committerwdenk <wdenk>
Sun, 3 Nov 2002 00:30:25 +0000 (00:30 +0000)
board/RRvision/flash.c [new file with mode: 0644]
board/bmw/Makefile [new file with mode: 0644]
board/bmw/README [new file with mode: 0644]
board/bmw/m48t59y.c [new file with mode: 0644]
board/csb226/config.mk [new file with mode: 0644]
board/csb226/flash.c [new file with mode: 0644]

diff --git a/board/RRvision/flash.c b/board/RRvision/flash.c
new file mode 100644 (file)
index 0000000..06f7c4b
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * (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
+ */
+
+#define DEBUG
+
+#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);
+
+/*-----------------------------------------------------------------------
+ */
+
+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 & 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 = flash_get_size((vu_long *)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
+
+       flash_info[0].size = size;
+
+       return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+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;
+       default:                puts ("Unknown Vendor ");       break;
+       }
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       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;
+       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");
+       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              */
+       case AMD_ID_LV320T:
+               info->flash_id += FLASH_AM320T;
+               info->sector_count = 71;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+
+       case AMD_ID_LV320B:
+               info->flash_id += FLASH_AM320B;
+               info->sector_count = 71;
+               info->size = 0x00800000;
+               break;                          /* => 8 MB              */
+       default:
+               info->flash_id = FLASH_UNKNOWN;
+               return (0);                     /* => no or unknown flash */
+       }
+
+       /* set up sector start address table */
+       switch (value) {
+       case AMD_ID_LV400B:
+       case AMD_ID_LV800B:
+       case AMD_ID_LV160B:
+               /* 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;
+               }
+               break;
+       case AMD_ID_LV400T:
+       case AMD_ID_LV800T:
+       case AMD_ID_LV160T:
+               /* 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;
+               }
+               break;
+       case AMD_ID_LV320B:
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base;
+                       /*
+                        * The first 8 sectors are 8 kB,
+                        * all the other ones  are 64 kB
+                        */
+                       base += (i < 8)
+                               ?  2 * ( 8 << 10)
+                               :  2 * (64 << 10);
+               }
+               break;
+       case AMD_ID_LV320T:
+               for (i = 0; i < info->sector_count; i++) {
+                       info->start[i] = base;
+                       /*
+                        * The last 8 sectors are 8 kB,
+                        * all the other ones  are 64 kB
+                        */
+                       base += (i < (info->sector_count - 8))
+                               ?  2 * (64 << 10)
+                               :  2 * ( 8 << 10);
+               }
+               break;
+       default:
+               return (0);
+               break;
+       }
+
+       /* 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) {
+                       puts ("- missing\n");
+               } else {
+                       puts ("- 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 {
+               puts ("\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) {
+                       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];
+       addr[0] = 0x00F000F0;   /* reset bank */
+
+       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();
+
+       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/bmw/Makefile b/board/bmw/Makefile
new file mode 100644 (file)
index 0000000..46fe791
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2002
+# James F. Dougherty, Broadcom Corporation, jfd@broadcom.com
+# 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 $(TOPDIR)/config.mk
+
+LIB    = lib$(BOARD).a
+
+OBJS   = $(BOARD).o flash.o ns16550.o serial.o m48t59y.o
+
+SOBJS  = early_init.o
+
+$(LIB):        .depend $(OBJS) $(SOBJS)
+       $(AR) crv $@ $^
+
+#########################################################################
+
+.depend:       Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+               $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/board/bmw/README b/board/bmw/README
new file mode 100644 (file)
index 0000000..55ef56e
--- /dev/null
@@ -0,0 +1,340 @@
+Broadcom 95xx BMW CPCI Platform
+
+Overview
+=========
+BMW is an MPC8245 system controller featuring:
+* 3U CPCI Form Factor
+* BCM5703 Gigabit Ethernet
+* M48T59Y NVRAM
+* 16MB DOC
+* DIP Socket for Socketed DOC up to 1GB
+* 64MB SDRAM
+* LCD Display
+* Configurable Jumper options for 66,85, and 100Mhz memory bus
+
+
+BMW System Address Map
+======================
+BMW uses the MPC8245 CHRP Address MAP B found in the MPC8245 Users Manual
+(P.121, Section 3.1 Address Maps, Address Map B). Other I/O devices found
+onboard the processor module are listed briefly below:
+
+0x00000000 - 0x40000000 - 64MB SDRAM SIMM
+                          (Unregistered PC-100 SDRAM DIMM Module)
+
+0xFF000000 - 0xFF001FFF - M-Systems DiskOnChip (TM) 2000
+                          TSOP 16MB (MD2211-D16-V3)
+
+0x70000000 - 0x70001FFF - M-Systems DiskOnChip (TM) 2000
+                          DIP32 (Socketed 16MB - 1GB ) *
+                          NOTE: this is not populated on all systems.
+
+0x7c000000 - 0x7c000000 - Reset Register
+                          (Write 0 to reset)
+
+0x7c000001 - 0x7c000001 - System LED
+                          (Clear Bit 7 to turn on, set to shut off)
+
+0x7c000002 - 0x7c000002 - M48T59 Watchdog IRQ3
+                          (Clear bit 7 to reset, set to assert IRQ3)
+
+0x7c000003 - 0x7c000003 - M48T59 Write-Protect Register
+                          (Clear bit 7 to make R/W, set to make R/O)
+
+0x7c002000 - 0x7c002003 - Infineon OSRAM DLR2416 4 Character
+                          5x7 Dot Matrix Alphanumeric Display
+                          (Each byte sets the appropriate character)
+
+0x7c004000 - 0x7c005FF0 - SGS-THOMSON M48T59Y 8K NVRAM/RTC
+                          NVRAM Memory Region
+
+0x7c005FF0 - 0x7c005FFF - SGS-THOMSON M48T59Y 8K NVRAM/RTC
+                          Realtime Clock Registers
+
+0xFFF00000 - 0xFFF80000 - 512K PLCC32 BootRom
+                          (AMD AM29F040, ST 29W040B)
+
+0xFFF00100 -              System Reset Vector
+
+
+IO/MMU (BAT) Configuration
+======================
+The following Block-Address-Translation (BAT) configuration
+is recommended to access all I/O devices.
+
+#define CFG_IBAT0L  (0x00000000 | BATL_PP_10 | BATL_MEMCOHERENCE)
+#define CFG_IBAT0U  (0x00000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT1L  (0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT1U  (0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT2L  (0x80000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT2U  (0x80000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_IBAT3L  (0xF0000000 | BATL_PP_10 | BATL_CACHEINHIBIT)
+#define CFG_IBAT3U  (0xF0000000 | BATU_BL_256M | BATU_VS | BATU_VP)
+
+#define CFG_DBAT0L  CFG_IBAT0L
+#define CFG_DBAT0U  CFG_IBAT0U
+#define CFG_DBAT1L  CFG_IBAT1L
+#define CFG_DBAT1U  CFG_IBAT1U
+#define CFG_DBAT2L  CFG_IBAT2L
+#define CFG_DBAT2U  CFG_IBAT2U
+#define CFG_DBAT3L  CFG_IBAT3L
+#define CFG_DBAT3U  CFG_IBAT3U
+
+
+Interrupt Mappings
+======================
+BMW uses MPC8245 discrete mode interrupts. With the following
+hardwired mappings:
+
+BCM5701 10/100/1000 Ethernet           IRQ1
+CompactPCI Interrupt A                 IRQ2
+RTC/Watchdog Interrupt                 IRQ3
+Internal NS16552 UART                  IRQ4
+
+
+Jumper Settings
+======================
+
+BMW has a jumper (JP600) for selecting 66, 85, or 100Mhz memory bus.
+A jumper (X) is a 0 bit.
+
+Hence 66= 10110
+      85= 11000
+     100= 10000
+
+Jumper Settings for various Speeds
+=======================
+J1 J2 J3 J4 J5
+    X        X    66Mhz
+=======================
+J1 J2 J3 J4 J5
+       X  X  X    85Mhz
+=======================
+J1 J2 J3 J4 J5
+    X  X  X  X   100Mhz
+=======================
+
+Obviously, 100Mhz memory bus is recommended for optimum performance.
+
+
+U-Boot
+===============
+Broadcom BMW board is supported under config_BWM option.
+Supported features:
+
+- NVRAM setenv/getenv (used by Linux Kernel for configuration variables)
+- BCM570x TFTP file transfer support
+- LCD Display Support
+- DOC Support - (underway)
+
+
+
+U-Boot 1.2.0 (Aug  6 2002 - 17:44:48)
+
+CPU:   MPC8245 Revision 16.20 at 264 MHz: 16 kB I-Cache 16 kB D-Cache
+Board: BMW MPC8245/KAHLUA2 - CHRP (MAP B)
+Built: Aug  6 2002 at 17:44:37
+Local Bus at 66 MHz
+DRAM:  64 MB
+FLASH: 4095 MB
+In:    serial
+Out:   serial
+Err:   serial
+DOC:   No DiskOnChip found
+Hit any key to stop autoboot:  0
+=>printenv
+bootdelay=5
+baudrate=9600
+clocks_in_mhz=1
+hostname=switch-2
+bootcmd=tftp 100000 vmlinux.img;bootm
+gateway=10.16.64.1
+ethaddr=00:00:10:18:10:10
+nfsroot=172.16.40.111:/boot/root-fs
+filesize=5ec8c
+netmask=255.255.240.0
+ipaddr=172.16.40.114
+serverip=172.16.40.111
+root=/dev/nfs
+stdin=serial
+stdout=serial
+stderr=serial
+
+Environment size: 315/8172 bytes
+=>boot
+
+
+
+
+
+
+
+DevTools
+========
+ELDK
+        DENX Embedded Linux Development Kit
+
+ROM Emulator
+       Grammar Engine PROMICE P1160-90-AI21E (2MBx8bit, 90ns access time)
+       Grammar Engine PL32E 32Pin PLCC Emulation cables
+       Grammar Engine 3VA8CON (3Volt adapter with Short cables)
+       Grammar Engine FPNET PromICE Ethernet Adapters
+
+ICE
+       WRS/EST VisionICE-II (PPC8240)
+
+
+
+=>reset
+
+
+U-Boot 1.2.0 (Aug  6 2002 - 17:44:48)
+
+CPU:   MPC8245 Revision 16.20 at 264 MHz: 16 kB I-Cache 16 kB D-Cache
+Board: BMW MPC8245/KAHLUA2 - CHRP (MAP B)
+Built: Aug  6 2002 at 17:44:37
+Local Bus at 66 MHz
+DRAM:  64 MB
+FLASH: 4095 MB
+In:    serial
+Out:   serial
+Err:   serial
+DOC:   No DiskOnChip found
+Hit any key to stop autoboot:  0
+
+Broadcom BCM5701 1000Base-T: bus 0, device 13, function 0: MBAR=0x80100000
+BCM570x PCI Memory base address @0x80100000
+eth0:Broadcom BCM5701 1000Base-T: 100 Mbps half duplex link up, flow control OFF
+eth0: Broadcom BCM5701 1000Base-T @0x80100000,node addr 000010181010
+eth0: BCM5700 with Broadcom BCM5701 Integrated Copper transceiver found
+eth0: 32-bit PCI 33MHz, MTU: 1500,Rx Checksum ON
+ARP broadcast 1
+TFTP from server 172.16.40.111; our IP address is 172.16.40.114
+Filename 'vmlinux.img'.
+Load address: 0x100000
+Loading: #################################################################
+         ####################################T #############################
+         ######################
+done
+Bytes transferred = 777199 (bdbef hex)
+
+eth0:Broadcom BCM5701 1000Base-T,HALT,POWER DOWN,done - offline.
+## Booting image at 00100000 ...
+   Image Name:   vmlinux.bin.gz
+   Created:      2002-08-06   6:30:13 UTC
+   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+   Data Size:    777135 Bytes = 758 kB = 0 MB
+   Load Address: 00000000
+   Entry Point:  00000000
+   Verifying Checksum ... OK
+   Uncompressing Kernel Image ... OK
+Memory BAT mapping: BAT2=64Mb, BAT3=0Mb, residual: 0Mb
+Linux version 2.4.19-rc3 (jfd@que) (gcc version 2.95.3 20010111 (prerelease/franzo/20010111)) #168 Mon Aug 5 23:29:20 PDT 2002
+CPU:82xx: 32 I-Cache Block Size, 32 D-Cache Block Size PVR: 0x810000
+U-Boot Environment: 0xc01b08f0
+IP PNP: 802.3 Ethernet Address=<0:0:10:18:10:10>
+cpu0: MPC8245/KAHLUA-II : BMW Platform : 64MB RAM: BPLD Rev. 6e
+NOTICE: mounting root file system via NFS
+IP PNP: switch-2: eth0 IP 172.16.40.114/255.255.240.0 gateway 10.16.64.1 server 172.16.40.111
+On node 0 totalpages: 16384
+zone(0): 16384 pages.
+zone(1): 0 pages.
+zone(2): 0 pages.
+Kernel command line: console=ttyS0,9600 ip=172.16.40.114:172.16.40.111:10.16.64.1:255.255.240.0:switch-2:eth0 root=/dev/nfs rw nfsroot=172.16.40.111:/boot/root-fs,timeo=200,retrans=500 nfsaddrs=172.16.40.114:172.16.40.111
+root_dev_setup:/dev/nfs or 00:ff
+time_init: decrementer frequency = 16.501145 MHz
+Calibrating delay loop... 175.71 BogoMIPS
+Memory: 62572k available (1396k kernel code, 436k data, 100k init, 0k highmem)
+Dentry cache hash table entries: 8192 (order: 4, 65536 bytes)
+Inode cache hash table entries: 4096 (order: 3, 32768 bytes)
+Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
+Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)
+Page-cache hash table entries: 16384 (order: 4, 65536 bytes)
+POSIX conformance testing by UNIFIX
+PCI: Probing PCI hardware
+Linux NET4.0 for Linux 2.4
+Based upon Swansea University Computer Society NET3.039
+Initializing RT netlink socket
+Starting kswapd
+devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au)
+devfs: devfs_debug: 0x0
+devfs: boot_options: 0x1
+Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
+pty: 256 Unix98 ptys configured
+Serial driver version 5.05c (2001-07-08) with MANY_PORTS SHARE_IRQ SERIAL_PCI enabled
+Testing ttyS0 (0xf7f51500, 0xf7f51500)...
+Testing ttyS1 (0xfc004600, 0xfc004600)...
+ttyS00 at 0xf7f51500 (irq = 24) is a ST16650
+ttyS01 at 0xfc004600 (irq = 25) is a 16550A
+Real Time Clock Driver v1.10e
+RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
+loop: loaded (max 8 devices)
+TFFS 5.1.1 Flash disk driver for DiskOnChip
+Copyright (C) 1998,2001 M-Systems Flash Disk Pioneers Ltd.
+DOC device(s) found: 1
+fl_init: registered device at major: 100
+fl_geninit: registered device at major: 100
+Partition check:
+ fla: p1
+partition: /dev/fl/0: start_sect: 0,nr_sects: 32000 Fl_blk_size[]: 16000KB
+partition: /dev/fl/1: start_sect: 2,nr_sects: 31998 Fl_blk_size[]: 15999KB
+partition: /dev/fl/2: start_sect: 0,nr_sects: 0 Fl_blk_size[]: 0KB
+partition: /dev/fl/3: start_sect: 0,nr_sects: 0 Fl_blk_size[]: 0KB
+Broadcom Gigabit Ethernet Driver bcm5700 ver. 3.0.7 (07/17/02)
+eth0: Broadcom BCM5701 found at mem bfff0000, IRQ 1, node addr 000010181010
+eth0: Broadcom BCM5701 Integrated Copper transceiver found
+eth0: Scatter-gather ON, 64-bit DMA ON, Tx Checksum ON, Rx Checksum ON, 802.1Q VLAN ON
+bond0 registered without MII link monitoring, in bonding mode.
+rtc: unable to get misc minor
+NET4: Linux TCP/IP 1.0 for NET4.0
+IP Protocols: ICMP, UDP, TCP, IGMP
+IP: routing cache hash table of 512 buckets, 4Kbytes
+TCP: Hash tables configured (established 4096 bind 4096)
+bcm5700: eth0 NIC Link is UP, 100 Mbps half duplex
+IP-Config: Gateway not on directly connected network.
+NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
+802.1Q VLAN Support v1.7 Ben Greear <greearb@candelatech.com>
+All bugs added by David S. Miller <davem@redhat.com>
+Looking up port of RPC 100003/2 on 172.16.40.111
+Looking up port of RPC 100005/1 on 172.16.40.111
+VFS: Mounted root (nfs filesystem).
+Mounted devfs on /dev
+Freeing unused kernel memory: 100k init
+INIT: version 2.78 booting
+Mounting local filesystems...
+not mounted anything
+Setting up symlinks in /dev...done.
+Setting up extra devices in /dev...done.
+Starting devfsd...Started device management daemon for /dev
+INIT: Entering runlevel: 2
+Starting internet superserver: inetd.
+
+
+Welcome to Linux/PPC
+MPC8245/BMW
+
+
+
+switch-2 login: root
+Password:
+PAM_unix[49]: (login) session opened for user root by LOGIN(uid=0)
+Last login: Thu Nov 25 11:51:14 1920 on console
+
+
+Welcome to Linux/PPC
+MPC8245/BMW
+
+
+
+login[49]: ROOT LOGIN on `console'
+
+root@switch-2:~# cat /proc/cpuinfo
+cpu             : 82xx
+revision        : 16.20 (pvr 8081 1014)
+bogomips        : 175.71
+vendor          : Broadcom
+machine         : BMW/MPC8245
+root@switch-2:~#
diff --git a/board/bmw/m48t59y.c b/board/bmw/m48t59y.c
new file mode 100644 (file)
index 0000000..469f1ad
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * SGS M48-T59Y TOD/NVRAM Driver
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
+ *
+ * (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
+ *
+ * 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
+ */
+
+/*
+ * SGS M48-T59Y TOD/NVRAM Driver
+ *
+ * The SGS M48 an 8K NVRAM starting at offset M48_BASE_ADDR and
+ * continuing for 8176 bytes. After that starts the Time-Of-Day (TOD)
+ * registers which are used to set/get the internal date/time functions.
+ *
+ * This module implements Y2K compliance by taking full year numbers
+ * and translating back and forth from the TOD 2-digit year.
+ *
+ * NOTE: for proper interaction with an operating system, the TOD should
+ * be used to store Universal Coordinated Time (GMT) and timezone
+ * conversions should be used.
+ *
+ * Here is a diagram of the memory layout:
+ *
+ * +---------------------------------------------+ 0xffe0a000
+ * | Non-volatile memory                         | .
+ * |                                             | .
+ * | (8176 bytes of Non-volatile memory)         | .
+ * |                                             | .
+ * +---------------------------------------------+ 0xffe0bff0
+ * | Flags                                       |
+ * +---------------------------------------------+ 0xffe0bff1
+ * | Unused                                      |
+ * +---------------------------------------------+ 0xffe0bff2
+ * | Alarm Seconds                               |
+ * +---------------------------------------------+ 0xffe0bff3
+ * | Alarm Minutes                               |
+ * +---------------------------------------------+ 0xffe0bff4
+ * | Alarm Date                                  |
+ * +---------------------------------------------+ 0xffe0bff5
+ * | Interrupts                                  |
+ * +---------------------------------------------+ 0xffe0bff6
+ * | WatchDog                                    |
+ * +---------------------------------------------+ 0xffe0bff7
+ * | Calibration                                 |
+ * +---------------------------------------------+ 0xffe0bff8
+ * | Seconds                                     |
+ * +---------------------------------------------+ 0xffe0bff9
+ * | Minutes                                     |
+ * +---------------------------------------------+ 0xffe0bffa
+ * | Hours                                       |
+ * +---------------------------------------------+ 0xffe0bffb
+ * | Day                                         |
+ * +---------------------------------------------+ 0xffe0bffc
+ * | Date                                        |
+ * +---------------------------------------------+ 0xffe0bffd
+ * | Month                                       |
+ * +---------------------------------------------+ 0xffe0bffe
+ * | Year (2 digits only)                        |
+ * +---------------------------------------------+ 0xffe0bfff
+ */
+#include <common.h>
+#include <rtc.h>
+#include "bmw.h"
+
+/*
+ * Imported from mousse.h:
+ *
+ *   TOD_REG_BASE              Base of m48t59y TOD registers
+ *   SYS_TOD_UNPROTECT()       Disable NVRAM write protect
+ *   SYS_TOD_PROTECT()         Re-enable NVRAM write protect
+ */
+
+#define YEAR           0xf
+#define MONTH          0xe
+#define DAY            0xd
+#define DAY_OF_WEEK    0xc
+#define HOUR           0xb
+#define MINUTE         0xa
+#define SECOND         0x9
+#define CONTROL                0x8
+#define WATCH          0x7
+#define INTCTL         0x6
+#define WD_DATE                0x5
+#define WD_HOUR                0x4
+#define WD_MIN         0x3
+#define WD_SEC         0x2
+#define _UNUSED                0x1
+#define FLAGS          0x0
+
+#define M48_ADDR       ((volatile unsigned char *) TOD_REG_BASE)
+
+int m48_tod_init(void)
+{
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] = 0;
+    M48_ADDR[WATCH] = 0;
+    M48_ADDR[INTCTL] = 0;
+
+    /*
+     * If the oscillator is currently stopped (as on a new part shipped
+     * from the factory), start it running.
+     *
+     * Here is an example of the TOD bytes on a brand new M48T59Y part:
+     *         00 00 00 00 00 00 00 00 00 88 8c c3 bf c8 f5 01
+     */
+
+    if (M48_ADDR[SECOND] & 0x80)
+       M48_ADDR[SECOND] = 0;
+
+    /* Is battery low */
+    if ( M48_ADDR[FLAGS] & 0x10) {
+        printf("NOTICE: Battery low on Real-Time Clock (replace SNAPHAT).\n");
+    }
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+/*
+ * m48_tod_set
+ */
+
+static int to_bcd(int value)
+{
+    return value / 10 * 16 + value % 10;
+}
+
+static int from_bcd(int value)
+{
+    return value / 16 * 10 + value % 16;
+}
+
+static int day_of_week(int y, int m, int d)    /* 0-6 ==> Sun-Sat */
+{
+    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+    y -= m < 3;
+    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
+}
+
+/*
+ * Note: the TOD should store the current GMT
+ */
+
+int m48_tod_set(int year,              /* 1980-2079 */
+               int month,              /* 01-12 */
+               int day,                /* 01-31 */
+               int hour,               /* 00-23 */
+               int minute,             /* 00-59 */
+               int second)             /* 00-59 */
+
+{
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] |= 0x80; /* Set WRITE bit */
+
+    M48_ADDR[YEAR] = to_bcd(year % 100);
+    M48_ADDR[MONTH] = to_bcd(month);
+    M48_ADDR[DAY] = to_bcd(day);
+    M48_ADDR[DAY_OF_WEEK] = day_of_week(year, month, day) + 1;
+    M48_ADDR[HOUR] = to_bcd(hour);
+    M48_ADDR[MINUTE] = to_bcd(minute);
+    M48_ADDR[SECOND] = to_bcd(second);
+
+    M48_ADDR[CONTROL] &= ~0x80;        /* Clear WRITE bit */
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+/*
+ * Note: the TOD should store the current GMT
+ */
+
+int m48_tod_get(int *year,             /* 1980-2079 */
+               int *month,             /* 01-12 */
+               int *day,               /* 01-31 */
+               int *hour,              /* 00-23 */
+               int *minute,            /* 00-59 */
+               int *second)            /* 00-59 */
+{
+    int y;
+
+    SYS_TOD_UNPROTECT();
+
+    M48_ADDR[CONTROL] |= 0x40; /* Set READ bit */
+
+    y = from_bcd(M48_ADDR[YEAR]);
+    *year = y < 80 ? 2000 + y : 1900 + y;
+    *month = from_bcd(M48_ADDR[MONTH]);
+    *day = from_bcd(M48_ADDR[DAY]);
+    /* day_of_week = M48_ADDR[DAY_OF_WEEK] & 0xf; */
+    *hour = from_bcd(M48_ADDR[HOUR]);
+    *minute = from_bcd(M48_ADDR[MINUTE]);
+    *second = from_bcd(M48_ADDR[SECOND] & 0x7f);
+
+    M48_ADDR[CONTROL] &= ~0x40;        /* Clear READ bit */
+
+    SYS_TOD_PROTECT();
+
+    return 0;
+}
+
+int m48_tod_get_second(void)
+{
+    return from_bcd(M48_ADDR[SECOND] & 0x7f);
+}
+
+/*
+ * Watchdog function
+ *
+ *  If usec is 0, the watchdog timer is disarmed.
+ *
+ *  If usec is non-zero, the watchdog timer is armed (or re-armed) for
+ *    approximately usec microseconds (if the exact requested usec is
+ *    not supported by the chip, the next higher available value is used).
+ *
+ *  Minimum watchdog timeout = 62500 usec
+ *  Maximum watchdog timeout = 124 sec (124000000 usec)
+ */
+
+void m48_watchdog_arm(int usec)
+{
+    int                mpy, res;
+
+    SYS_TOD_UNPROTECT();
+
+    if (usec == 0) {
+       res = 0;
+       mpy = 0;
+    } else if (usec < 2000000) {       /* Resolution: 1/16s if below 2s */
+       res = 0;
+       mpy = (usec + 62499) / 62500;
+    } else if (usec < 8000000) {       /* Resolution: 1/4s if below 8s */
+       res = 1;
+       mpy = (usec + 249999) / 250000;
+    } else if (usec < 32000000) {      /* Resolution: 1s if below 32s */
+       res = 2;
+       mpy = (usec + 999999) / 1000000;
+    } else {                           /* Resolution: 4s up to 124s */
+       res = 3;
+       mpy = (usec + 3999999) / 4000000;
+       if (mpy > 31)
+           mpy = 31;
+    }
+
+    M48_ADDR[WATCH] = (0x80 |          /* Steer to RST signal (IRQ = N/C) */
+                      mpy << 2 |
+                      res);
+
+    SYS_TOD_PROTECT();
+}
+
+/*
+ * U-Boot RTC support.
+ */
+void
+rtc_get( struct rtc_time *tmp )
+{
+       m48_tod_get(&tmp->tm_year,
+                   &tmp->tm_mon,
+                   &tmp->tm_mday,
+                   &tmp->tm_hour,
+                   &tmp->tm_min,
+                   &tmp->tm_sec);
+       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 )
+{
+       m48_tod_set(tmp->tm_year,               /* 1980-2079 */
+                   tmp->tm_mon,                /* 01-12 */
+                   tmp->tm_mday,              /* 01-31 */
+                   tmp->tm_hour,               /* 00-23 */
+                   tmp->tm_min,                /* 00-59 */
+                   tmp->tm_sec);               /* 00-59 */
+
+#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
+
+}
+
+void
+rtc_reset (void)
+{
+  m48_tod_init();
+}
+
diff --git a/board/csb226/config.mk b/board/csb226/config.mk
new file mode 100644 (file)
index 0000000..939ffff
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Linux-Kernel is expected to be at c000'8000, entry c000'8000
+#
+# we load ourself to c170'0000, the upper 1 MB of second bank
+#
+# download areas is c800'0000
+#
+
+# This is the address where U-Boot lives in flash:
+#TEXT_BASE = 0
+
+# FIXME: armboot does only work correctly when being compiled
+# for the addresses _after_ relocation to RAM!! Otherwhise the
+# .bss segment is assumed in flash...
+TEXT_BASE = 0xa1fe0000
+
diff --git a/board/csb226/flash.c b/board/csb226/flash.c
new file mode 100644 (file)
index 0000000..0b95648
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * (C) Copyright 2002
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * (C) Copyright 2002
+ * 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
+ */
+
+#include <common.h>
+
+#define FLASH_BANK_SIZE 0x02000000
+#define MAIN_SECT_SIZE  0x40000         /* 2x16 = 256k per sector */
+
+flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+
+ulong flash_init(void)
+{
+    int i, j;
+    ulong size = 0;
+
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+    {
+       ulong flashbase = 0;
+       flash_info[i].flash_id =
+         (INTEL_MANUFACT & FLASH_VENDMASK) |
+         (INTEL_ID_28F128J3 & FLASH_TYPEMASK);
+       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);
+
+        switch (i)
+        {
+           case 0:
+               flashbase = PHYS_FLASH_1;
+                break;
+           default:
+               panic("configured to many flash banks!\n");
+                break;
+        }
+       for (j = 0; j < flash_info[i].sector_count; j++)
+       {
+           flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE;
+       }
+       size += flash_info[i].size;
+    }
+
+    /* Protect monitor and environment sectors
+     */
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_FLASH_BASE,
+                 CFG_FLASH_BASE + _armboot_end_data - _armboot_start,
+                 &flash_info[0]);
+
+    flash_protect(FLAG_PROTECT_SET,
+                 CFG_ENV_ADDR,
+                 CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+                 &flash_info[0]);
+
+    return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info  (flash_info_t *info)
+{
+    int i, j;
+
+    for (j=0; j<CFG_MAX_FLASH_BANKS; j++)
+    {
+        switch (info->flash_id & FLASH_VENDMASK)
+        {
+        case (INTEL_MANUFACT & FLASH_VENDMASK):
+               printf("Intel: ");
+               break;
+        default:
+               printf("Unknown Vendor ");
+               break;
+        }
+
+        switch (info->flash_id & FLASH_TYPEMASK)
+        {
+        case (INTEL_ID_28F128J3 & FLASH_TYPEMASK):
+               printf("28F128J3 (128Mbit)\n");
+               break;
+        default:
+               printf("Unknown Chip Type\n");
+               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");
+        info++;
+    }
+
+Done:
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+    int flag, prot, sect;
+    int rc = ERR_OK;
+
+    if (info->flash_id == FLASH_UNKNOWN)
+       return ERR_UNKNOWN_FLASH_TYPE;
+
+    if ((s_first < 0) || (s_first > s_last)) {
+       return ERR_INVAL;
+    }
+
+    if ((info->flash_id & FLASH_VENDMASK) !=
+       (INTEL_MANUFACT & FLASH_VENDMASK)) {
+       return ERR_UNKNOWN_FLASH_VENDOR;
+    }
+
+    prot = 0;
+    for (sect=s_first; sect<=s_last; ++sect) {
+       if (info->protect[sect]) {
+           prot++;
+       }
+    }
+    if (prot)
+       return ERR_PROTECTED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* Start erase on unprotected sectors */
+    for (sect = s_first; sect<=s_last && !ctrlc(); sect++) {
+
+       printf("Erasing sector %2d ... ", sect);
+
+       /* arm simple, non interrupt dependent timer */
+       reset_timer_masked();
+
+       if (info->protect[sect] == 0) { /* not protected */
+           /* vushort *addr = (vushort *)(info->start[sect]); */
+           ushort *addr = (ushort *)(info->start[sect]);
+
+           *addr = 0x20;       /* erase setup */
+           *addr = 0xD0;       /* erase confirm */
+
+           while ((*addr & 0x80) != 0x80) {
+               if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) {
+                   *addr = 0xB0; /* suspend erase */
+                   *addr = 0xFF;       /* reset to read mode */
+                   rc = ERR_TIMOUT;
+                   goto outahere;
+               }
+           }
+
+           /* clear status register command */
+           *addr = 0x50;
+           /* reset to read mode */
+           *addr = 0xFF;
+       }
+       printf("ok.\n");
+    }
+    if (ctrlc())
+      printf("User Interrupt!\n");
+
+outahere:
+
+    /* allow flash to settle - wait 10 ms */
+    udelay_masked(10000);
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash
+ */
+
+static int write_word (flash_info_t *info, ulong dest, ushort data)
+{
+    /* vushort *addr = (vushort *)dest, val; */
+    ushort *addr = (ushort *)dest, val;
+    int rc = ERR_OK;
+    int flag;
+
+    /* Check if Flash is (sufficiently) erased
+     */
+    if ((*addr & data) != data)
+        return ERR_NOT_ERASED;
+
+    /*
+     * Disable interrupts which might cause a timeout
+     * here. Remember that our exception vectors are
+     * at address 0 in the flash, and we don't want a
+     * (ticker) exception to happen while the flash
+     * chip is in programming mode.
+     */
+    flag = disable_interrupts();
+
+    /* clear status register command */
+    *addr = 0x50;
+
+    /* program set-up command */
+    *addr = 0x40;
+
+    /* latch address/data */
+    *addr = data;
+
+    /* arm simple, non interrupt dependent timer */
+    reset_timer_masked();
+
+    /* wait while polling the status register */
+    while(((val = *addr) & 0x80) != 0x80)
+    {
+       if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) {
+           rc = ERR_TIMOUT;
+           /* suspend program command */
+           *addr = 0xB0;
+           goto outahere;
+       }
+    }
+
+    if(val & 0x1A) {   /* check for error */
+        printf("\nFlash write error %02x at address %08lx\n",
+          (int)val, (unsigned long)dest);
+        if(val & (1<<3)) {
+           printf("Voltage range error.\n");
+           rc = ERR_PROG_ERROR;
+           goto outahere;
+        }
+        if(val & (1<<1)) {
+           printf("Device protect error.\n");
+           rc = ERR_PROTECTED;
+           goto outahere;
+        }
+        if(val & (1<<4)) {
+           printf("Programming error.\n");
+           rc = ERR_PROG_ERROR;
+           goto outahere;
+        }
+        rc = ERR_PROG_ERROR;
+        goto outahere;
+    }
+
+outahere:
+    /* read array command */
+    *addr = 0xFF;
+
+    if (flag)
+      enable_interrupts();
+
+    return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+    ulong cp, wp;
+    ushort data;
+    int l;
+    int i, rc;
+
+    wp = (addr & ~1);  /* 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 << 8);
+       }
+       for (; i<2 && cnt>0; ++i) {
+           data = (data >> 8) | (*src++ << 8);
+           --cnt;
+           ++cp;
+       }
+       for (; cnt==0 && i<2; ++i, ++cp) {
+           data = (data >> 8) | (*(uchar *)cp << 8);
+       }
+
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       wp += 2;
+    }
+
+    /*
+     * handle word aligned part
+     */
+    while (cnt >= 2) {
+       /* data = *((vushort*)src); */
+       data = *((ushort*)src);
+       if ((rc = write_word(info, wp, data)) != 0) {
+           return (rc);
+       }
+       src += 2;
+       wp  += 2;
+       cnt -= 2;
+    }
+
+    if (cnt == 0) {
+       return ERR_OK;
+    }
+
+    /*
+     * handle unaligned tail bytes
+     */
+    data = 0;
+    for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
+       data = (data >> 8) | (*src++ << 8);
+       --cnt;
+    }
+    for (; i<2; ++i, ++cp) {
+       data = (data >> 8) | (*(uchar *)cp << 8);
+    }
+
+    return write_word(info, wp, data);
+}