diff options
author | wdenk <wdenk> | 2002-08-17 09:36:01 (GMT) |
---|---|---|
committer | wdenk <wdenk> | 2002-08-17 09:36:01 (GMT) |
commit | affae2bff825c1a8d2cfeaf7b270188d251d39d2 (patch) | |
tree | e025ca5a84cdcd70cff986e09f89e1aaa360499c /board/siemens | |
parent | cf356ef708390102d493c53d18fd19a5963c6aa9 (diff) | |
download | u-boot-fsl-qoriq-affae2bff825c1a8d2cfeaf7b270188d251d39d2.tar.xz |
Initial revision
Diffstat (limited to 'board/siemens')
-rw-r--r-- | board/siemens/CCM/flash.c | 553 | ||||
-rw-r--r-- | board/siemens/IAD210/atm.c | 653 | ||||
-rw-r--r-- | board/siemens/IAD210/flash.c | 502 | ||||
-rw-r--r-- | board/siemens/SCM/flash.c | 488 | ||||
-rw-r--r-- | board/siemens/pcu_e/flash.c | 700 |
5 files changed, 2896 insertions, 0 deletions
diff --git a/board/siemens/CCM/flash.c b/board/siemens/CCM/flash.c new file mode 100644 index 0000000..e56114f --- /dev/null +++ b/board/siemens/CCM/flash.c @@ -0,0 +1,553 @@ +/* + * (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); +} + +/*----------------------------------------------------------------------- + */ diff --git a/board/siemens/IAD210/atm.c b/board/siemens/IAD210/atm.c new file mode 100644 index 0000000..c77e359 --- /dev/null +++ b/board/siemens/IAD210/atm.c @@ -0,0 +1,653 @@ + +#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(); +} diff --git a/board/siemens/IAD210/flash.c b/board/siemens/IAD210/flash.c new file mode 100644 index 0000000..1ed5262 --- /dev/null +++ b/board/siemens/IAD210/flash.c @@ -0,0 +1,502 @@ +/* + * (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); +} + +/*----------------------------------------------------------------------- + */ diff --git a/board/siemens/SCM/flash.c b/board/siemens/SCM/flash.c new file mode 100644 index 0000000..dd7a4cc --- /dev/null +++ b/board/siemens/SCM/flash.c @@ -0,0 +1,488 @@ +/* + * (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); +} diff --git a/board/siemens/pcu_e/flash.c b/board/siemens/pcu_e/flash.c new file mode 100644 index 0000000..b8c0df7 --- /dev/null +++ b/board/siemens/pcu_e/flash.c @@ -0,0 +1,700 @@ +/* + * (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); +} + +/*----------------------------------------------------------------------- + */ |