summaryrefslogtreecommitdiffstats
path: root/board/w7o
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-03 00:24:07 +0000
committerwdenk <wdenk>2002-11-03 00:24:07 +0000
commitc609719b8d1b2dca590e0ed499016d041203e403 (patch)
tree7ea1755d80903ff972f312a249eb856061d40e15 /board/w7o
parent5b1d713721c3ea02549940133f09236783dda1f9 (diff)
downloadtalos-obmc-uboot-c609719b8d1b2dca590e0ed499016d041203e403.tar.gz
talos-obmc-uboot-c609719b8d1b2dca590e0ed499016d041203e403.zip
Initial revision
Diffstat (limited to 'board/w7o')
-rw-r--r--board/w7o/flash.c941
-rw-r--r--board/w7o/fpga.c380
-rw-r--r--board/w7o/init.S264
-rw-r--r--board/w7o/post1.S745
-rw-r--r--board/w7o/post2.c109
-rw-r--r--board/w7o/vpd.c408
-rw-r--r--board/w7o/vpd.h135
-rw-r--r--board/w7o/w7o.c271
8 files changed, 3253 insertions, 0 deletions
diff --git a/board/w7o/flash.c b/board/w7o/flash.c
new file mode 100644
index 0000000000..0048476236
--- /dev/null
+++ b/board/w7o/flash.c
@@ -0,0 +1,941 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ * Based on code by:
+ * 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 <ppc4xx.h>
+#include <asm/processor.h>
+
+#include <watchdog.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_word8(flash_info_t *info, ulong dest, ulong data);
+static int write_word32 (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ int i;
+ unsigned long size_b0, base_b0;
+ unsigned long size_b1, base_b1;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Get Size of Boot and Main Flashes */
+ 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);
+ return 0;
+ }
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+ if (flash_info[1].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n",
+ size_b1, size_b1<<20);
+ return 0;
+ }
+
+ /* Calculate base addresses */
+ base_b0 = -size_b0;
+ base_b1 = -size_b1;
+
+ /* Setup offsets for Boot Flash */
+ flash_get_offsets (base_b0, &flash_info[0]);
+
+ /* Protect board level data */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ base_b0,
+ flash_info[0].start[1] - 1,
+ &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]);
+
+ /* Protect the FPGA image */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ FLASH_BASE1_PRELIM,
+ FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN - 1,
+ &flash_info[1]);
+
+ /* Protect the default boot image */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN,
+ FLASH_BASE1_PRELIM + CFG_FPGA_IMAGE_LEN + 0x600000 - 1,
+ &flash_info[1]);
+
+ /* Setup offsets for Main Flash */
+ flash_get_offsets (FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ return (size_b0 + size_b1);
+} /* end flash_init() */
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table - FOR BOOT ROM ONLY!!! */
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ }
+} /* end flash_get_offsets() */
+
+/*-----------------------------------------------------------------------
+ */
+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 ("1 x AMD "); break;
+ case FLASH_MAN_STM: printf ("1 x STM "); break;
+ case FLASH_MAN_INTEL: printf ("2 x Intel "); break;
+ default: printf ("Unknown Vendor ");
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
+ printf ("AM29LV040 (4096 Kbit, uniform sector size)\n");
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM)
+ printf ("M29W040B (4096 Kbit, uniform block size)\n");
+ else
+ printf ("UNKNOWN 29x040x (4096 Kbit, uniform sector size)\n");
+ break;
+ case FLASH_28F320J3A:
+ printf ("28F320J3A (32 Mbit = 128K x 32)\n");
+ break;
+ case FLASH_28F640J3A:
+ printf ("28F640J3A (64 Mbit = 128K x 64)\n");
+ break;
+ case FLASH_28F128J3A:
+ printf ("28F128J3A (128 Mbit = 128K x 128)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM) {
+ printf (" Size: %ld KB in %d Blocks\n",
+ info->size >> 10, info->sector_count);
+ } else {
+ 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 ");
+ printf (" %08lX%s%s",
+ info->start[i],
+ erased ? " E" : " ",
+ info->protect[i] ? "RO " : " "
+ );
+ }
+ printf ("\n");
+} /* end flash_print_info() */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong base = (ulong)addr;
+
+ /* Setup default type */
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count =0;
+ info->size = 0;
+
+ /* Test for Boot Flash */
+ if (base == FLASH_BASE0_PRELIM) {
+ unsigned char value;
+ volatile unsigned char * addr2 = (unsigned char *)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ *(addr2 + 0x555) = 0xaa;
+ *(addr2 + 0x2aa) = 0x55;
+ *(addr2 + 0x555) = 0x90;
+
+ /* Manufacture ID */
+ value = *addr2;
+ switch (value) {
+ case (unsigned char)AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (unsigned char)STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ default:
+ *addr2 = 0xf0; /* no or unknown flash */
+ return 0;
+ }
+
+ /* Device ID */
+ value = *(addr2 + 1);
+ switch (value) {
+ case (unsigned char)AMD_ID_LV040B:
+ case (unsigned char)STM_ID_29W040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512Kb */
+ default:
+ *addr2 = 0xf0; /* => no or unknown flash */
+ return 0;
+ }
+ }
+ else { /* MAIN Flash */
+ unsigned long value;
+ volatile unsigned long * addr2 = (unsigned long *)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ *addr2 = 0x90909090;
+
+ /* Manufacture ID */
+ value = *addr2;
+ switch (value) {
+ case (unsigned long)INTEL_MANUFACT:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ *addr2 = 0xff; /* no or unknown flash */
+ return 0;
+ }
+
+ /* Device ID - This shit is interleaved... */
+ value = *(addr2 + 1);
+ switch (value) {
+ case (unsigned long)INTEL_ID_28F320J3A:
+ info->flash_id += FLASH_28F320J3A;
+ info->sector_count = 32;
+ info->size = 0x00400000 * 2;
+ break; /* => 2 X 4 MB */
+ case (unsigned long)INTEL_ID_28F640J3A:
+ info->flash_id += FLASH_28F640J3A;
+ info->sector_count = 64;
+ info->size = 0x00800000 * 2;
+ break; /* => 2 X 8 MB */
+ case (unsigned long)INTEL_ID_28F128J3A:
+ info->flash_id += FLASH_28F128J3A;
+ info->sector_count = 128;
+ info->size = 0x01000000 * 2;
+ break; /* => 2 X 16 MB */
+ default:
+ *addr2 = 0xff; /* => no or unknown flash */
+ }
+ }
+
+ /* Make sure we don't exceed CFG_MAX_FLASH_SECT */
+ 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;
+ }
+
+ /* set up sector start address table */
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ break;
+ case FLASH_28F320J3A:
+ case FLASH_28F640J3A:
+ case FLASH_28F128J3A:
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00020000 * 2); /* 2 Banks */
+ break;
+ }
+
+ /* Test for Boot Flash */
+ if (base == FLASH_BASE0_PRELIM) {
+ volatile unsigned char *addr2;
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (AX .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr2 = (volatile unsigned char *)(info->start[i]);
+ info->protect[i] = *(addr2 + 2) & 1;
+ }
+
+ /* Restore read mode */
+ *(unsigned char *)base = 0xF0; /* Reset NORMAL Flash */
+ }
+ else { /* Main Flash */
+ volatile unsigned long *addr2;
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (AX .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr2 = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = *(addr2 + 2) & 0x1;
+ }
+
+ /* Restore read mode */
+ *(unsigned long *)base = 0xFFFFFFFF; /* Reset Flash */
+ }
+
+ return (info->size);
+} /* end flash_get_size() */
+
+/*-----------------------------------------------------------------------
+ */
+
+static int wait_for_DQ7(ulong addr, uchar cmp_val, ulong tout)
+{
+ int i;
+
+ volatile uchar *vaddr = (uchar *)addr;
+
+ /* Loop X times */
+ for (i = 1; i <= (100 * tout); i++) { /* Wait up to tout ms */
+ udelay(10);
+ /* Pause 10 us */
+
+ /* Check for completion */
+ if ((vaddr[0] & 0x80) == (cmp_val & 0x80)) {
+ return 0;
+ }
+
+ /* KEEP THE LUSER HAPPY - Print a dot every 1.1 seconds */
+ if (!(i % 110000))
+ putc('.');
+
+ /* Kick the dog if needed */
+ WATCHDOG_RESET();
+ }
+
+ return 1;
+} /* wait_for_DQ7() */
+
+/*-----------------------------------------------------------------------
+ */
+
+static int flash_erase8(flash_info_t *info, int s_first, int s_last)
+{
+ int tcode, rcode = 0;
+ volatile uchar *addr = (uchar *)(info->start[0]);
+ volatile uchar *sector_addr;
+ int flag, prot, sect;
+
+ /* Validate arguments */
+ 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;
+ }
+
+ /* Check for KNOWN flash type */
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ /* Check for protected sectors */
+ 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 erase on unprotected sectors */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ sector_addr = (uchar *)(info->start[sect]);
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM)
+ printf("Erasing block %p\n", sector_addr);
+ else
+ printf("Erasing sector %p\n", sector_addr);
+
+ /* Disable interrupts which might cause Flash to timeout */
+ flag = disable_interrupts();
+
+ *(addr + 0x555) = (uchar)0xAA;
+ *(addr + 0x2aa) = (uchar)0x55;
+ *(addr + 0x555) = (uchar)0x80;
+ *(addr + 0x555) = (uchar)0xAA;
+ *(addr + 0x2aa) = (uchar)0x55;
+ *sector_addr = (uchar)0x30; /* sector erase */
+
+ /*
+ * 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)!!
+ * Takes up to 6 seconds.
+ */
+ tcode = wait_for_DQ7((ulong)sector_addr, 0x80, 6000);
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* Make sure we didn't timeout */
+ if (tcode) {
+ printf ("Timeout\n");
+ rcode = 1;
+ }
+ }
+ }
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /* reset to read mode */
+ addr = (uchar *)info->start[0];
+ *addr = (uchar)0xF0; /* reset bank */
+
+ printf (" done\n");
+ return rcode;
+} /* end flash_erase8() */
+
+static int flash_erase32(flash_info_t *info, int s_first, int s_last)
+{
+ int flag, sect;
+ ulong start, now, last;
+ int prot = 0;
+
+ /* Validate arguments */
+ 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;
+ }
+
+ /* Check for KNOWN flash type */
+ if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+ printf ("Can erase only Intel flash types - aborted\n");
+ return 1;
+ }
+
+ /* Check for protected sectors */
+ 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++) {
+ WATCHDOG_RESET();
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_long *addr = (vu_long *)(info->start[sect]);
+ unsigned long status;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = 0x00500050; /* clear status register */
+ *addr = 0x00200020; /* erase setup */
+ *addr = 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) & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = 0x00B000B0; /* suspend erase */
+ *addr = 0x00FF00FF; /* reset to read mode */
+ return 1;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 990) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+ *addr = 0x00FF00FF; /* reset to read mode */
+ }
+ }
+ printf (" done\n");
+ return 0;
+} /* end flash_erase32() */
+
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040)
+ return flash_erase8(info, s_first, s_last);
+ else
+ return flash_erase32(info, s_first, s_last);
+} /* end flash_erase() */
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_buff8(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ ulong start;
+ int i, l, rc;
+
+ start = get_timer (0);
+
+ 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_word8(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_word8(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ if (get_timer(start) > 1000) { /* every second */
+ WATCHDOG_RESET();
+ putc ('.');
+ start = get_timer(0);
+ }
+ }
+
+ 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_word8(info, wp, data));
+} /* end write_buff8() */
+
+#define FLASH_WIDTH 4 /* flash bus width in bytes */
+static int write_buff32 (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+ ulong start;
+
+ start = get_timer (0);
+
+ 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_word32(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_word32(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ cnt -= FLASH_WIDTH;
+ if (get_timer(start) > 990) { /* every second */
+ putc ('.');
+ start = get_timer(0);
+ }
+ }
+
+ 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_word32(info, wp, data));
+} /* write_buff32() */
+
+int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ int retval;
+
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040)
+ retval = write_buff8(info, src, addr, cnt);
+ else
+ retval = write_buff32(info, src, addr, cnt);
+
+ return retval;
+} /* end write_buff() */
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+static int write_word8(flash_info_t *info, ulong dest, ulong data)
+{
+ volatile uchar *addr2 = (uchar *)(info->start[0]);
+ volatile uchar *dest2 = (uchar *)dest;
+ volatile uchar *data2 = (uchar *)&data;
+ int flag;
+ int i, tcode, rcode = 0;
+
+ /* Check if Flash is (sufficently) erased */
+ if ((*((volatile uchar *)dest) &
+ (uchar)data) != (uchar)data) {
+ return (2);
+ }
+
+ for (i=0; i < (4 / sizeof(uchar)); i++) {
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *(addr2 + 0x555) = (uchar)0xAA;
+ *(addr2 + 0x2aa) = (uchar)0x55;
+ *(addr2 + 0x555) = (uchar)0xA0;
+
+ dest2[i] = data2[i];
+
+ /* Wait for write to complete, up to 1ms */
+ tcode = wait_for_DQ7((ulong)&dest2[i], data2[i], 1);
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* Make sure we didn't timeout */
+ if (tcode) {
+ rcode = 1;
+ }
+ }
+
+ return rcode;
+} /* end write_word8() */
+
+static int write_word32(flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long *)dest;
+ ulong status;
+ ulong start;
+ 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();
+
+ *addr = 0x00400040; /* write setup */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (((status = *addr) & 0x00800080) != 0x00800080) {
+ WATCHDOG_RESET();
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *addr = 0x00FF00FF; /* restore read mode */
+ return (1);
+ }
+ }
+
+ *addr = 0x00FF00FF; /* restore read mode */
+
+ return (0);
+} /* end write_word32() */
+
+
+static int _flash_protect(flash_info_t *info, long sector)
+{
+ int i;
+ int flag;
+ ulong status;
+ int rcode = 0;
+ volatile long *addr = (unsigned long *)sector;
+
+ switch(info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F320J3A:
+ case FLASH_28F640J3A:
+ case FLASH_28F128J3A:
+ /* Disable interrupts which might cause Flash to timeout */
+ flag = disable_interrupts();
+
+ /* Issue command */
+ *addr = 0x00500050L; /* Clear the status register */
+ *addr = 0x00600060L; /* Set lock bit setup */
+ *addr = 0x00010001L; /* Set lock bit confirm */
+
+ /* Wait for command completion */
+ for (i = 0; i < 10; i++) { /* 75us timeout, wait 100us */
+ udelay(10);
+ if ((*addr & 0x00800080L) == 0x00800080L)
+ break;
+ }
+
+ /* Not successful? */
+ status = *addr;
+ if (status != 0x00800080L) {
+ printf("Protect %x sector failed: %x\n",
+ (uint)sector, (uint)status);
+ rcode = 1;
+ }
+
+ /* Restore read mode */
+ *addr = 0x00ff00ffL;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ break;
+ case FLASH_AM040: /* No soft sector protection */
+ break;
+ }
+
+ /* Turn protection on for this sector */
+ for (i = 0; i < info->sector_count; i++) {
+ if (info->start[i] == sector) {
+ info->protect[i] = 1;
+ break;
+ }
+ }
+
+ return rcode;
+} /* end _flash_protect() */
+
+static int _flash_unprotect(flash_info_t *info, long sector)
+{
+ int i;
+ int flag;
+ ulong status;
+ int rcode = 0;
+ volatile long *addr = (unsigned long *)sector;
+
+ switch(info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F320J3A:
+ case FLASH_28F640J3A:
+ case FLASH_28F128J3A:
+ /* Disable interrupts which might cause Flash to timeout */
+ flag = disable_interrupts();
+
+ *addr = 0x00500050L; /* Clear the status register */
+ *addr = 0x00600060L; /* Clear lock bit setup */
+ *addr = 0x00D000D0L; /* Clear lock bit confirm */
+
+ /* Wait for command completion */
+ for (i = 0; i < 80 ; i++) { /* 700ms timeout, wait 800 */
+ udelay(10000); /* Delay 10ms */
+ if ((*addr & 0x00800080L) == 0x00800080L)
+ break;
+ }
+
+ /* Not successful? */
+ status = *addr;
+ if (status != 0x00800080L) {
+ printf("Un-protect %x sector failed: %x\n",
+ (uint)sector, (uint)status);
+ *addr = 0x00ff00ffL;
+ rcode = 1;
+ }
+
+ /* restore read mode */
+ *addr = 0x00ff00ffL;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ break;
+ case FLASH_AM040: /* No soft sector protection */
+ break;
+ }
+
+ /*
+ * Fix Intel's little red wagon. Reprotect
+ * sectors that were protected before we undid
+ * protection on a specific sector.
+ */
+ for (i = 0; i < info->sector_count; i++) {
+ if (info->start[i] != sector) {
+ if (info->protect[i]) {
+ if (_flash_protect(info, info->start[i]))
+ rcode = 1;
+ }
+ }
+ else /* Turn protection off for this sector */
+ info->protect[i] = 0;
+ }
+
+ return rcode;
+} /* end _flash_unprotect() */
+
+
+int flash_real_protect(flash_info_t *info, long sector, int prot)
+{
+ int rcode;
+
+ if (prot)
+ rcode = _flash_protect(info, info->start[sector]);
+ else
+ rcode = _flash_unprotect(info, info->start[sector]);
+
+ return rcode;
+} /* end flash_real_protect() */
+
+/*-----------------------------------------------------------------------
+ */
+
diff --git a/board/w7o/fpga.c b/board/w7o/fpga.c
new file mode 100644
index 0000000000..e84123b907
--- /dev/null
+++ b/board/w7o/fpga.c
@@ -0,0 +1,380 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
+ * and
+ * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
+ *
+ * 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 "w7o.h"
+#include <asm/processor.h>
+#include "errors.h"
+
+static void
+fpga_img_write(unsigned long *src, unsigned long len, unsigned short *daddr)
+{
+ unsigned long i;
+ volatile unsigned long val;
+ volatile unsigned short *dest = daddr; /* volatile-bypass optimizer */
+
+ for (i = 0; i < len; i++, src++) {
+ val = *src;
+ *dest = (unsigned short)((val & 0xff000000L) >> 16);
+ *dest = (unsigned short)((val & 0x00ff0000L) >> 8);
+ *dest = (unsigned short)(val & 0x0000ff00L);
+ *dest = (unsigned short)((val & 0x000000ffL) << 8);
+ }
+
+ /* Terminate programming with 4 C clocks */
+ dest = daddr;
+ val = *(unsigned short *)dest;
+ val = *(unsigned short *)dest;
+ val = *(unsigned short *)dest;
+ val = *(unsigned short *)dest;
+
+}
+
+
+int
+fpgaDownload(unsigned char *saddr,
+ unsigned long size,
+ unsigned short *daddr)
+{
+ int i; /* index, intr disable flag */
+ int start; /* timer */
+ unsigned long greg, grego; /* GPIO & output register */
+ unsigned long length; /* image size in words */
+ unsigned long *source; /* image source addr */
+ unsigned short *dest; /* destination FPGA addr */
+ volatile unsigned short *ndest; /* temp dest FPGA addr */
+ volatile unsigned short val; /* temp val */
+ unsigned long cnfg = GPIO_XCV_CNFG; /* FPGA CNFG */
+ unsigned long eirq = GPIO_XCV_IRQ;
+ int retval = -1; /* Function return value */
+
+ /* Setup some basic values */
+ length = (size / 4) + 1; /* size in words, rounding UP
+ is OK */
+ source = (unsigned long *)saddr;
+ dest = (unsigned short *)daddr;
+
+ /* Get DCR output register */
+ grego = in32(IBM405GP_GPIO0_OR);
+
+ /* Reset FPGA */
+ grego &= ~GPIO_XCV_PROG; /* PROG line low */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ /* Setup timeout timer */
+ start = get_timer(0);
+
+ /* Wait for FPGA init line */
+ while(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT) { /* Wait INIT line low */
+ /* Check for timeout - 100us max, so use 3ms */
+ if (get_timer(start) > 3) {
+ printf(" failed to start init.\n");
+ log_warn(ERR_XINIT0); /* Don't halt */
+
+ /* Reset line stays low */
+ goto done; /* I like gotos... */
+ }
+ }
+
+ /* Unreset FPGA */
+ grego |= GPIO_XCV_PROG; /* PROG line high */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ /* Wait for FPGA end of init period . */
+ while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_INIT)) { /* Wait for INIT hi */
+
+ /* Check for timeout */
+ if (get_timer(start) > 3) {
+ printf(" failed to exit init.\n");
+ log_warn(ERR_XINIT1);
+
+ /* Reset FPGA */
+ grego &= ~GPIO_XCV_PROG; /* PROG line low */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ goto done;
+ }
+ }
+
+ /* Now program FPGA ... */
+ ndest = dest;
+ for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+ /* Toggle IRQ/GPIO */
+ greg = mfdcr(CPC0_CR0); /* get chip ctrl register */
+ greg |= eirq; /* toggle irq/gpio */
+ mtdcr(CPC0_CR0, greg); /* ... just do it */
+
+ /* turn on open drain for CNFG */
+ greg = in32(IBM405GP_GPIO0_ODR); /* get open drain register */
+ greg |= cnfg; /* CNFG open drain */
+ out32(IBM405GP_GPIO0_ODR, greg); /* .. just do it */
+
+ /* Turn output enable on for CNFG */
+ greg = in32(IBM405GP_GPIO0_TCR); /* get tristate register */
+ greg |= cnfg; /* CNFG tristate inactive */
+ out32(IBM405GP_GPIO0_TCR, greg); /* ... just do it */
+
+ /* Setup FPGA for programming */
+ grego &= ~cnfg; /* CONFIG line low */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ /*
+ * Program the FPGA
+ */
+ printf("\n destination: 0x%lx ", (unsigned long)ndest);
+
+ fpga_img_write(source, length, (unsigned short *)ndest);
+
+ /* Done programming */
+ grego |= cnfg; /* CONFIG line high */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ /* Turn output enable OFF for CNFG */
+ greg = in32(IBM405GP_GPIO0_TCR); /* get tristate register */
+ greg &= ~cnfg; /* CNFG tristate inactive */
+ out32(IBM405GP_GPIO0_TCR, greg); /* ... just do it */
+
+ /* Toggle IRQ/GPIO */
+ greg = mfdcr(CPC0_CR0); /* get chip ctrl register */
+ greg &= ~eirq; /* toggle irq/gpio */
+ mtdcr(CPC0_CR0, greg); /* ... just do it */
+
+ ndest = (unsigned short *)((char *)ndest + 0x00100000L); /* XXX - Next FPGA addr */
+ cnfg >>= 1; /* XXX - Next */
+ eirq >>= 1;
+ }
+
+ /* Terminate programming with 4 C clocks */
+ ndest = dest;
+ for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+ val = *ndest;
+ val = *ndest;
+ val = *ndest;
+ val = *ndest;
+ ndest = (unsigned short *)((char *)ndest + 0x00100000L);
+ }
+
+ /* Setup timer */
+ start = get_timer(0);
+
+ /* Wait for FPGA end of programming period . */
+ while(!(in32(IBM405GP_GPIO0_IR) & GPIO_XCV_DONE)) { /* Test DONE low */
+
+ /* Check for timeout */
+ if (get_timer(start) > 3) {
+ printf(" done failed to come high.\n");
+ log_warn(ERR_XDONE1);
+
+ /* Reset FPGA */
+ grego &= ~GPIO_XCV_PROG; /* PROG line low */
+ out32(IBM405GP_GPIO0_OR, grego);
+
+ goto done;
+ }
+ }
+
+ printf("\n FPGA load succeeded\n");
+ retval = 0; /* Program OK */
+
+done:
+ return retval;
+}
+
+/* FPGA image is stored in flash */
+extern flash_info_t flash_info[];
+
+int init_fpga(void)
+{
+ unsigned int i,j,ptr; /* General purpose */
+ unsigned char bufchar; /* General purpose character */
+ unsigned char *buf; /* Start of image pointer */
+ unsigned long len; /* Length of image */
+ unsigned char *fn_buf; /* Start of filename string */
+ unsigned int fn_len; /* Length of filename string */
+ unsigned char *xcv_buf; /* Pointer to start of image */
+ unsigned long xcv_len; /* Length of image */
+ unsigned long crc; /* 30bit crc in image */
+ unsigned long calc_crc; /* Calc'd 30bit crc */
+ int retval = -1;
+
+ /* Tell the world what we are doing */
+ printf("FPGA: ");
+
+ /*
+ * Get address of first sector where the FPGA
+ * image is stored.
+ */
+ buf = (unsigned char *)flash_info[1].start[0];
+
+ /*
+ * Get the stored image's CRC & length.
+ */
+ crc = *(unsigned long *)(buf+4); /* CRC is first long word */
+ len = *(unsigned long *)(buf+8); /* Image len is next long */
+
+ /* Pedantic */
+ if ((len < 0x133A4) || (len > 0x80000))
+ goto bad_image;
+
+ /*
+ * Get the file name pointer and length.
+ */
+ fn_len = (*(unsigned short *)(buf+12) & 0xff); /* filename length
+ is next short */
+ fn_buf = buf + 14;
+
+ /*
+ * Get the FPGA image pointer and length length.
+ */
+ xcv_buf = fn_buf + fn_len; /* pointer to fpga image */
+ xcv_len = len - 14 - fn_len; /* fpga image length */
+
+ /* Check for uninitialized FLASH */
+ if ((strncmp(buf, "w7o", 3)!=0) || (len > 0x0007ffffL) || (len == 0))
+ goto bad_image;
+
+ /*
+ * Calculate and Check the image's CRC.
+ */
+ calc_crc = crc32(0, xcv_buf, xcv_len);
+ if (crc != calc_crc) {
+ printf("\nfailed - bad CRC\n");
+ goto done;
+ }
+
+ /* Output the file name */
+ printf("file name : ");
+ for (i=0;i<fn_len;i++) {
+ bufchar = fn_buf[+i];
+ if (bufchar<' ' || bufchar>'~') bufchar = '.';
+ putc(bufchar);
+ }
+
+ /*
+ * find rest of display data
+ */
+ ptr = 15; /* Offset to ncd filename
+ length in fpga image */
+ j = xcv_buf[ptr]; /* Get len of ncd filename */
+ if (j > 32) goto bad_image;
+ ptr = ptr + j + 3; /* skip ncd filename string +
+ 3 bytes more bytes */
+
+ /*
+ * output target device string
+ */
+ j = xcv_buf[ptr++] - 1; /* len of targ str less term */
+ if (j > 32) goto bad_image;
+ printf("\n target : ");
+ for (i = 0; i < j; i++) {
+ bufchar = (xcv_buf[ptr++]);
+ if (bufchar<' ' || bufchar>'~') bufchar = '.';
+ putc(bufchar);
+ }
+
+ /*
+ * output compilation date string and time string
+ */
+ ptr += 3; /* skip 2 bytes */
+ printf("\n synth time : ");
+ j = (xcv_buf[ptr++] - 1); /* len of date str less term */
+ if (j > 32) goto bad_image;
+ for (i = 0; i < j; i++) {
+ bufchar = (xcv_buf[ptr++]);
+ if (bufchar<' ' || bufchar>'~') bufchar = '.';
+ putc(bufchar);
+ }
+
+ ptr += 3; /* Skip 2 bytes */
+ printf(" - ");
+ j = (xcv_buf[ptr++] - 1); /* slen = targ dev str len */
+ if (j > 32) goto bad_image;
+ for (i = 0; i < j; i++) {
+ bufchar = (xcv_buf[ptr++]);
+ if (bufchar<' ' || bufchar>'~') bufchar = '.';
+ putc(bufchar);
+ }
+
+ /*
+ * output crc and length strings
+ */
+ printf("\n len & crc : 0x%lx 0x%lx", len, crc);
+
+ /*
+ * Program the FPGA.
+ */
+ retval = fpgaDownload((unsigned char*)xcv_buf, xcv_len,
+ (unsigned short *)0xfd000000L);
+ return retval;
+
+bad_image:
+ printf("\n BAD FPGA image format @ %lx\n", flash_info[1].start[0]);
+ log_warn(ERR_XIMAGE);
+done:
+ return retval;
+}
+
+void test_fpga(unsigned short *daddr)
+{
+ int i;
+ volatile unsigned short *ndest = daddr;
+
+ for (i = 0; i < CONFIG_NUM_FPGAS; i++) {
+#if defined(CONFIG_W7OLMG)
+ ndest[0x7e] = 0x55aa;
+ if (ndest[0x7e] != 0x55aa)
+ log_warn(ERR_XRW1 + i);
+ ndest[0x7e] = 0xaa55;
+ if (ndest[0x7e] != 0xaa55)
+ log_warn(ERR_XRW1 + i);
+ ndest[0x7e] = 0xc318;
+ if (ndest[0x7e] != 0xc318)
+ log_warn(ERR_XRW1 + i);
+
+#elif defined(CONFIG_W7OLMC)
+ ndest[0x800] = 0x55aa;
+ ndest[0x801] = 0xaa55;
+ ndest[0x802] = 0xc318;
+ ndest[0x4800] = 0x55aa;
+ ndest[0x4801] = 0xaa55;
+ ndest[0x4802] = 0xc318;
+ if ((ndest[0x800] != 0x55aa) ||
+ (ndest[0x801] != 0xaa55) ||
+ (ndest[0x802] != 0xc318))
+ log_warn(ERR_XRW1 + (2 * i)); /* Auto gen error code */
+ if ((ndest[0x4800] != 0x55aa) ||
+ (ndest[0x4801] != 0xaa55) ||
+ (ndest[0x4802] != 0xc318))
+ log_warn(ERR_XRW2 + (2 * i)); /* Auto gen error code */
+
+#else
+# error "Unknown W7O board configuration"
+#endif
+ }
+
+ printf(" FPGA ready\n");
+ return;
+}
+
diff --git a/board/w7o/init.S b/board/w7o/init.S
new file mode 100644
index 0000000000..0abf21fe86
--- /dev/null
+++ b/board/w7o/init.S
@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ *****************************************************************************/
+#include <config.h>
+#include <ppc4xx.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/******************************************************************************
+ * Function: ext_bus_cntlr_init
+ *
+ * Description: Configures EBC Controller and a few basic chip selects.
+ *
+ * CS0 is setup to get the Boot Flash out of the addresss range
+ * so that we may setup a stack. CS7 is setup so that we can
+ * access and reset the hardware watchdog.
+ *
+ * IMPORTANT: For pass1 this code must run from
+ * cache since you can not reliably change a peripheral banks
+ * timing register (pbxap) while running code from that bank.
+ * For ex., since we are running from ROM on bank 0, we can NOT
+ * execute the code that modifies bank 0 timings from ROM, so
+ * we run it from cache.
+ *
+ * Notes: Does NOT use the stack.
+ *****************************************************************************/
+ .section ".text"
+ .align 2
+ .globl ext_bus_cntlr_init
+ .type ext_bus_cntlr_init, @function
+ext_bus_cntlr_init:
+ mflr r0
+ /********************************************************************
+ * Prefetch entire ext_bus_cntrl_init function into the icache.
+ * This is necessary because we are going to change the same CS we
+ * are executing from. Otherwise a CPU lockup may occur.
+ *******************************************************************/
+ bl ..getAddr
+..getAddr:
+ mflr r3 /* get address of ..getAddr */
+
+ /* Calculate number of cache lines for this function */
+ addi r4, 0, (((.Lfe0 - ..getAddr) / CFG_CACHELINE_SIZE) + 2)
+ mtctr r4
+..ebcloop:
+ icbt r0, r3 /* prefetch cache line for addr in r3*/
+ addi r3, r3, CFG_CACHELINE_SIZE /* move to next cache line */
+ bdnz ..ebcloop /* continue for $CTR cache lines */
+
+ /********************************************************************
+ * Delay to ensure all accesses to ROM are complete before changing
+ * bank 0 timings. 200usec should be enough.
+ * 200,000,000 (cycles/sec) X .000200 (sec) = 0x9C40 cycles.
+ *******************************************************************/
+ addis r3, 0, 0x0
+ ori r3, r3, 0xA000 /* wait 200us from reset */
+ mtctr r3
+..spinlp:
+ bdnz ..spinlp /* spin loop */
+
+ /********************************************************************
+ * Setup External Bus Controller (EBC).
+ *******************************************************************/
+ addi r3, 0, epcr
+ mtdcr ebccfga, r3
+ addis r4, 0, 0xb040 /* Device base timeout = 1024 cycles */
+ ori r4, r4, 0x0 /* Drive CS with external master */
+ mtdcr ebccfgd, r4
+
+ /********************************************************************
+ * Change PCIINT signal to PerWE
+ *******************************************************************/
+ mfdcr r4, cntrl1
+ ori r4, r4, 0x4000
+ mtdcr cntrl1, r4
+
+ /********************************************************************
+ * Memory Bank 0 (Flash Bank 0) initialization
+ *******************************************************************/
+ addi r3, 0, pb0ap
+ mtdcr ebccfga, r3
+ addis r4, 0, CFG_W7O_EBC_PB0AP@h
+ ori r4, r4, CFG_W7O_EBC_PB0AP@l
+ mtdcr ebccfgd, r4
+
+ addi r3, 0, pb0cr
+ mtdcr ebccfga, r3
+ addis r4, 0, CFG_W7O_EBC_PB0CR@h
+ ori r4, r4, CFG_W7O_EBC_PB0CR@l
+ mtdcr ebccfgd, r4
+
+ /********************************************************************
+ * Memory Bank 7 LEDs - NEEDED BECAUSE OF HW WATCHDOG AND LEDs.
+ *******************************************************************/
+ addi r3, 0, pb7ap
+ mtdcr ebccfga, r3
+ addis r4, 0, CFG_W7O_EBC_PB7AP@h
+ ori r4, r4, CFG_W7O_EBC_PB7AP@l
+ mtdcr ebccfgd, r4
+
+ addi r3, 0, pb7cr
+ mtdcr ebccfga, r3
+ addis r4, 0, CFG_W7O_EBC_PB7CR@h
+ ori r4, r4, CFG_W7O_EBC_PB7CR@l
+ mtdcr ebccfgd, r4
+
+ /* We are all done */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+.Lfe0: .size ext_bus_cntlr_init,.Lfe0-ext_bus_cntlr_init
+/* end ext_bus_cntlr_init() */
+
+/******************************************************************************
+ * Function: sdram_init
+ *
+ * Description: Configures SDRAM memory banks.
+ *
+ * Serial Presence Detect, "SPD," reads the SDRAM EEPROM
+ * via the IIC bus and then configures the SDRAM memory
+ * banks appropriately. If Auto Memory Configuration is
+ * is not used, it is assumed that a 4MB 11x8x2, non-ECC,
+ * SDRAM is soldered down.
+ *
+ * Notes: Expects that the stack is already setup.
+ *****************************************************************************/
+ .section ".text"
+ .align 2
+ .globl sdram_init
+ .type sdram_init, @function
+sdram_init:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save link register */
+
+ /*
+ * First call spd_sdram to try to init SDRAM according to the
+ * contents of the SPD EEPROM. If the SPD EEPROM is blank or
+ * erronious, spd_sdram returns 0 in R3.
+ */
+ bl spd_sdram
+ addic. r3, r3, 0 /* Check for error, save dram size */
+ bne ..sdri_done /* If it worked, we're done... */
+
+ /********************************************************************
+ * If SPD detection fails, we'll default to 4MB, 11x8x2, as this
+ * is the SMALLEST SDRAM size the 405 supports. We can do this
+ * because W7O boards have soldered on RAM, and there will always
+ * be some amount present. If we were using DIMMs, we should hang
+ * the board instead, since it doesn't have any RAM to continue
+ * running with.
+ *******************************************************************/
+
+ /*
+ * Disable memory controller to allow
+ * values to be changed.
+ */
+ addi r3, 0, mem_mcopt1
+ mtdcr memcfga, r3
+ addis r4, 0, 0x0
+ ori r4, r4, 0x0
+ mtdcr memcfgd, r4
+
+ /*
+ * Set MB0CF for ext bank 0. (0-4MB) Address Mode 5 since 11x8x2
+ * All other banks are disabled.
+ */
+ addi r3, 0, mem_mb0cf
+ mtdcr memcfga, r3
+ addis r4, 0, 0x0000 /* BA=0x0, SZ=4MB */
+ ori r4, r4, 0x8001 /* Mode is 5, 11x8x2or4, BE=Enabled */
+ mtdcr memcfgd, r4
+
+ /* Clear MB1CR,MB2CR,MB3CR to turn other banks off */
+ addi r4, 0, 0 /* Zero the data reg */
+
+ addi r3, r3, 4 /* Point to MB1CF reg */
+ mtdcr memcfga, r3 /* Set the address */
+ mtdcr memcfgd, r4 /* Zero the reg */
+
+ addi r3, r3, 4 /* Point to MB2CF reg */
+ mtdcr memcfga, r3 /* Set the address */
+ mtdcr memcfgd, r4 /* Zero the reg */
+
+ addi r3, r3, 4 /* Point to MB3CF reg */
+ mtdcr memcfga, r3 /* Set the address */
+ mtdcr memcfgd, r4 /* Zero the reg */
+
+ /********************************************************************
+ * Set the SDRAM Timing reg, SDTR1 and the refresh timer reg, RTR.
+ * To set the appropriate timings, we assume sdram is
+ * 100MHz (pc100 compliant).
+ *******************************************************************/
+
+ /*
+ * Set up SDTR1
+ */
+ addi r3, 0, mem_sdtr1
+ mtdcr memcfga, r3
+ addis r4, 0, 0x0086 /* SDTR1 value for 100Mhz */
+ ori r4, r4, 0x400D
+ mtdcr memcfgd, r4
+
+ /*
+ * Set RTR
+ */
+ addi r3, 0, mem_rtr
+ mtdcr memcfga, r3
+ addis r4, 0, 0x05F0 /* RTR refresh val = 15.625ms@100Mhz */
+ mtdcr memcfgd, r4
+
+ /********************************************************************
+ * Delay to ensure 200usec have elapsed since reset. Assume worst
+ * case that the core is running 200Mhz:
+ * 200,000,000 (cycles/sec) X .000200 (sec) = 0x9C40 cycles
+ *******************************************************************/
+ addis r3, 0, 0x0000
+ ori r3, r3, 0xA000 /* Wait 200us from reset */
+ mtctr r3
+..spinlp2:
+ bdnz ..spinlp2 /* spin loop */
+
+ /********************************************************************
+ * Set memory controller options reg, MCOPT1.
+ *******************************************************************/
+ addi r3, 0, mem_mcopt1
+ mtdcr memcfga, r3
+ addis r4, 0, 0x80E0 /* DC_EN=1,SRE=0,PME=0,MEMCHK=0 */
+ ori r4, r4, 0x0000 /* REGEN=0,DRW=00,BRPF=01,ECCDD=1 */
+ mtdcr memcfgd, r4 /* EMDULR=1 */
+
+..sdri_done:
+ /* restore and return */
+ lwz r0, +12(r1) /* Get saved link register */
+ addi r1, r1, +8 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+.Lfe1: .size sdram_init,.Lfe1-sdram_init
+/* end sdram_init() */
+
diff --git a/board/w7o/post1.S b/board/w7o/post1.S
new file mode 100644
index 0000000000..d510cca1f6
--- /dev/null
+++ b/board/w7o/post1.S
@@ -0,0 +1,745 @@
+/*
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, william.hunter@mediaone.net
+ * and
+ * 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
+ */
+/*
+ * Description:
+ * Routine to exercise memory for the bringing up of our boards.
+ */
+#include <config.h>
+#include <ppc4xx.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#include <watchdog.h>
+
+#include "errors.h"
+
+#define _ASMLANGUAGE
+
+ .globl test_sdram
+ .globl test_led
+ .globl log_stat
+ .globl log_warn
+ .globl log_err
+ .globl temp_uart_init
+ .globl post_puts
+ .globl disp_hex
+
+/*****************************************************
+******* Text Strings for low level printing ******
+******* In section got2 *******
+*****************************************************/
+
+/*
+ * Define the text strings for errors and warnings.
+ * Switch to .data section.
+ */
+ .section ".data"
+err_str: .asciz "*** POST ERROR = "
+warn_str: .asciz "*** POST WARNING = "
+end_str: .asciz "\r\n"
+
+/*
+ * Enter the labels in Global Entry Table (GOT).
+ * Switch to .got2 section.
+ */
+ START_GOT
+ GOT_ENTRY(err_str)
+ GOT_ENTRY(warn_str)
+ GOT_ENTRY(end_str)
+ END_GOT
+
+/*
+ * Switch back to .text section.
+ */
+ .text
+
+/****************************************
+ ****************************************
+ ******** LED register test ********
+ ****************************************
+ ***************************************/
+test_led:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r4, +8(r1) /* save R4 */
+
+ WATCHDOG_RESET /* Reset the watchdog */
+
+ addi r3, 0, ERR_FF /* first test value is ffff */
+ addi r4, r3, 0 /* save copy of pattern */
+ bl set_led /* store first test value */
+ bl get_led /* read it back */
+ xor. r4, r4, r3 /* compare to original */
+#if defined(CONFIG_W7OLMC)
+ andi. r4, r4, 0x00ff /* lmc has 8 bits */
+#else
+ andi. r4, r4, 0xffff /* lmg has 16 bits */
+#endif
+ beq LED2 /* next test */
+ addi r3, 0, ERR_LED /* error code = 1 */
+ bl log_err /* display error and halt */
+LED2: addi r3, 0, ERR_00 /* 2nd test value is 0000 */
+ addi r4, r3, 0 /* save copy of pattern */
+ bl set_led /* store first test value */
+ bl get_led /* read it back */
+ xor. r4, r4, r3 /* compare to original */
+#if defined(CONFIG_W7OLMC)
+ andi. r4, r4, 0x00ff /* lmc has 8 bits */
+#else
+ andi. r4, r4, 0xffff /* lmg has 16 bits */
+#endif
+ beq LED3 /* next test */
+ addi r3, 0, ERR_LED /* error code = 1 */
+ bl log_err /* display error and halt */
+
+LED3: /* restore stack and return */
+ lwz r0, +16(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ lwz r4, +8(r1) /* restore r4 */
+ addi r1, r1, +12 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+/****************************************
+ ****************************************
+ ******** SDRAM TESTS ********
+ ****************************************
+ ***************************************/
+test_sdram:
+ /* called with mem size in r3 */
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -16(r1) /* Save back chain and move SP */
+ stw r0, +20(r1) /* Save link register */
+ stmw r30, +8(r1) /* save R30,R31 */
+ /* r30 is log2(mem size) */
+ /* r31 is mem size */
+
+ /* take log2 of total mem size */
+ addi r31, r3, 0 /* save total mem size */
+ addi r30, 0, 0 /* clear r30 */
+l2_loop:
+ srwi. r31, r31, 1 /* shift right 1 */
+ addi r30, r30, 1 /* count shifts */
+ bne l2_loop /* loop till done */
+ addi r30, r30, -1 /* correct for over count */
+ addi r31, r3, 0 /* save original size */
+
+ /* now kick the dog and test the mem */
+ WATCHDOG_RESET /* Reset the watchdog */
+ bl Data_Buster /* test crossed/shorted data lines */
+ addi r3, r30, 0 /* get log2(memsize) */
+ addi r4, r31, 0 /* get memsize */
+ bl Ghost_Buster /* test crossed/shorted addr lines */
+ addi r3, r31, 0 /* get mem size */
+ bl Bit_Buster /* check for bad internal bits */
+
+ /* restore stack and return */
+ lmw r30, +8(r1) /* Restore r30, r31 */
+ lwz r0, +20(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +16 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+
+/****************************************
+ ******** sdram data bus test ********
+ ***************************************/
+Data_Buster:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -24(r1) /* Save back chain and move SP */
+ stw r0, +28(r1) /* Save link register */
+ stmw r28, 8(r1) /* save r28 - r31 on stack */
+ /* r31 i/o register */
+ /* r30 sdram base address */
+ /* r29 5555 syndrom */
+ /* r28 aaaa syndrom */
+
+ /* set up led register for this test */
+ addi r3, 0, ERR_RAMG /* set led code to 1 */
+ bl log_stat /* store test value */
+ /* now test the dram data bus */
+ xor r30, r30, r30 /* load r30 with base addr of sdram */
+ addis r31, 0, 0x5555 /* load r31 with test value */
+ ori r31, r31, 0x5555
+ stw r31,0(r30) /* sto the value */
+ lwz r29,0(r30) /* read it back */
+ xor r29,r31,r29 /* compare it to original */
+ addis r31, 0, 0xaaaa /* load r31 with test value */
+ ori r31, r31, 0xaaaa
+ stw r31,0(r30) /* sto the value */
+ lwz r28,0(r30) /* read it back */
+ xor r28,r31,r28 /* compare it to original */
+ or r3,r28,r29 /* or together both error terms */
+ /*
+ * Now that we have the error bits,
+ * we have to decide which part they are in.
+ */
+ bl get_idx /* r5 is now index to error */
+ addi r3, r3, ERR_RAMG
+ cmpwi r3, ERR_RAMG /* check for errors */
+ beq db_done /* skip if no errors */
+ bl log_err /* log the error */
+
+db_done:
+ lmw r28, 8(r1) /* restore r28 - r31 from stack */
+ lwz r0, +28(r1) /* Get saved link register */
+ addi r1, r1, +24 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+
+/****************************************************
+ ******** test for address ghosting in dram ********
+ ***************************************************/
+
+Ghost_Buster:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -36(r1) /* Save back chain and move SP */
+ stw r0, +40(r1) /* Save link register */
+ stmw r25, 8(r1) /* save r25 - r31 on stack */
+ /* r31 = scratch register */
+ /* r30 is main referance loop counter,
+ 0 to 23 */
+ /* r29 is ghost loop count, 0 to 22 */
+ /* r28 is referance address */
+ /* r27 is ghost address */
+ /* r26 is log2 (mem size) =
+ number of byte addr bits */
+ /* r25 is mem size */
+
+ /* save the log2(mem size) and mem size */
+ addi r26, r3, 0 /* r26 is number of byte addr bits */
+ addi r25, r4, 0 /* r25 is mem size in bytes */
+
+ /* set the leds for address ghost test */
+ addi r3, 0, ERR_ADDG
+ bl set_led
+
+ /* first fill memory with zeros */
+ srwi r31, r25, 2 /* convert bytes to longs */
+ mtctr r31 /* setup byte counter */
+ addi r28, 0, 0 /* start at address at 0 */
+ addi r31, 0, 0 /* data value = 0 */
+clr_loop:
+ stw r31, 0(r28) /* Store zero value */
+ addi r28, r28, 4 /* Increment to next word */
+ andi. r27, r28, 0xffff /* check for 2^16 loops */
+ bne clr_skip /* if not there, then skip */
+ WATCHDOG_RESET /* kick the dog every now and then */
+clr_skip:
+ bdnz clr_loop /* Round and round... */
+
+ /* now do main test */
+ addi r30, 0, 0 /* start referance counter at 0 */
+outside:
+ /*
+ * Calculate the referance address
+ * the referance address is calculated by setting the (r30-1)
+ * bit of the base address
+ * when r30=0, the referance address is the base address.
+ * thus the sequence 0,1,2,4,8,..,2^(n-1)
+ * setting the bit is done with the following shift functions.
+ */
+ WATCHDOG_RESET /* Reset the watchdog */
+
+ addi r31, 0, 1 /* r31 = 1 */
+ slw r28, r31, r30 /* set bit coresponding to loop cnt */
+ srwi r28, r28, 1 /* then shift it right one so */
+ /* we start at location 0 */
+ /* fill referance address with Fs */
+ addi r31, 0, 0x00ff /* r31 = one byte of set bits */
+ stb r31,0(r28) /* save ff in referance address */
+
+ /* ghost (inner) loop, now check all posible ghosted addresses */
+ addi r29, 0, 0 /* start ghosted loop counter at 0 */
+inside:
+ /*
+ * Calculate the ghost address by flipping one
+ * bit of referance address. This gives the
+ * sequence 1,2,4,8,...,2^(n-1)
+ */
+ addi r31, 0, 1 /* r31 = 1 */
+ slw r27, r31, r29 /* set bit coresponding to loop cnt */
+ xor r27, r28, r27 /* ghost address = ref addr with
+ bit flipped*/
+
+ /* now check for ghosting */
+ lbz r31,0(r27) /* get content of ghost addr */
+ cmpwi r31, 0 /* compare read value to 0 */
+ bne Casper /* we found a ghost! */
+
+ /* now close ghost ( inner ) loop */
+ addi r29, r29, 1 /* increment inner loop counter */
+ cmpw r29, r26 /* check for last inner loop */
+ blt inside /* do more inner loops */
+
+ /* now close referance ( outer ) loop */
+ addi r31, 0, 0 /* r31 = zero */
+ stb r31, 0(28) /* zero out the altered address loc. */
+ /*
+ * Increment and check for end, count is zero based.
+ * With the ble, this gives us one more loops than
+ * address bits for sequence 0,1,2,4,8,...2^(n-1)
+ */
+ addi r30, r30, 1 /* increment outer loop counter */
+ cmpw r30, r26 /* check for last inner loop */
+ ble outside /* do more outer loops */
+
+ /* were done, lets go home */
+ b gb_done
+Casper: /* we found a ghost !! */
+ addi r3, 0, ERR_ADDF /* get indexed error message */
+ bl log_err /* log error led error code */
+gb_done: /* pack your bags, and go home */
+ lmw r25, 8(r1) /* restore r25 - r31 from stack */
+ lwz r0, +40(r1) /* Get saved link register */
+ addi r1, r1, +36 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+/****************************************************
+ ******** SDRAM data fill tests **********
+ ***************************************************/
+Bit_Buster:
+ /* called with mem size in r3 */
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -16(r1) /* Save back chain and move SP */
+ stw r0, +20(r1) /* Save link register */
+ stw r4, +8(r1) /* save R4 */
+ stw r5, +12(r1) /* save r5 */
+
+ addis r5, r3, 0 /* save mem size */
+
+ /* Test 55555555 */
+ addi r3, 0, ERR_R55G /* set up error code in case we fail */
+ bl log_stat /* store test value */
+ addis r4, 0, 0x5555
+ ori r4, r4, 0x5555
+ bl fill_test
+
+ /* Test aaaaaaaa */
+ addi r3, 0, ERR_RAAG /* set up error code in case we fail */
+ bl log_stat /* store test value */
+ addis r4, 0, 0xAAAA
+ ori r4, r4, 0xAAAA
+ bl fill_test
+
+ /* Test 00000000 */
+ addi r3, 0, ERR_R00G /* set up error code in case we fail */
+ bl log_stat /* store test value */
+ addis r4, 0, 0
+ ori r4, r4, 0
+ bl fill_test
+
+ /* restore stack and return */
+ lwz r5, +12(r1) /* restore r4 */
+ lwz r4, +8(r1) /* restore r4 */
+ lwz r0, +20(r1) /* Get saved link register */
+ addi r1, r1, +16 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+
+
+/****************************************************
+ ******** fill test ********
+ ***************************************************/
+/* tests memory by filling with value, and reading back */
+/* r5 = Size of memory in bytes */
+/* r4 = Value to write */
+/* r3 = Error code */
+fill_test:
+ mflr r0 /* Get link register */
+ stwu r1, -32(r1) /* Save back chain and move SP */
+ stw r0, +36(r1) /* Save link register */
+ stmw r27, 8(r1) /* save r27 - r31 on stack */
+ /* r31 - scratch register */
+ /* r30 - memory address */
+ mr r27, r3
+ mr r28, r4
+ mr r29, r5
+
+ WATCHDOG_RESET /* Reset the watchdog */
+
+ /* first fill memory with Value */
+ srawi r31, r29, 2 /* convert bytes to longs */
+ mtctr r31 /* setup counter */
+ addi r30, 0, 0 /* Make r30 = addr 0 */
+ft_0: stw r28, 0(r30) /* Store value */
+ addi r30, r30, 4 /* Increment to next word */
+ andi. r31, r30, 0xffff /* check for 2^16 loops */
+ bne ft_0a /* if not there, then skip */
+ WATCHDOG_RESET /* kick the dog every now and then */
+ft_0a: bdnz ft_0 /* Round and round... */
+
+ WATCHDOG_RESET /* Reset the watchdog */
+
+ /* Now confirm Value is in memory */
+ srawi r31, r29, 2 /* convert bytes to longs */
+ mtctr r31 /* setup counter */
+ addi r30, 0, 0 /* Make r30 = addr 0 */
+ft_1: lwz r31, 0(r30) /* get value from memory */
+ xor. r31, r31, r28 /* Writen = Read ? */
+ bne ft_err /* If bad, than halt */
+ addi r30, r30, 4 /* Increment to next word */
+ andi. r31, r30, 0xffff /* check for 2^16 loops*/
+ bne ft_1a /* if not there, then skip */
+ WATCHDOG_RESET /* kick the dog every now and then */
+ft_1a: bdnz ft_1 /* Round and round... */
+
+ WATCHDOG_RESET /* Reset the watchdog */
+
+ b fill_done /* restore and return */
+
+ft_err: addi r29, r27, 0 /* save current led code */
+ addi r27, r31, 0 /* get pattern in r27 */
+ bl get_idx /* get index from r27 */
+ add r27, r27, r29 /* add index to old led code */
+ bl log_err /* output led err code, halt CPU */
+
+fill_done:
+ lmw r27, 8(r1) /* restore r27 - r31 from stack */
+ lwz r0, +36(r1) /* Get saved link register */
+ addi r1, r1, +32 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+
+/****************************************************
+ ******* get error index from r3 pattern ********
+ ***************************************************/
+get_idx: /* r3 = (MSW(r3) !=0)*2 +
+ (LSW(r3) !=0) */
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r4, +8(r1) /* save R4 */
+
+ andi. r4, r3, 0xffff /* check for lower bits */
+ beq gi2 /* skip if no bits set */
+ andis. r4, r3, 0xffff /* check for upper bits */
+ beq gi3 /* skip if no bits set */
+ addi r3, 0, 3 /* both upper and lower bits set */
+ b gi_done
+gi2: andis. r4, r3, 0xffff /* check for upper bits*/
+ beq gi4 /* skip if no bits set */
+ addi r3, 0, 2 /* only upper bits set */
+ b gi_done
+gi3: addi r3, 0, 1 /* only lower bits set */
+ b gi_done
+gi4: addi r3, 0, 0 /* no bits set */
+gi_done:
+ /* restore stack and return */
+ lwz r0, +16(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ lwz r4, +8(r1) /* restore r4 */
+ addi r1, r1, +12 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+/****************************************************
+ ******** set LED to R5 and hang ********
+ ***************************************************/
+log_stat: /* output a led code and continue */
+set_led:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r4, +8(r1) /* save R4 */
+
+ addis r4, 0, 0xfe00 /* LED buffer is at 0xfe000000 */
+#if defined(CONFIG_W7OLMG) /* only on gateway, invert outputs */
+ xori r3,r3, 0xffff /* complement led code, active low */
+ sth r3, 0(r4) /* store first test value */
+ xori r3,r3, 0xffff /* complement led code, active low */
+#else /* if not gateway, then don't invert */
+ sth r3, 0(r4) /* store first test value */
+#endif
+
+ /* restore stack and return */
+ lwz r0, +16(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ lwz r4, +8(r1) /* restore r4 */
+ addi r1, r1, +12 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+get_led:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r4, +8(r1) /* save R4 */
+
+ addis r4, 0, 0xfe00 /* LED buffer is at 0xfe000000 */
+ lhz r3, 0(r4) /* store first test value */
+#if defined(CONFIG_W7OLMG) /* only on gateway, invert inputs */
+ xori r3,r3, 0xffff /* complement led code, active low */
+#endif
+
+ /* restore stack and return */
+ lwz r0, +16(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ lwz r4, +8(r1) /* restore r4 */
+ addi r1, r1, +12 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+log_err: /* output the error and hang the board ( for now ) */
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r3, +8(r1) /* save a copy of error code */
+ bl set_led /* set the led pattern */
+ GET_GOT /* get GOT address in r14 */
+ lwz r3,GOT(err_str) /* get address of string */
+ bl post_puts /* output the warning string */
+ lwz r3, +8(r1) /* get error code */
+ addi r4, 0, 2 /* set disp length to 2 nibbles */
+ bl disp_hex /* output the error code */
+ lwz r3,GOT(end_str) /* get address of string */
+ bl post_puts /* output the warning string */
+halt:
+ b halt /* hang */
+
+ /* restore stack and return */
+ lwz r0, +16(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +12 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+log_warn: /* output a warning, then continue with operations */
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -16(r1) /* Save back chain and move SP */
+ stw r0, +20(r1) /* Save link register */
+ stw r3, +8(r1) /* save a copy of error code */
+ stw r14, +12(r1) /* save a copy of r14 (used by GOT) */
+
+ bl set_led /* set the led pattern */
+ GET_GOT /* get GOT address in r14 */
+ lwz r3,GOT(warn_str) /* get address of string */
+ bl post_puts /* output the warning string */
+ lwz r3, +8(r1) /* get error code */
+ addi r4, 0, 2 /* set disp length to 2 nibbles */
+ bl disp_hex /* output the error code */
+ lwz r3,GOT(end_str) /* get address of string */
+ bl post_puts /* output the warning string */
+
+ addis r3, 0, 64 /* has a long delay */
+ mtctr r3
+log_2:
+ WATCHDOG_RESET /* this keeps dog from barking, */
+ /* and takes time */
+ bdnz log_2 /* loop till time expires */
+
+ /* restore stack and return */
+ lwz r0, +20(r1) /* Get saved link register */
+ lwz r14, +12(r1) /* restore r14 */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +16 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+/*******************************************************************
+ * temp_uart_init
+ * Temporary UART initialization routine
+ * Sets up UART0 to run at 9600N81 off of the internal clock.
+ * R3-R4 are used.
+ ******************************************************************/
+temp_uart_init:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save link register */
+
+ addis r3, 0, 0xef60
+ ori r3, r3, 0x0303 /* r3 = UART0_LCR */
+ addi r4, 0, 0x83 /* n81 format, divisor regs enabled */
+ stb r4, 0(r3)
+
+ /* set baud rate to use internal clock,
+ baud = (200e6/16)/31/42 = 9600 */
+
+ addis r3, 0, 0xef60 /* Address of baud divisor reg */
+ ori r3, r3, 0x0300 /* UART0_DLM */
+ addi r4, 0, +42 /* uart baud divisor LSB = 93 */
+ stb r4, 0(r3) /* baud = (200 /16)/14/93 */
+
+ addi r3, r3, 0x0001 /* uart baud divisor addr */
+ addi r4, 0, 0
+ stb r4, 0(r3) /* Divisor Latch MSB = 0 */
+
+ addis r3, 0, 0xef60
+ ori r3, r3, 0x0303 /* r3 = UART0_LCR */
+ addi r4, 0, 0x03 /* n81 format, tx/rx regs enabled */
+ stb r4, 0(r3)
+
+ /* output a few line feeds */
+ addi r3, 0, '\n' /* load line feed */
+ bl post_putc /* output the char */
+ addi r3, 0, '\n' /* load line feed */
+ bl post_putc /* output the char */
+
+ /* restore stack and return */
+ lwz r0, +12(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +8 /* Remove frame from stack */
+ blr /* Return to calling function */
+
+/**********************************************************************
+ ** post_putc
+ ** outputs charactor in R3
+ ** r3 returns the error code ( -1 if there is an error )
+ *********************************************************************/
+
+post_putc:
+
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -20(r1) /* Save back chain and move SP */
+ stw r0, +24(r1) /* Save link register */
+ stmw r29, 8(r1) /* save r29 - r31 on stack
+ r31 - uart base address
+ r30 - delay counter
+ r29 - scratch reg */
+
+ addis r31, 0, 0xef60 /* Point to uart base */
+ ori r31, r31, 0x0300
+ addis r30, 0, 152 /* Load about 10,000,000 ticks. */
+pputc_lp:
+ lbz r29, 5(r31) /* Read Line Status Register */
+ andi. r29, r29, 0x20 /* Check THRE status */
+ bne thre_set /* Branch if FIFO empty */
+ addic. r30, r30, -1 /* Decrement and check if empty. */
+ bne pputc_lp /* Try, try again */
+ addi r3, 0, -1 /* Load error code for timeout */
+ b pputc_done /* Bail out with error code set */
+thre_set:
+ stb r3, 0(r31) /* Store character to UART */
+ addi r3, 0, 0 /* clear error code */
+pputc_done:
+ lmw r29, 8(r1) /*restore r29 - r31 from stack */
+ lwz r0, +24(r1) /* Get saved link register */
+ addi r1, r1, +20 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+
+/****************************************************************
+ post_puts
+ Accepts a null-terminated string pointed to by R3
+ Outputs to the serial port until 0x00 is found.
+ r3 returns the error code ( -1 if there is an error )
+*****************************************************************/
+post_puts:
+
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -12(r1) /* Save back chain and move SP */
+ stw r0, +16(r1) /* Save link register */
+ stw r31, 8(r1) /* save r31 - char pointer */
+
+ addi r31, r3, 0 /* move pointer to R31 */
+pputs_nxt:
+ lbz r3, 0(r31) /* Get next character */
+ addic. r3, r3, 0 /* Check for zero */
+ beq pputs_term /* bail out if zero */
+ bl post_putc /* output the char */
+ addic. r3, r3, 0 /* check for error */
+ bne pputs_err
+ addi r31, r31, 1 /* point to next char */
+ b pputs_nxt /* loop till term */
+pputs_err:
+ addi r3, 0, -1 /* set error code */
+ b pputs_end /* were outa here */
+pputs_term:
+ addi r3, 0, 1 /* set success code */
+ /* restore stack and return */
+pputs_end:
+ lwz r31, 8(r1) /* restore r27 - r31 from stack */
+ lwz r0, +16(r1) /* Get saved link register */
+ addi r1, r1, +12 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
+
+
+/********************************************************************
+ ***** disp_hex
+ ***** Routine to display a hex value from a register.
+ ***** R3 is value to display
+ ***** R4 is number of nibbles to display ie 2 for byte 8 for (long)word
+ ***** Returns -1 in R3 if there is an error ( ie serial port hangs )
+ ***** Returns 0 in R3 if no error
+ *******************************************************************/
+disp_hex:
+ /* save the return info on stack */
+ mflr r0 /* Get link register */
+ stwu r1, -16(r1) /* Save back chain and move SP */
+ stw r0, +20(r1) /* Save link register */
+ stmw r30, 8(r1) /* save r30 - r31 on stack */
+ /* r31 output char */
+ /* r30 uart base address */
+ addi r30, 0, 8 /* Go through 8 nibbles. */
+ addi r31, r3, 0
+pputh_nxt:
+ rlwinm r31, r31, 4, 0, 31 /* Rotate next nibble into position */
+ andi. r3, r31, 0x0f /* Get nibble. */
+ addi r3, r3, 0x30 /* Add zero's ASCII code. */
+ cmpwi r3, 0x03a
+ blt pputh_out
+ addi r3, r3, 0x07 /* 0x27 for lower case. */
+pputh_out:
+ cmpw r30, r4
+ bgt pputh_skip
+ bl post_putc
+ addic. r3, r3, 0 /* check for error */
+ bne pputh_err
+pputh_skip:
+ addic. r30, r30, -1
+ bne pputh_nxt
+ xor r3, r3, r3 /* Clear error code */
+ b pputh_done
+pputh_err:
+ addi r3, 0, -1 /* set error code */
+pputh_done:
+ /* restore stack and return */
+ lmw r30, 8(r1) /* restore r30 - r31 from stack */
+ lwz r0, +20(r1) /* Get saved link register */
+ addi r1, r1, +16 /* Remove frame from stack */
+ mtlr r0 /* Restore link register */
+ blr /* Return to calling function */
+
diff --git a/board/w7o/post2.c b/board/w7o/post2.c
new file mode 100644
index 0000000000..271c197f06
--- /dev/null
+++ b/board/w7o/post2.c
@@ -0,0 +1,109 @@
+/*
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net
+ * and
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <rtc.h>
+#include "errors.h"
+#include "dtt.h"
+
+#if defined(CONFIG_RTC_M48T35A)
+void rtctest(void)
+{
+ volatile uchar *tchar = (uchar*)(CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 9);
+ struct rtc_time tmp;
+
+ /* set up led code for RTC tests */
+ log_stat(ERR_RTCG);
+
+ /*
+ * Do RTC battery test. The first write after power up
+ * fails if battery is low.
+ */
+ *tchar = 0xaa;
+ if ((*tchar ^ 0xaa) != 0x0) log_warn(ERR_RTCBAT);
+ *tchar = 0x55; /* Reset test address */
+
+ /*
+ * Now lets check the validity of the values in the RTC.
+ */
+ rtc_get(&tmp);
+ if ((tmp.tm_sec < 0) | (tmp.tm_sec > 59) |
+ (tmp.tm_min < 0) | (tmp.tm_min > 59) |
+ (tmp.tm_hour < 0) | (tmp.tm_hour > 23) |
+ (tmp.tm_mday < 1 ) | (tmp.tm_mday > 31) |
+ (tmp.tm_mon < 1 ) | (tmp.tm_mon > 12) |
+ (tmp.tm_year < 2000) | (tmp.tm_year > 2500) |
+ (tmp.tm_wday < 1 ) | (tmp.tm_wday > 7)) {
+ log_warn(ERR_RTCTIM);
+ rtc_reset();
+ }
+
+ /*
+ * Now lets do a check to see if the NV RAM is there.
+ */
+ *tchar = 0xaa;
+ if ((*tchar ^ 0xaa) != 0x0) log_err(ERR_RTCVAL);
+ *tchar = 0x55; /* Reset test address */
+
+} /* rtctest() */
+#endif /* CONFIG_RTC_M48T35A */
+
+
+#ifdef CONFIG_DTT_LM75
+int dtt_test(int sensor)
+{
+ short temp, trip, hyst;
+
+ /* get values */
+ temp = dtt_read(sensor, DTT_READ_TEMP) / 256;
+ trip = dtt_read(sensor, DTT_TEMP_SET) / 256;
+ hyst = dtt_read(sensor, DTT_TEMP_HYST) / 256;
+
+ /* check values */
+ if ((hyst != (CFG_DTT_MAX_TEMP - CFG_DTT_HYSTERESIS)) ||
+ (trip != CFG_DTT_MAX_TEMP) ||
+ (temp < CFG_DTT_LOW_TEMP) || (temp > CFG_DTT_MAX_TEMP))
+ return 1;
+
+ return 0;
+} /* dtt_test() */
+#endif /* CONFIG_DTT_LM75 */
+
+/*****************************************/
+
+void post2(void)
+{
+#if defined(CONFIG_RTC_M48T35A)
+ rtctest();
+#endif /* CONFIG_RTC_M48T35A */
+
+#ifdef CONFIG_DTT_LM75
+ log_stat(ERR_TempG);
+ if(dtt_test(2) != 0) log_warn(ERR_Ttest0);
+ if(dtt_test(4) != 0) log_warn(ERR_Ttest1);
+#endif /* CONFIG_DTT_LM75 */
+} /* post2() */
+
diff --git a/board/w7o/vpd.c b/board/w7o/vpd.c
new file mode 100644
index 0000000000..c24b127d3c
--- /dev/null
+++ b/board/w7o/vpd.c
@@ -0,0 +1,408 @@
+/*
+ * (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
+ */
+
+#if defined(VXWORKS)
+# include <stdio.h>
+# include <string.h>
+# define CFG_DEF_EEPROM_ADDR 0xa0
+extern char iicReadByte( char, char );
+extern ulong_t crc32( unsigned char *, unsigned long );
+#else
+#include <common.h>
+#endif
+
+#include "vpd.h"
+
+/*
+ * vpd_reader() - reads VPD data from I2C EEPROMS.
+ * returns pointer to buffer or NULL.
+ */
+static unsigned char *
+vpd_reader(unsigned char *buf, unsigned dev_addr, unsigned off, unsigned count)
+{
+ unsigned offset = off; /* Calculated offset */
+
+ /*
+ * The main board EEPROM contains
+ * SDRAM SPD in the first 128 bytes,
+ * so skew the offset.
+ */
+ if (dev_addr == CFG_DEF_EEPROM_ADDR)
+ offset += SDRAM_SPD_DATA_SIZE;
+
+ /* Try to read the I2C EEPROM */
+#if defined(VXWORKS)
+ {
+ int i;
+ for( i = 0; i < count; ++i ) {
+ buf[ i ] = iicReadByte( dev_addr, offset+i );
+ }
+ }
+#else
+ if (eeprom_read(dev_addr, offset, buf, count)) {
+ printf("Failed to read %d bytes from VPD EEPROM 0x%x @ 0x%x\n",
+ count, dev_addr, offset);
+ return NULL;
+ }
+#endif
+
+ return buf;
+} /* vpd_reader() */
+
+
+/*
+ * vpd_get_packet() - returns next VPD packet or NULL.
+ */
+static vpd_packet_t *vpd_get_packet(vpd_packet_t *vpd_packet)
+{
+ vpd_packet_t *packet = vpd_packet;
+
+ if (packet != NULL) {
+ if (packet->identifier == VPD_PID_TERM)
+ return NULL;
+ else
+ packet = (vpd_packet_t *)((char *)packet + packet->size + 2);
+ }
+
+ return packet;
+} /* vpd_get_packet() */
+
+
+/*
+ * vpd_find_packet() - Locates and returns the specified
+ * VPD packet or NULL on error.
+ */
+static vpd_packet_t *vpd_find_packet(vpd_t *vpd, unsigned char ident)
+{
+ vpd_packet_t *packet = (vpd_packet_t *)&vpd->packets;
+
+ /* Guaranteed illegal */
+ if (ident == VPD_PID_GI)
+ return NULL;
+
+ /* Scan tuples looking for a match */
+ while ((packet->identifier != ident) &&
+ (packet->identifier != VPD_PID_TERM))
+ packet = vpd_get_packet(packet);
+
+ /* Did we find it? */
+ if ((packet->identifier) && (packet->identifier != ident))
+ return NULL;
+ return packet;
+}
+
+
+/*
+ * vpd_is_valid() - Validates contents of VPD data
+ * in I2C EEPROM. Returns 1 for
+ * success or 0 for failure.
+ */
+static int vpd_is_valid(unsigned dev_addr, unsigned char *buf)
+{
+ unsigned num_bytes;
+ vpd_packet_t *packet;
+ vpd_t *vpd = (vpd_t *)buf;
+ unsigned short stored_crc16, calc_crc16 = 0xffff;
+
+ /* Check Eyecatcher */
+ if (strncmp(vpd->header.eyecatcher, VPD_EYECATCHER, VPD_EYE_SIZE) != 0) {
+ unsigned offset = 0;
+ if (dev_addr == CFG_DEF_EEPROM_ADDR)
+ offset += SDRAM_SPD_DATA_SIZE;
+ printf("Error: VPD EEPROM 0x%x corrupt @ 0x%x\n", dev_addr, offset);
+
+ return 0;
+ }
+
+ /* Check Length */
+ if (vpd->header.size> VPD_MAX_EEPROM_SIZE) {
+ printf("Error: VPD EEPROM 0x%x contains bad size 0x%x\n",
+ dev_addr, vpd->header.size);
+ return 0;
+ }
+
+ /* Now find the termination packet */
+ if ((packet = vpd_find_packet(vpd, VPD_PID_TERM)) == NULL) {
+ printf("Error: VPD EEPROM 0x%x missing termination packet\n",
+ dev_addr);
+ return 0;
+ }
+
+ /* Calculate data size */
+ num_bytes = (unsigned long)((unsigned char *)packet -
+ (unsigned char *)vpd + sizeof(vpd_packet_t));
+
+ /* Find stored CRC and clear it */
+ if ((packet = vpd_find_packet(vpd, VPD_PID_CRC)) == NULL) {
+ printf("Error: VPD EEPROM 0x%x missing CRC\n", dev_addr);
+ return 0;
+ }
+ stored_crc16 = *((ushort *)packet->data);
+ *(ushort *)packet->data = 0;
+
+ /* OK, lets calculate the CRC and check it */
+#if defined(VXWORKS)
+ calc_crc16 = (0xffff & crc32(buf, num_bytes));
+#else
+ calc_crc16 = (0xffff & crc32(0, buf, num_bytes));
+#endif
+ *(ushort *)packet->data = stored_crc16; /* Now restore the CRC */
+ if (stored_crc16 != calc_crc16) {
+ printf("Error: VPD EEPROM 0x%x has bad CRC 0x%x\n",
+ dev_addr, stored_crc16);
+ return 0;
+ }
+
+ return 1;
+} /* vpd_is_valid() */
+
+
+/*
+ * size_ok() - Check to see if packet size matches
+ * size of data we want. Returns 1 for
+ * good match or 0 for failure.
+ */
+static int size_ok(vpd_packet_t *packet, unsigned long size)
+{
+ if (packet->size != size) {
+ printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
+ return 0;
+ }
+ return 1;
+} /* size_ok() */
+
+
+/*
+ * strlen_ok() - Check to see if packet size matches
+ * strlen of the string we want to populate.
+ * Returns 1 for valid length or 0 for failure.
+ */
+static int strlen_ok(vpd_packet_t *packet, unsigned long length)
+{
+ if (packet->size >= length) {
+ printf("VPD Packet 0x%x corrupt.\n", packet->identifier);
+ return 0;
+ }
+ return 1;
+} /* strlen_ok() */
+
+
+/*
+ * get_vpd_data() - populates the passed VPD structure 'vpdInfo'
+ * with data obtained from the specified
+ * I2C EEPROM 'dev_addr'. Returns 0 for
+ * success or 1 for failure.
+ */
+int vpd_get_data(unsigned char dev_addr, VPD *vpdInfo)
+{
+ unsigned char buf[VPD_EEPROM_SIZE];
+ vpd_t *vpd = (vpd_t *)buf;
+ vpd_packet_t *packet;
+
+ if (vpdInfo == NULL)
+ return 1;
+
+ /*
+ * Fill vpdInfo with 0s to blank out
+ * unused fields, fill vpdInfo->ethAddrs
+ * with all 0xffs so that other's code can
+ * determine how many real Ethernet addresses
+ * there are. OUIs starting with 0xff are
+ * broadcast addresses, and would never be
+ * permantely stored.
+ */
+ memset((void *)vpdInfo, 0, sizeof(VPD));
+ memset((void *)&vpdInfo->ethAddrs, 0xff, sizeof(vpdInfo->ethAddrs));
+ vpdInfo->_devAddr = dev_addr;
+
+ /* Read the minimum size first */
+ if (vpd_reader(buf, dev_addr, 0, VPD_EEPROM_SIZE) == NULL) {
+ return 1;
+ }
+
+ /* Check validity of VPD data */
+ if (!vpd_is_valid(dev_addr, buf)) {
+ printf("VPD Data is INVALID!\n");
+ return 1;
+ }
+
+ /*
+ * Walk all the packets and populate
+ * the VPD info structure.
+ */
+ packet = (vpd_packet_t *)&vpd->packets;
+ do {
+ switch (packet->identifier) {
+ case VPD_PID_GI:
+ printf("Error: Illegal VPD value\n");
+ break;
+ case VPD_PID_PID:
+ if (strlen_ok(packet, MAX_PROD_ID)) {
+ strncpy(vpdInfo->productId,
+ packet->data, packet->size);
+ }
+ break;
+ case VPD_PID_REV:
+ if (size_ok(packet, sizeof(char)))
+ vpdInfo->revisionId = *packet->data;
+ break;
+ case VPD_PID_SN:
+ if (size_ok(packet, sizeof(unsigned long))) {
+ vpdInfo->serialNum =
+ *(unsigned long *)packet->data;
+ }
+ break;
+ case VPD_PID_MANID:
+ if (size_ok(packet, sizeof(unsigned char)))
+ vpdInfo->manuID = *packet->data;
+ break;
+ case VPD_PID_PCO:
+ if (size_ok(packet, sizeof(unsigned long))) {
+ vpdInfo->configOpt =
+ *(unsigned long *)packet->data;
+ }
+ break;
+ case VPD_PID_SYSCLK:
+ if (size_ok(packet, sizeof(unsigned long)))
+ vpdInfo->sysClk = *(unsigned long *)packet->data;
+ break;
+ case VPD_PID_SERCLK:
+ if (size_ok(packet, sizeof(unsigned long)))
+ vpdInfo->serClk = *(unsigned long *)packet->data;
+ break;
+ case VPD_PID_FLASH:
+ if (size_ok(packet, 9)) { /* XXX - hardcoded,
+ padding in struct */
+ memcpy(&vpdInfo->flashCfg, packet->data, 9);
+ }
+ break;
+ case VPD_PID_ETHADDR:
+ memcpy(vpdInfo->ethAddrs, packet->data, packet->size);
+ break;
+ case VPD_PID_POTS:
+ if (size_ok(packet, sizeof(char)))
+ vpdInfo->numPOTS = (unsigned)*packet->data;
+ break;
+ case VPD_PID_DS1:
+ if (size_ok(packet, sizeof(char)))
+ vpdInfo->numDS1 = (unsigned)*packet->data;
+ case VPD_PID_GAL:
+ case VPD_PID_CRC:
+ case VPD_PID_TERM:
+ break;
+ default:
+ printf("Warning: Found unknown VPD packet ID 0x%x\n",
+ packet->identifier);
+ break;
+ }
+ } while ((packet = vpd_get_packet(packet)));
+
+ return 0;
+} /* end get_vpd_data() */
+
+
+/*
+ * vpd_init() - Initialize default VPD environment
+ */
+int vpd_init(unsigned char dev_addr)
+{
+ return (0);
+} /* vpd_init() */
+
+
+/*
+ * vpd_print() - Pretty print the VPD data.
+ */
+void vpd_print(VPD *vpdInfo)
+{
+ const char *const sp = "";
+ const char *const sfmt = "%4s%-20s: \"%s\"\n";
+ const char *const cfmt = "%4s%-20s: '%c'\n";
+ const char *const dfmt = "%4s%-20s: %ld\n";
+ const char *const hfmt = "%4s%-20s: %08lX\n";
+ const char *const dsfmt = "%4s%-20s: %d\n";
+ const char *const hsfmt = "%4s%-20s: %04X\n";
+ const char *const dhfmt = "%4s%-20s: %ld (%lX)\n";
+
+ printf("VPD read from I2C device: %02X\n", vpdInfo->_devAddr);
+
+ if (vpdInfo->productId[0])
+ printf(sfmt, sp, "Product ID", vpdInfo->productId);
+ else
+ printf(sfmt, sp, "Product ID", "UNKNOWN");
+
+ if (vpdInfo->revisionId)
+ printf(cfmt, sp, "Revision ID", vpdInfo->revisionId);
+
+ if (vpdInfo->serialNum)
+ printf(dfmt, sp, "Serial Number", vpdInfo->serialNum);
+
+ if (vpdInfo->manuID)
+ printf(dfmt, sp, "Manufacture ID", (long)vpdInfo->manuID);
+
+ if (vpdInfo->configOpt)
+ printf(hfmt, sp, "Configuration", vpdInfo->configOpt);
+
+ if (vpdInfo->sysClk)
+ printf(dhfmt, sp, "System Clock", vpdInfo->sysClk, vpdInfo->sysClk);
+
+ if (vpdInfo->serClk)
+ printf(dhfmt, sp, "Serial Clock", vpdInfo->serClk, vpdInfo->serClk);
+
+ if (vpdInfo->numPOTS)
+ printf(dfmt, sp, "Number of POTS lines", vpdInfo->numPOTS);
+
+ if (vpdInfo->numDS1)
+ printf(dfmt, sp, "Number of DS1s", vpdInfo->numDS1);
+
+ /* Print Ethernet Addresses */
+ if (vpdInfo->ethAddrs[0][0] != 0xff) {
+ int i, j;
+ printf("%4sEtherNet Address(es): ", sp);
+ for (i = 0; i < MAX_ETH_ADDRS; i++) {
+ if (vpdInfo->ethAddrs[i][0] != 0xff) {
+ for (j = 0; j < 6; j++) {
+ printf("%02X", vpdInfo->ethAddrs[i][j]);
+ if (((j + 1) % 6) != 0)
+ printf(":");
+ else
+ printf(" ");
+ }
+ if (((i + 1) % 3) == 0) printf("\n%24s: ", sp);
+ }
+ }
+ printf("\n");
+ }
+
+ if (vpdInfo->flashCfg.mfg && vpdInfo->flashCfg.dev) {
+ printf("Main Flash Configuration:\n");
+ printf(hsfmt, sp, "Manufacture ID", vpdInfo->flashCfg.mfg);
+ printf(hsfmt, sp, "Device ID", vpdInfo->flashCfg.dev);
+ printf(dsfmt, sp, "Device Width", vpdInfo->flashCfg.devWidth);
+ printf(dsfmt, sp, "Num. Devices", vpdInfo->flashCfg.numDevs);
+ printf(dsfmt, sp, "Num. Columns", vpdInfo->flashCfg.numCols);
+ printf(dsfmt, sp, "Column Width", vpdInfo->flashCfg.colWidth);
+ printf(dsfmt, sp, "WE Data Width", vpdInfo->flashCfg.weDataWidth);
+ }
+} /* vpd_print() */
+
diff --git a/board/w7o/vpd.h b/board/w7o/vpd.h
new file mode 100644
index 0000000000..35bbe3e62d
--- /dev/null
+++ b/board/w7o/vpd.h
@@ -0,0 +1,135 @@
+/*
+ * (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
+ */
+
+#ifndef _VPD_H_
+#define _VPD_H_
+
+/*
+ * Main Flash Configuration.
+ */
+typedef struct flashCfg_s {
+ unsigned short mfg; /* Manufacture ID */
+ unsigned short dev; /* Device ID */
+ unsigned char devWidth; /* Device Width */
+ unsigned char numDevs; /* Number of devices */
+ unsigned char numCols; /* Number of columns */
+ unsigned char colWidth; /* Width of a column */
+ unsigned char weDataWidth; /* Write/Erase Data Width */
+} flashCfg_t;
+
+/*
+ * Vital Product Data - VPD
+ */
+#define MAX_PROD_ID 15
+#define MAX_ETH_ADDRS 10
+typedef unsigned char EthAddr[6];
+typedef struct vpd {
+ unsigned char _devAddr; /* Device address during read */
+ char productId[MAX_PROD_ID]; /* Product ID */
+ char revisionId; /* Revision ID as a char */
+ unsigned long serialNum; /* Serial number */
+ unsigned char manuID; /* Manufact ID - byte int */
+ unsigned long configOpt; /* Config Option - bit field */
+ unsigned long sysClk; /* System clock in Hertz */
+ unsigned long serClk; /* Ext. clock in Hertz */
+ flashCfg_t flashCfg; /* Flash configuration */
+ unsigned long numPOTS; /* Number of POTS lines */
+ unsigned long numDS1; /* Number of DS1 circuits */
+ EthAddr ethAddrs[MAX_ETH_ADDRS]; /* Ethernet MAC, 1st = craft */
+} VPD;
+
+
+#define VPD_MAX_EEPROM_SIZE 512 /* Max size VPD EEPROM */
+#define SDRAM_SPD_DATA_SIZE 128 /* Size SPD in VPD EEPROM */
+
+/*
+ * PIDs - Packet Identifiers
+ */
+#define VPD_PID_GI 0x0 /* Guaranted Illegal */
+#define VPD_PID_PID 0x1 /* Product Identifier */
+#define VPD_PID_REV 0x2 /* Product Revision */
+#define VPD_PID_SN 0x3 /* Serial Number */
+#define VPD_PID_MANID 0x4 /* Manufacture ID */
+#define VPD_PID_PCO 0x5 /* Product configuration */
+#define VPD_PID_SYSCLK 0x6 /* System Clock */
+#define VPD_PID_SERCLK 0x7 /* Ser. Clk. Speed in Hertz */
+#define VPD_PID_CRC 0x8 /* VPD CRC */
+#define VPD_PID_FLASH 0x9 /* Flash Configuration */
+#define VPD_PID_ETHADDR 0xA /* Ethernet Address(es) */
+#define VPD_PID_GAL 0xB /* Galileo Switch Config */
+#define VPD_PID_POTS 0xC /* Number of POTS Lines */
+#define VPD_PID_DS1 0xD /* Number of DS1s */
+#define VPD_PID_TERM 0xFF /* Termination packet */
+
+/*
+ * VPD - Eyecatcher/Magic
+ */
+#define VPD_EYECATCHER "W7O"
+#define VPD_EYE_SIZE 3
+typedef struct vpd_header {
+ unsigned char eyecatcher[VPD_EYE_SIZE]; /* eyecatcher - "W7O" */
+ unsigned short size __attribute__((packed)); /* size of EEPROM */
+} vpd_header_t;
+
+
+#define VPD_DATA_SIZE (VPD_MAX_EEPROM_SIZE - SDRAM_SPD_DATA_SIZE - \
+ sizeof(vpd_header_t))
+typedef struct vpd_s {
+ vpd_header_t header;
+ unsigned char packets[VPD_DATA_SIZE];
+} vpd_t;
+
+typedef struct vpd_packet {
+ unsigned char identifier;
+ unsigned char size;
+ unsigned char data[1];
+} vpd_packet_t;
+
+/*
+ * VPD configOpt bit mask
+ */
+#define VPD_HAS_BBRAM 0x1 /* Battery backed SRAM */
+#define VPD_HAS_RTC 0x2 /* Battery backed RTC */
+#define VPD_HAS_EXT_SER_CLK 0x4 /* External serial clock */
+#define VPD_HAS_SER_TRANS_1 0x8 /* COM1 transceiver */
+#define VPD_HAS_SER_TRANS_2 0x10 /* COM2 transceiver */
+#define VPD_HAS_CRAFT_PHY 0x20 /* CRAFT Ethernet */
+#define VPD_HAS_DTT_1 0x40 /* I2C Digital therm. #1 */
+#define VPD_HAS_DTT_2 0x80 /* I2C Digital therm. #2 */
+#define VPD_HAS_1000_UP_LASER 0x100 /* GMM - 1000Mbit Uplink */
+#define VPD_HAS_70KM_UP_LASER 0x200 /* CMM - 70KM Uplink laser */
+#define VPD_HAS_2_UPLINKS 0x400 /* CMM - 2 uplink lasers */
+#define VPD_HAS_FPGA 0x800 /* Has 1 or more FPGAs */
+#define VPD_HAS_DFA 0x1000 /* CLM - Has 2 Fiber Inter. */
+#define VPD_HAS_GAL_SWITCH 0x2000 /* GMM - Has a Gal switch */
+#define VPD_HAS_POTS_LINES 0x4000 /* GMM - Has POTS lines */
+#define VPD_HAS_DS1_CHANNELS 0x8000 /* GMM - Has DS1 channels */
+#define VPD_HAS_CABLE_RETURN 0x10000 /* GBM/GBR - Cable ret. path */
+
+#define VPD_EEPROM_SIZE (256 - SDRAM_SPD_DATA_SIZE) /* Size EEPROM */
+
+extern int vpd_get_data(unsigned char dev_addr, VPD *vpd);
+extern void vpd_print(VPD *vpdInfo);
+
+#endif /* _VPD_H_ */
+
diff --git a/board/w7o/w7o.c b/board/w7o/w7o.c
new file mode 100644
index 0000000000..b404d61c1a
--- /dev/null
+++ b/board/w7o/w7o.c
@@ -0,0 +1,271 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include "w7o.h"
+#include <asm/processor.h>
+
+#include "vpd.h"
+#include "errors.h"
+#include <watchdog.h>
+
+unsigned long get_dram_size(void);
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+
+/* ------------------------------------------------------------------------- */
+
+int board_pre_init (void)
+{
+#if defined(CONFIG_W7OLMG)
+ /*
+ * Setup GPIO pins - reset devices.
+ */
+ out32(IBM405GP_GPIO0_ODR, 0x10000000); /* one open drain pin */
+ out32(IBM405GP_GPIO0_OR, 0x3E000000); /* set output pins to default */
+ out32(IBM405GP_GPIO0_TCR, 0x7f800000); /* setup for output */
+
+ /*
+ * IRQ 0-15 405GP internally generated; active high; level sensitive
+ * IRQ 16 405GP internally generated; active low; level sensitive
+ * IRQ 17-24 RESERVED
+ * IRQ 25 (EXT IRQ 0) XILINX; active low; level sensitive
+ * IRQ 26 (EXT IRQ 1) PCI INT A; active low; level sensitive
+ * IRQ 27 (EXT IRQ 2) PCI INT B; active low; level sensitive
+ * IRQ 28 (EXT IRQ 3) SAM 2; active low; level sensitive
+ * IRQ 29 (EXT IRQ 4) Battery Bad; active low; level sensitive
+ * IRQ 30 (EXT IRQ 5) Level One PHY; active low; level sensitive
+ * IRQ 31 (EXT IRQ 6) SAM 1; active high; level sensitive
+ */
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+ mtdcr(uicer, 0x00000000); /* disable all ints */
+
+ mtdcr(uiccr, 0x00000000); /* set all to be non-critical*/
+ mtdcr(uicpr, 0xFFFFFF80); /* set int polarities */
+ mtdcr(uictr, 0x10000000); /* set int trigger levels */
+ mtdcr(uicvcr, 0x00000001); /* set vect base=0,
+ INT0 highest priority*/
+
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+
+#elif defined(CONFIG_W7OLMC)
+ /*
+ * Setup GPIO pins
+ */
+ out32(IBM405GP_GPIO0_ODR, 0x01800000); /* XCV Done Open Drain */
+ out32(IBM405GP_GPIO0_OR, 0x03800000); /* set out pins to default */
+ out32(IBM405GP_GPIO0_TCR, 0x66C00000); /* setup for output */
+
+ /*
+ * IRQ 0-15 405GP internally generated; active high; level sensitive
+ * IRQ 16 405GP internally generated; active low; level sensitive
+ * IRQ 17-24 RESERVED
+ * IRQ 25 (EXT IRQ 0) DBE 0; active low; level sensitive
+ * IRQ 26 (EXT IRQ 1) DBE 1; active low; level sensitive
+ * IRQ 27 (EXT IRQ 2) DBE 2; active low; level sensitive
+ * IRQ 28 (EXT IRQ 3) DBE Common; active low; level sensitive
+ * IRQ 29 (EXT IRQ 4) PCI; active low; level sensitive
+ * IRQ 30 (EXT IRQ 5) RCMM Reset; active low; level sensitive
+ * IRQ 31 (EXT IRQ 6) PHY; active high; level sensitive
+ */
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+ mtdcr(uicer, 0x00000000); /* disable all ints */
+
+ mtdcr(uiccr, 0x00000000); /* set all to be non-critical*/
+ mtdcr(uicpr, 0xFFFFFF80); /* set int polarities */
+ mtdcr(uictr, 0x10000000); /* set int trigger levels */
+ mtdcr(uicvcr, 0x00000001); /* set vect base=0,
+ INT0 highest priority*/
+
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+
+#else /* Unknown */
+# error "Unknown W7O board configuration"
+#endif
+
+ WATCHDOG_RESET(); /* Reset the watchdog */
+ temp_uart_init(); /* init the uart for debug */
+ WATCHDOG_RESET(); /* Reset the watchdog */
+ test_led(); /* test the LEDs */
+ test_sdram(get_dram_size()); /* test the dram */
+ log_stat(ERR_POST1); /* log status,post1 complete */
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Check Board Identity:
+ */
+int checkboard (void)
+{
+ VPD vpd;
+
+ puts ("Board: ");
+
+ /* VPD data present in I2C EEPROM */
+ if (vpd_get_data(CFG_DEF_EEPROM_ADDR, &vpd) == 0) {
+ /*
+ * Known board type.
+ */
+ if (vpd.productId[0] &&
+ ((strncmp(vpd.productId, "GMM", 3) == 0) ||
+ (strncmp(vpd.productId, "CMM", 3) == 0))) {
+
+ /* Output board information on startup */
+ printf("\"%s\", revision '%c', serial# %ld, manufacturer %u\n",
+ vpd.productId, vpd.revisionId, vpd.serialNum, vpd.manuID);
+ return (0);
+ }
+ }
+
+ puts ("### Unknown HW ID - assuming NOTHING\n");
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+long int initdram (int board_type)
+{
+ return get_dram_size();
+}
+
+unsigned long get_dram_size (void)
+{
+ int tmp, i, regs[4];
+ int size = 0;
+
+ /* Get bank Size registers */
+ mtdcr(memcfga, mem_mb0cf); /* get bank 0 config reg */
+ regs[0] = mfdcr(memcfgd);
+
+ mtdcr(memcfga, mem_mb1cf); /* get bank 1 config reg */
+ regs[1] = mfdcr(memcfgd);
+
+ mtdcr(memcfga, mem_mb2cf); /* get bank 2 config reg */
+ regs[2] = mfdcr(memcfgd);
+
+ mtdcr(memcfga, mem_mb3cf); /* get bank 3 config reg */
+ regs[3] = mfdcr(memcfgd);
+
+ /* compute the size, add each bank if enabled */
+ for(i = 0; i < 4; i++) {
+ if (regs[i] & 0x0001) { /* if enabled, */
+ tmp = ((regs[i] >> (31 - 14)) & 0x7); /* get size bits */
+ tmp = 0x400000 << tmp; /* Size bits X 4MB = size */
+ size += tmp;
+ }
+ }
+
+ return size;
+}
+
+int misc_init_f (void)
+{
+ return 0;
+}
+
+static void
+w7o_env_init(VPD *vpd)
+{
+ /*
+ * Read VPD
+ */
+ if (vpd_get_data(CFG_DEF_EEPROM_ADDR, vpd) != 0)
+ return;
+
+ /*
+ * Known board type.
+ */
+ if (vpd->productId[0] &&
+ ((strncmp(vpd->productId, "GMM", 3) == 0) ||
+ (strncmp(vpd->productId, "CMM", 3) == 0))) {
+ char buf[30];
+ char *eth;
+ unsigned char *serial = getenv("serial#");
+ unsigned char *ethaddr = getenv("ethaddr");
+
+ /* Set 'serial#' envvar if serial# isn't set */
+ if (!serial) {
+ sprintf(buf, "%s-%ld", vpd->productId, vpd->serialNum);
+ setenv("serial#", buf);
+ }
+
+ /* Set 'ethaddr' envvar if 'ethaddr' envvar is the default */
+ eth = vpd->ethAddrs[0];
+ if (ethaddr && (strcmp(ethaddr, MK_STR(CONFIG_ETHADDR)) == 0)) {
+ /* Now setup ethaddr */
+ sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+ eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ setenv("ethaddr", buf);
+ }
+ }
+} /* w7o_env_init() */
+
+
+int misc_init_r (void)
+{
+ VPD vpd; /* VPD information */
+
+#if defined(CONFIG_W7OLMG)
+ unsigned long greg; /* GPIO Register */
+
+ greg = in32(IBM405GP_GPIO0_OR);
+
+ /*
+ * XXX - Unreset devices - this should be moved into VxWorks driver code
+ */
+ greg |= 0x41800000L; /* SAM, PHY, Galileo */
+
+ out32(IBM405GP_GPIO0_OR, greg); /* set output pins to default */
+#endif /* CONFIG_W7OLMG */
+
+ /*
+ * Initialize W7O environment variables
+ */
+ w7o_env_init(&vpd);
+
+ /*
+ * Initialize the FPGA(s).
+ */
+ if (init_fpga() == 0)
+ test_fpga((unsigned short *)CONFIG_FPGAS_BASE);
+
+ /* More POST testing. */
+ post2();
+
+ /* Done with hardware initialization and POST. */
+ log_stat(ERR_POSTOK);
+
+ /* Call silly, fail safe boot init routine */
+ init_fsboot();
+
+ return (0);
+}
+
OpenPOWER on IntegriCloud