diff --git a/board/bmw/bmw.h b/board/bmw/bmw.h new file mode 100644 index 0000000..6b7571c --- /dev/null +++ b/board/bmw/bmw.h @@ -0,0 +1,86 @@ +/* + * BMW/MPC8245 Board definitions. + * For more info, see http://www.vooha.com/ + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * James Dougherty (jfd@broadcom.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __BMW_H +#define __BMW_H + +/* System addresses */ + +#define PCI_SPECIAL_BASE 0xfe000000 +#define PCI_SPECIAL_SIZE 0x01000000 + +#define EUMBBAR_VAL 0x80500000 /* Location of EUMB region */ +#define EUMBSIZE 0x00100000 /* Size of EUMB region */ + +/* Extended ROM space devices */ +#define DOC_BASE_ADDR 0xff000000 /* Onboard DOC TSOP 16MB */ +#define DOC2_BASE_ADDR 0x70000000 /* DIP32 socket -> 1GB */ +#define XROM_BASE_ADDR 0x7c000000 /* RCS2 (PAL / Satellite IO) */ +#define PLD_REG_BASE XROM_BASE_ADDR +#define LED_REG_BASE (XROM_BASE_ADDR | 0x2000) +#define TOD_BASE (XROM_BASE_ADDR | 0x4000) +#define LED_REG(x) (*(volatile unsigned char *) \ + (LED_REG_BASE + (x))) +#define XROM_DEV_SIZE 0x00006000 + +#define ENET_DEV_BASE 0x80000000 + +#define PLD_REG(off) (*(volatile unsigned char *)\ + (PLD_REG_BASE + (off))) + +#define PLD_REVID_B1 0x7f /* Fix me */ +#define PLD_REVID_B2 0x01 /* Fix me */ + +#define SYS_HARD_RESET() { for (;;) PLD_REG(0) = 0; } /* clr 0x80 bit */ +#define SYS_REVID_GET() ((int) PLD_REG(0) & 0x7f) +#define SYS_LED_OFF() (PLD_REG(1) |= 0x80) +#define SYS_LED_ON() (PLD_REG(1) &= ~0x80) +#define SYS_WATCHDOG_IRQ3() (PLD_REG(2) |= 0x80) +#define SYS_WATCHDOG_RESET() (PLD_REG(2) &= ~0x80) +#define SYS_TOD_PROTECT() (PLD_REG(3) |= 0x80) +#define SYS_TOD_UNPROTECT() (PLD_REG(3) &= ~0x80) + +#define TOD_REG_BASE (TOD_BASE | 0x1ff0) +#define TOD_NVRAM_BASE TOD_BASE +#define TOD_NVRAM_SIZE 0x1ff0 +#define TOD_NVRAM_LIMIT (TOD_NVRAM_BASE + TOD_NVRAM_SIZE) +#define RTC(r) (TOD_BASE + r) + +/* Onboard BCM570x device */ +#define PCI_ENET_IOADDR 0x80000000 +#define PCI_ENET_MEMADDR 0x80000000 + + +#ifndef __ASSEMBLY__ +/* C Function prototypes */ +void sys_led_msg(char* msg); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __BMW_H */ diff --git a/board/bmw/flash.c b/board/bmw/flash.c new file mode 100644 index 0000000..6a7649f --- /dev/null +++ b/board/bmw/flash.c @@ -0,0 +1,757 @@ +/* + * (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 +#include +#include +#include + +#define ROM_CS0_START 0xFF800000 +#define ROM_CS1_START 0xFF000000 + +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 0 +static void flash_get_offsets (ulong base, flash_info_t *info); +#endif /* 0 */ + +/*flash command address offsets*/ + +#if 0 +#define ADDR0 (0x555) +#define ADDR1 (0x2AA) +#define ADDR3 (0x001) +#else +#define ADDR0 (0xAAA) +#define ADDR1 (0x555) +#define ADDR3 (0x001) +#endif + +#define FLASH_WORD_SIZE unsigned char + +/*----------------------------------------------------------------------- + */ + +#if 0 +static int byte_parity_odd(unsigned char x) __attribute__ ((const)); +#endif /* 0 */ +static unsigned long flash_id(unsigned char mfct, unsigned char chip) __attribute__ ((const)); + +typedef struct +{ + FLASH_WORD_SIZE extval; + unsigned short intval; +} map_entry; + +#if 0 +static int +byte_parity_odd(unsigned char x) +{ + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return (x & 0x1) != 0; +} +#endif /* 0 */ + + + +static unsigned long +flash_id(unsigned char mfct, unsigned char chip) +{ + static const map_entry mfct_map[] = + { + {(FLASH_WORD_SIZE) AMD_MANUFACT, (unsigned short) ((unsigned long) FLASH_MAN_AMD >> 16)}, + {(FLASH_WORD_SIZE) FUJ_MANUFACT, (unsigned short) ((unsigned long) FLASH_MAN_FUJ >> 16)}, + {(FLASH_WORD_SIZE) STM_MANUFACT, (unsigned short) ((unsigned long) FLASH_MAN_STM >> 16)}, + {(FLASH_WORD_SIZE) MT_MANUFACT, (unsigned short) ((unsigned long) FLASH_MAN_MT >> 16)}, + {(FLASH_WORD_SIZE) INTEL_MANUFACT,(unsigned short) ((unsigned long) FLASH_MAN_INTEL >> 16)}, + {(FLASH_WORD_SIZE) INTEL_ALT_MANU,(unsigned short) ((unsigned long) FLASH_MAN_INTEL >> 16)} + }; + + static const map_entry chip_map[] = + { + {AMD_ID_F040B, FLASH_AM040}, + {(FLASH_WORD_SIZE) STM_ID_x800AB, FLASH_STM800AB} + }; + + const map_entry *p; + unsigned long result = FLASH_UNKNOWN; + + /* find chip id */ + for(p = &chip_map[0]; p < &chip_map[sizeof chip_map / sizeof chip_map[0]]; p++) + if(p->extval == chip) + { + result = FLASH_VENDMASK | p->intval; + break; + } + + /* find vendor id */ + for(p = &mfct_map[0]; p < &mfct_map[sizeof mfct_map / sizeof mfct_map[0]]; p++) + if(p->extval == mfct) + { + result &= ~FLASH_VENDMASK; + result |= (unsigned long) p->intval << 16; + break; + } + + return result; +} + + + +unsigned long +flash_init(void) +{ + unsigned long i; + unsigned char j; + static const ulong flash_banks[] = CFG_FLASH_BANKS; + + /* Init: no FLASHes known */ + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) + { + flash_info_t * const pflinfo = &flash_info[i]; + pflinfo->flash_id = FLASH_UNKNOWN; + pflinfo->size = 0; + pflinfo->sector_count = 0; + } + + for(i = 0; i < sizeof flash_banks / sizeof flash_banks[0]; i++) + { + flash_info_t * const pflinfo = &flash_info[i]; + const unsigned long base_address = flash_banks[i]; + volatile FLASH_WORD_SIZE * const flash = (FLASH_WORD_SIZE *) base_address; +#if 0 + volatile FLASH_WORD_SIZE * addr2; +#endif +#if 0 + /* write autoselect sequence */ + flash[0x5555] = 0xaa; + flash[0x2aaa] = 0x55; + flash[0x5555] = 0x90; +#else + flash[0xAAA << (3 * i)] = 0xaa; + flash[0x555 << (3 * i)] = 0x55; + flash[0xAAA << (3 * i)] = 0x90; +#endif + __asm__ __volatile__("sync"); + +#if 0 + pflinfo->flash_id = flash_id(flash[0x0], flash[0x1]); +#else + pflinfo->flash_id = flash_id(flash[0x0], flash[0x2 + 14 * i]); +#endif + + switch(pflinfo->flash_id & FLASH_TYPEMASK) + { + case FLASH_AM040: + pflinfo->size = 0x00080000; + pflinfo->sector_count = 8; + for(j = 0; j < 8; j++) + { + pflinfo->start[j] = base_address + 0x00010000 * j; + pflinfo->protect[j] = flash[(j << 16) | 0x2]; + } + break; + case FLASH_STM800AB: + pflinfo->size = 0x00100000; + pflinfo->sector_count = 19; + pflinfo->start[0] = base_address; + pflinfo->start[1] = base_address + 0x4000; + pflinfo->start[2] = base_address + 0x6000; + pflinfo->start[3] = base_address + 0x8000; + for(j = 1; j < 16; j++) + { + pflinfo->start[j+3] = base_address + 0x00010000 * j; + } +#if 0 + /* check for protected sectors */ + for (j = 0; j < pflinfo->sector_count; j++) { + /* read sector protection at sector address, (A7 .. A0) = 0x02 */ + /* D0 = 1 if protected */ + addr2 = (volatile FLASH_WORD_SIZE *)(pflinfo->start[j]); + if (pflinfo->flash_id & FLASH_MAN_SST) + pflinfo->protect[j] = 0; + else + pflinfo->protect[j] = addr2[2] & 1; + } +#endif + break; + } + /* 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 + +#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR) + flash_protect(FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, + &flash_info[0]); +#endif + + /* reset device to read mode */ + flash[0x0000] = 0xf0; + __asm__ __volatile__("sync"); + } + + return flash_info[0].size + flash_info[1].size; +} + +#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_MAN_SST) + { + 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 /* 0 */ + +/*----------------------------------------------------------------------- + */ +void +flash_print_info(flash_info_t *info) +{ + static const char unk[] = "Unknown"; + const char *mfct = unk, *type = unk; + unsigned int i; + + if(info->flash_id != FLASH_UNKNOWN) + { + switch(info->flash_id & FLASH_VENDMASK) + { + case FLASH_MAN_AMD: mfct = "AMD"; break; + case FLASH_MAN_FUJ: mfct = "FUJITSU"; break; + case FLASH_MAN_STM: mfct = "STM"; break; + case FLASH_MAN_SST: mfct = "SST"; break; + case FLASH_MAN_BM: mfct = "Bright Microelectonics"; break; + case FLASH_MAN_INTEL: mfct = "Intel"; break; + } + + switch(info->flash_id & FLASH_TYPEMASK) + { + case FLASH_AM040: type = "AM29F040B (512K * 8, uniform sector size)"; break; + case FLASH_AM400B: type = "AM29LV400B (4 Mbit, bottom boot sect)"; break; + case FLASH_AM400T: type = "AM29LV400T (4 Mbit, top boot sector)"; break; + case FLASH_AM800B: type = "AM29LV800B (8 Mbit, bottom boot sect)"; break; + case FLASH_AM800T: type = "AM29LV800T (8 Mbit, top boot sector)"; break; + case FLASH_AM160T: type = "AM29LV160T (16 Mbit, top boot sector)"; break; + case FLASH_AM320B: type = "AM29LV320B (32 Mbit, bottom boot sect)"; break; + case FLASH_AM320T: type = "AM29LV320T (32 Mbit, top boot sector)"; break; + case FLASH_STM800AB: type = "M29W800AB (8 Mbit, bottom boot sect)"; break; + case FLASH_SST800A: type = "SST39LF/VF800 (8 Mbit, uniform sector size)"; break; + case FLASH_SST160A: type = "SST39LF/VF160 (16 Mbit, uniform sector size)"; break; + } + } + + printf( + "\n Brand: %s Type: %s\n" + " Size: %lu KB in %d Sectors\n", + mfct, + type, + info->size >> 10, + info->sector_count + ); + + printf (" Sector Start Addresses:"); + + for (i = 0; i < info->sector_count; i++) + { + unsigned long size; + unsigned int erased; + unsigned long * flash = (unsigned long *) info->start[i]; + + /* + * Check if whole sector is erased + */ + size = + (i != (info->sector_count - 1)) ? + (info->start[i + 1] - info->start[i]) >> 2 : + (info->start[0] + info->size - info->start[i]) >> 2; + + for( + flash = (unsigned long *) info->start[i], erased = 1; + (flash != (unsigned long *) info->start[i] + size) && erased; + flash++ + ) + erased = *flash == ~0x0UL; + + printf( + "%s %08lX %s %s", + (i % 5) ? "" : "\n ", + info->start[i], + erased ? "E" : " ", + info->protect[i] ? "RO" : " " + ); + } + + puts("\n"); + return; +} + +#if 0 + +/* + * The following code cannot be run from FLASH! + */ +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; + + printf("flash_get_size: \n"); + /* Write auto select command: read Manufacturer ID */ + eieio(); + addr2[ADDR0] = (FLASH_WORD_SIZE)0xAA; + addr2[ADDR1] = (FLASH_WORD_SIZE)0x55; + addr2[ADDR0] = (FLASH_WORD_SIZE)0x90; + value = addr2[0]; + + 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)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 */ + } + printf("recognised manufacturer"); + + value = addr2[ADDR3]; /* device ID */ + debug ("\ndev_code=%x\n", value); + + switch (value) { + 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 */ + + 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)SST_ID_xF160A: + info->flash_id += FLASH_SST160A; + info->sector_count = 32; + info->size = 0x00200000; + break; /* => 2 MB */ + + case (FLASH_WORD_SIZE)AMD_ID_F040B: + info->flash_id += FLASH_AM040; + info->sector_count = 8; + info->size = 0x00080000; + break; /* => 0.5 MB */ + + default: + info->flash_id = FLASH_UNKNOWN; + return (0); /* => no or unknown flash */ + + } + + printf("flash id %lx; sector count %x, size %lx\n", info->flash_id,info->sector_count,info->size); + /* set up sector start address table */ + if (info->flash_id & FLASH_MAN_SST) + { + 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; + } + } + + /* 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_MAN_SST) + info->protect[i] = 0; + else + info->protect[i] = addr2[2] & 1; + } + + /* + * Prevent writes to uninitialized FLASH. + */ + if (info->flash_id != FLASH_UNKNOWN) { + addr2 = (FLASH_WORD_SIZE *)info->start[0]; + *addr2 = (FLASH_WORD_SIZE)0x00F000F0; /* reset bank */ + } + + return (info->size); +} + +#endif + + +int +flash_erase(flash_info_t *info, int s_first, int s_last) +{ + volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]); + int flag, prot, sect, l_sect; + ulong start, now, last; + unsigned char sh8b; + + 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_MAN_STM | 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; + + /* Check the ROM CS */ + if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START)) + sh8b = 3; + else + sh8b = 0; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055; + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080; + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055; + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + addr = (FLASH_WORD_SIZE *)(info->start[0] + ( + (info->start[sect] - info->start[0]) << sh8b)); + if (info->flash_id & FLASH_MAN_SST) + { + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055; + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00800080; + addr[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA; + addr[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055; + addr[0] = (FLASH_WORD_SIZE)0x00500050; /* block erase */ + udelay(30000); /* wait 30 ms */ + } + else + addr[0] = (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 = (FLASH_WORD_SIZE *)(info->start[0] + ( + (info->start[l_sect] - info->start[0]) << sh8b)); + 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 */ + serial_putc ('.'); + last = now; + } + } + +DONE: + /* reset to read mode */ + addr = (FLASH_WORD_SIZE *)info->start[0]; + addr[0] = (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; i0; ++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 FLASH_WORD_SIZE *addr2 = (FLASH_WORD_SIZE *)info->start[0]; + volatile FLASH_WORD_SIZE *dest2; + volatile FLASH_WORD_SIZE *data2 = (FLASH_WORD_SIZE *)&data; + ulong start; + int flag; + int i; + unsigned char sh8b; + + /* Check the ROM CS */ + if ((info->start[0] >= ROM_CS1_START) && (info->start[0] < ROM_CS0_START)) + sh8b = 3; + else + sh8b = 0; + + dest2 = (FLASH_WORD_SIZE *)(((dest - info->start[0]) << sh8b) + + info->start[0]); + + /* Check if Flash is (sufficiently) erased */ + if ((*dest2 & (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++) + { + addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00AA00AA; + addr2[ADDR1 << sh8b] = (FLASH_WORD_SIZE)0x00550055; + addr2[ADDR0 << sh8b] = (FLASH_WORD_SIZE)0x00A000A0; + + dest2[i << sh8b] = data2[i]; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* data polling for D7 */ + start = get_timer (0); + while ((dest2[i << sh8b] & (FLASH_WORD_SIZE)0x00800080) != + (data2[i] & (FLASH_WORD_SIZE)0x00800080)) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + return (1); + } + } + } + + return (0); +} + +/*----------------------------------------------------------------------- + */ diff --git a/board/cradle/memsetup.S b/board/cradle/memsetup.S new file mode 100644 index 0000000..2f1e042 --- /dev/null +++ b/board/cradle/memsetup.S @@ -0,0 +1,515 @@ +/* + * Most of this taken from Redboot hal_platform_setup.h with cleanup + * + * 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 +#include +#include + +DRAM_SIZE: .long CFG_DRAM_SIZE + +/* wait for coprocessor write complete */ + .macro CPWAIT reg + mrc p15,0,\reg,c2,c0,0 + mov \reg,\reg + sub pc,pc,#4 + .endm + + .macro SET_LED val + ldr r6, =CRADLE_LED_CLR_REG + ldr r7, =0 + str r7, [r6] + ldr r6, =CRADLE_LED_SET_REG + ldr r7, =\val + str r7, [r6] + .endm + + +.globl memsetup +memsetup: + + mov r10, lr + + /* Set up GPIO pins first */ + + ldr r0, =GPSR0 + ldr r1, =CFG_GPSR0_VAL + str r1, [r0] + + ldr r0, =GPSR1 + ldr r1, =CFG_GPSR1_VAL + str r1, [r0] + + ldr r0, =GPSR2 + ldr r1, =CFG_GPSR2_VAL + str r1, [r0] + + ldr r0, =GPCR0 + ldr r1, =CFG_GPCR0_VAL + str r1, [r0] + + ldr r0, =GPCR1 + ldr r1, =CFG_GPCR1_VAL + str r1, [r0] + + ldr r0, =GPCR2 + ldr r1, =CFG_GPCR2_VAL + str r1, [r0] + + ldr r0, =GRER0 + ldr r1, =CFG_GRER0_VAL + str r1, [r0] + + ldr r0, =GRER1 + ldr r1, =CFG_GRER1_VAL + str r1, [r0] + + ldr r0, =GRER2 + ldr r1, =CFG_GRER2_VAL + str r1, [r0] + + ldr r0, =GFER0 + ldr r1, =CFG_GFER0_VAL + str r1, [r0] + + ldr r0, =GFER1 + ldr r1, =CFG_GFER1_VAL + str r1, [r0] + + ldr r0, =GFER2 + ldr r1, =CFG_GFER2_VAL + str r1, [r0] + + ldr r0, =GPDR0 + ldr r1, =CFG_GPDR0_VAL + str r1, [r0] + + ldr r0, =GPDR1 + ldr r1, =CFG_GPDR1_VAL + str r1, [r0] + + ldr r0, =GPDR2 + ldr r1, =CFG_GPDR2_VAL + str r1, [r0] + + ldr r0, =GAFR0_L + ldr r1, =CFG_GAFR0_L_VAL + str r1, [r0] + + ldr r0, =GAFR0_U + ldr r1, =CFG_GAFR0_U_VAL + str r1, [r0] + + ldr r0, =GAFR1_L + ldr r1, =CFG_GAFR1_L_VAL + str r1, [r0] + + ldr r0, =GAFR1_U + ldr r1, =CFG_GAFR1_U_VAL + str r1, [r0] + + ldr r0, =GAFR2_L + ldr r1, =CFG_GAFR2_L_VAL + str r1, [r0] + + ldr r0, =GAFR2_U + ldr r1, =CFG_GAFR2_U_VAL + str r1, [r0] + + /* enable GPIO pins */ + ldr r0, =PSSR + ldr r1, =CFG_PSSR_VAL + str r1, [r0] + + SET_LED 1 + + ldr r3, =MSC1 /* low - bank 2 Lubbock Registers / SRAM */ + ldr r2, =CFG_MSC1_VAL /* high - bank 3 Ethernet Controller */ + str r2, [r3] /* need to set MSC1 before trying to write to the HEX LEDs */ + ldr r2, [r3] /* need to read it back to make sure the value latches (see MSC section of manual) */ + + +/********************************************************************* + Initlialize Memory Controller + + See PXA250 Operating System Developer's Guide + + pause for 200 uSecs- allow internal clocks to settle + *Note: only need this if hard reset... doing it anyway for now +*/ + + @ Step 1 + @ ---- Wait 200 usec + ldr r3, =OSCR @ reset the OS Timer Count to zero + mov r2, #0 + str r2, [r3] + ldr r4, =0x300 @ really 0x2E1 is about 200usec, so 0x300 should be plenty +1: + ldr r2, [r3] + cmp r4, r2 + bgt 1b + + SET_LED 2 + +mem_init: + @ get memory controller base address + ldr r1, =MEMC_BASE + + +@**************************************************************************** +@ Step 2 +@ + + @ Step 2a + @ write msc0, read back to ensure data latches + @ + ldr r2, =CFG_MSC0_VAL + str r2, [r1, #MSC0_OFFSET] + ldr r2, [r1, #MSC0_OFFSET] + + @ write msc1 + ldr r2, =CFG_MSC1_VAL + str r2, [r1, #MSC1_OFFSET] + ldr r2, [r1, #MSC1_OFFSET] + + @ write msc2 + ldr r2, =CFG_MSC2_VAL + str r2, [r1, #MSC2_OFFSET] + ldr r2, [r1, #MSC2_OFFSET] + + @ Step 2b + @ write mecr + ldr r2, =CFG_MECR_VAL + str r2, [r1, #MECR_OFFSET] + + @ write mcmem0 + ldr r2, =CFG_MCMEM0_VAL + str r2, [r1, #MCMEM0_OFFSET] + + @ write mcmem1 + ldr r2, =CFG_MCMEM1_VAL + str r2, [r1, #MCMEM1_OFFSET] + + @ write mcatt0 + ldr r2, =CFG_MCATT0_VAL + str r2, [r1, #MCATT0_OFFSET] + + @ write mcatt1 + ldr r2, =CFG_MCATT1_VAL + str r2, [r1, #MCATT1_OFFSET] + + @ write mcio0 + ldr r2, =CFG_MCIO0_VAL + str r2, [r1, #MCIO0_OFFSET] + + @ write mcio1 + ldr r2, =CFG_MCIO1_VAL + str r2, [r1, #MCIO1_OFFSET] + + /*SET_LED 3 */ + + @ Step 2c + @ fly-by-dma is defeatured on this part + @ write flycnfg + @ldr r2, =CFG_FLYCNFG_VAL + @str r2, [r1, #FLYCNFG_OFFSET] + +/* FIXME Does this sequence really make sense */ +#ifdef REDBOOT_WAY + @ Step 2d + @ get the mdrefr settings + ldr r3, =CFG_MDREFR_VAL + + @ extract DRI field (we need a valid DRI field) + @ + ldr r2, =0xFFF + + @ valid DRI field in r3 + @ + and r3, r3, r2 + + @ get the reset state of MDREFR + @ + ldr r4, [r1, #MDREFR_OFFSET] + + @ clear the DRI field + @ + bic r4, r4, r2 + + @ insert the valid DRI field loaded above + @ + orr r4, r4, r3 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + + @ *Note: preserve the mdrefr value in r4 * + + /*SET_LED 4 */ + +@**************************************************************************** +@ Step 3 +@ +@ NO SRAM + + mov pc, r10 + + +@**************************************************************************** +@ Step 4 +@ + + @ Assumes previous mdrefr value in r4, if not then read current mdrefr + + @ clear the free-running clock bits + @ (clear K0Free, K1Free, K2Free + @ + bic r4, r4, #(0x00800000 | 0x01000000 | 0x02000000) + + @ set K0RUN for CPLD clock + @ + orr r4, r4, #0x00002000 + + @ set K1RUN if bank 0 installed + @ + orr r4, r4, #0x00010000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + ldr r4, [r1, #MDREFR_OFFSET] + + @ deassert SLFRSH + @ + bic r4, r4, #0x00400000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + + @ assert E1PIN + @ + orr r4, r4, #0x00008000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + ldr r4, [r1, #MDREFR_OFFSET] + nop + nop +#else + @ Step 2d + @ get the mdrefr settings + ldr r3, =CFG_MDREFR_VAL + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + + @ Step 4 + + @ set K0RUN for CPLD clock + @ + orr r4, r4, #0x00002000 + + @ set K1RUN for bank 0 + @ + orr r4, r4, #0x00010000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + ldr r4, [r1, #MDREFR_OFFSET] + + @ deassert SLFRSH + @ + bic r4, r4, #0x00400000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + + @ assert E1PIN + @ + orr r4, r4, #0x00008000 + + @ write back mdrefr + @ + str r4, [r1, #MDREFR_OFFSET] + ldr r4, [r1, #MDREFR_OFFSET] + nop + nop +#endif + + @ Step 4d + @ fetch platform value of mdcnfg + @ + ldr r2, =CFG_MDCNFG_VAL + + @ disable all sdram banks + @ + bic r2, r2, #(MDCNFG_DE0 | MDCNFG_DE1) + bic r2, r2, #(MDCNFG_DE2 | MDCNFG_DE3) + + @ program banks 0/1 for bus width + @ + bic r2, r2, #MDCNFG_DWID0 @0=32-bit + + @ write initial value of mdcnfg, w/o enabling sdram banks + @ + str r2, [r1, #MDCNFG_OFFSET] + + @ Step 4e + @ pause for 200 uSecs + @ + ldr r3, =OSCR @ reset the OS Timer Count to zero + mov r2, #0 + str r2, [r3] + ldr r4, =0x300 @ really 0x2E1 is about 200usec, so 0x300 should be plenty +1: + ldr r2, [r3] + cmp r4, r2 + bgt 1b + + /*SET_LED 5 */ + + /* Why is this here??? */ + mov r0, #0x78 @turn everything off + mcr p15, 0, r0, c1, c0, 0 @(caches off, MMU off, etc.) + + @ Step 4f + @ Access memory *not yet enabled* for CBR refresh cycles (8) + @ - CBR is generated for all banks + + ldr r2, =CFG_DRAM_BASE + str r2, [r2] + str r2, [r2] + str r2, [r2] + str r2, [r2] + str r2, [r2] + str r2, [r2] + str r2, [r2] + str r2, [r2] + + @ Step 4g + @get memory controller base address + @ + ldr r1, =MEMC_BASE + + @fetch current mdcnfg value + @ + ldr r3, [r1, #MDCNFG_OFFSET] + + @enable sdram bank 0 if installed (must do for any populated bank) + @ + orr r3, r3, #MDCNFG_DE0 + + @write back mdcnfg, enabling the sdram bank(s) + @ + str r3, [r1, #MDCNFG_OFFSET] + + @ Step 4h + @ write mdmrs + @ + ldr r2, =CFG_MDMRS_VAL + str r2, [r1, #MDMRS_OFFSET] + + @ Done Memory Init + + /*SET_LED 6 */ + + @******************************************************************** + @ Disable (mask) all interrupts at the interrupt controller + @ + + @ clear the interrupt level register (use IRQ, not FIQ) + @ + mov r1, #0 + ldr r2, =ICLR + str r1, [r2] + + @ Set interrupt mask register + @ + ldr r1, =CFG_ICMR_VAL + ldr r2, =ICMR + str r1, [r2] + + @ ******************************************************************** + @ Disable the peripheral clocks, and set the core clock + @ + + @ Turn Off ALL on-chip peripheral clocks for re-configuration + @ + ldr r1, =CKEN + mov r2, #0 + str r2, [r1] + + @ set core clocks + @ + ldr r2, =CFG_CCCR_VAL + ldr r1, =CCCR + str r2, [r1] + +#ifdef ENABLE32KHZ + @ enable the 32Khz oscillator for RTC and PowerManager + @ + ldr r1, =OSCC + mov r2, #OSCC_OON + str r2, [r1] + + @ NOTE: spin here until OSCC.OOK get set, + @ meaning the PLL has settled. + @ +60: + ldr r2, [r1] + ands r2, r2, #1 + beq 60b +#endif + + @ Turn on needed clocks + @ + ldr r1, =CKEN + ldr r2, =CFG_CKEN_VAL + str r2, [r1] + + /*SET_LED 7 */ + +/* Is this needed???? */ +#define NODEBUG +#ifdef NODEBUG + /*Disable software and data breakpoints */ + mov r0,#0 + mcr p15,0,r0,c14,c8,0 /* ibcr0 */ + mcr p15,0,r0,c14,c9,0 /* ibcr1 */ + mcr p15,0,r0,c14,c4,0 /* dbcon */ + + /*Enable all debug functionality */ + mov r0,#0x80000000 + mcr p14,0,r0,c10,c0,0 /* dcsr */ + +#endif + + /*SET_LED 8 */ + + mov pc, r10 + +@ End memsetup