--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#ifndef CFG_ENV_ADDR
+#define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#endif
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+ memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ &flash_info[1]);
+#endif
+ } else {
+ memctl->memc_br1 = 0; /* invalidate bank */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+#include <common.h>
+#include <board/cogent/dipsw.h>
+
+unsigned char
+dipsw_raw(void)
+{
+ return cma_mb_reg_read(&((cma_mb_dipsw *)CMA_MB_DIPSW_BASE)->dip_val);
+}
+
+unsigned char
+dipsw_cooked(void)
+{
+ unsigned char val1, val2, mask1, mask2;
+
+ val1 = dipsw_raw();
+
+ /*
+ * we want to mirror the bits because the low bit is switch 1 and high
+ * bit is switch 8 and also invert them because 1=off and 0=on, according
+ * to manual.
+ *
+ * this makes the value more intuitive i.e.
+ * - left most, or high, or top, bit is left most switch (1);
+ * - right most, or low, or bottom, bit is right most switch (8)
+ * - a set bit means "on" and a clear bit means "off"
+ */
+
+ val2 = 0;
+ for (mask1 = 1 << 7, mask2 = 1; mask1 > 0; mask1 >>= 1, mask2 <<= 1)
+ if ((val1 & mask1) == 0)
+ val2 |= mask2;
+
+ return (val2);
+}
+
+void
+dipsw_init(void)
+{
+ unsigned char val, mask;
+
+ val = dipsw_cooked();
+
+ printf("|");
+ for (mask = 1 << 7; mask > 0; mask >>= 1)
+ if (val & mask)
+ printf("on |");
+ else
+ printf("off|");
+ printf("\n");
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <board/cogent/flash.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+
+#if defined(CONFIG_CMA302)
+
+/*
+ * probe for the existence of flash at address "addr"
+ * 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
+ */
+static int
+c302f_probe_word(c302f_addr_t addr)
+{
+ /* reset the flash */
+ *addr = C302F_BNK_CMD_RST;
+
+ /* check the manufacturer id */
+ *addr = C302F_BNK_CMD_RD_ID;
+ if (*C302F_BNK_ADDR_MAN(addr) != C302F_BNK_RD_ID_MAN)
+ return 1;
+
+ /* check the device id */
+ *addr = C302F_BNK_CMD_RD_ID;
+ if (*C302F_BNK_ADDR_DEV(addr) != C302F_BNK_RD_ID_DEV)
+ return 2;
+
+#ifdef FLASH_DEBUG
+ {
+ int i;
+
+ printf("\nMaster Lock Config = 0x%08lx\n",
+ *C302F_BNK_ADDR_CFGM(addr));
+ for (i = 0; i < C302F_BNK_NBLOCKS; i++)
+ printf("Block %2d Lock Config = 0x%08lx\n",
+ i, *C302F_BNK_ADDR_CFG(i, addr));
+ }
+#endif
+
+ /* reset the flash again */
+ *addr = C302F_BNK_CMD_RST;
+
+ return 0;
+}
+
+/*
+ * probe for Cogent CMA302 flash module at address "base" and store
+ * info for any found into flash_info entry "fip". Must find at least
+ * one bank.
+ */
+static void
+c302f_probe(flash_info_t *fip, c302f_addr_t base)
+{
+ c302f_addr_t addr, eaddr;
+ int nbanks;
+
+ fip->size = 0L;
+ fip->sector_count = 0;
+
+ addr = base;
+ eaddr = C302F_BNK_ADDR_BASE(addr, C302F_MAX_BANKS);
+ nbanks = 0;
+
+ while (addr < eaddr) {
+ c302f_addr_t addrw, eaddrw, addrb;
+ int i, osc, nsc;
+
+ addrw = addr;
+ eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
+
+ while (addrw < eaddrw)
+ if (c302f_probe_word(addrw++) != 0)
+ goto out;
+
+ /* bank exists - append info for this bank to *fip */
+ fip->flash_id = FLASH_MAN_INTEL|FLASH_28F008S5;
+ fip->size += C302F_BNK_SIZE;
+ osc = fip->sector_count;
+ fip->sector_count += C302F_BNK_NBLOCKS;
+ if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
+ panic("Too many sectors in flash at address 0x%08lx\n",
+ (unsigned long)base);
+
+ addrb = addr;
+ for (i = osc; i < nsc; i++) {
+ fip->start[i] = (ulong)addrb;
+ fip->protect[i] = 0;
+ addrb = C302F_BNK_ADDR_NEXT_BLK(addrb);
+ }
+
+ addr = C302F_BNK_ADDR_NEXT_BNK(addr);
+ nbanks++;
+ }
+
+out:
+ if (nbanks == 0)
+ panic("ERROR: no flash found at address 0x%08lx\n",
+ (unsigned long)base);
+}
+
+static void
+c302f_reset(flash_info_t *info, int sect)
+{
+ c302f_addr_t addrw, eaddrw;
+
+ addrw = (c302f_addr_t)info->start[sect];
+ eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
+
+ while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+ printf(" writing reset cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = C302F_BNK_CMD_RST;
+ addrw++;
+ }
+}
+
+static void
+c302f_erase_init(flash_info_t *info, int sect)
+{
+ c302f_addr_t addrw, saddrw, eaddrw;
+ int flag;
+
+#ifdef FLASH_DEBUG
+ printf("0x%08lx C302F_BNK_CMD_PROG\n", C302F_BNK_CMD_PROG);
+ printf("0x%08lx C302F_BNK_CMD_ERASE1\n", C302F_BNK_CMD_ERASE1);
+ printf("0x%08lx C302F_BNK_CMD_ERASE2\n", C302F_BNK_CMD_ERASE2);
+ printf("0x%08lx C302F_BNK_CMD_CLR_STAT\n", C302F_BNK_CMD_CLR_STAT);
+ printf("0x%08lx C302F_BNK_CMD_RST\n", C302F_BNK_CMD_RST);
+ printf("0x%08lx C302F_BNK_STAT_RDY\n", C302F_BNK_STAT_RDY);
+ printf("0x%08lx C302F_BNK_STAT_ERR\n", C302F_BNK_STAT_ERR);
+#endif
+
+ saddrw = (c302f_addr_t)info->start[sect];
+ eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+ printf("erasing sector %d, start addr = 0x%08lx "
+ "(bank next word addr = 0x%08lx)\n", sect,
+ (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+ /* Disable intrs which might cause a timeout here */
+ flag = disable_interrupts();
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+ printf(" writing erase cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = C302F_BNK_CMD_ERASE1;
+ *addrw = C302F_BNK_CMD_ERASE2;
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+}
+
+static int
+c302f_erase_poll(flash_info_t *info, int sect)
+{
+ c302f_addr_t addrw, saddrw, eaddrw;
+ int sectdone, haderr;
+
+ saddrw = (c302f_addr_t)info->start[sect];
+ eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
+
+ sectdone = 1;
+ haderr = 0;
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+ c302f_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+ printf(" checking status at addr "
+ "0x%08lx [0x%08lx]\n",
+ (unsigned long)addrw, stat);
+#endif
+ if ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY)
+ sectdone = 0;
+ else if ((stat & C302F_BNK_STAT_ERR) != 0) {
+ printf(" failed on sector %d "
+ "(stat = 0x%08lx) at "
+ "address 0x%08lx\n",
+ sect, stat,
+ (unsigned long)addrw);
+ *addrw = C302F_BNK_CMD_CLR_STAT;
+ haderr = 1;
+ }
+ }
+
+ if (haderr)
+ return (-1);
+ else
+ return (sectdone);
+}
+
+static int
+c302f_write_word(c302f_addr_t addr, c302f_word_t value)
+{
+ c302f_word_t stat;
+ ulong start;
+ int flag, retval;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = C302F_BNK_CMD_PROG;
+
+ *addr = value;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ retval = 0;
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ do {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ retval = 1;
+ goto done;
+ }
+ stat = *addr;
+ } while ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY);
+
+ if ((stat & C302F_BNK_STAT_ERR) != 0) {
+ printf("flash program failed (stat = 0x%08lx) "
+ "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+ *addr = C302F_BNK_CMD_CLR_STAT;
+ retval = 3;
+ }
+
+done:
+ /* reset to read mode */
+ *addr = C302F_BNK_CMD_RST;
+
+ return (retval);
+}
+
+#endif /* CONFIG_CMA302 */
+
+unsigned long
+flash_init(void)
+{
+ unsigned long total;
+ int i;
+ flash_info_t *fip;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ fip = &flash_info[0];
+ total = 0L;
+
+#if defined(CONFIG_CMA302)
+ c302f_probe(fip, (c302f_addr_t)CFG_FLASH_BASE);
+ total += fip->size;
+ fip++;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+ /* not yet ...
+ cmbf_probe(fip, (cmbf_addr_t)CMA_MB_FLASH_BASE);
+ total += fip->size;
+ fip++;
+ */
+#endif
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE == CFG_FLASH_BASE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+ return total;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void
+flash_print_info(flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F008S5: printf ("28F008S5\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 4) == 0)
+ printf ("\n ");
+ printf (" %2d - %08lX%s", i,
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+ int prot, sect, haderr;
+ ulong start, now, last;
+ void (*erase_init)(flash_info_t *, int);
+ int (*erase_poll)(flash_info_t *, int);
+ void (*reset)(flash_info_t *, int);
+ int rcode = 0;
+
+#ifdef FLASH_DEBUG
+ printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+ " Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+ (info - flash_info) + 1);
+ flash_print_info(info);
+#endif
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ switch (info->flash_id) {
+
+#if defined(CONFIG_CMA302)
+ case FLASH_MAN_INTEL|FLASH_28F008S5:
+ erase_init = c302f_erase_init;
+ erase_poll = c302f_erase_poll;
+ reset = c302f_reset;
+ break;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+ case FLASH_MAN_INTEL|FLASH_28F800_B:
+ case FLASH_MAN_AMD|FLASH_AM29F800B:
+ /* not yet ...
+ erase_init = cmbf_erase_init;
+ erase_poll = cmbf_erase_poll;
+ reset = cmbf_reset;
+ break;
+ */
+#endif
+
+ default:
+ printf ("Flash type %08lx not supported - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf("- Warning: %d protected sector%s will not be erased!\n",
+ prot, (prot > 1 ? "s" : ""));
+ }
+
+ start = get_timer (0);
+ last = 0;
+ haderr = 0;
+
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ ulong estart;
+ int sectdone;
+
+ (*erase_init)(info, sect);
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ estart = get_timer(start);
+
+ do {
+ now = get_timer(start);
+
+ if (now - estart > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout (sect %d)\n", sect);
+ haderr = 1;
+ break;
+ }
+
+#ifndef FLASH_DEBUG
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+#endif
+
+ sectdone = (*erase_poll)(info, sect);
+
+ if (sectdone < 0) {
+ haderr = 1;
+ break;
+ }
+
+ } while (!sectdone);
+
+ if (haderr)
+ break;
+ }
+ }
+
+ if (haderr > 0) {
+ printf (" failed\n");
+ rcode = 1;
+ }
+ else
+ printf (" done\n");
+
+ /* reset to read mode */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ (*reset)(info, sect);
+ }
+ }
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 3 - write error
+ */
+
+int
+write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+ ulong start, now, last;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ start = get_timer (0);
+ last = 0;
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+
+ /* show that we're waiting */
+ now = get_timer(start);
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 3 - write error
+ */
+static int
+write_word(flash_info_t *info, ulong dest, ulong data)
+{
+ int retval;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*(ulong *)dest & data) != data) {
+ return (2);
+ }
+
+ switch (info->flash_id) {
+
+#if defined(CONFIG_CMA302)
+ case FLASH_MAN_INTEL|FLASH_28F008S5:
+ retval = c302f_write_word((c302f_addr_t)dest, (c302f_word_t)data);
+ break;
+#endif
+
+#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
+ case FLASH_MAN_INTEL|FLASH_28F800_B:
+ case FLASH_MAN_AMD|FLASH_AM29F800B:
+ /* not yet ...
+ retval = cmbf_write_word((cmbf_addr_t)dest, (cmbf_word_t)data);
+ */
+ retval = 3;
+ break;
+#endif
+
+ default:
+ printf ("Flash type %08lx not supported - aborted\n",
+ info->flash_id);
+ retval = 3;
+ break;
+ }
+
+ return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+#define FLASH_BANK_SIZE 0x800000
+#define MAIN_SECT_SIZE 0x40000
+#define PARAM_SECT_SIZE 0x8000
+
+#define BOARD_CTRL_REG 0xFE800013
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+static int write_data (flash_info_t *info, ulong dest, ulong *data);
+static void write_via_fpu(vu_long *addr, ulong *data);
+static __inline__ unsigned long get_msr(void);
+static __inline__ void set_msr(unsigned long msr);
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+/*---------------------------------------------------------------------*/
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init(void)
+{
+ int i, j;
+ ulong size = 0;
+ volatile unsigned char *bcr = (volatile unsigned char *)(BOARD_CTRL_REG);
+
+ DEBUGF("Write protect was: 0x%02X\n", *bcr);
+ *bcr &= 0x1; /* FWPT must be 0 */
+ *bcr |= 0x6; /* FWP0 = FWP1 = 1 */
+ DEBUGF("Write protect is: 0x%02X\n", *bcr);
+
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+ vu_long *addr = (vu_long *)(CFG_FLASH_BASE + i * FLASH_BANK_SIZE);
+
+ addr[0] = 0x00900090;
+
+ DEBUGF ("Flash bank # %d:\n"
+ "\tManuf. ID @ 0x%08lX: 0x%08lX\n"
+ "\tDevice ID @ 0x%08lX: 0x%08lX\n",
+ i,
+ (ulong)(&addr[0]), addr[0],
+ (ulong)(&addr[2]), addr[2]);
+
+ if ((addr[0] == addr[1]) && (addr[0] == INTEL_MANUFACT) &&
+ (addr[2] == addr[3]) && (addr[2] == INTEL_ID_28F160F3B))
+ {
+ flash_info[i].flash_id = (FLASH_MAN_INTEL & FLASH_VENDMASK) |
+ (INTEL_ID_28F160F3B & FLASH_TYPEMASK);
+ } else {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ addr[0] = 0xFFFFFFFF;
+ goto Done;
+ }
+
+ DEBUGF ("flash_id = 0x%08lX\n", flash_info[i].flash_id);
+
+ addr[0] = 0xFFFFFFFF;
+
+ flash_info[i].size = FLASH_BANK_SIZE;
+ flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
+ memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
+ for (j = 0; j < flash_info[i].sector_count; j++) {
+ if (j <= 7) {
+ flash_info[i].start[j] = CFG_FLASH_BASE +
+ i * FLASH_BANK_SIZE +
+ j * PARAM_SECT_SIZE;
+ } else {
+ flash_info[i].start[j] = CFG_FLASH_BASE +
+ i * FLASH_BANK_SIZE +
+ (j - 7)*MAIN_SECT_SIZE;
+ }
+ }
+ size += flash_info[i].size;
+ }
+
+ /* Protect monitor and environment sectors
+ */
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + FLASH_BANK_SIZE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+ &flash_info[1]);
+#else
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+ &flash_info[0]);
+#endif
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+#if CFG_ENV_ADDR >= CFG_FLASH_BASE + FLASH_BANK_SIZE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[1]);
+#else
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[0]);
+#endif
+#endif
+
+Done:
+ return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+ int i;
+
+ switch ((i = info->flash_id & FLASH_VENDMASK)) {
+ case (FLASH_MAN_INTEL & FLASH_VENDMASK):
+ printf ("Intel: ");
+ break;
+ default:
+ printf ("Unknown Vendor 0x%04x ", i);
+ break;
+ }
+
+ switch ((i = info->flash_id & FLASH_TYPEMASK)) {
+ case (INTEL_ID_28F160F3B & FLASH_TYPEMASK):
+ printf ("28F160F3B (16Mbit)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type 0x%04x\n", i);
+ goto Done;
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; i++) {
+ if ((i % 5) == 0) {
+ printf ("\n ");
+ }
+ printf (" %08lX%s", info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+ printf ("\n");
+
+Done:
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong start, now, last;
+
+ DEBUGF ("Erase flash bank %d sect %d ... %d\n",
+ info - &flash_info[0], s_first, s_last);
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) !=
+ (FLASH_MAN_INTEL & FLASH_VENDMASK)) {
+ printf ("Can erase only Intel flash types - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_long *addr = (vu_long *)(info->start[sect]);
+
+ DEBUGF ("Erase sect %d @ 0x%08lX\n",
+ sect, (ulong)addr);
+
+ /* Disable interrupts which might cause a timeout
+ * here.
+ */
+ flag = disable_interrupts();
+
+ addr[0] = 0x00500050; /* clear status register */
+ addr[0] = 0x00200020; /* erase setup */
+ addr[0] = 0x00D000D0; /* erase confirm */
+
+ addr[1] = 0x00500050; /* clear status register */
+ addr[1] = 0x00200020; /* erase setup */
+ addr[1] = 0x00D000D0; /* erase confirm */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while (((addr[0] & 0x00800080) != 0x00800080) ||
+ ((addr[1] & 0x00800080) != 0x00800080) ) {
+ if ((now=get_timer(start)) >
+ CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ addr[0] = 0x00B000B0; /* suspend erase */
+ addr[0] = 0x00FF00FF; /* to read mode */
+ return 1;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ addr[0] = 0x00FF00FF;
+ }
+ }
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define FLASH_WIDTH 8 /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong wp, cp, msr;
+ int l, rc, i;
+ ulong data[2];
+ ulong *datah = &data[0];
+ ulong *datal = &data[1];
+
+ DEBUGF ("Flash write_buff: @ 0x%08lx, src 0x%08lx len %ld\n",
+ addr, (ulong)src, cnt);
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+
+ msr = get_msr();
+ set_msr(msr | MSR_FP);
+
+ wp = (addr & ~(FLASH_WIDTH-1)); /* get lower aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ *datah = *datal = 0;
+
+ for (i = 0, cp = wp; i < l; i++, cp++) {
+ if (i >= 4) {
+ *datah = (*datah << 8) |
+ ((*datal & 0xFF000000) >> 24);
+ }
+
+ *datal = (*datal << 8) | (*(uchar *)cp);
+ }
+ for (; i < FLASH_WIDTH && cnt > 0; ++i) {
+ char tmp;
+
+ tmp = *src;
+
+ src++;
+
+ if (i >= 4) {
+ *datah = (*datah << 8) |
+ ((*datal & 0xFF000000) >> 24);
+ }
+
+ *datal = (*datal << 8) | tmp;
+
+ --cnt; ++cp;
+ }
+
+ for (; cnt == 0 && i < FLASH_WIDTH; ++i, ++cp) {
+ if (i >= 4) {
+ *datah = (*datah << 8) |
+ ((*datal & 0xFF000000) >> 24);
+ }
+
+ *datal = (*datah << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_data(info, wp, data)) != 0) {
+ set_msr(msr);
+ return (rc);
+ }
+
+ wp += FLASH_WIDTH;
+ }
+
+ /*
+ * handle FLASH_WIDTH aligned part
+ */
+ while (cnt >= FLASH_WIDTH) {
+ *datah = *(ulong *)src;
+ *datal = *(ulong *)(src + 4);
+ if ((rc = write_data(info, wp, data)) != 0) {
+ set_msr(msr);
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ cnt -= FLASH_WIDTH;
+ src += FLASH_WIDTH;
+ }
+
+ if (cnt == 0) {
+ set_msr(msr);
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ *datah = *datal = 0;
+ for (i = 0, cp = wp; i < FLASH_WIDTH && cnt > 0; ++i, ++cp) {
+ char tmp;
+
+ tmp = *src;
+
+ src++;
+
+ if (i >= 4) {
+ *datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
+ }
+
+ *datal = (*datal << 8) | tmp;
+
+ --cnt;
+ }
+
+ for (; i < FLASH_WIDTH; ++i, ++cp) {
+ if (i >= 4) {
+ *datah = (*datah << 8) | ((*datal & 0xFF000000) >> 24);
+ }
+
+ *datal = (*datal << 8) | (*(uchar *)cp);
+ }
+
+ rc = write_data(info, wp, data);
+ set_msr(msr);
+
+ return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong *data)
+{
+ vu_long *addr = (vu_long *)dest;
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if (((addr[0] & data[0]) != data[0]) ||
+ ((addr[1] & data[1]) != data[1]) ) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0] = 0x00400040; /* write setup */
+ write_via_fpu(addr, data);
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (((addr[0] & 0x00800080) != 0x00800080) ||
+ ((addr[1] & 0x00800080) != 0x00800080) ) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ addr[0] = 0x00FF00FF; /* restore read mode */
+ return (1);
+ }
+ }
+
+ addr[0] = 0x00FF00FF; /* restore read mode */
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void write_via_fpu(vu_long *addr, ulong *data)
+{
+ __asm__ __volatile__ ("lfd 1, 0(%0)" : : "r" (data));
+ __asm__ __volatile__ ("stfd 1, 0(%0)" : : "r" (addr));
+}
+/*-----------------------------------------------------------------------
+ */
+static __inline__ unsigned long get_msr(void)
+{
+ unsigned long msr;
+
+ __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
+ return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+ __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <linux/byteorder/swab.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET 0x01
+#define FLAG_PROTECT_CLEAR 0x02
+
+/* Board support for 1 or 2 flash devices */
+#undef FLASH_PORT_WIDTH32
+#define FLASH_PORT_WIDTH16
+
+#ifdef FLASH_PORT_WIDTH16
+#define FLASH_PORT_WIDTH ushort
+#define FLASH_PORT_WIDTHV vu_short
+#define SWAP(x) __swab16(x)
+#else
+#define FLASH_PORT_WIDTH ulong
+#define FLASH_PORT_WIDTHV vu_long
+#define SWAP(x) __swab32(x)
+#endif
+
+#define FPW FLASH_PORT_WIDTH
+#define FPWV FLASH_PORT_WIDTHV
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (FPW *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, FPW data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+ size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_FLASH_BASE,
+ CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F640J5 :
+ printf ("28F640J5 \n"); break;
+ default: printf ("Unknown Chip Type=0x%lXh\n",
+ info->flash_id & FLASH_TYPEMASK); break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (FPW *addr, flash_info_t *info)
+{
+ FPW value;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x5555] = (FPW)0xAA00AA00;
+ addr[0x2AAA] = (FPW)0x55005500;
+ addr[0x5555] = (FPW)0x90009000;
+
+ value = SWAP(addr[0]);
+
+ switch (value) {
+ case (FPW)INTEL_MANUFACT:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ addr[0] = (FPW)0xFF00FF00; /* restore read mode */
+ return (0); /* no or unknown flash */
+ }
+
+ value = SWAP(addr[1]); /* device ID no swap !*/
+
+ switch (value) {
+ case (FPW)INTEL_ID_28F640J5 :
+ info->flash_id += FLASH_28F640J5 ;
+ info->sector_count = 64;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ break;
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ addr[0] = (FPW)0xFF00FF00; /* restore read mode */
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong type, start, now, last;
+ int rc = 0;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ type = (info->flash_id & FLASH_VENDMASK);
+ if ((type != FLASH_MAN_INTEL)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ FPWV *addr = (FPWV *)(info->start[sect]);
+ FPW status;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = (FPW)0x50005000; /* clear status register */
+ *addr = (FPW)0x20002000; /* erase setup */
+ *addr = (FPW)0xD000D000; /* erase confirm */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = (FPW)0xB000B000; /* suspend erase */
+ *addr = (FPW)0xFF00FF00; /* reset to read mode */
+ rc = 1;
+ break;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ *addr = (FPW)0xFF00FF00; /* reset to read mode */
+ printf (" done\n");
+ }
+ }
+ return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp;
+ FPW data;
+ int count, i, l, rc, port_width;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+/* get lower word aligned address */
+#ifdef FLASH_PORT_WIDTH16
+ wp = (addr & ~1);
+ port_width = 2;
+#else
+ wp = (addr & ~3);
+ port_width = 4;
+#endif
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<port_width && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<port_width; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += port_width;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ count = 0;
+ while (cnt >= port_width) {
+ data = 0;
+ for (i=0; i<port_width; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += port_width;
+ cnt -= port_width;
+ if ((wp & 0xfff) == 0)
+ {
+ printf("%08lX",wp);
+ printf("\x1b[8D");
+ }
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<port_width; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word or halfword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, FPW data)
+{
+ FPWV *addr = (FPWV *)dest;
+ ulong status;
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*addr & data) != data) {
+ printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = (FPW)0x40004000; /* write setup */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *addr = (FPW)0xFF00FF00; /* restore read mode */
+ return (1);
+ }
+ }
+
+ *addr = (FPW)0xFF00FF00; /* restore read mode */
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Frank Panno <fpanno@delphintech.com>, Delphin Technology AG
+ *
+ * Flash Routines for AMD device AM29DL323DB on the EP8260 board.
+ *
+ * This file is based on board/tqm8260/flash.c.
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#define V_ULONG(a) (*(volatile unsigned long *)( a ))
+#define V_BYTE(a) (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset(void)
+{
+ if( flash_info[0].flash_id != FLASH_UNKNOWN ) {
+ V_ULONG( flash_info[0].start[0] ) = 0x00F000F0;
+ V_ULONG( flash_info[0].start[0] + 4 ) = 0x00F000F0;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size( ulong baseaddr, flash_info_t *info )
+{
+ short i;
+ unsigned long flashtest_h, flashtest_l;
+
+ /* Write auto select command sequence and test FLASH answer */
+ V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055;
+ V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090;
+ V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055;
+ V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090;
+
+ flashtest_h = V_ULONG(baseaddr); /* manufacturer ID */
+ flashtest_l = V_ULONG(baseaddr + 4);
+
+ if ((int)flashtest_h == AMD_MANUFACT) {
+ info->flash_id = FLASH_MAN_AMD;
+ } else {
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ flashtest_h = V_ULONG(baseaddr + 8); /* device ID */
+ flashtest_l = V_ULONG(baseaddr + 12);
+ if (flashtest_h != flashtest_l) {
+ info->flash_id = FLASH_UNKNOWN;
+ return(0);
+ }
+ if (flashtest_h == AMD_ID_DL323B) {
+ info->flash_id += FLASH_AMDL323B;
+ info->sector_count = 71;
+ info->size = 0x01000000; /* 4 * 4 MB = 16 MB */
+ } else {
+ info->flash_id = FLASH_UNKNOWN;
+ return(0); /* no or unknown flash */
+ }
+
+ /* set up sector start adress table (bottom sector type) */
+ for (i = 0; i < 8; i++) {
+ info->start[i] = baseaddr + (i * 0x00008000);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) ||
+ (V_ULONG( info->start[i] + 20 ) & 0x00010001)) {
+ info->protect[i] = 1; /* D0 = 1 if protected */
+ } else {
+ info->protect[i] = 0;
+ }
+ }
+
+ flash_reset();
+ return(info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+ unsigned long size_b0 = 0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here (only one bank) */
+
+ size_b0 = flash_get_size(CFG_FLASH0_BASE, &flash_info[0]);
+ if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0>>20);
+ }
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[0]);
+#endif
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch ((info->flash_id >> 16) & 0xff) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AMDL323B: printf ("29DL323B (32 M, bottom sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect])
+ prot++;
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+ V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00800080;
+ V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+ V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+ V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00800080;
+ V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+ udelay (1000);
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ V_ULONG( info->start[sect] ) = 0x00300030;
+ V_ULONG( info->start[sect] + 4 ) = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ while ((V_ULONG( info->start[l_sect] ) & 0x00800080) != 0x00800080 ||
+ (V_ULONG( info->start[l_sect] + 4 ) & 0x00800080) != 0x00800080)
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ flash_reset ();
+
+ printf (" done\n");
+ return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong dp;
+ static unsigned char bb[8];
+ int i, l, rc, cc = cnt;
+
+ dp = (addr & ~7); /* get lower dword aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - dp) != 0) {
+ for (i = 0; i < 8; i++)
+ bb[i] = (i < l || (i-l) >= cc) ? V_BYTE(dp+i) : *src++;
+ if ((rc = write_dword(info, dp, bb)) != 0)
+ {
+ return (rc);
+ }
+ dp += 8;
+ cc -= 8 - l;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cc >= 8) {
+ if ((rc = write_dword(info, dp, src)) != 0) {
+ return (rc);
+ }
+ dp += 8;
+ src += 8;
+ cc -= 8;
+ }
+
+ if (cc <= 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ for (i = 0; i < 8; i++) {
+ bb[i] = (i < cc) ? *src++ : V_BYTE(dp+i);
+ }
+ return (write_dword(info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t *info, ulong dest, unsigned char * pdata)
+{
+ ulong start;
+ ulong cl = 0, ch =0;
+ int flag, i;
+
+ for (ch=0, i=0; i < 4; i++)
+ ch = (ch << 8) + *pdata++; /* high word */
+ for (cl=0, i=0; i < 4; i++)
+ cl = (cl << 8) + *pdata++; /* low word */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & ch) != ch
+ ||(*((vu_long *)(dest + 4)) & cl) != cl)
+ {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + (0x02AA << 3) ) = 0x00550055;
+ V_ULONG( info->start[0] + (0x0555 << 3) ) = 0x00A000A0;
+ V_ULONG( dest ) = ch;
+ V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00AA00AA;
+ V_ULONG( info->start[0] + 4 + (0x02AA << 3) ) = 0x00550055;
+ V_ULONG( info->start[0] + 4 + (0x0555 << 3) ) = 0x00A000A0;
+ V_ULONG( dest + 4 ) = cl;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while (((V_ULONG( dest ) & 0x00800080) != (ch & 0x00800080)) ||
+ ((V_ULONG( dest + 4 ) & 0x00800080) != (cl & 0x00800080))) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
--- /dev/null
+#include <common.h>
+#include <mii_phy.h>
+#include "ep8260.h"
+
+#define MII_MDIO 0x01
+#define MII_MDCK 0x02
+#define MII_MDIR 0x04
+
+void
+mii_discover_phy(void)
+{
+ int known;
+ unsigned short phy_reg;
+ unsigned long phy_id;
+
+ known = 0;
+ printf("Discovering phy @ 0: ");
+ phy_id = mii_phy_read(2) << 16;
+ phy_id |= mii_phy_read(3);
+ if ((phy_id & 0xFFFFFC00) == 0x00137800) {
+ printf("Level One ");
+ if ((phy_id & 0x000003F0) == 0xE0) {
+ printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
+ known = 1;
+ }
+ else printf("unknown type\n");
+ }
+ else printf("unknown OUI = 0x%08lX\n", phy_id);
+
+ phy_reg = mii_phy_read(1);
+ if (!(phy_reg & 0x0004)) printf("Link is down\n");
+ if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
+ if (phy_reg & 0x0002) printf("Jabber condition detected\n");
+ if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
+
+ if (known) {
+ phy_reg = mii_phy_read(17);
+ if (phy_reg & 0x0400)
+ printf("Phy operating at %d MBit/s in %s-duplex mode\n",
+ phy_reg & 0x4000 ? 100 : 10,
+ phy_reg & 0x0200 ? "full" : "half");
+ else
+ printf("bad link!!\n");
+/*
+left off: no link, green 100MBit, yellow 10MBit
+right off: no activity, green full-duplex, yellow half-duplex
+*/
+ mii_phy_write(20, 0x0452);
+ }
+}
+
+unsigned short
+mii_phy_read(unsigned short reg)
+{
+ int i;
+ unsigned short tmp, val = 0, adr = 0;
+ t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
+
+ tmp = 0x6002 | (adr << 7) | (reg << 2);
+ regs->bcsr4 = 0xC3;
+ for (i = 0; i < 64; i++) {
+ regs->bcsr4 ^= MII_MDCK;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ tmp <<= 1;
+ }
+ regs->bcsr4 |= MII_MDIR;
+ for (i = 0; i < 16; i++) {
+ val <<= 1;
+ regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
+ if (regs->bcsr4 & MII_MDIO) val |= 1;
+ regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
+ }
+ return val;
+}
+
+void
+mii_phy_write(unsigned short reg, unsigned short val)
+{
+ int i;
+ unsigned short tmp, adr = 0;
+ t_ep_regs *regs = (t_ep_regs*)CFG_REGS_BASE;
+
+ tmp = 0x5002 | (adr << 7) | (reg << 2);
+ regs->bcsr4 = 0xC3;
+ for (i = 0; i < 64; i++) {
+ regs->bcsr4 ^= MII_MDCK;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ tmp <<= 1;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ val <<= 1;
+ }
+}
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
+ FLASH_BASE0_PRELIM+size_b0-1,
+ &flash_info[0]);
+
+ if (size_b1) {
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(FLASH_BASE0_PRELIM + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (FLASH_BASE0_PRELIM + size_b0, &flash_info[1]);
+
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ FLASH_BASE0_PRELIM+size_b0+size_b1-CFG_MONITOR_LEN,
+ FLASH_BASE0_PRELIM+size_b0+size_b1-1,
+ &flash_info[1]);
+ /* monitor protection OFF by default (one is enough) */
+ flash_protect(FLAG_PROTECT_CLEAR,
+ FLASH_BASE0_PRELIM+size_b0-CFG_MONITOR_LEN,
+ FLASH_BASE0_PRELIM+size_b0-1,
+ &flash_info[0]);
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+ short n;
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
+ /* set sector offsets for bottom boot block type */
+ for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
+ info->start[i] = base;
+ base += 8 << 10;
+ }
+ while (i < info->sector_count) { /* 64k regular sectors */
+ info->start[i] = base;
+ base += 64 << 10;
+ ++i;
+ }
+ } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
+ /* set sector offsets for top boot block type */
+ base += info->size;
+ i = info->sector_count;
+ for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
+ base -= 8 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ while (i > 0) { /* 64k regular sectors */
+ base -= 64 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+ int k;
+ int size;
+ int erased;
+ volatile unsigned long *flash;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 M, top sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL322T: printf ("AM29DL322T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL322B: printf ("AM29DL322B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL323T: printf ("AM29DL323T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL323B: printf ("AM29DL323B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AM640U: printf ("AM29LV640D (64 M, uniform sector)\n");
+ break;
+ case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+#ifdef CFG_FLASH_EMPTY_INFO
+ /*
+ * Check if whole sector is erased
+ */
+ if (i != (info->sector_count-1))
+ size = info->start[i+1] - info->start[i];
+ else
+ size = info->start[0] + info->size - info->start[i];
+ erased = 1;
+ flash = (volatile unsigned long *)info->start[i];
+ size = size >> 2; /* divide by 4 for longword access */
+ for (k=0; k<size; k++)
+ {
+ if (*flash++ != 0xffffffff)
+ {
+ erased = 0;
+ break;
+ }
+ }
+
+ if ((i % 5) == 0)
+ printf ("\n ");
+ /* print empty and read-only info */
+ printf (" %08lX%s%s",
+ info->start[i],
+ erased ? " E" : " ",
+ info->protect[i] ? "RO " : " ");
+#else
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+#endif
+
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ short n;
+ CFG_FLASH_WORD_SIZE value;
+ ulong base = (ulong)addr;
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;
+
+ value = addr2[CFG_FLASH_READ0];
+
+ switch (value) {
+ case (CFG_FLASH_WORD_SIZE)AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (CFG_FLASH_WORD_SIZE)FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (CFG_FLASH_WORD_SIZE)SST_MANUFACT:
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr2[CFG_FLASH_READ1]; /* device ID */
+
+ switch (value) {
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322T:
+ info->flash_id += FLASH_AMDL322T;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322B:
+ info->flash_id += FLASH_AMDL322B;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323T:
+ info->flash_id += FLASH_AMDL323T;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323B:
+ info->flash_id += FLASH_AMDL323B;
+ info->sector_count = 71;
+ info->size = 0x00400000; break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE)AMD_ID_LV640U:
+ info->flash_id += FLASH_AM640U;
+ info->sector_count = 128;
+ info->size = 0x00800000; break; /* => 8 MB */
+
+ case (CFG_FLASH_WORD_SIZE)SST_ID_xF800A:
+ info->flash_id += FLASH_SST800A;
+ info->sector_count = 16;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_WORD_SIZE)SST_ID_xF160A:
+ info->flash_id += FLASH_SST160A;
+ info->sector_count = 32;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {
+ /* set sector offsets for bottom boot block type */
+ for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
+ info->start[i] = base;
+ base += 8 << 10;
+ }
+ while (i < info->sector_count) { /* 64k regular sectors */
+ info->start[i] = base;
+ base += 64 << 10;
+ ++i;
+ }
+ } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {
+ /* set sector offsets for top boot block type */
+ base += info->size;
+ i = info->sector_count;
+ for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
+ base -= 8 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ while (i > 0) { /* 64k regular sectors */
+ base -= 64 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
+ info->protect[i] = 0;
+ else
+ info->protect[i] = addr2[CFG_FLASH_READ2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr2 = (CFG_FLASH_WORD_SIZE *)info->start[0];
+ *addr2 = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *addr2;
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+ int i;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */
+ for (i=0; i<50; i++)
+ udelay(1000); /* wait 1 ms */
+ } else {
+ if (sect == s_first) {
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ }
+ addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030; /* sector erase */
+ }
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);
+ while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (CFG_FLASH_WORD_SIZE *)info->start[0];
+ addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;
+ volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;
+ ulong start;
+ int flag;
+ int i;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((volatile CFG_FLASH_WORD_SIZE *)dest) &
+ (CFG_FLASH_WORD_SIZE)data) != (CFG_FLASH_WORD_SIZE)data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)
+ {
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
+ addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;
+
+ dest2[i] = data2[i];
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=
+ (data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+ uint pbcr;
+ unsigned long base_b0, base_b1;
+ int size_val = 0;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ base_b0 = FLASH_BASE0_PRELIM;
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 << 20);
+ }
+
+ base_b1 = FLASH_BASE1_PRELIM;
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ /* Re-do sizing to get full correct info */
+
+ if (size_b1) {
+ mtdcr (ebccfga, pb0cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb0cr);
+ base_b1 = -size_b1;
+ switch (size_b1) {
+ case 1 << 20:
+ size_val = 0;
+ break;
+ case 2 << 20:
+ size_val = 1;
+ break;
+ case 4 << 20:
+ size_val = 2;
+ break;
+ case 8 << 20:
+ size_val = 3;
+ break;
+ case 16 << 20:
+ size_val = 4;
+ break;
+ default:
+ size_val = 0;
+ break;
+
+ }
+ pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb1cr = %x\n", pbcr); */
+ }
+
+ if (size_b0) {
+ mtdcr (ebccfga, pb1cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb1cr);
+ base_b0 = base_b1 - size_b0;
+ switch (size_b1) {
+ case 1 << 20:
+ size_val = 0;
+ break;
+ case 2 << 20:
+ size_val = 1;
+ break;
+ case 4 << 20:
+ size_val = 2;
+ break;
+ case 8 << 20:
+ size_val = 3;
+ break;
+ case 16 << 20:
+ size_val = 4;
+ break;
+ }
+ pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb0cr = %x\n", pbcr); */
+ }
+
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ flash_get_offsets (base_b0, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+
+ if (size_b1) {
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ flash_get_offsets (base_b1, &flash_info[1]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b1 + size_b1 - CFG_MONITOR_LEN,
+ base_b1 + size_b1 - 1, &flash_info[1]);
+ /* monitor protection OFF by default (one is enough) */
+ flash_protect (FLAG_PROTECT_CLEAR,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <pci.h>
+
+#define OK 0
+#define ERROR (-1)
+
+#define TRUE 1
+#define FALSE 0
+
+
+extern u_long pci9054_iobase;
+
+
+/***************************************************************************
+ *
+ * Routines for PLX PCI9054 eeprom access
+ *
+ */
+
+static unsigned int PciEepromReadLongVPD(int offs)
+{
+ unsigned int value;
+ unsigned int ret;
+ int count;
+
+ pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x0003);
+ count = 0;
+
+ for (;;)
+ {
+ udelay(10 * 1000);
+ pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
+ if ((ret & 0x80000000) != 0)
+ {
+ break;
+ }
+ else
+ {
+ count++;
+ if (count > 10)
+ {
+ printf("\nTimeout: ret=%08x - Please try again!\n", ret);
+ break;
+ }
+ }
+ }
+
+ pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x50, &value);
+
+ return value;
+}
+
+
+static int PciEepromWriteLongVPD(int offs, unsigned int value)
+{
+ unsigned int ret;
+ int count;
+
+ pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x50, value);
+ pci_write_config_dword(CFG_PCI9054_DEV_FN, 0x4c, (offs<<16) | 0x80000003);
+ count = 0;
+
+ for (;;)
+ {
+ udelay(10 * 1000);
+ pci_read_config_dword(CFG_PCI9054_DEV_FN, 0x4c, &ret);
+ if ((ret & 0x80000000) == 0)
+ {
+ break;
+ }
+ else
+ {
+ count++;
+ if (count > 10)
+ {
+ printf("\nTimeout: ret=%08x - Please try again!\n", ret);
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+static void showPci9054(void)
+{
+ int val;
+ int l, i;
+
+ /* read 9054-values */
+ for (l=0; l<6; l++)
+ {
+ printf("%02x: ", l*0x10);
+ for (i=0; i<4; i++)
+ {
+ pci_read_config_dword(CFG_PCI9054_DEV_FN, l*16+i*4, &val);
+ printf("%08x ", val);
+ }
+ printf("\n");
+ }
+ printf("\n");
+
+ for (l=0; l<7; l++)
+ {
+ printf("%02x: ", l*0x10);
+ for (i=0; i<4; i++)
+ printf("%08x ", PciEepromReadLongVPD((i+l*4)*4));
+ printf("\n");
+ }
+ printf("\n");
+}
+
+
+static void updatePci9054(void)
+{
+ int val;
+
+ /*
+ * Set EEPROM write-protect register to 0
+ */
+ out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
+
+ /* Long Serial EEPROM Load Registers... */
+ val = PciEepromWriteLongVPD(0x00, 0x905410b5);
+ val = PciEepromWriteLongVPD(0x04, 0x09800001); /* other input controller */
+ val = PciEepromWriteLongVPD(0x08, 0x28140100);
+
+ val = PciEepromWriteLongVPD(0x0c, 0x00000000); /* MBOX0... */
+ val = PciEepromWriteLongVPD(0x10, 0x00000000);
+
+ /* las0: fpga access (0x0000.0000 ... 0x0003.ffff) */
+ val = PciEepromWriteLongVPD(0x14, 0xfffc0000); /* LAS0RR... */
+ val = PciEepromWriteLongVPD(0x18, 0x00000001); /* LAS0BA */
+
+ val = PciEepromWriteLongVPD(0x1c, 0x00200000); /* MARBR... */
+ val = PciEepromWriteLongVPD(0x20, 0x00300500); /* LMISC/BIGEND */
+
+ val = PciEepromWriteLongVPD(0x24, 0x00000000); /* EROMRR... */
+ val = PciEepromWriteLongVPD(0x28, 0x00000000); /* EROMBA */
+
+ val = PciEepromWriteLongVPD(0x2c, 0x43030000); /* LBRD0... */
+
+ val = PciEepromWriteLongVPD(0x30, 0x00000000); /* DMRR... */
+ val = PciEepromWriteLongVPD(0x34, 0x00000000);
+ val = PciEepromWriteLongVPD(0x38, 0x00000000);
+
+ val = PciEepromWriteLongVPD(0x3c, 0x00000000); /* DMPBAM... */
+ val = PciEepromWriteLongVPD(0x40, 0x00000000);
+
+ /* Extra Long Serial EEPROM Load Registers... */
+ val = PciEepromWriteLongVPD(0x44, 0x010212fe); /* PCISID... */
+
+ /* las1: 505-sram access (0x0004.0000 ... 0x001f.ffff) */
+ /* Offset to LAS1: Group 1: 0x00040000 */
+ /* Group 2: 0x00080000 */
+ /* Group 3: 0x000c0000 */
+ val = PciEepromWriteLongVPD(0x48, 0xffe00000); /* LAS1RR */
+ val = PciEepromWriteLongVPD(0x4c, 0x00040001); /* LAS1BA */
+ val = PciEepromWriteLongVPD(0x50, 0x00000208); /* LBRD1 */ /* so wars bisher */
+
+ val = PciEepromWriteLongVPD(0x54, 0x00004c06); /* HotSwap... */
+
+ printf("Finished writing defaults into PLX PCI9054 EEPROM!\n");
+}
+
+
+static void clearPci9054(void)
+{
+ int val;
+
+ /*
+ * Set EEPROM write-protect register to 0
+ */
+ out32(pci9054_iobase+0x0c, in32(pci9054_iobase+0x0c) & 0xffff00ff);
+
+ /* Long Serial EEPROM Load Registers... */
+ val = PciEepromWriteLongVPD(0x00, 0xffffffff);
+ val = PciEepromWriteLongVPD(0x04, 0xffffffff); /* other input controller */
+
+ printf("Finished clearing PLX PCI9054 EEPROM!\n");
+}
+
+
+/* ------------------------------------------------------------------------- */
+int do_pci9054(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+ if (strcmp(argv[1], "info") == 0)
+ {
+ showPci9054();
+ return 0;
+ }
+
+ if (strcmp(argv[1], "update") == 0)
+ {
+ updatePci9054();
+ return 0;
+ }
+
+ if (strcmp(argv[1], "clear") == 0)
+ {
+ clearPci9054();
+ return 0;
+ }
+
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0;
+ int i;
+ unsigned long base_b0;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ /* Setup offsets */
+ flash_get_offsets (-size_b0, &flash_info[0]);
+
+ base_b0 = -size_b0;
+
+ /* Monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ -CFG_MONITOR_LEN,
+ 0xffffffff,
+ &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+ return (size_b0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+ uint pbcr;
+ unsigned long base_b0, base_b1;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ base_b0 = FLASH_BASE0_PRELIM;
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 << 20);
+ }
+
+ base_b1 = FLASH_BASE1_PRELIM;
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ /* Re-do sizing to get full correct info */
+
+ if (size_b1) {
+ mtdcr (ebccfga, pb0cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb0cr);
+ base_b1 = -size_b1;
+ pbcr = (pbcr & 0x0001ffff) | base_b1 |
+ (((size_b1 / 1024 / 1024) - 1) << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb1cr = %x\n", pbcr); */
+ }
+
+ if (size_b0) {
+ mtdcr (ebccfga, pb1cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb1cr);
+ base_b0 = base_b1 - size_b0;
+ pbcr = (pbcr & 0x0001ffff) | base_b0 |
+ (((size_b0 / 1024 / 1024) - 1) << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb0cr = %x\n", pbcr); */
+ }
+
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ flash_get_offsets (base_b0, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+
+ if (size_b1) {
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ flash_get_offsets (base_b1, &flash_info[1]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b1 + size_b1 - CFG_MONITOR_LEN,
+ base_b1 + size_b1 - 1, &flash_info[1]);
+ /* monitor protection OFF by default (one is enough) */
+ flash_protect (FLAG_PROTECT_CLEAR,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+ uint pbcr;
+ unsigned long base_b0, base_b1;
+ int size_val = 0;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ base_b0 = FLASH_BASE0_PRELIM;
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 << 20);
+ }
+
+ base_b1 = FLASH_BASE1_PRELIM;
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ /* Re-do sizing to get full correct info */
+
+ if (size_b1) {
+ mtdcr (ebccfga, pb0cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb0cr);
+ base_b1 = -size_b1;
+ switch (size_b1) {
+ case 1 << 20:
+ size_val = 0;
+ break;
+ case 2 << 20:
+ size_val = 1;
+ break;
+ case 4 << 20:
+ size_val = 2;
+ break;
+ case 8 << 20:
+ size_val = 3;
+ break;
+ case 16 << 20:
+ size_val = 4;
+ break;
+ }
+ pbcr = (pbcr & 0x0001ffff) | base_b1 | (size_val << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb1cr = %x\n", pbcr); */
+ }
+
+ if (size_b0) {
+ mtdcr (ebccfga, pb1cr);
+ pbcr = mfdcr (ebccfgd);
+ mtdcr (ebccfga, pb1cr);
+ base_b0 = base_b1 - size_b0;
+ switch (size_b1) {
+ case 1 << 20:
+ size_val = 0;
+ break;
+ case 2 << 20:
+ size_val = 1;
+ break;
+ case 4 << 20:
+ size_val = 2;
+ break;
+ case 8 << 20:
+ size_val = 3;
+ break;
+ case 16 << 20:
+ size_val = 4;
+ break;
+ }
+ pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+ mtdcr (ebccfgd, pbcr);
+ /* printf("pb0cr = %x\n", pbcr); */
+ }
+
+ size_b0 = flash_get_size ((vu_long *) base_b0, &flash_info[0]);
+
+ flash_get_offsets (base_b0, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+
+ if (size_b1) {
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size ((vu_long *) base_b1, &flash_info[1]);
+
+ flash_get_offsets (base_b1, &flash_info[1]);
+
+ /* monitor protection ON by default */
+ flash_protect (FLAG_PROTECT_SET,
+ base_b1 + size_b1 - CFG_MONITOR_LEN,
+ base_b1 + size_b1 - 1, &flash_info[1]);
+ /* monitor protection OFF by default (one is enough) */
+ flash_protect (FLAG_PROTECT_CLEAR,
+ base_b0 + size_b0 - CFG_MONITOR_LEN,
+ base_b0 + size_b0 - 1, &flash_info[0]);
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+/*
+ * include common flash code (for esd boards)
+ */
+#include "../common/flash.c"
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long * addr, flash_info_t * info);
+static void flash_get_offsets (ulong base, flash_info_t * info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0;
+ int i;
+ uint pbcr;
+ unsigned long base_b0;
+ int size_val = 0;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ /* Setup offsets */
+ flash_get_offsets (-size_b0, &flash_info[0]);
+
+ /* Re-do sizing to get full correct info */
+ mtdcr(ebccfga, pb0cr);
+ pbcr = mfdcr(ebccfgd);
+ mtdcr(ebccfga, pb0cr);
+ base_b0 = -size_b0;
+ switch (size_b0) {
+ case 1 << 20:
+ size_val = 0;
+ break;
+ case 2 << 20:
+ size_val = 1;
+ break;
+ case 4 << 20:
+ size_val = 2;
+ break;
+ case 8 << 20:
+ size_val = 3;
+ break;
+ case 16 << 20:
+ size_val = 4;
+ break;
+ }
+ pbcr = (pbcr & 0x0001ffff) | base_b0 | (size_val << 17);
+ mtdcr(ebccfgd, pbcr);
+
+ /* Monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ -CFG_MONITOR_LEN,
+ 0xffffffff,
+ &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+ return (size_b0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#ifdef CONFIG_FLASH_16BIT
+#define FLASH_WORD_SIZE unsigned short
+#define FLASH_ID_MASK 0xFFFF
+#else
+#define FLASH_WORD_SIZE unsigned long
+#define FLASH_ID_MASK 0xFFFFFFFF
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info);
+#ifndef CONFIG_FLASH_16BIT
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+#else
+static int write_short (flash_info_t *info, ulong dest, ushort data);
+#endif
+/*int flash_write (uchar *, ulong, ulong); */
+/*flash_info_t *addr2info (ulong); */
+
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE0_PRELIM,
+ &flash_info[0]);
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)FLASH_BASE1_PRELIM,
+ &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = CFG_FLASH_BASE | 0x00000801; /* (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;*/
+
+ /* Re-do sizing to get full correct info */
+
+ size_b0 = flash_get_size((volatile FLASH_WORD_SIZE *)CFG_FLASH_BASE,
+ &flash_info[0]);
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+ memctl->memc_br1 = (CFG_FLASH_BASE | 0x00000801) + (size_b0 & BR_BA_MSK);
+ /*((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V;*/
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((volatile FLASH_WORD_SIZE *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+ } else {
+ memctl->memc_br1 = 0; /* invalidate bank */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE) {
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00008000;
+ info->start[3] = base + 0x0000C000;
+ info->start[4] = base + 0x00010000;
+ info->start[5] = base + 0x00014000;
+ info->start[6] = base + 0x00018000;
+ info->start[7] = base + 0x0001C000;
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x000E0000;
+ }
+ }
+ else {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ }
+#else
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00002000;
+ info->start[2] = base + 0x00004000;
+ info->start[3] = base + 0x00006000;
+ info->start[4] = base + 0x00008000;
+ info->start[5] = base + 0x0000A000;
+ info->start[6] = base + 0x0000C000;
+ info->start[7] = base + 0x0000E000;
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00070000;
+ }
+ }
+ else {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ }
+#endif
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ info->start[i--] = base + info->size - 0x00014000;
+ info->start[i--] = base + info->size - 0x00018000;
+ info->start[i--] = base + info->size - 0x0001C000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+
+ } else {
+
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+#else
+ info->start[i--] = base + info->size - 0x00002000;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000A000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x0000E000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+
+ } else {
+
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+#endif
+ }
+
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+ uchar *boottype;
+ uchar botboot[]=", bottom boot sect)\n";
+ uchar topboot[]=", top boot sector)\n";
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ if (info->flash_id & 0x0001 ) {
+ boottype = botboot;
+ } else {
+ boottype = topboot;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit%s",boottype);
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit%s",boottype);
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit%s",boottype);
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit%s",boottype);
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit%s",boottype);
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit%s",boottype);
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit%s",boottype);
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL800B: printf ("INTEL28F800B (8 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL800T: printf ("INTEL28F800T (8 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL160B: printf ("INTEL28F160B (16 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL160T: printf ("INTEL28F160T (16 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL320B: printf ("INTEL28F320B (32 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL320T: printf ("INTEL28F320T (32 Mbit%s",boottype);
+ break;
+
+#if 0 /* enable when devices are available */
+
+ case FLASH_INTEL640B: printf ("INTEL28F640B (64 Mbit%s",boottype);
+ break;
+ case FLASH_INTEL640T: printf ("INTEL28F640T (64 Mbit%s",boottype);
+ break;
+#endif
+
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+ulong flash_get_size (volatile FLASH_WORD_SIZE *addr, flash_info_t *info)
+{
+ short i;
+ ulong base = (ulong)addr;
+ FLASH_WORD_SIZE value;
+
+ /* Write auto select command: read Manufacturer ID */
+
+
+#ifndef CONFIG_FLASH_16BIT
+
+ /*
+ * Note: if it is an AMD flash and the word at addr[0000]
+ * is 0x00890089 this routine will think it is an Intel
+ * flash device and may(most likely) cause trouble.
+ */
+
+ addr[0x0000] = 0x00900090;
+ if(addr[0x0000] != 0x00890089){
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+#else
+
+ /*
+ * Note: if it is an AMD flash and the word at addr[0000]
+ * is 0x0089 this routine will think it is an Intel
+ * flash device and may(most likely) cause trouble.
+ */
+
+ addr[0x0000] = 0x0090;
+
+ if(addr[0x0000] != 0x0089){
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+ addr[0x0555] = 0x0090;
+#endif
+ }
+ value = addr[0];
+
+ switch (value) {
+ case (AMD_MANUFACT & FLASH_ID_MASK):
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (FUJ_MANUFACT & FLASH_ID_MASK):
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (STM_MANUFACT & FLASH_ID_MASK):
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ case (SST_MANUFACT & FLASH_ID_MASK):
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case (INTEL_MANUFACT & FLASH_ID_MASK):
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+
+ case (AMD_ID_LV400T & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV400B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV800T & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (AMD_ID_LV800B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (AMD_ID_LV160T & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (AMD_ID_LV160B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case (AMD_ID_LV320T & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_LV320B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+
+ case (INTEL_ID_28F800B3T & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL800T;
+ info->sector_count = 23;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (INTEL_ID_28F800B3B & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL800B;
+ info->sector_count = 23;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (INTEL_ID_28F160B3T & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL160T;
+ info->sector_count = 39;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (INTEL_ID_28F160B3B & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL160B;
+ info->sector_count = 39;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL320T;
+ info->sector_count = 71;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 71;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+#if 0 /* enable when devices are available */
+ case (INTEL_ID_28F320B3T & FLASH_ID_MASK):
+ info->flash_id += FLASH_INTEL320T;
+ info->sector_count = 135;
+ info->size = 0x01000000;
+ break; /* => 16 MB */
+
+ case (INTEL_ID_28F320B3B & FLASH_ID_MASK):
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 135;
+ info->size = 0x01000000;
+ break; /* => 16 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE) {
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00008000;
+ info->start[3] = base + 0x0000C000;
+ info->start[4] = base + 0x00010000;
+ info->start[5] = base + 0x00014000;
+ info->start[6] = base + 0x00018000;
+ info->start[7] = base + 0x0001C000;
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x000E0000;
+ }
+ }
+ else {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ }
+#else
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00002000;
+ info->start[2] = base + 0x00004000;
+ info->start[3] = base + 0x00006000;
+ info->start[4] = base + 0x00008000;
+ info->start[5] = base + 0x0000A000;
+ info->start[6] = base + 0x0000C000;
+ info->start[7] = base + 0x0000E000;
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00070000;
+ }
+ }
+ else {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ }
+#endif
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+
+#ifndef CONFIG_FLASH_16BIT
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ info->start[i--] = base + info->size - 0x00014000;
+ info->start[i--] = base + info->size - 0x00018000;
+ info->start[i--] = base + info->size - 0x0001C000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+
+ } else {
+
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+#else
+ info->start[i--] = base + info->size - 0x00002000;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000A000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x0000E000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+
+ } else {
+
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+#endif
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile FLASH_WORD_SIZE *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+ if( (info->flash_id & 0xFF00) == FLASH_MAN_INTEL){
+ *addr = (0x00F000F0 & FLASH_ID_MASK); /* reset bank */
+ } else {
+ *addr = (0x00FF00FF & FLASH_ID_MASK); /* reset bank */
+ }
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+
+ volatile FLASH_WORD_SIZE *addr=(volatile FLASH_WORD_SIZE*)(info->start[0]);
+ int flag, prot, sect, l_sect, barf;
+ ulong start, now, last;
+ int rcode = 0;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ ((info->flash_id > FLASH_AMD_COMP) &&
+ ( (info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL ) ) ){
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+ if(info->flash_id < FLASH_AMD_COMP) {
+#ifndef CONFIG_FLASH_16BIT
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+#else
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+ addr[0x0555] = 0x0080;
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+#endif
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (volatile FLASH_WORD_SIZE *)(info->start[sect]);
+ addr[0] = (0x00300030 & FLASH_ID_MASK);
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (volatile FLASH_WORD_SIZE*)(info->start[l_sect]);
+ while ((addr[0] & (0x00800080&FLASH_ID_MASK)) !=
+ (0x00800080&FLASH_ID_MASK) )
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+ addr[0] = (0x00F000F0 & FLASH_ID_MASK); /* reset bank */
+ } else {
+
+
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ barf = 0;
+#ifndef CONFIG_FLASH_16BIT
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00200020;
+ addr[0] = 0x00D000D0;
+ while(!(addr[0] & 0x00800080)); /* wait for error or finish */
+ if( addr[0] & 0x003A003A) { /* check for error */
+ barf = addr[0] & 0x003A0000;
+ if( barf ) {
+ barf >>=16;
+ } else {
+ barf = addr[0] & 0x0000003A;
+ }
+ }
+#else
+ addr = (vu_short*)(info->start[sect]);
+ addr[0] = 0x0020;
+ addr[0] = 0x00D0;
+ while(!(addr[0] & 0x0080)); /* wait for error or finish */
+ if( addr[0] & 0x003A) /* check for error */
+ barf = addr[0] & 0x003A;
+#endif
+ if(barf) {
+ printf("\nFlash error in sector at %lx\n",(unsigned long)addr);
+ if(barf & 0x0002) printf("Block locked, not erased.\n");
+ if((barf & 0x0030) == 0x0030)
+ printf("Command Sequence error.\n");
+ if((barf & 0x0030) == 0x0020)
+ printf("Block Erase error.\n");
+ if(barf & 0x0008) printf("Vpp Low error.\n");
+ rcode = 1;
+ } else printf(".");
+ l_sect = sect;
+ }
+ addr = (volatile FLASH_WORD_SIZE *)info->start[0];
+ addr[0] = (0x00FF00FF & FLASH_ID_MASK); /* reset bank */
+
+ }
+
+ }
+ printf (" done\n");
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+#ifndef CONFIG_FLASH_16BIT
+ ulong cp, wp, data;
+ int l;
+#else
+ ulong cp, wp;
+ ushort data;
+#endif
+ int i, rc;
+
+#ifndef CONFIG_FLASH_16BIT
+
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+
+#else
+ wp = (addr & ~1); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start byte
+ */
+ if (addr - wp) {
+ data = 0;
+ data = (data << 8) | *src++;
+ --cnt;
+ if ((rc = write_short(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 2;
+ }
+
+ /*
+ * handle word aligned part
+ */
+/* l = 0; used for debuging */
+ while (cnt >= 2) {
+ data = 0;
+ for (i=0; i<2; ++i) {
+ data = (data << 8) | *src++;
+ }
+
+/* if(!l){
+ printf("%x",data);
+ l = 1;
+ } used for debuging */
+
+ if ((rc = write_short(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 2;
+ cnt -= 2;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<2; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_short(info, wp, data));
+
+
+#endif
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+#ifndef CONFIG_FLASH_16BIT
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start,barf;
+ int flag;
+
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ if(info->flash_id > FLASH_AMD_COMP) {
+ /* AMD stuff */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+ } else {
+ /* intel stuff */
+ *addr = 0x00400040;
+ }
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+
+ if(info->flash_id > FLASH_AMD_COMP) {
+
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+
+ } else {
+
+ while(!(addr[0] & 0x00800080)){ /* wait for error or finish */
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+
+ if( addr[0] & 0x003A003A) { /* check for error */
+ barf = addr[0] & 0x003A0000;
+ if( barf ) {
+ barf >>=16;
+ } else {
+ barf = addr[0] & 0x0000003A;
+ }
+ printf("\nFlash write error at address %lx\n",(unsigned long)dest);
+ if(barf & 0x0002) printf("Block locked, not erased.\n");
+ if(barf & 0x0010) printf("Programming error.\n");
+ if(barf & 0x0008) printf("Vpp Low error.\n");
+ return(2);
+ }
+
+
+ }
+
+ return (0);
+
+}
+
+#else
+
+static int write_short (flash_info_t *info, ulong dest, ushort data)
+{
+ vu_short *addr = (vu_short*)(info->start[0]);
+ ulong start,barf;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_short *)dest) & data) != data) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ if(info->flash_id < FLASH_AMD_COMP) {
+ /* AMD stuff */
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+ addr[0x0555] = 0x00A0;
+ } else {
+ /* intel stuff */
+ *addr = 0x00D0;
+ *addr = 0x0040;
+ }
+ *((vu_short *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+
+ if(info->flash_id < FLASH_AMD_COMP) {
+ /* AMD stuff */
+ while ((*((vu_short *)dest) & 0x0080) != (data & 0x0080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+
+ } else {
+ /* intel stuff */
+ while(!(addr[0] & 0x0080)){ /* wait for error or finish */
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) return (1);
+ }
+
+ if( addr[0] & 0x003A) { /* check for error */
+ barf = addr[0] & 0x003A;
+ printf("\nFlash write error at address %lx\n",(unsigned long)dest);
+ if(barf & 0x0002) printf("Block locked, not erased.\n");
+ if(barf & 0x0010) printf("Programming error.\n");
+ if(barf & 0x0008) printf("Vpp Low error.\n");
+ return(2);
+ }
+ *addr = 0x00B0;
+ *addr = 0x0070;
+ while(!(addr[0] & 0x0080)){ /* wait for error or finish */
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) return (1);
+ }
+
+ *addr = 0x00FF;
+
+ }
+
+ return (0);
+
+}
+
+
+#endif
+
+/*-----------------------------------------------------------------------
+ */
+
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+#ifdef CONFIG_FLASH_16BIT
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V | BR_PS_16; /* 16 Bit data port */
+#else
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+#endif
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+#ifdef CONFIG_FLASH_16BIT
+ memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V | BR_PS_16;
+#else
+ memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V;
+#endif
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+ } else {
+ memctl->memc_br1 = 0; /* invalidate bank */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00002000);
+ }
+ return;
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+#ifdef CONFIG_FLASH_16BIT
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+#else
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+#endif
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_SST200A: printf ("39xF200A (2M = 128K x 16)\n");
+ break;
+ case FLASH_SST400A: printf ("39xF400A (4M = 256K x 16)\n");
+ break;
+ case FLASH_SST800A: printf ("39xF800A (8M = 512K x 16)\n");
+ break;
+ case FLASH_STM800AB: printf ("M29W800AB (8M = 512K x 16)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+#ifdef CONFIG_FLASH_16BIT
+ vu_short *s_addr = (vu_short*)addr;
+ s_addr[0x5555] = 0x00AA;
+ s_addr[0x2AAA] = 0x0055;
+ s_addr[0x5555] = 0x0090;
+ value = s_addr[0];
+ value = value|(value<<16);
+#else
+ addr[0x5555] = 0x00AA00AA;
+ addr[0x2AAA] = 0x00550055;
+ addr[0x5555] = 0x00900090;
+ value = addr[0];
+#endif
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case SST_MANUFACT:
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+#ifdef CONFIG_FLASH_16BIT
+ value = s_addr[1];
+ value = value|(value<<16);
+#else
+ value = addr[1]; /* device ID */
+#endif
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+#ifdef CONFIG_FLASH_16BIT
+ info->sector_count = 19;
+ info->size = 0x00100000; /* => 1 MB */
+#else
+ info->sector_count = 19;
+ info->size = 0x00200000; /* => 2 MB */
+#endif
+ break;
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+#ifdef CONFIG_FLASH_16BIT
+ info->sector_count = 35;
+ info->size = 0x00200000; /* => 2 MB */
+#else
+ info->sector_count = 35;
+ info->size = 0x00400000; /* => 4 MB */
+#endif
+
+ break;
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ case SST_ID_xF200A:
+ info->flash_id += FLASH_SST200A;
+ info->sector_count = 64; /* 39xF200A ID ( 2M = 128K x 16 ) */
+ info->size = 0x00080000;
+ break;
+ case SST_ID_xF400A:
+ info->flash_id += FLASH_SST400A;
+ info->sector_count = 128; /* 39xF400A ID ( 4M = 256K x 16 ) */
+ info->size = 0x00100000;
+ break;
+ case SST_ID_xF800A:
+ info->flash_id += FLASH_SST800A;
+ info->sector_count = 256; /* 39xF800A ID ( 8M = 512K x 16 ) */
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ case STM_ID_x800AB:
+ info->flash_id += FLASH_STM800AB;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00002000);
+ }
+ } else { /* AMD and Fujitsu types */
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+#ifdef CONFIG_FLASH_16BIT
+
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+#else
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+#endif
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address:
+ * (A7 .. A0) = 0x02
+ * D0 = 1 if protected
+ */
+#ifdef CONFIG_FLASH_16BIT
+ s_addr = (volatile unsigned short *)(info->start[i]);
+ info->protect[i] = s_addr[2] & 1;
+#else
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+#endif
+ }
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+#ifdef CONFIG_FLASH_16BIT
+ s_addr = (volatile unsigned short *)(info->start[0]);
+ *s_addr = 0x00F0; /* reset bank */
+#else
+ addr = (volatile unsigned long *)info->start[0];
+ *addr = 0x00F000F0; /* reset bank */
+#endif
+
+ }
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect;
+ ulong start, now, last;
+#ifdef CONFIG_FLASH_16BIT
+ vu_short *s_addr = (vu_short*)addr;
+#endif
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+/*#ifndef CONFIG_FLASH_16BIT
+ ulong type;
+ type = (info->flash_id & FLASH_VENDMASK);
+ if ((type != FLASH_MAN_SST) && (type != FLASH_MAN_STM)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return;
+ }
+#endif*/
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+#ifdef CONFIG_FLASH_16BIT
+ vu_short *s_sect_addr = (vu_short*)(info->start[sect]);
+#else
+ vu_long *sect_addr = (vu_long*)(info->start[sect]);
+#endif
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#ifdef CONFIG_FLASH_16BIT
+
+ /*printf("\ns_sect_addr=%x",s_sect_addr);*/
+ s_addr[0x5555] = 0x00AA;
+ s_addr[0x2AAA] = 0x0055;
+ s_addr[0x5555] = 0x0080;
+ s_addr[0x5555] = 0x00AA;
+ s_addr[0x2AAA] = 0x0055;
+ s_sect_addr[0] = 0x0030;
+#else
+ addr[0x5555] = 0x00AA00AA;
+ addr[0x2AAA] = 0x00550055;
+ addr[0x5555] = 0x00800080;
+ addr[0x5555] = 0x00AA00AA;
+ addr[0x2AAA] = 0x00550055;
+ sect_addr[0] = 0x00300030;
+#endif
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+#ifdef CONFIG_FLASH_16BIT
+ while ((s_sect_addr[0] & 0x0080) != 0x0080) {
+#else
+ while ((sect_addr[0] & 0x00800080) != 0x00800080) {
+#endif
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+ }
+ }
+
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+#ifdef CONFIG_FLASH_16BIT
+ s_addr[0] = 0x00F0; /* reset bank */
+#else
+ addr[0] = 0x00F000F0; /* reset bank */
+#endif
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+
+#ifdef CONFIG_FLASH_16BIT
+ vu_short high_data;
+ vu_short low_data;
+ vu_short *s_addr = (vu_short*)addr;
+#endif
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+
+#ifdef CONFIG_FLASH_16BIT
+ /* Write the 16 higher-bits */
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ high_data = ((data>>16) & 0x0000ffff);
+
+ s_addr[0x5555] = 0x00AA;
+ s_addr[0x2AAA] = 0x0055;
+ s_addr[0x5555] = 0x00A0;
+
+ *((vu_short *)dest) = high_data;
+
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_short *)dest) & 0x0080) != (high_data & 0x0080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+
+
+ /* Write the 16 lower-bits */
+#endif
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+#ifdef CONFIG_FLASH_16BIT
+ dest += 0x2;
+ low_data = (data & 0x0000ffff);
+
+ s_addr[0x5555] = 0x00AA;
+ s_addr[0x2AAA] = 0x0055;
+ s_addr[0x5555] = 0x00A0;
+ *((vu_short *)dest) = low_data;
+
+#else
+ addr[0x5555] = 0x00AA00AA;
+ addr[0x2AAA] = 0x00550055;
+ addr[0x5555] = 0x00A000A0;
+ *((vu_long *)dest) = data;
+#endif
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+
+#ifdef CONFIG_FLASH_16BIT
+ while ((*((vu_short *)dest) & 0x0080) != (low_data & 0x0080)) {
+#else
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+#endif
+
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+#include <common.h>
+#include <mpc8xx.h>
+#include <malloc.h>
+#include <galileo/gt64260R.h>
+#include <galileo/core.h>
+
+#define MAX_I2C_RETRYS 10
+#define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */
+#undef DEBUG_I2C
+
+#ifdef DEBUG_I2C
+#define DP(x) x
+#else
+#define DP(x)
+#endif
+
+/* Assuming that there is only one master on the bus (us) */
+
+static void
+i2c_init(int speed, int slaveaddr)
+{
+ unsigned int n, m, freq, margin, power;
+ unsigned int actualFreq, actualN=0, actualM=0;
+ unsigned int control, status;
+ unsigned int minMargin = 0xffffffff;
+ unsigned int tclk = 125000000;
+
+ DP(puts("i2c_init\n"));
+
+ for(n = 0 ; n < 8 ; n++)
+ {
+ for(m = 0 ; m < 16 ; m++)
+ {
+ power = 2<<n; /* power = 2^(n+1) */
+ freq = tclk/(10*(m+1)*power);
+ if (speed > freq)
+ margin = speed - freq;
+ else
+ margin = freq - speed;
+ if(margin < minMargin)
+ {
+ minMargin = margin;
+ actualFreq = freq;
+ actualN = n;
+ actualM = m;
+ }
+ }
+ }
+
+ DP(puts("setup i2c bus\n"));
+
+ /* Setup bus */
+
+ GT_REG_WRITE(I2C_SOFT_RESET, 0);
+
+ DP(puts("udelay...\n"));
+
+ udelay(I2C_DELAY);
+
+ DP(puts("set baudrate\n"));
+
+ GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN);
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6));
+
+ udelay(I2C_DELAY * 10);
+
+ DP(puts("read control, baudrate\n"));
+
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ GT_REG_READ(I2C_CONTROL, &control);
+}
+
+static uchar
+i2c_start(void)
+{
+ unsigned int control, status;
+ int count = 0;
+
+ DP(puts("i2c_start\n"));
+
+ /* Set the start bit */
+
+ GT_REG_READ(I2C_CONTROL, &control);
+ control |= (0x1 << 5);
+ GT_REG_WRITE(I2C_CONTROL, control);
+
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+
+ count = 0;
+ while ((status & 0xff) != 0x08) {
+ udelay(I2C_DELAY);
+ if (count > 20) {
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+ return (status);
+ }
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ }
+
+ return (0);
+}
+
+static uchar
+i2c_select_device(uchar dev_addr, uchar read, int ten_bit)
+{
+ unsigned int status, data, bits = 7;
+ int count = 0;
+
+ DP(puts("i2c_select_device\n"));
+
+ /* Output slave address */
+
+ if (ten_bit) {
+ bits = 10;
+ }
+
+ data = (dev_addr << 1);
+ /* set the read bit */
+ data |= read;
+ GT_REG_WRITE(I2C_DATA, data);
+ /* assert the address */
+ RESET_REG_BITS(I2C_CONTROL, BIT3);
+
+ udelay(I2C_DELAY);
+
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count = 0;
+ while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) {
+ udelay(I2C_DELAY);
+ if (count > 20) {
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+ return(status);
+ }
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ }
+
+ if (bits == 10) {
+ printf("10 bit I2C addressing not yet implemented\n");
+ return (0xff);
+ }
+
+ return (0);
+}
+
+static uchar
+i2c_get_data(uchar* return_data, int len) {
+
+ unsigned int data, status;
+ int count = 0;
+
+ DP(puts("i2c_get_data\n"));
+
+ while (len) {
+
+ /* Get and return the data */
+
+ RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
+
+ udelay(I2C_DELAY * 5);
+
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ while ((status & 0xff) != 0x50) {
+ udelay(I2C_DELAY);
+ if(count > 2) {
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+ return 0;
+ }
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ }
+ GT_REG_READ(I2C_DATA, &data);
+ len--;
+ *return_data = (uchar)data;
+ return_data++;
+ }
+ RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3);
+ while ((status & 0xff) != 0x58) {
+ udelay(I2C_DELAY);
+ if(count > 200) {
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+ return (status);
+ }
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ }
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */
+
+ return (0);
+}
+
+static uchar
+i2c_write_data(unsigned int data, int len)
+{
+ unsigned int status;
+ int count = 0;
+
+ DP(puts("i2c_write_data\n"));
+
+ if (len > 4)
+ return -1;
+
+ while (len) {
+ /* Set and assert the data */
+
+ GT_REG_WRITE(I2C_DATA, (unsigned int)data);
+ RESET_REG_BITS(I2C_CONTROL, (0x1 << 3));
+
+ udelay(I2C_DELAY);
+
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ while ((status & 0xff) != 0x28) {
+ udelay(I2C_DELAY);
+ if(count > 20) {
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/
+ return (status);
+ }
+ GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status);
+ count++;
+ }
+ len--;
+ }
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4));
+ GT_REG_WRITE(I2C_CONTROL, (0x1 << 4));
+
+ udelay(I2C_DELAY * 10);
+
+ return (0);
+}
+
+static uchar
+i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit)
+{
+ uchar status;
+
+ DP(puts("i2c_set_dev_offset\n"));
+
+ status = i2c_select_device(dev_addr, 0, ten_bit);
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Failed to select device setting offset: 0x%02x\n",
+ status);
+#endif
+ return status;
+ }
+
+ status = i2c_write_data(offset, 1);
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Failed to write data: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ return (0);
+}
+
+uchar
+i2c_read(uchar dev_addr, unsigned int offset, int len, uchar* data,
+ int ten_bit)
+{
+ uchar status = 0;
+ unsigned int i2cFreq = 400000;
+
+ DP(puts("i2c_read\n"));
+
+ i2c_init(i2cFreq,0);
+
+ status = i2c_start();
+
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Transaction start failed: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ status = i2c_set_dev_offset(dev_addr, 0, 0);
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Failed to set offset: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ i2c_init(i2cFreq,0);
+
+ status = i2c_start();
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Transaction restart failed: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ status = i2c_select_device(dev_addr, 1, ten_bit);
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Address not acknowledged: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ status = i2c_get_data(data, len);
+ if (status) {
+#ifdef DEBUG_I2C
+ printf("Data not recieved: 0x%02x\n", status);
+#endif
+ return status;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <galileo/gt64260R.h>
+#include <galileo/memory.h>
+#include "intel_flash.h"
+
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET 0x01
+#define FLAG_PROTECT_CLEAR 0x02
+
+static void
+bank_reset(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, eaddrw;
+
+ addrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+ while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+ printf(" writing reset cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = BANK_CMD_RST;
+ addrw++;
+ }
+}
+
+static void
+bank_erase_init(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, saddrw, eaddrw;
+ int flag;
+
+#ifdef FLASH_DEBUG
+ printf("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG);
+ printf("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
+ printf("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
+ printf("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
+ printf("0x%08x BANK_CMD_RST\n", BANK_CMD_RST);
+ printf("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY);
+ printf("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR);
+#endif
+
+ saddrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+ printf("erasing sector %d, start addr = 0x%08lx "
+ "(bank next word addr = 0x%08lx)\n", sect,
+ (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+ /* Disable intrs which might cause a timeout here */
+ flag = disable_interrupts();
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+ printf(" writing erase cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = BANK_CMD_ERASE1;
+ *addrw = BANK_CMD_ERASE2;
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+}
+
+static int
+bank_erase_poll(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, saddrw, eaddrw;
+ int sectdone, haderr;
+
+ saddrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+ sectdone = 1;
+ haderr = 0;
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+ bank_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+ printf(" checking status at addr "
+ "0x%08x [0x%08x]\n",
+ (unsigned long)addrw, stat);
+#endif
+ if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
+ sectdone = 0;
+ else if ((stat & BANK_STAT_ERR) != 0) {
+ printf(" failed on sector %d "
+ "(stat = 0x%08x) at "
+ "address 0x%p\n",
+ sect, stat, addrw);
+ *addrw = BANK_CMD_CLR_STAT;
+ haderr = 1;
+ }
+ }
+
+ if (haderr)
+ return (-1);
+ else
+ return (sectdone);
+}
+
+int
+write_word_intel(bank_addr_t addr, bank_word_t value)
+{
+ bank_word_t stat;
+ ulong start;
+ int flag, retval;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = BANK_CMD_PROG;
+
+ *addr = value;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ retval = 0;
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ do {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ retval = 1;
+ goto done;
+ }
+ stat = *addr;
+ } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
+
+ if ((stat & BANK_STAT_ERR) != 0) {
+ printf("flash program failed (stat = 0x%08lx) "
+ "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+ *addr = BANK_CMD_CLR_STAT;
+ retval = 3;
+ }
+
+done:
+ /* reset to read mode */
+ *addr = BANK_CMD_RST;
+
+ return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int
+flash_erase_intel(flash_info_t *info, int s_first, int s_last)
+{
+ int prot, sect, haderr;
+ ulong start, now, last;
+
+#ifdef FLASH_DEBUG
+ printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+ " Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+ (info - flash_info) + 1);
+ flash_print_info(info);
+#endif
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf("- Warning: %d protected sector%s will not be erased!\n",
+ prot, (prot > 1 ? "s" : ""));
+ }
+
+ start = get_timer (0);
+ last = 0;
+ haderr = 0;
+
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ ulong estart;
+ int sectdone;
+
+ bank_erase_init(info, sect);
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ estart = get_timer(start);
+
+ do {
+ now = get_timer(start);
+
+ if (now - estart > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout (sect %d)\n", sect);
+ haderr = 1;
+ break;
+ }
+
+#ifndef FLASH_DEBUG
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+#endif
+
+ sectdone = bank_erase_poll(info, sect);
+
+ if (sectdone < 0) {
+ haderr = 1;
+ break;
+ }
+
+ } while (!sectdone);
+
+ if (haderr)
+ break;
+ }
+ }
+
+ if (haderr > 0)
+ printf (" failed\n");
+ else
+ printf (" done\n");
+
+ /* reset to read mode */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ bank_reset(info, sect);
+ }
+ }
+ return haderr;
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long total_size;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ total_size = 0;
+ size_b0 = 0xffffffff;
+
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+ {
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
+
+ if (flash_info[i].flash_id == FLASH_UNKNOWN)
+ {
+ printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", i, size_b1, size_b1>>20);
+ }
+
+ /* Is this really needed ? - LP */
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: Bank %d (0x%08lx = %ld MB) > Bank %d (0x%08lx = %ld MB)\n",
+ i, size_b1, size_b1>>20, i-1, size_b0, size_b0>>20);
+ goto out_error;
+ }
+ size_b0 = size_b1;
+ total_size += size_b1;
+ }
+
+ /* Compute the Address Mask */
+ for (i=0; (total_size >> i) != 0; ++i) {};
+ i--;
+
+ if (total_size != (1 << i)) {
+ printf ("## WARNING: Total FLASH size (0x%08lx = %ld MB) is not a power of 2\n",
+ total_size, total_size>>20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = ((((unsigned long)~1) << i) & OR_AM_MSK) | CFG_OR_TIMING_FLASH;
+ memctl->memc_br0 = CFG_BR0_PRELIM;
+
+ total_size = 0;
+
+ for (i=0; i < CFG_MAX_FLASH_BANKS && flash_info[i].size != 0; ++i)
+ {
+ /* Re-do sizing to get full correct info */
+ /* Why ? - LP */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + total_size), &flash_info[i]);
+
+ /* This is done by flash_get_size - LP */
+ /* flash_get_offsets (CFG_FLASH_BASE + total_size, &flash_info[i]); */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[i]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ &flash_info[i]);
+#endif
+
+ total_size += size_b1;
+ }
+
+ return (total_size);
+
+out_error:
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = -1;
+ flash_info[i].size = 0;
+ }
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00040000);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK)
+ {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK)
+ {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i)
+ {
+ if ((i % 5) == 0)
+ {
+ printf ("\n ");
+ }
+
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+#if 0
+ ulong base = (ulong)addr;
+#endif
+ uchar value;
+
+ /* Write auto select command: read Manufacturer ID */
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x90909090;
+#endif
+
+ value = addr[0];
+
+ switch (value + (value << 16))
+ {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value)
+ {
+ case AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+#if 0
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+#else
+ flash_get_offsets ((ulong)addr, info);
+#endif
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++)
+ {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN)
+ {
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ *addr = 0x00F000F0; /* reset bank */
+#else
+ *addr = 0xF0F0F0F0; /* reset bank */
+#endif
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x80808080;
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+#endif
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+#if 0
+ addr[0] = 0x00300030;
+#else
+ addr[0] = 0x30303030;
+#endif
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+#if 0
+ while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+ while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ addr[0] = 0x00F000F0; /* reset bank */
+#else
+ addr[0] = 0xF0F0F0F0; /* reset bank */
+#endif
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+#if 0
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+ while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+#include <config.h>
+#include <common.h>
+
+void
+signal_delay(unsigned int n)
+{
+ while (n--);
+}
+
+void
+signal_on(void)
+{
+ *((volatile uint *)BCSR4) &= ~(1<<(31-3)); /* led on */
+}
+
+void
+signal_off(void)
+{
+ *((volatile uint *)BCSR4) |= (1<<(31-3)); /* led off */
+}
+
+void
+slow_blink(unsigned int n)
+{
+ while (n--) {
+ signal_on();
+ signal_delay(0x00400000);
+ signal_off();
+ signal_delay(0x00400000);
+ }
+}
+
+void
+fast_blink(unsigned int n)
+{
+ while (n--) {
+ signal_on();
+ signal_delay(0x00100000);
+ signal_off();
+ signal_delay(0x00100000);
+ }
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+
+ /* Detect size */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ /* Setup offsets */
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* Monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ size_b1 = 0 ;
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ * Fix this to support variable sector sizes
+*/
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ {
+ puts ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK)
+ {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK)
+ {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size >> 20) {
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20,
+ info->sector_count);
+ } else {
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size >> 10,
+ info->sector_count);
+ }
+
+ puts (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i)
+ {
+ if ((i % 5) == 0)
+ {
+ puts ("\n ");
+ }
+
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+
+ putc ('\n');
+ return;
+}
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ volatile unsigned char *caddr;
+ char value;
+
+ caddr = (volatile unsigned char *)addr ;
+
+ /* Write auto select command: read Manufacturer ID */
+
+#if 0
+ printf("Base address is: %08x\n", caddr);
+#endif
+
+ caddr[0x0555] = 0xAA;
+ caddr[0x02AA] = 0x55;
+ caddr[0x0555] = 0x90;
+
+ value = caddr[0];
+
+#if 0
+ printf("Manufact ID: %02x\n", value);
+#endif
+ switch (value)
+ {
+ case 0x01:
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+ }
+
+ value = caddr[1]; /* device ID */
+#if 0
+ printf("Device ID: %02x\n", value);
+#endif
+ switch (value)
+ {
+ case AMD_ID_LV040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512Kb */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ flash_get_offsets ((ulong)addr, &flash_info[0]);
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++)
+ {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ caddr = (volatile unsigned char *)(info->start[i]);
+ info->protect[i] = caddr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN)
+ {
+ caddr = (volatile unsigned char *)info->start[0];
+ *caddr = 0xF0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile unsigned char *addr = (volatile unsigned char *)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0xAA;
+ addr[0x02AA] = 0x55;
+ addr[0x0555] = 0x80;
+ addr[0x0555] = 0xAA;
+ addr[0x02AA] = 0x55;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (volatile unsigned char *)(info->start[sect]);
+ addr[0] = 0x30;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (volatile unsigned char *)(info->start[l_sect]);
+
+ while ((addr[0] & 0xFF) != 0xFF)
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned char *)info->start[0];
+
+ addr[0] = 0xF0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ volatile unsigned char *addr = (volatile unsigned char*)(info->start[0]),
+ *cdest,*cdata;
+ ulong start;
+ int flag, count = 4 ;
+
+ cdest = (volatile unsigned char *)dest ;
+ cdata = (volatile unsigned char *)&data ;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+
+ while(count--)
+ {
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0xAA;
+ addr[0x02AA] = 0x55;
+ addr[0x0555] = 0xA0;
+
+ *cdest = *cdata;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*cdest ^ *cdata) & 0x80)
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+
+ cdata++ ;
+ cdest++ ;
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/* Module for handling DALLAS DS2438, smart battery monitor
+ Chip can store up to 40 bytes of user data in EEPROM,
+ perform temp, voltage and current measurements.
+ Chip also contains a unique serial number.
+
+ Always read/write LSb first
+
+ For documentaion, see data sheet for DS2438, 2438.pdf
+
+ By Thomas.Lange@corelatus.com 001025 */
+
+#include <common.h>
+#include <config.h>
+#include <mpc8xx.h>
+
+#include <../board/gth/ee_dev.h>
+
+/* We dont have kernel functions */
+#define printk printf
+#define KERN_DEBUG
+#define KERN_ERR
+#define EIO 1
+
+static int Debug = 0;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * lookup table ripped from DS app note 17, understanding and using
+ * cyclic redundancy checks...
+ */
+
+static u8 crc_lookup[256] = {
+ 0, 94, 188, 226, 97, 63, 221, 131,
+ 194, 156, 126, 32, 163, 253, 31, 65,
+ 157, 195, 33, 127, 252, 162, 64, 30,
+ 95, 1, 227, 189, 62, 96, 130, 220,
+ 35, 125, 159, 193, 66, 28, 254, 160,
+ 225, 191, 93, 3, 128, 222, 60, 98,
+ 190, 224, 2, 92, 223, 129, 99, 61,
+ 124, 34, 192, 158, 29, 67, 161, 255,
+ 70, 24, 250, 164, 39, 121, 155, 197,
+ 132, 218, 56, 102, 229, 187, 89, 7,
+ 219, 133, 103, 57, 186, 228, 6, 88,
+ 25, 71, 165, 251, 120, 38, 196, 154,
+ 101, 59, 217, 135, 4, 90, 184, 230,
+ 167, 249, 27, 69, 198, 152, 122, 36,
+ 248, 166, 68, 26, 153, 199, 37, 123,
+ 58, 100, 134, 216, 91, 5, 231, 185,
+ 140, 210, 48, 110, 237, 179, 81, 15,
+ 78, 16, 242, 172, 47, 113, 147, 205,
+ 17, 79, 173, 243, 112, 46, 204, 146,
+ 211, 141, 111, 49, 178, 236, 14, 80,
+ 175, 241, 19, 77, 206, 144, 114, 44,
+ 109, 51, 209, 143, 12, 82, 176, 238,
+ 50, 108, 142, 208, 83, 13, 239, 177,
+ 240, 174, 76, 18, 145, 207, 45, 115,
+ 202, 148, 118, 40, 171, 245, 23, 73,
+ 8, 86, 180, 234, 105, 55, 213, 139,
+ 87, 9, 235, 181, 54, 104, 138, 212,
+ 149, 203, 41, 119, 244, 170, 72, 22,
+ 233, 183, 85, 11, 136, 214, 52, 106,
+ 43, 117, 151, 201, 74, 20, 246, 168,
+ 116, 42, 200, 150, 21, 75, 169, 247,
+ 182, 232, 10, 84, 215, 137, 107, 53
+};
+
+static u8 make_new_crc( u8 Old_crc, u8 New_value ){
+ /* Compute a new checksum with new byte, using previous checksum as input
+ See DS app note 17, understanding and using cyclic redundancy checks...
+ Also see DS2438, page 11 */
+ return( crc_lookup[Old_crc ^ New_value ]);
+}
+
+int ee_crc_ok( u8 *Buffer, int Len, u8 Crc ){
+ /* Check if the checksum for this buffer is correct */
+ u8 Curr_crc=0;
+ int i;
+ u8 *Curr_byte = Buffer;
+
+ for(i=0;i<Len;i++){
+ Curr_crc = make_new_crc( Curr_crc, *Curr_byte);
+ Curr_byte++;
+ }
+ E_DEBUG("Calculated CRC = 0x%x, read = 0x%x\n", Curr_crc, Crc);
+
+ if(Curr_crc == Crc){
+ /* Good */
+ return(TRUE);
+ }
+ printk(KERN_ERR"EE checksum error, Calculated CRC = 0x%x, read = 0x%x\n",
+ Curr_crc, Crc);
+ return(FALSE);
+}
+
+static void
+set_idle(void){
+ /* Send idle and keep start time
+ Continous 1 is idle */
+ WRITE_PORT(1);
+}
+
+static int
+do_reset(void){
+ /* Release reset and verify that chip responds with presence pulse */
+ int Retries = 0;
+ while(Retries<5){
+ udelay(RESET_LOW_TIME);
+
+ /* Send reset */
+ WRITE_PORT(0);
+ udelay(RESET_LOW_TIME);
+
+ /* Release reset */
+ WRITE_PORT(1);
+
+ /* Wait for EEPROM to drive output */
+ udelay(PRESENCE_TIMEOUT);
+ if(!READ_PORT){
+ /* Ok, EEPROM is driving a 0 */
+ E_DEBUG("Presence detected\n");
+ if(Retries){
+ E_DEBUG("Retries %d\n",Retries);
+ }
+ /* Make sure chip releases pin */
+ udelay(PRESENCE_LOW_TIME);
+ return 0;
+ }
+ Retries++;
+ }
+
+ printk(KERN_ERR"EEPROM did not respond when releasing reset\n");
+
+ /* Make sure chip releases pin */
+ udelay(PRESENCE_LOW_TIME);
+
+ /* Set to idle again */
+ set_idle();
+
+ return(-EIO);
+}
+
+static u8
+read_byte(void){
+ /* Read a single byte from EEPROM
+ Read LSb first */
+ int i;
+ int Value;
+ u8 Result=0;
+#ifndef CFG_IMMR
+ u32 Flags;
+#endif
+
+ E_DEBUG("Reading byte\n");
+
+ for(i=0;i<8;i++){
+ /* Small delay between pulses */
+ udelay(1);
+
+#ifndef CFG_IMMR
+ /* Disable irq */
+ save_flags(Flags);
+ cli();
+#endif
+
+ /* Pull down pin short time to start read
+ See page 26 in data sheet */
+
+ WRITE_PORT(0);
+ udelay(READ_LOW);
+ WRITE_PORT(1);
+
+ /* Wait for chip to drive pin */
+ udelay(READ_TIMEOUT);
+
+ Value = READ_PORT;
+ if(Value)
+ Value=1;
+
+#ifndef CFG_IMMR
+ /* Enable irq */
+ restore_flags(Flags);
+#endif
+
+ /* Wait for chip to release pin */
+ udelay(TOTAL_READ_LOW-READ_TIMEOUT);
+
+ /* LSb first */
+ Result|=Value<<i;
+ }
+
+ E_DEBUG("Read byte 0x%x\n",Result);
+
+ return(Result);
+}
+
+static void
+write_byte(u8 Byte){
+ /* Write a single byte to EEPROM
+ Write LSb first */
+ int i;
+ int Value;
+#ifndef CFG_IMMR
+ u32 Flags;
+#endif
+
+ E_DEBUG("Writing byte 0x%x\n",Byte);
+
+ for(i=0;i<8;i++){
+ /* Small delay between pulses */
+ udelay(1);
+ Value = Byte&1;
+
+#ifndef CFG_IMMR
+ /* Disable irq */
+ save_flags(Flags);
+ cli();
+#endif
+
+ /* Pull down pin short time for a 1, long time for a 0
+ See page 26 in data sheet */
+
+ WRITE_PORT(0);
+ if(Value){
+ /* Write a 1 */
+ udelay(WRITE_1_LOW);
+ }
+ else{
+ /* Write a 0 */
+ udelay(WRITE_0_LOW);
+ }
+
+ WRITE_PORT(1);
+
+#ifndef CFG_IMMR
+ /* Enable irq */
+ restore_flags(Flags);
+#endif
+
+ if(Value)
+ /* Wait for chip to read the 1 */
+ udelay(TOTAL_WRITE_LOW-WRITE_1_LOW);
+ Byte>>=1;
+ }
+}
+
+int ee_do_command( u8 *Tx, int Tx_len, u8 *Rx, int Rx_len, int Send_skip ){
+ /* Execute this command string, including
+ giving reset and setting to idle after command
+ if Rx_len is set, we read out data from EEPROM */
+ int i;
+
+ E_DEBUG("Command, Tx_len %d, Rx_len %d\n", Tx_len, Rx_len );
+
+ if(do_reset()){
+ /* Failed! */
+ return(-EIO);
+ }
+
+ if(Send_skip)
+ /* Always send SKIP_ROM first to tell chip we are sending a command,
+ except when we read out rom data for chip */
+ write_byte(SKIP_ROM);
+
+ /* Always have Tx data */
+ for(i=0;i<Tx_len;i++){
+ write_byte(Tx[i]);
+ }
+
+ if(Rx_len){
+ for(i=0;i<Rx_len;i++){
+ Rx[i]=read_byte();
+ }
+ }
+
+ set_idle();
+
+ E_DEBUG("Command done\n");
+
+ return(0);
+}
+
+int ee_init_data(void){
+ int i;
+ u8 Tx[10];
+ int tmp;
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+ while(0){
+ tmp = 1-tmp;
+ if(tmp)
+ immap->im_ioport.iop_padat &= ~PA_FRONT_LED;
+ else
+ immap->im_ioport.iop_padat |= PA_FRONT_LED;
+ udelay(1);
+ }
+
+ /* Set port to open drain to be able to read data from
+ port without setting it to input */
+ PORT_B_PAR &= ~PB_EEPROM;
+ PORT_B_ODR |= PB_EEPROM;
+ SET_PORT_B_OUTPUT(PB_EEPROM);
+
+ /* Set idle mode */
+ set_idle();
+
+ /* Copy all User EEPROM data to scratchpad */
+ for(i=0;i<USER_PAGES;i++){
+ Tx[0]=RECALL_MEMORY;
+ Tx[1]=EE_USER_PAGE_0+i;
+ if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
+ }
+
+ /* Make sure chip doesnt store measurements in NVRAM */
+ Tx[0]=WRITE_SCRATCHPAD;
+ Tx[1]=0; /* Page */
+ Tx[2]=9;
+ if(ee_do_command(Tx,3,NULL,0,TRUE)) return(-EIO);
+
+ Tx[0]=COPY_SCRATCHPAD;
+ if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO);
+
+ /* FIXME check status bit instead
+ Could take 10 ms to store in EEPROM */
+ for(i=0;i<10;i++){
+ udelay(1000);
+ }
+
+ return(0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET 0x01
+#define FLAG_PROTECT_CLEAR 0x02
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /*printf("faking");*/
+
+ return(0x1fffff);
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN)
+ {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+#if 0
+ if (FLASH_BASE1_PRELIM != 0x0) {
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,size_b0, size_b0<<20);
+
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+ } else {
+#endif
+ size_b1 = 0;
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR0_PRELIM;
+ memctl->memc_br0 = CFG_BR0_PRELIM;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1)
+ {
+ /* memctl->memc_or1 = CFG_OR1_PRELIM;
+ memctl->memc_br1 = CFG_BR1_PRELIM; */
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+ }
+ else
+ {
+/* memctl->memc_or1 = CFG_OR1_PRELIM;
+ FIXME memctl->memc_br1 = CFG_BR1_PRELIM; */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE)
+ {
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < info->sector_count; i++)
+ {
+ info->start[i] = base + (i * 0x00040000);
+ }
+ }
+ else
+ {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ for (; i >= 0; i--)
+ {
+ info->start[i] = base + i * 0x00040000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+
+#if 0
+ case FLASH_AM040B:
+ printf ("AM29F040B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM040T:
+ printf ("AM29F040T (4 Mbit, top boot sect)\n");
+ break;
+#endif
+ case FLASH_AM400B:
+ printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T:
+ printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B:
+ printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T:
+ printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B:
+ printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T:
+ printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B:
+ printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T:
+ printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20,
+ info->sector_count);
+
+ printf (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i)
+ {
+ if ((i % 5) == 0)
+ {
+ printf ("\n ");
+ }
+
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+#if 0
+ ulong base = (ulong)addr;
+#endif
+ uchar value;
+
+ /* Write auto select command: read Manufacturer ID */
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x90909090;
+#endif
+
+ value = addr[0];
+
+ switch (value)
+ {
+ case AMD_MANUFACT:case 0x01:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value)
+ {
+#if 0
+ case AMD_ID_F040B:
+ info->flash_id += FLASH_AM040B;
+ info->sector_count = 8;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+#endif
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+#if 0
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+#else
+ flash_get_offsets ((ulong)addr, &flash_info[0]);
+#endif
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++)
+ {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN)
+ {
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ *addr = 0x00F000F0; /* reset bank */
+#else
+ *addr = 0xF0F0F0F0; /* reset bank */
+#endif
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x80808080;
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+#endif
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+#if 0
+ addr[0] = 0x00300030;
+#else
+ addr[0] = 0x30303030;
+#endif
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+#if 0
+ while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+ while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ addr[0] = 0x00F000F0; /* reset bank */
+#else
+ addr[0] = 0xF0F0F0F0; /* reset bank */
+#endif
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+#if 0
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+ while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_byte (flash_info_t *info, ulong dest, uchar data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size, size<<20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) |
+ (memctl->memc_br0 & ~(BR_BA_MSK));
+
+ /* Re-do sizing to get full correct info */
+ size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ flash_info[0].size = size;
+
+ return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ uchar value;
+ vu_char *caddr = (vu_char *)addr;
+ ulong base = (ulong)addr;
+
+
+ /* Write auto select command: read Manufacturer ID */
+ caddr[0x0AAA] = 0xAA;
+ caddr[0x0555] = 0x55;
+ caddr[0x0AAA] = 0x90;
+
+ value = caddr[0];
+ switch (value) {
+ case (AMD_MANUFACT & 0xFF):
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (FUJ_MANUFACT & 0xFF):
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = caddr[2]; /* device ID */
+
+ switch (value) {
+ case (AMD_ID_LV400T & 0xFF):
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case (AMD_ID_LV400B & 0xFF):
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case (AMD_ID_LV800T & 0xFF):
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV800B & 0xFF):
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV160T & 0xFF):
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (AMD_ID_LV160B & 0xFF):
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+#if 0 /* enable when device IDs are available */
+ case (AMD_ID_LV320T & 0xFF):
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (AMD_ID_LV320B & 0xFF):
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection: D0 = 1 if protected */
+ caddr = (volatile unsigned char *)(info->start[i]);
+ info->protect[i] = caddr[4] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ caddr = (vu_char *)info->start[0];
+
+ *caddr = 0xF0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_char *addr = (vu_char*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0AAA] = 0xAA;
+ addr[0x0555] = 0x55;
+ addr[0x0AAA] = 0x80;
+ addr[0x0AAA] = 0xAA;
+ addr[0x0555] = 0x55;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_char*)(info->start[sect]);
+ addr[0] = 0x30;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_char*)(info->start[l_sect]);
+ while ((addr[0] & 0x80) != 0x80) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (vu_char *)info->start[0];
+ addr[0] = 0xF0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ int rc;
+
+ while (cnt > 0) {
+ if ((rc = write_byte(info, addr++, *src++)) != 0) {
+ return (rc);
+ }
+ --cnt;
+ }
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_byte (flash_info_t *info, ulong dest, uchar data)
+{
+ vu_char *addr = (vu_char*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_char *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0AAA] = 0xAA;
+ addr[0x0555] = 0x55;
+ addr[0x0AAA] = 0xA0;
+
+ *((vu_char *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Murray Jensen, CSIRO Manufacturing Science and Technology,
+ * <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+
+/* imports from fetch.c */
+extern int fetch_and_parse(bd_t *, char *, ulong, int (*)(uchar *, uchar *));
+
+int
+eeprom_load(unsigned offset, hymod_eeprom_t *ep)
+{
+ uchar data[HYMOD_EEPROM_SIZE], *dp, *edp;
+ hymod_eehdr_t *hp;
+ ulong len, crc;
+
+ memset(ep, 0, sizeof *ep);
+ memset(data, 0, HYMOD_EEPROM_SIZE);
+ crc = 0;
+
+ hp = (hymod_eehdr_t *)data;
+ eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)hp, sizeof (*hp));
+ offset += sizeof (*hp);
+
+ if (hp->id != HYMOD_EEPROM_ID || hp->ver > HYMOD_EEPROM_VER ||
+ (len = hp->len) > HYMOD_EEPROM_MAXLEN)
+ return (0);
+
+ dp = (uchar *)(hp + 1); edp = dp + len;
+ eeprom_read(CFG_DEF_EEPROM_ADDR, offset, dp, len);
+ offset += len;
+
+ eeprom_read(CFG_DEF_EEPROM_ADDR, offset, (uchar *)&crc, sizeof (ulong));
+
+ if (crc32(0, data, edp - data) != crc)
+ return (0);
+
+ ep->ver = hp->ver;
+
+ for (;;) {
+ hymod_eerec_t *rp = (hymod_eerec_t *)dp;
+ ulong rtyp;
+ uchar rlen, *rdat;
+ uint rsiz;
+
+ if (rp->small.topbit == 0) {
+ rtyp = rp->small.type;
+ rlen = rp->small.len;
+ rdat = rp->small.data;
+ rsiz = offsetof(hymod_eerec_t, small.data) + rlen;
+ }
+ else if (rp->medium.nxtbit == 0) {
+ rtyp = rp->medium.type;
+ rlen = rp->medium.len;
+ rdat = rp->medium.data;
+ rsiz = offsetof(hymod_eerec_t, medium.data) + rlen;
+ }
+ else {
+ rtyp = rp->large.type;
+ rlen = rp->large.len;
+ rdat = rp->large.data;
+ rsiz = offsetof(hymod_eerec_t, large.data) + rlen;
+ }
+
+ if (rtyp == 0)
+ break;
+
+ dp += rsiz;
+ if (dp > edp) /* error? */
+ break;
+
+ switch (rtyp) {
+
+ case HYMOD_EEREC_SERNO: /* serial number */
+ if (rlen == sizeof (ulong))
+ memcpy(&ep->serno, rdat, sizeof (ulong));
+ break;
+
+ case HYMOD_EEREC_DATE: /* date */
+ if (rlen == sizeof (hymod_date_t))
+ memcpy(&ep->date, rdat, sizeof (hymod_date_t));
+ break;
+
+ case HYMOD_EEREC_BATCH: /* batch */
+ if (rlen <= HYMOD_MAX_BATCH)
+ memcpy(ep->batch, rdat, ep->batchlen = rlen);
+ break;
+
+ case HYMOD_EEREC_TYPE: /* board type */
+ if (rlen == 1)
+ ep->bdtype = *rdat;
+ break;
+
+ case HYMOD_EEREC_REV: /* board revision */
+ if (rlen == 1)
+ ep->bdrev = *rdat;
+ break;
+
+ case HYMOD_EEREC_SDRAM: /* sdram size(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_SDRAM) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->sdramsz[i] = rdat[i];
+ ep->nsdram = rlen;
+ }
+ break;
+
+ case HYMOD_EEREC_FLASH: /* flash size(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_FLASH) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->flashsz[i] = rdat[i];
+ ep->nflash = rlen;
+ }
+ break;
+
+ case HYMOD_EEREC_ZBT: /* zbt ram size(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_ZBT) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->zbtsz[i] = rdat[i];
+ ep->nzbt = rlen;
+ }
+ break;
+
+ case HYMOD_EEREC_XLXTYP: /* xilinx fpga type(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->xlx[i].type = rdat[i];
+ ep->nxlx = rlen;
+ }
+ break;
+
+ case HYMOD_EEREC_XLXSPD: /* xilinx fpga speed(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->xlx[i].speed = rdat[i];
+ }
+ break;
+
+ case HYMOD_EEREC_XLXTMP: /* xilinx fpga temperature(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->xlx[i].temp = rdat[i];
+ }
+ break;
+
+ case HYMOD_EEREC_XLXGRD: /* xilinx fpga grade(s) */
+ if (rlen > 0 && rlen <= HYMOD_MAX_XLX) {
+ int i;
+
+ for (i = 0; i < rlen; i++)
+ ep->xlx[i].grade = rdat[i];
+ }
+ break;
+
+ case HYMOD_EEREC_CPUTYP: /* CPU type */
+ if (rlen == 1)
+ ep->mpc.type = *rdat;
+ break;
+
+ case HYMOD_EEREC_CPUSPD: /* CPU speed */
+ if (rlen == 1)
+ ep->mpc.cpuspd = *rdat;
+ break;
+
+ case HYMOD_EEREC_CPMSPD: /* CPM speed */
+ if (rlen == 1)
+ ep->mpc.cpmspd = *rdat;
+ break;
+
+ case HYMOD_EEREC_BUSSPD: /* bus speed */
+ if (rlen == 1)
+ ep->mpc.busspd = *rdat;
+ break;
+
+ case HYMOD_EEREC_HSTYPE: /* high-speed serial chip type */
+ if (rlen == 1)
+ ep->hss.type = *rdat;
+ break;
+
+ case HYMOD_EEREC_HSCHIN: /* high-speed serial input channels */
+ if (rlen == 1)
+ ep->hss.nchin = *rdat;
+ break;
+
+ case HYMOD_EEREC_HSCHOUT: /* high-speed serial output channels */
+ if (rlen == 1)
+ ep->hss.nchout = *rdat;
+ break;
+
+ default: /* ignore */
+ break;
+ }
+ }
+
+ return (1);
+}
+
+/* maps an ascii "name=value" into a binary eeprom data record */
+typedef
+ struct _eerec_map {
+ char *name;
+ uint type;
+ uchar *(*handler)(struct _eerec_map *, uchar *, uchar *, uchar *);
+ uint length;
+ uint maxlen;
+ }
+eerec_map_t;
+
+static uchar *
+uint_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+ uchar *eval;
+ union {
+ uchar cval[4];
+ ushort sval[2];
+ ulong lval;
+ } rdata;
+
+ rdata.lval = simple_strtol(value, (char **)&eval, 10);
+
+ if (eval == value || *eval != '\0') {
+ printf("%s record (%s) is not a valid uint\n", rp->name, value);
+ return (NULL);
+ }
+
+ if (dp + 2 + rp->length > edp) {
+ printf("can't fit %s record into eeprom\n", rp->name);
+ return (NULL);
+ }
+
+ *dp++ = rp->type;
+ *dp++ = rp->length;
+
+ switch (rp->length) {
+
+ case 1:
+ if (rdata.lval >= 256) {
+ printf("%s record value (%lu) out of range (0-255)\n",
+ rp->name, rdata.lval);
+ return (NULL);
+ }
+ *dp++ = rdata.cval[3];
+ break;
+
+ case 2:
+ if (rdata.lval >= 65536) {
+ printf("%s record value (%lu) out of range (0-65535)\n",
+ rp->name, rdata.lval);
+ return (NULL);
+ }
+ memcpy(dp, &rdata.sval[1], 2);
+ dp += 2;
+ break;
+
+ case 4:
+ memcpy(dp, &rdata.lval, 4);
+ dp += 4;
+ break;
+
+ default:
+ printf("huh? rp->length not 1, 2 or 4! (%d)\n", rp->length);
+ return (NULL);
+ }
+
+ return (dp);
+}
+
+static uchar *
+date_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+ hymod_date_t date;
+ uchar *p = value, *ep;
+
+ date.year = simple_strtol(p, (char **)&ep, 10);
+ if (ep == p || *ep++ != '-') {
+bad_date:
+ printf("%s record (%s) is not a valid date\n", rp->name, value);
+ return (NULL);
+ }
+
+ date.month = simple_strtol(p = ep, (char **)&ep, 10);
+ if (ep == p || *ep++ != '-' || date.month == 0 || date.month > 12)
+ goto bad_date;
+
+ date.day = simple_strtol(p = ep, (char **)&ep, 10);
+ if (ep == p || *ep != '\0' || date.day == 0 || date.day > 31)
+ goto bad_date;
+
+ if (dp + 2 + sizeof (hymod_date_t) > edp) {
+ printf("can't fit %s record into eeprom\n", rp->name);
+ return (NULL);
+ }
+
+ *dp++ = rp->type;
+ *dp++ = sizeof (hymod_date_t);
+ memcpy(dp, &date, sizeof (hymod_date_t));
+ dp += sizeof (hymod_date_t);
+
+ return (dp);
+}
+
+static uchar *
+string_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+ uint len;
+
+ if ((len = strlen(value)) > rp->maxlen) {
+ printf("%s record (%s) string is too long (%d>%d)\n",
+ rp->name, value, len, rp->maxlen);
+ return (NULL);
+ }
+
+ if (dp + 2 + len > edp) {
+ printf("can't fit %s record into eeprom\n", rp->name);
+ return (NULL);
+ }
+
+ *dp++ = rp->type;
+ *dp++ = len;
+ memcpy(dp, value, len);
+ dp += len;
+
+ return (dp);
+}
+
+static uchar *
+bytes_handler(eerec_map_t *rp, uchar *value, uchar *dp, uchar *edp)
+{
+ uchar bytes[HYMOD_MAX_BYTES], nbytes = 0;
+ uchar *p = value, *ep;
+
+ for (;;) {
+
+ if (nbytes >= HYMOD_MAX_BYTES) {
+ printf("%s record (%s) byte array too long\n", rp->name, value);
+ return (NULL);
+ }
+
+ bytes[nbytes++] = simple_strtol(p, (char **)&ep, 10);
+
+ if (ep == p || (*ep != '\0' && *ep != ',')) {
+ printf("%s record (%s) byte array has invalid uint\n",
+ rp->name, value);
+ return (NULL);
+ }
+
+ if (*ep++ == '\0')
+ break;
+
+ p = ep;
+ }
+
+ if (dp + 2 + nbytes > edp) {
+ printf("can't fit %s record into eeprom\n", rp->name);
+ return (NULL);
+ }
+
+ *dp++ = rp->type;
+ *dp++ = nbytes;
+ memcpy(dp, bytes, nbytes);
+ dp += nbytes;
+
+ return (dp);
+}
+
+static eerec_map_t eerec_map[] = {
+ /* name type handler len max */
+ { "serno", HYMOD_EEREC_SERNO, uint_handler, 4, 0 },
+ { "date", HYMOD_EEREC_DATE, date_handler, 4, 0 },
+ { "batch", HYMOD_EEREC_BATCH, string_handler, 0, HYMOD_MAX_BATCH },
+ { "type", HYMOD_EEREC_TYPE, uint_handler, 1, 0 },
+ { "rev", HYMOD_EEREC_REV, uint_handler, 1, 0 },
+ { "sdram", HYMOD_EEREC_SDRAM, bytes_handler, 0, HYMOD_MAX_SDRAM },
+ { "flash", HYMOD_EEREC_FLASH, bytes_handler, 0, HYMOD_MAX_FLASH },
+ { "zbt", HYMOD_EEREC_ZBT, bytes_handler, 0, HYMOD_MAX_ZBT },
+ { "xlxtyp", HYMOD_EEREC_XLXTYP, bytes_handler, 0, HYMOD_MAX_XLX },
+ { "xlxspd", HYMOD_EEREC_XLXSPD, bytes_handler, 0, HYMOD_MAX_XLX },
+ { "xlxtmp", HYMOD_EEREC_XLXTMP, bytes_handler, 0, HYMOD_MAX_XLX },
+ { "xlxgrd", HYMOD_EEREC_XLXGRD, bytes_handler, 0, HYMOD_MAX_XLX },
+ { "cputyp", HYMOD_EEREC_CPUTYP, uint_handler, 1, 0 },
+ { "cpuspd", HYMOD_EEREC_CPUSPD, uint_handler, 1, 0 },
+ { "cpmspd", HYMOD_EEREC_CPMSPD, uint_handler, 1, 0 },
+ { "busspd", HYMOD_EEREC_BUSSPD, uint_handler, 1, 0 },
+ { "hstype", HYMOD_EEREC_HSTYPE, uint_handler, 1, 0 },
+ { "hschin", HYMOD_EEREC_HSCHIN, uint_handler, 1, 0 },
+ { "hschout", HYMOD_EEREC_HSCHOUT, uint_handler, 1, 0 },
+};
+
+static int neerecs = sizeof eerec_map / sizeof eerec_map[0];
+
+static uchar data[HYMOD_EEPROM_SIZE], *sdp, *dp, *edp;
+
+static int
+eeprom_fetch_callback(uchar *name, uchar *value)
+{
+ eerec_map_t *rp;
+
+ for (rp = eerec_map; rp < &eerec_map[neerecs]; rp++)
+ if (strcmp(name, rp->name) == 0)
+ break;
+
+ if (rp >= &eerec_map[neerecs])
+ return (0);
+
+ if ((dp = (*rp->handler)(rp, value, dp, edp)) == NULL)
+ return (0);
+
+ return (1);
+}
+
+int
+eeprom_fetch(unsigned offset, bd_t *bd, char *filename, ulong addr)
+{
+ hymod_eehdr_t *hp = (hymod_eehdr_t *)&data[0];
+ ulong crc;
+
+ hp->id = HYMOD_EEPROM_ID;
+ hp->ver = HYMOD_EEPROM_VER;
+
+ dp = sdp = (uchar *)(hp + 1);
+ edp = dp + HYMOD_EEPROM_MAXLEN;
+
+ if (fetch_and_parse(bd, filename, addr, eeprom_fetch_callback) == 0)
+ return (0);
+
+ hp->len = dp - sdp;
+
+ crc = crc32(0, data, dp - data);
+ memcpy(dp, &crc, sizeof (ulong));
+ dp += sizeof (ulong);
+
+ eeprom_write(CFG_DEF_EEPROM_ADDR, offset, data, dp - data);
+
+ return (1);
+}
+
+static char *type_vals[] = {
+ "NONE", "IO", "CLP", "DSP", "INPUT", "ALT-INPUT", "DISPLAY"
+};
+
+static char *xlxtyp_vals[] = {
+ "NONE", "XCV300E", "XCV400E", "XCV600E"
+};
+
+static char *xlxspd_vals[] = {
+ "NONE", "6", "7", "8"
+};
+
+static char *xlxtmp_vals[] = {
+ "NONE", "COM", "IND"
+};
+
+static char *xlxgrd_vals[] = {
+ "NONE", "NORMAL", "ENGSAMP"
+};
+
+static char *cputyp_vals[] = {
+ "NONE", "MPC8260"
+};
+
+static char *clk_vals[] = {
+ "NONE", "33", "66", "100", "133", "166", "200"
+};
+
+static char *hstype_vals[] = {
+ "NONE", "AMCC-S2064A"
+};
+
+static void
+print_mem(char *l, char *s, uchar n, uchar a[])
+{
+ if (n > 0) {
+ if (n == 1)
+ printf("%s%dMB %s", s, 1 << (a[0] - 20), l);
+ else {
+ ulong t = 0;
+ int i;
+
+ for (i = 0; i < n; i++)
+ t += 1 << (a[i] - 20);
+
+ printf("%s%luMB %s (%d banks:", s, t, l, n);
+
+ for (i = 0; i < n; i++)
+ printf("%dMB%s", 1 << (a[i] - 20), (i == n - 1) ? ")" : ",");
+ }
+ }
+ else
+ printf("%sNO %s", s, l);
+}
+
+void
+eeprom_print(hymod_eeprom_t *ep)
+{
+ int i;
+
+ printf(" Hymod %s board, rev %03d\n",
+ type_vals[ep->bdtype], ep->bdrev);
+
+ printf(" serial #: %010lu, date %04d-%02d-%02d",
+ ep->serno, ep->date.year, ep->date.month, ep->date.day);
+ if (ep->batchlen > 0)
+ printf(", batch \"%.*s\"", ep->batchlen, ep->batch);
+ puts("\n");
+
+ switch (ep->bdtype) {
+
+ case HYMOD_BDTYPE_IO:
+ case HYMOD_BDTYPE_CLP:
+ case HYMOD_BDTYPE_DSP:
+ printf(" Motorola %s CPU, speeds: %s/%s/%s",
+ cputyp_vals[ep->mpc.type], clk_vals[ep->mpc.cpuspd],
+ clk_vals[ep->mpc.cpmspd], clk_vals[ep->mpc.busspd]);
+
+ print_mem("SDRAM", ", ", ep->nsdram, ep->sdramsz);
+
+ print_mem("FLASH", ", ", ep->nflash, ep->flashsz);
+
+ puts("\n");
+
+ print_mem("ZBT", " ", ep->nzbt, ep->zbtsz);
+
+ if (ep->nxlx > 0) {
+ hymod_xlx_t *xp;
+
+ if (ep->nxlx == 1) {
+ xp = &ep->xlx[0];
+ printf(", Xilinx %s FPGA (%s/%s/%s)",
+ xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
+ xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade]);
+ }
+ else {
+ printf(", %d Xilinx FPGAs (", ep->nxlx);
+ for (i = 0; i < ep->nxlx; i++) {
+ xp = &ep->xlx[i];
+ printf("%s[%s/%s/%s]%s",
+ xlxtyp_vals[xp->type], xlxspd_vals[xp->speed],
+ xlxtmp_vals[xp->temp], xlxgrd_vals[xp->grade],
+ (i == ep->nxlx - 1) ? ")" : ", ");
+ }
+ }
+ }
+ else
+ puts(", NO FPGAs");
+
+ puts("\n");
+
+ if (ep->hss.type > 0)
+ printf(" High Speed Serial: %s, %d input%s, %d output%s\n",
+ hstype_vals[ep->hss.type],
+ ep->hss.nchin, (ep->hss.nchin == 1 ? "" : "s"),
+ ep->hss.nchout, (ep->hss.nchout == 1 ? "" : "s"));
+ break;
+
+ case HYMOD_BDTYPE_INPUT:
+ case HYMOD_BDTYPE_ALTINPUT:
+ case HYMOD_BDTYPE_DISPLAY:
+ break;
+
+ default:
+ /* crap! */
+ printf(" UNKNOWN BOARD TYPE: %d\n", ep->bdtype);
+ break;
+ }
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <board/hymod/flash.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET 0x01
+#define FLAG_PROTECT_CLEAR 0x02
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+#if 0
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+#endif
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * probe for the existence of flash at bank word address "addr"
+ * 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
+ */
+static int
+bank_probe_word(bank_addr_t addr)
+{
+ int retval;
+
+ /* reset the flash */
+ *addr = BANK_CMD_RST;
+
+ /* check the manufacturer id */
+ *addr = BANK_CMD_RD_ID;
+ if (*BANK_ADDR_REG_MAN(addr) != BANK_RD_ID_MAN) {
+ retval = -1;
+ goto out;
+ }
+
+ /* check the device id */
+ *addr = BANK_CMD_RD_ID;
+ if (*BANK_ADDR_REG_DEV(addr) != BANK_RD_ID_DEV) {
+ retval = -2;
+ goto out;
+ }
+
+ retval = CFG_FLASH_TYPE;
+
+out:
+ /* reset the flash again */
+ *addr = BANK_CMD_RST;
+
+ return retval;
+}
+
+/*
+ * probe for flash banks at address "base" and store info for any found
+ * into flash_info entry "fip". Must find at least one bank.
+ */
+static void
+bank_probe(flash_info_t *fip, bank_addr_t base)
+{
+ bank_addr_t addr, eaddr;
+ int nbanks;
+
+ fip->flash_id = FLASH_UNKNOWN;
+ fip->size = 0L;
+ fip->sector_count = 0;
+
+ addr = base;
+ eaddr = BANK_ADDR_BASE(addr, MAX_BANKS);
+ nbanks = 0;
+
+ while (addr < eaddr) {
+ bank_addr_t addrw, eaddrw, addrb;
+ int i, osc, nsc, curtype = -1;
+
+ addrw = addr;
+ eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+ while (addrw < eaddrw) {
+ int thistype;
+
+#ifdef FLASH_DEBUG
+ printf(" probing for flash at addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ if ((thistype = bank_probe_word(addrw++)) < 0)
+ goto out;
+
+ if (curtype < 0)
+ curtype = thistype;
+ else {
+ if (thistype != curtype) {
+ printf("Differing flash type found!\n");
+ goto out;
+ }
+ }
+ }
+
+ if (curtype < 0)
+ goto out;
+
+ /* bank exists - append info for this bank to *fip */
+ fip->flash_id = FLASH_MAN_INTEL|curtype;
+ fip->size += BANK_SIZE;
+ osc = fip->sector_count;
+ fip->sector_count += BANK_NBLOCKS;
+ if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
+ panic("Too many sectors in flash at address 0x%08lx\n",
+ (unsigned long)base);
+
+ addrb = addr;
+ for (i = osc; i < nsc; i++) {
+ fip->start[i] = (ulong)addrb;
+ fip->protect[i] = 0;
+ addrb = BANK_ADDR_NEXT_BLK(addrb);
+ }
+
+ addr = BANK_ADDR_NEXT_BANK(addr);
+ nbanks++;
+ }
+
+out:
+ if (nbanks == 0)
+ panic("ERROR: no flash found at address 0x%08lx\n",
+ (unsigned long)base);
+}
+
+static void
+bank_reset(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, eaddrw;
+
+ addrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(addrw);
+
+ while (addrw < eaddrw) {
+#ifdef FLASH_DEBUG
+ printf(" writing reset cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = BANK_CMD_RST;
+ addrw++;
+ }
+}
+
+static void
+bank_erase_init(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, saddrw, eaddrw;
+ int flag;
+
+#ifdef FLASH_DEBUG
+ printf("0x%08lx BANK_CMD_PROG\n", BANK_CMD_PROG);
+ printf("0x%08lx BANK_CMD_ERASE1\n", BANK_CMD_ERASE1);
+ printf("0x%08lx BANK_CMD_ERASE2\n", BANK_CMD_ERASE2);
+ printf("0x%08lx BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT);
+ printf("0x%08lx BANK_CMD_RST\n", BANK_CMD_RST);
+ printf("0x%08lx BANK_STAT_RDY\n", BANK_STAT_RDY);
+ printf("0x%08lx BANK_STAT_ERR\n", BANK_STAT_ERR);
+#endif
+
+ saddrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+#ifdef FLASH_DEBUG
+ printf("erasing sector %d, start addr = 0x%08lx "
+ "(bank next word addr = 0x%08lx)\n", sect,
+ (unsigned long)saddrw, (unsigned long)eaddrw);
+#endif
+
+ /* Disable intrs which might cause a timeout here */
+ flag = disable_interrupts();
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+#ifdef FLASH_DEBUG
+ printf(" writing erase cmd to addr 0x%08lx\n",
+ (unsigned long)addrw);
+#endif
+ *addrw = BANK_CMD_ERASE1;
+ *addrw = BANK_CMD_ERASE2;
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+}
+
+static int
+bank_erase_poll(flash_info_t *info, int sect)
+{
+ bank_addr_t addrw, saddrw, eaddrw;
+ int sectdone, haderr;
+
+ saddrw = (bank_addr_t)info->start[sect];
+ eaddrw = BANK_ADDR_NEXT_WORD(saddrw);
+
+ sectdone = 1;
+ haderr = 0;
+
+ for (addrw = saddrw; addrw < eaddrw; addrw++) {
+ bank_word_t stat = *addrw;
+
+#ifdef FLASH_DEBUG
+ printf(" checking status at addr "
+ "0x%08lx [0x%08lx]\n",
+ (unsigned long)addrw, stat);
+#endif
+ if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY)
+ sectdone = 0;
+ else if ((stat & BANK_STAT_ERR) != 0) {
+ printf(" failed on sector %d "
+ "(stat = 0x%08lx) at "
+ "address 0x%08lx\n",
+ sect, stat,
+ (unsigned long)addrw);
+ *addrw = BANK_CMD_CLR_STAT;
+ haderr = 1;
+ }
+ }
+
+ if (haderr)
+ return (-1);
+ else
+ return (sectdone);
+}
+
+static int
+bank_write_word(bank_addr_t addr, bank_word_t value)
+{
+ bank_word_t stat;
+ ulong start;
+ int flag, retval;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = BANK_CMD_PROG;
+
+ *addr = value;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ retval = 0;
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ do {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ retval = 1;
+ goto done;
+ }
+ stat = *addr;
+ } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY);
+
+ if ((stat & BANK_STAT_ERR) != 0) {
+ printf("flash program failed (stat = 0x%08lx) "
+ "at address 0x%08lx\n", (ulong)stat, (ulong)addr);
+ *addr = BANK_CMD_CLR_STAT;
+ retval = 3;
+ }
+
+done:
+ /* reset to read mode */
+ *addr = BANK_CMD_RST;
+
+ return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long
+flash_init(void)
+{
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ bank_probe(&flash_info[0], (bank_addr_t)CFG_FLASH_BASE);
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE == CFG_FLASH_BASE
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#if defined(CFG_FLASH_ENV_ADDR)
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_FLASH_ENV_ADDR,
+#if defined(CFG_FLASH_ENV_BUF)
+ CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_BUF - 1,
+#else
+ CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1,
+#endif
+ &flash_info[0]);
+#endif
+
+ return flash_info[0].size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+#if 0
+static void
+flash_get_offsets(ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+}
+#endif /* 0 */
+
+/*-----------------------------------------------------------------------
+ */
+void
+flash_print_info(flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F320J5: printf ("28F320J5 (32 Mbit, 2 x 16bit)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+#if 0
+static ulong
+flash_get_size(vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start adress table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+#endif /* 0 */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int
+flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+ int prot, sect, haderr;
+ ulong start, now, last;
+ int rcode = 0;
+
+#ifdef FLASH_DEBUG
+ printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n"
+ " Bank # %d: ", s_last - s_first + 1, s_first, s_last,
+ (info - flash_info) + 1);
+ flash_print_info(info);
+#endif
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf("- Warning: %d protected sector%s will not be erased!\n",
+ prot, (prot > 1 ? "s" : ""));
+ }
+
+ start = get_timer (0);
+ last = 0;
+ haderr = 0;
+
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ ulong estart;
+ int sectdone;
+
+ bank_erase_init(info, sect);
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ estart = get_timer(start);
+
+ do {
+ now = get_timer(start);
+
+ if (now - estart > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout (sect %d)\n", sect);
+ haderr = 1;
+ rcode = 1;
+ break;
+ }
+
+#ifndef FLASH_DEBUG
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+#endif
+
+ sectdone = bank_erase_poll(info, sect);
+
+ if (sectdone < 0) {
+ haderr = 1;
+ rcode = 1;
+ break;
+ }
+
+ } while (!sectdone);
+
+ if (haderr)
+ break;
+ }
+ }
+
+ if (haderr > 0)
+ printf (" failed\n");
+ else
+ printf (" done\n");
+
+ /* reset to read mode */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ bank_reset(info, sect);
+ }
+ }
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int
+write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int
+write_word(flash_info_t *info, ulong dest, ulong data)
+{
+ int retval;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*(ulong *)dest & data) != data) {
+ return (2);
+ }
+
+ retval = bank_write_word((bank_addr_t)dest, (bank_word_t)data);
+
+ return (retval);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0,
+ size_b0 >> 20);
+ }
+
+ if (FLASH_BASE1_PRELIM != 0x0) {
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: Bank 1 (0x%08lx = %ld MB)"
+ " > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1 >> 20,
+ size_b0, size_b0 >> 20);
+
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+ } else {
+ size_b1 = 0;
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ /* ICU862 Board has only one Flash Bank */
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM033C)) {
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00040000);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ puts ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: puts ("AMD "); break;
+ case FLASH_MAN_FUJ: puts ("FUJITSU "); break;
+ case FLASH_MAN_BM: puts ("BRIGHT MICRO "); break;
+ default: puts ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: puts ("29F040/29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: puts ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: puts ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: puts ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: puts ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: puts ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: puts ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: puts ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: puts ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM033C: puts ("AM29LV033C (32 Mbit)\n");
+ break;
+ default: puts ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ puts (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0) {
+ puts ("\n ");
+ }
+
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+
+ puts ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+#if 0
+ ulong base = (ulong)addr;
+#endif
+ uchar value;
+
+ /* Write auto select command: read Manufacturer ID */
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x90909090;
+#endif
+
+ value = addr[0];
+
+ switch (value + (value << 16)) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ case AMD_ID_LV033C:
+ info->flash_id += FLASH_AM033C;
+ info->sector_count = 64;
+ info->size = 0x01000000;
+ break; /* => 16Mb */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+#if 0
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+#else
+ flash_get_offsets ((ulong)addr, &flash_info[0]);
+#endif
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+#if 1
+ /* We don't know why it happens, but on ICU Board *
+ * for AMD29033C flash we need to resend the command of *
+ * reading flash protection for upper 8 Mb of flash */
+ if ( i == 32 ) {
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x90909090;
+ }
+#endif
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ *addr = 0x00F000F0; /* reset bank */
+#else
+ *addr = 0xF0F0F0F0; /* reset bank */
+#endif
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ puts ("- missing\n");
+ } else {
+ puts ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ puts ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ puts ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x80808080;
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+#endif
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+#if 0
+ addr[0] = 0x00300030;
+#else
+ addr[0] = 0x30303030;
+#endif
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+#if 0
+ while ((addr[0] & 0x00800080) != 0x00800080)
+#else
+ while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF)
+#endif
+ {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ puts ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+#if 0
+ addr[0] = 0x00F000F0; /* reset bank */
+#else
+ addr[0] = 0xF0F0F0F0; /* reset bank */
+#endif
+
+ puts (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+#if 0
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+#else
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0xA0A0A0A0;
+#endif
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+#if 0
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080))
+#else
+ while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080))
+#endif
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ volatile ip860_bcsr_t *bcsr = (ip860_bcsr_t *)BCSR_BASE;
+ unsigned long size;
+ int i;
+
+ /* Init: enable write,
+ * or we cannot even write flash commands
+ */
+ bcsr->bd_ctrl |= BD_CTRL_FLWE;
+
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size = flash_get_size((vu_long *)FLASH_BASE, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size, size<<20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+ memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
+ (memctl->memc_br1 & ~(BR_BA_MSK));
+
+ /* Re-do sizing to get full correct info */
+ size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+ return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* all possible flash types
+ * (28F016SV, 28F160S3, 28F320S3)
+ * have the same erase block size: 64 kB per chip,
+ * of 128 kB per bank
+ */
+
+ /* set up sector start address table */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base;
+ base += 0x00020000;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("Intel "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F016SV: printf ("28F016SV (16 Mbit, 32 x 64k)\n");
+ break;
+ case FLASH_28F160S3: printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
+ break;
+ case FLASH_28F320S3: printf ("28F320S3 (32 Mbit, 64 x 512K)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+ /* Write "Intelligent Identifier" command: read Manufacturer ID */
+ *addr = 0x90909090;
+
+ value = addr[0];
+ switch (value) {
+ case (MT_MANUFACT & 0x00FF00FF): /* MT or => Intel */
+ case (INTEL_ALT_MANU & 0x00FF00FF):
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case (INTEL_ID_28F016S):
+ info->flash_id += FLASH_28F016SV;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ break; /* => 2x2 MB */
+
+ case (INTEL_ID_28F160S3):
+ info->flash_id += FLASH_28F160S3;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ break; /* => 2x2 MB */
+
+ case (INTEL_ID_28F320S3):
+ info->flash_id += FLASH_28F320S3;
+ info->sector_count = 64;
+ info->size = 0x00800000;
+ break; /* => 2x4 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000);
+ /* don't know how to check sector protection */
+ info->protect[i] = 0;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (vu_long *)info->start[0];
+
+ *addr = 0xFFFFFF; /* reset bank to read array mode */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_long *addr = (vu_long *)(info->start[sect]);
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Single Block Erase Command */
+ *addr = 0x20202020;
+ /* Confirm */
+ *addr = 0xD0D0D0D0;
+ /* Resume Command, as per errata update */
+ *addr = 0xD0D0D0D0;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while ((*addr & 0x00800080) != 0x00800080) {
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = 0xFFFFFFFF; /* reset bank */
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ /* reset to read mode */
+ *addr = 0xFFFFFFFF;
+ }
+ }
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long *)dest;
+ ulong start, csr;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*addr & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Write Command */
+ *addr = 0x10101010;
+
+ /* Write Data */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ flag = 0;
+ while (((csr = *addr) & 0x00800080) != 0x00800080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ flag = 1;
+ break;
+ }
+ }
+ if (csr & 0x00400040) {
+printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
+ flag = 1;
+ }
+
+ /* Clear Status Registers Command */
+ *addr = 0x50505050;
+ /* Reset to read array mode */
+ *addr = 0xFFFFFFFF;
+
+ return (flag);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0: "
+ "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+ flash_info[0].flash_id,
+ size_b0, size_b0<<20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
+ BR_MS_GPCM | BR_PS_16 | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_MT:
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + ((i-3) * 0x00020000);
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+ return;
+
+ case FLASH_MAN_SST:
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00002000);
+ }
+ return;
+
+ case FLASH_MAN_AMD:
+ case FLASH_MAN_FUJ:
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+ return;
+ default:
+ printf ("Don't know sector ofsets for flash type 0x%lx\n",
+ info->flash_id);
+ return;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("Fujitsu "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ case FLASH_MAN_MT: printf ("MT "); break;
+ case FLASH_MAN_INTEL: printf ("Intel "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_SST200A: printf ("39xF200A (2M = 128K x 16)\n");
+ break;
+ case FLASH_SST400A: printf ("39xF400A (4M = 256K x 16)\n");
+ break;
+ case FLASH_SST800A: printf ("39xF800A (8M = 512K x 16)\n");
+ break;
+ case FLASH_STM800AB: printf ("M29W800AB (8M = 512K x 16)\n");
+ break;
+ case FLASH_28F008S5: printf ("28F008S5 (1M = 64K x 16)\n");
+ break;
+ case FLASH_28F400_T: printf ("28F400B3 (4Mbit, top boot sector)\n");
+ break;
+ case FLASH_28F400_B: printf ("28F400B3 (4Mbit, bottom boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size >= (1 << 20)) {
+ i = 20;
+ } else {
+ i = 10;
+ }
+ printf (" Size: %ld %cB in %d Sectors\n",
+ info->size >> i,
+ (i == 20) ? 'M' : 'k',
+ info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ ushort value;
+ vu_short *saddr = (vu_short *)addr;
+
+ /* Read Manufacturer ID */
+ saddr[0] = 0x0090;
+ value = saddr[0];
+
+ switch (value) {
+ case (AMD_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (FUJ_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (SST_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case (STM_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ case (MT_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_MT;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ saddr[0] = 0x00FF; /* restore read mode */
+ return (0); /* no or unknown flash */
+ }
+
+ value = saddr[1]; /* device ID */
+
+ switch (value) {
+ case (AMD_ID_LV400T & 0xFFFF):
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV400B & 0xFFFF):
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (AMD_ID_LV800T & 0xFFFF):
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (AMD_ID_LV800B & 0xFFFF):
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (AMD_ID_LV160T & 0xFFFF):
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (AMD_ID_LV160B & 0xFFFF):
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case (AMD_ID_LV320T & 0xFFFF):
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_LV320B & 0xFFFF):
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ case (SST_ID_xF200A & 0xFFFF):
+ info->flash_id += FLASH_SST200A;
+ info->sector_count = 64; /* 39xF200A ID ( 2M = 128K x 16 ) */
+ info->size = 0x00080000;
+ break;
+ case (SST_ID_xF400A & 0xFFFF):
+ info->flash_id += FLASH_SST400A;
+ info->sector_count = 128; /* 39xF400A ID ( 4M = 256K x 16 ) */
+ info->size = 0x00100000;
+ break;
+ case (SST_ID_xF800A & 0xFFFF):
+ info->flash_id += FLASH_SST800A;
+ info->sector_count = 256; /* 39xF800A ID ( 8M = 512K x 16 ) */
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ case (STM_ID_x800AB & 0xFFFF):
+ info->flash_id += FLASH_STM800AB;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ case (MT_ID_28F400_T & 0xFFFF):
+ info->flash_id += FLASH_28F400_T;
+ info->sector_count = 7;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+ case (MT_ID_28F400_B & 0xFFFF):
+ info->flash_id += FLASH_28F400_B;
+ info->sector_count = 7;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ saddr[0] = 0x00FF; /* restore read mode */
+ return (0); /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ saddr[0] = 0x00FF; /* restore read mode */
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MT) {
+ printf ("Can erase only MT flash types - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_short *addr = (vu_short *)(info->start[sect]);
+ unsigned short status;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = 0x0050; /* clear status register */
+ *addr = 0x0020; /* erase setup */
+ *addr = 0x00D0; /* erase confirm */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while (((status = *addr) & 0x0080) != 0x0080) {
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = 0x00FF; /* reset to read mode */
+ return 1;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ *addr = 0x00FF; /* reset to read mode */
+ }
+ }
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define FLASH_WIDTH 2 /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+
+ wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<FLASH_WIDTH && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ }
+
+ /*
+ * handle FLASH_WIDTH aligned part
+ */
+ while (cnt >= FLASH_WIDTH) {
+ data = 0;
+ for (i=0; i<FLASH_WIDTH; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ cnt -= FLASH_WIDTH;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<FLASH_WIDTH; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_short *addr = (vu_short *)dest;
+ ushort sdata = (ushort)data;
+ ushort status;
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*addr & sdata) != sdata) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = 0x0040; /* write setup */
+ *addr = sdata;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (((status = *addr) & 0x0080) != 0x0080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *addr = 0x00FF; /* restore read mode */
+ return (1);
+ }
+ }
+
+ *addr = 0x00FF; /* restore read mode */
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Derived from ../tqm8xx/flash.c
+ * [Torsten Stevens, FHG IMS; Bruno Achauer, Exet AG]
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0: "
+ "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+ flash_info[0].flash_id,
+ size_b0, size_b0<<20);
+ }
+
+ DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE5_PRELIM);
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE5_PRELIM, &flash_info[1]);
+
+ DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ DEBUGF ("## Before remap: "
+ "BR0: 0x%08x OR0: 0x%08x "
+ "BR1: 0x%08x OR1: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0,
+ memctl->memc_br1, memctl->memc_or1);
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | \
+ BR_MS_GPCM | BR_PS_32 | BR_V;
+
+ DEBUGF("## BR0: 0x%08x OR0: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0);
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or5 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+ memctl->memc_br5 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_PS_32 | BR_V;
+
+ DEBUGF("## BR5: 0x%08x OR5: 0x%08x\n",
+ memctl->memc_br5, memctl->memc_or5);
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_info[1].size = size_b1;
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[1]);
+#endif
+ } else {
+ memctl->memc_br5 = 0; /* invalidate bank */
+ memctl->memc_or5 = 0; /* invalidate bank */
+
+ DEBUGF("## DISABLE BR5: 0x%08x OR5: 0x%08x\n",
+ memctl->memc_br5, memctl->memc_or5);
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ flash_info[1].size = 0;
+ }
+
+ DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AM290[48]0B devices
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include "vpd.h"
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size, totsize;
+ int i;
+ ulong addr;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ totsize = 0;
+ addr = 0xfc000000;
+ for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+ size = flash_get_size((vu_long *)addr, &flash_info[i]);
+ if (flash_info[i].flash_id == FLASH_UNKNOWN)
+ break;
+ totsize += size;
+ addr += size;
+ }
+
+ addr = 0xfe000000;
+ for(i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+
+ size = flash_get_size((vu_long *)addr, &flash_info[i]);
+ if (flash_info[i].flash_id == FLASH_UNKNOWN)
+ break;
+ totsize += size;
+ addr += size;
+ }
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ return (totsize);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id >> 16) {
+ case 0x1:
+ printf ("AMD ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case AMD_ID_F040B:
+ printf ("AM29F040B (4 Mbit)\n");
+ break;
+ case AMD_ID_F080B:
+ printf ("AM29F080B (8 Mbit)\n");
+ break;
+ case AMD_ID_F016D:
+ printf ("AM29F016D (16 Mbit)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong vendor, devid;
+ ulong base = (ulong)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x90909090;
+
+ vendor = addr[0];
+ devid = addr[1] & 0xff;
+
+ /* only support AMD */
+ if (vendor != 0x01010101) {
+ return 0;
+ }
+
+ vendor &= 0xf;
+ devid &= 0xff;
+
+ if (devid == AMD_ID_F040B) {
+ info->flash_id = vendor << 16 | devid;
+ info->sector_count = 8;
+ info->size = info->sector_count * 0x10000;
+ }
+ else if (devid == AMD_ID_F080B) {
+ info->flash_id = vendor << 16 | devid;
+ info->sector_count = 16;
+ info->size = 4 * info->sector_count * 0x10000;
+ }
+ else if (devid == AMD_ID_F016D) {
+ info->flash_id = vendor << 16 | devid;
+ info->sector_count = 32;
+ info->size = 4 * info->sector_count * 0x10000;
+ }
+ else {
+ printf ("## Unknown Flash Type: %08lx\n", devid);
+ return 0;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* sector base address */
+ info->start[i] = base + i * (info->size / info->sector_count);
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (vu_long *)info->start[0];
+ addr[0] = 0xF0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0XAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0x80808080;
+ addr[0x0555] = 0XAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x30303030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x80808080) != 0x80808080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0xF0F0F0F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0xAAAAAAAA;
+ addr[0x02AA] = 0x55555555;
+ addr[0x0555] = 0xA0A0A0A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Code in faintly related to linux/arch/ppc/8xx_io:
+ * MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * This file implements functions to read the MBX's Vital Product Data
+ * (VPD). I can't use the more general i2c code in mpc8xx/... since I need
+ * the VPD at a time where there is no RAM available yet. Hence the VPD is
+ * read into a special area in the DPRAM (see config_MBX.h::CFG_DPRAMVPD).
+ *
+ * -----------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#ifdef CONFIG_8xx
+#include <commproc.h>
+#endif
+#include "vpd.h"
+
+/* Location of receive/transmit buffer descriptors
+ * Allocate one transmit bd and one receive bd.
+ * IIC_BD_FREE points to free bd space which we'll use as tx buffer.
+ */
+#define IIC_BD_TX1 (BD_IIC_START + 0*sizeof(cbd_t))
+#define IIC_BD_TX2 (BD_IIC_START + 1*sizeof(cbd_t))
+#define IIC_BD_RX (BD_IIC_START + 2*sizeof(cbd_t))
+#define IIC_BD_FREE (BD_IIC_START + 3*sizeof(cbd_t))
+
+/* FIXME -- replace 0x2000 with offsetof */
+#define VPD_P ((vpd_t *)(CFG_IMMR + 0x2000 + CFG_DPRAMVPD))
+
+/* transmit/receive buffers */
+#define IIC_RX_LENGTH 128
+
+#define WITH_MICROCODE_PATCH
+
+vpd_packet_t * vpd_find_packet(u_char ident)
+{
+ vpd_packet_t *packet;
+ vpd_t *vpd = VPD_P;
+
+ packet = (vpd_packet_t *)&vpd->packets;
+ while ((packet->identifier != ident) && packet->identifier != 0xFF)
+ {
+ packet = (vpd_packet_t *)((char *)packet + packet->size + 2);
+ }
+ return packet;
+}
+
+void vpd_init(void)
+{
+ volatile immap_t *im = (immap_t *)CFG_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
+ volatile iic_t *iip;
+#ifdef WITH_MICROCODE_PATCH
+ ulong reloc = 0;
+#endif
+
+ iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+ /*
+ * kludge: when running from flash, no microcode patch can be
+ * installed. However, the DPMEM usually contains non-zero
+ * garbage at the relocatable patch base location, so lets clear
+ * it now. This way the rest of the code can support the microcode
+ * patch dynamically.
+ */
+ if ((ulong)vpd_init & 0xff000000)
+ iip->iic_rpbase = 0;
+
+#ifdef WITH_MICROCODE_PATCH
+ /* Check for and use a microcode relocation patch. */
+ if ((reloc = iip->iic_rpbase))
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+ /* Initialize Port B IIC pins */
+ cp->cp_pbpar |= 0x00000030;
+ cp->cp_pbdir |= 0x00000030;
+ cp->cp_pbodr |= 0x00000030;
+
+ i2c->i2c_i2mod = 0x04; /* filter clock */
+ i2c->i2c_i2add = 0x34; /* select an arbitrary (unique) address */
+ i2c->i2c_i2brg = 0x07; /* make clock run maximum slow */
+ i2c->i2c_i2cmr = 0x00; /* disable interrupts */
+ i2c->i2c_i2cer = 0x1f; /* clear events */
+ i2c->i2c_i2com = 0x01; /* configure i2c to work as master */
+
+ if (vpd_read(0xa4, (uchar*)VPD_P, VPD_EEPROM_SIZE, 0) != VPD_EEPROM_SIZE)
+ {
+ hang();
+ }
+}
+
+
+/* Read from I2C.
+ * This is a two step process. First, we send the "dummy" write
+ * to set the device offset for the read. Second, we perform
+ * the read operation.
+ */
+int vpd_read(uint iic_device, uchar *buf, int count, int offset)
+{
+ volatile immap_t *im = (immap_t *)CFG_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c);
+ volatile iic_t *iip;
+ volatile cbd_t *tbdf1, *tbdf2, *rbdf;
+ uchar *tb;
+ uchar event;
+#ifdef WITH_MICROCODE_PATCH
+ ulong reloc = 0;
+#endif
+
+ iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+#ifdef WITH_MICROCODE_PATCH
+ /* Check for and use a microcode relocation patch. */
+ if ((reloc = iip->iic_rpbase))
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+ tbdf1 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX1];
+ tbdf2 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX2];
+ rbdf = (cbd_t *)&cp->cp_dpmem[IIC_BD_RX];
+
+ /* Send a "dummy write" operation. This is a write request with
+ * only the offset sent, followed by another start condition.
+ * This will ensure we start reading from the first location
+ * of the EEPROM.
+ */
+ tb = (uchar*)&cp->cp_dpmem[IIC_BD_FREE];
+ tb[0] = iic_device & 0xfe; /* device address */
+ tb[1] = offset; /* offset */
+ tbdf1->cbd_bufaddr = (uint)tb;
+ tbdf1->cbd_datlen = 2;
+ tbdf1->cbd_sc = 0x8400;
+
+ tb += 2;
+ tb[0] = iic_device | 1; /* device address */
+ tbdf2->cbd_bufaddr = (uint)tb;
+ tbdf2->cbd_datlen = count+1;
+ tbdf2->cbd_sc = 0xbc00;
+
+ rbdf->cbd_bufaddr = (uint)buf;
+ rbdf->cbd_datlen = 0;
+ rbdf->cbd_sc = 0xb000;
+
+ iip->iic_tbase = IIC_BD_TX1;
+ iip->iic_tbptr = IIC_BD_TX1;
+ iip->iic_rbase = IIC_BD_RX;
+ iip->iic_rbptr = IIC_BD_RX;
+ iip->iic_rfcr = 0x15;
+ iip->iic_tfcr = 0x15;
+ iip->iic_mrblr = count;
+ iip->iic_rstate = 0;
+ iip->iic_tstate = 0;
+
+ i2c->i2c_i2cer = 0x1f; /* clear event mask */
+ i2c->i2c_i2mod |= 1; /* enable iic operation */
+ i2c->i2c_i2com |= 0x80; /* start master */
+
+ /* wait for IIC transfer */
+ do {
+ __asm__ volatile ("eieio");
+ event = i2c->i2c_i2cer;
+ } while (event == 0);
+
+ if ((event & 0x10) || (event & 0x04)) {
+ count = -1;
+ goto bailout;
+ }
+
+bailout:
+ i2c->i2c_i2mod &= ~1; /* turn off iic operation */
+ i2c->i2c_i2cer = 0x1f; /* clear event mask */
+
+ return count;
+}
--- /dev/null
+#ifndef FLASH_LIB_H
+#define FLASH_LIB_H
+
+#include <common.h>
+
+/* PIO operations max */
+#define FLASH_PROGRAM_POLLS 100000
+
+/* 10 Seconds default */
+#define FLASH_ERASE_SECTOR_TIMEOUT (10*1000 /*SEC*/ )
+
+/* Flash device info structure */
+typedef struct flash_dev_s {
+ char name[24]; /* Bank Name */
+ int bank; /* Bank 0 or 1 */
+ unsigned int base; /* Base address */
+ int sectors; /* Sector count */
+ int lgSectorSize; /* Log2(usable bytes/sector) */
+ int vendorID; /* Expected vendor ID */
+ int deviceID; /* Expected device ID */
+ int found; /* Set if found by flashLibInit */
+ int swap; /* Set for bank 1 if byte swap req'd */
+} flash_dev_t;
+
+#define FLASH_MAX_POS(dev) \
+ ((dev)->sectors << (dev)->lgSectorSize)
+
+#define FLASH_SECTOR_POS(dev, sector) \
+ ((sector) << (dev)->lgSectorSize)
+
+/* AMD 29F040 */
+#define FLASH0_BANK 0
+#define FLASH0_VENDOR_ID 0x01
+#define FLASH0_DEVICE_ID 0x49
+
+/* AMD29LV160DB */
+#define FLASH1_BANK 1
+#define FLASH1_VENDOR_ID 0x0001
+#define FLASH1_DEVICE_ID 0x2249
+
+extern flash_dev_t flashDev[];
+extern int flashDevCount;
+
+/*
+ * Device pointers
+ *
+ * These must be kept in sync with the table in flashLib.c.
+ */
+#define FLASH_DEV_BANK0_SA0 (&flashDev[0])
+#define FLASH_DEV_BANK0_SA1 (&flashDev[1])
+#define FLASH_DEV_BANK0_SA2 (&flashDev[2])
+#define FLASH_DEV_BANK0_LOW (&flashDev[3]) /* 960K */
+#define FLASH_DEV_BANK0_BOOT (&flashDev[4]) /* PLCC */
+#define FLASH_DEV_BANK0_HIGH (&flashDev[5]) /* 512K PLCC shadow */
+
+unsigned long flash_init(void);
+int flashEraseSector(flash_dev_t *dev, int sector);
+int flashErase(flash_dev_t *dev);
+int flashRead(flash_dev_t *dev, int pos, char *buf, int len);
+int flashWrite(flash_dev_t *dev, int pos, char *buf, int len);
+int flashWritable(flash_dev_t *dev, int pos, int len);
+int flashDiag(flash_dev_t *dev);
+int flashDiagAll(void);
+
+ulong flash_get_size (vu_long *addr, flash_info_t *info);
+void flash_print_info (flash_info_t *info);
+int flash_erase (flash_info_t *info, int s_first, int s_last);
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt);
+
+/*
+ * Flash info indices.
+ */
+#define FLASH_BANK_KERNEL 0
+#define FLASH_BANK_BOOT 1
+#define FLASH_BANK_AUX 2
+#define FIRST_SECTOR 0
+
+#endif /* !FLASH_LIB_H */
--- /dev/null
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001, Stuart Hughes, Lineo Inc, stuarth@lineo.com
+ * Add support the Sharp chips on the mpc8260ads.
+ * I started with board/ip860/flash.c and made changes I found in
+ * the MTD project by David Schleef.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static int clear_block_lock_bit(vu_long * addr);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+#ifndef CONFIG_MPC8260ADS
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ volatile ip860_bcsr_t *bcsr = (ip860_bcsr_t *)BCSR_BASE;
+#endif
+ unsigned long size;
+ int i;
+
+ /* Init: enable write,
+ * or we cannot even write flash commands
+ */
+#ifndef CONFIG_MPC8260ADS
+ bcsr->bd_ctrl |= BD_CTRL_FLWE;
+#endif
+
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+
+ /* set the default sector offset */
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size = flash_get_size((vu_long *)FLASH_BASE, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size, size<<20);
+ }
+#ifndef CONFIG_MPC8260ADS
+ /* Remap FLASH according to real size */
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+ memctl->memc_br1 = (CFG_FLASH_BASE & BR_BA_MSK) |
+ (memctl->memc_br1 & ~(BR_BA_MSK));
+#endif
+
+ /* Re-do sizing to get full correct info */
+ size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+ return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("Intel "); break;
+ case FLASH_MAN_SHARP: printf ("Sharp "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F016SV: printf ("28F016SV (16 Mbit, 32 x 64k)\n");
+ break;
+ case FLASH_28F160S3: printf ("28F160S3 (16 Mbit, 32 x 512K)\n");
+ break;
+ case FLASH_28F320S3: printf ("28F320S3 (32 Mbit, 64 x 512K)\n");
+ break;
+ case FLASH_LH28F016SCT: printf ("28F016SC (16 Mbit, 32 x 64K)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+ ulong sector_offset;
+
+ /* Write "Intelligent Identifier" command: read Manufacturer ID */
+ *addr = 0x90909090;
+
+ value = addr[0] & 0x00FF00FF;
+ switch (value) {
+ case MT_MANUFACT: /* SHARP, MT or => Intel */
+ case INTEL_ALT_MANU:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ printf("unknown manufacturer: %x\n", (unsigned int)value);
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case (INTEL_ID_28F016S):
+ info->flash_id += FLASH_28F016SV;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ sector_offset = 0x20000;
+ break; /* => 2x2 MB */
+
+ case (INTEL_ID_28F160S3):
+ info->flash_id += FLASH_28F160S3;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ sector_offset = 0x20000;
+ break; /* => 2x2 MB */
+
+ case (INTEL_ID_28F320S3):
+ info->flash_id += FLASH_28F320S3;
+ info->sector_count = 64;
+ info->size = 0x00800000;
+ sector_offset = 0x20000;
+ break; /* => 2x4 MB */
+
+ case SHARP_ID_28F016SCL:
+ case SHARP_ID_28F016SCZ:
+ info->flash_id = FLASH_MAN_SHARP | FLASH_LH28F016SCT;
+ info->sector_count = 32;
+ info->size = 0x00800000;
+ sector_offset = 0x40000;
+ break; /* => 4x2 MB */
+
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base;
+ base += sector_offset;
+ /* don't know how to check sector protection */
+ info->protect[i] = 0;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (vu_long *)info->start[0];
+
+ *addr = 0xFFFFFF; /* reset bank to read array mode */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ( ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL)
+ && ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_SHARP) ) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ /* Make Sure Block Lock Bit is not set. */
+ if(clear_block_lock_bit((vu_long *)(info->start[s_first]))){
+ return 1;
+ }
+
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_long *addr = (vu_long *)(info->start[sect]);
+
+ last = start = get_timer (0);
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Reset Array */
+ *addr = 0xffffffff;
+ /* Clear Status Register */
+ *addr = 0x50505050;
+ /* Single Block Erase Command */
+ *addr = 0x20202020;
+ /* Confirm */
+ *addr = 0xD0D0D0D0;
+
+ if((info->flash_id & FLASH_TYPEMASK) != FLASH_LH28F016SCT) {
+ /* Resume Command, as per errata update */
+ *addr = 0xD0D0D0D0;
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+ while ((*addr & 0x80808080) != 0x80808080) {
+ if(*addr & 0x20202020){
+ printf("Error in Block Erase - Lock Bit may be set!\n");
+ printf("Status Register = 0x%X\n", (uint)*addr);
+ *addr = 0xFFFFFFFF; /* reset bank */
+ return 1;
+ }
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = 0xFFFFFFFF; /* reset bank */
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ /* reset to read mode */
+ *addr = 0xFFFFFFFF;
+ }
+ }
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long *)dest;
+ ulong start, csr;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*addr & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Write Command */
+ *addr = 0x10101010;
+
+ /* Write Data */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ flag = 0;
+ while (((csr = *addr) & 0x80808080) != 0x80808080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ flag = 1;
+ break;
+ }
+ }
+ if (csr & 0x40404040) {
+ printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr);
+ flag = 1;
+ }
+
+ /* Clear Status Registers Command */
+ *addr = 0x50505050;
+ /* Reset to read array mode */
+ *addr = 0xFFFFFFFF;
+
+ return (flag);
+}
+
+/*-----------------------------------------------------------------------
+ * Clear Block Lock Bit, returns:
+ * 0 - OK
+ * 1 - Timeout
+ */
+
+static int clear_block_lock_bit(vu_long * addr)
+{
+ ulong start, now;
+
+ /* Reset Array */
+ *addr = 0xffffffff;
+ /* Clear Status Register */
+ *addr = 0x50505050;
+
+ *addr = 0x60606060;
+ *addr = 0xd0d0d0d0;
+
+ start = get_timer (0);
+ while(*addr != 0x80808080){
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout on clearing Block Lock Bit\n");
+ *addr = 0xFFFFFFFF; /* reset bank */
+ return 1;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Modified 4/5/2001
+ * Wait for completion of each sector erase command issued
+ * 4/5/2001
+ * Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
+ */
+
+/*
+ * Modified 3/7/2001
+ * - adopted for pip405, Denis Peter, MPL AG Switzerland
+ * TODO:
+ * clean-up
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+#ifdef CONFIG_PIP405
+#include "../pip405/pip405.h"
+#endif
+#ifdef CONFIG_MIP405
+#include "../mip405/mip405.h"
+#endif
+#include "common_util.h"
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt);
+
+
+#ifdef CONFIG_ADCIOP
+#define ADDR0 0x0aa9
+#define ADDR1 0x0556
+#define FLASH_WORD_SIZE unsigned char
+#endif
+
+#ifdef CONFIG_CPCI405
+#define ADDR0 0x5555
+#define ADDR1 0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#ifdef CONFIG_PIP405
+#define ADDR0 0x5555
+#define ADDR1 0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#ifdef CONFIG_MIP405
+#define ADDR0 0x5555
+#define ADDR1 0x2aaa
+#define FLASH_WORD_SIZE unsigned short
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+/*-----------------------------------------------------------------------
+ */
+
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+ unsigned long pbcr;
+ unsigned long base_b0, base_b1;
+ unsigned char rc;
+
+ rc=switch_cs(FALSE); /* map Flash High */
+
+ if(rc)
+ printf("(MPS Boot) ");
+ else
+ printf("(Flash Boot) ");
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+ /* Only one bank */
+ if (CFG_MAX_FLASH_BANKS == 1)
+ {
+ /* Setup offsets */
+ /* flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]); */
+ /* Monitor protection ON by default */
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+ size_b1 = 0 ;
+ flash_info[0].size = size_b0;
+ }
+
+ /* 2 banks */
+ else
+ {
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ /* Re-do sizing to get full correct info */
+
+ if (size_b1)
+ {
+ mtdcr(ebccfga, pb0cr);
+ pbcr = mfdcr(ebccfgd);
+ mtdcr(ebccfga, pb0cr);
+ base_b1 = -size_b1;
+ pbcr = (pbcr & 0x0001ffff) | base_b1 | (((size_b1/1024/1024)-1)<<17);
+ mtdcr(ebccfgd, pbcr);
+ /* printf("pb1cr = %x\n", pbcr); */
+ }
+
+ if (size_b0)
+ {
+ mtdcr(ebccfga, pb1cr);
+ pbcr = mfdcr(ebccfgd);
+ mtdcr(ebccfga, pb1cr);
+ base_b0 = base_b1 - size_b0;
+ pbcr = (pbcr & 0x0001ffff) | base_b0 | (((size_b0/1024/1024)-1)<<17);
+ mtdcr(ebccfgd, pbcr);
+ /* printf("pb0cr = %x\n", pbcr); */
+ }
+
+ size_b0 = flash_get_size((vu_long *)base_b0, &flash_info[0]);
+
+ flash_get_offsets (base_b0, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ base_b0+size_b0-CFG_MONITOR_LEN,
+ base_b0+size_b0-1,
+ &flash_info[0]);
+
+ if (size_b1) {
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)base_b1, &flash_info[1]);
+
+ flash_get_offsets (base_b1, &flash_info[1]);
+
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ base_b1+size_b1-CFG_MONITOR_LEN,
+ base_b1+size_b1-1,
+ &flash_info[1]);
+ /* monitor protection OFF by default (one is enough) */
+ (void)flash_protect(FLAG_PROTECT_CLEAR,
+ base_b0+size_b0-CFG_MONITOR_LEN,
+ base_b0+size_b0-1,
+ &flash_info[0]);
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+ }/* else 2 banks */
+ switch_cs(rc); /* switch mode back */
+ return (size_b0 + size_b1);
+}
+
+
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ return;
+}
+#if 0
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ (info->flash_id == FLASH_AM040)){
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ }
+ else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+}
+
+#endif
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+ int k;
+ int size;
+ int erased;
+ volatile unsigned long *flash;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_INTEL: printf ("Intel "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: printf ("AM29F040 (512 Kbit, uniform sector size)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_INTEL320T: printf ("TE28F320C3 (32 Mbit, top sector size)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size >> 10, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ /*
+ * Check if whole sector is erased
+ */
+ if (i != (info->sector_count-1))
+ size = info->start[i+1] - info->start[i];
+ else
+ size = info->start[0] + info->size - info->start[i];
+ erased = 1;
+ flash = (volatile unsigned long *)info->start[i];
+ size = size >> 2; /* divide by 4 for longword access */
+ for (k=0; k<size; k++)
+ {
+ if (*flash++ != 0xffffffff)
+ {
+ erased = 0;
+ break;
+ }
+ }
+ if ((i % 5) == 0)
+ printf ("\n ");
+#if 0 /* test-only */
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+#else
+ printf (" %08lX%s%s",
+ info->start[i],
+ erased ? " E" : " ",
+ info->protect[i] ? "RO " : " "
+#endif
+ );
+ }
+ printf ("\n");
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ FLASH_WORD_SIZE value;
+ ulong base = (ulong)addr;
+ volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr2[ADDR0] = (FLASH_WORD_SIZE)0x00900090;
+
+ value = addr2[0];
+ /* printf("flash_get_size value: %x\n",value); */
+ switch (value) {
+ case (FLASH_WORD_SIZE)AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (FLASH_WORD_SIZE)FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (FLASH_WORD_SIZE)INTEL_MANUFACT:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ case (FLASH_WORD_SIZE)SST_MANUFACT:
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+ value = addr2[1]; /* device ID */
+ /* printf("Device value %x\n",value); */
+ switch (value) {
+ case (FLASH_WORD_SIZE)AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+ case (FLASH_WORD_SIZE)AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+#if 0 /* enable when device IDs are available */
+ case (FLASH_WORD_SIZE)AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (FLASH_WORD_SIZE)AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#endif
+ case (FLASH_WORD_SIZE)SST_ID_xF800A:
+ info->flash_id += FLASH_SST800A;
+ info->sector_count = 16;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+ case (FLASH_WORD_SIZE)INTEL_ID_28F320C3T:
+ info->flash_id += FLASH_INTEL320T;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+
+ case (FLASH_WORD_SIZE)SST_ID_xF160A:
+ info->flash_id += FLASH_SST160A;
+ info->sector_count = 32;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ (info->flash_id == FLASH_AM040)){
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000) - 0x00030000;
+ }
+ else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ if(info->sector_count==71) {
+
+ info->start[i--] = base + info->size - 0x00002000;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000A000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x0000E000;
+ for (; i >= 0; i--)
+ info->start[i] = base + i * 0x000010000;
+ }
+ else {
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--)
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr2 = (volatile FLASH_WORD_SIZE *)(info->start[i]);
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+ info->protect[i] = 0;
+ else
+ info->protect[i] = addr2[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+#if 0 /* test-only */
+#ifdef CONFIG_ADCIOP
+ addr2 = (volatile unsigned char *)info->start[0];
+ addr2[ADDR0] = 0xAA;
+ addr2[ADDR1] = 0x55;
+ addr2[ADDR0] = 0xF0; /* reset bank */
+#else
+ addr2 = (FLASH_WORD_SIZE *)info->start[0];
+ *addr2 = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
+#endif
+#else /* test-only */
+ addr2 = (FLASH_WORD_SIZE *)info->start[0];
+ *addr2 = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
+#endif /* test-only */
+ }
+ return (info->size);
+}
+
+int wait_for_DQ7(flash_info_t *info, int sect)
+{
+ ulong start, now, last;
+ volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
+
+ start = get_timer (0);
+ last = start;
+ while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return -1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+ return 0;
+}
+
+int intel_wait_for_DQ7(flash_info_t *info, int sect)
+{
+ ulong start, now, last;
+ volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[sect]);
+
+ start = get_timer (0);
+ last = start;
+ while ((addr[0] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return -1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+ addr[0]=(FLASH_WORD_SIZE)0x00500050;
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
+ volatile FLASH_WORD_SIZE *addr2;
+ int flag, prot, sect, l_sect;
+ int i;
+
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
+ /* printf("Erasing sector %p\n", addr2); */ /* CLH */
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr2[0] = (FLASH_WORD_SIZE)0x00500050; /* block erase */
+ for (i=0; i<50; i++)
+ udelay(1000); /* wait 1 ms */
+ wait_for_DQ7(info, sect);
+ }
+ else {
+ if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+ addr2[0] = (FLASH_WORD_SIZE)0x00600060; /* unlock sector */
+ addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* sector erase */
+ intel_wait_for_DQ7(info, sect);
+ addr2[0] = (FLASH_WORD_SIZE)0x00200020; /* sector erase */
+ addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* sector erase */
+ intel_wait_for_DQ7(info, sect);
+ }
+ else {
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
+ addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr2[0] = (FLASH_WORD_SIZE)0x00300030; /* sector erase */
+ wait_for_DQ7(info, sect);
+ }
+ }
+ l_sect = sect;
+ /*
+ * Wait for each sector to complete, it's more
+ * reliable. According to AMD Spec, you must
+ * issue all erase commands within a specified
+ * timeout. This has been seen to fail, especially
+ * if printf()s are included (for debug)!!
+ */
+ /* wait_for_DQ7(info, sect); */
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+#if 0
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+ wait_for_DQ7(info, l_sect);
+
+DONE:
+#endif
+ /* reset to read mode */
+ addr = (FLASH_WORD_SIZE *)info->start[0];
+ addr[0] = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+void unlock_intel_sectors(flash_info_t *info,ulong addr,ulong cnt)
+{
+ int i;
+ volatile FLASH_WORD_SIZE *addr2;
+ long c;
+ c= (long)cnt;
+ for(i=info->sector_count-1;i>0;i--)
+ {
+ if(addr>=info->start[i])
+ break;
+ }
+ do {
+ addr2 = (FLASH_WORD_SIZE *)(info->start[i]);
+ addr2[0] = (FLASH_WORD_SIZE)0x00600060; /* unlock sector setup */
+ addr2[0] = (FLASH_WORD_SIZE)0x00D000D0; /* unlock sector */
+ intel_wait_for_DQ7(info, i);
+ i++;
+ c-=(info->start[i]-info->start[i-1]);
+ }while(c>0);
+
+
+}
+
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+ unlock_intel_sectors(info,addr,cnt);
+ }
+ wp = (addr & ~3); /* get lower word aligned address */
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ if((wp % 0x10000)==0)
+ printf("."); /* show Progress */
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ rc=write_word(info, wp, data);
+ return rc;
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static FLASH_WORD_SIZE *read_val = (FLASH_WORD_SIZE *)0x200000;
+
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ volatile FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)(info->start[0]);
+ volatile FLASH_WORD_SIZE *dest2 = (FLASH_WORD_SIZE *)dest;
+ volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data;
+ ulong start;
+ int flag;
+ int i;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((volatile FLASH_WORD_SIZE *)dest) &
+ (FLASH_WORD_SIZE)data) != (FLASH_WORD_SIZE)data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+ for (i=0; i<4/sizeof(FLASH_WORD_SIZE); i++)
+ {
+ if((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+ /* intel style writting */
+ dest2[i] = (FLASH_WORD_SIZE)0x00500050;
+ dest2[i] = (FLASH_WORD_SIZE)0x00400040;
+ *read_val++ = data2[i];
+ dest2[i] = data2[i];
+ if (flag)
+ enable_interrupts();
+ /* data polling for D7 */
+ start = get_timer (0);
+ udelay(10);
+ while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) != (FLASH_WORD_SIZE)0x00800080)
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
+ return (1);
+ }
+ dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
+ udelay(10);
+ dest2[i] = (FLASH_WORD_SIZE)0x00FF00FF; /* return to read mode */
+ if(dest2[i]!=data2[i])
+ printf("Error at %p 0x%04X != 0x%04X\n",&dest2[i],dest2[i],data2[i]);
+ }
+ else {
+ addr2[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+ addr2[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+ addr2[ADDR0] = (FLASH_WORD_SIZE)0x00A000A0;
+ dest2[i] = data2[i];
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((dest2[i] & (FLASH_WORD_SIZE)0x00800080) !=
+ (data2[i] & (FLASH_WORD_SIZE)0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * TODO: clean-up
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <devices.h>
+#include "isa.h"
+#include "piix4_pci.h"
+#include "kbd.h"
+#include "video.h"
+
+extern int drv_isa_kbd_init (void);
+
+#undef ISA_DEBUG
+
+#ifdef ISA_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+
+/* fdc (logical device 0) */
+const SIO_LOGDEV_TABLE sio_fdc[] = {
+ {0x60, 3}, /* set IO to FDPort (3F0) */
+ {0x61, 0xF0}, /* set IO to FDPort (3F0) */
+ {0x70, 06}, /* set IRQ 6 for FDPort */
+ {0x74, 02}, /* set DMA 2 for FDPort */
+ {0xF0, 0x05}, /* set to PS2 type */
+ {0xF1, 0x00}, /* default value */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+/* paralell port (logical device 3) */
+const SIO_LOGDEV_TABLE sio_pport[] = {
+ {0x60, 3}, /* set IO to PPort (378) */
+ {0x61, 0x78}, /* set IO to PPort (378) */
+ {0x70, 07}, /* set IRQ 7 for PPort */
+ {0xF1, 00}, /* set PPort to normal */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+/* paralell port (logical device 3) Floppy assigned to lpt */
+const SIO_LOGDEV_TABLE sio_pport_fdc[] = {
+ {0x60, 3}, /* set IO to PPort (378) */
+ {0x61, 0x78}, /* set IO to PPort (378) */
+ {0x70, 07}, /* set IRQ 7 for PPort */
+ {0xF1, 02}, /* set PPort to Floppy */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+/* uart 1 (logical device 4) */
+const SIO_LOGDEV_TABLE sio_com1[] = {
+ {0x60, 3}, /* set IO to COM1 (3F8) */
+ {0x61, 0xF8}, /* set IO to COM1 (3F8) */
+ {0x70, 04}, /* set IRQ 4 for COM1 */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+/* uart 2 (logical device 5) */
+const SIO_LOGDEV_TABLE sio_com2[] = {
+ {0x60, 2}, /* set IO to COM2 (2F8) */
+ {0x61, 0xF8}, /* set IO to COM2 (2F8) */
+ {0x70, 03}, /* set IRQ 3 for COM2 */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+
+/* keyboard controller (logical device 7) */
+const SIO_LOGDEV_TABLE sio_keyboard[] = {
+ {0x70, 1}, /* set IRQ 1 for keyboard */
+ {0x72, 12}, /* set IRQ 12 for mouse */
+ {0xF0, 0}, /* disable Port92 (this is a PowerPC!!) */
+ {0x30, 1}, /* and activate the device */
+ {0xFF, 0} /* end of device table */
+};
+
+
+/*******************************************************************************
+* Config SuperIO FDC37C672
+********************************************************************************/
+unsigned char open_cfg_super_IO(int address)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,0x55); /* open config */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,0x20); /* set address to DEV ID */
+ if(in8(CFG_ISA_IO_BASE_ADDRESS | address | 0x1)==0x40) /* ok Device ID is correct */
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void close_cfg_super_IO(int address)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,0xAA); /* close config */
+}
+
+
+unsigned char read_cfg_super_IO(int address, unsigned char function, unsigned char regaddr)
+{
+ /* assuming config reg is open */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
+ return in8(CFG_ISA_IO_BASE_ADDRESS | address | 1);
+}
+
+void write_cfg_super_IO(int address, unsigned char function, unsigned char regaddr, unsigned char data)
+{
+ /* assuming config reg is open */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,0x7); /* points to the function reg */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,function); /* set the function no */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address,regaddr); /* sets the address in the function */
+ out8(CFG_ISA_IO_BASE_ADDRESS | address | 1,data); /* writes the data */
+}
+
+void isa_write_table(SIO_LOGDEV_TABLE *ldt,unsigned char ldev)
+{
+ while (ldt->index != 0xFF) {
+ write_cfg_super_IO(SIO_CFG_PORT, ldev, ldt->index, ldt->val);
+ ldt++;
+ } /* endwhile */
+}
+
+void isa_sio_loadtable(void)
+{
+ unsigned char *s = getenv("floppy");
+ /* setup Floppy device 0*/
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_fdc,0);
+ /* setup parallel port device 3 */
+ if(s && !strncmp(s, "lpt", 3)) {
+ printf("SIO: Floppy assigned to LPT\n");
+ /* floppy is assigned to the LPT */
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport_fdc,3);
+ }
+ else {
+ /*printf("Floppy assigned to internal port\n");*/
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_pport,3);
+ }
+ /* setup Com1 port device 4 */
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_com1,4);
+ /* setup Com2 port device 5 */
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_com2,5);
+ /* setup keyboards device 7 */
+ isa_write_table((SIO_LOGDEV_TABLE *)&sio_keyboard,7);
+}
+
+
+void isa_sio_setup(void)
+{
+ if(open_cfg_super_IO(SIO_CFG_PORT)==TRUE)
+ {
+ isa_sio_loadtable();
+ close_cfg_super_IO(0x3F0);
+ }
+}
+
+
+
+/******************************************************************************
+ * IRQ Controller
+ * we use the Vector mode
+ */
+
+struct isa_irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ int count;
+};
+
+static struct isa_irq_action isa_irqs[16];
+
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_imr1 (unsigned char)cached_irq_mask
+#define cached_imr2 (unsigned char)(cached_irq_mask>>8)
+#define IMR_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_OCW1
+#define IMR_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_OCW1
+#define ICW1_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW1
+#define ICW1_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW1
+#define ICW2_1 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT1_ICW2
+#define ICW2_2 CFG_ISA_IO_BASE_ADDRESS + PIIX4_ISA_INT2_ICW2
+#define ICW3_1 ICW2_1
+#define ICW3_2 ICW2_2
+#define ICW4_1 ICW2_1
+#define ICW4_2 ICW2_2
+#define ISR_1 ICW1_1
+#define ISR_2 ICW1_2
+
+
+void disable_8259A_irq(unsigned int irq)
+{
+ unsigned int mask = 1 << irq;
+
+ cached_irq_mask |= mask;
+ if (irq & 8)
+ out8(IMR_2,cached_imr2);
+ else
+ out8(IMR_1,cached_imr1);
+}
+
+void enable_8259A_irq(unsigned int irq)
+{
+ unsigned int mask = ~(1 << irq);
+
+ cached_irq_mask &= mask;
+ if (irq & 8)
+ out8(IMR_2,cached_imr2);
+ else
+ out8(IMR_1,cached_imr1);
+}
+/*
+int i8259A_irq_pending(unsigned int irq)
+{
+ unsigned int mask = 1<<irq;
+ int ret;
+
+ if (irq < 8)
+ ret = inb(0x20) & mask;
+ else
+ ret = inb(0xA0) & (mask >> 8);
+ spin_unlock_irqrestore(&i8259A_lock, flags);
+
+ return ret;
+}
+*/
+
+/*
+ * This function assumes to be called rarely. Switching between
+ * 8259A registers is slow.
+ */
+int i8259A_irq_real(unsigned int irq)
+{
+ int value;
+ int irqmask = 1<<irq;
+
+ if (irq < 8) {
+ out8(ISR_1,0x0B); /* ISR register */
+ value = in8(ISR_1) & irqmask;
+ out8(ISR_1,0x0A); /* back to the IRR register */
+ return value;
+ }
+ out8(ISR_2,0x0B); /* ISR register */
+ value = in8(ISR_2) & (irqmask >> 8);
+ out8(ISR_2,0x0A); /* back to the IRR register */
+ return value;
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+void mask_and_ack_8259A(unsigned int irq)
+{
+ unsigned int irqmask = 1 << irq;
+ unsigned int temp_irqmask = cached_irq_mask;
+ /*
+ * Lightweight spurious IRQ detection. We do not want
+ * to overdo spurious IRQ handling - it's usually a sign
+ * of hardware problems, so we only do the checks we can
+ * do without slowing down good hardware unnecesserily.
+ *
+ * Note that IRQ7 and IRQ15 (the two spurious IRQs
+ * usually resulting from the 8259A-1|2 PICs) occur
+ * even if the IRQ is masked in the 8259A. Thus we
+ * can check spurious 8259A IRQs without doing the
+ * quite slow i8259A_irq_real() call for every IRQ.
+ * This does not cover 100% of spurious interrupts,
+ * but should be enough to warn the user that there
+ * is something bad going on ...
+ */
+ if (temp_irqmask & irqmask)
+ goto spurious_8259A_irq;
+ temp_irqmask |= irqmask;
+
+handle_real_irq:
+ if (irq & 8) {
+ in8(IMR_2); /* DUMMY - (do we need this?) */
+ out8(IMR_2,(unsigned char)(temp_irqmask>>8));
+ out8(ISR_2,0x60+(irq&7));/* 'Specific EOI' to slave */
+ out8(ISR_1,0x62); /* 'Specific EOI' to master-IRQ2 */
+ out8(IMR_2,cached_imr2); /* turn it on again */
+ } else {
+ in8(IMR_1); /* DUMMY - (do we need this?) */
+ out8(IMR_1,(unsigned char)temp_irqmask);
+ out8(ISR_1,0x60+irq); /* 'Specific EOI' to master */
+ out8(IMR_1,cached_imr1); /* turn it on again */
+ }
+
+ return;
+
+spurious_8259A_irq:
+ /*
+ * this is the slow path - should happen rarely.
+ */
+ if (i8259A_irq_real(irq))
+ /*
+ * oops, the IRQ _is_ in service according to the
+ * 8259A - not spurious, go handle it.
+ */
+ goto handle_real_irq;
+
+ {
+ static int spurious_irq_mask;
+ /*
+ * At this point we can be sure the IRQ is spurious,
+ * lets ACK and report it. [once per IRQ]
+ */
+ if (!(spurious_irq_mask & irqmask)) {
+ PRINTF("spurious 8259A interrupt: IRQ%d.\n", irq);
+ spurious_irq_mask |= irqmask;
+ }
+ /* irq_err_count++; */
+ /*
+ * Theoretically we do not have to handle this IRQ,
+ * but in Linux this does not cause problems and is
+ * simpler for us.
+ */
+ goto handle_real_irq;
+ }
+}
+
+void init_8259A(void)
+{
+ out8(IMR_1,0xff); /* mask all of 8259A-1 */
+ out8(IMR_2,0xff); /* mask all of 8259A-2 */
+
+ out8(ICW1_1,0x11); /* ICW1: select 8259A-1 init */
+ out8(ICW2_1,0x20 + 0); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
+ out8(ICW3_1,0x04); /* 8259A-1 (the master) has a slave on IR2 */
+ out8(ICW4_1,0x01); /* master expects normal EOI */
+ out8(ICW1_2,0x11); /* ICW2: select 8259A-2 init */
+ out8(ICW2_2,0x20 + 8); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
+ out8(ICW3_2,0x02); /* 8259A-2 is a slave on master's IR2 */
+ out8(ICW4_2,0x01); /* (slave's support for AEOI in flat mode
+ is to be investigated) */
+ udelay(10000); /* wait for 8259A to initialize */
+ out8(IMR_1,cached_imr1); /* restore master IRQ mask */
+ udelay(10000); /* wait for 8259A to initialize */
+ out8(IMR_2,cached_imr2); /* restore slave IRQ mask */
+}
+
+
+#define PCI_INT_ACK_ADDR 0xEED00000
+
+int handle_isa_int(void)
+{
+ unsigned long irqack;
+ unsigned char isr1,isr2,irq;
+ /* first we acknokledge the int via the PCI bus */
+ irqack=in32(PCI_INT_ACK_ADDR);
+ /* now we get the ISRs */
+ isr2=in8(ISR_2);
+ isr1=in8(ISR_1);
+ irq=(unsigned char)irqack;
+ if((irq==7)&&((isr1&0x80)==0)) {
+ PRINTF("IRQ7 detected but not in ISR\n");
+ }
+ else {
+ /* we should handle cascaded interrupts here also */
+ /* printf("ISA Irq %d\n",irq); */
+ isa_irqs[irq].count++;
+ if (isa_irqs[irq].handler != NULL)
+ (*isa_irqs[irq].handler)(isa_irqs[irq].arg); /* call isr */
+ else
+ {
+ PRINTF ("bogus interrupt vector 0x%x\n", irq);
+ }
+ }
+ /* issue EOI instruction to clear the IRQ */
+ mask_and_ack_8259A(irq);
+ return 0;
+}
+
+
+
+/******************************************************************
+ * Install and free an ISA interrupt handler.
+ */
+
+void isa_irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+ if (isa_irqs[vec].handler != NULL) {
+ printf ("ISA Interrupt vector %d: handler 0x%x replacing 0x%x\n",
+ vec, (uint)handler, (uint)isa_irqs[vec].handler);
+ }
+ isa_irqs[vec].handler = handler;
+ isa_irqs[vec].arg = arg;
+ enable_8259A_irq(vec);
+ PRINTF ("Install ISA IRQ %d ==> %p, @ %p mask=%04x\n", vec, handler, &isa_irqs[vec].handler,cached_irq_mask);
+
+}
+
+void isa_irq_free_handler(int vec)
+{
+ disable_8259A_irq(vec);
+ isa_irqs[vec].handler = NULL;
+ isa_irqs[vec].arg = NULL;
+ printf ("Free ISA IRQ %d mask=%04x\n", vec, cached_irq_mask);
+
+}
+
+/****************************************************************************/
+void isa_init_irq_contr(void)
+{
+ int i;
+ /* disable all Interrupts */
+ /* first write icws controller 1 */
+ for(i=0;i<16;i++)
+ {
+ isa_irqs[i].handler=NULL;
+ isa_irqs[i].arg=NULL;
+ isa_irqs[i].count=0;
+ }
+ init_8259A();
+ out8(IMR_2,0xFF);
+}
+
+
+/******************************************************************
+ * Init the ISA bus and devices.
+ */
+
+
+int isa_init(void)
+{
+ isa_sio_setup();
+ drv_isa_kbd_init();
+ return 0;
+}
+
+
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Source partly derived from:
+ * linux/drivers/char/pc_keyb.c
+ *
+ *
+ */
+#include <common.h>
+#include <asm/processor.h>
+#include <devices.h>
+#include "isa.h"
+#include "kbd.h"
+
+
+unsigned char kbd_read_status(void);
+unsigned char kbd_read_input(void);
+void kbd_send_data(unsigned char data);
+void disable_8259A_irq(unsigned int irq);
+void enable_8259A_irq(unsigned int irq);
+
+/* used only by send_data - set by keyboard_interrupt */
+
+
+#undef KBG_DEBUG
+
+#ifdef KBG_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#define KBD_STAT_KOBF 0x01
+#define KBD_STAT_IBF 0x02
+#define KBD_STAT_SYS 0x04
+#define KBD_STAT_CD 0x08
+#define KBD_STAT_LOCK 0x10
+#define KBD_STAT_MOBF 0x20
+#define KBD_STAT_TI_OUT 0x40
+#define KBD_STAT_PARERR 0x80
+
+#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */
+#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 2000 /* Timeout in ms for keyboard command acknowledge */
+/*
+ * Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
+#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
+#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
+#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
+ initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
+
+/*
+ * Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
+#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
+#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
+#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
+#define KBD_CMD_RESET 0xFF /* Reset */
+
+/*
+ * Keyboard Replies
+ */
+
+#define KBD_REPLY_POR 0xAA /* Power on reset */
+#define KBD_REPLY_ACK 0xFA /* Command ACK */
+#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
+
+/*
+ * Status Register Bits
+ */
+
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
+#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
+#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
+#define KBD_STAT_PERR 0x80 /* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ * Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 0x04 /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
+#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
+#define KBD_MODE_RFU 0x80
+
+
+#define KDB_DATA_PORT 0x60
+#define KDB_COMMAND_PORT 0x64
+
+#define LED_SCR 0x01 /* scroll lock led */
+#define LED_CAP 0x04 /* caps lock led */
+#define LED_NUM 0x02 /* num lock led */
+
+#define KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
+
+
+
+
+static volatile char kbd_buffer[KBD_BUFFER_LEN];
+static volatile int in_pointer = 0;
+static volatile int out_pointer = 0;
+
+
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+static unsigned char shift = 0;
+static unsigned char ctrl = 0;
+static unsigned char alt = 0;
+static unsigned char e0 = 0;
+static unsigned char leds = 0;
+
+#define DEVNAME "kbd"
+
+/* Simple translation table for the keys */
+
+static unsigned char kbd_plain_xlate[] = {
+ 0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', /* 0x00 - 0x0f */
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's', /* 0x10 - 0x1f */
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
+ 'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+static unsigned char kbd_shift_xlate[] = {
+ 0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', /* 0x00 - 0x0f */
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S', /* 0x10 - 0x1f */
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
+ 'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+static unsigned char kbd_ctrl_xlate[] = {
+ 0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t', /* 0x00 - 0x0f */
+ 0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13, /* 0x10 - 0x1f */
+ 0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16, /* 0x20 - 0x2f */
+ 0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
+ '\r',0xff,0xff
+ };
+
+/******************************************************************
+ * Init
+ ******************************************************************/
+int isa_kbd_init(void)
+{
+ char* result;
+ result=kbd_initialize();
+ if(result==NULL) {
+ PRINTF("AT Keyboard initialized\n");
+ irq_install_handler(25, (interrupt_handler_t *)handle_isa_int, NULL);
+ isa_irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
+ return (1);
+ }
+ else {
+ printf("%s\n",result);
+ return (-1);
+ }
+}
+
+#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+ return (0);
+}
+#endif
+
+int drv_isa_kbd_init (void)
+{
+ int error;
+ device_t kbddev ;
+ char *stdinname = getenv ("stdin");
+
+ if(isa_kbd_init()==-1)
+ return -1;
+ memset (&kbddev, 0, sizeof(kbddev));
+ strcpy(kbddev.name, DEVNAME);
+ kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ kbddev.putc = NULL ;
+ kbddev.puts = NULL ;
+ kbddev.getc = kbd_getc ;
+ kbddev.tstc = kbd_testc ;
+
+ error = device_register (&kbddev);
+ if(error==0) {
+ /* check if this is the standard input device */
+ if(strcmp(stdinname,DEVNAME)==0) {
+ /* reassign the console */
+ if(overwrite_console()) {
+ return 1;
+ }
+ error=console_assign(stdin,DEVNAME);
+ if(error==0)
+ return 1;
+ else
+ return error;
+ }
+ return 1;
+ }
+ return error;
+}
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+void kbd_put_queue(char data)
+{
+ if((in_pointer+1)==KBD_BUFFER_LEN) {
+ if(out_pointer==0) {
+ return; /* buffer full */
+ } else{
+ in_pointer=0;
+ }
+ } else {
+ if((in_pointer+1)==out_pointer)
+ return; /* buffer full */
+ in_pointer++;
+ }
+ kbd_buffer[in_pointer]=data;
+ return;
+}
+
+/* test if a character is in the queue */
+int kbd_testc(void)
+{
+ if(in_pointer==out_pointer)
+ return(0); /* no data */
+ else
+ return(1);
+}
+/* gets the character from the queue */
+int kbd_getc(void)
+{
+ char c;
+ while(in_pointer==out_pointer);
+ if((out_pointer+1)==KBD_BUFFER_LEN)
+ out_pointer=0;
+ else
+ out_pointer++;
+ c=kbd_buffer[out_pointer];
+ return (int)c;
+
+}
+
+
+/* set LEDs */
+
+void kbd_set_leds(void)
+{
+ if(caps_lock==0)
+ leds&=~LED_CAP; /* switch caps_lock off */
+ else
+ leds|=LED_CAP; /* switch on LED */
+ if(num_lock==0)
+ leds&=~LED_NUM; /* switch LED off */
+ else
+ leds|=LED_NUM; /* switch on LED */
+ if(scroll_lock==0)
+ leds&=~LED_SCR; /* switch LED off */
+ else
+ leds|=LED_SCR; /* switch on LED */
+ kbd_send_data(KBD_CMD_SET_LEDS);
+ kbd_send_data(leds);
+}
+
+
+void handle_keyboard_event(unsigned char scancode)
+{
+ unsigned char keycode;
+
+ /* Convert scancode to keycode */
+ PRINTF("scancode %x\n",scancode);
+ if(scancode==0xe0) {
+ e0=1; /* special charakters */
+ return;
+ }
+ if(e0==1) {
+ e0=0; /* delete flag */
+ if(!( ((scancode&0x7F)==0x38)|| /* the right ctrl key */
+ ((scancode&0x7F)==0x1D)|| /* the right alt key */
+ ((scancode&0x7F)==0x35)|| /* the right '/' key */
+ ((scancode&0x7F)==0x1C) )) /* the right enter key */
+ /* we swallow unknown e0 codes */
+ return;
+ }
+ /* special cntrl keys */
+ switch(scancode)
+ {
+ case 0x2A:
+ case 0x36: /* shift pressed */
+ shift=1;
+ return; /* do nothing else */
+ case 0xAA:
+ case 0xB6: /* shift released */
+ shift=0;
+ return; /* do nothing else */
+ case 0x38: /* alt pressed */
+ alt=1;
+ return; /* do nothing else */
+ case 0xB8: /* alt released */
+ alt=0;
+ return; /* do nothing else */
+ case 0x1d: /* ctrl pressed */
+ ctrl=1;
+ return; /* do nothing else */
+ case 0x9d: /* ctrl released */
+ ctrl=0;
+ return; /* do nothing else */
+ case 0x46: /* scrollock pressed */
+ scroll_lock=~scroll_lock;
+ kbd_set_leds();
+ return; /* do nothing else */
+ case 0x3A: /* capslock pressed */
+ caps_lock=~caps_lock;
+ kbd_set_leds();
+ return;
+ case 0x45: /* numlock pressed */
+ num_lock=~num_lock;
+ kbd_set_leds();
+ return;
+ case 0xC6: /* scroll lock released */
+ case 0xC5: /* num lock released */
+ case 0xBA: /* caps lock released */
+ return; /* just swallow */
+ }
+ if((scancode&0x80)==0x80) /* key released */
+ return;
+ /* now, decide which table we need */
+ if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ /* setup plain code first */
+ keycode=kbd_plain_xlate[scancode];
+ if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
+ if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown caps-locked scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_shift_xlate[scancode];
+ if(keycode<'A') { /* we only want the alphas capital */
+ keycode=kbd_plain_xlate[scancode];
+ }
+ }
+ if(shift==1) { /* shift overwrites caps_lock */
+ if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown shifted scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_shift_xlate[scancode];
+ }
+ if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
+ if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
+ PRINTF("unkown ctrl scancode %X\n",scancode);
+ return; /* swallow it */
+ }
+ keycode=kbd_ctrl_xlate[scancode];
+ }
+ /* check if valid keycode */
+ if(keycode==0xff) {
+ PRINTF("unkown scancode %X\n",scancode);
+ return; /* swallow unknown codes */
+ }
+
+ kbd_put_queue(keycode);
+ PRINTF("%x\n",keycode);
+}
+
+/*
+ * This reads the keyboard status port, and does the
+ * appropriate action.
+ *
+ */
+unsigned char handle_kbd_event(void)
+{
+ unsigned char status = kbd_read_status();
+ unsigned int work = 10000;
+
+ while ((--work > 0) && (status & KBD_STAT_OBF)) {
+ unsigned char scancode;
+
+ scancode = kbd_read_input();
+
+ /* Error bytes must be ignored to make the
+ Synaptics touchpads compaq use work */
+ /* Ignore error bytes */
+ if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
+ {
+ if (status & KBD_STAT_MOUSE_OBF)
+ ; /* not supported: handle_mouse_event(scancode); */
+ else
+ handle_keyboard_event(scancode);
+ }
+ status = kbd_read_status();
+ }
+ if (!work)
+ PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
+ return status;
+}
+
+
+
+/******************************************************************************
+ * Lowlevel Part of keyboard section
+ */
+unsigned char kbd_read_status(void)
+{
+ return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
+}
+
+unsigned char kbd_read_input(void)
+{
+ return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
+}
+
+void kbd_write_command(unsigned char cmd)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
+}
+
+void kbd_write_output(unsigned char data)
+{
+ out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
+}
+
+int kbd_read_data(void)
+{
+ int val;
+ unsigned char status;
+
+ val=-1;
+ status = kbd_read_status();
+ if (status & KBD_STAT_OBF) {
+ val = kbd_read_input();
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+ val = -2;
+ }
+ return val;
+}
+
+int kbd_wait_for_input(void)
+{
+ unsigned long timeout;
+ int val;
+
+ timeout = KBD_TIMEOUT;
+ val=kbd_read_data();
+ while(val < 0)
+ {
+ if(timeout--==0)
+ return -1;
+ udelay(1000);
+ val=kbd_read_data();
+ }
+ return val;
+}
+
+
+int kb_wait(void)
+{
+ unsigned long timeout = KBC_TIMEOUT * 10;
+
+ do {
+ unsigned char status = handle_kbd_event();
+ if (!(status & KBD_STAT_IBF))
+ return 0; /* ok */
+ udelay(1000);
+ timeout--;
+ } while (timeout);
+ return 1;
+}
+
+void kbd_write_command_w(int data)
+{
+ if(kb_wait())
+ PRINTF("timeout in kbd_write_command_w\n");
+ kbd_write_command(data);
+}
+
+void kbd_write_output_w(int data)
+{
+ if(kb_wait())
+ PRINTF("timeout in kbd_write_output_w\n");
+ kbd_write_output(data);
+}
+
+void kbd_send_data(unsigned char data)
+{
+ unsigned char status;
+ disable_8259A_irq(1); /* disable interrupt */
+ kbd_write_output_w(data);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ enable_8259A_irq(1); /* enable interrupt */
+}
+
+
+char * kbd_initialize(void)
+{
+ int status;
+
+ in_pointer = 0; /* delete in Buffer */
+ out_pointer = 0;
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55)
+ return "Kbd: failed self test";
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_TEST);
+ if (kbd_wait_for_input() != 0x00)
+ return "Kbd: interface failed self test";
+ /*
+ * Enable the keyboard by allowing the keyboard clock to run.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
+ status = kbd_wait_for_input();
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_RESET);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ {
+ PRINTF("status: %X\n",status);
+ return "Kbd: reset failed, no ACK";
+ }
+ } while (1);
+ if (kbd_wait_for_input() != KBD_REPLY_POR)
+ return "Kbd: reset failed, no POR";
+
+ /*
+ * Set keyboard controller mode. During this, the keyboard should be
+ * in the disabled state.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_DISABLE);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Kbd: disable keyboard: no ACK";
+ } while (1);
+
+ kbd_write_command_w(KBD_CCMD_WRITE_MODE);
+ kbd_write_output_w(KBD_MODE_KBD_INT
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
+
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write_command_w(KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write_output_w(0xF0);
+ kbd_wait_for_input();
+ kbd_write_output_w(0x01);
+ kbd_wait_for_input();
+ }
+ kbd_write_output_w(KBD_CMD_ENABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: enable keyboard: no ACK";
+
+ /*
+ * Finally, set the typematic rate to maximum.
+ */
+ kbd_write_output_w(KBD_CMD_SET_RATE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: Set rate: no ACK";
+ kbd_write_output_w(0x00);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Kbd: Set rate: no ACK";
+ return NULL;
+}
+
+void kbd_interrupt(void)
+{
+ handle_kbd_event();
+}
+
+
+
+/* eof */
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Note: Part of this code has been derived from linux
+ *
+ */
+
+/**********************************************************************
+ * How it works:
+ * -------------
+ * The framelist / Transfer descriptor / Queue Heads are similar like
+ * in the linux usb_uhci.c.
+ *
+ * During initialization, the following skeleton is allocated in init_skel:
+ *
+ * framespecific | common chain
+ *
+ * framelist[]
+ * [ 0 ]-----> TD ---------\
+ * [ 1 ]-----> TD ----------> TD ------> QH -------> QH -------> QH ---> NULL
+ * ... TD ---------/
+ * [1023]-----> TD --------/
+ *
+ * ^^ ^^ ^^ ^^ ^^
+ * 7 TDs for 1 TD for Start of Start of End Chain
+ * INT (2-128ms) 1ms-INT CTRL Chain BULK Chain
+ *
+ *
+ * Since this is a bootloader, the isochronous transfer descriptor have been removed.
+ *
+ * Interrupt Transfers.
+ * --------------------
+ * For Interupt transfers USB_MAX_TEMP_INT_TD Transfer descriptor are available. They
+ * will be inserted after the appropriate (depending the interval setting) skeleton TD.
+ * If an interrupt has been detected the dev->irqhandler is called. The status and number
+ * of transfered bytes is stored in dev->irq_status resp. dev->irq_act_len. If the
+ * dev->irqhandler returns 0, the interrupt TD is removed and disabled. If an 1 is returned,
+ * the interrupt TD will be reactivated.
+ *
+ * Control Transfers
+ * -----------------
+ * Control Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_cntrl queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ * Bulk Transfers
+ * --------------
+ * Bulk Transfers are issued by filling the tmp_td with the appropriate data and connect
+ * them to the qh_bulk queue header. Before other control/bulk transfers can be issued,
+ * the programm has to wait for completion. This does not allows asynchronous data transfer.
+ *
+ *
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#ifdef CONFIG_USB_UHCI
+
+#include <usb.h>
+#include "usb_uhci.h"
+
+#define USB_MAX_TEMP_TD 128 /* number of temporary TDs for bulk and control transfers */
+#define USB_MAX_TEMP_INT_TD 32 /* number of temporary TDs for Interrupt transfers */
+
+
+#undef USB_UHCI_DEBUG
+
+#ifdef USB_UHCI_DEBUG
+#define USB_UHCI_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_UHCI_PRINTF(fmt,args...)
+#endif
+
+
+static int irqvec = -1; /* irq vector, if -1 uhci is stopped / reseted */
+unsigned int usb_base_addr; /* base address */
+
+static uhci_td_t td_int[8]; /* Interrupt Transfer descriptors */
+static uhci_qh_t qh_cntrl; /* control Queue Head */
+static uhci_qh_t qh_bulk; /* bulk Queue Head */
+static uhci_qh_t qh_end; /* end Queue Head */
+static uhci_td_t td_last; /* last TD (linked with end chain) */
+
+/* temporary tds */
+static uhci_td_t tmp_td[USB_MAX_TEMP_TD]; /* temporary bulk/control td's */
+static uhci_td_t tmp_int_td[USB_MAX_TEMP_INT_TD]; /* temporary interrupt td's */
+
+static unsigned long framelist[1024] __attribute__ ((aligned (0x1000))); /* frame list */
+
+static struct virt_root_hub rh; /* struct for root hub */
+
+/**********************************************************************
+ * some forward decleration
+ */
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,struct devrequest *setup);
+
+/* fill a td with the approproiate data. Link, status, info and buffer
+ * are used by the USB controller itselfes, dev is used to identify the
+ * "connected" device
+ */
+void usb_fill_td(uhci_td_t* td,unsigned long link,unsigned long status,
+ unsigned long info, unsigned long buffer, unsigned long dev)
+{
+ td->link=swap_32(link);
+ td->status=swap_32(status);
+ td->info=swap_32(info);
+ td->buffer=swap_32(buffer);
+ td->dev_ptr=dev;
+}
+
+/* fill a qh with the approproiate data. Head and element are used by the USB controller
+ * itselfes. As soon as a valid dev_ptr is filled, a td chain is connected to the qh.
+ * Please note, that after completion of the td chain, the entry element is removed /
+ * marked invalid by the USB controller.
+ */
+void usb_fill_qh(uhci_qh_t* qh,unsigned long head,unsigned long element)
+{
+ qh->head=swap_32(head);
+ qh->element=swap_32(element);
+ qh->dev_ptr=0L;
+}
+
+/* get the status of a td->status
+ */
+unsigned long usb_uhci_td_stat(unsigned long status)
+{
+ unsigned long result=0;
+ result |= (status & TD_CTRL_NAK) ? USB_ST_NAK_REC : 0;
+ result |= (status & TD_CTRL_STALLED) ? USB_ST_STALLED : 0;
+ result |= (status & TD_CTRL_DBUFERR) ? USB_ST_BUF_ERR : 0;
+ result |= (status & TD_CTRL_BABBLE) ? USB_ST_BABBLE_DET : 0;
+ result |= (status & TD_CTRL_CRCTIMEO) ? USB_ST_CRC_ERR : 0;
+ result |= (status & TD_CTRL_BITSTUFF) ? USB_ST_BIT_ERR : 0;
+ result |= (status & TD_CTRL_ACTIVE) ? USB_ST_NOT_PROC : 0;
+ return result;
+}
+
+/* get the status and the transfered len of a td chain.
+ * called from the completion handler
+ */
+int usb_get_td_status(uhci_td_t *td,struct usb_device *dev)
+{
+ unsigned long temp,info;
+ unsigned long stat;
+ uhci_td_t *mytd=td;
+
+ if(dev->devnum==rh.devnum)
+ return 0;
+ dev->act_len=0;
+ stat=0;
+ do {
+ temp=swap_32((unsigned long)mytd->status);
+ stat=usb_uhci_td_stat(temp);
+ info=swap_32((unsigned long)mytd->info);
+ if(((info & 0xff)!= USB_PID_SETUP) &&
+ (((info >> 21) & 0x7ff)!= 0x7ff) &&
+ (temp & 0x7FF)!=0x7ff)
+ { /* if not setup and not null data pack */
+ dev->act_len+=(temp & 0x7FF) + 1; /* the transfered len is act_len + 1 */
+ }
+ if(stat) { /* status no ok */
+ dev->status=stat;
+ return -1;
+ }
+ temp=swap_32((unsigned long)mytd->link);
+ mytd=(uhci_td_t *)(temp & 0xfffffff0);
+ }while((temp & 0x1)==0); /* process all TDs */
+ dev->status=stat;
+ return 0; /* Ok */
+}
+
+
+/*-------------------------------------------------------------------
+ * LOW LEVEL STUFF
+ * assembles QHs und TDs for control, bulk and iso
+ *-------------------------------------------------------------------*/
+
+/* Submits a control message. That is a Setup, Data and Status transfer.
+ * Routine does not wait for completion.
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len,struct devrequest *setup)
+{
+ unsigned long destination, status;
+ int maxsze = usb_maxpacket(dev, pipe);
+ unsigned long dataptr;
+ int len;
+ int pktsze;
+ int i=0;
+
+ if (!maxsze) {
+ USB_UHCI_PRINTF("uhci_submit_control_urb: pipesize for pipe %lx is zero\n", pipe);
+ return -1;
+ }
+ if(((pipe>>8)&0x7f)==rh.devnum) {
+ /* this is the root hub -> redirect it */
+ return uhci_submit_rh_msg(dev,pipe,buffer,transfer_len,setup);
+ }
+ USB_UHCI_PRINTF("uhci_submit_control start len %x, maxsize %x\n",transfer_len,maxsze);
+ /* The "pipe" thing contains the destination in bits 8--18 */
+ destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* Setup stage */
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD); */
+ /* Build the TD for the control request, try forever, 8 bytes of data */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM ,status, destination | (7 << 21),(unsigned long)setup,(unsigned long)dev);
+#if 0
+ {
+ char *sp=(char *)setup;
+ printf("SETUP to pipe %lx: %x %x %x %x %x %x %x %x\n", pipe,
+ sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+ }
+#endif
+ dataptr = (unsigned long)buffer;
+ len=transfer_len;
+
+ /* If direction is "send", change the frame from SETUP (0x2D)
+ to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+ destination = (pipe & PIPE_DEVEP_MASK) | ((pipe & USB_DIR_IN)==0 ? USB_PID_OUT : USB_PID_IN);
+ while (len > 0) {
+ /* data stage */
+ pktsze = len;
+ i++;
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+ destination ^= 1 << TD_TOKEN_TOGGLE; /* toggle DATA0/1 */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, destination | ((pktsze - 1) << 21),dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+
+ dataptr += pktsze;
+ len -= pktsze;
+ }
+
+ /* Build the final TD for control status */
+ /* It's only IN if the pipe is out AND we aren't expecting data */
+
+ destination &= ~UHCI_PID;
+ if (((pipe & USB_DIR_IN)==0) || (transfer_len == 0))
+ destination |= USB_PID_IN;
+ else
+ destination |= USB_PID_OUT;
+ destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */
+ i++;
+ status &=~TD_CTRL_SPD;
+ /* no limit on errors on final packet , 0 bytes of data */
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),0,(unsigned long)dev);
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]); /* queue status td */
+ /* usb_show_td(i+1);*/
+ USB_UHCI_PRINTF("uhci_submit_control end (%d tmp_tds used)\n",i);
+ /* first mark the control QH element terminated */
+ qh_cntrl.element=0xffffffffL;
+ /* set qh active */
+ qh_cntrl.dev_ptr=(unsigned long)dev;
+ /* fill in tmp_td_chain */
+ qh_cntrl.element=swap_32((unsigned long)&tmp_td[0]);
+ return 0;
+}
+
+/*-------------------------------------------------------------------
+ * Prepare TDs for bulk transfers.
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len)
+{
+ unsigned long destination, status,info;
+ unsigned long dataptr;
+ int maxsze = usb_maxpacket(dev, pipe);
+ int len;
+ int i=0;
+
+ if(transfer_len < 0) {
+ printf("Negative transfer length in submit_bulk\n");
+ return -1;
+ }
+ if (!maxsze)
+ return -1;
+ /* The "pipe" thing contains the destination in bits 8--18. */
+ destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+ /* 3 errors */
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ /* ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); */
+ /* Build the TDs for the bulk request */
+ len = transfer_len;
+ dataptr = (unsigned long)buffer;
+ do {
+ int pktsze = len;
+ if (pktsze > maxsze)
+ pktsze = maxsze;
+ /* pktsze bytes of data */
+ info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+ (usb_gettoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+ if((len-pktsze)==0)
+ status |= TD_CTRL_IOC; /* last one generates INT */
+
+ usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, info,dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */
+ if(i>0)
+ tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]);
+ i++;
+ dataptr += pktsze;
+ len -= pktsze;
+ usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+ } while (len > 0);
+ /* first mark the bulk QH element terminated */
+ qh_bulk.element=0xffffffffL;
+ /* set qh active */
+ qh_bulk.dev_ptr=(unsigned long)dev;
+ /* fill in tmp_td_chain */
+ qh_bulk.element=swap_32((unsigned long)&tmp_td[0]);
+ return 0;
+}
+
+
+/* search a free interrupt td
+ */
+uhci_td_t *uhci_alloc_int_td(void)
+{
+ int i;
+ for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+ if(tmp_int_td[i].dev_ptr==0) /* no device assigned -> free TD */
+ return &tmp_int_td[i];
+ }
+ return NULL;
+}
+
+#if 0
+void uhci_show_temp_int_td(void)
+{
+ int i;
+ for(i=0;i<USB_MAX_TEMP_INT_TD;i++) {
+ if((tmp_int_td[i].dev_ptr&0x01)!=0x1L) /* no device assigned -> free TD */
+ printf("temp_td %d is assigned to dev %lx\n",i,tmp_int_td[i].dev_ptr);
+ }
+ printf("all others temp_tds are free\n");
+}
+#endif
+/*-------------------------------------------------------------------
+ * submits USB interrupt (ie. polling ;-)
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, int interval)
+{
+ int nint, n;
+ unsigned long status, destination;
+ unsigned long info,tmp;
+ uhci_td_t *mytd;
+ if (interval < 0 || interval >= 256)
+ return -1;
+
+ if (interval == 0)
+ nint = 0;
+ else {
+ for (nint = 0, n = 1; nint <= 8; nint++, n += n) /* round interval down to 2^n */
+ {
+ if(interval < n) {
+ interval = n / 2;
+ break;
+ }
+ }
+ nint--;
+ }
+
+ USB_UHCI_PRINTF("Rounded interval to %i, chain %i\n", interval, nint);
+ mytd=uhci_alloc_int_td();
+ if(mytd==NULL) {
+ printf("No free INT TDs found\n");
+ return -1;
+ }
+ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27);
+/* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+*/
+
+ destination =(pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe) | (((transfer_len - 1) & 0x7ff) << 21);
+
+ info = destination | (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
+ tmp = swap_32(td_int[nint].link);
+ usb_fill_td(mytd,tmp,status, info,(unsigned long)buffer,(unsigned long)dev);
+ /* Link it */
+ tmp = swap_32((unsigned long)mytd);
+ td_int[nint].link=tmp;
+
+ usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+ return 0;
+}
+
+/**********************************************************************
+ * Low Level functions
+ */
+
+
+void reset_hc(void)
+{
+
+ /* Global reset for 100ms */
+ out16r( usb_base_addr + USBPORTSC1,0x0204);
+ out16r( usb_base_addr + USBPORTSC2,0x0204);
+ out16r( usb_base_addr + USBCMD,USBCMD_GRESET | USBCMD_RS);
+ /* Turn off all interrupts */
+ out16r(usb_base_addr + USBINTR,0);
+ wait_ms(50);
+ out16r( usb_base_addr + USBCMD,0);
+ wait_ms(10);
+}
+
+void start_hc(void)
+{
+ int timeout = 1000;
+
+ while(in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) {
+ if (!--timeout) {
+ printf("USBCMD_HCRESET timed out!\n");
+ break;
+ }
+ }
+ /* Turn on all interrupts */
+ out16r(usb_base_addr + USBINTR,USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
+ /* Start at frame 0 */
+ out16r(usb_base_addr + USBFRNUM,0);
+ /* set Framebuffer base address */
+ out32r(usb_base_addr+USBFLBASEADD,(unsigned long)&framelist);
+ /* Run and mark it configured with a 64-byte max packet */
+ out16r(usb_base_addr + USBCMD,USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
+}
+
+/* Initialize the skeleton
+ */
+void usb_init_skel(void)
+{
+ unsigned long temp;
+ int n;
+
+ for(n=0;n<USB_MAX_TEMP_INT_TD;n++)
+ tmp_int_td[n].dev_ptr=0L; /* no devices connected */
+ /* last td */
+ usb_fill_td(&td_last,UHCI_PTR_TERM,TD_CTRL_IOC ,0,0,0L);
+ /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */
+ /* End Queue Header */
+ usb_fill_qh(&qh_end,UHCI_PTR_TERM,(unsigned long)&td_last);
+ /* Bulk Queue Header */
+ temp=(unsigned long)&qh_end;
+ usb_fill_qh(&qh_bulk,temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+ /* Control Queue Header */
+ temp=(unsigned long)&qh_bulk;
+ usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH,UHCI_PTR_TERM);
+ /* 1ms Interrupt td */
+ temp=(unsigned long)&qh_cntrl;
+ usb_fill_td(&td_int[0],temp | UHCI_PTR_QH,0,0,0,0L);
+ temp=(unsigned long)&td_int[0];
+ for(n=1; n<8; n++)
+ usb_fill_td(&td_int[n],temp,0,0,0,0L);
+ for (n = 0; n < 1024; n++) {
+ /* link all framelist pointers to one of the interrupts */
+ int m, o;
+ if ((n&127)==127)
+ framelist[n]= swap_32((unsigned long)&td_int[0]);
+ else
+ for (o = 1, m = 2; m <= 128; o++, m += m)
+ if ((n & (m - 1)) == ((m - 1) / 2))
+ framelist[n]= swap_32((unsigned long)&td_int[o]);
+ }
+}
+
+/* check the common skeleton for completed transfers, and update the status
+ * of the "connected" device. Called from the IRQ routine.
+ */
+void usb_check_skel(void)
+{
+ struct usb_device *dev;
+ /* start with the control qh */
+ if(qh_cntrl.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+ {
+ dev=(struct usb_device *)qh_cntrl.dev_ptr;
+ usb_get_td_status(&tmp_td[0],dev); /* update status */
+ if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+ qh_cntrl.dev_ptr=0;
+ }
+ }
+ /* now process the bulk */
+ if(qh_bulk.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */
+ {
+ dev=(struct usb_device *)qh_bulk.dev_ptr;
+ usb_get_td_status(&tmp_td[0],dev); /* update status */
+ if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */
+ qh_bulk.dev_ptr=0;
+ }
+ }
+}
+
+/* check the interrupt chain, ubdate the status of the appropriate device,
+ * call the appropriate irqhandler and reactivate the TD if the irqhandler
+ * returns with 1
+ */
+void usb_check_int_chain(void)
+{
+ int i,res;
+ unsigned long link,status;
+ struct usb_device *dev;
+ uhci_td_t *td,*prevtd;
+
+ for(i=0;i<8;i++) {
+ prevtd=&td_int[i]; /* the first previous td is the skeleton td */
+ link=swap_32(td_int[i].link) & 0xfffffff0; /* next in chain */
+ td=(uhci_td_t *)link; /* assign it */
+ /* all interrupt TDs are finally linked to the td_int[0].
+ * so we process all until we find the td_int[0].
+ * if int0 chain points to a QH, we're also done
+ */
+ while(((i>0) && (link != (unsigned long)&td_int[0])) ||
+ ((i==0) && !(swap_32(td->link) & UHCI_PTR_QH)))
+ {
+ /* check if a device is assigned with this td */
+ status=swap_32(td->status);
+ if((td->dev_ptr!=0L) && !(status & TD_CTRL_ACTIVE)) {
+ /* td is not active and a device is assigned -> call irqhandler */
+ dev=(struct usb_device *)td->dev_ptr;
+ dev->irq_act_len=((status & 0x7FF)==0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */
+ dev->irq_status=usb_uhci_td_stat(status); /* get status */
+ res=dev->irq_handle(dev); /* call irqhandler */
+ if(res==1) {
+ /* reactivate */
+ status|=TD_CTRL_ACTIVE;
+ td->status=swap_32(status);
+ prevtd=td; /* previous td = this td */
+ }
+ else {
+ prevtd->link=td->link; /* link previous td directly to the nex td -> unlinked */
+ /* remove device pointer */
+ td->dev_ptr=0L;
+ }
+ } /* if we call the irq handler */
+ link=swap_32(td->link) & 0xfffffff0; /* next in chain */
+ td=(uhci_td_t *)link; /* assign it */
+ } /* process all td in this int chain */
+ } /* next interrupt chain */
+}
+
+
+/* usb interrupt service routine.
+ */
+void handle_usb_interrupt(void)
+{
+ unsigned short status;
+
+ /*
+ * Read the interrupt status, and write it back to clear the
+ * interrupt cause
+ */
+
+ status = in16r(usb_base_addr + USBSTS);
+
+ if (!status) /* shared interrupt, not mine */
+ return;
+ if (status != 1) {
+ /* remove host controller halted state */
+ if ((status&0x20) && ((in16r(usb_base_addr+USBCMD) && USBCMD_RS)==0)) {
+ out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD));
+ }
+ }
+ usb_check_int_chain(); /* call interrupt handlers for int tds */
+ usb_check_skel(); /* call completion handler for common transfer routines */
+ out16r(usb_base_addr+USBSTS,status);
+}
+
+
+/* init uhci
+ */
+int usb_lowlevel_init(void)
+{
+ unsigned char temp;
+ int busdevfunc;
+
+ busdevfunc=pci_find_device(USB_UHCI_VEND_ID,USB_UHCI_DEV_ID,0); /* get PCI Device ID */
+ if(busdevfunc==-1) {
+ printf("Error USB UHCI (%04X,%04X) not found\n",USB_UHCI_VEND_ID,USB_UHCI_DEV_ID);
+ return -1;
+ }
+ pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp);
+ irqvec = temp;
+ irq_free_handler(irqvec);
+ USB_UHCI_PRINTF("Interrupt Line = %d, is %d\n",irqvec);
+ pci_read_config_byte(busdevfunc,PCI_INTERRUPT_PIN,&temp);
+ USB_UHCI_PRINTF("Interrupt Pin = %ld\n",temp);
+ pci_read_config_dword(busdevfunc,PCI_BASE_ADDRESS_4,&usb_base_addr);
+ USB_UHCI_PRINTF("IO Base Address = 0x%lx\n",usb_base_addr);
+ usb_base_addr&=0xFFFFFFF0;
+ usb_base_addr+=CFG_ISA_IO_BASE_ADDRESS;
+ rh.devnum = 0;
+ usb_init_skel();
+ reset_hc();
+ start_hc();
+ irq_install_handler(irqvec, (interrupt_handler_t *)handle_usb_interrupt, NULL);
+ return 0;
+}
+
+/* stop uhci
+ */
+int usb_lowlevel_stop(void)
+{
+ if(irqvec==-1)
+ return 1;
+ irq_free_handler(irqvec);
+ reset_hc();
+ irqvec=-1;
+ return 0;
+}
+
+/*******************************************************************************************
+ * Virtual Root Hub
+ * Since the uhci does not have a real HUB, we simulate one ;-)
+ */
+#undef USB_RH_DEBUG
+
+#ifdef USB_RH_DEBUG
+#define USB_RH_PRINTF(fmt,args...) printf (fmt ,##args)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex);
+static void usb_display_Req(unsigned short req);
+#else
+#define USB_RH_PRINTF(fmt,args...)
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex) {}
+static void usb_display_Req(unsigned short req) {}
+#endif
+
+static unsigned char root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, /* __u16 bcdUSB; v1.0 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x01, /* __u8 iManufacturer; */
+ 0x00, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static unsigned char root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+
+static unsigned char root_hub_hub_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00,
+ 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'U', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+
+/*
+ * Root Hub Control Pipe (interrupt Pipes are not supported)
+ */
+
+
+int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len,struct devrequest *cmd)
+{
+ void *data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int status = 0;
+ int stat = 0;
+ int i;
+
+ unsigned short cstatus;
+
+ unsigned short bmRType_bReq;
+ unsigned short wValue;
+ unsigned short wIndex;
+ unsigned short wLength;
+
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ printf("Root-Hub submit IRQ: NOT implemented\n");
+#if 0
+ uhci->rh.urb = urb;
+ uhci->rh.send = 1;
+ uhci->rh.interval = urb->interval;
+ rh_init_int_timer (urb);
+#endif
+ return 0;
+ }
+ bmRType_bReq = cmd->requesttype | cmd->request << 8;
+ wValue = swap_16(cmd->value);
+ wIndex = swap_16(cmd->index);
+ wLength = swap_16(cmd->length);
+ usb_display_Req(bmRType_bReq);
+ for (i = 0; i < 8; i++)
+ rh.c_p_r[i] = 0;
+ USB_RH_PRINTF("Root-Hub: adr: %2x cmd(%1x): %02x%02x %04x %04x %04x\n",
+ dev->devnum, 8, cmd->requesttype,cmd->request, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(unsigned short *) data = swap_16(1);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(unsigned short *) data = swap_16(0);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(unsigned short *) data = swap_16(0);
+ len=2;
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ *(unsigned long *) data = swap_32(0);
+ len=4;
+ break; /* hub power ** */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+
+ status = in16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1));
+ cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+ ((status & USBPORTSC_PEC) >> (3 - 1)) |
+ (rh.c_p_r[wIndex - 1] << (0 + 4));
+ status = (status & USBPORTSC_CCS) |
+ ((status & USBPORTSC_PE) >> (2 - 1)) |
+ ((status & USBPORTSC_SUSP) >> (12 - 2)) |
+ ((status & USBPORTSC_PR) >> (9 - 4)) |
+ (1 << 8) | /* power on ** */
+ ((status & USBPORTSC_LSDA) << (-8 + 9));
+
+ *(unsigned short *) data = swap_16(status);
+ *(unsigned short *) (data + 2) = swap_16(cstatus);
+ len=4;
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL):
+ len=0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case (RH_C_HUB_OVER_CURRENT):
+ len=0; /* hub power over current ** */
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ usb_display_wValue(wValue,wIndex);
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) & ~USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_SUSPEND):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) & ~USBPORTSC_SUSP;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_POWER):
+ len=0; /* port power ** */
+ break;
+ case (RH_C_PORT_CONNECTION):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_CSC;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_C_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PEC;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+ len=0;
+ break;
+ case (RH_C_PORT_OVER_CURRENT):
+ len=0;
+ break;
+ case (RH_C_PORT_RESET):
+ rh.c_p_r[wIndex - 1] = 0;
+ len=0;
+ break;
+ }
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ usb_display_wValue(wValue,wIndex);
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_SUSP;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_RESET):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PR;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ wait_ms(10);
+ status = (status & 0xfff5) & ~USBPORTSC_PR;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ udelay(10);
+ status = (status & 0xfff5) | USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ wait_ms(10);
+ status = (status & 0xfff5) | 0xa;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ case (RH_PORT_POWER):
+ len=0; /* port power ** */
+ break;
+ case (RH_PORT_ENABLE):
+ status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1));
+ status = (status & 0xfff5) | USBPORTSC_PE;
+ out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status);
+ len=0;
+ break;
+ }
+ break;
+
+ case RH_SET_ADDRESS:
+ rh.devnum = wValue;
+ len=0;
+ break;
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ i=sizeof(root_hub_config_des);
+ status=i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_dev_des, len);
+ break;
+ case (0x02): /* configuration descriptor */
+ i=sizeof(root_hub_config_des);
+ status=i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_config_des, len);
+ break;
+ case (0x03): /*string descriptors */
+ if(wValue==0x0300) {
+ i=sizeof(root_hub_str_index0);
+ status = i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_str_index0, len);
+ break;
+ }
+ if(wValue==0x0301) {
+ i=sizeof(root_hub_str_index1);
+ status = i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_str_index1, len);
+ break;
+ }
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ root_hub_hub_des[2] = 2;
+ i=sizeof(root_hub_hub_des);
+ status= i > wLength ? wLength : i;
+ len = leni > status ? status : leni;
+ memcpy (data, root_hub_hub_des, len);
+ break;
+ case RH_GET_CONFIGURATION:
+ *(unsigned char *) data = 0x01;
+ len = 1;
+ break;
+ case RH_SET_CONFIGURATION:
+ len=0;
+ break;
+ default:
+ stat = USB_ST_STALLED;
+ }
+ USB_RH_PRINTF("Root-Hub stat %lx port1: %x port2: %x\n\n",stat,
+ in16r(usb_base_addr + USBPORTSC1), in16r(usb_base_addr + USBPORTSC2));
+ dev->act_len=len;
+ dev->status=stat;
+ return stat;
+
+}
+
+/********************************************************************************
+ * Some Debug Routines
+ */
+
+#ifdef USB_RH_DEBUG
+
+static void usb_display_Req(unsigned short req)
+{
+ USB_RH_PRINTF("- Root-Hub Request: ");
+ switch (req) {
+ case RH_GET_STATUS:
+ USB_RH_PRINTF("Get Status ");
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ USB_RH_PRINTF("Get Status Interface ");
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ USB_RH_PRINTF("Get Status Endpoint ");
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ USB_RH_PRINTF("Get Status Class");
+ break; /* hub power ** */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Get Status Class Others");
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ USB_RH_PRINTF("Clear Feature Endpoint ");
+ break;
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ USB_RH_PRINTF("Clear Feature Class ");
+ break;
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Clear Feature Other Class ");
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ USB_RH_PRINTF("Set Feature Other Class ");
+ break;
+ case RH_SET_ADDRESS:
+ USB_RH_PRINTF("Set Address ");
+ break;
+ case RH_GET_DESCRIPTOR:
+ USB_RH_PRINTF("Get Descriptor ");
+ break;
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ USB_RH_PRINTF("Get Descriptor Class ");
+ break;
+ case RH_GET_CONFIGURATION:
+ USB_RH_PRINTF("Get Configuration ");
+ break;
+ case RH_SET_CONFIGURATION:
+ USB_RH_PRINTF("Get Configuration ");
+ break;
+ default:
+ USB_RH_PRINTF("****UNKNOWN**** 0x%04X ",req);
+ }
+ USB_RH_PRINTF("\n");
+
+}
+
+static void usb_display_wValue(unsigned short wValue,unsigned short wIndex)
+{
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ USB_RH_PRINTF("Root-Hub: Enable Port %d\n",wIndex);
+ break;
+ case (RH_PORT_SUSPEND):
+ USB_RH_PRINTF("Root-Hub: Suspend Port %d\n",wIndex);
+ break;
+ case (RH_PORT_POWER):
+ USB_RH_PRINTF("Root-Hub: Port Power %d\n",wIndex);
+ break;
+ case (RH_C_PORT_CONNECTION):
+ USB_RH_PRINTF("Root-Hub: C Port Connection Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_ENABLE):
+ USB_RH_PRINTF("Root-Hub: C Port Enable Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_SUSPEND):
+ USB_RH_PRINTF("Root-Hub: C Port Suspend Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_OVER_CURRENT):
+ USB_RH_PRINTF("Root-Hub: C Port Over Current Port %d\n",wIndex);
+ break;
+ case (RH_C_PORT_RESET):
+ USB_RH_PRINTF("Root-Hub: C Port reset Port %d\n",wIndex);
+ break;
+ default:
+ USB_RH_PRINTF("Root-Hub: unknown %x %x\n",wValue,wIndex);
+ break;
+ }
+}
+
+#endif
+
+
+
+#ifdef USB_UHCI_DEBUG
+
+static int usb_display_td(uhci_td_t *td)
+{
+ unsigned long tmp;
+ int valid;
+
+ printf("TD at %p:\n",td);
+
+ tmp=swap_32(td->link);
+ printf("Link points to 0x%08lX, %s first, %s, %s\n",tmp&0xfffffff0,
+ ((tmp & 0x4)==0x4) ? "Depth" : "Breath",
+ ((tmp & 0x2)==0x2) ? "QH" : "TD",
+ ((tmp & 0x1)==0x1) ? "invalid" : "valid");
+ valid=((tmp & 0x1)==0x0);
+ tmp=swap_32(td->status);
+ printf(" %s %ld Errors %s %s %s \n %s %s %s %s %s %s\n Len 0x%lX\n",
+ (((tmp>>29)&0x1)==0x1) ? "SPD Enable" : "SPD Disable",
+ ((tmp>>28)&0x3),
+ (((tmp>>26)&0x1)==0x1) ? "Low Speed" : "Full Speed",
+ (((tmp>>25)&0x1)==0x1) ? "ISO " : "",
+ (((tmp>>24)&0x1)==0x1) ? "IOC " : "",
+ (((tmp>>23)&0x1)==0x1) ? "Active " : "Inactive ",
+ (((tmp>>22)&0x1)==0x1) ? "Stalled" : "",
+ (((tmp>>21)&0x1)==0x1) ? "Data Buffer Error" : "",
+ (((tmp>>20)&0x1)==0x1) ? "Babble" : "",
+ (((tmp>>19)&0x1)==0x1) ? "NAK" : "",
+ (((tmp>>18)&0x1)==0x1) ? "Bitstuff Error" : "",
+ (tmp&0x7ff));
+ tmp=swap_32(td->info);
+ printf(" MaxLen 0x%lX\n",((tmp>>21)&0x7FF));
+ printf(" %s Endpoint 0x%lX Dev Addr 0x%lX PID 0x%lX\n",((tmp>>19)&0x1)==0x1 ? "TOGGLE" : "",
+ ((tmp>>15)&0xF),((tmp>>8)&0x7F),tmp&0xFF);
+ tmp=swap_32(td->buffer);
+ printf(" Buffer 0x%08lX\n",tmp);
+ printf(" DEV %08lX\n",td->dev_ptr);
+ return valid;
+}
+
+
+void usb_show_td(int max)
+{
+ int i;
+ if(max>0) {
+ for(i=0;i<max;i++) {
+ usb_display_td(&tmp_td[i]);
+ }
+ }
+ else {
+ i=0;
+ do {
+ printf("tmp_td[%d]\n",i);
+ }while(usb_display_td(&tmp_td[i++]));
+ }
+}
+
+
+#endif
+#endif /* CONFIG_USB_UHCI */
+
+/* EOF */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_char *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, uchar *dest, uchar data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+
+
+/*
+ * don't ask. its stupid, but more than one soul has had to live with this mistake
+ * "swaptab[i]" is the value of "i" with the bits reversed.
+ */
+
+#define MUSENKI_BROKEN_FLASH 1
+
+#ifdef MUSENKI_BROKEN_FLASH
+unsigned char swaptab[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+#define BS(b) (swaptab[b])
+
+#else
+
+#define BS(b) (b)
+
+#endif
+
+#define BYTEME(x) ((x) & 0xFF)
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",CFG_FLASH_BASE0_PRELIM);
+
+ size_b0 = flash_get_size((vu_char *)CFG_FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0: "
+ "ID 0x%lx, Size = 0x%08lx = %ld MB\n",
+ flash_info[0].flash_id,
+ size_b0, size_b0<<20);
+ }
+
+ DEBUGF("## Get flash bank 2 size @ 0x%08x\n",CFG_FLASH_BASE1_PRELIM);
+ size_b1 = flash_get_size((vu_char *)CFG_FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ DEBUGF("protect monitor %x @ %x\n", CFG_MONITOR_BASE, CFG_MONITOR_LEN);
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ DEBUGF("protect environtment %x @ %x\n", CFG_ENV_ADDR, CFG_ENV_SECT_SIZE);
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ flash_info[1].size = size_b1;
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[1]);
+#endif
+ } else {
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ flash_info[1].size = 0;
+ }
+
+ DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL:
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base;
+ base += 0x00020000; /* 128k per bank */
+ }
+ return;
+
+ default:
+ printf ("Don't know sector ofsets for flash type 0x%lx\n", info->flash_id);
+ return;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("Fujitsu "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ case FLASH_MAN_INTEL: printf ("Intel "); break;
+ case FLASH_MAN_MT: printf ("MT "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F320J3A: printf ("28F320J3A (32Mbit = 128K x 32)\n");
+ break;
+ case FLASH_28F640J3A: printf ("28F640J3A (64Mbit = 128K x 64)\n");
+ break;
+ case FLASH_28F128J3A: printf ("28F128J3A (128Mbit = 128K x 128)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size >= (1 << 20)) {
+ i = 20;
+ } else {
+ i = 10;
+ }
+ printf (" Size: %ld %cB in %d Sectors\n",
+ info->size >> i,
+ (i == 20) ? 'M' : 'k',
+ info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (vu_char *addr, flash_info_t *info)
+{
+ vu_char manuf, device;
+
+ addr[0] = BS(0x90);
+ manuf = BS(addr[0]);
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (vu_char *)addr, manuf);
+
+ switch (manuf) {
+ case BYTEME(AMD_MANUFACT):
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case BYTEME(FUJ_MANUFACT):
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case BYTEME(SST_MANUFACT):
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case BYTEME(STM_MANUFACT):
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ case BYTEME(INTEL_MANUFACT):
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ addr[0] = BS(0xFF); /* restore read mode, (yes, BS is a NOP) */
+ return 0; /* no or unknown flash */
+ }
+
+ device = BS(addr[2]); /* device ID */
+
+ DEBUGF("Device ID @ 0x%08x: 0x%08x\n", (&addr[1]), device);
+
+ switch (device) {
+ case BYTEME(INTEL_ID_28F320J3A):
+ info->flash_id += FLASH_28F320J3A;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case BYTEME(INTEL_ID_28F640J3A):
+ info->flash_id += FLASH_28F640J3A;
+ info->sector_count = 64;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case BYTEME(INTEL_ID_28F128J3A):
+ info->flash_id += FLASH_28F128J3A;
+ info->sector_count = 128;
+ info->size = 0x01000000;
+ break; /* => 16 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ addr[0] = BS(0xFF); /* restore read mode (yes, a NOP) */
+ return 0; /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ addr[0] = BS(0xFF); /* restore read mode */
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) {
+ printf ("Can erase only Intel flash types - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n", prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ vu_char *addr = (vu_char *)(info->start[sect]);
+ unsigned long status;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = BS(0x50); /* clear status register */
+ *addr = BS(0x20); /* erase setup */
+ *addr = BS(0xD0); /* erase confirm */
+
+ /* re-enable interrupts if necessary */
+ if (flag) {
+ enable_interrupts();
+ }
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = BS(0xB0); /* suspend erase */
+ *addr = BS(0xFF); /* reset to read mode */
+ return 1;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ *addr = BS(0xFF); /* reset to read mode */
+ }
+ }
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+#define FLASH_WIDTH 1 /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ uchar *wp = (uchar *)addr;
+ int rc;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+
+ while (cnt > 0) {
+ if ((rc = write_data(info, wp, *src)) != 0) {
+ return rc;
+ }
+ wp++;
+ src++;
+ cnt--;
+ }
+
+ return cnt;
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, uchar *dest, uchar data)
+{
+ vu_char *addr = (vu_char *)dest;
+ ulong status;
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((BS(*addr) & data) != data) {
+ return 2;
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = BS(0x40); /* write setup */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag) {
+ enable_interrupts();
+ }
+
+ start = get_timer (0);
+
+ while (((status = BS(*addr)) & BYTEME(0x00800080)) != BYTEME(0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *addr = BS(0xFF); /* restore read mode */
+ return 1;
+ }
+ }
+
+ *addr = BS(0xFF); /* restore read mode */
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+extern u_long *my_sernum; /* from nx823.c */
+
+/*-----------------------------------------------------------------------
+ * Protection Flags:
+ */
+#define FLAG_PROTECT_SET 0x01
+#define FLAG_PROTECT_CLEAR 0x02
+
+/* Board support for 1 or 2 flash devices */
+#undef FLASH_PORT_WIDTH32
+#define FLASH_PORT_WIDTH16
+
+#ifdef FLASH_PORT_WIDTH16
+#define FLASH_PORT_WIDTH ushort
+#define FLASH_PORT_WIDTHV vu_short
+#else
+#define FLASH_PORT_WIDTH ulong
+#define FLASH_PORT_WIDTHV vu_long
+#endif
+
+#define FPW FLASH_PORT_WIDTH
+#define FPWV FLASH_PORT_WIDTHV
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (FPW *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, FPW data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+ size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_FLASH_BASE,
+ CFG_FLASH_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F320J3A:
+ printf ("28F320J3A\n"); break;
+ case FLASH_28F640J3A:
+ printf ("28F640J3A\n"); break;
+ case FLASH_28F128J3A:
+ printf ("28F128J3A\n"); break;
+ default: printf ("Unknown Chip Type\n"); break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (FPW *addr, flash_info_t *info)
+{
+ FPW value;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x5555] = (FPW)0x00AA00AA;
+ addr[0x2AAA] = (FPW)0x00550055;
+ addr[0x5555] = (FPW)0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case (FPW)INTEL_MANUFACT:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ addr[0] = (FPW)0x00FF00FF; /* restore read mode */
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case (FPW)INTEL_ID_28F320J3A:
+ info->flash_id += FLASH_28F320J3A;
+ info->sector_count = 32;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (FPW)INTEL_ID_28F640J3A:
+ info->flash_id += FLASH_28F640J3A;
+ info->sector_count = 64;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case (FPW)INTEL_ID_28F128J3A:
+ info->flash_id += FLASH_28F128J3A;
+ info->sector_count = 128;
+ info->size = 0x01000000;
+ break; /* => 16 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ break;
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ addr[0] = (FPW)0x00FF00FF; /* restore read mode */
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect;
+ ulong type, start, now, last;
+ int rcode = 0;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ type = (info->flash_id & FLASH_VENDMASK);
+ if ((type != FLASH_MAN_INTEL)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer (0);
+ last = start;
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ FPWV *addr = (FPWV *)(info->start[sect]);
+ FPW status;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = (FPW)0x00500050; /* clear status register */
+ *addr = (FPW)0x00200020; /* erase setup */
+ *addr = (FPW)0x00D000D0; /* erase confirm */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
+ if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ *addr = (FPW)0x00B000B0; /* suspend erase */
+ *addr = (FPW)0x00FF00FF; /* reset to read mode */
+ rcode = 1;
+ break;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ *addr = (FPW)0x00FF00FF; /* reset to read mode */
+ printf (" done\n");
+ }
+ }
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ * 4 - Flash not identified
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp;
+ FPW data;
+ int count, i, l, rc, port_width;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return 4;
+ }
+/* get lower word aligned address */
+#ifdef FLASH_PORT_WIDTH16
+ wp = (addr & ~1);
+ port_width = 2;
+#else
+ wp = (addr & ~3);
+ port_width = 4;
+#endif
+
+ /* save sernum if needed */
+ if (addr >= CFG_FLASH_SN_SECTOR && addr < CFG_FLASH_SN_BASE)
+ {
+ u_long dest = CFG_FLASH_SN_BASE;
+ u_short *sn = (u_short *)my_sernum;
+
+ printf("(saving sernum)");
+ for (i=0; i<4; i++)
+ {
+ if ((rc = write_data(info, dest, sn[i])) != 0) {
+ return (rc);
+ }
+ dest += port_width;
+ }
+ }
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<port_width && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<port_width; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += port_width;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ count = 0;
+ while (cnt >= port_width) {
+ data = 0;
+ for (i=0; i<port_width; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += port_width;
+ cnt -= port_width;
+ if (count++ > 0x800)
+ {
+ putc('.');
+ count = 0;
+ }
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<port_width; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word or halfword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, FPW data)
+{
+ FPWV *addr = (FPWV *)dest;
+ ulong status;
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*addr & data) != data) {
+ printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *addr = (FPW)0x00400040; /* write setup */
+ *addr = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *addr = (FPW)0x00FF00FF; /* restore read mode */
+ return (1);
+ }
+ }
+
+ *addr = (FPW)0x00FF00FF; /* restore read mode */
+
+ return (0);
+}
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <flash.h>
+#include <asm/io.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+static ulong flash_get_size (ulong addr, flash_info_t *info);
+static int flash_get_offsets (ulong base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (ulong addr);
+
+unsigned long flash_init (void)
+{
+ unsigned int i;
+ unsigned long flash_size = 0;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+ DEBUGF("\n## Get flash size @ 0x%08x\n", CFG_FLASH_BASE);
+
+ flash_size = flash_get_size (CFG_FLASH_BASE, flash_info);
+
+ DEBUGF("## Flash bank size: %08lx\n", flash_size);
+
+ if (flash_size) {
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
+ CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+ &flash_info[0]);
+#endif
+
+ } else {
+ puts ("Warning: the BOOT Flash is not initialised !");
+ }
+
+ return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (ulong addr, flash_info_t *info)
+{
+ short i;
+ uchar value;
+
+ /* Write auto select command: read Manufacturer ID */
+ out8(addr + 0x0555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x02AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x0555, 0x90);
+ iobarrier_rw();
+
+ value = in8(addr);
+ iobarrier_rw();
+
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
+
+ switch (value | (value << 16)) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ case STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ flash_reset (addr);
+ return 0;
+ }
+
+ value = in8(addr + 1); /* device ID */
+ iobarrier_rw();
+
+ DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
+
+ switch (value) {
+ case AMD_ID_F040B:
+ DEBUGF("Am29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV040B:
+ DEBUGF("Am29LV040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV400T:
+ DEBUGF("Am29LV400T\n");
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ DEBUGF("Am29LV800T\n");
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ DEBUGF("Am29LV160T\n");
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ DEBUGF("Am29LV160B\n");
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV320T:
+ DEBUGF("Am29LV320T\n");
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+#if 0
+ /* Has the same ID as AMD_ID_LV320T, to be fixed */
+ case AMD_ID_LV320B:
+ DEBUGF("Am29LV320B\n");
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+
+ case AMD_ID_LV033C:
+ DEBUGF("Am29LV033C\n");
+ info->flash_id += FLASH_AM033C;
+ info->sector_count = 64;
+ info->size = 0x01000000;
+ break; /* => 16Mb */
+
+ case STM_ID_F040B:
+ DEBUGF("M29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ flash_reset (addr);
+ return (0); /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ if (! flash_get_offsets (addr, info)) {
+ flash_reset (addr);
+ return 0;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ value = in8(info->start[i] + 2);
+ iobarrier_rw();
+ info->protect[i] = (value & 1) != 0;
+ }
+
+ /*
+ * Reset bank to read mode
+ */
+ flash_reset (addr);
+
+ return (info->size);
+}
+
+static int flash_get_offsets (ulong base, flash_info_t *info)
+{
+ unsigned int i;
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + i * info->size /
+ info->sector_count;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile ulong addr = info->start[0];
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if (s_first < 0 || s_first > s_last) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0x80);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = info->start[sect];
+ out8(addr, 0x30);
+ iobarrier_rw();
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = info->start[l_sect];
+
+ DEBUGF ("Start erase timeout: %d\n", CFG_FLASH_ERASE_TOUT);
+
+ while ((in8(addr) & 0x80) != 0x80) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ flash_reset (info->start[0]);
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ iobarrier_rw();
+ }
+
+DONE:
+ /* reset to read mode */
+ flash_reset (info->start[0]);
+
+ printf (" done\n");
+ return 0;
+}
+
+/*
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ volatile ulong addr = info->start[0];
+ ulong start;
+ int i;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((in32(dest) & data) != data) {
+ return (2);
+ }
+
+ /* write each byte out */
+ for (i = 0; i < 4; i++) {
+ char *data_ch = (char *)&data;
+ int flag = disable_interrupts();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xA0);
+ iobarrier_rw();
+ out8(dest+i, data_ch[i]);
+ iobarrier_rw();
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ flash_reset (addr);
+ return (1);
+ }
+ iobarrier_rw();
+ }
+ }
+
+ flash_reset (addr);
+ return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (ulong addr)
+{
+ out8(addr, 0xF0); /* reset bank */
+ iobarrier_rw();
+}
+
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ case FLASH_MAN_STM: printf ("SGS THOMSON "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size % 0x100000 == 0) {
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size / 0x100000, info->sector_count);
+ } else if (info->size % 0x400 == 0) {
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size / 0x400, info->sector_count);
+ } else {
+ printf (" Size: %ld B in %d Sectors\n",
+ info->size, info->sector_count);
+ }
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
--- /dev/null
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _PCIPPC2_H_
+#define _PCIPPC2_H_
+
+#include <config.h>
+#include <common.h>
+
+#include "hardware.h"
+
+#define FPGA(r, p) (pcippc2_fpga0_phys + HW_FPGA0_##r##_##p)
+#define UART(r) (pcippc2_fpga0_phys + HW_FPGA0_UART1 + NS16550_##r * 4)
+#define RTC(r) (pcippc2_fpga1_phys + HW_FPGA1_RTC + r)
+
+extern u32 pcippc2_fpga0_phys;
+extern u32 pcippc2_fpga1_phys;
+
+extern u32 pcippc2_sdram_size (void);
+
+extern void pcippc2_fpga_init (void);
+
+extern void cpc710_pci_init (void);
+extern void cpc710_pci_enable_timeout (void);
+
+extern unsigned long
+ cpc710_ram_init (void);
+
+#endif
--- /dev/null
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+
+#include "pci.h"
+
+#include "hardware.h"
+#include "pcippc2.h"
+
+u32 pcippc2_fpga0_phys;
+u32 pcippc2_fpga1_phys;
+
+void pcippc2_fpga_init (void)
+{
+ pci_dev_t bdf = pci_find_device(FPGA_VENDOR_ID, FPGA_DEVICE_ID, 0);
+ unsigned int addr;
+ u16 cmd;
+
+ if (bdf == -1)
+ {
+ puts("Unable to find FPGA !\n");
+ hang();
+ }
+
+ pci_read_config_word(bdf, PCI_COMMAND, &cmd);
+ if ((cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) != (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))
+ {
+ puts("FPGA is not configured !\n");
+ hang();
+ }
+
+ pci_read_config_dword(bdf, PCI_BASE_ADDRESS_0, &addr);
+ if (addr & 0x1)
+ {
+ /* IO space
+ */
+ pcippc2_fpga0_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
+ }
+ else
+ {
+ /* Memory space
+ */
+ pcippc2_fpga0_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
+ }
+
+ pci_read_config_dword(bdf, PCI_BASE_ADDRESS_1, &addr);
+ if (addr & 0x1)
+ {
+ /* IO space
+ */
+ pcippc2_fpga1_phys = pci_io_to_phys(bdf, addr & 0xfffffffc);
+ }
+ else
+ {
+ /* Memory space
+ */
+ pcippc2_fpga1_phys = pci_mem_to_phys(bdf, addr & 0xfffffff0);
+ }
+
+ /* Interrupts are not used
+ */
+ out32(FPGA(INT, INTR_MASK), 0xffffffff);
+ iobarrier_rw();
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD 29F080B devices
+ * Added support for 64bit and AMD 29DL323B
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/io.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+#define RD_SWP32(x) in_le32((volatile u32*)x)
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ unsigned long size;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* for now, only support the 4 MB Flash SIMM */
+ size = flash_get_size((vu_long *)CFG_FLASH0_BASE, &flash_info[0]);
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[0]);
+#endif
+
+ return /*size*/ (CFG_FLASH0_SIZE * 1024 * 1024);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case (AMD_MANUFACT & FLASH_VENDMASK):
+ printf ("AMD ");
+ break;
+ case (FUJ_MANUFACT & FLASH_VENDMASK):
+ printf ("FUJITSU ");
+ break;
+ case (SST_MANUFACT & FLASH_VENDMASK):
+ printf ("SST ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case (AMD_ID_DL323B & FLASH_TYPEMASK):
+ printf("AM29DL323B (32 MBit)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; ++i) {
+ if ((i % 5) == 0) printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ vu_long vendor[2], devid[2];
+ ulong base = (ulong)addr;
+
+ /* Reset and Write auto select command: read Manufacturer ID */
+ addr[0] = 0xf0f0f0f0;
+ addr[2 * 0x0555] = 0xAAAAAAAA;
+ addr[2 * 0x02AA] = 0x55555555;
+ addr[2 * 0x0555] = 0x90909090;
+ addr[1] = 0xf0f0f0f0;
+ addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+ addr[2 * 0x02AA + 1] = 0x55555555;
+ addr[2 * 0x0555 + 1] = 0x90909090;
+ udelay (1000);
+
+ vendor[0] = RD_SWP32(&addr[0]);
+ vendor[1] = RD_SWP32(&addr[1]);
+ if (vendor[0] != vendor[1] || vendor[0] != AMD_MANUFACT) {
+ info->size = 0;
+ goto out;
+ }
+
+ devid[0] = RD_SWP32(&addr[2]);
+ devid[1] = RD_SWP32(&addr[3]);
+
+ if (devid[0] == AMD_ID_DL323B) {
+ /*
+ * we have 2 Banks
+ * Bank 1 (23 Sectors): 0-7=8kbyte, 8-22=64kbyte
+ * Bank 2 (48 Sectors): 23-70=64kbyte
+ */
+ info->flash_id = (AMD_MANUFACT & FLASH_VENDMASK) |
+ (AMD_ID_DL323B & FLASH_TYPEMASK);
+ info->sector_count = 71;
+ info->size = 4 * (8 * 8 + 63 * 64) * 1024;
+ }
+ else {
+ info->size = 0;
+ goto out;
+ }
+
+ /* set up sector start address table */
+ for (i = 0; i < 8; i++) {
+ info->start[i] = base + (i * 0x8000);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x40000) + 8 * 0x8000 - 8 * 0x40000;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address */
+ addr = (volatile unsigned long *)(info->start[i]);
+ addr[2 * 0x0555] = 0xAAAAAAAA;
+ addr[2 * 0x02AA] = 0x55555555;
+ addr[2 * 0x0555] = 0x90909090;
+ addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+ addr[2 * 0x02AA + 1] = 0x55555555;
+ addr[2 * 0x0555 + 1] = 0x90909090;
+ udelay (1000);
+ base = RD_SWP32(&addr[4]);
+ base |= RD_SWP32(&addr[5]);
+ info->protect[i] = base & 0x00010001 ? 1 : 0;
+ }
+ addr = (vu_long*)info->start[0];
+
+out:
+ /* reset command */
+ addr[0] = 0xf0f0f0f0;
+ addr[1] = 0xf0f0f0f0;
+
+ return info->size;
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[2 * 0x0555] = 0xAAAAAAAA;
+ addr[2 * 0x02AA] = 0x55555555;
+ addr[2 * 0x0555] = 0x80808080;
+ addr[2 * 0x0555] = 0xAAAAAAAA;
+ addr[2 * 0x02AA] = 0x55555555;
+ addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+ addr[2 * 0x02AA + 1] = 0x55555555;
+ addr[2 * 0x0555 + 1] = 0x80808080;
+ addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+ addr[2 * 0x02AA + 1] = 0x55555555;
+ udelay (100);
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x30303030;
+ addr[1] = 0x30303030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ( (addr[0] & 0x80808080) != 0x80808080 ||
+ (addr[1] & 0x80808080) != 0x80808080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0xF0F0F0F0; /* reset bank */
+ addr[1] = 0xF0F0F0F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ if ((dest & 0x00000004) == 0) {
+ addr[2 * 0x0555] = 0xAAAAAAAA;
+ addr[2 * 0x02AA] = 0x55555555;
+ addr[2 * 0x0555] = 0xA0A0A0A0;
+ }
+ else {
+ addr[2 * 0x0555 + 1] = 0xAAAAAAAA;
+ addr[2 * 0x02AA + 1] = 0x55555555;
+ addr[2 * 0x0555 + 1] = 0xA0A0A0A0;
+ }
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+#include <common.h>
+#include <mii_phy.h>
+#include "rpxsuper.h"
+
+#define MII_MDIO 0x01
+#define MII_MDCK 0x02
+#define MII_MDIR 0x04
+
+void
+mii_discover_phy(void)
+{
+ int known;
+ unsigned short phy_reg;
+ unsigned long phy_id;
+
+ known = 0;
+ printf("Discovering phy @ 0: ");
+ phy_id = mii_phy_read(2) << 16;
+ phy_id |= mii_phy_read(3);
+ if ((phy_id & 0xFFFFFC00) == 0x00137800) {
+ printf("Level One ");
+ if ((phy_id & 0x000003F0) == 0xE0) {
+ printf("LXT971A Revision %d\n", (int)(phy_id & 0xF));
+ known = 1;
+ }
+ else printf("unknown type\n");
+ }
+ else printf("unknown OUI = 0x%08lX\n", phy_id);
+
+ phy_reg = mii_phy_read(1);
+ if (!(phy_reg & 0x0004)) printf("Link is down\n");
+ if (!(phy_reg & 0x0020)) printf("Auto-negotiation not complete\n");
+ if (phy_reg & 0x0002) printf("Jabber condition detected\n");
+ if (phy_reg & 0x0010) printf("Remote fault condition detected \n");
+
+ if (known) {
+ phy_reg = mii_phy_read(17);
+ if (phy_reg & 0x0400)
+ printf("Phy operating at %d MBit/s in %s-duplex mode\n",
+ phy_reg & 0x4000 ? 100 : 10,
+ phy_reg & 0x0200 ? "full" : "half");
+ else
+ printf("bad link!!\n");
+/*
+left off: no link, green 100MBit, yellow 10MBit
+right off: no activity, green full-duplex, yellow half-duplex
+*/
+ mii_phy_write(20, 0x0452);
+ }
+}
+
+unsigned short
+mii_phy_read(unsigned short reg)
+{
+ int i;
+ unsigned short tmp, val = 0, adr = 0;
+ t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
+
+ tmp = 0x6002 | (adr << 7) | (reg << 2);
+ regs->bcsr4 = 0xC3;
+ for (i = 0; i < 64; i++) {
+ regs->bcsr4 ^= MII_MDCK;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ tmp <<= 1;
+ }
+ regs->bcsr4 |= MII_MDIR;
+ for (i = 0; i < 16; i++) {
+ val <<= 1;
+ regs->bcsr4 = MII_MDIO | (regs->bcsr4 | MII_MDCK);
+ if (regs->bcsr4 & MII_MDIO) val |= 1;
+ regs->bcsr4 = MII_MDIO | (regs->bcsr4 &= ~MII_MDCK);
+ }
+ return val;
+}
+
+void
+mii_phy_write(unsigned short reg, unsigned short val)
+{
+ int i;
+ unsigned short tmp, adr = 0;
+ t_rpx_regs *regs = (t_rpx_regs*)CFG_REGS_BASE;
+
+ tmp = 0x5002 | (adr << 7) | (reg << 2);
+ regs->bcsr4 = 0xC3;
+ for (i = 0; i < 64; i++) {
+ regs->bcsr4 ^= MII_MDCK;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (tmp & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ tmp <<= 1;
+ }
+ for (i = 0; i < 16; i++) {
+ regs->bcsr4 &= ~MII_MDCK;
+ if (val & 0x8000) regs->bcsr4 |= MII_MDIO;
+ else regs->bcsr4 &= ~MII_MDIO;
+ regs->bcsr4 |= MII_MDCK;
+ val <<= 1;
+ }
+}
+
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AM290[48]0B devices
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+/* flash hardware ids */
+#define VENDOR_AMD 0x0001
+#define AMD_29DL323C_B 0x2253
+
+/* Define this to include autoselect sequence in flash_init(). Does NOT
+ * work when executing from flash itself, so this should be turned
+ * on only when debugging the RAM version.
+ */
+#undef WITH_AUTOSELECT
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if 1
+#define D(x)
+#else
+#define D(x) printf x
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+static unsigned char write_ull(flash_info_t *info,
+ unsigned long address,
+ volatile unsigned long long data);
+
+/* from flash_asm.S */
+extern void ull_write(unsigned long long volatile *address,
+ unsigned long long volatile *data);
+extern void ull_read(unsigned long long volatile *address,
+ unsigned long long volatile *data);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ int i;
+ ulong addr;
+
+#ifdef WITH_AUTOSELECT
+ {
+ unsigned long long *f_addr = (unsigned long long *)PHYS_FLASH;
+ unsigned long long f_command, vendor, device;
+ /* Perform Autoselect */
+ f_command = 0x00AA00AA00AA00AAULL;
+ ull_write(&f_addr[0x555], &f_command);
+ f_command = 0x0055005500550055ULL;
+ ull_write(&f_addr[0x2AA], &f_command);
+ f_command = 0x0090009000900090ULL;
+ ull_write(&f_addr[0x555], &f_command);
+ ull_read(&f_addr[0], &vendor);
+ vendor &= 0xffff;
+ ull_read(&f_addr[1], &device);
+ device &= 0xffff;
+ f_command = 0x00F000F000F000F0ULL;
+ ull_write(&f_addr[0x555], &f_command);
+ if (vendor != VENDOR_AMD || device != AMD_29DL323C_B)
+ return 0;
+ }
+#endif
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* 1st bank: 8 x 32 KB sectors */
+ flash_info[0].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
+ flash_info[0].sector_count = 8;
+ flash_info[0].size = flash_info[0].sector_count * 32 * 1024;
+ addr = PHYS_FLASH;
+ for(i = 0; i < flash_info[0].sector_count; i++) {
+ flash_info[0].start[i] = addr;
+ addr += flash_info[0].size / flash_info[0].sector_count;
+ }
+ /* 1st bank: 63 x 256 KB sectors */
+ flash_info[1].flash_id = VENDOR_AMD << 16 | AMD_29DL323C_B;
+ flash_info[1].sector_count = 63;
+ flash_info[1].size = flash_info[1].sector_count * 256 * 1024;
+ for(i = 0; i < flash_info[1].sector_count; i++) {
+ flash_info[1].start[i] = addr;
+ addr += flash_info[1].size / flash_info[1].sector_count;
+ }
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE >= PHYS_FLASH
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[0]);
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
+ &flash_info[1]);
+#endif
+
+ return flash_info[0].size + flash_info[1].size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id >> 16) {
+ case VENDOR_AMD:
+ printf ("AMD ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case AMD_29DL323C_B:
+ printf ("AM29DL323CB (32 Mbit)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ int flag, prot, sect, l_sect;
+ ulong start;
+ unsigned long long volatile *f_addr;
+ unsigned long long volatile f_command;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ f_addr = (unsigned long long *)info->start[0];
+ f_command = 0x00AA00AA00AA00AAULL;
+ ull_write(&f_addr[0x555], &f_command);
+ f_command = 0x0055005500550055ULL;
+ ull_write(&f_addr[0x2AA], &f_command);
+ f_command = 0x0080008000800080ULL;
+ ull_write(&f_addr[0x555], &f_command);
+ f_command = 0x00AA00AA00AA00AAULL;
+ ull_write(&f_addr[0x555], &f_command);
+ f_command = 0x0055005500550055ULL;
+ ull_write(&f_addr[0x2AA], &f_command);
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Start erase on unprotected sectors */
+ for (l_sect = -1, sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+
+ f_addr =
+ (unsigned long long *)(info->start[sect]);
+ f_command = 0x0030003000300030ULL;
+ ull_write(f_addr, &f_command);
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+ do
+ {
+ if (get_timer(start) > CFG_FLASH_ERASE_TOUT)
+ { /* write reset command, command address is unimportant */
+ /* this command turns the flash back to read mode */
+ f_addr =
+ (unsigned long long *)(info->start[l_sect]);
+ f_command = 0x00F000F000F000F0ULL;
+ ull_write(f_addr, &f_command);
+ printf (" timeout\n");
+ return 1;
+ }
+ } while(*f_addr != 0xFFFFFFFFFFFFFFFFULL);
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ unsigned long cp, wp;
+ unsigned long long data;
+ int i, l, rc;
+
+ wp = (addr & ~7); /* get lower long long aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<8 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<8; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_ull(info, wp, data)) != 0) {
+ return rc;
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle long long aligned part
+ */
+ while (cnt >= 8) {
+ data = 0;
+ for (i=0; i<8; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_ull(info, wp, data)) != 0) {
+ return rc;
+ }
+ wp += 8;
+ cnt -= 8;
+ }
+
+ if (cnt == 0) {
+ return ERR_OK;
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<8 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<8; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return write_ull(info, wp, data);
+}
+
+/*---------------------------------------------------------------------------
+*
+* FUNCTION NAME: write_ull
+*
+* DESCRIPTION: writes 8 bytes to flash
+*
+* EXTERNAL EFFECT: nothing
+*
+* PARAMETERS: 32 bit long pointer to address, 64 bit long pointer to data
+*
+* RETURNS: 0 if OK, 1 if timeout, 4 if parameter error
+*--------------------------------------------------------------------------*/
+
+static unsigned char write_ull(flash_info_t *info,
+ unsigned long address,
+ volatile unsigned long long data)
+{
+ static unsigned long long f_command;
+ static unsigned long long *f_addr;
+ ulong start;
+
+ /* address muss be 8-aligned! */
+ if (address & 0x7)
+ return ERR_ALIGN;
+
+ f_addr = (unsigned long long *)info->start[0];
+ f_command = 0x00AA00AA00AA00AAULL;
+ ull_write(&f_addr[0x555], &f_command);
+ f_command = 0x0055005500550055ULL;
+ ull_write(&f_addr[0x2AA], &f_command);
+ f_command = 0x00A000A000A000A0ULL;
+ ull_write(&f_addr[0x555], &f_command);
+
+ f_addr = (unsigned long long *)address;
+ f_command = data;
+ ull_write(f_addr, &f_command);
+
+ start = get_timer (0);
+ do
+ {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT)
+ {
+ /* write reset command, command address is unimportant */
+ /* this command turns the flash back to read mode */
+ f_addr = (unsigned long long *)info->start[0];
+ f_command = 0x00F000F000F000F0ULL;
+ ull_write(f_addr, &f_command);
+ return ERR_TIMOUT;
+ }
+ } while(*((unsigned long long *)address) != data);
+
+ return 0;
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+ memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+#endif
+ } else {
+ memctl->memc_br1 = 0; /* invalidate bank */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+ flash_info[0].size = size_b0;
+ flash_info[1].size = size_b1;
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#include "atm.h"
+#include <linux/stddef.h>
+
+#define SYNC __asm__("sync")
+#define ALIGN(p, a) ((char *)(((uint32)(p)+(a)-1) & ~((uint32)(a)-1)))
+
+#define FALSE 1
+#define TRUE 0
+#define OK 0
+#define ERROR -1
+
+struct atm_connection_t g_conn[NUM_CONNECTIONS] =
+{
+ { NULL, 10, NULL, 10, NULL, NULL, NULL, NULL }, /* OAM */
+};
+
+struct atm_driver_t g_atm =
+{
+ FALSE, /* loaded */
+ FALSE, /* started */
+ NULL, /* csram */
+ 0, /* csram_size */
+ NULL, /* am_top */
+ NULL, /* ap_top */
+ NULL, /* int_reload_ptr */
+ NULL, /* int_serv_ptr */
+ NULL, /* rbd_base_ptr */
+ NULL, /* tbd_base_ptr */
+ 0 /* linerate */
+};
+
+char csram[1024]; /* more than enough for doing nothing*/
+
+int atmLoad(void);
+void atmUnload(void);
+int atmMemInit(void);
+void atmIntInit(void);
+void atmApcInit(void);
+void atmAmtInit(void);
+void atmCpmInit(void);
+void atmUtpInit(void);
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmLoad
+ *
+ * DESCRIPTION: Basic ATM initialization.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmLoad()
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+ volatile iop8xx_t *iop = &immap->im_ioport;
+
+ timers->cpmt_tgcr &= 0x0FFF; SYNC; /* Disable Timer 4 */
+ immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
+ iop->iop_pdpar &= 0x3FFF; SYNC; /* Disable SAR and UTOPIA */
+
+ if ( atmMemInit() != OK ) return ERROR;
+
+ atmIntInit();
+ atmApcInit();
+ atmAmtInit();
+ atmCpmInit();
+ atmUtpInit();
+
+ g_atm.loaded = TRUE;
+
+ return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUnload
+ *
+ * DESCRIPTION: Disables ATM and UTOPIA.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmUnload()
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile cpmtimer8xx_t *timers = &immap->im_cpmtimer;
+ volatile iop8xx_t *iop = &immap->im_ioport;
+
+ timers->cpmt_tgcr &= 0x0FFF; SYNC; /* Disable Timer 4 */
+ immap->im_cpm.cp_scc[4].scc_gsmrl = 0x0; SYNC; /* Disable SCC4 */
+ iop->iop_pdpar &= 0x3FFF; SYNC; /* Disable SAR and UTOPIA */
+ g_atm.loaded = FALSE;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmMemInit
+ *
+ * DESCRIPTION:
+ *
+ * The ATM driver uses the following resources:
+ *
+ * A. Memory in DPRAM to hold
+ *
+ * 1/ CT = Connection Table ( RCT & TCT )
+ * 2/ TCTE = Transmit Connection Table Extension
+ * 3/ MPHYPT = Multi-PHY Pointing Table
+ * 4/ APCP = APC Parameter Table
+ * 5/ APCT_PRIO_1 = APC Table ( priority 1 for AAL1/2 )
+ * 6/ APCT_PRIO_2 = APC Table ( priority 2 for VBR )
+ * 7/ APCT_PRIO_3 = APC Table ( priority 3 for UBR )
+ * 8/ TQ = Transmit Queue
+ * 9/ AM = Address Matching Table
+ * 10/ AP = Address Pointing Table
+ *
+ * B. Memory in cache safe RAM to hold
+ *
+ * 1/ INT = Interrupt Queue
+ * 2/ RBD = Receive Buffer Descriptors
+ * 3/ TBD = Transmit Buffer Descriptors
+ *
+ * This function
+ * 1. clears the ATM DPRAM area,
+ * 2. Allocates and clears cache safe memory,
+ * 3. Initializes 'g_conn'.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: OK or ERROR
+ *
+ ****************************************************************************/
+int atmMemInit()
+{
+ int i;
+ unsigned immr = CFG_IMMR;
+ int total_num_rbd = 0;
+ int total_num_tbd = 0;
+
+ memset((char *)CFG_IMMR + 0x2000 + ATM_DPRAM_BEGIN, 0x00, ATM_DPRAM_SIZE);
+
+ g_atm.csram_size = NUM_INT_ENTRIES * SIZE_OF_INT_ENTRY;
+
+ for ( i = 0; i < NUM_CONNECTIONS; ++i ) {
+ total_num_rbd += g_conn[i].num_rbd;
+ total_num_tbd += g_conn[i].num_tbd;
+ }
+
+ g_atm.csram_size += total_num_rbd * SIZE_OF_RBD + total_num_tbd * SIZE_OF_TBD + 4;
+
+ g_atm.csram = &csram[0];
+ memset(&(g_atm.csram), 0x00, g_atm.csram_size);
+
+ g_atm.int_reload_ptr = (uint32 *)ALIGN(g_atm.csram, 4);
+ g_atm.rbd_base_ptr = (struct atm_bd_t *)(g_atm.int_reload_ptr + NUM_INT_ENTRIES);
+ g_atm.tbd_base_ptr = (struct atm_bd_t *)(g_atm.rbd_base_ptr + total_num_rbd);
+
+ g_conn[0].rbd_ptr = g_atm.rbd_base_ptr;
+ g_conn[0].tbd_ptr = g_atm.tbd_base_ptr;
+ g_conn[0].ct_ptr = CT_PTR(immr);
+ g_conn[0].tcte_ptr = TCTE_PTR(immr);
+
+ return OK;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmIntInit
+ *
+ * DESCRIPTION:
+ *
+ * Initialization of the MPC860 ESAR Interrupt Queue.
+ * This function
+ * - clears all entries in the INT,
+ * - sets the WRAP bit of the last INT entry,
+ * - initializes the 'int_serv_ptr' attribuut of the AtmDriver structure
+ * to the first INT entry.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * - The INT resides in external cache safe memory.
+ * - The base address of the INT is stored in g_atm.int_reload_ptr.
+ * - The number of entries in the INT is given by NUM_INT_ENTRIES.
+ * - The INTBASE field in SAR Parameter RAM is set by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmIntInit()
+{
+ int i;
+ for ( i = 0; i < NUM_INT_ENTRIES - 1; ++i) g_atm.int_reload_ptr[i] = 0;
+ g_atm.int_reload_ptr[i] = INT_WRAP;
+ g_atm.int_serv_ptr = g_atm.int_reload_ptr;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmApcInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the following ATM Pace Controller related
+ * data structures:
+ *
+ * - 1 MPHY Pointing Table (contains only one entry)
+ * - 3 APC Parameter Tables (one PHY with 3 priorities)
+ * - 3 APC Tables (one table for each priority)
+ * - 1 Transmit Queue (one transmit queue per PHY)
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmApcInit()
+{
+ int i;
+ /* unsigned immr = CFG_IMMR; */
+ uint16 * mphypt_ptr = MPHYPT_PTR(CFG_IMMR);
+ struct apc_params_t * apcp_ptr = APCP_PTR(CFG_IMMR);
+ uint16 * apct_prio1_ptr = APCT1_PTR(CFG_IMMR);
+ uint16 * tq_ptr = TQ_PTR(CFG_IMMR);
+ /***************************************************/
+ /* Initialize MPHY Pointing Table (only one entry) */
+ /***************************************************/
+ *mphypt_ptr = APCP_BASE;
+
+ /********************************************/
+ /* Initialize APC parameters for priority 1 */
+ /********************************************/
+ apcp_ptr->apct_base1 = APCT_PRIO_1_BASE;
+ apcp_ptr->apct_end1 = APCT_PRIO_1_BASE + NUM_APCT_PRIO_1_ENTRIES * 2;
+ apcp_ptr->apct_ptr1 = APCT_PRIO_1_BASE;
+ apcp_ptr->apct_sptr1 = APCT_PRIO_1_BASE;
+ apcp_ptr->etqbase = TQ_BASE;
+ apcp_ptr->etqend = TQ_BASE + ( NUM_TQ_ENTRIES - 1 ) * 2;
+ apcp_ptr->etqaptr = TQ_BASE;
+ apcp_ptr->etqtptr = TQ_BASE;
+ apcp_ptr->apc_mi = 8;
+ apcp_ptr->ncits = 0x0100; /* NCITS = 1 */
+ apcp_ptr->apcnt = 0;
+ apcp_ptr->reserved1 = 0;
+ apcp_ptr->eapcst = 0x2009; /* LAST, ESAR, MPHY */
+ apcp_ptr->ptp_counter = 0;
+ apcp_ptr->ptp_txch = 0;
+ apcp_ptr->reserved2 = 0;
+
+
+ /***************************************************/
+ /* Initialize APC Tables with empty slots (0xFFFF) */
+ /***************************************************/
+ for ( i = 0; i < NUM_APCT_PRIO_1_ENTRIES; ++i ) *(apct_prio1_ptr++) = 0xFFFF;
+
+ /************************/
+ /* Clear Transmit Queue */
+ /************************/
+ for ( i = 0; i < NUM_TQ_ENTRIES; ++i ) *(tq_ptr++) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmAmtInit
+ *
+ * DESCRIPTION:
+ *
+ * This function clears the first entry in the Address Matching Table and
+ * lets the first entry in the Address Pointing table point to the first
+ * entry in the TCT table (i.e. the raw cell channel).
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARKS:
+ *
+ * The values for the AMBASE, AMEND and APBASE registers in SAR parameter
+ * RAM are initialized by atmCpmInit().
+ *
+ ****************************************************************************/
+void atmAmtInit()
+{
+ unsigned immr = CFG_IMMR;
+
+ g_atm.am_top = AM_PTR(immr);
+ g_atm.ap_top = AP_PTR(immr);
+
+ *(g_atm.ap_top--) = CT_BASE;
+ *(g_atm.am_top--) = 0;
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmCpmInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the Utopia Interface Parameter RAM Map
+ * (SCC4, ATM Protocol) of the Communication Processor Modudule.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ ****************************************************************************/
+void atmCpmInit()
+{
+ unsigned immr = CFG_IMMR;
+
+ memset((char *)immr + 0x3F00, 0x00, 0xC0);
+
+ /*-----------------------------------------------------------------*/
+ /* RBDBASE - Receive buffer descriptors base address */
+ /* The RBDs reside in cache safe external memory. */
+ /*-----------------------------------------------------------------*/
+ *RBDBASE(immr) = (uint32)g_atm.rbd_base_ptr;
+
+ /*-----------------------------------------------------------------*/
+ /* SRFCR - SAR receive function code */
+ /* 0-2 rsvd = 000 */
+ /* 3-4 BO = 11 Byte ordering (big endian). */
+ /* 5-7 FC = 000 Value driven on the address type signals AT[1-3] */
+ /* when the SDMA channel accesses memory. */
+ /*-----------------------------------------------------------------*/
+ *SRFCR(immr) = 0x18;
+
+ /*-----------------------------------------------------------------*/
+ /* SRSTATE - SAR receive status */
+ /* 0 EXT = 0 Extended mode off. */
+ /* 1 ACP = 0 Valid only if EXT = 1. */
+ /* 2 EC = 0 Standard 53-byte ATM cell. */
+ /* 3 SNC = 0 In sync. Must be set to 0 during initialization. */
+ /* 4 ESAR = 1 Enhanced SAR functionality enabled. */
+ /* 5 MCF = 1 Management Cell Filter active. */
+ /* 6 SER = 0 UTOPIA mode. */
+ /* 7 MPY = 1 Multiple PHY mode. */
+ /*-----------------------------------------------------------------*/
+ *SRSTATE(immr) = 0x0D;
+
+ /*-----------------------------------------------------------------*/
+ /* MRBLR - Maximum receive buffer length register. */
+ /* Must be cleared for ATM operation (see also SMRBLR). */
+ /*-----------------------------------------------------------------*/
+ *MRBLR(immr) = 0;
+
+ /*-----------------------------------------------------------------*/
+ /* RSTATE - SCC internal receive state parameters */
+ /* The first byte must be initialized with the value of SRFCR. */
+ /*-----------------------------------------------------------------*/
+ *RSTATE(immr) = (uint32)(*SRFCR(immr)) << 24;
+
+ /*-----------------------------------------------------------------*/
+ /* STFCR - SAR transmit function code */
+ /* 0-2 rsvd = 000 */
+ /* 3-4 BO = 11 Byte ordering (big endian). */
+ /* 5-7 FC = 000 Value driven on the address type signals AT[1-3] */
+ /* when the SDMA channel accesses memory. */
+ /*-----------------------------------------------------------------*/
+ *STFCR(immr) = 0x18;
+
+ /*-----------------------------------------------------------------*/
+ /* SRSTATE - SAR transmit status */
+ /* 0 EXT = 0 : Extended mode off */
+ /* 1 rsvd = 0 : */
+ /* 2 EC = 0 : Standard 53-byte ATM cell */
+ /* 3 rsvd = 0 : */
+ /* 4 ESAR = 1 : Enhanced SAR functionality enabled */
+ /* 5 rsvd = 0 : */
+ /* 6 SER = 0 : UTOPIA mode */
+ /* 7 MPY = 1 : Multiple PHY mode */
+ /*-----------------------------------------------------------------*/
+ *STSTATE(immr) = 0x09;
+
+ /*-----------------------------------------------------------------*/
+ /* TBDBASE - Transmit buffer descriptors base address */
+ /* The TBDs reside in cache safe external memory. */
+ /*-----------------------------------------------------------------*/
+ *TBDBASE(immr) = (uint32)g_atm.tbd_base_ptr;
+
+ /*-----------------------------------------------------------------*/
+ /* TSTATE - SCC internal transmit state parameters */
+ /* The first byte must be initialized with the value of STFCR. */
+ /*-----------------------------------------------------------------*/
+ *TSTATE(immr) = (uint32)(*STFCR(immr)) << 24;
+
+ /*-----------------------------------------------------------------*/
+ /* CTBASE - Connection table base address */
+ /* Offset from the beginning of DPRAM (64-byte aligned). */
+ /*-----------------------------------------------------------------*/
+ *CTBASE(immr) = CT_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* INTBASE - Interrupt queue base pointer. */
+ /* The interrupt queue resides in cache safe external memory. */
+ /*-----------------------------------------------------------------*/
+ *INTBASE(immr) = (uint32)g_atm.int_reload_ptr;
+
+ /*-----------------------------------------------------------------*/
+ /* INTPTR - Pointer into interrupt queue. */
+ /* Initialize to INTBASE. */
+ /*-----------------------------------------------------------------*/
+ *INTPTR(immr) = *INTBASE(immr);
+
+ /*-----------------------------------------------------------------*/
+ /* C_MASK - Constant mask for CRC32 */
+ /* Must be initialized to 0xDEBB20E3. */
+ /*-----------------------------------------------------------------*/
+ *C_MASK(immr) = 0xDEBB20E3;
+
+ /*-----------------------------------------------------------------*/
+ /* INT_ICNT - Interrupt threshold value */
+ /*-----------------------------------------------------------------*/
+ *INT_ICNT(immr) = 1;
+
+ /*-----------------------------------------------------------------*/
+ /* INT_CNT - Interrupt counter */
+ /* Initalize to INT_ICNT. Decremented for each interrupt entry */
+ /* reported in the interrupt queue. On zero an interrupt is */
+ /* signaled to the host by setting the GINT bit in the event */
+ /* register. The counter is reinitialized with INT_ICNT. */
+ /*-----------------------------------------------------------------*/
+ *INT_CNT(immr) = *INT_ICNT(immr);
+
+ /*-----------------------------------------------------------------*/
+ /* SMRBLR - SAR maximum receive buffer length register. */
+ /* Must be a multiple of 48 bytes. Common for all ATM connections. */
+ /*-----------------------------------------------------------------*/
+ *SMRBLR(immr) = SAR_RXB_SIZE;
+
+ /*-----------------------------------------------------------------*/
+ /* APCST - APC status register. */
+ /* 0 rsvd 0 */
+ /* 1-2 CSER 11 Initialize with the same value as NSER. */
+ /* 3-4 NSER 11 Next serial or UTOPIA channel. */
+ /* 5-7 rsvd 000 */
+ /* 8-10 rsvd 000 */
+ /* 11 rsvd 0 */
+ /* 12 ESAR 1 UTOPIA Level 2 MPHY enabled. */
+ /* 13 DIS 0 APC disable. Must be initiazed to 0. */
+ /* 14 PL2 0 Not used. */
+ /* 15 MPY 1 Multiple PHY mode on. */
+ /*-----------------------------------------------------------------*/
+ *APCST(immr) = 0x7809;
+
+ /*-----------------------------------------------------------------*/
+ /* APCPTR - Pointer to the APC parameter table */
+ /* In MPHY master mode this parameter points to the MPHY pointing */
+ /* table. 2-byte aligned. */
+ /*-----------------------------------------------------------------*/
+ *APCPTR(immr) = MPHYPT_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* HMASK - Header mask */
+ /* Each incoming cell is masked with HMASK before being compared */
+ /* to the entries in the address matching table. */
+ /*-----------------------------------------------------------------*/
+ *HMASK(immr) = AM_HMASK;
+
+ /*-----------------------------------------------------------------*/
+ /* AMBASE - Address matching table base address */
+ /*-----------------------------------------------------------------*/
+ *AMBASE(immr) = AM_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* AMEND - Address matching table end address */
+ /*-----------------------------------------------------------------*/
+ *AMEND(immr) = AM_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* APBASE - Address pointing table base address */
+ /*-----------------------------------------------------------------*/
+ *APBASE(immr) = AP_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* MPHYST - MPHY status register */
+ /* 0-1 rsvd 00 */
+ /* 2-6 NMPHY 00000 1 PHY */
+ /* 7-9 rsvd 000 */
+ /* 10-14 CMPHY 00000 Initialize with same value as NMPHY */
+ /*-----------------------------------------------------------------*/
+ *MPHYST(immr) = 0x0000;
+
+ /*-----------------------------------------------------------------*/
+ /* TCTEBASE - Transmit connection table extension base address */
+ /* Offset from the beginning of DPRAM (32-byte aligned). */
+ /*-----------------------------------------------------------------*/
+ *TCTEBASE(immr) = TCTE_BASE;
+
+ /*-----------------------------------------------------------------*/
+ /* Clear not used registers. */
+ /*-----------------------------------------------------------------*/
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION NAME: atmUtpInit
+ *
+ * DESCRIPTION:
+ *
+ * This function initializes the ATM interface for
+ *
+ * - UTOPIA mode
+ * - muxed bus
+ * - master operation
+ * - multi PHY (because of a bug in the MPC860P rev. E.0)
+ * - internal clock = SYSCLK / 2
+ *
+ * EXTERNAL EFFECTS:
+ *
+ * After calling this function, the MPC860ESAR UTOPIA bus is
+ * active and uses the following ports/pins:
+ *
+ * Port Pin Signal Description
+ * ------ --- ------- -------------------------------------------
+ * PB[15] R17 TxClav Transmit cell available input/output signal
+ * PC[15] D16 RxClav Receive cell available input/output signal
+ * PD[15] U17 UTPB[0] UTOPIA bus bit 0 input/output signal
+ * PD[14] V19 UTPB[1] UTOPIA bus bit 1 input/output signal
+ * PD[13] V18 UTPB[2] UTOPIA bus bit 2 input/output signal
+ * PD[12] R16 UTPB[3] UTOPIA bus bit 3 input/output signal
+ * PD[11] T16 RXENB Receive enable input/output signal
+ * PD[10] W18 TXENB Transmit enable input/output signal
+ * PD[9] V17 UTPCLK UTOPIA clock input/output signal
+ * PD[7] T15 UTPB[4] UTOPIA bus bit 4 input/output signal
+ * PD[6] V16 UTPB[5] UTOPIA bus bit 5 input/output signal
+ * PD[5] U15 UTPB[6] UTOPIA bus bit 6 input/output signal
+ * PD[4] U16 UTPB[7] UTOPIA bus bit 7 input/output signal
+ * PD[3] W16 SOC Start of cell input/output signal
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS: void
+ *
+ * REMARK:
+ *
+ * The ATM parameters and data structures must be configured before
+ * initializing the UTOPIA port. The UTOPIA port activates immediately
+ * upon initialization, and if its associated data structures are not
+ * initialized, the CPM will lock up.
+ *
+ ****************************************************************************/
+void atmUtpInit()
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile iop8xx_t *iop = &immap->im_ioport;
+ volatile car8xx_t *car = &immap->im_clkrst;
+ volatile cpm8xx_t *cpm = &immap->im_cpm;
+ int flag;
+
+ flag = disable_interrupts();
+
+ /*-----------------------------------------------------------------*/
+ /* SCCR - System Clock Control Register */
+ /* */
+ /* The UTOPIA clock can be selected to be internal clock or */
+ /* external clock (selected by the UTOPIA mode register). */
+ /* In case of internal clock, the UTOPIA clock is derived from */
+ /* the system frequency divided by two dividers. */
+ /* Bits 27-31 of the SCCR register are defined to control the */
+ /* UTOPIA clock. */
+ /* */
+ /* SCCR[27:29] DFUTP Division factor. Divide the system clock */
+ /* by 2^DFUTP. */
+ /* SCCR[30:31] DFAUTP Additional division factor. Divide the */
+ /* system clock by the following value: */
+ /* 00 = divide by 1 */
+ /* 00 = divide by 3 */
+ /* 10 = divide by 5 */
+ /* 11 = divide by 7 */
+ /* */
+ /* Note that the UTOPIA clock must be programmed as to operate */
+ /* within the range SYSCLK/10 .. 50Mhz. */
+ /*-----------------------------------------------------------------*/
+ car->car_sccr &= 0xFFFFFFE0;
+ car->car_sccr |= 0x00000008; /* UTPCLK = SYSCLK / 4 */
+
+ /*-----------------------------------------------------------------*/
+ /* RCCR - RISC Controller Configuration Register */
+ /* */
+ /* RCCR[8] DR1M IDMA Request 0 Mode */
+ /* 0 = edge sensitive */
+ /* 1 = level sensitive */
+ /* RCCR[9] DR0M IDMA Request 0 Mode */
+ /* 0 = edge sensitive */
+ /* 1 = level sensitive */
+ /* RCCR[10:11] DRQP IDMA Request Priority */
+ /* 00 = IDMA req. have more prio. than SCCs */
+ /* 01 = IDMA req. have less prio. then SCCs */
+ /* 10 = IDMA requests have the lowest prio. */
+ /* 11 = reserved */
+ /* */
+ /* The RCCR[DR0M] and RCCR[DR1M] bits must be set to enable UTOPIA */
+ /* operation. Also, program RCCR[DPQP] to 01 to give SCC transfers */
+ /* higher priority. */
+ /*-----------------------------------------------------------------*/
+ cpm->cp_rccr &= 0xFF0F;
+ cpm->cp_rccr |= 0x00D0;
+
+ /*-----------------------------------------------------------------*/
+ /* Port B - TxClav Signal */
+ /*-----------------------------------------------------------------*/
+ cpm->cp_pbpar |= 0x00010000; /* PBPAR[15] = 1 */
+ cpm->cp_pbdir &= 0xFFFEFFFF; /* PBDIR[15] = 0 */
+
+ /*-----------------------------------------------------------------*/
+ /* UTOPIA Mode Register */
+ /* */
+ /* - muxed bus (master operation only) */
+ /* - multi PHY (because of a bug in the MPC860P rev.E.0) */
+ /* - internal clock */
+ /* - no loopback */
+ /* - do no activate statistical counters */
+ /*-----------------------------------------------------------------*/
+ iop->utmode = 0x00000004; SYNC;
+
+ /*-----------------------------------------------------------------*/
+ /* Port D - UTOPIA Data and Control Signals */
+ /* */
+ /* 15-12 UTPB[0:3] UTOPIA bus bit 0 - 3 input/output signals */
+ /* 11 RXENB UTOPIA receive enable input/output signal */
+ /* 10 TXENB UTOPIA transmit enable input/output signal */
+ /* 9 TUPCLK UTOPIA clock input/output signal */
+ /* 8 MII-MDC Used by MII in simult. MII and UTOPIA operation */
+ /* 7-4 UTPB[4:7] UTOPIA bus bit 4 - 7 input/output signals */
+ /* 3 SOC UTOPIA Start of cell input/output signal */
+ /* 2 Reserved */
+ /* 1 Enable UTOPIA mode */
+ /* 0 Enable SAR */
+ /*-----------------------------------------------------------------*/
+ iop->iop_pdpar |= 0xDF7F; SYNC;
+ iop->iop_pddir &= 0x2080; SYNC;
+
+ /*-----------------------------------------------------------------*/
+ /* Port C - RxClav Signal */
+ /*-----------------------------------------------------------------*/
+ iop->iop_pcpar |= 0x0001; /* PCPAR[15] = 1 */
+ iop->iop_pcdir &= 0xFFFE; /* PCDIR[15] = 0 */
+ iop->iop_pcso &= 0xFFFE; /* PCSO[15] = 0 */
+
+ if (flag)
+ enable_interrupts();
+}
--- /dev/null
+/*
+ * (C) Copyright 2000, 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size, size<<20);
+ }
+
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size & 0xFFFF8000);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+ /* Re-do sizing to get full correct info */
+ size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size;
+
+ return (size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ switch (value) {
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD devices on the TQM8260 board
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#define V_ULONG(a) (*(volatile unsigned long *)( a ))
+#define V_BYTE(a) (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset (void)
+{
+ if (flash_info[0].flash_id != FLASH_UNKNOWN) {
+ V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
+ V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size (ulong baseaddr, flash_info_t * info)
+{
+ short i;
+ unsigned long flashtest_h, flashtest_l;
+
+ /* Write auto select command sequence and test FLASH answer */
+ V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
+ V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
+
+ flashtest_h = V_ULONG (baseaddr); /* manufacturer ID */
+ flashtest_l = V_ULONG (baseaddr + 4);
+
+ switch ((int) flashtest_h) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ flashtest_h = V_ULONG (baseaddr + 8); /* device ID */
+ flashtest_l = V_ULONG (baseaddr + 12);
+ if (flashtest_h != flashtest_l) {
+ info->flash_id = FLASH_UNKNOWN;
+ } else {
+ switch (flashtest_h) {
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00400000;
+ break; /* 4 * 1 MB = 4 MB */
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00400000;
+ break; /* 4 * 1 MB = 4 MB */
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00800000;
+ break; /* 4 * 2 MB = 8 MB */
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00800000;
+ break; /* 4 * 2 MB = 8 MB */
+ case AMD_ID_DL322T:
+ info->flash_id += FLASH_AMDL322T;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL322B:
+ info->flash_id += FLASH_AMDL322B;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL323T:
+ info->flash_id += FLASH_AMDL323T;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL323B:
+ info->flash_id += FLASH_AMDL323B;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_LV640U:
+ info->flash_id += FLASH_AM640U;
+ info->sector_count = 128;
+ info->size = 0x02000000;
+ break; /* 4 * 8 MB = 32 MB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* no or unknown flash */
+ }
+ }
+
+ if (flashtest_h == AMD_ID_LV640U) {
+
+ /* set up sector start adress table (uniform sector type) */
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = baseaddr + (i * 0x00040000);
+
+ } else if (info->flash_id & FLASH_BTYPE) {
+
+ /* set up sector start adress table (bottom sector type) */
+ info->start[0] = baseaddr + 0x00000000;
+ info->start[1] = baseaddr + 0x00010000;
+ info->start[2] = baseaddr + 0x00018000;
+ info->start[3] = baseaddr + 0x00020000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
+ }
+
+ } else {
+
+ /* set up sector start adress table (top sector type) */
+ i = info->sector_count - 1;
+ info->start[i--] = baseaddr + info->size - 0x00010000;
+ info->start[i--] = baseaddr + info->size - 0x00018000;
+ info->start[i--] = baseaddr + info->size - 0x00020000;
+ for (; i >= 0; i--) {
+ info->start[i] = baseaddr + i * 0x00040000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
+ (V_ULONG (info->start[i] + 20) & 0x00010001)) {
+ info->protect[i] = 1; /* D0 = 1 if protected */
+ } else {
+ info->protect[i] = 0;
+ }
+ }
+
+ flash_reset ();
+ return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+ unsigned long size_b0 = 0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here (only one bank) */
+
+ size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]);
+ if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 >> 20);
+ }
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+#endif
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD:
+ printf ("AMD ");
+ break;
+ case FLASH_MAN_FUJ:
+ printf ("FUJITSU ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM800T:
+ printf ("29LV800T (8 M, top sector)\n");
+ break;
+ case FLASH_AM800B:
+ printf ("29LV800T (8 M, bottom sector)\n");
+ break;
+ case FLASH_AM160T:
+ printf ("29LV160T (16 M, top sector)\n");
+ break;
+ case FLASH_AM160B:
+ printf ("29LV160B (16 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL322T:
+ printf ("29DL322T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL322B:
+ printf ("29DL322B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL323T:
+ printf ("29DL323T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL323B:
+ printf ("29DL323B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AM640U:
+ printf ("29LV640D (64 M, uniform sector)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect])
+ prot++;
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts ();
+
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ udelay (1000);
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ V_ULONG (info->start[sect]) = 0x00300030;
+ V_ULONG (info->start[sect] + 4) = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts ();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
+ (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
+ {
+ if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ flash_reset ();
+
+ printf (" done\n");
+ return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ ulong dp;
+ static unsigned char bb[8];
+ int i, l, rc, cc = cnt;
+
+ dp = (addr & ~7); /* get lower dword aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - dp) != 0) {
+ for (i = 0; i < 8; i++)
+ bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
+ if ((rc = write_dword (info, dp, bb)) != 0) {
+ return (rc);
+ }
+ dp += 8;
+ cc -= 8 - l;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cc >= 8) {
+ if ((rc = write_dword (info, dp, src)) != 0) {
+ return (rc);
+ }
+ dp += 8;
+ src += 8;
+ cc -= 8;
+ }
+
+ if (cc <= 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ for (i = 0; i < 8; i++) {
+ bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
+ }
+ return (write_dword (info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
+{
+ ulong start, cl, ch;
+ int flag, i;
+
+ for (ch = 0, i = 0; i < 4; i++)
+ ch = (ch << 8) + *pdata++; /* high word */
+ for (cl = 0, i = 0; i < 4; i++)
+ cl = (cl << 8) + *pdata++; /* low word */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *) dest) & ch) != ch
+ || (*((vu_long *) (dest + 4)) & cl) != cl) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts ();
+
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
+ V_ULONG (dest) = ch;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
+ V_ULONG (dest + 4) = cl;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts ();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
+ ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
+ if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_data (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ *
+ * The PCU E uses an address map where flash banks are aligned top
+ * down, so that the "first" flash bank ends at top of memory, and
+ * the monitor entry point is at address (0xFFF00100). The second
+ * flash bank is mapped immediately below bank 0.
+ *
+ * This is NOT in conformance to the "official" memory map!
+ *
+ */
+
+#define PCU_MONITOR_BASE ( (flash_info[0].start[0] + flash_info[0].size - 1) \
+ - (0xFFFFFFFF - CFG_MONITOR_BASE) )
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long base, size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ /*
+ * Warning:
+ *
+ * Since the PCU E memory map assigns flash banks top down,
+ * we swap the numbering later if both banks are equipped,
+ * so they look like a contiguous area of memory.
+ */
+ DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+ DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE6_PRELIM);
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE6_PRELIM, &flash_info[1]);
+
+ DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n", size_b0, size_b1);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+
+ DEBUGF ("## Before remap: "
+ "BR0: 0x%08x OR0: 0x%08x "
+ "BR6: 0x%08x OR6: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0,
+ memctl->memc_br6, memctl->memc_or6);
+
+ /* Remap FLASH according to real size */
+ base = 0 - size_b0;
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
+ memctl->memc_br0 = (base & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
+
+ DEBUGF("## BR0: 0x%08x OR0: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0);
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)base, &flash_info[0]);
+ base = 0 - size_b0;
+
+ flash_info[0].size = size_b0;
+
+ flash_get_offsets (base, &flash_info[0]);
+
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ PCU_MONITOR_BASE,
+ PCU_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ flash_info_t tmp_info;
+
+ memctl->memc_or6 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000);
+ memctl->memc_br6 = ((base - size_b1) & BR_BA_MSK) |
+ BR_PS_16 | BR_MS_GPCM | BR_V;
+
+ DEBUGF("## New BR6: 0x%08x OR6: 0x%08x\n",
+ memctl->memc_br6, memctl->memc_or6);
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(base - size_b1),
+ &flash_info[1]);
+ base -= size_b1;
+
+ flash_get_offsets (base, &flash_info[1]);
+
+ flash_info[1].size = size_b1;
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[1]);
+#endif
+ /*
+ * Swap bank numbers so that addresses are in ascending order
+ */
+ tmp_info = flash_info[0];
+ flash_info[0] = flash_info[1];
+ flash_info[1] = tmp_info;
+ } else {
+ memctl->memc_br1 = 0; /* invalidate bank */
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ }
+
+
+ DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+ short n;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ return;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_AMD) {
+ return;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AMDL322T:
+ case FLASH_AMDL323T:
+ case FLASH_AMDL324T:
+ /* set sector offsets for top boot block type */
+
+ base += info->size;
+ i = info->sector_count;
+ for (n=0; n<8; ++n) { /* 8 x 8k boot sectors */
+ base -= 8 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ while (i > 0) { /* 64k regular sectors */
+ base -= 64 << 10;
+ --i;
+ info->start[i] = base;
+ }
+ return;
+ case FLASH_AMDL322B:
+ case FLASH_AMDL323B:
+ case FLASH_AMDL324B:
+ /* set sector offsets for bottom boot block type */
+ for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
+ info->start[i] = base;
+ base += 8 << 10;
+ }
+ while (base < info->size) { /* 64k regular sectors */
+ info->start[i] = base;
+ base += 64 << 10;
+ ++i;
+ }
+ return;
+ case FLASH_AMDL640:
+ /* set sector offsets for dual boot block type */
+ for (i=0; i<8; ++i) { /* 8 x 8k boot sectors */
+ info->start[i] = base;
+ base += 8 << 10;
+ }
+ n = info->sector_count - 8;
+ while (i < n) { /* 64k regular sectors */
+ info->start[i] = base;
+ base += 64 << 10;
+ ++i;
+ }
+ while (i < info->sector_count) { /* 8 x 8k boot sectors */
+ info->start[i] = base;
+ base += 8 << 10;
+ ++i;
+ }
+ return;
+ default:
+ return;
+ }
+ /* NOTREACHED */
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AMDL322B: printf ("AM29DL322B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AMDL322T: printf ("AM29DL322T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AMDL323B: printf ("AM29DL323B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AMDL323T: printf ("AM29DL323T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AMDL324B: printf ("AM29DL324B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AMDL324T: printf ("AM29DL324T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AMDL640: printf ("AM29DL640D (64 Mbit, dual boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type 0x%lX\n",
+ info->flash_id);
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ushort value;
+ vu_short *saddr = (vu_short *)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ saddr[0x0555] = 0x00AA;
+ saddr[0x02AA] = 0x0055;
+ saddr[0x0555] = 0x0090;
+
+ value = saddr[0];
+
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%04x\n", (ulong)addr, value);
+
+ switch (value) {
+ case (AMD_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (FUJ_MANUFACT & 0xFFFF):
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ DEBUGF("Unknown Manufacturer ID\n");
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = saddr[1]; /* device ID */
+
+ DEBUGF("Device ID @ 0x%08lx: 0x%04x\n", (ulong)(&addr[1]), value);
+
+ switch (value) {
+
+ case (AMD_ID_DL322T & 0xFFFF):
+ info->flash_id += FLASH_AMDL322T;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_DL322B & 0xFFFF):
+ info->flash_id += FLASH_AMDL322B;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_DL323T & 0xFFFF):
+ info->flash_id += FLASH_AMDL323T;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_DL323B & 0xFFFF):
+ info->flash_id += FLASH_AMDL323B;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_DL324T & 0xFFFF):
+ info->flash_id += FLASH_AMDL324T;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+
+ case (AMD_ID_DL324B & 0xFFFF):
+ info->flash_id += FLASH_AMDL324B;
+ info->sector_count = 71;
+ info->size = 0x00400000;
+ break; /* => 8 MB */
+ case (AMD_ID_DL640 & 0xFFFF):
+ info->flash_id += FLASH_AMDL640;
+ info->sector_count = 142;
+ info->size = 0x00800000;
+ break;
+ default:
+ DEBUGF("Unknown Device ID\n");
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+
+ }
+
+ flash_get_offsets ((ulong)addr, info);
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+#if 0
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ saddr = (vu_short *)(info->start[i]);
+ info->protect[i] = saddr[2] & 1;
+#else
+ info->protect[i] =0;
+#endif
+ }
+
+ if (info->sector_count > CFG_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CFG_MAX_FLASH_SECT);
+ info->sector_count = CFG_MAX_FLASH_SECT;
+ }
+
+ saddr = (vu_short *)info->start[0];
+ *saddr = 0x00F0; /* restore read mode */
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_short *addr = (vu_short*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+ addr[0x0555] = 0x0080;
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_short*)(info->start[sect]);
+ addr[0] = 0x0030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_short*)(info->start[l_sect]);
+ while ((addr[0] & 0x0080) != 0x0080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (vu_short *)info->start[0];
+ addr[0] = 0x00F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+#define FLASH_WIDTH 2 /* flash bus width in bytes */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~(FLASH_WIDTH-1)); /* get lower FLASH_WIDTH aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<FLASH_WIDTH && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<FLASH_WIDTH; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ }
+
+ /*
+ * handle FLASH_WIDTH aligned part
+ */
+ while (cnt >= FLASH_WIDTH) {
+ data = 0;
+ for (i=0; i<FLASH_WIDTH; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_data(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += FLASH_WIDTH;
+ cnt -= FLASH_WIDTH;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<FLASH_WIDTH && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<FLASH_WIDTH; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_data(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_data (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_short *addr = (vu_short*)(info->start[0]);
+ vu_short *sdest = (vu_short *)dest;
+ ushort sdata = (ushort)data;
+ ushort sval;
+ ulong start, passed;
+ int flag, rc;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*sdest & sdata) != sdata) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA;
+ addr[0x02AA] = 0x0055;
+ addr[0x0555] = 0x00A0;
+
+#ifdef WORKAROUND_FOR_BROKEN_HARDWARE
+ /* work around the timeout bugs */
+ udelay(20);
+#endif
+
+ *sdest = sdata;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ rc = 0;
+ /* data polling for D7 */
+ start = get_timer (0);
+
+ for (passed=0; passed < CFG_FLASH_WRITE_TOUT; passed=get_timer(start)) {
+
+ sval = *sdest;
+
+ if ((sval & 0x0080) == (sdata & 0x0080))
+ break;
+
+ if ((sval & 0x0020) == 0) /* DQ5: Timeout? */
+ continue;
+
+ sval = *sdest;
+
+ if ((sval & 0x0080) != (sdata & 0x0080))
+ rc = 1;
+
+ break;
+ }
+
+ if (rc) {
+ DEBUGF ("Program cycle failed @ addr 0x%08lX: val %04X data %04X\n",
+ dest, sval, sdata);
+ }
+
+ if (passed >= CFG_FLASH_WRITE_TOUT) {
+ DEBUGF ("Timeout @ addr 0x%08lX: val %04X data %04X\n",
+ dest, sval, sdata);
+ rc = 1;
+ }
+
+ /* reset to read mode */
+ addr = (vu_short *)info->start[0];
+ addr[0] = 0x00F0; /* reset bank */
+
+ return (rc);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
+ * has nothing to do with the flash chip being 8-bit or 16-bit.
+ */
+#ifdef CONFIG_FLASH_16BIT
+typedef unsigned short FLASH_PORT_WIDTH;
+typedef volatile unsigned short FLASH_PORT_WIDTHV;
+#define FLASH_ID_MASK 0xFFFF
+#else
+typedef unsigned long FLASH_PORT_WIDTH;
+typedef volatile unsigned long FLASH_PORT_WIDTHV;
+#define FLASH_ID_MASK 0xFFFFFFFF
+#endif
+
+#define FPW FLASH_PORT_WIDTH
+#define FPWV FLASH_PORT_WIDTHV
+
+#define ORMASK(size) ((-size) & OR_AM_MSK)
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size(FPWV *addr, flash_info_t *info);
+static void flash_reset(flash_info_t *info);
+static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
+static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
+static void flash_get_offsets(ulong base, flash_info_t *info);
+#ifdef CFG_FLASH_PROTECTION
+static void flash_sync_real_protect(flash_info_t *info);
+#endif
+
+/*-----------------------------------------------------------------------
+ * flash_init()
+ *
+ * sets up flash_info and returns size of FLASH (bytes)
+ */
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ size_b = flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size_b;
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx\n",size_b);
+ }
+
+ /* Remap FLASH according to real size, so only at proper address */
+ memctl->memc_or0 = (memctl->memc_or0 & ~OR_AM_MSK) | ORMASK(size_b);
+
+ /* Do this again (was done already in flast_get_size), just
+ * in case we move it when remap the FLASH.
+ */
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+#ifdef CFG_FLASH_PROTECTION
+ /* read the hardware protection status (if any) into the
+ * protection array in flash_info.
+ */
+ flash_sync_real_protect(&flash_info[0]);
+#endif
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+ return (size_b);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_reset(flash_info_t *info)
+{
+ FPWV *base = (FPWV *)(info->start[0]);
+
+ /* Put FLASH back in read mode */
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+ *base = (FPW)0x00FF00FF; /* Intel Read Mode */
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
+ *base = (FPW)0x00F000F0; /* AMD Read Mode */
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
+ && (info->flash_id & FLASH_BTYPE)) {
+ int bootsect_size; /* number of bytes/boot sector */
+ int sect_size; /* number of bytes/regular sector */
+
+ bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < 8; ++i) {
+ info->start[i] = base + (i * bootsect_size);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + ((i - 7) * sect_size);
+ }
+ }
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
+ && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
+
+ int sect_size; /* number of bytes/sector */
+
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set up sector start address table (uniform sector type) */
+ for( i = 0; i < info->sector_count; i++ )
+ info->start[i] = base + (i * sect_size);
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+ uchar *boottype;
+ uchar *bootletter;
+ uchar *fmt;
+ uchar botbootletter[] = "B";
+ uchar topbootletter[] = "T";
+ uchar botboottype[] = "bottom boot sector";
+ uchar topboottype[] = "top boot sector";
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ /* check for top or bottom boot, if it applies */
+ if (info->flash_id & FLASH_BTYPE) {
+ boottype = botboottype;
+ bootletter = botbootletter;
+ }
+ else {
+ boottype = topboottype;
+ bootletter = topbootletter;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM640U:
+ fmt = "29LV641D (64 Mbit, uniform sectors)\n";
+ break;
+ case FLASH_28F800C3B:
+ case FLASH_28F800C3T:
+ fmt = "28F800C3%s (8 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL800B:
+ case FLASH_INTEL800T:
+ fmt = "28F800B3%s (8 Mbit, %s)\n";
+ break;
+ case FLASH_28F160C3B:
+ case FLASH_28F160C3T:
+ fmt = "28F160C3%s (16 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL160B:
+ case FLASH_INTEL160T:
+ fmt = "28F160B3%s (16 Mbit, %s)\n";
+ break;
+ case FLASH_28F320C3B:
+ case FLASH_28F320C3T:
+ fmt = "28F320C3%s (32 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL320B:
+ case FLASH_INTEL320T:
+ fmt = "28F320B3%s (32 Mbit, %s)\n";
+ break;
+ case FLASH_28F640C3B:
+ case FLASH_28F640C3T:
+ fmt = "28F640C3%s (64 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL640B:
+ case FLASH_INTEL640T:
+ fmt = "28F640B3%s (64 Mbit, %s)\n";
+ break;
+ default:
+ fmt = "Unknown Chip Type\n";
+ break;
+ }
+
+ printf (fmt, bootletter, boottype);
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20,
+ info->sector_count);
+
+ printf (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0) {
+ printf ("\n ");
+ }
+
+ printf (" %08lX%s", info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+ulong flash_get_size (FPWV *addr, flash_info_t *info)
+{
+ /* Write auto select command: read Manufacturer ID */
+
+ /* Write auto select command sequence and test FLASH answer */
+ addr[0x0555] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
+ addr[0x02AA] = (FPW)0x00550055; /* for AMD, Intel ignores this */
+ addr[0x0555] = (FPW)0x00900090; /* selects Intel or AMD */
+
+ /* The manufacturer codes are only 1 byte, so just use 1 byte.
+ * This works for any bus width and any FLASH device width.
+ */
+ switch (addr[0] & 0xff) {
+
+ case (uchar)AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case (uchar)INTEL_MANUFACT:
+ info->flash_id = FLASH_MAN_INTEL;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+ }
+
+ /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
+ if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) {
+
+ case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
+ info->flash_id += FLASH_AM640U;
+ info->sector_count = 128;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ case (FPW)INTEL_ID_28F800C3B:
+ info->flash_id += FLASH_28F800C3B;
+ info->sector_count = 23;
+ info->size = 0x00100000 * (sizeof(FPW)/2);
+ break; /* => 1 or 2 MB */
+
+ case (FPW)INTEL_ID_28F800B3B:
+ info->flash_id += FLASH_INTEL800B;
+ info->sector_count = 23;
+ info->size = 0x00100000 * (sizeof(FPW)/2);
+ break; /* => 1 or 2 MB */
+
+ case (FPW)INTEL_ID_28F160C3B:
+ info->flash_id += FLASH_28F160C3B;
+ info->sector_count = 39;
+ info->size = 0x00200000 * (sizeof(FPW)/2);
+ break; /* => 2 or 4 MB */
+
+ case (FPW)INTEL_ID_28F160B3B:
+ info->flash_id += FLASH_INTEL160B;
+ info->sector_count = 39;
+ info->size = 0x00200000 * (sizeof(FPW)/2);
+ break; /* => 2 or 4 MB */
+
+ case (FPW)INTEL_ID_28F320C3B:
+ info->flash_id += FLASH_28F320C3B;
+ info->sector_count = 71;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break; /* => 4 or 8 MB */
+
+ case (FPW)INTEL_ID_28F320B3B:
+ info->flash_id += FLASH_INTEL320B;
+ info->sector_count = 71;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break; /* => 4 or 8 MB */
+
+ case (FPW)INTEL_ID_28F640C3B:
+ info->flash_id += FLASH_28F640C3B;
+ info->sector_count = 135;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ case (FPW)INTEL_ID_28F640B3B:
+ info->flash_id += FLASH_INTEL640B;
+ info->sector_count = 135;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* => no or unknown flash */
+ }
+
+ flash_get_offsets((ulong)addr, info);
+
+ /* Put FLASH back in read mode */
+ flash_reset(info);
+
+ return (info->size);
+}
+
+#ifdef CFG_FLASH_PROTECTION
+/*-----------------------------------------------------------------------
+ */
+
+static void flash_sync_real_protect(flash_info_t *info)
+{
+ FPWV *addr = (FPWV *)(info->start[0]);
+ FPWV *sect;
+ int i;
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F800C3B:
+ case FLASH_28F800C3T:
+ case FLASH_28F160C3B:
+ case FLASH_28F160C3T:
+ case FLASH_28F320C3B:
+ case FLASH_28F320C3T:
+ case FLASH_28F640C3B:
+ case FLASH_28F640C3T:
+ /* check for protected sectors */
+ *addr = (FPW)0x00900090;
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02.
+ * D0 = 1 for each device if protected.
+ * If at least one device is protected the sector is marked
+ * protected, but mixed protected and unprotected devices
+ * within a sector should never happen.
+ */
+ sect = (FPWV *)(info->start[i]);
+ info->protect[i] = (sect[2] & (FPW)(0x00010001)) ? 1 : 0;
+ }
+
+ /* Put FLASH back in read mode */
+ flash_reset(info);
+ break;
+
+ case FLASH_AM640U:
+ default:
+ /* no hardware protect that we support */
+ break;
+ }
+}
+#endif
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ FPWV *addr;
+ int flag, prot, sect;
+ int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
+ ulong start, now, last;
+ int rcode = 0;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_INTEL800B:
+ case FLASH_INTEL160B:
+ case FLASH_INTEL320B:
+ case FLASH_INTEL640B:
+ case FLASH_28F800C3B:
+ case FLASH_28F160C3B:
+ case FLASH_28F320C3B:
+ case FLASH_28F640C3B:
+ case FLASH_AM640U:
+ break;
+ case FLASH_UNKNOWN:
+ default:
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ start = get_timer(0);
+ last = start;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
+
+ if (info->protect[sect] != 0) /* protected, skip it */
+ continue;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr = (FPWV *)(info->start[sect]);
+ if (intel) {
+ *addr = (FPW)0x00500050; /* clear status register */
+ *addr = (FPW)0x00200020; /* erase setup */
+ *addr = (FPW)0x00D000D0; /* erase confirm */
+ }
+ else {
+ /* must be AMD style if not Intel */
+ FPWV *base; /* first address in bank */
+
+ base = (FPWV *)(info->start[0]);
+ base[0x0555] = (FPW)0x00AA00AA; /* unlock */
+ base[0x02AA] = (FPW)0x00550055; /* unlock */
+ base[0x0555] = (FPW)0x00800080; /* erase mode */
+ base[0x0555] = (FPW)0x00AA00AA; /* unlock */
+ base[0x02AA] = (FPW)0x00550055; /* unlock */
+ *addr = (FPW)0x00300030; /* erase sector */
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 50us for AMD, 80us for Intel.
+ * Let's wait 1 ms.
+ */
+ udelay (1000);
+
+ while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+
+ if (intel) {
+ /* suspend erase */
+ *addr = (FPW)0x00B000B0;
+ }
+
+ flash_reset(info); /* reset to read mode */
+ rcode = 1; /* failed */
+ break;
+ }
+
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+ flash_reset(info); /* reset to read mode */
+ }
+
+ printf (" done\n");
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
+ int bytes; /* number of bytes to program in current word */
+ int left; /* number of bytes left to program */
+ int i, res;
+
+ for (left = cnt, res = 0;
+ left > 0 && res == 0;
+ addr += sizeof(data), left -= sizeof(data) - bytes) {
+
+ bytes = addr & (sizeof(data) - 1);
+ addr &= ~(sizeof(data) - 1);
+
+ /* combine source and destination data so can program
+ * an entire word of 16 or 32 bits
+ */
+ for (i = 0; i < sizeof(data); i++) {
+ data <<= 8;
+ if (i < bytes || i - bytes >= left )
+ data += *((uchar *)addr + i);
+ else
+ data += *src++;
+ }
+
+ /* write one word to the flash */
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD:
+ res = write_word_amd(info, (FPWV *)addr, data);
+ break;
+ case FLASH_MAN_INTEL:
+ res = write_word_intel(info, (FPWV *)addr, data);
+ break;
+ default:
+ /* unknown flash type, error! */
+ printf ("missing or unknown FLASH type\n");
+ res = 1; /* not really a timeout, but gives error */
+ break;
+ }
+ }
+
+ return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for AMD FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
+{
+ ulong start;
+ int flag;
+ int res = 0; /* result, assume success */
+ FPWV *base; /* first address in flash bank */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*dest & data) != data) {
+ return (2);
+ }
+
+
+ base = (FPWV *)(info->start[0]);
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ base[0x0555] = (FPW)0x00AA00AA; /* unlock */
+ base[0x02AA] = (FPW)0x00550055; /* unlock */
+ base[0x0555] = (FPW)0x00A000A0; /* selects program mode */
+
+ *dest = data; /* start programming the data */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ /* data polling for D7 */
+ while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *dest = (FPW)0x00F000F0; /* reset bank */
+ res = 1;
+ }
+ }
+
+ return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for Intel FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
+{
+ ulong start;
+ int flag;
+ int res = 0; /* result, assume success */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*dest & data) != data) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ *dest = (FPW)0x00500050; /* clear status register */
+ *dest = (FPW)0x00FF00FF; /* make sure in read mode */
+ *dest = (FPW)0x00400040; /* program setup */
+
+ *dest = data; /* start programming the data */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *dest = (FPW)0x00B000B0; /* Suspend program */
+ res = 1;
+ }
+ }
+
+ if (res == 0 && (*dest & (FPW)0x00100010))
+ res = 1; /* write failed, time out error is close enough */
+
+ *dest = (FPW)0x00500050; /* clear status register */
+ *dest = (FPW)0x00FF00FF; /* make sure in read mode */
+
+ return (res);
+}
+
+#ifdef CFG_FLASH_PROTECTION
+/*-----------------------------------------------------------------------
+ */
+int flash_real_protect (flash_info_t * info, long sector, int prot)
+{
+ int rcode = 0; /* assume success */
+ FPWV *addr; /* address of sector */
+ FPW value;
+
+ addr = (FPWV *) (info->start[sector]);
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_28F800C3B:
+ case FLASH_28F800C3T:
+ case FLASH_28F160C3B:
+ case FLASH_28F160C3T:
+ case FLASH_28F320C3B:
+ case FLASH_28F320C3T:
+ case FLASH_28F640C3B:
+ case FLASH_28F640C3T:
+ flash_reset (info); /* make sure in read mode */
+ *addr = (FPW) 0x00600060L; /* lock command setup */
+ if (prot)
+ *addr = (FPW) 0x00010001L; /* lock sector */
+ else
+ *addr = (FPW) 0x00D000D0L; /* unlock sector */
+ flash_reset (info); /* reset to read mode */
+
+ /* now see if it really is locked/unlocked as requested */
+ *addr = (FPW) 0x00900090;
+ /* read sector protection at sector address, (A7 .. A0) = 0x02.
+ * D0 = 1 for each device if protected.
+ * If at least one device is protected the sector is marked
+ * protected, but return failure. Mixed protected and
+ * unprotected devices within a sector should never happen.
+ */
+ value = addr[2] & (FPW) 0x00010001;
+ if (value == 0)
+ info->protect[sector] = 0;
+ else if (value == (FPW) 0x00010001)
+ info->protect[sector] = 1;
+ else {
+ /* error, mixed protected and unprotected */
+ rcode = 1;
+ info->protect[sector] = 1;
+ }
+ if (info->protect[sector] != prot)
+ rcode = 1; /* failed to protect/unprotect as requested */
+
+ /* reload all protection bits from hardware for now */
+ flash_sync_real_protect (info);
+ break;
+
+ case FLASH_AM640U:
+ default:
+ /* no hardware protect that we support */
+ info->protect[sector] = prot;
+ break;
+ }
+
+ return rcode;
+}
+#endif
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ /* All Speech Design board memory (DRAM and EPROM) initialisation is
+ done in dram_init().
+ The caller of ths function here expects the total size and will hang,
+ if we give here back 0. So we return the EPROM size. */
+
+ return (1024 * 1024); /* 1 MB */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_print_info (flash_info_t *info)
+{
+ printf("no FLASH memory in MPC823TS board\n");
+ return;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ return 1;
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Flash Routines for AMD devices on the TQM8260 board
+ *
+ *--------------------------------------------------------------------
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+#define V_ULONG(a) (*(volatile unsigned long *)( a ))
+#define V_BYTE(a) (*(volatile unsigned char *)( a ))
+
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
+
+
+/*-----------------------------------------------------------------------
+ */
+void flash_reset (void)
+{
+ if (flash_info[0].flash_id != FLASH_UNKNOWN) {
+ V_ULONG (flash_info[0].start[0]) = 0x00F000F0;
+ V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+ulong flash_get_size (ulong baseaddr, flash_info_t * info)
+{
+ short i;
+ unsigned long flashtest_h, flashtest_l;
+
+ /* Write auto select command sequence and test FLASH answer */
+ V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
+ V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
+ V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;
+
+ flashtest_h = V_ULONG (baseaddr); /* manufacturer ID */
+ flashtest_l = V_ULONG (baseaddr + 4);
+
+ switch ((int) flashtest_h) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ flashtest_h = V_ULONG (baseaddr + 8); /* device ID */
+ flashtest_l = V_ULONG (baseaddr + 12);
+ if (flashtest_h != flashtest_l) {
+ info->flash_id = FLASH_UNKNOWN;
+ } else {
+ switch (flashtest_h) {
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00400000;
+ break; /* 4 * 1 MB = 4 MB */
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00400000;
+ break; /* 4 * 1 MB = 4 MB */
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00800000;
+ break; /* 4 * 2 MB = 8 MB */
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00800000;
+ break; /* 4 * 2 MB = 8 MB */
+ case AMD_ID_DL322T:
+ info->flash_id += FLASH_AMDL322T;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL322B:
+ info->flash_id += FLASH_AMDL322B;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL323T:
+ info->flash_id += FLASH_AMDL323T;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_DL323B:
+ info->flash_id += FLASH_AMDL323B;
+ info->sector_count = 71;
+ info->size = 0x01000000;
+ break; /* 4 * 4 MB = 16 MB */
+ case AMD_ID_LV640U:
+ info->flash_id += FLASH_AM640U;
+ info->sector_count = 128;
+ info->size = 0x02000000;
+ break; /* 4 * 8 MB = 32 MB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* no or unknown flash */
+ }
+ }
+
+ if (flashtest_h == AMD_ID_LV640U) {
+
+ /* set up sector start adress table (uniform sector type) */
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = baseaddr + (i * 0x00040000);
+
+ } else if (info->flash_id & FLASH_BTYPE) {
+
+ /* set up sector start adress table (bottom sector type) */
+ info->start[0] = baseaddr + 0x00000000;
+ info->start[1] = baseaddr + 0x00010000;
+ info->start[2] = baseaddr + 0x00018000;
+ info->start[3] = baseaddr + 0x00020000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
+ }
+
+ } else {
+
+ /* set up sector start adress table (top sector type) */
+ i = info->sector_count - 1;
+ info->start[i--] = baseaddr + info->size - 0x00010000;
+ info->start[i--] = baseaddr + info->size - 0x00018000;
+ info->start[i--] = baseaddr + info->size - 0x00020000;
+ for (; i >= 0; i--) {
+ info->start[i] = baseaddr + i * 0x00040000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
+ (V_ULONG (info->start[i] + 20) & 0x00010001)) {
+ info->protect[i] = 1; /* D0 = 1 if protected */
+ } else {
+ info->protect[i] = 0;
+ }
+ }
+
+ flash_reset ();
+ return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+unsigned long flash_init (void)
+{
+ unsigned long size_b0 = 0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here (only one bank) */
+
+ size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]);
+ if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 >> 20);
+ }
+
+ /*
+ * protect monitor and environment sectors
+ */
+
+#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]);
+#endif
+
+#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR)
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+ flash_protect (FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
+#endif
+
+ return (size_b0);
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD:
+ printf ("AMD ");
+ break;
+ case FLASH_MAN_FUJ:
+ printf ("FUJITSU ");
+ break;
+ default:
+ printf ("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM800T:
+ printf ("29LV800T (8 M, top sector)\n");
+ break;
+ case FLASH_AM800B:
+ printf ("29LV800T (8 M, bottom sector)\n");
+ break;
+ case FLASH_AM160T:
+ printf ("29LV160T (16 M, top sector)\n");
+ break;
+ case FLASH_AM160B:
+ printf ("29LV160B (16 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL322T:
+ printf ("29DL322T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL322B:
+ printf ("29DL322B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AMDL323T:
+ printf ("29DL323T (32 M, top sector)\n");
+ break;
+ case FLASH_AMDL323B:
+ printf ("29DL323B (32 M, bottom sector)\n");
+ break;
+ case FLASH_AM640U:
+ printf ("29LV640D (64 M, uniform sector)\n");
+ break;
+ default:
+ printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+ return;
+}
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect])
+ prot++;
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts ();
+
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ udelay (1000);
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ V_ULONG (info->start[sect]) = 0x00300030;
+ V_ULONG (info->start[sect] + 4) = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts ();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 ||
+ (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080)
+ {
+ if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ serial_putc ('.');
+ last = now;
+ }
+ }
+
+ DONE:
+ /* reset to read mode */
+ flash_reset ();
+
+ printf (" done\n");
+ return 0;
+}
+
+static int write_dword (flash_info_t *, ulong, unsigned char *);
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+ ulong dp;
+ static unsigned char bb[8];
+ int i, l, rc, cc = cnt;
+
+ dp = (addr & ~7); /* get lower dword aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - dp) != 0) {
+ for (i = 0; i < 8; i++)
+ bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++;
+ if ((rc = write_dword (info, dp, bb)) != 0) {
+ return (rc);
+ }
+ dp += 8;
+ cc -= 8 - l;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cc >= 8) {
+ if ((rc = write_dword (info, dp, src)) != 0) {
+ return (rc);
+ }
+ dp += 8;
+ src += 8;
+ cc -= 8;
+ }
+
+ if (cc <= 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ for (i = 0; i < 8; i++) {
+ bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i);
+ }
+ return (write_dword (info, dp, bb));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a dword to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata)
+{
+ ulong start, cl, ch;
+ int flag, i;
+
+ for (ch = 0, i = 0; i < 4; i++)
+ ch = (ch << 8) + *pdata++; /* high word */
+ for (cl = 0, i = 0; i < 4; i++)
+ cl = (cl << 8) + *pdata++; /* low word */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *) dest) & ch) != ch
+ || (*((vu_long *) (dest + 4)) & cl) != cl) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts ();
+
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0;
+ V_ULONG (dest) = ch;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA;
+ V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055;
+ V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0;
+ V_ULONG (dest + 4) = cl;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts ();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) ||
+ ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) {
+ if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wave 7 Optics, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <cmd_elf.h>
+
+/*
+ * FIXME: Add code to test image and it's header.
+ */
+static int
+image_check(ulong addr)
+{
+ return valid_elf_image(addr);
+}
+
+void
+init_fsboot(void)
+{
+ char *envp;
+ ulong loadaddr;
+ ulong testaddr;
+ ulong alt_loadaddr;
+ char buf[9];
+
+ /*
+ * Get test image address
+ */
+ if ((envp = getenv("testaddr")) != NULL)
+ testaddr = simple_strtoul(envp, NULL, 16);
+ else
+ testaddr = -1;
+
+ /*
+ * Are we going to test boot and image?
+ */
+ if ((testaddr != -1) && image_check(testaddr)) {
+
+ /* Set alt_loadaddr */
+ alt_loadaddr = testaddr;
+ sprintf(buf, "%lX", alt_loadaddr);
+ setenv("alt_loadaddr", buf);
+
+ /* Clear test_addr */
+ setenv("testaddr", NULL);
+
+ /*
+ * Save current environment with alt_loadaddr,
+ * and cleared testaddr.
+ */
+ saveenv();
+
+ /*
+ * Setup temporary loadaddr to alt_loadaddr
+ * XXX - DO NOT SAVE ENVIRONMENT!
+ */
+ loadaddr = alt_loadaddr;
+ sprintf(buf, "%lX", loadaddr);
+ setenv("loadaddr", buf);
+
+ } else { /* Normal boot */
+ setenv("alt_loadaddr", NULL); /* Clear alt_loadaddr */
+ setenv("testaddr", NULL); /* Clear testaddr */
+ saveenv();
+ }
+
+ return;
+}
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * W7O board level hardware watchdog.
+ */
+#include <common.h>
+#include <config.h>
+
+#ifdef CONFIG_HW_WATCHDOG
+#include <watchdog.h>
+
+void hw_watchdog_reset(void)
+{
+ volatile ushort *hwd = (ushort *)(CFG_W7O_EBC_PB7CR & 0xfff00000);
+
+ /*
+ * Read the LMG's hwd register and toggle the
+ * watchdog bit to reset it. On the LMC, just
+ * reading it is enough, but toggling the bit
+ * doen't hurt either.
+ */
+ *hwd = *hwd ^ 0x8000;
+
+} /* hw_watchdog_reset() */
+
+#endif /* CONFIG_HW_WATCHDOG */
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#if defined(CFG_ENV_IS_IN_FLASH)
+# ifndef CFG_ENV_ADDR
+# define CFG_ENV_ADDR (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+# endif
+# ifndef CFG_ENV_SIZE
+# define CFG_ENV_SIZE CFG_ENV_SECT_SIZE
+# endif
+# ifndef CFG_ENV_SECT_SIZE
+# define CFG_ENV_SECT_SIZE CFG_ENV_SIZE
+# endif
+#endif
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size (vu_long *addr, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_get_offsets (ulong base, flash_info_t *info);
+
+/*-----------------------------------------------------------------------
+ */
+
+unsigned long flash_init (void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ unsigned long size_b0, size_b1;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ DEBUGF("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM);
+
+ size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0<<20);
+ }
+
+#if defined(FLASH_BASE1_PRELIM) && (FLASH_BASE1_PRELIM != 0)
+ DEBUGF("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM);
+
+ size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]);
+
+ if (size_b1 > size_b0) {
+ printf ("## ERROR: "
+ "Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n",
+ size_b1, size_b1<<20,
+ size_b0, size_b0<<20
+ );
+ flash_info[0].flash_id = FLASH_UNKNOWN;
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[0].sector_count = -1;
+ flash_info[1].sector_count = -1;
+ flash_info[0].size = 0;
+ flash_info[1].size = 0;
+ return (0);
+ }
+#else
+ size_b1 = 0;
+#endif /* FLASH_BASE1_PRELIM */
+
+ DEBUGF("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ DEBUGF ("## Before remap: "
+ "BR0: 0x%08x OR0: 0x%08x "
+ "BR1: 0x%08x OR1: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0,
+ memctl->memc_br1, memctl->memc_or1);
+
+ /* Remap FLASH according to real size */
+ memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK);
+ memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V;
+
+ DEBUGF("## BR0: 0x%08x OR0: 0x%08x\n",
+ memctl->memc_br0, memctl->memc_or0);
+
+ /* Re-do sizing to get full correct info */
+ size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[0]);
+#endif
+
+ if (size_b1) {
+ memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & OR_AM_MSK);
+ memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) |
+ BR_MS_GPCM | BR_V;
+
+ DEBUGF("## BR1: 0x%08x OR1: 0x%08x\n",
+ memctl->memc_br1, memctl->memc_or1);
+
+ /* Re-do sizing to get full correct info */
+ size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0),
+ &flash_info[1]);
+
+ flash_info[1].size = size_b1;
+
+ flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]);
+
+# if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ &flash_info[1]);
+# endif
+
+# ifdef CFG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
+ &flash_info[1]);
+#endif
+ } else {
+#ifndef CONFIG_AMX_RAM_EXT
+ memctl->memc_br1 = 0; /* invalidate bank */
+ memctl->memc_or1 = 0; /* invalidate bank */
+#endif
+
+ DEBUGF("## DISABLE BR1: 0x%08x OR1: 0x%08x\n",
+ memctl->memc_br1, memctl->memc_or1);
+
+ flash_info[1].flash_id = FLASH_UNKNOWN;
+ flash_info[1].sector_count = -1;
+ flash_info[1].size = 0;
+ }
+
+ DEBUGF("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1);
+
+ return (size_b0 + size_b1);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) {
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00040000);
+ }
+ } else if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+static ulong flash_get_size (vu_long *addr, flash_info_t *info)
+{
+ short i;
+ ulong value;
+ ulong base = (ulong)addr;
+
+ /* Write auto select command: read Manufacturer ID */
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00900090;
+
+ value = addr[0];
+
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value);
+
+ switch (value) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* no or unknown flash */
+ }
+
+ value = addr[1]; /* device ID */
+
+ DEBUGF("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value);
+
+ switch (value) {
+ case AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+#if 0 /* enable when device IDs are available */
+ case AMD_ID_LV320T:
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+ case AMD_ID_LV320B:
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return (0); /* => no or unknown flash */
+ }
+
+ /* set up sector start address table */
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00008000;
+ info->start[2] = base + 0x0000C000;
+ info->start[3] = base + 0x00010000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000) - 0x00060000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00008000;
+ info->start[i--] = base + info->size - 0x0000C000;
+ info->start[i--] = base + info->size - 0x00010000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00020000;
+ }
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ addr = (volatile unsigned long *)(info->start[i]);
+ info->protect[i] = addr[2] & 1;
+ }
+
+ /*
+ * Prevent writes to uninitialized FLASH.
+ */
+ if (info->flash_id != FLASH_UNKNOWN) {
+ addr = (volatile unsigned long *)info->start[0];
+
+ *addr = 0x00F000F0; /* reset bank */
+ }
+
+ return (info->size);
+}
+
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if ((info->flash_id == FLASH_UNKNOWN) ||
+ (info->flash_id > FLASH_AMD_COMP)) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00800080;
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = (vu_long*)(info->start[sect]);
+ addr[0] = 0x00300030;
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = (vu_long*)(info->start[l_sect]);
+ while ((addr[0] & 0x00800080) != 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ }
+
+DONE:
+ /* reset to read mode */
+ addr = (volatile unsigned long *)info->start[0];
+ addr[0] = 0x00F000F0; /* reset bank */
+
+ printf (" done\n");
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ vu_long *addr = (vu_long*)(info->start[0]);
+ ulong start;
+ int flag;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return (2);
+ }
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr[0x0555] = 0x00AA00AA;
+ addr[0x02AA] = 0x00550055;
+ addr[0x0555] = 0x00A000A0;
+
+ *((vu_long *)dest) = data;
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ */
--- /dev/null
+/*
+ * ECC algorithm for M-systems disk on chip. We use the excellent Reed
+ * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the
+ * GNU GPL License. The rest is simply to convert the disk on chip
+ * syndrom into a standard syndom.
+ *
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+
+#include <linux/mtd/doc2000.h>
+
+#undef ECC_DEBUG
+#undef PSYCHO_DEBUG
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* need to undef it (from asm/termbits.h) */
+#undef B0
+
+#define MM 10 /* Symbol size in bits */
+#define KK (1023-4) /* Number of data symbols per block */
+#define B0 510 /* First root of generator polynomial, alpha form */
+#define PRIM 1 /* power of alpha used to generate roots of generator poly */
+#define NN ((1 << MM) - 1)
+
+typedef unsigned short dtype;
+
+/* 1+x^3+x^10 */
+static const int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
+
+/* This defines the type used to store an element of the Galois Field
+ * used by the code. Make sure this is something larger than a char if
+ * if anything larger than GF(256) is used.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium.
+ */
+typedef int gf;
+
+/* No legal value in index form represents zero, so
+ * we need a special value for this purpose
+ */
+#define A0 (NN)
+
+/* Compute x % NN, where NN is 2**MM - 1,
+ * without a slow divide
+ */
+static inline gf
+modnn(int x)
+{
+ while (x >= NN) {
+ x -= NN;
+ x = (x >> MM) + (x & NN);
+ }
+ return x;
+}
+
+#define CLEAR(a,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = 0;\
+}
+
+#define COPY(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define COPYDOWN(a,b,n) {\
+int ci;\
+for(ci=(n)-1;ci >=0;ci--)\
+(a)[ci] = (b)[ci];\
+}
+
+#define Ldec 1
+
+/* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
+ lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
+ polynomial form -> index form index_of[j=alpha**i] = i
+ alpha=2 is the primitive element of GF(2**m)
+ HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
+ Let @ represent the primitive element commonly called "alpha" that
+ is the root of the primitive polynomial p(x). Then in GF(2^m), for any
+ 0 <= i <= 2^m-2,
+ @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+ where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
+ of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
+ example the polynomial representation of @^5 would be given by the binary
+ representation of the integer "alpha_to[5]".
+ Similarily, index_of[] can be used as follows:
+ As above, let @ represent the primitive element of GF(2^m) that is
+ the root of the primitive polynomial p(x). In order to find the power
+ of @ (alpha) that has the polynomial representation
+ a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
+ we consider the integer "i" whose binary representation with a(0) being LSB
+ and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
+ "index_of[i]". Now, @^index_of[i] is that element whose polynomial
+ representation is (a(0),a(1),a(2),...,a(m-1)).
+ NOTE:
+ The element alpha_to[2^m-1] = 0 always signifying that the
+ representation of "@^infinity" = 0 is (0,0,0,...,0).
+ Similarily, the element index_of[0] = A0 always signifying
+ that the power of alpha which has the polynomial representation
+ (0,0,...,0) is "infinity".
+
+*/
+
+static void
+generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
+{
+ register int i, mask;
+
+ mask = 1;
+ Alpha_to[MM] = 0;
+ for (i = 0; i < MM; i++) {
+ Alpha_to[i] = mask;
+ Index_of[Alpha_to[i]] = i;
+ /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
+ if (Pp[i] != 0)
+ Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */
+ mask <<= 1; /* single left-shift */
+ }
+ Index_of[Alpha_to[MM]] = MM;
+ /*
+ * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
+ * poly-repr of @^i shifted left one-bit and accounting for any @^MM
+ * term that may occur when poly-repr of @^i is shifted.
+ */
+ mask >>= 1;
+ for (i = MM + 1; i < NN; i++) {
+ if (Alpha_to[i - 1] >= mask)
+ Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1);
+ else
+ Alpha_to[i] = Alpha_to[i - 1] << 1;
+ Index_of[Alpha_to[i]] = i;
+ }
+ Index_of[0] = A0;
+ Alpha_to[NN] = 0;
+}
+
+/*
+ * Performs ERRORS+ERASURES decoding of RS codes. bb[] is the content
+ * of the feedback shift register after having processed the data and
+ * the ECC.
+ *
+ * Return number of symbols corrected, or -1 if codeword is illegal
+ * or uncorrectable. If eras_pos is non-null, the detected error locations
+ * are written back. NOTE! This array must be at least NN-KK elements long.
+ * The corrected data are written in eras_val[]. They must be xor with the data
+ * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
+ *
+ * First "no_eras" erasures are declared by the calling program. Then, the
+ * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
+ * If the number of channel errors is not greater than "t_after_eras" the
+ * transmitted codeword will be recovered. Details of algorithm can be found
+ * in R. Blahut's "Theory ... of Error-Correcting Codes".
+
+ * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
+ * will result. The decoder *could* check for this condition, but it would involve
+ * extra time on every decoding operation.
+ * */
+static int
+eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
+ gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
+ int no_eras)
+{
+ int deg_lambda, el, deg_omega;
+ int i, j, r,k;
+ gf u,q,tmp,num1,num2,den,discr_r;
+ gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly
+ * and syndrome poly */
+ gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1];
+ gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK];
+ int syn_error, count;
+
+ syn_error = 0;
+ for(i=0;i<NN-KK;i++)
+ syn_error |= bb[i];
+
+ if (!syn_error) {
+ /* if remainder is zero, data[] is a codeword and there are no
+ * errors to correct. So return data[] unmodified
+ */
+ count = 0;
+ goto finish;
+ }
+
+ for(i=1;i<=NN-KK;i++){
+ s[i] = bb[0];
+ }
+ for(j=1;j<NN-KK;j++){
+ if(bb[j] == 0)
+ continue;
+ tmp = Index_of[bb[j]];
+
+ for(i=1;i<=NN-KK;i++)
+ s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
+ }
+
+ /* undo the feedback register implicit multiplication and convert
+ syndromes to index form */
+
+ for(i=1;i<=NN-KK;i++) {
+ tmp = Index_of[s[i]];
+ if (tmp != A0)
+ tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
+ s[i] = tmp;
+ }
+
+ CLEAR(&lambda[1],NN-KK);
+ lambda[0] = 1;
+
+ if (no_eras > 0) {
+ /* Init lambda to be the erasure locator polynomial */
+ lambda[1] = Alpha_to[modnn(PRIM * eras_pos[0])];
+ for (i = 1; i < no_eras; i++) {
+ u = modnn(PRIM*eras_pos[i]);
+ for (j = i+1; j > 0; j--) {
+ tmp = Index_of[lambda[j - 1]];
+ if(tmp != A0)
+ lambda[j] ^= Alpha_to[modnn(u + tmp)];
+ }
+ }
+#ifdef ECC_DEBUG
+ /* Test code that verifies the erasure locator polynomial just constructed
+ Needed only for decoder debugging. */
+
+ /* find roots of the erasure location polynomial */
+ for(i=1;i<=no_eras;i++)
+ reg[i] = Index_of[lambda[i]];
+ count = 0;
+ for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+ q = 1;
+ for (j = 1; j <= no_eras; j++)
+ if (reg[j] != A0) {
+ reg[j] = modnn(reg[j] + j);
+ q ^= Alpha_to[reg[j]];
+ }
+ if (q != 0)
+ continue;
+ /* store root and error location number indices */
+ root[count] = i;
+ loc[count] = k;
+ count++;
+ }
+ if (count != no_eras) {
+ printf("\n lambda(x) is WRONG\n");
+ count = -1;
+ goto finish;
+ }
+#ifdef PSYCHO_DEBUG
+ printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
+ for (i = 0; i < count; i++)
+ printf("%d ", loc[i]);
+ printf("\n");
+#endif
+#endif
+ }
+ for(i=0;i<NN-KK+1;i++)
+ b[i] = Index_of[lambda[i]];
+
+ /*
+ * Begin Berlekamp-Massey algorithm to determine error+erasure
+ * locator polynomial
+ */
+ r = no_eras;
+ el = no_eras;
+ while (++r <= NN-KK) { /* r is the step number */
+ /* Compute discrepancy at the r-th step in poly-form */
+ discr_r = 0;
+ for (i = 0; i < r; i++){
+ if ((lambda[i] != 0) && (s[r - i] != A0)) {
+ discr_r ^= Alpha_to[modnn(Index_of[lambda[i]] + s[r - i])];
+ }
+ }
+ discr_r = Index_of[discr_r]; /* Index form */
+ if (discr_r == A0) {
+ /* 2 lines below: B(x) <-- x*B(x) */
+ COPYDOWN(&b[1],b,NN-KK);
+ b[0] = A0;
+ } else {
+ /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
+ t[0] = lambda[0];
+ for (i = 0 ; i < NN-KK; i++) {
+ if(b[i] != A0)
+ t[i+1] = lambda[i+1] ^ Alpha_to[modnn(discr_r + b[i])];
+ else
+ t[i+1] = lambda[i+1];
+ }
+ if (2 * el <= r + no_eras - 1) {
+ el = r + no_eras - el;
+ /*
+ * 2 lines below: B(x) <-- inv(discr_r) *
+ * lambda(x)
+ */
+ for (i = 0; i <= NN-KK; i++)
+ b[i] = (lambda[i] == 0) ? A0 : modnn(Index_of[lambda[i]] - discr_r + NN);
+ } else {
+ /* 2 lines below: B(x) <-- x*B(x) */
+ COPYDOWN(&b[1],b,NN-KK);
+ b[0] = A0;
+ }
+ COPY(lambda,t,NN-KK+1);
+ }
+ }
+
+ /* Convert lambda to index form and compute deg(lambda(x)) */
+ deg_lambda = 0;
+ for(i=0;i<NN-KK+1;i++){
+ lambda[i] = Index_of[lambda[i]];
+ if(lambda[i] != A0)
+ deg_lambda = i;
+ }
+ /*
+ * Find roots of the error+erasure locator polynomial by Chien
+ * Search
+ */
+ COPY(®[1],&lambda[1],NN-KK);
+ count = 0; /* Number of roots of lambda(x) */
+ for (i = 1,k=NN-Ldec; i <= NN; i++,k = modnn(NN+k-Ldec)) {
+ q = 1;
+ for (j = deg_lambda; j > 0; j--){
+ if (reg[j] != A0) {
+ reg[j] = modnn(reg[j] + j);
+ q ^= Alpha_to[reg[j]];
+ }
+ }
+ if (q != 0)
+ continue;
+ /* store root (index-form) and error location number */
+ root[count] = i;
+ loc[count] = k;
+ /* If we've already found max possible roots,
+ * abort the search to save time
+ */
+ if(++count == deg_lambda)
+ break;
+ }
+ if (deg_lambda != count) {
+ /*
+ * deg(lambda) unequal to number of roots => uncorrectable
+ * error detected
+ */
+ count = -1;
+ goto finish;
+ }
+ /*
+ * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+ * x**(NN-KK)). in index form. Also find deg(omega).
+ */
+ deg_omega = 0;
+ for (i = 0; i < NN-KK;i++){
+ tmp = 0;
+ j = (deg_lambda < i) ? deg_lambda : i;
+ for(;j >= 0; j--){
+ if ((s[i + 1 - j] != A0) && (lambda[j] != A0))
+ tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])];
+ }
+ if(tmp != 0)
+ deg_omega = i;
+ omega[i] = Index_of[tmp];
+ }
+ omega[NN-KK] = A0;
+
+ /*
+ * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+ * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
+ */
+ for (j = count-1; j >=0; j--) {
+ num1 = 0;
+ for (i = deg_omega; i >= 0; i--) {
+ if (omega[i] != A0)
+ num1 ^= Alpha_to[modnn(omega[i] + i * root[j])];
+ }
+ num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
+ den = 0;
+
+ /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
+ for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
+ if(lambda[i+1] != A0)
+ den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
+ }
+ if (den == 0) {
+#ifdef ECC_DEBUG
+ printf("\n ERROR: denominator = 0\n");
+#endif
+ /* Convert to dual- basis */
+ count = -1;
+ goto finish;
+ }
+ /* Apply error to data */
+ if (num1 != 0) {
+ eras_val[j] = Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])];
+ } else {
+ eras_val[j] = 0;
+ }
+ }
+ finish:
+ for(i=0;i<count;i++)
+ eras_pos[i] = loc[i];
+ return count;
+}
+
+/***************************************************************************/
+/* The DOC specific code begins here */
+
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA MM bits words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
+
+/*
+ * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
+ * content of the feedback shift register applyied to the sector and
+ * the ECC. Return the number of errors corrected (and correct them in
+ * sector), or -1 if error
+ */
+int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
+{
+ int parity, i, nb_errors;
+ gf bb[NN - KK + 1];
+ gf error_val[NN-KK];
+ int error_pos[NN-KK], pos, bitpos, index, val;
+ dtype *Alpha_to, *Index_of;
+
+ /* init log and exp tables here to save memory. However, it is slower */
+ Alpha_to = malloc((NN + 1) * sizeof(dtype));
+ if (!Alpha_to)
+ return -1;
+
+ Index_of = malloc((NN + 1) * sizeof(dtype));
+ if (!Index_of) {
+ free(Alpha_to);
+ return -1;
+ }
+
+ generate_gf(Alpha_to, Index_of);
+
+ parity = ecc1[1];
+
+ bb[0] = (ecc1[4] & 0xff) | ((ecc1[5] & 0x03) << 8);
+ bb[1] = ((ecc1[5] & 0xfc) >> 2) | ((ecc1[2] & 0x0f) << 6);
+ bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
+ bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
+
+ nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
+ error_val, error_pos, 0);
+ if (nb_errors <= 0)
+ goto the_end;
+
+ /* correct the errors */
+ for(i=0;i<nb_errors;i++) {
+ pos = error_pos[i];
+ if (pos >= NB_DATA && pos < KK) {
+ nb_errors = -1;
+ goto the_end;
+ }
+ if (pos < NB_DATA) {
+ /* extract bit position (MSB first) */
+ pos = 10 * (NB_DATA - 1 - pos) - 6;
+ /* now correct the following 10 bits. At most two bytes
+ can be modified since pos is even */
+ index = (pos >> 3) ^ 1;
+ bitpos = pos & 7;
+ if ((index >= 0 && index < SECTOR_SIZE) ||
+ index == (SECTOR_SIZE + 1)) {
+ val = error_val[i] >> (2 + bitpos);
+ parity ^= val;
+ if (index < SECTOR_SIZE)
+ sector[index] ^= val;
+ }
+ index = ((pos >> 3) + 1) ^ 1;
+ bitpos = (bitpos + 10) & 7;
+ if (bitpos == 0)
+ bitpos = 8;
+ if ((index >= 0 && index < SECTOR_SIZE) ||
+ index == (SECTOR_SIZE + 1)) {
+ val = error_val[i] << (8 - bitpos);
+ parity ^= val;
+ if (index < SECTOR_SIZE)
+ sector[index] ^= val;
+ }
+ }
+ }
+
+ /* use parity to test extra errors */
+ if ((parity & 0xff) != 0)
+ nb_errors = -1;
+
+ the_end:
+ free(Alpha_to);
+ free(Index_of);
+ return nb_errors;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_DOC) */
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <flash.h>
+
+#if !defined(CFG_NO_FLASH)
+
+extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+ ulong b_end = info->start[0] + info->size - 1; /* bank end address */
+ short s_end = info->sector_count - 1; /* index of last sector */
+ int i;
+
+ /* Do nothing if input data is bad. */
+ if (info->sector_count == 0 || info->size == 0 || to < from) {
+ return;
+ }
+
+ /* There is nothing to do if we have no data about the flash
+ * or the protect range and flash range don't overlap.
+ */
+ if (info->flash_id == FLASH_UNKNOWN ||
+ to < info->start[0] || from > b_end) {
+ return;
+ }
+
+ for (i=0; i<info->sector_count; ++i) {
+ ulong end; /* last address in current sect */
+
+ end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+ /* Update protection if any part of the sector
+ * is in the specified range.
+ */
+ if (from <= end && to >= info->start[i]) {
+ if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CFG_FLASH_PROTECTION)
+ flash_real_protect(info, i, 0);
+#else
+ info->protect[i] = 0;
+#endif /* CFG_FLASH_PROTECTION */
+ }
+ else if (flag & FLAG_PROTECT_SET) {
+#if defined(CFG_FLASH_PROTECTION)
+ flash_real_protect(info, i, 1);
+#else
+ info->protect[i] = 1;
+#endif /* CFG_FLASH_PROTECTION */
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+ flash_info_t *info;
+ int i;
+
+ for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
+ if (info->flash_id != FLASH_UNKNOWN &&
+ addr >= info->start[0] &&
+ /* WARNING - The '- 1' is needed if the flash
+ * is at the end of the address space, since
+ * info->start[0] + info->size wraps back to 0.
+ * Please don't change this unless you understand this.
+ */
+ addr <= info->start[0] + info->size - 1) {
+ return (info);
+ }
+ }
+#endif /* CONFIG_SPD823TS */
+
+ return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK 0 - OK
+ * ERR_TIMOUT 1 - write timeout
+ * ERR_NOT_ERASED 2 - Flash not erased
+ * ERR_PROTECTED 4 - target range includes protected sectors
+ * ERR_INVAL 8 - target address not in Flash memory
+ * ERR_ALIGN 16 - target address not aligned on boundary
+ * (only some targets require alignment)
+ */
+int
+flash_write (uchar *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+ return (ERR_TIMOUT); /* any other error codes are possible as well */
+#else
+ int i;
+ ulong end = addr + cnt - 1;
+ flash_info_t *info_first = addr2info (addr);
+ flash_info_t *info_last = addr2info (end );
+ flash_info_t *info;
+
+ if (cnt == 0) {
+ return (ERR_OK);
+ }
+
+ if (!info_first || !info_last) {
+ return (ERR_INVAL);
+ }
+
+ for (info = info_first; info <= info_last; ++info) {
+ ulong b_end = info->start[0] + info->size; /* bank end addr */
+ short s_end = info->sector_count - 1;
+ for (i=0; i<info->sector_count; ++i) {
+ ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+ if ((end >= info->start[i]) && (addr < e_addr) &&
+ (info->protect[i] != 0) ) {
+ return (ERR_PROTECTED);
+ }
+ }
+ }
+
+ /* finally write data to flash */
+ for (info = info_first; info <= info_last && cnt>0; ++info) {
+ ulong len;
+
+ len = info->start[0] + info->size - addr;
+ if (len > cnt)
+ len = cnt;
+ if ((i = write_buff(info, src, addr, len)) != 0) {
+ return (i);
+ }
+ cnt -= len;
+ addr += len;
+ src += len;
+ }
+ return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_perror (int err)
+{
+ switch (err) {
+ case ERR_OK:
+ break;
+ case ERR_TIMOUT:
+ puts ("Timeout writing to Flash\n");
+ break;
+ case ERR_NOT_ERASED:
+ puts ("Flash not Erased\n");
+ break;
+ case ERR_PROTECTED:
+ puts ("Can't write to protected Flash sectors\n");
+ break;
+ case ERR_INVAL:
+ puts ("Outside available Flash\n");
+ break;
+ case ERR_ALIGN:
+ puts ("Start and/or end address not on sector boundary\n");
+ break;
+ case ERR_UNKNOWN_FLASH_VENDOR:
+ puts ("Unknown Vendor of Flash\n");
+ break;
+ case ERR_UNKNOWN_FLASH_TYPE:
+ puts ("Unknown Type of Flash\n");
+ break;
+ case ERR_PROG_ERROR:
+ puts ("General Flash Programming Error\n");
+ break;
+ default:
+ printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+#endif /* !CFG_NO_FLASH */
--- /dev/null
+#include <common.h>
+#include <malloc.h>
+#include <lists.h>
+
+#define MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+#define CAT4CHARS(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d)
+
+/* increase list size by 10% every time it is full */
+#define kDefaultAllocationPercentIncrease 10
+
+/* always increase list size by 4 items when it is full */
+#define kDefaultAllocationminNumItemsIncrease 4
+
+/*
+ * how many items to expand the list by when it becomes full
+ * = current listSize (in items) + (hiword percent of list size) + loword
+ */
+#define NUMITEMSPERALLOC(list) MAX(((*list)->listSize * \
+ ((*list)->percentIncrease + 100)) / 100, \
+ (*list)->minNumItemsIncrease )
+
+#define ITEMPTR(list,item) &(((char *)&(*list)->itemList)[(*(list))->itemSize * (item)])
+
+#define LIST_SIGNATURE CAT4CHARS('L', 'I', 'S', 'T');
+
+#define calloc(size,num) malloc(size*num)
+
+/********************************************************************/
+
+Handle NewHandle (unsigned int numBytes)
+{
+ void *memPtr;
+ HandleRecord *hanPtr;
+
+ memPtr = calloc (numBytes, 1);
+ hanPtr = (HandleRecord *) calloc (sizeof (HandleRecord), 1);
+ if (hanPtr && (memPtr || numBytes == 0)) {
+ hanPtr->ptr = memPtr;
+ hanPtr->size = numBytes;
+ return (Handle) hanPtr;
+ } else {
+ free (memPtr);
+ free (hanPtr);
+ return NULL;
+ }
+}
+/********************************************************************/
+
+void DisposeHandle (Handle handle)
+{
+ if (handle) {
+ free (*handle);
+ free ((void *) handle);
+ }
+}
+/********************************************************************/
+
+unsigned int GetHandleSize (Handle handle)
+{
+ return ((HandleRecord *) handle)->size;
+}
+/********************************************************************/
+
+int SetHandleSize (Handle handle, unsigned int newSize)
+{
+ HandleRecord *hanRecPtr = (HandleRecord *) handle;
+ void *newPtr, *oldPtr;
+ unsigned int oldSize;
+
+
+ oldPtr = hanRecPtr->ptr;
+ oldSize = hanRecPtr->size;
+
+ if (oldSize == newSize)
+ return 1;
+
+ if (oldPtr == NULL) {
+ newPtr = malloc (newSize);
+ } else {
+ newPtr = realloc (oldPtr, newSize);
+ }
+ if (newPtr || (newSize == 0)) {
+ hanRecPtr->ptr = newPtr;
+ hanRecPtr->size = newSize;
+ if (newSize > oldSize)
+ memset ((char *) newPtr + oldSize, 0, newSize - oldSize);
+ return 1;
+ } else
+ return 0;
+}
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/* Used to compare list elements by their raw data contents */
+static int ListMemBlockCmp (void *a, void *b, int size)
+{
+ return memcmp (a, b, size);
+}
+
+/***************************************************************************/
+
+/*
+ * Binary search numElements of size elementSize in array for a match
+ * to the. item. Return the index of the element that matches
+ * (0 - numElements - 1). If no match is found return the -i-1 where
+ * i is the index (0 - numElements) where the item should be placed.
+ * (*theCmp)(a,b) should return <0 if a<b, 0 if a==b, >0 if a>b.
+ *
+ * This function is like the C-Library function bsearch() except that
+ * this function returns the index where the item should be placed if
+ * it is not found.
+ */
+int BinSearch ( void *array, int numElements, int elementSize,
+ void *itemPtr, CompareFunction compareFunction)
+{
+ int low, high, mid, cmp;
+ void *arrayItemPtr;
+
+ for (low = 0, high = numElements - 1, mid = 0, cmp = -1; low <= high;) {
+ mid = (low + high) >> 1;
+
+ arrayItemPtr = (void *) (((char *) array) + (mid * elementSize));
+ cmp = compareFunction
+ ? compareFunction (itemPtr, arrayItemPtr)
+ : ListMemBlockCmp (itemPtr, arrayItemPtr, elementSize);
+ if (cmp == 0) {
+ return mid;
+ } else if (cmp < 0) {
+ high = mid - 1;
+ } else {
+ low = mid + 1;
+ }
+ }
+ if (cmp > 0)
+ mid++;
+
+ return -mid - 1;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************************************************************/
+
+/*
+ * If numNewItems == 0 then expand the list by the number of items
+ * indicated by its allocation policy.
+ * If numNewItems > 0 then expand the list by exactly the number of
+ * items indicated.
+ * If numNewItems < 0 then expand the list by the absolute value of
+ * numNewItems plus the number of items indicated by its allocation
+ * policy.
+ * Returns 1 for success, 0 if out of memory
+*/
+static int ExpandListSpace (list_t list, int numNewItems)
+{
+ if (numNewItems == 0) {
+ numNewItems = NUMITEMSPERALLOC (list);
+ } else if (numNewItems < 0) {
+ numNewItems = (-numNewItems) + NUMITEMSPERALLOC (list);
+ }
+
+ if (SetHandleSize ((Handle) list,
+ sizeof (ListStruct) +
+ ((*list)->listSize +
+ numNewItems) * (*list)->itemSize)) {
+ (*list)->listSize += numNewItems;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/*
+ * This function reallocate the list, minus any currently unused
+ * portion of its allotted memory.
+ */
+void ListCompact (list_t list)
+{
+
+ if (!SetHandleSize ((Handle) list,
+ sizeof (ListStruct) +
+ (*list)->numItems * (*list)->itemSize)) {
+ return;
+ }
+
+ (*list)->listSize = (*list)->numItems;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+list_t ListCreate (int elementSize)
+{
+ list_t list;
+
+ list = (list_t) (NewHandle (sizeof (ListStruct))); /* create empty list */
+ if (list) {
+ (*list)->signature = LIST_SIGNATURE;
+ (*list)->numItems = 0;
+ (*list)->listSize = 0;
+ (*list)->itemSize = elementSize;
+ (*list)->percentIncrease = kDefaultAllocationPercentIncrease;
+ (*list)->minNumItemsIncrease =
+ kDefaultAllocationminNumItemsIncrease;
+ }
+
+ return list;
+}
+
+/*******************************/
+
+void ListSetAllocationPolicy (list_t list, int minItemsPerAlloc,
+ int percentIncreasePerAlloc)
+{
+ (*list)->percentIncrease = percentIncreasePerAlloc;
+ (*list)->minNumItemsIncrease = minItemsPerAlloc;
+}
+
+/*******************************/
+
+void ListDispose (list_t list)
+{
+ DisposeHandle ((Handle) list);
+}
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+void ListDisposePtrList (list_t list)
+{
+ int index;
+ int numItems;
+
+ if (list) {
+ numItems = ListNumItems (list);
+
+ for (index = 1; index <= numItems; index++)
+ free (*(void **) ListGetPtrToItem (list, index));
+
+ ListDispose (list);
+ }
+}
+
+/*******************************/
+
+/*
+ * keeps memory, resets the number of items to 0
+ */
+void ListClear (list_t list)
+{
+ if (!list)
+ return;
+ (*list)->numItems = 0;
+}
+
+/*******************************/
+
+/*
+ * copy is only as large as necessary
+ */
+list_t ListCopy (list_t originalList)
+{
+ list_t tempList = NULL;
+ int numItems;
+
+ if (!originalList)
+ return NULL;
+
+ tempList = ListCreate ((*originalList)->itemSize);
+ if (tempList) {
+ numItems = ListNumItems (originalList);
+
+ if (!SetHandleSize ((Handle) tempList,
+ sizeof (ListStruct) +
+ numItems * (*tempList)->itemSize)) {
+ ListDispose (tempList);
+ return NULL;
+ }
+
+ (*tempList)->numItems = (*originalList)->numItems;
+ (*tempList)->listSize = (*originalList)->numItems;
+ (*tempList)->itemSize = (*originalList)->itemSize;
+ (*tempList)->percentIncrease = (*originalList)->percentIncrease;
+ (*tempList)->minNumItemsIncrease =
+ (*originalList)->minNumItemsIncrease;
+
+ memcpy (ITEMPTR (tempList, 0), ITEMPTR (originalList, 0),
+ numItems * (*tempList)->itemSize);
+ }
+
+ return tempList;
+}
+
+/********************************/
+
+/*
+ * list1 = list1 + list2
+ */
+int ListAppend (list_t list1, list_t list2)
+{
+ int numItemsL1, numItemsL2;
+
+ if (!list2)
+ return 1;
+
+ if (!list1)
+ return 0;
+ if ((*list1)->itemSize != (*list2)->itemSize)
+ return 0;
+
+ numItemsL1 = ListNumItems (list1);
+ numItemsL2 = ListNumItems (list2);
+
+ if (numItemsL2 == 0)
+ return 1;
+
+ if (!SetHandleSize ((Handle) list1,
+ sizeof (ListStruct) + (numItemsL1 + numItemsL2) *
+ (*list1)->itemSize)) {
+ return 0;
+ }
+
+ (*list1)->numItems = numItemsL1 + numItemsL2;
+ (*list1)->listSize = numItemsL1 + numItemsL2;
+
+ memmove (ITEMPTR (list1, numItemsL1),
+ ITEMPTR (list2, 0),
+ numItemsL2 * (*list2)->itemSize);
+
+ return 1;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+/*
+ * returns 1 if the item is inserted, returns 0 if out of memory or
+ * bad arguments were passed.
+ */
+int ListInsertItem (list_t list, void *ptrToItem, int itemPosition)
+{
+ return ListInsertItems (list, ptrToItem, itemPosition, 1);
+}
+
+/*******************************/
+
+int ListInsertItems (list_t list, void *ptrToItems, int firstItemPosition,
+ int numItemsToInsert)
+{
+ int numItems = (*list)->numItems;
+
+ if (firstItemPosition == numItems + 1)
+ firstItemPosition = LIST_END;
+ else if (firstItemPosition > numItems)
+ return 0;
+
+ if ((*list)->numItems >= (*list)->listSize) {
+ if (!ExpandListSpace (list, -numItemsToInsert))
+ return 0;
+ }
+
+ if (firstItemPosition == LIST_START) {
+ if (numItems == 0) {
+ /* special case for empty list */
+ firstItemPosition = LIST_END;
+ } else {
+ firstItemPosition = 1;
+ }
+ }
+
+ if (firstItemPosition == LIST_END) { /* add at the end of the list */
+ if (ptrToItems)
+ memcpy (ITEMPTR (list, numItems), ptrToItems,
+ (*list)->itemSize * numItemsToInsert);
+ else
+ memset (ITEMPTR (list, numItems), 0,
+ (*list)->itemSize * numItemsToInsert);
+
+ (*list)->numItems += numItemsToInsert;
+ } else { /* move part of list up to make room for new item */
+ memmove (ITEMPTR (list, firstItemPosition - 1 + numItemsToInsert),
+ ITEMPTR (list, firstItemPosition - 1),
+ (numItems + 1 - firstItemPosition) * (*list)->itemSize);
+
+ if (ptrToItems)
+ memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
+ (*list)->itemSize * numItemsToInsert);
+ else
+ memset (ITEMPTR (list, firstItemPosition - 1), 0,
+ (*list)->itemSize * numItemsToInsert);
+
+ (*list)->numItems += numItemsToInsert;
+ }
+
+ return 1;
+}
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+/*******************************/
+
+int ListEqual (list_t list1, list_t list2)
+{
+ if (list1 == list2)
+ return 1;
+
+ if (list1 == NULL || list2 == NULL)
+ return 0;
+
+ if ((*list1)->itemSize == (*list1)->itemSize) {
+ if ((*list1)->numItems == (*list2)->numItems) {
+ return (memcmp (ITEMPTR (list1, 0), ITEMPTR (list2, 0),
+ (*list1)->itemSize * (*list1)->numItems) == 0);
+ }
+ }
+
+ return 0;
+}
+
+/*******************************/
+
+/*
+ * The item pointed to by ptrToItem is copied over the current item
+ * at itemPosition
+ */
+void ListReplaceItem (list_t list, void *ptrToItem, int itemPosition)
+{
+ ListReplaceItems (list, ptrToItem, itemPosition, 1);
+}
+
+/*******************************/
+
+/*
+ * The item pointed to by ptrToItems is copied over the current item
+ * at itemPosition
+ */
+void ListReplaceItems ( list_t list, void *ptrToItems,
+ int firstItemPosition, int numItemsToReplace)
+{
+
+ if (firstItemPosition == LIST_END)
+ firstItemPosition = (*list)->numItems;
+ else if (firstItemPosition == LIST_START)
+ firstItemPosition = 1;
+
+ memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems,
+ (*list)->itemSize * numItemsToReplace);
+}
+
+/*******************************/
+
+void ListGetItem (list_t list, void *itemDestination, int itemPosition)
+{
+ ListGetItems (list, itemDestination, itemPosition, 1);
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/*******************************/
+
+#if defined(CFG_ALL_LIST_FUNCTIONS) || defined(CFG_DEVICE_DEREGISTER)
+
+void ListRemoveItem (list_t list, void *itemDestination, int itemPosition)
+{
+ ListRemoveItems (list, itemDestination, itemPosition, 1);
+}
+
+/*******************************/
+
+void ListRemoveItems (list_t list, void *itemsDestination,
+ int firstItemPosition, int numItemsToRemove)
+{
+ int firstItemAfterChunk, numToMove;
+
+ if (firstItemPosition == LIST_START)
+ firstItemPosition = 1;
+ else if (firstItemPosition == LIST_END)
+ firstItemPosition = (*list)->numItems;
+
+ if (itemsDestination != NULL)
+ memcpy (itemsDestination, ITEMPTR (list, firstItemPosition - 1),
+ (*list)->itemSize * numItemsToRemove);
+
+ firstItemAfterChunk = firstItemPosition + numItemsToRemove;
+ numToMove = (*list)->numItems - (firstItemAfterChunk - 1);
+
+ if (numToMove > 0) {
+ /*
+ * move part of list down to cover hole left by removed item
+ */
+ memmove (ITEMPTR (list, firstItemPosition - 1),
+ ITEMPTR (list, firstItemAfterChunk - 1),
+ (*list)->itemSize * numToMove);
+ }
+
+ (*list)->numItems -= numItemsToRemove;
+}
+#endif /* CFG_ALL_LIST_FUNCTIONS || CFG_DEVICE_DEREGISTER */
+
+/*******************************/
+
+void ListGetItems (list_t list, void *itemsDestination,
+ int firstItemPosition, int numItemsToGet)
+{
+
+ if (firstItemPosition == LIST_START)
+ firstItemPosition = 1;
+ else if (firstItemPosition == LIST_END)
+ firstItemPosition = (*list)->numItems;
+
+ memcpy (itemsDestination,
+ ITEMPTR (list, firstItemPosition - 1),
+ (*list)->itemSize * numItemsToGet);
+}
+
+/*******************************/
+
+/*
+ * Returns a pointer to the item at itemPosition. returns null if an
+ * errors occurred.
+ */
+void *ListGetPtrToItem (list_t list, int itemPosition)
+{
+ if (itemPosition == LIST_START)
+ itemPosition = 1;
+ else if (itemPosition == LIST_END)
+ itemPosition = (*list)->numItems;
+
+ return ITEMPTR (list, itemPosition - 1);
+}
+
+/*******************************/
+
+/*
+ * returns a pointer the lists data (abstraction violation for
+ * optimization)
+ */
+void *ListGetDataPtr (list_t list)
+{
+ return &((*list)->itemList[0]);
+}
+
+/********************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+int ListApplyToEach (list_t list, int ascending,
+ ListApplicationFunc funcToApply,
+ void *callbackData)
+{
+ int result = 0, index;
+
+ if (!list || !funcToApply)
+ goto Error;
+
+ if (ascending) {
+ for (index = 1; index <= ListNumItems (list); index++) {
+ result = funcToApply (index,
+ ListGetPtrToItem (list, index),
+ callbackData);
+ if (result < 0)
+ goto Error;
+ }
+ } else {
+ for (index = ListNumItems (list);
+ index > 0 && index <= ListNumItems (list);
+ index--) {
+ result = funcToApply (index,
+ ListGetPtrToItem (list, index),
+ callbackData);
+ if (result < 0)
+ goto Error;
+ }
+ }
+
+Error:
+ return result;
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
+
+/********************************/
+
+int ListGetItemSize (list_t list)
+{
+ return (*list)->itemSize;
+}
+
+/********************************/
+
+int ListNumItems (list_t list)
+{
+ return (*list)->numItems;
+}
+
+/*******************************/
+
+#ifdef CFG_ALL_LIST_FUNCTIONS
+
+void ListRemoveDuplicates (list_t list, CompareFunction compareFunction)
+{
+ int numItems, index, startIndexForFind, duplicatesIndex;
+
+ numItems = ListNumItems (list);
+
+ for (index = 1; index < numItems; index++) {
+ startIndexForFind = index + 1;
+ while (startIndexForFind <= numItems) {
+ duplicatesIndex =
+ ListFindItem (list,
+ ListGetPtrToItem (list, index),
+ startIndexForFind,
+ compareFunction);
+ if (duplicatesIndex > 0) {
+ ListRemoveItem (list, NULL, duplicatesIndex);
+ numItems--;
+ startIndexForFind = duplicatesIndex;
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+/*******************************/
+
+
+/*******************************/
+
+int ListFindItem (list_t list, void *ptrToItem, int startingPosition,
+ CompareFunction compareFunction)
+{
+ int numItems, size, index, cmp;
+ void *listItemPtr;
+
+ if ((numItems = (*list)->numItems) == 0)
+ return 0;
+
+ size = (*list)->itemSize;
+
+ if (startingPosition == LIST_START)
+ startingPosition = 1;
+ else if (startingPosition == LIST_END)
+ startingPosition = numItems;
+
+ for (index = startingPosition; index <= numItems; index++) {
+ listItemPtr = ITEMPTR (list, index - 1);
+ cmp = compareFunction
+ ? compareFunction (ptrToItem, listItemPtr)
+ : ListMemBlockCmp (ptrToItem, listItemPtr, size);
+ if (cmp == 0)
+ return index;
+ }
+
+ return 0;
+}
+
+/*******************************/
+
+int ShortCompare (void *a, void *b)
+{
+ if (*(short *) a < *(short *) b)
+ return -1;
+ if (*(short *) a > *(short *) b)
+ return 1;
+ return 0;
+}
+
+/*******************************/
+
+int IntCompare (void *a, void *b)
+{
+ if (*(int *) a < *(int *) b)
+ return -1;
+ if (*(int *) a > *(int *) b)
+ return 1;
+ return 0;
+}
+
+/*******************************/
+
+int CStringCompare (void *a, void *b)
+{
+ return strcmp (*(char **) a, *(char **) b);
+}
+
+/*******************************/
+
+
+int ListBinSearch (list_t list, void *ptrToItem,
+ CompareFunction compareFunction)
+{
+ int index;
+
+ index = BinSearch (ITEMPTR (list, 0),
+ (int) (*list)->numItems,
+ (int) (*list)->itemSize, ptrToItem,
+ compareFunction);
+
+ if (index >= 0)
+ index++; /* lists start from 1 */
+ else
+ index = 0; /* item not found */
+
+ return index;
+}
+
+/**************************************************************************/
+
+/*
+ * Reserves memory for numItems in the list. If it succeeds then
+ * numItems items can be inserted without possibility of an out of
+ * memory error (useful to simplify error recovery in complex
+ * functions). Returns 1 if success, 0 if out of memory.
+ */
+int ListPreAllocate (list_t list, int numItems)
+{
+ if ((*list)->listSize - (*list)->numItems < numItems) {
+ return ExpandListSpace (list,
+ numItems - ((*list)->listSize -
+ (*list)->numItems));
+ } else {
+ return 1; /* enough items are already pre-allocated */
+ }
+}
+
+#endif /* CFG_ALL_LIST_FUNCTIONS */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This provides a bit-banged interface to the ethernet MII management
+ * channel.
+ */
+
+#include <common.h>
+#include <ioports.h>
+#include <ppc_asm.tmpl>
+
+#ifdef CONFIG_BITBANGMII
+
+
+/*****************************************************************************
+ *
+ * Utility to send the preamble, address, and register (common to read
+ * and write).
+ */
+static void miiphy_pre(char read,
+ unsigned char addr,
+ unsigned char reg)
+{
+ int j; /* counter */
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+ /*
+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
+ * The IEEE spec says this is a PHY optional requirement. The AMD
+ * 79C874 requires one after power up and one after a MII communications
+ * error. This means that we are doing more preambles than we need,
+ * but it is safer and will be much more robust.
+ */
+
+ MDIO_ACTIVE;
+ MDIO(1);
+ for(j = 0; j < 32; j++)
+ {
+ MDC(0);
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+ }
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
+ MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
+ MDC(0); MDIO(read); MIIDELAY; MDC(1); MIIDELAY;
+ MDC(0); MDIO(!read); MIIDELAY; MDC(1); MIIDELAY;
+
+ /* send the PHY address */
+ for(j = 0; j < 5; j++)
+ {
+ MDC(0);
+ if((addr & 0x10) == 0)
+ {
+ MDIO(0);
+ }
+ else
+ {
+ MDIO(1);
+ }
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+ addr <<= 1;
+ }
+
+ /* send the register address */
+ for(j = 0; j < 5; j++)
+ {
+ MDC(0);
+ if((reg & 0x10) == 0)
+ {
+ MDIO(0);
+ }
+ else
+ {
+ MDIO(1);
+ }
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+ reg <<= 1;
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * Read a MII PHY register.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_read(unsigned char addr,
+ unsigned char reg,
+ unsigned short *value)
+{
+ short rdreg; /* register working value */
+ int j; /* counter */
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+ miiphy_pre(1, addr, reg);
+
+ /* tri-state our MDIO I/O pin so we can read */
+ MDC(0);
+ MDIO_TRISTATE;
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+
+ /* check the turnaround bit: the PHY should be driving it to zero */
+ if(MDIO_READ != 0)
+ {
+ /* printf("PHY didn't drive TA low\n"); */
+ for(j = 0; j < 32; j++)
+ {
+ MDC(0);
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+ }
+ return(-1);
+ }
+
+ MDC(0);
+ MIIDELAY;
+
+ /* read 16 bits of register data, MSB first */
+ rdreg = 0;
+ for(j = 0; j < 16; j++)
+ {
+ MDC(1);
+ MIIDELAY;
+ rdreg <<= 1;
+ rdreg |= MDIO_READ;
+ MDC(0);
+ MIIDELAY;
+ }
+
+ MDC(1);
+ MIIDELAY;
+ MDC(0);
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+
+ *value = rdreg;
+
+#ifdef DEBUG
+ printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
+#endif
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ *
+ * Write a MII PHY register.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_write(unsigned char addr,
+ unsigned char reg,
+ unsigned short value)
+{
+ int j; /* counter */
+ volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, MDIO_PORT);
+
+ miiphy_pre(0, addr, reg);
+
+ /* send the turnaround (10) */
+ MDC(0); MDIO(1); MIIDELAY; MDC(1); MIIDELAY;
+ MDC(0); MDIO(0); MIIDELAY; MDC(1); MIIDELAY;
+
+ /* write 16 bits of register data, MSB first */
+ for(j = 0; j < 16; j++)
+ {
+ MDC(0);
+ if((value & 0x00008000) == 0)
+ {
+ MDIO(0);
+ }
+ else
+ {
+ MDIO(1);
+ }
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+ value <<= 1;
+ }
+
+ /*
+ * Tri-state the MDIO line.
+ */
+ MDIO_TRISTATE;
+ MDC(0);
+ MIIDELAY;
+ MDC(1);
+ MIIDELAY;
+
+ return 0;
+}
+
+#endif /* CONFIG_BITBANGMII */
+
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <s_record.h>
+
+static int hex1_bin (char c);
+static int hex2_bin (char *s);
+
+int srec_decode (char *input, int *count, ulong *addr, char *data)
+{
+ int i;
+ int v; /* conversion buffer */
+ int srec_type; /* S-Record type */
+ unsigned char chksum; /* buffer for checksum */
+
+ chksum = 0;
+
+ /* skip anything before 'S', and the 'S' itself.
+ * Return error if not found
+ */
+
+ for (; *input; ++input) {
+ if (*input == 'S') { /* skip 'S' */
+ ++input;
+ break;
+ }
+ }
+ if (*input == '\0') { /* no more data? */
+ return (SREC_EMPTY);
+ }
+
+ v = *input++; /* record type */
+
+ if ((*count = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ chksum += *count;
+ input += 2;
+
+ switch (v) { /* record type */
+
+ case '0': /* start record */
+ srec_type = SREC_START; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '1':
+ srec_type = SREC_DATA2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ case '2':
+ srec_type = SREC_DATA3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '3': /* data record with a */
+ srec_type = SREC_DATA4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+/*** case '4' ***/
+ case '5': /* count record, addr field contains */
+ srec_type = SREC_COUNT; /* a 2 byte record counter */
+ *count = 0; /* no data */
+ break;
+/*** case '6' -- not used ***/
+ case '7': /* end record with a */
+ srec_type = SREC_END4; /* 4 byte addr field */
+ *count -= 5; /* - checksum and addr */
+ break;
+ case '8': /* end record with a */
+ srec_type = SREC_END3; /* 3 byte addr field */
+ *count -= 4; /* - checksum and addr */
+ break;
+ case '9': /* end record with a */
+ srec_type = SREC_END2; /* 2 byte addr field */
+ *count -= 3; /* - checksum and addr */
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* read address field */
+ *addr = 0;
+
+ switch (v) {
+ case '3': /* 4 byte addr field */
+ case '7':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '2': /* 3 byte addr field */
+ case '8':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+ /* FALL THRU */
+ case '0': /* 2 byte addr field */
+ case '1':
+ case '5':
+ case '9':
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ *addr <<= 8;
+ *addr += v;
+ chksum += v;
+ input += 2;
+
+ break;
+ default:
+ return (SREC_E_BADTYPE);
+ }
+
+ /* convert data and calculate checksum */
+ for (i=0; i < *count; ++i) {
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+ data[i] = v;
+ chksum += v;
+ input += 2;
+ }
+
+ /* read anc check checksum */
+ if ((v = hex2_bin(input)) < 0) {
+ return (SREC_E_NOSREC);
+ }
+
+ if ((unsigned char)v != (unsigned char)~chksum) {
+ return (SREC_E_BADCHKS);
+ }
+
+ return (srec_type);
+}
+
+static int hex1_bin (char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c + 10 - 'a');
+ if (c >= 'A' && c <= 'F')
+ return (c + 10 - 'A');
+ return (-1);
+}
+
+static int hex2_bin (char *s)
+{
+ int i, j;
+
+ if ((i = hex1_bin(*s++)) < 0) {
+ return (-1);
+ }
+ if ((j = hex1_bin(*s)) < 0) {
+ return (-1);
+ }
+
+ return ((i<<4) + j);
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Most of this source has been derived from the Linux USB
+ * project.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+
+/*
+ * How it works:
+ *
+ * Since this is a bootloader, the devices will not be automatic
+ * (re)configured on hotplug, but after a restart of the USB the
+ * device should work.
+ *
+ * For each transfer (except "Interrupt") we wait for completion.
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+
+#include <usb.h>
+#ifdef CONFIG_4xx
+#include <405gp_pci.h>
+#endif
+
+
+
+#undef USB_DEBUG
+
+#ifdef USB_DEBUG
+#define USB_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_PRINTF(fmt,args...)
+#endif
+
+static struct usb_device usb_dev[USB_MAX_DEVICE];
+static int dev_index;
+static int running;
+static int asynch_allowed;
+static struct devrequest setup_packet;
+
+/**********************************************************************
+ * some forward declerations...
+ */
+void usb_scan_devices(void);
+
+int usb_hub_probe(struct usb_device *dev, int ifnum);
+void usb_hub_reset(void);
+
+/***********************************************************************
+ * wait_ms
+ */
+
+void __inline__ wait_ms(unsigned long ms)
+{
+ while(ms-->0)
+ udelay(1000);
+}
+/***************************************************************************
+ * Init USB Device
+ */
+
+int usb_init(void)
+{
+ int result;
+
+ running=0;
+ dev_index=0;
+ asynch_allowed=1;
+ usb_hub_reset();
+ /* init low_level USB */
+ printf("USB: ");
+ result = usb_lowlevel_init();
+ /* if lowlevel init is OK, scan the bus for devices i.e. search HUBs and configure them */
+ if(result==0) {
+ printf("scanning bus for devices... ");
+ running=1;
+ usb_scan_devices();
+ return 0;
+ }
+ else {
+ printf("Error, couldn't init Lowlevel part\n");
+ return -1;
+ }
+}
+
+/******************************************************************************
+ * Stop USB this stops the LowLevel Part and deregisters USB devices.
+ */
+int usb_stop(void)
+{
+ asynch_allowed=1;
+ usb_hub_reset();
+ return usb_lowlevel_stop();
+}
+
+/*
+ * disables the asynch behaviour of the control message. This is used for data
+ * transfers that uses the exclusiv access to the control and bulk messages.
+ */
+void usb_disable_asynch(int disable)
+{
+ asynch_allowed=!disable;
+}
+
+
+/*-------------------------------------------------------------------
+ * Message wrappers.
+ *
+ */
+
+/*
+ * submits an Interrupt Message
+ */
+int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer,int transfer_len, int interval)
+{
+ return submit_int_msg(dev,pipe,buffer,transfer_len,interval);
+}
+
+/*
+ * submits a control message and waits for comletion (at least timeout * 1ms)
+ * If timeout is 0, we don't wait for completion (used as example to set and
+ * clear keyboards LEDs). For data transfers, (storage transfers) we don't
+ * allow control messages with 0 timeout, by previousely resetting the flag
+ * asynch_allowed (usb_disable_asynch(1)).
+ * returns the transfered length if OK or -1 if error. The transfered length
+ * and the current status are stored in the dev->act_len and dev->status.
+ */
+int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+ unsigned char request, unsigned char requesttype,
+ unsigned short value, unsigned short index,
+ void *data, unsigned short size, int timeout)
+{
+ if((timeout==0)&&(!asynch_allowed)) /* request for a asynch control pipe is not allowed */
+ return -1;
+ /* set setup command */
+ setup_packet.requesttype = requesttype;
+ setup_packet.request = request;
+ setup_packet.value = swap_16(value);
+ setup_packet.index = swap_16(index);
+ setup_packet.length = swap_16(size);
+ USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X\nvalue 0x%X index 0x%X length 0x%X\n",
+ request,requesttype,value,index,size);
+ dev->status=USB_ST_NOT_PROC; /*not yet processed */
+
+ submit_control_msg(dev,pipe,data,size,&setup_packet);
+ if(timeout==0) {
+ return (int)size;
+ }
+ while(timeout--) {
+ if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ wait_ms(1);
+ }
+ if(dev->status==0)
+ return dev->act_len;
+ else {
+ return -1;
+ }
+}
+
+/*-------------------------------------------------------------------
+ * submits bulk message, and waits for completion. returns 0 if Ok or
+ * -1 if Error.
+ * synchronous behavior
+ */
+int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ if (len < 0)
+ return -1;
+ dev->status=USB_ST_NOT_PROC; /*not yet processed */
+ submit_bulk_msg(dev,pipe,data,len);
+ while(timeout--) {
+ if(!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
+ break;
+ wait_ms(1);
+ }
+ *actual_length=dev->act_len;
+ if(dev->status==0)
+ return 0;
+ else
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------
+ * Max Packet stuff
+ */
+
+/*
+ * returns the max packet size, depending on the pipe direction and
+ * the configurations values
+ */
+int usb_maxpacket(struct usb_device *dev,unsigned long pipe)
+{
+ if((pipe & USB_DIR_IN)==0) /* direction is out -> use emaxpacket out */
+ return(dev->epmaxpacketout[((pipe>>15) & 0xf)]);
+ else
+ return(dev->epmaxpacketin[((pipe>>15) & 0xf)]);
+}
+
+/*
+ * set the max packed value of all endpoints in the given configuration
+ */
+int usb_set_maxpacket(struct usb_device *dev)
+{
+ int i,ii,b;
+ struct usb_endpoint_descriptor *ep;
+
+ for(i=0; i<dev->config.bNumInterfaces;i++) {
+ for(ii=0; ii<dev->config.if_desc[i].bNumEndpoints; ii++) {
+ ep=&dev->config.if_desc[i].ep_desc[ii];
+ b=ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+ if((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)==USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
+ dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+ dev->epmaxpacketin [b] = ep->wMaxPacketSize;
+ USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",b,dev->epmaxpacketin[b]);
+ }
+ else {
+ if ((ep->bEndpointAddress & 0x80)==0) { /* OUT Endpoint */
+ if(ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
+ dev->epmaxpacketout[b] = ep->wMaxPacketSize;
+ USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",b,dev->epmaxpacketout[b]);
+ }
+ }
+ else { /* IN Endpoint */
+ if(ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
+ dev->epmaxpacketin[b] = ep->wMaxPacketSize;
+ USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",b,dev->epmaxpacketin[b]);
+ }
+ } /* if out */
+ } /* if control */
+ } /* for each endpoint */
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * Parse the config, located in buffer, and fills the dev->config structure.
+ * Note that all little/big endian swapping are done automatically.
+ */
+int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno)
+{
+ struct usb_descriptor_header *head;
+ int index,ifno,epno;
+ ifno=-1;
+ epno=-1;
+
+ dev->configno=cfgno;
+ head =(struct usb_descriptor_header *)&buffer[0];
+ if(head->bDescriptorType!=USB_DT_CONFIG) {
+ printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
+ return -1;
+ }
+ memcpy(&dev->config,buffer,buffer[0]);
+ dev->config.wTotalLength=swap_16(dev->config.wTotalLength);
+ dev->config.no_of_if=0;
+
+ index=dev->config.bLength;
+ /* Ok the first entry must be a configuration entry, now process the others */
+ head=(struct usb_descriptor_header *)&buffer[index];
+ while(index+1 < dev->config.wTotalLength) {
+ switch(head->bDescriptorType) {
+ case USB_DT_INTERFACE:
+ ifno=dev->config.no_of_if;
+ dev->config.no_of_if++; /* found an interface desc, increase numbers */
+ memcpy(&dev->config.if_desc[ifno],&buffer[index],buffer[index]); /* copy new desc */
+ dev->config.if_desc[ifno].no_of_ep=0;
+
+ break;
+ case USB_DT_ENDPOINT:
+ epno=dev->config.if_desc[ifno].no_of_ep;
+ dev->config.if_desc[ifno].no_of_ep++; /* found an endpoint */
+ memcpy(&dev->config.if_desc[ifno].ep_desc[epno],&buffer[index],buffer[index]);
+ dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize
+ =swap_16(dev->config.if_desc[ifno].ep_desc[epno].wMaxPacketSize);
+ USB_PRINTF("if %d, ep %d\n",ifno,epno);
+ break;
+ default:
+ if(head->bLength==0)
+ return 1;
+ USB_PRINTF("unknown Description Type : %x\n",head->bDescriptorType);
+ {
+ int i;
+ unsigned char *ch;
+ ch=(unsigned char *)head;
+ for(i=0;i<head->bLength; i++)
+ USB_PRINTF("%02X ",*ch++);
+ USB_PRINTF("\n\n\n");
+ }
+ break;
+ }
+ index+=head->bLength;
+ head=(struct usb_descriptor_header *)&buffer[index];
+ }
+ return 1;
+}
+
+/***********************************************************************
+ * Clears an endpoint
+ * endp: endpoint number in bits 0-3;
+ * direction flag in bit 7 (1 = IN, 0 = OUT)
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
+{
+ int result;
+ unsigned short status;
+ int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, USB_CNTL_TIMEOUT * 3);
+
+ /* don't clear if failed */
+ if (result < 0)
+ return result;
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
+ &status, sizeof(status), USB_CNTL_TIMEOUT * 3);
+ if (result < 0)
+ return result;
+ USB_PRINTF("usb_clear_halt: status 0x%x\n",status);
+ if (status & 1)
+ return -1; /* still halted */
+ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+ /* toggle is reset on clear */
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+ return 0;
+}
+
+
+/**********************************************************************
+ * get_descriptor type
+ */
+int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+{
+ int res;
+ res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (type << 8) + index, 0,
+ buf, size, USB_CNTL_TIMEOUT);
+ return res;
+}
+
+/**********************************************************************
+ * gets configuration cfgno and store it in the buffer
+ */
+int usb_get_configuration_no(struct usb_device *dev,unsigned char *buffer,int cfgno)
+{
+ int result;
+ unsigned int tmp;
+ struct usb_config_descriptor *config;
+
+
+ config=(struct usb_config_descriptor *)&buffer[0];
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
+ if (result < 8) {
+ if (result < 0)
+ printf("unable to get descriptor, error %lX\n",dev->status);
+ else
+ printf("config descriptor too short (expected %i, got %i)\n",8,result);
+ return -1;
+ }
+ tmp=swap_16(config->wTotalLength);
+
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp);
+ USB_PRINTF("get_conf_no %d Result %d, wLength %d\n",cfgno,result,tmp);
+ return result;
+}
+
+/********************************************************************
+ * set address of a device to the value in dev->devnum.
+ * This can only be done by addressing the device via the default address (0)
+ */
+int usb_set_address(struct usb_device *dev)
+{
+ int res;
+
+ USB_PRINTF("set address %d\n",dev->devnum);
+ res=usb_control_msg(dev, usb_snddefctrl(dev),
+ USB_REQ_SET_ADDRESS, 0,
+ (dev->devnum),0,
+ NULL,0, USB_CNTL_TIMEOUT);
+ return res;
+}
+
+/********************************************************************
+ * set interface number to interface
+ */
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+ struct usb_interface_descriptor *if_face = NULL;
+ int ret, i;
+
+ for (i=0; i<dev->config.bNumInterfaces; i++) {
+ if (dev->config.if_desc[i].bInterfaceNumber == interface) {
+ if_face = &dev->config.if_desc[i];
+ break;
+ }
+ }
+ if (!if_face) {
+ printf("selecting invalid interface %d", interface);
+ return -1;
+ }
+
+ if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
+ interface, NULL, 0, USB_CNTL_TIMEOUT * 5)) < 0)
+ return ret;
+
+ if_face->act_altsetting = (unsigned char)alternate;
+ usb_set_maxpacket(dev);
+ return 0;
+}
+
+/********************************************************************
+ * set configuration number to configuration
+ */
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+ int res;
+ USB_PRINTF("set configuration %d\n",configuration);
+ /* set setup command */
+ res=usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+ USB_REQ_SET_CONFIGURATION, 0,
+ configuration,0,
+ NULL,0, USB_CNTL_TIMEOUT);
+ if(res==0) {
+ dev->toggle[0] = 0;
+ dev->toggle[1] = 0;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+/********************************************************************
+ * set protocol to protocol
+ */
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * set idle
+ */
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get report
+ */
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get class descriptor
+ */
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+ unsigned char type, unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+ (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * get string index in buffer
+ */
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid, buf, size, USB_CNTL_TIMEOUT);
+}
+
+/********************************************************************
+ * usb_string:
+ * Get string index and translate it to ascii.
+ * returns string length (> 0) or error (< 0)
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+
+ unsigned char mybuf[256];
+ unsigned char *tbuf;
+ int err;
+ unsigned int u, idx;
+
+ if (size <= 0 || !buf || !index)
+ return -1;
+ buf[0] = 0;
+ tbuf=&mybuf[0];
+
+ /* get langid for strings if it's not yet known */
+ if (!dev->have_langid) {
+ err = usb_get_string(dev, 0, 0, tbuf, 4);
+ if (err < 0) {
+ USB_PRINTF("error getting string descriptor 0 (error=%x)\n",dev->status);
+ return -1;
+ } else if (tbuf[0] < 4) {
+ USB_PRINTF("string descriptor 0 too short\n");
+ return -1;
+ } else {
+ dev->have_langid = -1;
+ dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+ /* always use the first langid listed */
+ USB_PRINTF("USB device number %d default language ID 0x%x\n",
+ dev->devnum, dev->string_langid);
+ }
+ }
+ /* Just ask for a maximum length string and then take the length
+ * that was returned. */
+ err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
+ if (err < 0)
+ return err;
+ u=tbuf[0];
+ USB_PRINTF("Strn Len %d, index %d\n",u,index);
+ err = usb_get_string(dev, dev->string_langid, index, tbuf, u);
+ if (err < 0)
+ return err;
+ size--; /* leave room for trailing NULL char in output buffer */
+ for (idx = 0, u = 2; u < err; u += 2) {
+ if (idx >= size)
+ break;
+ if (tbuf[u+1]) /* high byte */
+ buf[idx++] = '?'; /* non-ASCII character */
+ else
+ buf[idx++] = tbuf[u];
+ }
+ buf[idx] = 0;
+ err = idx;
+ return err;
+}
+
+
+/********************************************************************
+ * USB device handling:
+ * the USB device are static allocated [USB_MAX_DEVICE].
+ */
+
+
+/* returns a pointer to the device with the index [index].
+ * if the device is not assigned (dev->devnum==-1) returns NULL
+ */
+struct usb_device * usb_get_dev_index(int index)
+{
+ if(usb_dev[index].devnum==-1)
+ return NULL;
+ else
+ return &usb_dev[index];
+}
+
+
+/* returns a pointer of a new device structure or NULL, if
+ * no device struct is available
+ */
+struct usb_device * usb_alloc_new_device(void)
+{
+ int i;
+ USB_PRINTF("New Device %d\n",dev_index);
+ if(dev_index==USB_MAX_DEVICE) {
+ printf("ERROR, to many USB Devices max=%d\n",USB_MAX_DEVICE);
+ return NULL;
+ }
+ usb_dev[dev_index].devnum=dev_index+1; /* default Address is 0, real addresses start with 1 */
+ usb_dev[dev_index].maxchild=0;
+ for(i=0;i<USB_MAXCHILDREN;i++)
+ usb_dev[dev_index].children[i]=NULL;
+ usb_dev[dev_index].parent=NULL;
+ dev_index++;
+ return &usb_dev[dev_index-1];
+}
+
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+ int addr, err;
+ int tmp;
+ unsigned char tmpbuf[256];
+
+ dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */
+ dev->maxpacketsize = 0; /* Default to 8 byte max packet size */
+ dev->epmaxpacketin [0] = 8;
+ dev->epmaxpacketout[0] = 8;
+
+ /* We still haven't set the Address yet */
+ addr = dev->devnum;
+ dev->devnum = 0;
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+ if (err < 8) {
+ printf("\n USB device not responding, giving up (status=%lX)\n",dev->status);
+ return 1;
+ }
+ dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+ switch (dev->descriptor.bMaxPacketSize0) {
+ case 8: dev->maxpacketsize = 0; break;
+ case 16: dev->maxpacketsize = 1; break;
+ case 32: dev->maxpacketsize = 2; break;
+ case 64: dev->maxpacketsize = 3; break;
+ }
+ dev->devnum = addr;
+
+ err = usb_set_address(dev); /* set address */
+
+ if (err < 0) {
+ printf("\n USB device not accepting new address (error=%lX)\n", dev->status);
+ return 1;
+ }
+
+ wait_ms(10); /* Let the SET_ADDRESS settle */
+
+ tmp = sizeof(dev->descriptor);
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
+ if (err < tmp) {
+ if (err < 0)
+ printf("unable to get device descriptor (error=%d)\n",err);
+ else
+ printf("USB device descriptor short read (expected %i, got %i)\n",tmp,err);
+ return 1;
+ }
+ /* correct le values */
+ dev->descriptor.bcdUSB=swap_16(dev->descriptor.bcdUSB);
+ dev->descriptor.idVendor=swap_16(dev->descriptor.idVendor);
+ dev->descriptor.idProduct=swap_16(dev->descriptor.idProduct);
+ dev->descriptor.bcdDevice=swap_16(dev->descriptor.bcdDevice);
+ /* only support for one config for now */
+ usb_get_configuration_no(dev,&tmpbuf[0],0);
+ usb_parse_config(dev,&tmpbuf[0],0);
+ usb_set_maxpacket(dev);
+ /* we set the default configuration here */
+ if (usb_set_configuration(dev, dev->config.bConfigurationValue)) {
+ printf("failed to set default configuration len %d, status %lX\n",dev->act_len,dev->status);
+ return -1;
+ }
+ USB_PRINTF("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+ memset(dev->mf, 0, sizeof(dev->mf));
+ memset(dev->prod, 0, sizeof(dev->prod));
+ memset(dev->serial, 0, sizeof(dev->serial));
+ if (dev->descriptor.iManufacturer)
+ usb_string(dev, dev->descriptor.iManufacturer, dev->mf, sizeof(dev->mf));
+ if (dev->descriptor.iProduct)
+ usb_string(dev, dev->descriptor.iProduct, dev->prod, sizeof(dev->prod));
+ if (dev->descriptor.iSerialNumber)
+ usb_string(dev, dev->descriptor.iSerialNumber, dev->serial, sizeof(dev->serial));
+ USB_PRINTF("Manufacturer %s\n", dev->mf);
+ USB_PRINTF("Product %s\n", dev->prod);
+ USB_PRINTF("SerialNumber %s\n", dev->serial);
+ /* now prode if the device is a hub */
+ usb_hub_probe(dev,0);
+ return 0;
+}
+
+/* build device Tree */
+void usb_scan_devices(void)
+{
+ int i;
+ struct usb_device *dev;
+
+ /* first make all devices unknown */
+ for(i=0;i<USB_MAX_DEVICE;i++) {
+ memset(&usb_dev[i],0,sizeof(struct usb_device));
+ usb_dev[i].devnum=-1;
+ }
+ dev_index=0;
+ /* device 0 is always present (root hub, so let it analyze) */
+ dev=usb_alloc_new_device();
+ usb_new_device(dev);
+ printf("%d USB Devices found\n",dev_index);
+ /* insert "driver" if possible */
+#ifdef CONFIG_USB_KEYBOARD
+ drv_usb_kbd_init();
+ USB_PRINTF("scan end\n");
+#endif
+}
+
+
+/****************************************************************************
+ * HUB "Driver"
+ * Probes device for being a hub and configurate it
+ */
+
+#undef USB_HUB_DEBUG
+
+#ifdef USB_HUB_DEBUG
+#define USB_HUB_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_HUB_PRINTF(fmt,args...)
+#endif
+
+
+static struct usb_hub_device hub_dev[USB_MAX_HUB];
+static int usb_hub_index;
+
+
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+ USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_hub_feature(struct usb_device *dev, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+
+static void usb_hub_power_on(struct usb_hub_device *hub)
+{
+ int i;
+ struct usb_device *dev;
+
+ dev=hub->pusb_dev;
+ /* Enable power to the ports */
+ USB_HUB_PRINTF("enabling power on all ports\n");
+ for (i = 0; i < dev->maxchild; i++) {
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ USB_HUB_PRINTF("port %d returns %lX\n",i+1,dev->status);
+ wait_ms(hub->desc.bPwrOn2PwrGood * 2);
+ }
+}
+
+void usb_hub_reset(void)
+{
+ usb_hub_index=0;
+}
+
+struct usb_hub_device *usb_hub_allocate(void)
+{
+ if(usb_hub_index<USB_MAX_HUB) {
+ return &hub_dev[usb_hub_index++];
+ }
+ printf("ERROR: USB_MAX_HUB (%d) reached\n",USB_MAX_HUB);
+ return NULL;
+}
+
+#define MAX_TRIES 5
+
+void usb_hub_port_connect_change(struct usb_device *dev, int port)
+{
+ struct usb_device *usb;
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+ int tries;
+
+ /* Check status */
+ if (usb_get_port_status(dev, port + 1, &portsts)<0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ return;
+ }
+
+ portstatus = swap_16(portsts.wPortStatus);
+ portchange = swap_16(portsts.wPortChange);
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus, portchange,
+ portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+
+ /* Clear the connection change status */
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+ /* Disconnect any existing devices under this port */
+ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+ (!(portstatus & USB_PORT_STAT_ENABLE)))|| (dev->children[port])) {
+ USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
+ /* Return now if nothing is connected */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return;
+ }
+ wait_ms(200);
+
+ /* Reset the port */
+
+ for(tries=0;tries<MAX_TRIES;tries++) {
+
+ usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
+ wait_ms(200);
+
+ if (usb_get_port_status(dev, port + 1, &portsts)<0) {
+ USB_HUB_PRINTF("get_port_status failed status %lX\n",dev->status);
+ return;
+ }
+ portstatus = swap_16(portsts.wPortStatus);
+ portchange = swap_16(portsts.wPortChange);
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n", portstatus ,portchange,
+ portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
+ USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d USB_PORT_STAT_ENABLE %d\n",
+ (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
+ if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+ !(portstatus & USB_PORT_STAT_CONNECTION))
+ return;
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ break;
+
+ wait_ms(200);
+ }
+
+ if (tries==MAX_TRIES) {
+ USB_HUB_PRINTF("Cannot enable port %i after %i retries, disabling port.\n", port+1, MAX_TRIES);
+ USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
+ return;
+ }
+
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
+ wait_ms(200);
+
+ /* Allocate a new device struct for it */
+ usb=usb_alloc_new_device();
+ usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+
+ dev->children[port] = usb;
+ usb->parent=dev;
+ /* Run it through the hoops (find a driver, etc) */
+ if (usb_new_device(usb)) {
+ /* Woops, disable the port */
+ USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+ }
+}
+
+
+int usb_hub_configure(struct usb_device *dev)
+{
+ unsigned char buffer[256], *bitmap;
+ struct usb_hub_descriptor *descriptor;
+ struct usb_hub_status *hubsts;
+ int i;
+ struct usb_hub_device *hub;
+
+ /* "allocate" Hub device */
+ hub=usb_hub_allocate();
+ if(hub==NULL)
+ return -1;
+ hub->pusb_dev=dev;
+ /* Get the the hub descriptor */
+ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor, giving up %lX\n",dev->status);
+ return -1;
+ }
+ descriptor = (struct usb_hub_descriptor *)buffer;
+ if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get hub descriptor 2nd giving up %lX\n",dev->status);
+ return -1;
+ }
+ memcpy((unsigned char *)&hub->desc,buffer,descriptor->bLength);
+ /* adjust 16bit values */
+ hub->desc.wHubCharacteristics=swap_16(descriptor->wHubCharacteristics);
+ /* set the bitmap */
+ bitmap=(unsigned char *)&hub->desc.DeviceRemovable[0];
+ memset(bitmap,0xff,(USB_MAXCHILDREN+1+7)/8); /* devices not removable by default */
+ bitmap=(unsigned char *)&hub->desc.PortPowerCtrlMask[0];
+ memset(bitmap,0xff,(USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
+ for(i=0;i<((hub->desc.bNbrPorts + 1 + 7)/8);i++) {
+ hub->desc.DeviceRemovable[i]=descriptor->DeviceRemovable[i];
+ }
+ for(i=0;i<((hub->desc.bNbrPorts + 1 + 7)/8);i++) {
+ hub->desc.DeviceRemovable[i]=descriptor->PortPowerCtrlMask[i];
+ }
+ dev->maxchild = descriptor->bNbrPorts;
+ USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
+ case 0x00:
+ USB_HUB_PRINTF("ganged power switching\n");
+ break;
+ case 0x01:
+ USB_HUB_PRINTF("individual port power switching\n");
+ break;
+ case 0x02:
+ case 0x03:
+ USB_HUB_PRINTF("unknown reserved power switching mode\n");
+ break;
+ }
+
+ if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
+ USB_HUB_PRINTF("part of a compound device\n");
+ else
+ USB_HUB_PRINTF("standalone hub\n");
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
+ case 0x00:
+ USB_HUB_PRINTF("global over-current protection\n");
+ break;
+ case 0x08:
+ USB_HUB_PRINTF("individual port over-current protection\n");
+ break;
+ case 0x10:
+ case 0x18:
+ USB_HUB_PRINTF("no over-current protection\n");
+ break;
+ }
+ USB_HUB_PRINTF("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2);
+ USB_HUB_PRINTF("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent);
+ for (i = 0; i < dev->maxchild; i++)
+ USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
+ hub->desc.DeviceRemovable[(i + 1)/8] & (1 << ((i + 1)%8)) ? " not" : "");
+ if (usb_get_hub_status(dev, buffer) < 0) {
+ USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",dev->status);
+ return -1;
+ }
+ hubsts = (struct usb_hub_status *)buffer;
+ USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
+ swap_16(hubsts->wHubStatus),swap_16(hubsts->wHubChange));
+ USB_HUB_PRINTF("local power source is %s\n",
+ (swap_16(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+ USB_HUB_PRINTF("%sover-current condition exists\n",
+ (swap_16(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+ usb_hub_power_on(hub);
+ for (i = 0; i < dev->maxchild; i++) {
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ continue;
+ }
+ portstatus = swap_16(portsts.wPortStatus);
+ portchange = swap_16(portsts.wPortChange);
+ USB_HUB_PRINTF("Port %d Status %X Change %X\n",i+1,portstatus,portchange);
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ USB_HUB_PRINTF("port %d connection change\n", i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ USB_HUB_PRINTF("port %d enable change, status %x\n", i + 1, portstatus);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+
+ /* EM interference sometimes causes bad shielded USB devices to
+ * be shutdown by the hub, this hack enables them again.
+ * Works at least with mouse driver */
+ if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
+ USB_HUB_PRINTF("already running port %i disabled by hub (EMI?), re-enabling...\n",
+ i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ }
+ if (portstatus & USB_PORT_STAT_SUSPEND) {
+ USB_HUB_PRINTF("port %d suspend change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND);
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ USB_HUB_PRINTF("port %d over-current change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+ usb_hub_power_on(hub);
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ USB_HUB_PRINTF("port %d reset change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+ }
+ } /* end for i all ports */
+
+ return 0;
+}
+
+int usb_hub_probe(struct usb_device *dev, int ifnum)
+{
+ struct usb_interface_descriptor *iface;
+ struct usb_endpoint_descriptor *ep;
+ int ret;
+
+ iface = &dev->config.if_desc[ifnum];
+ /* Is it a hub? */
+ if (iface->bInterfaceClass != USB_CLASS_HUB)
+ return 0;
+ /* Some hubs have a subclass of 1, which AFAICT according to the */
+ /* specs is not defined, but it works */
+ if ((iface->bInterfaceSubClass != 0) &&
+ (iface->bInterfaceSubClass != 1))
+ return 0;
+ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+ if (iface->bNumEndpoints != 1)
+ return 0;
+ ep = &iface->ep_desc[0];
+ /* Output endpoint? Curiousier and curiousier.. */
+ if (!(ep->bEndpointAddress & USB_DIR_IN))
+ return 0;
+ /* If it's not an interrupt endpoint, we'd better punt! */
+ if ((ep->bmAttributes & 3) != 3)
+ return 0;
+ /* We found a hub */
+ USB_HUB_PRINTF("USB hub found\n");
+ ret=usb_hub_configure(dev);
+ return ret;
+}
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_USB) */
+
+/* EOF */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Part of this source has been derived from the Linux USB
+ * project.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+#include <common.h>
+#include <devices.h>
+
+#ifdef CONFIG_USB_KEYBOARD
+
+#include <usb.h>
+
+#undef USB_KBD_DEBUG
+/*
+ * if overwrite_console returns 1, the stdin, stderr and stdout
+ * are switched to the serial port, else the settings in the
+ * environment are used
+ */
+#ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
+extern int overwrite_console (void);
+#else
+int overwrite_console (void)
+{
+ return (0);
+}
+#endif
+
+#ifdef USB_KBD_DEBUG
+#define USB_KBD_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_KBD_PRINTF(fmt,args...)
+#endif
+
+
+#define REPEAT_RATE 40/4 /* 40msec -> 25cps */
+#define REPEAT_DELAY 10 /* 10 x REAPEAT_RATE = 400msec */
+
+#define NUM_LOCK 0x53
+#define CAPS_LOCK 0x39
+#define SCROLL_LOCK 0x47
+
+
+/* Modifier bits */
+#define LEFT_CNTR 0
+#define LEFT_SHIFT 1
+#define LEFT_ALT 2
+#define LEFT_GUI 3
+#define RIGHT_CNTR 4
+#define RIGHT_SHIFT 5
+#define RIGHT_ALT 6
+#define RIGHT_GUI 7
+
+#define USB_KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
+
+static volatile char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
+static volatile int usb_in_pointer = 0;
+static volatile int usb_out_pointer = 0;
+
+unsigned char new[8];
+unsigned char old[8];
+int repeat_delay;
+#define DEVNAME "usbkbd"
+static unsigned char num_lock = 0;
+static unsigned char caps_lock = 0;
+static unsigned char scroll_lock = 0;
+
+static unsigned char leds __attribute__ ((aligned (0x4)));
+
+static unsigned char usb_kbd_numkey[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0','\r',0x1b,'\b','\t',' ', '-',
+ '=', '[', ']','\\', '#', ';', '\'', '`', ',', '.', '/'
+};
+static unsigned char usb_kbd_numkey_shifted[] = {
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')','\r',0x1b,'\b','\t',' ', '_',
+ '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'
+};
+
+/******************************************************************
+ * Queue handling
+ ******************************************************************/
+/* puts character in the queue and sets up the in and out pointer */
+static void usb_kbd_put_queue(char data)
+{
+ if((usb_in_pointer+1)==USB_KBD_BUFFER_LEN) {
+ if(usb_out_pointer==0) {
+ return; /* buffer full */
+ } else{
+ usb_in_pointer=0;
+ }
+ } else {
+ if((usb_in_pointer+1)==usb_out_pointer)
+ return; /* buffer full */
+ usb_in_pointer++;
+ }
+ usb_kbd_buffer[usb_in_pointer]=data;
+ return;
+}
+
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+ if(usb_in_pointer==usb_out_pointer)
+ return(0); /* no data */
+ else
+ return(1);
+}
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+ char c;
+ while(usb_in_pointer==usb_out_pointer);
+ if((usb_out_pointer+1)==USB_KBD_BUFFER_LEN)
+ usb_out_pointer=0;
+ else
+ usb_out_pointer++;
+ c=usb_kbd_buffer[usb_out_pointer];
+ return (int)c;
+
+}
+
+/* forward decleration */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+
+/* search for keyboard and register it if found */
+int drv_usb_kbd_init(void)
+{
+ int error,i,index;
+ device_t usb_kbd_dev,*old_dev;
+ struct usb_device *dev;
+ char *stdinname = getenv ("stdin");
+
+ usb_in_pointer=0;
+ usb_out_pointer=0;
+ /* scan all USB Devices */
+ for(i=0;i<USB_MAX_DEVICE;i++) {
+ dev=usb_get_dev_index(i); /* get device */
+ if(dev->devnum!=-1) {
+ if(usb_kbd_probe(dev,0)==1) { /* Ok, we found a keyboard */
+ /* check, if it is already registered */
+ USB_KBD_PRINTF("USB KBD found set up device.\n");
+ for (index=1; index<=ListNumItems(devlist); index++) {
+ old_dev = ListGetPtrToItem(devlist, index);
+ if(strcmp(old_dev->name,DEVNAME)==0) {
+ /* ok, already registered, just return ok */
+ USB_KBD_PRINTF("USB KBD is already registered.\n");
+ return 1;
+ }
+ }
+ /* register the keyboard */
+ USB_KBD_PRINTF("USB KBD register.\n");
+ memset (&usb_kbd_dev, 0, sizeof(device_t));
+ strcpy(usb_kbd_dev.name, DEVNAME);
+ usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ usb_kbd_dev.putc = NULL;
+ usb_kbd_dev.puts = NULL;
+ usb_kbd_dev.getc = usb_kbd_getc;
+ usb_kbd_dev.tstc = usb_kbd_testc;
+ error = device_register (&usb_kbd_dev);
+ if(error==0) {
+ /* check if this is the standard input device */
+ if(strcmp(stdinname,DEVNAME)==0) {
+ /* reassign the console */
+ if(overwrite_console()) {
+ return 1;
+ }
+ error=console_assign(stdin,DEVNAME);
+ if(error==0)
+ return 1;
+ else
+ return error;
+ }
+ return 1;
+ }
+ return error;
+ }
+ }
+ }
+ /* no USB Keyboard found */
+ return -1;
+}
+
+
+/* deregistering the keyboard */
+int usb_kbd_deregister(void)
+{
+ return device_deregister(DEVNAME);
+}
+
+/**************************************************************************
+ * Low Level drivers
+ */
+
+/* set the LEDs. Since this is used in the irq routine, the control job
+ is issued with a timeout of 0. This means, that the job is queued without
+ waiting for job completion */
+
+static void usb_kbd_setled(struct usb_device *dev)
+{
+ struct usb_interface_descriptor *iface;
+ iface = &dev->config.if_desc[0];
+ leds=0;
+ if(scroll_lock!=0)
+ leds|=1;
+ leds<<=1;
+ if(caps_lock!=0)
+ leds|=1;
+ leds<<=1;
+ if(num_lock!=0)
+ leds|=1;
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x200, iface->bInterfaceNumber,(void *)&leds, 1, 0);
+
+}
+
+
+#define CAPITAL_MASK 0x20
+/* Translate the scancode in ASCII */
+static int usb_kbd_translate(unsigned char scancode,unsigned char modifier,int pressed)
+{
+ unsigned char keycode;
+
+ if(pressed==0) {
+ /* key released */
+ repeat_delay=0;
+ return 0;
+ }
+ if(pressed==2) {
+ repeat_delay++;
+ if(repeat_delay<REPEAT_DELAY)
+ return 0;
+ repeat_delay=REPEAT_DELAY;
+ }
+ keycode=0;
+ if((scancode>3) && (scancode<0x1d)) { /* alpha numeric values */
+ keycode=scancode-4 + 0x61;
+ if(caps_lock)
+ keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+ if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) {
+ if(keycode & CAPITAL_MASK)
+ keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+ else
+ keycode|=CAPITAL_MASK; /* switch to non capital Letters */
+ }
+ }
+ if((scancode>0x1d) && (scancode<0x3A)) {
+ if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) /* shifted */
+ keycode=usb_kbd_numkey_shifted[scancode-0x1e];
+ else /* non shifted */
+ keycode=usb_kbd_numkey[scancode-0x1e];
+ }
+ if(pressed==1) {
+ if(scancode==NUM_LOCK) {
+ num_lock=~num_lock;
+ return 1;
+ }
+ if(scancode==CAPS_LOCK) {
+ caps_lock=~caps_lock;
+ return 1;
+ }
+ if(scancode==SCROLL_LOCK) {
+ scroll_lock=~scroll_lock;
+ return 1;
+ }
+ }
+ if(keycode!=0) {
+ USB_KBD_PRINTF("%c",keycode);
+ usb_kbd_put_queue(keycode);
+ }
+ return 0;
+}
+
+/* Interrupt service routine */
+static int usb_kbd_irq(struct usb_device *dev)
+{
+ int i,res;
+
+ if((dev->irq_status!=0)||(dev->irq_act_len!=8))
+ {
+ USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",dev->irq_status,dev->irq_act_len);
+ return 1;
+ }
+ res=0;
+ for (i = 2; i < 8; i++) {
+ if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) {
+ res|=usb_kbd_translate(old[i],new[0],0);
+ }
+ if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) {
+ res|=usb_kbd_translate(new[i],new[0],1);
+ }
+ }
+ if((new[2]>3) && (old[2]==new[2])) /* still pressed */
+ res|=usb_kbd_translate(new[2],new[0],2);
+ if(res==1)
+ usb_kbd_setled(dev);
+ memcpy(&old[0],&new[0], 8);
+ return 1; /* install IRQ Handler again */
+}
+
+/* probes the USB device dev for keyboard type */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_interface_descriptor *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe,maxp;
+
+ if (dev->descriptor.bNumConfigurations != 1) return 0;
+ iface = &dev->config.if_desc[ifnum];
+
+ if (iface->bInterfaceClass != 3) return 0;
+ if (iface->bInterfaceSubClass != 1) return 0;
+ if (iface->bInterfaceProtocol != 1) return 0;
+ if (iface->bNumEndpoints != 1) return 0;
+
+ ep = &iface->ep_desc[0];
+
+ if (!(ep->bEndpointAddress & 0x80)) return 0;
+ if ((ep->bmAttributes & 3) != 3) return 0;
+ USB_KBD_PRINTF("USB KBD found set protocol...\n");
+ /* ok, we found a USB Keyboard, install it */
+ /* usb_kbd_get_hid_desc(dev); */
+ usb_set_protocol(dev, iface->bInterfaceNumber, 0);
+ USB_KBD_PRINTF("USB KBD found set idle...\n");
+ usb_set_idle(dev, iface->bInterfaceNumber, REPEAT_RATE, 0);
+ memset(&new[0], 0, 8);
+ memset(&old[0], 0, 8);
+ repeat_delay=0;
+ pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe);
+ dev->irq_handle=usb_kbd_irq;
+ USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
+ usb_submit_int_msg(dev,pipe,&new[0], maxp > 8 ? 8 : maxp,ep->bInterval);
+ return 1;
+}
+
+
+#if 0
+struct usb_hid_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType; /* 0x21 for HID */
+ unsigned short bcdHID; /* release number */
+ unsigned char bCountryCode;
+ unsigned char bNumDescriptors;
+ unsigned char bReportDescriptorType;
+ unsigned short wDescriptorLength;
+} __attribute__ ((packed));
+
+/*
+ * We parse each description item into this structure. Short items data
+ * values are expanded to 32-bit signed int, long items contain a pointer
+ * into the data area.
+ */
+
+struct hid_item {
+ unsigned char format;
+ unsigned char size;
+ unsigned char type;
+ unsigned char tag;
+ union {
+ unsigned char u8;
+ char s8;
+ unsigned short u16;
+ short s16;
+ unsigned long u32;
+ long s32;
+ unsigned char *longdata;
+ } data;
+};
+
+/*
+ * HID report item format
+ */
+
+#define HID_ITEM_FORMAT_SHORT 0
+#define HID_ITEM_FORMAT_LONG 1
+
+/*
+ * Special tag indicating long items
+ */
+
+#define HID_ITEM_TAG_LONG 15
+
+
+
+static struct usb_hid_descriptor usb_kbd_hid_desc;
+
+void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
+{
+ printf("USB_HID_DESC:\n");
+ printf(" bLenght 0x%x\n",hid->bLength);
+ printf(" bcdHID 0x%x\n",hid->bcdHID);
+ printf(" bCountryCode %d\n",hid->bCountryCode);
+ printf(" bNumDescriptors 0x%x\n",hid->bNumDescriptors);
+ printf(" bReportDescriptorType 0x%x\n",hid->bReportDescriptorType);
+ printf(" wDescriptorLength 0x%x\n",hid->wDescriptorLength);
+}
+
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static int fetch_item(unsigned char *start,unsigned char *end, struct hid_item *item)
+{
+ if((end - start) > 0) {
+ unsigned char b = *start++;
+ item->type = (b >> 2) & 3;
+ item->tag = (b >> 4) & 15;
+ if (item->tag == HID_ITEM_TAG_LONG) {
+ item->format = HID_ITEM_FORMAT_LONG;
+ if ((end - start) >= 2) {
+ item->size = *start++;
+ item->tag = *start++;
+ if ((end - start) >= item->size) {
+ item->data.longdata = start;
+ start += item->size;
+ return item->size;
+ }
+ }
+ } else {
+ item->format = HID_ITEM_FORMAT_SHORT;
+ item->size = b & 3;
+ switch (item->size) {
+ case 0:
+ return item->size;
+ case 1:
+ if ((end - start) >= 1) {
+ item->data.u8 = *start++;
+ return item->size;
+ }
+ break;
+ case 2:
+ if ((end - start) >= 2) {
+ item->data.u16 = swap_16((unsigned short *)start);
+ start+=2;
+ return item->size;
+ }
+ case 3:
+ item->size++;
+ if ((end - start) >= 4) {
+ item->data.u32 = swap_32((unsigned long *)start);
+ start+=4;
+ return item->size;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+ * HID report descriptor item type (prefix bit 2,3)
+ */
+
+#define HID_ITEM_TYPE_MAIN 0
+#define HID_ITEM_TYPE_GLOBAL 1
+#define HID_ITEM_TYPE_LOCAL 2
+#define HID_ITEM_TYPE_RESERVED 3
+/*
+ * HID report descriptor main item tags
+ */
+
+#define HID_MAIN_ITEM_TAG_INPUT 8
+#define HID_MAIN_ITEM_TAG_OUTPUT 9
+#define HID_MAIN_ITEM_TAG_FEATURE 11
+#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
+#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
+/*
+ * HID report descriptor main item contents
+ */
+
+#define HID_MAIN_ITEM_CONSTANT 0x001
+#define HID_MAIN_ITEM_VARIABLE 0x002
+#define HID_MAIN_ITEM_RELATIVE 0x004
+#define HID_MAIN_ITEM_WRAP 0x008
+#define HID_MAIN_ITEM_NONLINEAR 0x010
+#define HID_MAIN_ITEM_NO_PREFERRED 0x020
+#define HID_MAIN_ITEM_NULL_STATE 0x040
+#define HID_MAIN_ITEM_VOLATILE 0x080
+#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100
+
+/*
+ * HID report descriptor collection item types
+ */
+
+#define HID_COLLECTION_PHYSICAL 0
+#define HID_COLLECTION_APPLICATION 1
+#define HID_COLLECTION_LOGICAL 2
+/*
+ * HID report descriptor global item tags
+ */
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5
+#define HID_GLOBAL_ITEM_TAG_UNIT 6
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9
+#define HID_GLOBAL_ITEM_TAG_PUSH 10
+#define HID_GLOBAL_ITEM_TAG_POP 11
+
+/*
+ * HID report descriptor local item tags
+ */
+
+#define HID_LOCAL_ITEM_TAG_USAGE 0
+#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1
+#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7
+#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8
+#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9
+#define HID_LOCAL_ITEM_TAG_DELIMITER 10
+
+
+
+static void usb_kbd_show_item(struct hid_item *item)
+{
+ switch(item->type) {
+ case HID_ITEM_TYPE_MAIN:
+ switch(item->tag) {
+ case HID_MAIN_ITEM_TAG_INPUT:
+ printf("Main Input");
+ break;
+ case HID_MAIN_ITEM_TAG_OUTPUT:
+ printf("Main Output");
+ break;
+ case HID_MAIN_ITEM_TAG_FEATURE:
+ printf("Main Feature");
+ break;
+ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+ printf("Main Begin Collection");
+ break;
+ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+ printf("Main End Collection");
+ break;
+ default:
+ printf("Main reserved %d",item->tag);
+ break;
+ }
+ break;
+ case HID_ITEM_TYPE_GLOBAL:
+ switch(item->tag) {
+ case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+ printf("- Global Usage Page");
+ break;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+ printf("- Global Logical Minimum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+ printf("- Global Logical Maximum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+ printf("- Global physical Minimum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+ printf("- Global physical Maximum");
+ break;
+ case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+ printf("- Global Unit Exponent");
+ break;
+ case HID_GLOBAL_ITEM_TAG_UNIT:
+ printf("- Global Unit");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+ printf("- Global Report Size");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+ printf("- Global Report ID");
+ break;
+ case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+ printf("- Global Report Count");
+ break;
+ case HID_GLOBAL_ITEM_TAG_PUSH:
+ printf("- Global Push");
+ break;
+ case HID_GLOBAL_ITEM_TAG_POP:
+ printf("- Global Pop");
+ break;
+ default:
+ printf("- Global reserved %d",item->tag);
+ break;
+ }
+ break;
+ case HID_ITEM_TYPE_LOCAL:
+ switch(item->tag) {
+ case HID_LOCAL_ITEM_TAG_USAGE:
+ printf("-- Local Usage");
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ printf("-- Local Usage Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ printf("-- Local Usage Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
+ printf("-- Local Designator Index");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
+ printf("-- Local Designator Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
+ printf("-- Local Designator Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_INDEX:
+ printf("-- Local String Index");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
+ printf("-- Local String Minimum");
+ break;
+ case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
+ printf("-- Local String Maximum");
+ break;
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+ printf("-- Local Delimiter");
+ break;
+ default:
+ printf("-- Local reserved %d",item->tag);
+ break;
+ }
+ break;
+ default:
+ printf("--- reserved %d",item->type);
+ break;
+ }
+ switch(item->size) {
+ case 1:
+ printf(" %d",item->data.u8);
+ break;
+ case 2:
+ printf(" %d",item->data.u16);
+ break;
+ case 4:
+ printf(" %ld",item->data.u32);
+ break;
+ }
+ printf("\n");
+}
+
+
+
+static int usb_kbd_get_hid_desc(struct usb_device *dev)
+{
+ unsigned char buffer[256];
+ struct usb_descriptor_header *head;
+ struct usb_config_descriptor *config;
+ int index,len,i;
+ unsigned char *start, *end;
+ struct hid_item item;
+
+ if(usb_get_configuration_no(dev,&buffer[0],0)==-1)
+ return -1;
+ head =(struct usb_descriptor_header *)&buffer[0];
+ if(head->bDescriptorType!=USB_DT_CONFIG) {
+ printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
+ return -1;
+ }
+ index=head->bLength;
+ config=(struct usb_config_descriptor *)&buffer[0];
+ len=swap_16(config->wTotalLength);
+ /* Ok the first entry must be a configuration entry, now process the others */
+ head=(struct usb_descriptor_header *)&buffer[index];
+ while(index+1 < len) {
+ if(head->bDescriptorType==USB_DT_HID) {
+ printf("HID desc found\n");
+ memcpy(&usb_kbd_hid_desc,&buffer[index],buffer[index]);
+ usb_kbd_hid_desc.bcdHID=swap_16(usb_kbd_hid_desc.bcdHID);
+ usb_kbd_hid_desc.wDescriptorLength=swap_16(usb_kbd_hid_desc.wDescriptorLength);
+ usb_kbd_display_hid(&usb_kbd_hid_desc);
+ len=0;
+ break;
+ }
+ index+=head->bLength;
+ head=(struct usb_descriptor_header *)&buffer[index];
+ }
+ if(len>0)
+ return -1;
+ len=usb_kbd_hid_desc.wDescriptorLength;
+ if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) {
+ printf("reading report descriptor failed\n");
+ return -1;
+ }
+ printf(" report descriptor (size %u, read %d)\n", len, index);
+ start=&buffer[0];
+ end=&buffer[len];
+ i=0;
+ do {
+ index=fetch_item(start,end,&item);
+ i+=index;
+ i++;
+ if(index>=0)
+ usb_kbd_show_item(&item);
+
+ start+=index;
+ start++;
+ } while(index>=0);
+
+}
+
+
+#endif
+
+#endif /* CONFIG_USB_KEYBOARD */
+
+/* eof */
+
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * Most of this source has been derived from the Linux USB
+ * project.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/* Note:
+ * Currently only the CBI transport protocoll has been implemented, and it
+ * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
+ * transport protocoll may work as well.
+ */
+
+
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_USB)
+#include <usb.h>
+
+#ifdef CONFIG_USB_STORAGE
+
+#undef USB_STOR_DEBUG
+
+#ifdef USB_STOR_DEBUG
+#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define USB_STOR_PRINTF(fmt,args...)
+#endif
+
+#include <scsi.h>
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+unsigned char us_direction[256/8] = {
+ 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+ 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+static unsigned char usb_stor_buf[512];
+static ccb usb_ccb;
+
+/*
+ * CBI style
+ */
+
+#define US_CBI_ADSC 0
+
+
+#define USB_MAX_STOR_DEV 5
+static int usb_max_devs; /* number of highest available usb device */
+
+static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
+
+struct us_data;
+typedef int (*trans_cmnd)(ccb*, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+
+struct us_data {
+ struct usb_device *pusb_dev; /* this usb_device */
+ unsigned int flags; /* from filter initially */
+ unsigned char ifnum; /* interface number */
+ unsigned char ep_in; /* in endpoint */
+ unsigned char ep_out; /* out ....... */
+ unsigned char ep_int; /* interrupt . */
+ unsigned char subclass; /* as in overview */
+ unsigned char protocol; /* .............. */
+ unsigned char attention_done; /* force attn on first cmd */
+ unsigned short ip_data; /* interrupt data */
+ int action; /* what to do */
+ int ip_wanted; /* needed */
+ int *irq_handle; /* for USB int requests */
+ unsigned int irqpipe; /* pipe for release_irq */
+ unsigned char irqmaxp; /* max packed for irq Pipe */
+ unsigned char irqinterval; /* Intervall for IRQ Pipe */
+ ccb *srb; /* current srb */
+ trans_reset transport_reset; /* reset routine */
+ trans_cmnd transport; /* transport routine */
+};
+
+static struct us_data usb_stor[USB_MAX_STOR_DEV];
+
+
+
+#define USB_STOR_TRANSPORT_GOOD 0
+#define USB_STOR_TRANSPORT_FAILED -1
+#define USB_STOR_TRANSPORT_ERROR -2
+
+
+
+
+
+
+int usb_stor_get_info(struct usb_device *dev, struct us_data *us, block_dev_desc_t *dev_desc);
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss);
+unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer);
+struct usb_device * usb_get_dev_index(int index);
+void uhci_show_temp_int_td(void);
+
+block_dev_desc_t *usb_stor_get_dev(int index)
+{
+ return &usb_dev_desc[index];
+}
+
+
+void usb_show_progress(void)
+{
+ printf(".");
+}
+
+/*********************************************************************************
+ * (re)-scan the usb and reports device info
+ * to the user if mode = 1
+ * returns current device or -1 if no
+ */
+int usb_stor_scan(int mode)
+{
+ unsigned char i;
+ struct usb_device *dev;
+
+ if(mode==1) {
+ printf("scanning bus for storage devices...\n");
+ }
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ for(i=0;i<USB_MAX_STOR_DEV;i++) {
+ memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t));
+ usb_dev_desc[i].target=0xff;
+ usb_dev_desc[i].if_type=IF_TYPE_USB;
+ usb_dev_desc[i].dev=i;
+ usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
+ usb_dev_desc[i].block_read=usb_stor_read;
+ }
+ usb_max_devs=0;
+ for(i=0;i<USB_MAX_DEVICE;i++) {
+ dev=usb_get_dev_index(i); /* get device */
+ USB_STOR_PRINTF("i=%d\n",i);
+ if(dev==NULL) {
+ break; /* no more devices avaiable */
+ }
+ if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */
+ /* get info and fill it in */
+
+ if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs])) {
+ if(mode==1) {
+ printf (" Device %d: ", usb_max_devs);
+ dev_print(&usb_dev_desc[usb_max_devs]);
+ } /* if mode */
+ usb_max_devs++;
+ } /* if get info ok */
+ } /* if storage device */
+ if(usb_max_devs==USB_MAX_STOR_DEV) {
+ printf("max USB Storage Device reached: %d stopping\n",usb_max_devs);
+ break;
+ }
+ } /* for */
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if(usb_max_devs>0)
+ return 0;
+ else
+ return-1;
+}
+
+static int usb_stor_irq(struct usb_device *dev)
+{
+ struct us_data *us;
+ us=(struct us_data *)dev->privptr;
+
+ if(us->ip_wanted) {
+ us->ip_wanted=0;
+ }
+ return 0;
+}
+
+
+#ifdef USB_STOR_DEBUG
+
+static void usb_show_srb(ccb * pccb)
+{
+ int i;
+ printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen);
+ for(i=0;i<12;i++) {
+ printf("%02X ",pccb->cmd[i]);
+ }
+ printf("\n");
+}
+
+static void display_int_status(unsigned long tmp)
+{
+ printf("Status: %s %s %s %s %s %s %s\n",
+ (tmp & USB_ST_ACTIVE) ? "Active" : "",
+ (tmp & USB_ST_STALLED) ? "Stalled" : "",
+ (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
+ (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
+ (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
+ (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
+ (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
+}
+#endif
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
+{
+ int max_size;
+ int this_xfer;
+ int result;
+ int partial;
+ int maxtry;
+ int stat;
+
+ /* determine the maximum packet size for these transfers */
+ max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
+
+ /* while we have data left to transfer */
+ while (length) {
+
+ /* calculate how long this will be -- maximum or a remainder */
+ this_xfer = length > max_size ? max_size : length;
+ length -= this_xfer;
+
+ /* setup the retry counter */
+ maxtry = 10;
+
+ /* set up the transfer loop */
+ do {
+ /* transfer the data */
+ USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n",
+ (unsigned int)buf, this_xfer, 11 - maxtry);
+ result = usb_bulk_msg(us->pusb_dev, pipe, buf,
+ this_xfer, &partial, USB_CNTL_TIMEOUT*5);
+ USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n",
+ result, partial, this_xfer);
+ if(us->pusb_dev->status!=0) {
+ /* if we stall, we need to clear it before we go on */
+#ifdef USB_STOR_DEBUG
+ display_int_status(us->pusb_dev->status);
+#endif
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe);
+ stat = us->pusb_dev->status;
+ usb_clear_halt(us->pusb_dev, pipe);
+ us->pusb_dev->status=stat;
+ if(this_xfer == partial) {
+ USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status);
+ return 0;
+ }
+ else
+ return result;
+ }
+ if (us->pusb_dev->status & USB_ST_NAK_REC) {
+ USB_STOR_PRINTF("Device NAKed bulk_msg\n");
+ return result;
+ }
+ if(this_xfer == partial) {
+ USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status);
+ return 0;
+ }
+ /* if our try counter reaches 0, bail out */
+ USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial);
+ if (!maxtry--)
+ return result;
+ }
+ /* update to show what data was transferred */
+ this_xfer -= partial;
+ buf += partial;
+ /* continue until this transfer is done */
+ } while ( this_xfer );
+ }
+
+ /* if we get here, we're done and successful */
+ return 0;
+}
+
+/* FIXME: this reset function doesn't really reset the port, and it
+ * should. Actually it should probably do what it's doing here, and
+ * reset the port physically
+ */
+static int usb_stor_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ int result;
+
+ USB_STOR_PRINTF("CB_reset\n");
+ memset(cmd, 0xFF, sizeof(cmd));
+ cmd[0] = SCSI_SEND_DIAG;
+ cmd[1] = 4;
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5);
+
+ /* long wait for reset */
+ wait_ms(1500);
+ USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status);
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+ USB_STOR_PRINTF("CB_reset done\n");
+ return 0;
+}
+
+/* FIXME: we also need a CBI_command which sets up the completion
+ * interrupt, and waits for it
+ */
+int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
+{
+ int result;
+ int dir_in,retry;
+ unsigned int pipe;
+ unsigned long status;
+
+ retry=5;
+ dir_in=US_DIRECTION(srb->cmd[0]);
+
+ if(dir_in)
+ pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+ while(retry--) {
+ USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);
+#ifdef USB_STOR_DEBUG
+ usb_show_srb(srb);
+#endif
+ /* let's send the command via the control pipe */
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum,
+ srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5);
+ USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status);
+ /* check the return code for the command */
+ if (result < 0) {
+ if(us->pusb_dev->status & USB_ST_STALLED) {
+ status=us->pusb_dev->status;
+ USB_STOR_PRINTF(" stall during command found, clear pipe\n");
+ usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0));
+ us->pusb_dev->status=status;
+ }
+ USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status);
+ return result;
+ }
+ /* transfer the data payload for this command, if one exists*/
+
+ USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen);
+ if (srb->datalen) {
+ result = us_one_transfer(us, pipe, srb->pdata,srb->datalen);
+ USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len);
+ if(!(us->pusb_dev->status & USB_ST_NAK_REC))
+ break;
+ } /* if (srb->datalen) */
+ else
+ break;
+ }
+ /* return result */
+
+ return result;
+}
+
+
+int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
+{
+ int timeout;
+
+ us->ip_wanted=1;
+ submit_int_msg(us->pusb_dev,us->irqpipe,
+ (void *)&us->ip_data,us->irqmaxp ,us->irqinterval);
+ timeout=1000;
+ while(timeout--) {
+ if((volatile int *)us->ip_wanted==0)
+ break;
+ wait_ms(10);
+ }
+ if (us->ip_wanted) {
+ printf(" Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ USB_STOR_PRINTF("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data,us->pusb_dev->irq_act_len,us->pusb_dev->irq_status);
+ /* UFI gives us ASC and ASCQ, like a request sense */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmd[0] == SCSI_REQ_SENSE ||
+ srb->cmd[0] == SCSI_INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD; /* Good */
+ else
+ if (us->ip_data)
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* otherwise, we interpret the data normally */
+ switch (us->ip_data) {
+ case 0x0001:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x0002:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ } /* switch */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+#define USB_TRANSPORT_UNKNOWN_RETRY 5
+#define USB_TRANSPORT_NOT_READY_RETRY 10
+
+int usb_stor_CB_transport(ccb *srb, struct us_data *us)
+{
+ int result,status;
+ ccb *psrb;
+ ccb reqsrb;
+ int retry,notready;
+
+ psrb=&reqsrb;
+ status=USB_STOR_TRANSPORT_GOOD;
+ retry=0;
+ notready=0;
+ /* issue the command */
+do_retry:
+ result=usb_stor_CB_comdat(srb,us);
+ USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status);
+ /* if this is an CBI Protocol, get IRQ */
+ if(us->protocol==US_PR_CBI) {
+ status=usb_stor_CBI_get_status(srb,us);
+ /* if the status is error, report it */
+ if(status==USB_STOR_TRANSPORT_ERROR) {
+ USB_STOR_PRINTF(" USB CBI Command Error\n");
+ return status;
+ }
+ srb->sense_buf[12]=(unsigned char)(us->ip_data>>8);
+ srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff);
+ if(!us->ip_data) {
+ /* if the status is good, report it */
+ if(status==USB_STOR_TRANSPORT_GOOD) {
+ USB_STOR_PRINTF(" USB CBI Command Good\n");
+ return status;
+ }
+ }
+ }
+ /* do we have to issue an auto request? */
+ /* HERE we have to check the result */
+ if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status);
+ us->transport_reset(us);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ if((us->protocol==US_PR_CBI) &&
+ ((srb->cmd[0]==SCSI_REQ_SENSE) ||
+ (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */
+ USB_STOR_PRINTF("No auto request and good\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+ /* issue an request_sense */
+ memset(&psrb->cmd[0],0,12);
+ psrb->cmd[0]=SCSI_REQ_SENSE;
+ psrb->cmd[1]=srb->lun<<5;
+ psrb->cmd[4]=18;
+ psrb->datalen=18;
+ psrb->pdata=&srb->sense_buf[0];
+ psrb->cmdlen=12;
+ /* issue the command */
+ result=usb_stor_CB_comdat(psrb,us);
+ USB_STOR_PRINTF("auto request returned %d\n",result);
+ /* if this is an CBI Protocol, get IRQ */
+ if(us->protocol==US_PR_CBI) {
+ status=usb_stor_CBI_get_status(psrb,us);
+ }
+ if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ /* Check the auto request result */
+ if((srb->sense_buf[2]==0) &&
+ (srb->sense_buf[12]==0) &&
+ (srb->sense_buf[13]==0)) /* ok, no sense */
+ return USB_STOR_TRANSPORT_GOOD;
+ /* Check the auto request result */
+ switch(srb->sense_buf[2]) {
+ case 0x01: /* Recovered Error */
+ return USB_STOR_TRANSPORT_GOOD;
+ break;
+ case 0x02: /* Not Ready */
+ if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n",
+ srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+ else {
+ wait_ms(100);
+ goto do_retry;
+ }
+ break;
+ default:
+ if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+ else
+ goto do_retry;
+ break;
+ }
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+
+
+static int usb_inquiry(ccb *srb,struct us_data *ss)
+{
+ int retry,i;
+ retry=3;
+ do {
+ memset(&srb->cmd[0],0,12);
+ srb->cmd[0]=SCSI_INQUIRY;
+ srb->cmd[1]=srb->lun<<5;
+ srb->cmd[4]=36;
+ srb->datalen=36;
+ srb->cmdlen=12;
+ i=ss->transport(srb,ss);
+ USB_STOR_PRINTF("inquiry returns %d\n",i);
+ if(i==0)
+ break;
+ }while(retry--);
+ if(!retry) {
+ printf("error in inquiry\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int usb_request_sense(ccb *srb,struct us_data *ss)
+{
+ char *ptr;
+ return 0;
+ ptr=srb->pdata;
+ memset(&srb->cmd[0],0,12);
+ srb->cmd[0]=SCSI_REQ_SENSE;
+ srb->cmd[1]=srb->lun<<5;
+ srb->cmd[4]=18;
+ srb->datalen=18;
+ srb->pdata=&srb->sense_buf[0];
+ srb->cmdlen=12;
+ ss->transport(srb,ss);
+ USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ srb->pdata=ptr;
+ return 0;
+}
+
+static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
+{
+ int retries=10;
+ do {
+ memset(&srb->cmd[0],0,12);
+ srb->cmd[0]=SCSI_TST_U_RDY;
+ srb->cmd[1]=srb->lun<<5;
+ srb->datalen=0;
+ srb->cmdlen=12;
+ if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD)
+ {
+ return 0;
+ }
+ } while(retries--);
+ return -1;
+}
+
+static int usb_read_capacity(ccb *srb,struct us_data *ss)
+{
+ int retry;
+ retry=2; /* retries */
+ do {
+ memset(&srb->cmd[0],0,12);
+ srb->cmd[0]=SCSI_RD_CAPAC;
+ srb->cmd[1]=srb->lun<<5;
+ srb->datalen=8;
+ srb->cmdlen=12;
+ if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {
+ return 0;
+ }
+ }while(retry--);
+ return -1;
+}
+
+static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigned short blocks)
+{
+ memset(&srb->cmd[0],0,12);
+ srb->cmd[0]=SCSI_READ10;
+ srb->cmd[1]=srb->lun<<5;
+ srb->cmd[2]=((unsigned char) (start>>24))&0xff;
+ srb->cmd[3]=((unsigned char) (start>>16))&0xff;
+ srb->cmd[4]=((unsigned char) (start>>8))&0xff;
+ srb->cmd[5]=((unsigned char) (start))&0xff;
+ srb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
+ srb->cmd[8]=(unsigned char) blocks & 0xff;
+ srb->cmdlen=12;
+ USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks);
+ return ss->transport(srb,ss);
+}
+
+
+#define USB_MAX_READ_BLK 20
+
+unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, unsigned long *buffer)
+{
+ unsigned long start,blks, buf_addr;
+ unsigned short smallblks;
+ struct usb_device *dev;
+ int retry,i;
+ ccb *srb=&usb_ccb;
+ device&=0xff;
+ /* Setup device
+ */
+ USB_STOR_PRINTF("\nusb_read: dev %d \n",device);
+ dev=NULL;
+ for(i=0;i<USB_MAX_DEVICE;i++) {
+ dev=usb_get_dev_index(i);
+ if(dev==NULL) {
+ return 0;
+ }
+ if(dev->devnum==usb_dev_desc[device].target)
+ break;
+ }
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+ srb->lun=usb_dev_desc[device].lun;
+ buf_addr=(unsigned long)buffer;
+ start=blknr;
+ blks=blkcnt;
+ if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",
+ srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ return 0;
+ }
+ USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr);
+ do {
+ retry=2;
+ srb->pdata=(unsigned char *)buf_addr;
+ if(blks>USB_MAX_READ_BLK) {
+ smallblks=USB_MAX_READ_BLK;
+ }
+ else {
+ smallblks=(unsigned short) blks;
+ }
+retry_it:
+ if(smallblks==USB_MAX_READ_BLK)
+ usb_show_progress();
+ srb->datalen=usb_dev_desc[device].blksz * smallblks;
+ srb->pdata=(unsigned char *)buf_addr;
+ if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) {
+ USB_STOR_PRINTF("Read ERROR\n");
+ usb_request_sense(srb,(struct us_data *)dev->privptr);
+ if(retry--)
+ goto retry_it;
+ blkcnt-=blks;
+ break;
+ }
+ start+=smallblks;
+ blks-=smallblks;
+ buf_addr+=srb->datalen;
+ } while(blks!=0);
+ USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if(blkcnt>=USB_MAX_READ_BLK)
+ printf("\n");
+ return(blkcnt);
+}
+
+
+/* Probe to see if a new device is actually a Storage device */
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss)
+{
+ struct usb_interface_descriptor *iface;
+ int i;
+ unsigned int flags = 0;
+
+ int protocol = 0;
+ int subclass = 0;
+
+
+ memset(ss, 0, sizeof(struct us_data));
+
+ /* let's examine the device now */
+ iface = &dev->config.if_desc[ifnum];
+
+#if 0
+ /* this is the place to patch some storage devices */
+ USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct);
+ if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) {
+ USB_STOR_PRINTF("patched for E-USB\n");
+ protocol = US_PR_CB;
+ subclass = US_SC_UFI; /* an assumption */
+ }
+#endif
+
+ if (dev->descriptor.bDeviceClass != 0 ||
+ iface->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+ iface->bInterfaceSubClass < US_SC_MIN ||
+ iface->bInterfaceSubClass > US_SC_MAX) {
+ /* if it's not a mass storage, we go no further */
+ return 0;
+ }
+
+ /* At this point, we know we've got a live one */
+ USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n");
+
+ /* Initialize the us_data structure with some useful info */
+ ss->flags = flags;
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+ ss->attention_done = 0;
+
+ /* If the device has subclass and protocol, then use that. Otherwise,
+ * take data from the specific interface.
+ */
+ if (subclass) {
+ ss->subclass = subclass;
+ ss->protocol = protocol;
+ } else {
+ ss->subclass = iface->bInterfaceSubClass;
+ ss->protocol = iface->bInterfaceProtocol;
+ }
+
+ /* set the handler pointers based on the protocol */
+ USB_STOR_PRINTF("Transport: ");
+ switch (ss->protocol) {
+ case US_PR_CB:
+ USB_STOR_PRINTF("Control/Bulk\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+
+ case US_PR_CBI:
+ USB_STOR_PRINTF("Control/Bulk/Interrupt\n");
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ break;
+ default:
+ printf("USB Starage Transport unknown / not yet implemented\n");
+ return 0;
+ break;
+ }
+
+ /*
+ * We are expecting a minimum of 2 endpoints - in and out (bulk).
+ * An optional interrupt is OK (necessary for CBI protocol).
+ * We will ignore any others.
+ */
+ for (i = 0; i < iface->bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK) {
+ if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
+ ss->ep_in = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ else
+ ss->ep_out = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ ss->ep_int = iface->ep_desc[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->irqinterval = iface->ep_desc[i].bInterval;
+ }
+ }
+ USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",
+ ss->ep_in, ss->ep_out, ss->ep_int);
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (usb_set_interface(dev, iface->bInterfaceNumber, 0) ||
+ !ss->ep_in || !ss->ep_out ||
+ (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
+ USB_STOR_PRINTF("Problems with device\n");
+ return 0;
+ }
+ /* set class specific stuff */
+ /* We only handle certain protocols. Currently, this is
+ * the only one.
+ */
+ if (ss->subclass != US_SC_UFI) {
+ printf("Sorry, protocol %d not yet supported.\n",ss->subclass);
+ return 0;
+ }
+ if(ss->ep_int) /* we had found an interrupt endpoint, prepare irq pipe */
+ {
+ /* set up the IRQ pipe and handler */
+
+ ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
+ dev->irq_handle=usb_stor_irq;
+ dev->privptr=(void *)ss;
+ }
+ return 1;
+}
+
+int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc)
+{
+ unsigned char perq,modi;
+ unsigned long cap[2];
+ unsigned long *capacity,*blksz;
+ ccb *pccb=&usb_ccb;
+
+ ss->transport_reset(ss);
+ pccb->pdata=usb_stor_buf;
+
+ dev_desc->target=dev->devnum;
+ pccb->lun=dev_desc->lun;
+ USB_STOR_PRINTF(" address %d\n",dev_desc->target);
+
+ if(usb_inquiry(pccb,ss))
+ return -1;
+ perq=usb_stor_buf[0];
+ modi=usb_stor_buf[1];
+ if((perq & 0x1f)==0x1f) {
+ return 0; /* skip unknown devices */
+ }
+ if((modi&0x80)==0x80) {/* drive is removable */
+ dev_desc->removable=1;
+ }
+ memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
+ memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
+ memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
+ dev_desc->vendor[8]=0;
+ dev_desc->product[16]=0;
+ dev_desc->revision[4]=0;
+ USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]);
+ if(usb_test_unit_ready(pccb,ss)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]);
+ if(dev_desc->removable==1) {
+ dev_desc->type=perq;
+ return 1;
+ }
+ else
+ return 0;
+ }
+ pccb->pdata=(unsigned char *)&cap[0];
+ memset(pccb->pdata,0,8);
+ if(usb_read_capacity(pccb,ss)!=0) {
+ printf("READ_CAP ERROR\n");
+ cap[0]=2880;
+ cap[1]=0x200;
+ }
+ USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
+#if 0
+ if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */
+ cap[0]>>=16;
+#endif
+ cap[0]+=1;
+ capacity=&cap[0];
+ blksz=&cap[1];
+ USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
+ dev_desc->lba=*capacity;
+ dev_desc->blksz=*blksz;
+ dev_desc->type=perq;
+ USB_STOR_PRINTF(" address %d\n",dev_desc->target);
+ USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+
+ init_part(dev_desc);
+
+ USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+ return 1;
+}
+
+#endif
+#endif /* CONFIG_USB_STORAGE */
+
+
+
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void
+show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+ " %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP:"
+ " %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printf("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
--- /dev/null
+/**************************************************
+ *
+ * copyright @ motorola, 1999
+ *
+ *************************************************/
+#include <mpc824x.h>
+#include <common.h>
+#include "epic.h"
+
+
+#define PRINT(format, args...) printf(format , ## args)
+
+typedef void (*VOIDFUNCPTR) (void); /* ptr to function returning void */
+struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
+ {
+ { EPIC_EX_INT0_VEC_REG, "External Direct/Serial Source 0"},
+ { EPIC_EX_INT1_VEC_REG, "External Direct/Serial Source 1"},
+ { EPIC_EX_INT2_VEC_REG, "External Direct/Serial Source 2"},
+ { EPIC_EX_INT3_VEC_REG, "External Direct/Serial Source 3"},
+ { EPIC_EX_INT4_VEC_REG, "External Direct/Serial Source 4"},
+
+ { EPIC_SR_INT5_VEC_REG, "External Serial Source 5"},
+ { EPIC_SR_INT6_VEC_REG, "External Serial Source 6"},
+ { EPIC_SR_INT7_VEC_REG, "External Serial Source 7"},
+ { EPIC_SR_INT8_VEC_REG, "External Serial Source 8"},
+ { EPIC_SR_INT9_VEC_REG, "External Serial Source 9"},
+ { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
+ { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
+ { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
+ { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
+ { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
+ { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
+
+ { EPIC_I2C_INT_VEC_REG, "Internal I2C Source"},
+ { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
+ { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
+ { EPIC_MSG_INT_VEC_REG, "Internal Message Source"},
+ };
+
+VOIDFUNCPTR intVecTbl[MAXVEC]; /* Interrupt vector table */
+
+
+/****************************************************************************
+* epicInit - Initialize the EPIC registers
+*
+* This routine resets the Global Configuration Register, thus it:
+* - Disables all interrupts
+* - Sets epic registers to reset values
+* - Sets the value of the Processor Current Task Priority to the
+* highest priority (0xF).
+* epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
+* Through or 8259 compatible mode).
+*
+* If IRQType (input) is Direct IRQs:
+* - IRQType is written to the SIE bit of the EPIC Interrupt
+* Configuration register (ICR).
+* - clkRatio is ignored.
+* If IRQType is Serial IRQs:
+* - both IRQType and clkRatio will be written to the ICR register
+*/
+
+void epicInit
+ (
+ unsigned int IRQType, /* Direct or Serial */
+ unsigned int clkRatio /* Clk Ratio for Serial IRQs */
+ )
+ {
+ ULONG tmp;
+
+ tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
+ tmp |= 0xa0000000; /* Set the Global Conf. register */
+ sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
+ sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
+ tmp = sysEUMBBARRead(EPIC_INT_CONF_REG); /* Read interrupt conf. reg */
+
+ if (IRQType == EPIC_DIRECT_IRQ) /* direct mode */
+ sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
+ else /* Serial mode */
+ {
+ tmp = (clkRatio << 28) | 0x08000000; /* Set clock ratio */
+ sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
+ }
+
+ while (epicIntAck() != 0xff); /* Clear all pending interrupts */
+}
+
+/****************************************************************************
+ * epicIntEnable - Enable an interrupt source
+ *
+ * This routine clears the mask bit of an external, an internal or
+ * a Timer register to enable the interrupt.
+ *
+ * RETURNS: None
+ */
+void epicIntEnable
+ (
+ int intVec /* Interrupt Vector Number */
+ )
+ {
+ ULONG tmp;
+ ULONG srAddr;
+
+ srAddr = SrcVecTable[intVec].srcAddr; /* Retrieve src Vec/Prio register */
+ tmp = sysEUMBBARRead(srAddr);
+ tmp &= 0x7fffffff; /* Clear the mask bit */
+ sysEUMBBARWrite(srAddr, tmp);
+ return;
+ }
+
+/****************************************************************************
+ * epicIntDisable - Disable an interrupt source
+ *
+ * This routine sets the mask bit of an external, an internal or
+ * a Timer register to disable the interrupt.
+ *
+ * RETURNS: OK or ERROR
+ *
+ */
+
+void epicIntDisable
+ (
+ int intVec /* Interrupt vector number */
+ )
+ {
+
+ ULONG tmp, srAddr;
+
+ srAddr = SrcVecTable[intVec].srcAddr;
+ tmp = sysEUMBBARRead(srAddr);
+ tmp |= 0x80000000; /* Set the mask bit */
+ sysEUMBBARWrite(srAddr, tmp);
+ return;
+ }
+
+/****************************************************************************
+ * epicIntSourceConfig - Set properties of an interrupt source
+ *
+ * This function sets interrupt properites (Polarity, Sense, Interrupt
+ * Prority, and Interrupt Vector) of an Interrupt Source. The properties
+ * can be set when the current source is not in-request or in-service,
+ * which is determined by the Activity bit. This routine return ERROR
+ * if the the Activity bit is 1 (in-request or in-service).
+ *
+ * This function assumes that the Source Vector/Priority register (input)
+ * is a valid address.
+ *
+ * RETURNS: OK or ERROR
+ */
+
+int epicIntSourceConfig
+ (
+ int Vect, /* interrupt source vector number */
+ int Polarity, /* interrupt source polarity */
+ int Sense, /* interrupt source Sense */
+ int Prio /* interrupt source priority */
+ )
+
+ {
+ ULONG tmp, newVal;
+ ULONG actBit, srAddr;
+
+ srAddr = SrcVecTable[Vect].srcAddr;
+ tmp = sysEUMBBARRead(srAddr);
+ actBit = (tmp & 40000000) >> 30; /* retrieve activity bit - bit 30 */
+ if (actBit == 1)
+ return ERROR;
+
+ tmp &= 0xff30ff00; /* Erase previously set P,S,Prio,Vector bits */
+ newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
+ sysEUMBBARWrite(srAddr, tmp | newVal );
+ return (OK);
+ }
+
+/****************************************************************************
+ * epicIntAck - acknowledge an interrupt
+ *
+ * This function reads the Interrupt acknowldge register and return
+ * the vector number of the highest pending interrupt.
+ *
+ * RETURNS: Interrupt Vector number.
+ */
+
+unsigned int epicIntAck(void)
+{
+ return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
+}
+
+/****************************************************************************
+ * epicEOI - signal an end of interrupt
+ *
+ * This function writes 0x0 to the EOI register to signal end of interrupt.
+ * It is usually called after an interrupt routine is served.
+ *
+ * RETURNS: None
+ */
+
+void epicEOI(void)
+ {
+ sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
+ }
+
+/****************************************************************************
+ * epicCurTaskPrioSet - sets the priority of the Processor Current Task
+ *
+ * This function should be called after epicInit() to lower the priority
+ * of the processor current task.
+ *
+ * RETURNS: OK or ERROR
+ */
+
+int epicCurTaskPrioSet
+ (
+ int prioNum /* New priority value */
+ )
+ {
+
+ if ( (prioNum < 0) || (prioNum > 0xF))
+ return ERROR;
+ sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
+ return OK;
+ }
+
+
+/************************************************************************
+ * function: epicIntTaskGet
+ *
+ * description: Get value of processor current interrupt task priority register
+ *
+ * note:
+ ***********************************************************************/
+unsigned char epicIntTaskGet()
+{
+ /* get the interrupt task priority register */
+ ULONG reg;
+ unsigned char rec;
+
+ reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
+ rec = ( reg & 0x0F );
+ return rec;
+}
+
+
+/**************************************************************
+ * function: epicISR
+ *
+ * description: EPIC service routine called by the core exception
+ * at 0x500
+ *
+ * note:
+ **************************************************************/
+unsigned int epicISR(void)
+{
+ return 0;
+}
+
+
+/************************************************************
+ * function: epicModeGet
+ *
+ * description: query EPIC mode, return 0 if pass through mode
+ * return 1 if mixed mode
+ *
+ * note:
+ *************************************************************/
+unsigned int epicModeGet(void)
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_GLOBAL_REG );
+ return (( val & 0x20000000 ) >> 29);
+}
+
+
+/*********************************************
+ * function: epicConfigGet
+ *
+ * description: Get the EPIC interrupt Configuration
+ * return 0 if not error, otherwise return 1
+ *
+ * note:
+ ********************************************/
+void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_INT_CONF_REG );
+ *clkRatio = ( val & 0x70000000 ) >> 28;
+ *serEnable = ( val & 0x8000000 ) >> 27;
+}
+
+
+/*******************************************************************
+ * sysEUMBBARRead - Read a 32-bit EUMBBAR register
+ *
+ * This routine reads the content of a register in the Embedded
+ * Utilities Memory Block, and swaps to big endian before returning
+ * the value.
+ *
+ * RETURNS: The content of the specified EUMBBAR register.
+ */
+
+ULONG sysEUMBBARRead
+ (
+ ULONG regNum
+ )
+ {
+ ULONG temp;
+
+ temp = *(ULONG *) (CFG_EUMB_ADDR + regNum);
+ return ( LONGSWAP(temp));
+ }
+
+/*******************************************************************
+ * sysEUMBBARWrite - Write a 32-bit EUMBBAR register
+ *
+ * This routine swaps the value to little endian then writes it to
+ * a register in the Embedded Utilities Memory Block address space.
+ *
+ * RETURNS: N/A
+ */
+
+void sysEUMBBARWrite
+ (
+ ULONG regNum, /* EUMBBAR register address */
+ ULONG regVal /* Value to be written */
+ )
+ {
+
+ *(ULONG *) (CFG_EUMB_ADDR + regNum) = LONGSWAP(regVal);
+ return ;
+ }
+
+
+/********************************************************
+ * function: epicVendorId
+ *
+ * description: return the EPIC Vendor Identification
+ * register:
+ *
+ * siliccon version, device id, and vendor id
+ *
+ * note:
+ ********************************************************/
+void epicVendorId
+ (
+ unsigned int *step,
+ unsigned int *devId,
+ unsigned int *venId
+ )
+ {
+ ULONG val;
+ val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
+ *step = ( val & 0x00FF0000 ) >> 16;
+ *devId = ( val & 0x0000FF00 ) >> 8;
+ *venId = ( val & 0x000000FF );
+ }
+
+/**************************************************
+ * function: epicFeatures
+ *
+ * description: return the number of IRQ supported,
+ * number of CPU, and the version of the
+ * OpenEPIC
+ *
+ * note:
+ *************************************************/
+void epicFeatures
+ (
+ unsigned int *noIRQs,
+ unsigned int *noCPUs,
+ unsigned int *verId
+ )
+ {
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_FEATURES_REG );
+ *noIRQs = ( val & 0x07FF0000 ) >> 16;
+ *noCPUs = ( val & 0x00001F00 ) >> 8;
+ *verId = ( val & 0x000000FF );
+}
+
+
+/*********************************************************
+ * function: epciTmFrequncySet
+ *
+ * description: Set the timer frequency reporting register
+ ********************************************************/
+void epicTmFrequencySet( unsigned int frq )
+{
+ sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
+}
+
+/*******************************************************
+ * function: epicTmFrequncyGet
+ *
+ * description: Get the current value of the Timer Frequency
+ * Reporting register
+ *
+ ******************************************************/
+unsigned int epicTmFrequencyGet(void)
+{
+ return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
+}
+
+
+/****************************************************
+ * function: epicTmBaseSet
+ *
+ * description: Set the #n global timer base count register
+ * return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ****************************************************/
+unsigned int epicTmBaseSet
+ (
+ ULONG srcAddr, /* Address of the Timer Base register */
+ unsigned int cnt, /* Base count */
+ unsigned int inhibit /* 1 - count inhibit */
+ )
+{
+
+ unsigned int val = 0x80000000;
+ /* First inhibit counting the timer */
+ sysEUMBBARWrite(srcAddr, val) ;
+
+ /* set the new value */
+ val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
+ sysEUMBBARWrite(srcAddr, val) ;
+ return 0;
+}
+
+/***********************************************************************
+ * function: epicTmBaseGet
+ *
+ * description: Get the current value of the global timer base count register
+ * return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ***********************************************************************/
+unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
+{
+ *val = sysEUMBBARRead( srcAddr );
+ *val = *val & 0x7fffffff;
+ return 0;
+}
+
+/***********************************************************
+ * function: epicTmCountGet
+ *
+ * description: Get the value of a given global timer
+ * current count register
+ * return 0 if no error, otherwise return 1
+ * note:
+ **********************************************************/
+unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
+{
+ *val = sysEUMBBARRead( srcAddr );
+ *val = *val & 0x7fffffff;
+ return 0;
+}
+
+
+
+/***********************************************************
+ * function: epicTmInhibit
+ *
+ * description: Stop counting of a given global timer
+ * return 0 if no error, otherwise return 1
+ *
+ * note:
+ ***********************************************************/
+unsigned int epicTmInhibit( unsigned int srcAddr )
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( srcAddr );
+ val |= 0x80000000;
+ sysEUMBBARWrite( srcAddr, val );
+ return 0;
+}
+
+/******************************************************************
+ * function: epicTmEnable
+ *
+ * description: Enable counting of a given global timer
+ * return 0 if no error, otherwise return 1
+ *
+ * note:
+ *****************************************************************/
+unsigned int epicTmEnable( ULONG srcAddr )
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( srcAddr );
+ val &= 0x7fffffff;
+ sysEUMBBARWrite( srcAddr, val );
+ return 0;
+}
+
+void epicSourcePrint(int Vect)
+ {
+ ULONG srcVal;
+
+ srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
+ PRINT("%s\n", SrcVecTable[Vect].srcName);
+ PRINT("Address = 0x%lx\n", SrcVecTable[Vect].srcAddr);
+ PRINT("Vector = %ld\n", (srcVal & 0x000000FF) );
+ PRINT("Mask = %ld\n", srcVal >> 31);
+ PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
+ PRINT("Polarity = %ld\n", (srcVal & 0x00800000) >> 23);
+ PRINT("Sense = %ld\n", (srcVal & 0x00400000) >> 22);
+ PRINT("Priority = %ld\n", (srcVal & 0x000F0000) >> 16);
+ }
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x00400000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printf("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
--- /dev/null
+/*
+ * MPC8260 FCC Fast Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8260 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ * config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <net.h>
+#include <command.h>
+#include <config.h>
+
+#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET)
+
+/*---------------------------------------------------------------------*/
+#if (CONFIG_ETHER_INDEX == 1)
+
+#define PROFF_ENET PROFF_FCC1
+#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
+#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
+#define CPM_CR_ENET_PAGE CPM_CR_FCC1_PAGE
+
+/*---------------------------------------------------------------------*/
+#elif (CONFIG_ETHER_INDEX == 2)
+
+#define PROFF_ENET PROFF_FCC2
+#define CPM_CR_ENET_SBLOCK CPM_CR_FCC2_SBLOCK
+#define CPM_CR_ENET_PAGE CPM_CR_FCC2_PAGE
+
+/*---------------------------------------------------------------------*/
+#elif (CONFIG_ETHER_INDEX == 3)
+
+#define PROFF_ENET PROFF_FCC3
+#define CPM_CR_ENET_SBLOCK CPM_CR_FCC3_SBLOCK
+#define CPM_CR_ENET_PAGE CPM_CR_FCC3_PAGE
+
+/*---------------------------------------------------------------------*/
+#else
+#error "FCC Ethernet not correctly defined"
+#endif
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE 1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+
+/* Maximum input buffer size. Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE 1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+#ifdef __GNUC__
+static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
+#else
+#error "txbuf must be 64-bit aligned"
+#endif
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+ cbd_t rxbd[PKTBUFSRX];
+ cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/* Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+int eth_send(volatile void *packet, int length)
+{
+ int i;
+ int result = 0;
+
+ if (length <= 0) {
+ printf("fec: bad packet size: %d\n", length);
+ goto out;
+ }
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ printf("fec: tx buffer not ready\n");
+ goto out;
+ }
+ }
+
+ rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx.txbd[txIdx].cbd_datlen = length;
+ rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
+ BD_ENET_TX_WRAP);
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ printf("fec: tx error\n");
+ goto out;
+ }
+ }
+
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
+#endif
+
+ /* return only status bits */
+ result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+out:
+ return result;
+}
+
+int eth_rx(void)
+{
+ int length;
+
+ for (;;)
+ {
+ if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+ length = rtx.rxbd[rxIdx].cbd_datlen;
+
+ if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
+ printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+ }
+ else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ }
+
+
+ /* Give the buffer back to the FCC. */
+ rtx.rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ }
+ else {
+ rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+ }
+ return length;
+}
+
+
+int eth_init(bd_t *bis)
+{
+ int i;
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile cpm8260_t *cp = &(immr->im_cpm);
+ fcc_enet_t *pram_ptr;
+ unsigned long mem_addr;
+
+#if 0
+ mii_discover_phy();
+#endif
+
+ /* 28.9 - (1-2): ioports have been set up already */
+
+ /* 28.9 - (3): connect FCC's tx and rx clocks */
+ immr->im_cpmux.cmx_uar = 0;
+ immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~CFG_CMXFCR_MASK) |
+ CFG_CMXFCR_VALUE;
+
+ /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr =
+ FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+ /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC;
+
+ /* 28.9 - (6): FDSR: Ethernet Syn */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fdsr = 0xD555;
+
+ /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+ rxIdx = 0;
+ txIdx = 0;
+
+ /* Setup Receiver Buffer Descriptors */
+ for (i = 0; i < PKTBUFSRX; i++)
+ {
+ rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx.rxbd[i].cbd_datlen = 0;
+ rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+ }
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /* Setup Ethernet Transmitter Buffer Descriptors */
+ for (i = 0; i < TX_BUF_CNT; i++)
+ {
+ rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ rtx.txbd[i].cbd_datlen = 0;
+ rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+ }
+ rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* 28.9 - (7): initialise parameter ram */
+ pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
+
+ /* clear whole structure to make sure all reserved fields are zero */
+ memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+ /*
+ * common Parameter RAM area
+ *
+ * Allocate space in the reserved FCC area of DPRAM for the
+ * internal buffers. No one uses this space (yet), so we
+ * can do this. Later, we will add resource management for
+ * this area.
+ */
+ mem_addr = CPM_FCC_SPECIAL_BASE + ((CONFIG_ETHER_INDEX-1) * 64);
+ pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+ pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+ /*
+ * Set maximum bytes per receive buffer.
+ * It must be a multiple of 32.
+ */
+ pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+ pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+ CFG_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+ pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+ CFG_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+
+ /* protocol-specific area */
+ pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
+ pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
+ pram_ptr->fen_retlim = 15; /* Retry limit threshold */
+ pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
+ /*
+ * Set Ethernet station address.
+ *
+ * This is supplied in the board information structure, so we
+ * copy that into the controller.
+ * So, far we have only been given one Ethernet address. We make
+ * it unique by setting a few bits in the upper byte of the
+ * non-static part of the address.
+ */
+#define ea bis->bi_enetaddr
+ pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+ pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+ pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+ pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+ /* pad pointer. use tiptr since we don't need a specific padding char */
+ pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+ pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
+ pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
+ pram_ptr->fen_rfthr = 1;
+ pram_ptr->fen_rfcnt = 1;
+#if 0
+ printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
+ pram_ptr->fen_genfcc.fcc_rbase);
+ printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
+ pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+ /* 28.9 - (8): clear out events in FCCE */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fcce = ~0x0;
+
+ /* 28.9 - (9): FCCM: mask all events */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fccm = 0;
+
+ /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+ /* 28.9 - (13)
+ *
+ * Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
+ CPM_CR_ENET_SBLOCK,
+ 0x0c,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* 28.9 - (14): enable tx/rx in gfmr */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+ return 1;
+}
+
+void eth_halt(void)
+{
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+
+ /* write GFMR: disable tx/rx */
+ immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr &=
+ ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+}
+
+#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET */
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printf("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void
+DebugException(struct pt_regs *regs)
+{
+
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printf("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+SoftEmuException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
--- /dev/null
+#include <common.h>
+#include <commproc.h>
+
+#if defined(CFG_I2C_UCODE_PATCH) || defined(CFG_SPI_UCODE_PATCH)
+
+static void UcodeCopy (volatile cpm8xx_t *cpm);
+
+void cpm_load_patch (volatile immap_t *immr)
+{
+ immr->im_cpm.cp_rccr &= ~0x0003; /* Disable microcode program area */
+
+ UcodeCopy ((cpm8xx_t *)&immr->im_cpm); /* Copy ucode patch to DPRAM */
+#ifdef CFG_SPI_UCODE_PATCH
+ {
+ volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the SPI parameters (not I2C). */
+ immr->im_cpm.cp_cpmcr1 = 0x802a; /* Write Trap register 1 value */
+ immr->im_cpm.cp_cpmcr2 = 0x8028; /* Write Trap register 2 value */
+ spi->spi_rpbase = CFG_SPI_DPMEM_OFFSET; /* Where to relocte SPI params */
+ }
+#endif
+
+#ifdef CFG_I2C_UCODE_PATCH
+ {
+ volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the I2C parameters (not SPI). */
+ immr->im_cpm.cp_cpmcr3 = 0x802e; /* Write Trap register 3 value */
+ immr->im_cpm.cp_cpmcr4 = 0x802c; /* Write Trap register 4 value */
+ iip->iic_rpbase = CFG_I2C_DPMEM_OFFSET; /* Where to relocte I2C params */
+ }
+#endif
+
+ /*
+ * Enable DPRAM microcode to execute from the first 512 bytes
+ * and a 256 byte extension of DPRAM.
+ */
+ immr->im_cpm.cp_rccr |= 0x0001;
+}
+
+static ulong patch_2000[] = {
+ 0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
+ 0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
+ 0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
+ 0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
+ 0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
+ 0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
+ 0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
+ 0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
+ 0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
+ 0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
+ 0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
+ 0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
+ 0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
+ 0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
+ 0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
+ 0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
+ 0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
+ 0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
+ 0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
+ 0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
+ 0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
+ 0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
+ 0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
+ 0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
+ 0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
+ 0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
+ 0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
+ 0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
+ 0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
+ 0x7FBDB081, 0x5F8147F8,
+};
+
+static ulong patch_2F00[] = {
+ 0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
+ 0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
+ 0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
+ 0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
+ 0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
+ 0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
+ 0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
+ 0x19797937, 0x69350000,
+};
+
+static void UcodeCopy (volatile cpm8xx_t *cpm)
+{
+ vu_long *p;
+ int i;
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
+ for (i=0; i < sizeof(patch_2000)/4; ++i) {
+ p[i] = patch_2000[i];
+ }
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
+ for (i=0; i < sizeof(patch_2F00)/4; ++i) {
+ p[i] = patch_2F00[i];
+ }
+}
+
+#endif /* CFG_I2C_UCODE_PATCH, CFG_SPI_UCODE_PATCH */
--- /dev/null
+/*-----------------------------------------------------------------------------+
+ |
+ | This source code has been made available to you by IBM on an AS-IS
+ | basis. Anyone receiving this source is licensed under IBM
+ | copyrights to use it in any way he or she deems fit, including
+ | copying it, modifying it, compiling it, and redistributing it either
+ | with or without modifications. No license under IBM patents or
+ | patent applications is to be implied by the copyright license.
+ |
+ | Any user of this software should understand that IBM cannot provide
+ | technical support for this software and will not be responsible for
+ | any consequences resulting from the use of this software.
+ |
+ | Any person who transfers this source code or any derivative work
+ | must include the IBM copyright notice, this paragraph, and the
+ | preceding two paragraphs in the transferred software.
+ |
+ | COPYRIGHT I B M CORPORATION 1995
+ | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ +-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ |
+ | File Name: miiphy.c
+ |
+ | Function: This module has utilities for accessing the MII PHY through
+ | the EMAC3 macro.
+ |
+ | Author: Mark Wisner
+ |
+ | Change Activity-
+ |
+ | Date Description of Change BY
+ | --------- --------------------- ---
+ | 05-May-99 Created MKW
+ | 01-Jul-99 Changed clock setting of sta_reg from 66Mhz to 50Mhz to
+ | better match OPB speed. Also modified delay times. JWB
+ | 29-Jul-99 Added Full duplex support MKW
+ | 24-Aug-99 Removed printf from dp83843_duplex() JWB
+ | 19-Jul-00 Ported to esd cpci405 sr
+ |
+ +-----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <405gp_enet.h>
+#include <405_mal.h>
+#include <miiphy.h>
+
+#if defined(CONFIG_405GP) || defined(CONFIG_440)
+
+
+/***********************************************************/
+/* Dump out to the screen PHY regs */
+/***********************************************************/
+
+void miiphy_dump (unsigned char addr)
+{
+ unsigned long i;
+ unsigned short data;
+
+
+ for (i = 0; i < 0x1A; i++) {
+ if (miiphy_read (addr, i, &data)) {
+ printf ("read error for reg %lx\n", i);
+ return;
+ }
+ printf ("Phy reg %lx ==> %4x\n", i, data);
+
+ /* jump to the next set of regs */
+ if (i == 0x07)
+ i = 0x0f;
+
+ } /* end for loop */
+} /* end dump */
+
+
+
+/***********************************************************/
+/* read a phy reg and return the value with a rc */
+/***********************************************************/
+
+int miiphy_read (unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ unsigned long sta_reg; /* STA scratch area */
+ unsigned long i;
+
+ /* see if it is ready for 1000 nsec */
+ i = 0;
+
+ /* see if it is ready for sec */
+ while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5) {
+ printf ("read err 1\n");
+ return -1;
+ }
+ i++;
+ }
+ sta_reg = reg; /* reg address */
+ /* set clock (50Mhz) and read flags */
+ sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ;
+ sta_reg = sta_reg | (addr << 5); /* Phy address */
+
+ out32 (EMAC_STACR, sta_reg);
+#if 0 /* test-only */
+ printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */
+#endif
+
+ sta_reg = in32 (EMAC_STACR);
+ i = 0;
+ while ((sta_reg & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5) {
+ printf ("read err 2\n");
+ return -1;
+ }
+ i++;
+ sta_reg = in32 (EMAC_STACR);
+ }
+ if ((sta_reg & EMAC_STACR_PHYE) != 0) {
+ printf ("read err 3\n");
+ printf ("a2: read: EMAC_STACR=0x%0lx, i=%d\n",
+ sta_reg, (int) i); /* test-only */
+ return -1;
+ }
+
+ *value = *(short *) (&sta_reg);
+ return 0;
+
+
+} /* phy_read */
+
+
+/***********************************************************/
+/* write a phy reg and return the value with a rc */
+/***********************************************************/
+
+int miiphy_write (unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ unsigned long sta_reg; /* STA scratch area */
+ unsigned long i;
+
+ /* see if it is ready for 1000 nsec */
+ i = 0;
+
+ while ((in32 (EMAC_STACR) & EMAC_STACR_OC) == 0) {
+ if (i > 5)
+ return -1;
+ udelay (7);
+ i++;
+ }
+ sta_reg = 0;
+ sta_reg = reg; /* reg address */
+ /* set clock (50Mhz) and read flags */
+ sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ;
+ sta_reg = sta_reg | ((unsigned long) addr << 5); /* Phy address */
+ memcpy (&sta_reg, &value, 2); /* put in data */
+
+ out32 (EMAC_STACR, sta_reg);
+
+ /* wait for completion */
+ i = 0;
+ sta_reg = in32 (EMAC_STACR);
+ while ((sta_reg & EMAC_STACR_OC) == 0) {
+ udelay (7);
+ if (i > 5)
+ return -1;
+ i++;
+ sta_reg = in32 (EMAC_STACR);
+ }
+
+ if ((sta_reg & EMAC_STACR_PHYE) != 0)
+ return -1;
+ return 0;
+
+} /* phy_read */
+
+#endif /* CONFIG_405GP */
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+ */
+#define END_OF_MEM 0x00400000
+
+
+static __inline__ void set_tsr(unsigned long val)
+{
+#if defined(CONFIG_440)
+ asm volatile("mtspr 0x150, %0" : : "r" (val));
+#else
+ asm volatile("mttsr %0" : : "r" (val));
+#endif
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+ unsigned long val;
+
+#if defined(CONFIG_440)
+ asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+#else
+ asm volatile("mfesr %0" : "=r" (val) :);
+#endif
+ return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printf("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void
+AlignmentException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void
+ProgramCheckException(struct pt_regs *regs)
+{
+ long esr_val;
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+
+ esr_val = get_esr();
+ if( esr_val & ESR_PIL )
+ printf( "** Illegal Instruction **\n" );
+ else if( esr_val & ESR_PPR )
+ printf( "** Privileged Instruction **\n" );
+ else if( esr_val & ESR_PTR )
+ printf( "** Trap Instruction **\n" );
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void
+PITException(struct pt_regs *regs)
+{
+ /*
+ * Reset PIT interrupt
+ */
+ set_tsr(0x08000000);
+
+ /*
+ * Call timer_interrupt routine in interrupts.c
+ */
+ timer_interrupt(NULL);
+}
+
+
+void
+UnknownException(struct pt_regs *regs)
+{
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void
+DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <ide.h>
+#include <cmd_disk.h>
+
+#undef PART_DEBUG
+
+#ifdef PART_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)
+
+/* ------------------------------------------------------------------------- */
+/*
+ * reports device info to the user
+ */
+void dev_print (block_dev_desc_t *dev_desc)
+{
+ ulong lba512; /* number of blocks if 512bytes block size */
+
+ if (dev_desc->type==DEV_TYPE_UNKNOWN) {
+ puts ("not available\n");
+ return;
+ }
+ if (dev_desc->if_type==IF_TYPE_SCSI) {
+ printf ("(%d:%d) ", dev_desc->target,dev_desc->lun);
+ }
+ if (dev_desc->if_type==IF_TYPE_IDE) {
+ printf ("Model: %s Firm: %s Ser#: %s\n",
+ dev_desc->vendor,
+ dev_desc->revision,
+ dev_desc->product);
+ } else {
+ printf ("Vendor: %s Prod.: %s Rev: %s\n",
+ dev_desc->vendor,
+ dev_desc->product,
+ dev_desc->revision);
+ }
+ puts (" Type: ");
+ if (dev_desc->removable)
+ puts ("Removable ");
+ switch (dev_desc->type & 0x1F) {
+ case DEV_TYPE_HARDDISK: puts ("Hard Disk");
+ break;
+ case DEV_TYPE_CDROM: puts ("CD ROM");
+ break;
+ case DEV_TYPE_OPDISK: puts ("Optical Device");
+ break;
+ case DEV_TYPE_TAPE: puts ("Tape");
+ break;
+ default: printf ("# %02X #", dev_desc->type & 0x1F);
+ break;
+ }
+ puts ("\n");
+ if ((dev_desc->lba * dev_desc->blksz)>0L) {
+ ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
+
+ lba512 = (dev_desc->lba * (dev_desc->blksz/512));
+
+ mb = (10 * lba512) / 2048; /* 2048 = (1024 * 1024) / 512 MB */
+ /* round to 1 digit */
+ mb_quot = mb / 10;
+ mb_rem = mb - (10 * mb_quot);
+
+ gb = mb / 1024;
+ gb_quot = gb / 10;
+ gb_rem = gb - (10 * gb_quot);
+
+ printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
+ mb_quot, mb_rem,
+ gb_quot, gb_rem,
+ dev_desc->lba,
+ dev_desc->blksz);
+ } else {
+ puts (" Capacity: not available\n");
+ }
+}
+
+
+
+#if defined(CONFIG_MAC_PARTITION) || \
+ defined(CONFIG_DOS_PARTITION) || \
+ defined(CONFIG_ISO_PARTITION)
+
+void init_part (block_dev_desc_t * dev_desc)
+{
+#ifdef CONFIG_ISO_PARTITION
+ if (test_part_iso(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_ISO;
+ return;
+ }
+#endif
+
+#ifdef CONFIG_MAC_PARTITION
+ if (test_part_mac(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_MAC;
+ return;
+ }
+#endif
+
+#ifdef CONFIG_DOS_PARTITION
+ if (test_part_dos(dev_desc) == 0) {
+ dev_desc->part_type = PART_TYPE_DOS;
+ return;
+ }
+#endif
+}
+
+
+int get_partition_info (block_dev_desc_t *dev_desc, int part, disk_partition_t *info)
+{
+ switch (dev_desc->part_type) {
+#ifdef CONFIG_MAC_PARTITION
+ case PART_TYPE_MAC:
+ if (get_partition_info_mac(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid MAC partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
+
+#ifdef CONFIG_DOS_PARTITION
+ case PART_TYPE_DOS:
+ if (get_partition_info_dos(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid DOS partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
+
+#ifdef CONFIG_ISO_PARTITION
+ case PART_TYPE_ISO:
+ if (get_partition_info_iso(dev_desc,part,info) == 0) {
+ PRINTF ("## Valid ISO boot partition found ##\n");
+ return (0);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ return (-1);
+}
+
+static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
+{
+ puts ("\nPartition Map for ");
+ switch (dev_desc->if_type) {
+ case IF_TYPE_IDE: puts ("IDE");
+ break;
+ case IF_TYPE_SCSI: puts ("SCSI");
+ break;
+ case IF_TYPE_ATAPI: puts ("ATAPI");
+ break;
+ case IF_TYPE_USB: puts ("USB");
+ break;
+ case IF_TYPE_DOC: puts ("DOC");
+ break;
+ default: puts ("UNKNOWN");
+ break;
+ }
+ printf (" device %d -- Partition Type: %s\n\n",
+ dev_desc->dev, type);
+}
+
+void print_part (block_dev_desc_t * dev_desc)
+{
+
+ switch (dev_desc->part_type) {
+#ifdef CONFIG_MAC_PARTITION
+ case PART_TYPE_MAC:
+ PRINTF ("## Testing for valid MAC partition ##\n");
+ print_part_header ("MAC", dev_desc);
+ print_part_mac (dev_desc);
+ return;
+#endif
+#ifdef CONFIG_DOS_PARTITION
+ case PART_TYPE_DOS:
+ PRINTF ("## Testing for valid DOS partition ##\n");
+ print_part_header ("DOS", dev_desc);
+ print_part_dos (dev_desc);
+ return;
+#endif
+
+#ifdef CONFIG_ISO_PARTITION
+ case PART_TYPE_ISO:
+ PRINTF ("## Testing for valid ISO Boot partition ##\n");
+ print_part_header ("ISO", dev_desc);
+ print_part_iso (dev_desc);
+ return;
+#endif
+ }
+ puts ("## Unknown partition table\n");
+}
+
+
+#else /* neither MAC nor DOS nor ISO partition configured */
+# error neither CONFIG_MAC_PARTITION nor CONFIG_DOS_PARTITION nor CONFIG_ISO_PARTITION configured!
+#endif
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_IDE) || CONFIG_COMMANDS & CFG_CMD_SCSI) */
--- /dev/null
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+
+#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ unsigned int msr = mfmsr(); \
+ mtmsr(msr & ~(MSR_EE | MSR_CE)); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ out_le32(hose->cfg_addr, 0x00000000); \
+ mtmsr(msr); \
+ return 0; \
+}
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+#ifdef CONFIG_405GP
+INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
+#else
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ indirect_read_config_byte,
+ indirect_read_config_word,
+ indirect_read_config_dword,
+ indirect_write_config_byte,
+ indirect_write_config_word,
+ indirect_write_config_dword);
+
+ hose->cfg_addr = (unsigned int *) cfg_addr;
+ hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright 1998-2001 by Donald Becker.
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Contact the author for use under other terms.
+ *
+ * This program must be compiled with "-O"!
+ * See the bottom of this file for the suggested compile-command.
+ *
+ * The author may be reached as becker@scyld.com, or C/O
+ * Scyld Computing Corporation
+ * 410 Severn Ave., Suite 210
+ * Annapolis MD 21403
+ *
+ * Common-sense licensing statement: Using any portion of this program in
+ * your own program means that you must give credit to the original author
+ * and release the resulting code under the GPL.
+ */
+
+#define _PPC_STRING_H_ /* avoid unnecessary str/mem functions */
+#define _LINUX_STRING_H_ /* avoid unnecessary str/mem functions */
+
+#include <common.h>
+#include <syscall.h>
+
+static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr);
+
+int eepro100_eeprom(void)
+{
+ int ret = 0;
+
+ unsigned char hwaddr1[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x05 };
+ unsigned char hwaddr2[6] = { 0x00, 0x00, 0x02, 0x03, 0x04, 0x06 };
+
+#if defined(CONFIG_OXC)
+ ret |= reset_eeprom(0x80000000, hwaddr1);
+ ret |= reset_eeprom(0x81000000, hwaddr2);
+#endif
+
+ return ret;
+}
+
+/* Default EEPROM for i82559 */
+static unsigned short default_eeprom[64] = {
+ 0x0100, 0x0302, 0x0504, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0x40c0, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
+};
+
+static unsigned short eeprom[256];
+
+static int eeprom_size = 64;
+static int eeprom_addr_size = 6;
+
+static int debug = 0;
+
+static inline unsigned short swap16(unsigned short x)
+{
+ return (((x & 0xff) << 8) | ((x & 0xff00) >> 8));
+}
+
+static inline void outw(short data, long addr)
+{
+ *(volatile short *)(addr) = swap16(data);
+}
+
+static inline short inw(long addr)
+{
+ return swap16(*(volatile short *)(addr));
+}
+
+static inline void *memcpy(void *dst, const void *src, unsigned int len)
+{
+ void * ret = dst;
+ while (len-- > 0) *((char *)dst)++ = *((char *)src)++;
+ return ret;
+}
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+/* Serial EEPROM section. */
+#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
+#define EE_CS 0x02 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+#define EE_WRITE_0 0x4802
+#define EE_WRITE_1 0x4806
+#define EE_OFFSET 14
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay(ee_addr) inw(ee_addr)
+
+/* Wait for the EEPROM to finish the previous operation. */
+static int eeprom_busy_poll(long ee_ioaddr)
+{
+ int i;
+ outw(EE_ENB, ee_ioaddr);
+ for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
+ if (inw(ee_ioaddr) & EE_DATA_READ)
+ break;
+ return i;
+}
+
+/* This executes a generic EEPROM command, typically a write or write enable.
+ It returns the data output from the EEPROM, and thus may also be used for
+ reads. */
+static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
+{
+ unsigned retval = 0;
+ long ee_addr = ioaddr + EE_OFFSET;
+
+ if (debug > 1)
+ mon_printf(" EEPROM op 0x%x: ", cmd);
+
+ outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
+
+ /* Shift the command bits out. */
+ do {
+ short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+ outw(dataval, ee_addr);
+ eeprom_delay(ee_addr);
+ if (debug > 2)
+ mon_printf("%X", inw(ee_addr) & 15);
+ outw(dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay(ee_addr);
+ retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ } while (--cmd_len >= 0);
+#if 0
+ outw(EE_ENB, ee_addr);
+#endif
+ /* Terminate the EEPROM access. */
+ outw(EE_ENB & ~EE_CS, ee_addr);
+ if (debug > 1)
+ mon_printf(" EEPROM result is 0x%5.5x.\n", retval);
+ return retval;
+}
+
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+ return do_eeprom_cmd(ioaddr, ((EE_READ_CMD << addr_len) | location)
+ << 16 , 3 + addr_len + 16) & 0xffff;
+}
+
+static void write_eeprom(long ioaddr, int index, int value, int addr_len)
+{
+ long ee_ioaddr = ioaddr + EE_OFFSET;
+ int i;
+
+ /* Poll for previous op finished. */
+ eeprom_busy_poll(ee_ioaddr); /* Typical 0 ticks */
+ /* Enable programming modes. */
+ do_eeprom_cmd(ioaddr, (0x4f << (addr_len-4)), 3 + addr_len);
+ /* Do the actual write. */
+ do_eeprom_cmd(ioaddr,
+ (((EE_WRITE_CMD<<addr_len) | index)<<16) | (value & 0xffff),
+ 3 + addr_len + 16);
+ /* Poll for write finished. */
+ i = eeprom_busy_poll(ee_ioaddr); /* Typical 2000 ticks */
+ if (debug)
+ mon_printf(" Write finished after %d ticks.\n", i);
+ /* Disable programming. This command is not instantaneous, so we check
+ for busy before the next op. */
+ do_eeprom_cmd(ioaddr, (0x40 << (addr_len-4)), 3 + addr_len);
+ eeprom_busy_poll(ee_ioaddr);
+}
+
+static int reset_eeprom(unsigned long ioaddr, unsigned char *hwaddr)
+{
+ unsigned short checksum = 0;
+ int size_test;
+ int i;
+
+ mon_printf("Resetting i82559 EEPROM @ 0x%08x ... ", ioaddr);
+
+ size_test = do_eeprom_cmd(ioaddr, (EE_READ_CMD << 8) << 16, 27);
+ eeprom_addr_size = (size_test & 0xffe0000) == 0xffe0000 ? 8 : 6;
+ eeprom_size = 1 << eeprom_addr_size;
+
+ memcpy(eeprom, default_eeprom, sizeof default_eeprom);
+
+ for (i = 0; i < 3; i++)
+ eeprom[i] = (hwaddr[i*2+1]<<8) + hwaddr[i*2];
+
+ /* Recalculate the checksum. */
+ for (i = 0; i < eeprom_size - 1; i++)
+ checksum += eeprom[i];
+ eeprom[i] = 0xBABA - checksum;
+
+ for (i = 0; i < eeprom_size; i++)
+ write_eeprom(ioaddr, i, eeprom[i], eeprom_addr_size);
+
+ for (i = 0; i < eeprom_size; i++)
+ if (read_eeprom(ioaddr, i, eeprom_addr_size) != eeprom[i]) {
+ mon_printf("failed\n");
+ return 1;
+ }
+
+ mon_printf("done\n");
+ return 0;
+}
+
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _PCMCIA_H
+#define _PCMCIA_H
+
+#include <common.h>
+#include <config.h>
+
+/*
+ * Allow configuration to select PCMCIA slot,
+ * or try to generate a useful default
+ */
+#if ( CONFIG_COMMANDS & CFG_CMD_PCMCIA) || \
+ ((CONFIG_COMMANDS & CFG_CMD_IDE) && \
+ (defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) ) )
+
+#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
+
+ /* The RPX series use SLOT_B */
+#if defined(CONFIG_RPXCLASSIC) || defined(CONFIG_RPXLITE)
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_ADS) /* The ADS board use SLOT_A */
+# define CONFIG_PCMCIA_SLOT_A
+#elif defined(CONFIG_FADS) /* The FADS series are a mess */
+# if defined(CONFIG_MPC860T) || defined(CONFIG_MPC860) || defined(CONFIG_MPC821)
+# define CONFIG_PCMCIA_SLOT_A
+# else
+# define CONFIG_PCMCIA_SLOT_B
+# endif
+#elif defined(CONFIG_TQM8xxL)
+# define CONFIG_PCMCIA_SLOT_B /* The TQM8xxL use SLOT_B */
+#elif defined(CONFIG_SPD823TS) /* The SPD8xx use SLOT_B */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_IVMS8) || defined(CONFIG_IVML24) /* The IVM* use SLOT_A */
+# define CONFIG_PCMCIA_SLOT_A
+#elif defined(CONFIG_LWMON) /* The LWMON use SLOT_B */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_ICU862) /* The ICU862 use SLOT_B */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_C2MON) /* The C2MON use SLOT_B */
+# define CONFIG_PCMCIA_SLOT_B
+#elif defined(CONFIG_R360MPI) /* The R360MPI use SLOT_B */
+# define CONFIG_PCMCIA_SLOT_B
+#else
+# error "PCMCIA Slot not configured"
+#endif
+
+#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
+
+/* Make sure exactly one slot is defined - we support only one for now */
+#if !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B)
+#error Neither CONFIG_PCMCIA_SLOT_A nor CONFIG_PCMCIA_SLOT_B configured
+#endif
+#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
+#error Both CONFIG_PCMCIA_SLOT_A and CONFIG_PCMCIA_SLOT_B configured
+#endif
+
+#define PCMCIA_SOCKETS_NO 1
+#define PCMCIA_MEM_WIN_NO 4
+#define PCMCIA_IO_WIN_NO 2
+
+/* define _slot_ to be able to optimize macros */
+#ifdef CONFIG_PCMCIA_SLOT_A
+# define _slot_ 0
+# define PCMCIA_SLOT_MSG "slot A"
+# define PCMCIA_SLOT_x PCMCIA_PSLOT_A
+#else
+# define _slot_ 1
+# define PCMCIA_SLOT_MSG "slot B"
+# define PCMCIA_SLOT_x PCMCIA_PSLOT_B
+#endif
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE
+#endif
+
+/*
+ * This structure is used to address each window in the PCMCIA controller.
+ *
+ * Keep in mind that we assume that pcmcia_win_t[n+1] is mapped directly
+ * after pcmcia_win_t[n]...
+ */
+
+typedef struct {
+ ulong br;
+ ulong or;
+} pcmcia_win_t;
+
+/*
+ * Definitions for PCMCIA control registers to operate in IDE mode
+ *
+ * All timing related setup (PCMCIA_SHT, PCMCIA_SST, PCMCIA_SL)
+ * to be done later (depending on CPU clock)
+ */
+
+/* Window 0:
+ * Base: 0xFE100000 CS1
+ * Port Size: 2 Bytes
+ * Port Size: 16 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR0 0xFE100000
+#define CFG_PCMCIA_POR0 ( PCMCIA_BSIZE_2 \
+ | PCMCIA_PPS_16 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 1:
+ * Base: 0xFE100080 CS1
+ * Port Size: 8 Bytes
+ * Port Size: 8 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR1 0xFE100080
+#define CFG_PCMCIA_POR1 ( PCMCIA_BSIZE_8 \
+ | PCMCIA_PPS_8 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 2:
+ * Base: 0xFE100100 CS2
+ * Port Size: 8 Bytes
+ * Port Size: 8 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR2 0xFE100100
+#define CFG_PCMCIA_POR2 ( PCMCIA_BSIZE_8 \
+ | PCMCIA_PPS_8 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 3:
+ * not used
+ */
+#define CFG_PCMCIA_PBR3 0
+#define CFG_PCMCIA_POR3 0
+
+/* Window 4:
+ * Base: 0xFE100C00 CS1
+ * Port Size: 2 Bytes
+ * Port Size: 16 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR4 0xFE100C00
+#define CFG_PCMCIA_POR4 ( PCMCIA_BSIZE_2 \
+ | PCMCIA_PPS_16 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 5:
+ * Base: 0xFE100C80 CS1
+ * Port Size: 8 Bytes
+ * Port Size: 8 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR5 0xFE100C80
+#define CFG_PCMCIA_POR5 ( PCMCIA_BSIZE_8 \
+ | PCMCIA_PPS_8 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 6:
+ * Base: 0xFE100D00 CS2
+ * Port Size: 8 Bytes
+ * Port Size: 8 Bit
+ * Common Memory Space
+ */
+
+#define CFG_PCMCIA_PBR6 0xFE100D00
+#define CFG_PCMCIA_POR6 ( PCMCIA_BSIZE_8 \
+ | PCMCIA_PPS_8 \
+ | PCMCIA_PRS_MEM \
+ | PCMCIA_SLOT_x \
+ | PCMCIA_PV \
+ )
+
+/* Window 7:
+ * not used
+ */
+#define CFG_PCMCIA_PBR7 0
+#define CFG_PCMCIA_POR7 0
+
+/**********************************************************************/
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_LONGLINK_CB 0x02
+#define CISTPL_INDIRECT 0x03
+#define CISTPL_CONFIG_CB 0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC 0x06
+#define CISTPL_BAR 0x07
+#define CISTPL_PWR_MGMNT 0x08
+#define CISTPL_EXTDEVICE 0x09
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_DEVICE_OC 0x1c
+#define CISTPL_DEVICE_OA 0x1d
+#define CISTPL_DEVICE_GEO 0x1e
+#define CISTPL_DEVICE_GEO_A 0x1f
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_END 0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI 0x00
+#define CISTPL_FUNCID_MEMORY 0x01
+#define CISTPL_FUNCID_SERIAL 0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED 0x04
+#define CISTPL_FUNCID_VIDEO 0x05
+#define CISTPL_FUNCID_NETWORK 0x06
+#define CISTPL_FUNCID_AIMS 0x07
+#define CISTPL_FUNCID_SCSI 0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE 0x01
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER 0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON 0x04
+#define CISTPL_IDE_UNIQUE 0x08
+#define CISTPL_IDE_DUAL 0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP 0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE 0x04
+#define CISTPL_IDE_LOW_POWER 0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX 0x20
+#define CISTPL_IDE_IOIS16 0x40
+
+#endif /* CFG_CMD_PCMCIA || CFG_CMD_IDE && (CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT) */
+
+#endif /* _PCMCIA_H */
--- /dev/null
+#ifndef __MON_SYS_CALL_H__
+#define __MON_SYS_CALL_H__
+
+#ifndef __ASSEMBLY__
+
+#include <common.h>
+
+/* These are declarations of system calls available in C code */
+int mon_getc(void);
+int mon_tstc(void);
+void mon_putc(const char);
+void mon_puts(const char*);
+void mon_printf(const char* fmt, ...);
+void mon_install_hdlr(int, interrupt_handler_t*, void*);
+void mon_free_hdlr(int);
+void *mon_malloc(size_t);
+void mon_free(void*);
+
+#endif /* ifndef __ASSEMBLY__ */
+
+#define NR_SYSCALLS 9 /* number of syscalls */
+
+/*
+ * Make sure these functions are in the same order as they
+ * appear in the "examples/syscall.S" file !!!
+ */
+#define SYSCALL_GETC 0
+#define SYSCALL_TSTC 1
+#define SYSCALL_PUTC 2
+#define SYSCALL_PUTS 3
+#define SYSCALL_PRINTF 4
+#define SYSCALL_INSTALL_HDLR 5
+#define SYSCALL_FREE_HDLR 6
+#define SYSCALL_MALLOC 7
+#define SYSCALL_FREE 8
+
+#endif
--- /dev/null
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef USE_HOSTCC /* Shut down "ANSI does not permit..." warnings */
+#include <common.h> /* to get command definitions like CFG_CMD_JFFS2 */
+#endif
+
+#include "zlib.h"
+
+#define local static
+#define ZEXPORT /* empty */
+unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+ Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The table is simply the CRC of all possible eight bit values. This is all
+ the information needed to generate CRC's on data a byte at a time for all
+ combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+ uLong c;
+ int n, k;
+ uLong poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320L) */
+ poly = 0L;
+ for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+ poly |= 1L << (31 - p[n]);
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (uLong)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+#endif
+
+#if 0
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty) make_crc_table();
+#endif
+ return (const uLongf *)crc_table;
+}
+#endif
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+ uLong crc;
+ const Bytef *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return crc ^ 0xffffffffL;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+/* No ones complement version. JFFS2 (and other things ?)
+ * don't use ones compliment in their CRC calculations.
+ */
+uLong ZEXPORT crc32_no_comp(uLong crc, const Bytef *buf, uInt len)
+{
+ if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+
+ return crc;
+}
+
+#endif /* CFG_CMD_JFFS2 */
--- /dev/null
+/*
+ * (C) Copyright 2002
+ * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+
+int write_bat (ppc_bat_t bat, unsigned long upper, unsigned long lower)
+{
+ switch (bat) {
+ case IBAT0:
+ mtspr (IBAT0L, lower);
+ mtspr (IBAT0U, upper);
+ break;
+
+ case IBAT1:
+ mtspr (IBAT1L, lower);
+ mtspr (IBAT1U, upper);
+ break;
+
+ case IBAT2:
+ mtspr (IBAT2L, lower);
+ mtspr (IBAT2U, upper);
+ break;
+
+ case IBAT3:
+ mtspr (IBAT3L, lower);
+ mtspr (IBAT3U, upper);
+ break;
+
+ case DBAT0:
+ mtspr (DBAT0L, lower);
+ mtspr (DBAT0U, upper);
+ break;
+
+ case DBAT1:
+ mtspr (DBAT1L, lower);
+ mtspr (DBAT1U, upper);
+ break;
+
+ case DBAT2:
+ mtspr (DBAT2L, lower);
+ mtspr (DBAT2U, upper);
+ break;
+
+ case DBAT3:
+ mtspr (DBAT3L, lower);
+ mtspr (DBAT3U, upper);
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int read_bat (ppc_bat_t bat, unsigned long *upper, unsigned long *lower)
+{
+ unsigned long register u;
+ unsigned long register l;
+
+ switch (bat) {
+ case IBAT0:
+ l = mfspr (IBAT0L);
+ u = mfspr (IBAT0U);
+ break;
+
+ case IBAT1:
+ l = mfspr (IBAT1L);
+ u = mfspr (IBAT1U);
+ break;
+
+ case IBAT2:
+ l = mfspr (IBAT2L);
+ u = mfspr (IBAT2U);
+ break;
+
+ case IBAT3:
+ l = mfspr (IBAT3L);
+ u = mfspr (IBAT3U);
+ break;
+
+ case DBAT0:
+ l = mfspr (DBAT0L);
+ u = mfspr (DBAT0U);
+ break;
+
+ case DBAT1:
+ l = mfspr (DBAT1L);
+ u = mfspr (DBAT1U);
+ break;
+
+ case DBAT2:
+ l = mfspr (DBAT2L);
+ u = mfspr (DBAT2U);
+ break;
+
+ case DBAT3:
+ l = mfspr (DBAT3L);
+ u = mfspr (DBAT3U);
+ break;
+
+ default:
+ return (-1);
+ }
+
+ *upper = u;
+ *lower = l;
+
+ return (0);
+}
--- /dev/null
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+void flush_cache (ulong start_addr, ulong size)
+{
+ ulong addr, end_addr = start_addr + size;
+
+ if (CFG_CACHELINE_SIZE) {
+ addr = start_addr & (CFG_CACHELINE_SIZE - 1);
+ for (addr = start_addr;
+ addr < end_addr;
+ addr += CFG_CACHELINE_SIZE) {
+ asm ("dcbst 0,%0": :"r" (addr));
+ }
+ asm ("sync"); /* Wait for all dcbst to complete on bus */
+
+ for (addr = start_addr;
+ addr < end_addr;
+ addr += CFG_CACHELINE_SIZE) {
+ asm ("icbi 0,%0": :"r" (addr));
+ }
+ }
+ asm ("sync"); /* Always flush prefetch queue in any case */
+ asm ("isync");
+}
--- /dev/null
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "bootp.h"
+#include "rarp.h"
+#include "tftp.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+#define TIMEOUT 5 /* Seconds before trying BOOTP again */
+#ifndef CONFIG_NET_RETRY_COUNT
+# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */
+#else
+# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
+#endif
+
+
+int RarpTry;
+
+/*
+ * Handle a RARP received packet.
+ */
+static void
+RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
+{
+#ifdef DEBUG
+ printf("Got good RARP\n");
+#endif
+ TftpStart ();
+}
+
+
+/*
+ * Timeout on BOOTP request.
+ */
+static void
+RarpTimeout(void)
+{
+ if (RarpTry >= TIMEOUT_COUNT) {
+ puts ("\nRetry count exceeded; starting again\n");
+ NetStartAgain ();
+ } else {
+ NetSetTimeout (TIMEOUT * CFG_HZ, RarpTimeout);
+ RarpRequest ();
+ }
+}
+
+
+void
+RarpRequest (void)
+{
+ int i;
+ volatile uchar *pkt;
+ ARP_t * rarp;
+
+ printf("RARP broadcast %d\n", ++RarpTry);
+ pkt = NetTxPacket;
+
+ NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+ pkt += ETHER_HDR_SIZE;
+
+ rarp = (ARP_t *)pkt;
+
+ rarp->ar_hrd = ARP_ETHER;
+ rarp->ar_pro = PROT_IP;
+ rarp->ar_hln = 6;
+ rarp->ar_pln = 4;
+ rarp->ar_op = RARPOP_REQUEST;
+ memcpy (&rarp->ar_data[0], NetOurEther, 6); /* source ET addr */
+ memcpy (&rarp->ar_data[6], &NetOurIP, 4); /* source IP addr */
+ memcpy (&rarp->ar_data[10], NetOurEther, 6); /* dest ET addr = source ET addr ??*/
+ /* dest. IP addr set to broadcast */
+ for (i = 0; i <= 3; i++) {
+ rarp->ar_data[16 + i] = 0xff;
+ }
+
+ NetSendPacket(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+
+ NetSetTimeout(TIMEOUT * CFG_HZ, RarpTimeout);
+ NetSetHandler(RarpHandler);
+}
+
+#endif /* CFG_CMD_NET */
--- /dev/null
+/*
+ * (C) Copyright 2002 SIXNET, dge@sixnetio.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for DS1306 RTC using software SPI
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_DS1306) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static unsigned int bin2bcd(unsigned int n);
+static unsigned char bcd2bin(unsigned char c);
+static void soft_spi_send(unsigned char n);
+static unsigned char soft_spi_read(void);
+static void init_spi(void);
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#define PB_SPISCK 0x00000002 /* PB 30 */
+#define PB_SPIMOSI 0x00000004 /* PB 29 */
+#define PB_SPIMISO 0x00000008 /* PB 28 */
+#define PB_SPI_CE 0x00010000 /* PB 15 */
+
+/* ------------------------------------------------------------------------- */
+
+/* read clock time from DS1306 and return it in *tmp */
+void rtc_get(struct rtc_time *tmp)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ unsigned char spi_byte; /* Data Byte */
+
+ init_spi(); /* set port B for software SPI */
+
+ /* Now we can enable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+ udelay(10);
+
+ /* Shift out the address (0) of the time in the Clock Chip */
+ soft_spi_send(0);
+
+ /* Put the clock readings into the rtc_time structure */
+ tmp->tm_sec = bcd2bin(soft_spi_read()); /* Read seconds */
+ tmp->tm_min = bcd2bin(soft_spi_read()); /* Read minutes */
+
+ /* Hours are trickier */
+ spi_byte = soft_spi_read(); /* Read Hours into temporary value */
+ if (spi_byte & 0x40) {
+ /* 12 hour mode bit is set (time is in 1-12 format) */
+ if (spi_byte & 0x20) {
+ /* since PM we add 11 to get 0-23 for hours */
+ tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) + 11;
+ }
+ else {
+ /* since AM we subtract 1 to get 0-23 for hours */
+ tmp->tm_hour = (bcd2bin(spi_byte & 0x1F)) - 1;
+ }
+ }
+ else {
+ /* Otherwise, 0-23 hour format */
+ tmp->tm_hour = (bcd2bin(spi_byte & 0x3F));
+ }
+
+ soft_spi_read(); /* Read and discard Day of week */
+ tmp->tm_mday = bcd2bin(soft_spi_read()); /* Read Day of the Month */
+ tmp->tm_mon = bcd2bin(soft_spi_read()); /* Read Month */
+
+ /* Read Year and convert to this century */
+ tmp->tm_year = bcd2bin(soft_spi_read()) + 2000;
+
+ /* Now we can disable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ GregorianDay(tmp); /* Determine the day of week */
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* set clock time in DS1306 RTC and in MPC8xx RTC */
+void rtc_set(struct rtc_time *tmp)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+ init_spi(); /* set port B for software SPI */
+
+ /* Now we can enable the DS1306 RTC */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
+ udelay(10);
+
+ /* First disable write protect in the clock chip control register */
+ soft_spi_send(0x8F); /* send address of the control register */
+ soft_spi_send(0x00); /* send control register contents */
+
+ /* Now disable the DS1306 to terminate the write */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
+ udelay(10);
+
+ /* Now enable the DS1306 to initiate a new write */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE;
+ udelay(10);
+
+ /* Next, send the address of the clock time write registers */
+ soft_spi_send(0x80); /* send address of the first time register */
+
+ /* Use Burst Mode to send all of the time data to the clock */
+ bin2bcd(tmp->tm_sec);
+ soft_spi_send(bin2bcd(tmp->tm_sec)); /* Send Seconds */
+ soft_spi_send(bin2bcd(tmp->tm_min)); /* Send Minutes */
+ soft_spi_send(bin2bcd(tmp->tm_hour)); /* Send Hour */
+ soft_spi_send(bin2bcd(tmp->tm_wday)); /* Send Day of the Week */
+ soft_spi_send(bin2bcd(tmp->tm_mday)); /* Send Day of Month */
+ soft_spi_send(bin2bcd(tmp->tm_mon)); /* Send Month */
+ soft_spi_send(bin2bcd(tmp->tm_year - 2000)); /* Send Year */
+
+ /* Now we can disable the Clock chip to terminate the burst write */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ /* Now we can enable the Clock chip to initiate a new write */
+ immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */
+ udelay(10);
+
+ /* First we Enable write protect in the clock chip control register */
+ soft_spi_send(0x8F); /* send address of the control register */
+ soft_spi_send(0x40); /* send out Control Register contents */
+
+ /* Now disable the DS1306 */
+ immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
+ udelay(10);
+
+ /* Set standard MPC8xx clock to the same time so Linux will
+ * see the time even if it doesn't have a DS1306 clock driver.
+ * This helps with experimenting with standard kernels.
+ */
+ {
+ ulong tim;
+
+ tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ immap->im_sitk.sitk_rtck = KAPWR_KEY;
+ immap->im_sit.sit_rtc = tim;
+ }
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_reset(void)
+{
+ return; /* nothing to do */
+}
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned char bcd2bin(unsigned char n)
+{
+ return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static unsigned int bin2bcd(unsigned int n)
+{
+ return (((n / 10) << 4) | (n % 10));
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Initialize Port B for software SPI */
+static void init_spi(void) {
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+ /* Force output pins to begin at logic 0 */
+ immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
+
+ /* Set these 3 signals as outputs */
+ immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
+
+ immap->im_cpm.cp_pbdir &= ~PB_SPIMISO; /* Make MISO pin an input */
+ udelay(10);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
+static void soft_spi_send(unsigned char n)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+ unsigned char bitpos; /* bit position to receive */
+ unsigned char i; /* Loop Control */
+
+ /* bit position to send, start with most significant bit */
+ bitpos = 0x80;
+
+ /* Send 8 bits to software SPI */
+ for (i = 0; i < 8; i++) { /* Loop for 8 bits */
+ immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
+
+ if (n & bitpos)
+ immap->im_cpm.cp_pbdat |= PB_SPIMOSI; /* Set MOSI to 1 */
+ else
+ immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI; /* Set MOSI to 0 */
+ udelay(10);
+
+ immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
+ udelay(10);
+
+ bitpos >>= 1; /* Shift for next bit position */
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
+static unsigned char soft_spi_read(void)
+{
+ volatile immap_t *immap = (immap_t *)CFG_IMMR;
+
+ unsigned char spi_byte = 0; /* Return value, assume success */
+ unsigned char bitpos; /* bit position to receive */
+ unsigned char i; /* Loop Control */
+
+ /* bit position to receive, start with most significant bit */
+ bitpos = 0x80;
+
+ /* Read 8 bits here */
+ for (i = 0; i < 8; i++) { /* Do 8 bits in loop */
+ immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */
+ udelay(10);
+ if (immap->im_cpm.cp_pbdat & PB_SPIMISO) /* Get a bit of data */
+ spi_byte |= bitpos; /* Set data accordingly */
+ immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */
+ udelay(10);
+ bitpos >>= 1; /* Shift for next bit position */
+ }
+
+ return spi_byte; /* Return the byte read */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif
--- /dev/null
+/*
+ * (C) Copyright 2002
+ * Andrew May, Viasat Inc, amay@viasat.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * M41T11 Serial Access Timekeeper(R) SRAM
+ * can you believe a trademark on that?
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+/*
+ I Don't have an example config file but this
+ is what should be done.
+
+#define CONFIG_RTC_M41T11 1
+#define CFG_I2C_RTC_ADDR 0x68
+#if 0
+#define CFG_M41T11_EXT_CENTURY_DATA
+#else
+#define CFG_M41T11_BASE_YEAR 2000
+#endif
+*/
+
+#if defined(CONFIG_RTC_M41T11) && defined(CFG_I2C_RTC_ADDR) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+#define DEBUG 1
+
+static unsigned bcd2bin (uchar n)
+{
+ return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+ return (((n / 10) << 4) | (n % 10));
+}
+
+
+/* ------------------------------------------------------------------------- */
+/*
+ these are simple defines for the chip local to here so they aren't too
+ verbose
+ DAY/DATE aren't nice but that is how they are on the data sheet
+*/
+#define RTC_SEC_ADDR 0x0
+#define RTC_MIN_ADDR 0x1
+#define RTC_HOUR_ADDR 0x2
+#define RTC_DAY_ADDR 0x3
+#define RTC_DATE_ADDR 0x4
+#define RTC_MONTH_ADDR 0x5
+#define RTC_YEARS_ADDR 0x6
+
+#define RTC_REG_CNT 7
+
+#define RTC_CONTROL_ADDR 0x7
+
+
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+
+#define REG_CNT (RTC_REG_CNT+1)
+
+/*
+ you only get 00-99 for the year we will asume you
+ want from the year 2000 if you don't set the config
+*/
+#ifndef CFG_M41T11_BASE_YEAR
+#define CFG_M41T11_BASE_YEAR 2000
+#endif
+
+#else
+/* we will store extra year info in byte 9*/
+#define M41T11_YEAR_DATA 0x8
+#define M41T11_YEAR_SIZE 1
+#define REG_CNT (RTC_REG_CNT+1+M41T11_YEAR_SIZE)
+#endif
+
+#define M41T11_STORAGE_SZ (64-REG_CNT)
+
+void rtc_get (struct rtc_time *tmp)
+{
+ uchar data[RTC_REG_CNT];
+
+ i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+
+ if( data[RTC_SEC_ADDR] & 0x80 ){
+ printf( "m41t11 RTC Clock stopped!!!\n" );
+ }
+ tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F);
+ tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F);
+ tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F);
+ tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F);
+ tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F);
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+ tmp->tm_year = CFG_M41T11_BASE_YEAR
+ + bcd2bin(data[RTC_YEARS_ADDR])
+ + ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
+#else
+ {
+ unsigned char cent;
+ i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
+ if( !(data[RTC_HOUR_ADDR] & 0x80) ){
+ printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
+ }
+ if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){
+ /*century flip store off new year*/
+ cent += 1;
+ i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
+ }
+ tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
+ }
+#endif
+ tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR] & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+ uchar data[RTC_REG_CNT];
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ data[RTC_SEC_ADDR] = bin2bcd(tmp->tm_sec) & 0x7F;/*just in case*/
+ data[RTC_MIN_ADDR] = bin2bcd(tmp->tm_min);
+ data[RTC_HOUR_ADDR] = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/
+ data[RTC_DATE_ADDR] = bin2bcd(tmp->tm_mday) & 0x3F;
+ data[RTC_MONTH_ADDR] = bin2bcd(tmp->tm_mon);
+ data[RTC_DAY_ADDR] = bin2bcd(tmp->tm_wday) & 0x07;
+
+ data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/
+
+ data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/
+#ifndef CFG_M41T11_EXT_CENTURY_DATA
+ if( ((tmp->tm_year - CFG_M41T11_BASE_YEAR) > 200) ||
+ (tmp->tm_year < CFG_M41T11_BASE_YEAR) ){
+ printf( "m41t11 RTC setting year out of range!!need recompile\n" );
+ }
+ data[RTC_HOUR_ADDR] |= (tmp->tm_year - CFG_M41T11_BASE_YEAR) > 100 ? 0x40 : 0;
+#else
+ {
+ unsigned char cent;
+ cent = tmp->tm_year ? tmp->tm_year / 100 : 0;
+ data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0;
+ i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE);
+ }
+#endif
+ i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
+}
+
+void rtc_reset (void)
+{
+ unsigned char val;
+ /* clear all control & status registers */
+ i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1);
+ val = val & 0x7F;/*make sure we are running*/
+ i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT);
+
+ i2c_read(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+ val = val & 0x3F;/*turn off freq test keep calibration*/
+ i2c_write(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1);
+}
+
+int rtc_store(int addr, unsigned char* data, int size)
+{
+ /*don't let things wrap onto the time on a write*/
+ if( (addr+size) >= M41T11_STORAGE_SZ )
+ return 1;
+ return i2c_write( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+}
+
+int rtc_recall(int addr, unsigned char* data, int size)
+{
+ return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
+}
+
+#endif /* CONFIG_RTC_M41T11 && CFG_I2C_RTC_ADDR && CFG_CMD_DATE */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for ST Electronics M48T35Ax RTC
+ */
+
+/*#define DEBUG */
+
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <config.h>
+
+#if defined(CONFIG_RTC_M48T35A) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+static uchar bin2bcd (unsigned int n);
+static unsigned bcd2bin(uchar c);
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+ uchar sec, min, hour, cent_day, date, month, year;
+ uchar ccr; /* Clock control register */
+
+ /* Lock RTC for read using clock control register */
+ ccr = rtc_read(0);
+ ccr = ccr | 0x40;
+ rtc_write(0, ccr);
+
+ sec = rtc_read (0x1);
+ min = rtc_read (0x2);
+ hour = rtc_read (0x3);
+ cent_day= rtc_read (0x4);
+ date = rtc_read (0x5);
+ month = rtc_read (0x6);
+ year = rtc_read (0x7);
+
+ /* UNLock RTC */
+ ccr = rtc_read(0);
+ ccr = ccr & 0xBF;
+ rtc_write(0, ccr);
+
+ debug ( "Get RTC year: %02x month: %02x date: %02x cent_day: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, month, date, cent_day,
+ hour, min, sec );
+
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (date & 0x3F);
+ tmp->tm_mon = bcd2bin (month & 0x1F);
+ tmp->tm_year = bcd2bin (year) + ((cent_day & 0x10) ? 2000 : 1900);
+ tmp->tm_wday = bcd2bin (cent_day & 0x07);
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+ uchar ccr; /* Clock control register */
+ uchar century;
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ /* Lock RTC for write using clock control register */
+ ccr = rtc_read(0);
+ ccr = ccr | 0x80;
+ rtc_write(0, ccr);
+
+ rtc_write (0x07, bin2bcd(tmp->tm_year % 100));
+ rtc_write (0x06, bin2bcd(tmp->tm_mon));
+ rtc_write (0x05, bin2bcd(tmp->tm_mday));
+
+ century = ((tmp->tm_year >= 2000) ? 0x10 : 0) | 0x20;
+ rtc_write (0x04, bin2bcd(tmp->tm_wday) | century);
+
+ rtc_write (0x03, bin2bcd(tmp->tm_hour));
+ rtc_write (0x02, bin2bcd(tmp->tm_min ));
+ rtc_write (0x01, bin2bcd(tmp->tm_sec ));
+
+ /* UNLock RTC */
+ ccr = rtc_read(0);
+ ccr = ccr & 0x7F;
+ rtc_write(0, ccr);
+}
+
+void rtc_reset (void)
+{
+ uchar val;
+
+ /* Clear all clock control registers */
+ rtc_write (0x0, 0x80); /* No Read Lock or calibration */
+
+ /* Clear stop bit */
+ val = rtc_read (0x1);
+ val &= 0x7f;
+ rtc_write(0x1, val);
+
+ /* Enable century / disable frequency test */
+ val = rtc_read (0x4);
+ val = (val & 0xBF) | 0x20;
+ rtc_write(0x4, val);
+
+ /* Clear write lock */
+ rtc_write(0x0, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static uchar rtc_read (uchar reg)
+{
+ uchar val;
+ val = *(unsigned char *)
+ ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg);
+ return val;
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ *(unsigned char *)
+ ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg) = val;
+}
+
+static unsigned bcd2bin (uchar n)
+{
+ return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+ return (((n / 10) << 4) | (n % 10));
+}
+
+#endif /* CONFIG_RTC_M48T35A && CFG_CMD_DATE */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Denis Peter MPL AG Switzerland. d.peter@mpl.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for the MC146818 (PIXX4) RTC
+ */
+
+/*#define DEBUG*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_MC146818) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+static uchar rtc_read (uchar reg);
+static void rtc_write (uchar reg, uchar val);
+static uchar bin2bcd (unsigned int n);
+static unsigned bcd2bin(uchar c);
+
+#define RTC_PORT_MC146818 CFG_ISA_IO_BASE_ADDRESS + 0x70
+#define RTC_SECONDS 0x00
+#define RTC_SECONDS_ALARM 0x01
+#define RTC_MINUTES 0x02
+#define RTC_MINUTES_ALARM 0x03
+#define RTC_HOURS 0x04
+#define RTC_HOURS_ALARM 0x05
+#define RTC_DAY_OF_WEEK 0x06
+#define RTC_DATE_OF_MONTH 0x07
+#define RTC_MONTH 0x08
+#define RTC_YEAR 0x09
+#define RTC_CONFIG_A 0x0A
+#define RTC_CONFIG_B 0x0B
+#define RTC_CONFIG_C 0x0C
+#define RTC_CONFIG_D 0x0D
+
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+ uchar sec, min, hour, mday, wday, mon, year;
+ /* here check if rtc can be accessed */
+ while((rtc_read(RTC_CONFIG_A)&0x80)==0x80);
+ sec = rtc_read (RTC_SECONDS);
+ min = rtc_read (RTC_MINUTES);
+ hour = rtc_read (RTC_HOURS);
+ mday = rtc_read (RTC_DATE_OF_MONTH);
+ wday = rtc_read (RTC_DAY_OF_WEEK);
+ mon = rtc_read (RTC_MONTH);
+ year = rtc_read (RTC_YEAR);
+#ifdef RTC_DEBUG
+ printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x "
+ "hr: %02x min: %02x sec: %02x\n",
+ year, mon_cent, mday, wday,
+ hour, min, sec );
+ printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n",
+ rtc_read (RTC_CONFIG_D) & 0x3F,
+ rtc_read (RTC_HOURS_ALARM),
+ rtc_read (RTC_MINUTES_ALARM),
+ rtc_read (RTC_SECONDS_ALARM) );
+#endif
+ tmp->tm_sec = bcd2bin (sec & 0x7F);
+ tmp->tm_min = bcd2bin (min & 0x7F);
+ tmp->tm_hour = bcd2bin (hour & 0x3F);
+ tmp->tm_mday = bcd2bin (mday & 0x3F);
+ tmp->tm_mon = bcd2bin (mon & 0x1F);
+ tmp->tm_year = bcd2bin (year);
+ tmp->tm_wday = bcd2bin (wday & 0x07);
+ if(tmp->tm_year<70)
+ tmp->tm_year+=2000;
+ else
+ tmp->tm_year+=1900;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+#ifdef RTC_DEBUG
+ printf ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+#ifdef RTC_DEBUG
+ printf ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+#endif
+ rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
+
+ rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100));
+ rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon));
+
+ rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday));
+ rtc_write (RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday));
+ rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour));
+ rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min ));
+ rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec ));
+ rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+
+}
+
+void rtc_reset (void)
+{
+ rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */
+ rtc_write(RTC_CONFIG_A,0x20); /* Normal OP */
+ rtc_write(RTC_CONFIG_B,0x00);
+ rtc_write(RTC_CONFIG_B,0x00);
+ rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CFG_RTC_REG_BASE_ADDR
+/*
+ * use direct memory access
+ */
+static uchar rtc_read (uchar reg)
+{
+ return(in8(CFG_RTC_REG_BASE_ADDR+reg));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ out8(CFG_RTC_REG_BASE_ADDR+reg, val);
+}
+#else
+static uchar rtc_read (uchar reg)
+{
+ out8(RTC_PORT_MC146818,reg);
+ return(in8(RTC_PORT_MC146818+1));
+}
+
+static void rtc_write (uchar reg, uchar val)
+{
+ out8(RTC_PORT_MC146818,reg);
+ out8(RTC_PORT_MC146818+1,val);
+}
+#endif
+
+static unsigned bcd2bin (uchar n)
+{
+ return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
+}
+
+static unsigned char bin2bcd (unsigned int n)
+{
+ return (((n / 10) << 4) | (n % 10));
+}
+
+#endif /* CONFIG_RTC_MC146818 && CFG_CMD_DATE */
--- /dev/null
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for internal RTC of MPC8xx
+ */
+
+/*#define DEBUG*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_MPC8xx) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+/* ------------------------------------------------------------------------- */
+
+void rtc_get (struct rtc_time *tmp)
+{
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ ulong tim;
+
+ tim = immr->im_sit.sit_rtc;
+
+ to_tm (tim, tmp);
+
+ debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+}
+
+void rtc_set (struct rtc_time *tmp)
+{
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+ ulong tim;
+
+ debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ immr->im_sitk.sitk_rtck = KAPWR_KEY;
+ immr->im_sit.sit_rtc = tim;
+}
+
+void rtc_reset (void)
+{
+ return; /* nothing to do */
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* CONFIG_RTC_MPC8xx && CFG_CMD_DATE */