diff options
Diffstat (limited to 'board/gth')
-rw-r--r-- | board/gth/ee_access.c | 335 | ||||
-rw-r--r-- | board/gth/flash.c | 649 |
2 files changed, 984 insertions, 0 deletions
diff --git a/board/gth/ee_access.c b/board/gth/ee_access.c new file mode 100644 index 0000000..716c90e --- /dev/null +++ b/board/gth/ee_access.c @@ -0,0 +1,335 @@ +/* Module for handling DALLAS DS2438, smart battery monitor + Chip can store up to 40 bytes of user data in EEPROM, + perform temp, voltage and current measurements. + Chip also contains a unique serial number. + + Always read/write LSb first + + For documentaion, see data sheet for DS2438, 2438.pdf + + By Thomas.Lange@corelatus.com 001025 */ + +#include <common.h> +#include <config.h> +#include <mpc8xx.h> + +#include <../board/gth/ee_dev.h> + +/* We dont have kernel functions */ +#define printk printf +#define KERN_DEBUG +#define KERN_ERR +#define EIO 1 + +static int Debug = 0; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * lookup table ripped from DS app note 17, understanding and using + * cyclic redundancy checks... + */ + +static u8 crc_lookup[256] = { + 0, 94, 188, 226, 97, 63, 221, 131, + 194, 156, 126, 32, 163, 253, 31, 65, + 157, 195, 33, 127, 252, 162, 64, 30, + 95, 1, 227, 189, 62, 96, 130, 220, + 35, 125, 159, 193, 66, 28, 254, 160, + 225, 191, 93, 3, 128, 222, 60, 98, + 190, 224, 2, 92, 223, 129, 99, 61, + 124, 34, 192, 158, 29, 67, 161, 255, + 70, 24, 250, 164, 39, 121, 155, 197, + 132, 218, 56, 102, 229, 187, 89, 7, + 219, 133, 103, 57, 186, 228, 6, 88, + 25, 71, 165, 251, 120, 38, 196, 154, + 101, 59, 217, 135, 4, 90, 184, 230, + 167, 249, 27, 69, 198, 152, 122, 36, + 248, 166, 68, 26, 153, 199, 37, 123, + 58, 100, 134, 216, 91, 5, 231, 185, + 140, 210, 48, 110, 237, 179, 81, 15, + 78, 16, 242, 172, 47, 113, 147, 205, + 17, 79, 173, 243, 112, 46, 204, 146, + 211, 141, 111, 49, 178, 236, 14, 80, + 175, 241, 19, 77, 206, 144, 114, 44, + 109, 51, 209, 143, 12, 82, 176, 238, + 50, 108, 142, 208, 83, 13, 239, 177, + 240, 174, 76, 18, 145, 207, 45, 115, + 202, 148, 118, 40, 171, 245, 23, 73, + 8, 86, 180, 234, 105, 55, 213, 139, + 87, 9, 235, 181, 54, 104, 138, 212, + 149, 203, 41, 119, 244, 170, 72, 22, + 233, 183, 85, 11, 136, 214, 52, 106, + 43, 117, 151, 201, 74, 20, 246, 168, + 116, 42, 200, 150, 21, 75, 169, 247, + 182, 232, 10, 84, 215, 137, 107, 53 +}; + +static u8 make_new_crc( u8 Old_crc, u8 New_value ){ + /* Compute a new checksum with new byte, using previous checksum as input + See DS app note 17, understanding and using cyclic redundancy checks... + Also see DS2438, page 11 */ + return( crc_lookup[Old_crc ^ New_value ]); +} + +int ee_crc_ok( u8 *Buffer, int Len, u8 Crc ){ + /* Check if the checksum for this buffer is correct */ + u8 Curr_crc=0; + int i; + u8 *Curr_byte = Buffer; + + for(i=0;i<Len;i++){ + Curr_crc = make_new_crc( Curr_crc, *Curr_byte); + Curr_byte++; + } + E_DEBUG("Calculated CRC = 0x%x, read = 0x%x\n", Curr_crc, Crc); + + if(Curr_crc == Crc){ + /* Good */ + return(TRUE); + } + printk(KERN_ERR"EE checksum error, Calculated CRC = 0x%x, read = 0x%x\n", + Curr_crc, Crc); + return(FALSE); +} + +static void +set_idle(void){ + /* Send idle and keep start time + Continous 1 is idle */ + WRITE_PORT(1); +} + +static int +do_reset(void){ + /* Release reset and verify that chip responds with presence pulse */ + int Retries = 0; + while(Retries<5){ + udelay(RESET_LOW_TIME); + + /* Send reset */ + WRITE_PORT(0); + udelay(RESET_LOW_TIME); + + /* Release reset */ + WRITE_PORT(1); + + /* Wait for EEPROM to drive output */ + udelay(PRESENCE_TIMEOUT); + if(!READ_PORT){ + /* Ok, EEPROM is driving a 0 */ + E_DEBUG("Presence detected\n"); + if(Retries){ + E_DEBUG("Retries %d\n",Retries); + } + /* Make sure chip releases pin */ + udelay(PRESENCE_LOW_TIME); + return 0; + } + Retries++; + } + + printk(KERN_ERR"EEPROM did not respond when releasing reset\n"); + + /* Make sure chip releases pin */ + udelay(PRESENCE_LOW_TIME); + + /* Set to idle again */ + set_idle(); + + return(-EIO); +} + +static u8 +read_byte(void){ + /* Read a single byte from EEPROM + Read LSb first */ + int i; + int Value; + u8 Result=0; +#ifndef CFG_IMMR + u32 Flags; +#endif + + E_DEBUG("Reading byte\n"); + + for(i=0;i<8;i++){ + /* Small delay between pulses */ + udelay(1); + +#ifndef CFG_IMMR + /* Disable irq */ + save_flags(Flags); + cli(); +#endif + + /* Pull down pin short time to start read + See page 26 in data sheet */ + + WRITE_PORT(0); + udelay(READ_LOW); + WRITE_PORT(1); + + /* Wait for chip to drive pin */ + udelay(READ_TIMEOUT); + + Value = READ_PORT; + if(Value) + Value=1; + +#ifndef CFG_IMMR + /* Enable irq */ + restore_flags(Flags); +#endif + + /* Wait for chip to release pin */ + udelay(TOTAL_READ_LOW-READ_TIMEOUT); + + /* LSb first */ + Result|=Value<<i; + } + + E_DEBUG("Read byte 0x%x\n",Result); + + return(Result); +} + +static void +write_byte(u8 Byte){ + /* Write a single byte to EEPROM + Write LSb first */ + int i; + int Value; +#ifndef CFG_IMMR + u32 Flags; +#endif + + E_DEBUG("Writing byte 0x%x\n",Byte); + + for(i=0;i<8;i++){ + /* Small delay between pulses */ + udelay(1); + Value = Byte&1; + +#ifndef CFG_IMMR + /* Disable irq */ + save_flags(Flags); + cli(); +#endif + + /* Pull down pin short time for a 1, long time for a 0 + See page 26 in data sheet */ + + WRITE_PORT(0); + if(Value){ + /* Write a 1 */ + udelay(WRITE_1_LOW); + } + else{ + /* Write a 0 */ + udelay(WRITE_0_LOW); + } + + WRITE_PORT(1); + +#ifndef CFG_IMMR + /* Enable irq */ + restore_flags(Flags); +#endif + + if(Value) + /* Wait for chip to read the 1 */ + udelay(TOTAL_WRITE_LOW-WRITE_1_LOW); + Byte>>=1; + } +} + +int ee_do_command( u8 *Tx, int Tx_len, u8 *Rx, int Rx_len, int Send_skip ){ + /* Execute this command string, including + giving reset and setting to idle after command + if Rx_len is set, we read out data from EEPROM */ + int i; + + E_DEBUG("Command, Tx_len %d, Rx_len %d\n", Tx_len, Rx_len ); + + if(do_reset()){ + /* Failed! */ + return(-EIO); + } + + if(Send_skip) + /* Always send SKIP_ROM first to tell chip we are sending a command, + except when we read out rom data for chip */ + write_byte(SKIP_ROM); + + /* Always have Tx data */ + for(i=0;i<Tx_len;i++){ + write_byte(Tx[i]); + } + + if(Rx_len){ + for(i=0;i<Rx_len;i++){ + Rx[i]=read_byte(); + } + } + + set_idle(); + + E_DEBUG("Command done\n"); + + return(0); +} + +int ee_init_data(void){ + int i; + u8 Tx[10]; + int tmp; + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + while(0){ + tmp = 1-tmp; + if(tmp) + immap->im_ioport.iop_padat &= ~PA_FRONT_LED; + else + immap->im_ioport.iop_padat |= PA_FRONT_LED; + udelay(1); + } + + /* Set port to open drain to be able to read data from + port without setting it to input */ + PORT_B_PAR &= ~PB_EEPROM; + PORT_B_ODR |= PB_EEPROM; + SET_PORT_B_OUTPUT(PB_EEPROM); + + /* Set idle mode */ + set_idle(); + + /* Copy all User EEPROM data to scratchpad */ + for(i=0;i<USER_PAGES;i++){ + Tx[0]=RECALL_MEMORY; + Tx[1]=EE_USER_PAGE_0+i; + if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO); + } + + /* Make sure chip doesnt store measurements in NVRAM */ + Tx[0]=WRITE_SCRATCHPAD; + Tx[1]=0; /* Page */ + Tx[2]=9; + if(ee_do_command(Tx,3,NULL,0,TRUE)) return(-EIO); + + Tx[0]=COPY_SCRATCHPAD; + if(ee_do_command(Tx,2,NULL,0,TRUE)) return(-EIO); + + /* FIXME check status bit instead + Could take 10 ms to store in EEPROM */ + for(i=0;i<10;i++){ + udelay(1000); + } + + return(0); +} diff --git a/board/gth/flash.c b/board/gth/flash.c new file mode 100644 index 0000000..562a349 --- /dev/null +++ b/board/gth/flash.c @@ -0,0 +1,649 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc8xx.h> + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (vu_long *addr, flash_info_t *info); +static int write_word (flash_info_t *info, ulong dest, ulong data); +static void flash_get_offsets (ulong base, flash_info_t *info); + +/*----------------------------------------------------------------------- + * Protection Flags: + */ +#define FLAG_PROTECT_SET 0x01 +#define FLAG_PROTECT_CLEAR 0x02 + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + unsigned long size_b0, size_b1; + int i; + + /*printf("faking");*/ + + return(0x1fffff); + + /* Init: no FLASHes known */ + for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) + { + flash_info[i].flash_id = FLASH_UNKNOWN; + } + + /* Static FLASH Bank configuration here - FIXME XXX */ + + size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]); + + if (flash_info[0].flash_id == FLASH_UNKNOWN) + { + printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n", + size_b0, size_b0<<20); + } + +#if 0 + if (FLASH_BASE1_PRELIM != 0x0) { + size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]); + + if (size_b1 > size_b0) { + printf ("## ERROR: Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n", + size_b1, size_b1<<20,size_b0, size_b0<<20); + + flash_info[0].flash_id = FLASH_UNKNOWN; + flash_info[1].flash_id = FLASH_UNKNOWN; + flash_info[0].sector_count = -1; + flash_info[1].sector_count = -1; + flash_info[0].size = 0; + flash_info[1].size = 0; + return (0); + } + } else { +#endif + size_b1 = 0; + + /* Remap FLASH according to real size */ + memctl->memc_or0 = CFG_OR0_PRELIM; + memctl->memc_br0 = CFG_BR0_PRELIM; + + /* Re-do sizing to get full correct info */ + size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]); + + flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]); + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* monitor protection ON by default */ + (void)flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE+CFG_MONITOR_LEN-1, + &flash_info[0]); +#endif + + if (size_b1) + { + /* memctl->memc_or1 = CFG_OR1_PRELIM; + memctl->memc_br1 = CFG_BR1_PRELIM; */ + + /* Re-do sizing to get full correct info */ + size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0), + &flash_info[1]); + + flash_get_offsets (CFG_FLASH_BASE + size_b0, &flash_info[1]); + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* monitor protection ON by default */ + (void)flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE+CFG_MONITOR_LEN-1, + &flash_info[1]); +#endif + } + else + { +/* memctl->memc_or1 = CFG_OR1_PRELIM; + FIXME memctl->memc_br1 = CFG_BR1_PRELIM; */ + + flash_info[1].flash_id = FLASH_UNKNOWN; + flash_info[1].sector_count = -1; + } + + flash_info[0].size = size_b0; + flash_info[1].size = size_b1; + + return (size_b0 + size_b1); +} + + +static void flash_get_offsets (ulong base, flash_info_t *info) +{ + int i; + + /* set up sector start adress table */ + if (info->flash_id & FLASH_BTYPE) + { + /* set sector offsets for bottom boot block type */ + for (i = 0; i < info->sector_count; i++) + { + info->start[i] = base + (i * 0x00040000); + } + } + else + { + /* set sector offsets for top boot block type */ + i = info->sector_count - 1; + for (; i >= 0; i--) + { + info->start[i] = base + i * 0x00040000; + } + } + +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t *info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + printf ("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_AMD: printf ("AMD "); break; + case FLASH_MAN_FUJ: printf ("FUJITSU "); break; + default: printf ("Unknown Vendor "); break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + +#if 0 + case FLASH_AM040B: + printf ("AM29F040B (4 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM040T: + printf ("AM29F040T (4 Mbit, top boot sect)\n"); + break; +#endif + case FLASH_AM400B: + printf ("AM29LV400B (4 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM400T: + printf ("AM29LV400T (4 Mbit, top boot sector)\n"); + break; + case FLASH_AM800B: + printf ("AM29LV800B (8 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM800T: + printf ("AM29LV800T (8 Mbit, top boot sector)\n"); + break; + case FLASH_AM160B: + printf ("AM29LV160B (16 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM160T: + printf ("AM29LV160T (16 Mbit, top boot sector)\n"); + break; + case FLASH_AM320B: + printf ("AM29LV320B (32 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM320T: + printf ("AM29LV320T (32 Mbit, top boot sector)\n"); + break; + default: + printf ("Unknown Chip Type\n"); + break; + } + + printf (" Size: %ld MB in %d Sectors\n", + info->size >> 20, + info->sector_count); + + printf (" Sector Start Addresses:"); + + for (i=0; i<info->sector_count; ++i) + { + if ((i % 5) == 0) + { + printf ("\n "); + } + + printf (" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " "); + } + + printf ("\n"); + return; +} + +/*----------------------------------------------------------------------- + */ + + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ + +static ulong flash_get_size (vu_long *addr, flash_info_t *info) +{ + short i; +#if 0 + ulong base = (ulong)addr; +#endif + uchar value; + + /* Write auto select command: read Manufacturer ID */ +#if 0 + addr[0x0555] = 0x00AA00AA; + addr[0x02AA] = 0x00550055; + addr[0x0555] = 0x00900090; +#else + addr[0x0555] = 0xAAAAAAAA; + addr[0x02AA] = 0x55555555; + addr[0x0555] = 0x90909090; +#endif + + value = addr[0]; + + switch (value) + { + case AMD_MANUFACT:case 0x01: + info->flash_id = FLASH_MAN_AMD; + break; + + case FUJ_MANUFACT: + info->flash_id = FLASH_MAN_FUJ; + break; + + default: + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + break; + } + + value = addr[1]; /* device ID */ + + switch (value) + { +#if 0 + case AMD_ID_F040B: + info->flash_id += FLASH_AM040B; + info->sector_count = 8; + info->size = 0x00200000; + break; /* => 2 MB */ +#endif + case AMD_ID_LV400T: + info->flash_id += FLASH_AM400T; + info->sector_count = 11; + info->size = 0x00100000; + break; /* => 1 MB */ + + case AMD_ID_LV400B: + info->flash_id += FLASH_AM400B; + info->sector_count = 11; + info->size = 0x00100000; + break; /* => 1 MB */ + + case AMD_ID_LV800T: + info->flash_id += FLASH_AM800T; + info->sector_count = 19; + info->size = 0x00200000; + break; /* => 2 MB */ + + case AMD_ID_LV800B: + info->flash_id += FLASH_AM800B; + info->sector_count = 19; + info->size = 0x00200000; + break; /* => 2 MB */ + + case AMD_ID_LV160T: + info->flash_id += FLASH_AM160T; + info->sector_count = 35; + info->size = 0x00400000; + break; /* => 4 MB */ + + case AMD_ID_LV160B: + info->flash_id += FLASH_AM160B; + info->sector_count = 35; + info->size = 0x00400000; + break; /* => 4 MB */ +#if 0 /* enable when device IDs are available */ + case AMD_ID_LV320T: + info->flash_id += FLASH_AM320T; + info->sector_count = 67; + info->size = 0x00800000; + break; /* => 8 MB */ + + case AMD_ID_LV320B: + info->flash_id += FLASH_AM320B; + info->sector_count = 67; + info->size = 0x00800000; + break; /* => 8 MB */ +#endif + default: + info->flash_id = FLASH_UNKNOWN; + return (0); /* => no or unknown flash */ + + } + +#if 0 + /* set up sector start adress table */ + if (info->flash_id & FLASH_BTYPE) { + /* set sector offsets for bottom boot block type */ + info->start[0] = base + 0x00000000; + info->start[1] = base + 0x00008000; + info->start[2] = base + 0x0000C000; + info->start[3] = base + 0x00010000; + for (i = 4; i < info->sector_count; i++) { + info->start[i] = base + (i * 0x00020000) - 0x00060000; + } + } else { + /* set sector offsets for top boot block type */ + i = info->sector_count - 1; + info->start[i--] = base + info->size - 0x00008000; + info->start[i--] = base + info->size - 0x0000C000; + info->start[i--] = base + info->size - 0x00010000; + for (; i >= 0; i--) { + info->start[i] = base + i * 0x00020000; + } + } +#else + flash_get_offsets ((ulong)addr, &flash_info[0]); +#endif + + /* check for protected sectors */ + for (i = 0; i < info->sector_count; i++) + { + /* read sector protection at sector address, (A7 .. A0) = 0x02 */ + /* D0 = 1 if protected */ + addr = (volatile unsigned long *)(info->start[i]); + info->protect[i] = addr[2] & 1; + } + + /* + * Prevent writes to uninitialized FLASH. + */ + if (info->flash_id != FLASH_UNKNOWN) + { + addr = (volatile unsigned long *)info->start[0]; +#if 0 + *addr = 0x00F000F0; /* reset bank */ +#else + *addr = 0xF0F0F0F0; /* reset bank */ +#endif + } + + return (info->size); +} + + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + vu_long *addr = (vu_long*)(info->start[0]); + int flag, prot, sect, l_sect; + ulong start, now, last; + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + if ((info->flash_id == FLASH_UNKNOWN) || + (info->flash_id > FLASH_AMD_COMP)) { + printf ("Can't erase unknown flash type - aborted\n"); + return 1; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf ("- Warning: %d protected sectors will not be erased!\n", + prot); + } else { + printf ("\n"); + } + + l_sect = -1; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + +#if 0 + addr[0x0555] = 0x00AA00AA; + addr[0x02AA] = 0x00550055; + addr[0x0555] = 0x00800080; + addr[0x0555] = 0x00AA00AA; + addr[0x02AA] = 0x00550055; +#else + addr[0x0555] = 0xAAAAAAAA; + addr[0x02AA] = 0x55555555; + addr[0x0555] = 0x80808080; + addr[0x0555] = 0xAAAAAAAA; + addr[0x02AA] = 0x55555555; +#endif + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + addr = (vu_long*)(info->start[sect]); +#if 0 + addr[0] = 0x00300030; +#else + addr[0] = 0x30303030; +#endif + l_sect = sect; + } + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* wait at least 80us - let's wait 1 ms */ + udelay (1000); + + /* + * We wait for the last triggered sector + */ + if (l_sect < 0) + goto DONE; + + start = get_timer (0); + last = start; + addr = (vu_long*)(info->start[l_sect]); +#if 0 + while ((addr[0] & 0x00800080) != 0x00800080) +#else + while ((addr[0] & 0xFFFFFFFF) != 0xFFFFFFFF) +#endif + { + if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout\n"); + return 1; + } + /* show that we're waiting */ + if ((now - last) > 1000) { /* every second */ + putc ('.'); + last = now; + } + } + +DONE: + /* reset to read mode */ + addr = (volatile unsigned long *)info->start[0]; +#if 0 + addr[0] = 0x00F000F0; /* reset bank */ +#else + addr[0] = 0xF0F0F0F0; /* reset bank */ +#endif + + printf (" done\n"); + return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong cp, wp, data; + int i, l, rc; + + wp = (addr & ~3); /* get lower word aligned address */ + + /* + * handle unaligned start bytes + */ + if ((l = addr - wp) != 0) { + data = 0; + for (i=0, cp=wp; i<l; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + for (; i<4 && cnt>0; ++i) { + data = (data << 8) | *src++; + --cnt; + ++cp; + } + for (; cnt==0 && i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + } + + /* + * handle word aligned part + */ + while (cnt >= 4) { + data = 0; + for (i=0; i<4; ++i) { + data = (data << 8) | *src++; + } + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + cnt -= 4; + } + + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { + data = (data << 8) | *src++; + --cnt; + } + for (; i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + return (write_word(info, wp, data)); +} +/*----------------------------------------------------------------------- + * Write a word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_word (flash_info_t *info, ulong dest, ulong data) +{ + vu_long *addr = (vu_long*)(info->start[0]); + ulong start; + int flag; + + /* Check if Flash is (sufficiently) erased */ + if ((*((vu_long *)dest) & data) != data) { + return (2); + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + +#if 0 + addr[0x0555] = 0x00AA00AA; + addr[0x02AA] = 0x00550055; + addr[0x0555] = 0x00A000A0; +#else + addr[0x0555] = 0xAAAAAAAA; + addr[0x02AA] = 0x55555555; + addr[0x0555] = 0xA0A0A0A0; +#endif + + *((vu_long *)dest) = data; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* data polling for D7 */ + start = get_timer (0); +#if 0 + while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) +#else + while ((*((vu_long *)dest) & 0x80808080) != (data & 0x80808080)) +#endif + { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + return (1); + } + } + return (0); +} + +/*----------------------------------------------------------------------- + */ |