diff options
author | wdenk <wdenk> | 2002-11-03 00:24:07 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2002-11-03 00:24:07 +0000 |
commit | c609719b8d1b2dca590e0ed499016d041203e403 (patch) | |
tree | 7ea1755d80903ff972f312a249eb856061d40e15 /board/w7o | |
parent | 5b1d713721c3ea02549940133f09236783dda1f9 (diff) |
Initial revision
Diffstat (limited to 'board/w7o')
-rw-r--r-- | board/w7o/flash.c | 941 | ||||
-rw-r--r-- | board/w7o/fpga.c | 380 | ||||
-rw-r--r-- | board/w7o/init.S | 264 | ||||
-rw-r--r-- | board/w7o/post1.S | 745 | ||||
-rw-r--r-- | board/w7o/post2.c | 109 | ||||
-rw-r--r-- | board/w7o/vpd.c | 408 | ||||
-rw-r--r-- | board/w7o/vpd.h | 135 | ||||
-rw-r--r-- | board/w7o/w7o.c | 271 |
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); +} + |