Mercurial > flash_v2
view packages/devs/flash/intel/stratav2/current/include/flash_strata_v2.inl @ 1718:c8515e560548
2004-08-21 Andrew Lunn <andrew.lunn@ascom.ch>
* include/flash_strata_v2.inl (flash_unlock_block):
* cdl/flash_strata_v2.cdl: CDL to control the maximum number of
blocks the driver supports. Some of the newer strata device has more
than the default maximum of 128. Problem pointed out by Kevin Zhang.
| author | asl |
|---|---|
| date | Sat, 21 Aug 2004 08:48:17 +0000 |
| parents | e4f7f465ee77 |
| children | d2486ee206e4 |
line wrap: on
line source
#ifndef CYGONCE_DEVS_FLASH_STRATA_V2_INL #define CYGONCE_DEVS_FLASH_STRATA_V2_INL //========================================================================== // // flash_strata.inl // // Flash programming for the Strata device // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2004 Andrew Lunn // // eCos 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 or (at your option) any later version. // // eCos 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 eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas, hmt // Contributors: gthomas, asl // Date: 2001-02-14 // Purpose: // Description: // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/system.h> #include <pkgconf/devs_flash_strata_v2.h> #include <pkgconf/hal.h> #include <cyg/hal/hal_arch.h> #define _FLASH_PRIVATE_ #include <cyg/io/flash.h> #include <cyg/io/strata_v2_priv.h> #define _si(p) ((p[1]<<8)|p[0]) #ifdef CYGOPT_DEV_FLASH_STATE_V2_DUMP_UNKNOWN extern void diag_dump_buf(void *buf, CYG_ADDRWORD len); #endif extern int strncmp(const char *s1, const char *s2, size_t len); extern void *memcpy( void *, const void *, size_t ); //---------------------------------------------------------------------------- // Functions that put the flash device into non-read mode must reside // in RAM. static size_t strata_query_hwr (struct cyg_flash_dev *dev, void * data, const size_t len) __attribute__ ((section (".2ram.flash_query"))); static int strata_erase_block (struct cyg_flash_dev *dev, const cyg_flashaddr_t block) __attribute__ ((section (".2ram.flash_erase_block"))); static int strata_program_buf (struct cyg_flash_dev *dev, cyg_flashaddr_t base, const void* data, const size_t len) __attribute__ ((section (".2ram.flash_program_buf"))); #ifdef CYGOPT_DEVS_FLASH_STRATA_V2_LOCKING static int strata_unlock_block(struct cyg_flash_dev *dev, const cyg_flashaddr_t block_base) __attribute__ ((section (".2ram.flash_unlock_block"))); static int strata_lock_block(struct cyg_flash_dev *dev, const cyg_flashaddr_t block_base) __attribute__ ((section (".2ram.flash_lock_block"))); #endif //---------------------------------------------------------------------------- // Private structure used by the device. struct cyg_flash_strata_v2_priv { cyg_block_info_t block_info [1]; unsigned int buffer_size; // Size of write buffer }; //---------------------------------------------------------------------------- static int strata_init (struct cyg_flash_dev *dev) { struct FLASH_query data, *qp; int num_regions, region_size, buffer_size; struct cyg_flash_strata_v2_priv *priv = dev->priv; dev->funs->flash_query(dev, &data, sizeof(data)); qp = &data; if ( ((qp->manuf_code == FLASH_Intel_code) || (qp->manuf_code == FLASH_STMicro_code)) #ifdef CYGOPT_FLASH_IS_BOOTBLOCK // device types go as follows: 0x90 for 16-bits, 0xD0 for 8-bits, // plus 0 or 1 for -T (Top Boot) or -B (Bottom Boot) // [FIXME: whatever that means :FIXME] // [I think it means the boot blocks are top/bottom of addr space] // plus the following size codes: // 0: 16Mbit 2: 8Mbit 4: 4Mbit // 6: 32Mbit 8: 64Mbit #if 16 == CYGNUM_FLASH_WIDTH && (0x90 == (0xF0 & qp->device_code)) // 16-bit devices #elif 8 == CYGNUM_FLASH_WIDTH && (0xD0 == (0xF0 & qp->device_code)) // 8-bit devices #else && 0 #error Only understand 16 and 8-bit bootblock flash types #endif ) { int lookup[] = { 16, 8, 4, 32, 64 }; #define BLOCKSIZE (0x10000) region_size = BLOCKSIZE; num_regions = qp->device_code & 0x0F; num_regions >>= 1; if ( num_regions > 4 ) goto flash_type_unknown; num_regions = lookup[num_regions]; num_regions *= 1024 * 1024; // to bits num_regions /= 8; // to bytes num_regions /= BLOCKSIZE; // to blocks buffer_size = 0; #else // CYGOPT_FLASH_IS_BOOTBLOCK && (strncmp(qp->id, "QRY", 3) == 0)) { num_regions = _si(qp->num_regions)+1; region_size = _si(qp->region_size)*256; if (_si(qp->buffer_size)) { buffer_size = CYGNUM_FLASH_INTERLEAVE << _si(qp->buffer_size); } else { buffer_size = 0; } #endif // Not CYGOPT_FLASH_IS_BOOTBLOCK dev->end = dev->start + (num_regions*region_size*CYGNUM_FLASH_INTERLEAVE); priv->buffer_size = buffer_size; priv->block_info[0].blocks = num_regions; priv->block_info[0].block_size = region_size * CYGNUM_FLASH_INTERLEAVE; dev->block_info = priv->block_info; dev->num_block_infos = 1; #ifdef CYGNUM_FLASH_BASE_MASK // Then this gives us a maximum size for the (visible) device. // This is to cope with oversize devices fitted, with some high // address lines ignored. if ( (dev->start & CYGNUM_FLASH_BASE_MASK) != ((dev->end - 1) & CYGNUM_FLASH_BASE_MASK ) ) { // then the size of the device appears to span >1 device-worth! unsigned int x; x = (~(CYGNUM_FLASH_BASE_MASK)) + 1; // expected device size x += (unsigned int)dev->start; if ( x < (unsigned int)dev->end ) { // 2nd sanity check (dev->pf)("\nFLASH: Oversized device! End addr %p changed to %p\n", dev->end, (void *)x ); dev->end = x; // Also adjust the block count else unlock crashes! x = ((cyg_uint8 *)dev->end - (cyg_uint8 *)dev->start) / priv->block_info[0].block_size; priv->block_info[0].blocks = x; } } #endif // CYGNUM_FLASH_BASE_MASK return CYG_FLASH_ERR_OK; } #ifdef CYGOPT_FLASH_IS_BOOTBLOCK flash_type_unknown: #endif #ifdef CYGOPT_DEV_FLASH_STATE_V2_DUMP_UNKNOWN (dev->pf)("Can't identify FLASH, sorry, man %x, dev %x, id [%4s] \n", qp->manuf_code, qp->device_code, qp->id ); diag_dump_buf(qp, sizeof(data)); #endif return CYG_FLASH_ERR_HWR; } //---------------------------------------------------------------------------- // Map a hardware status to a package error static int strata_hwr_map_error (struct cyg_flash_dev *dev, int err) { if (err & FLASH_ErrorMask) { (dev->pf)("Err = %x\n", err); if (err & FLASH_ErrorProgram) return CYG_FLASH_ERR_PROGRAM; else if (err & FLASH_ErrorErase) return CYG_FLASH_ERR_ERASE; else return CYG_FLASH_ERR_HWR; // FIXME } else { return CYG_FLASH_ERR_OK; } } //---------------------------------------------------------------------------- #define CNT 20*1000*10 // Approx 20ms static size_t strata_query_hwr (struct cyg_flash_dev *dev, void *data_dst, const size_t len) { volatile flash_t *ROM; int i, cnt; unsigned char *data = (unsigned char *)data_dst; // Get base address and map addresses to virtual addresses ROM = FLASH_P2V( dev->start ); #ifdef CYGOPT_FLASH_IS_BOOTBLOCK // BootBlock flash does not support full Read_Query - we have do a // table oriented thing above, after getting just two bytes of results: ROM[0] = FLASH_Read_ID; i = 2; #else // StrataFlash supports the full Read_Query op: ROM[0] = FLASH_Read_Query; i = sizeof(struct FLASH_query); #endif // Not CYGOPT_FLASH_IS_BOOTBLOCK for (cnt = CNT; cnt > 0; cnt--) ; for ( /* i */; i > 0; i-- ) { // It is very deliberate that data is chars NOT flash_t: // The info comes out in bytes regardless of device. *data++ = (unsigned char) (*ROM++); #ifndef CYGOPT_FLASH_IS_BOOTBLOCK # if 8 == CYGNUM_FLASH_WIDTH // strata flash with 'byte-enable' contains the configuration data // at even addresses ++ROM; # endif #endif } ROM[0] = FLASH_Reset; return 0; } //---------------------------------------------------------------------------- static int strata_erase_block (struct cyg_flash_dev *dev, const cyg_flashaddr_t block_base) { volatile flash_t *ROM; flash_t stat = 0; int timeout = 50000; int len, block_len, erase_block_size; volatile flash_t *eb, *block; // Get base address and map addresses to virtual addresses ROM = FLASH_P2V(dev->start); eb = block = FLASH_P2V(block_base); block_len = dev->block_info[0].block_size; #ifdef CYGOPT_FLASH_IS_BOOTBLOCK #define BLOCKSIZE (0x10000*CYGNUM_FLASH_INTERLEAVE) #define ERASE_BLOCKSIZE (0x2000*CYGNUM_FLASH_INTERLEAVE) if ((eb - ROM) < BLOCKSIZE/(sizeof eb[0])) { erase_block_size = ERASE_BLOCKSIZE; } else { erase_block_size = block_size; } #else erase_block_size = dev->block_info[0].block_size; #endif // Clear any error conditions ROM[0] = FLASH_Clear_Status; // Erase block while (block_len > 0) { eb[0] = FLASH_Block_Erase; eb[0] = FLASH_Confirm; timeout = 5000000; while(((stat = eb[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) break; } block_len -= erase_block_size; eb = FLASH_P2V((unsigned int)eb + erase_block_size); } // Restore ROM to "normal" mode ROM[0] = FLASH_Reset; // If an error was reported, see if the block erased anyway if (stat & FLASH_ErrorMask ) { len = dev->block_info[0].block_size; while (len > 0) { if (*block++ != FLASH_BlankValue ) break; len -= sizeof(*block); } if (len == 0) stat = 0; } return stat; } //---------------------------------------------------------------------------- static int strata_program_buf (struct cyg_flash_dev *dev, cyg_flashaddr_t base_addr, const void* data_addr, const size_t total_len) { struct cyg_flash_strata_v2_priv *priv = dev->priv; volatile flash_t *ROM; volatile flash_t *BA, *addr; flash_t * data = (flash_t *)data_addr; flash_t stat = 0; int timeout = 50000; int len = total_len; #ifdef FLASH_Write_Buffer int i, wc; #endif // Get base address and map addresses to virtual addresses ROM = FLASH_P2V( dev->start ); BA = addr = FLASH_P2V(base_addr); // Clear any error conditions ROM[0] = FLASH_Clear_Status; #ifdef FLASH_Write_Buffer // Write any big chunks first while (len >= priv->buffer_size) { wc = priv->buffer_size; if (wc > len) wc = len; len -= wc; // convert 'wc' in bytes to 'wc' in 'flash_t' wc = wc / sizeof(flash_t); // Word count *BA = FLASH_Write_Buffer; timeout = 5000000; while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) { goto bad; } *BA = FLASH_Write_Buffer; } *BA = FLASHWORD(wc-1); // Count is 0..N-1 for (i = 0; i < wc; i++) { #ifdef CYGHWR_FLASH_WRITE_ELEM CYGHWR_FLASH_WRITE_ELEM(addr+i, data+i); #else *(addr+i) = *(data+i); #endif } *BA = FLASH_Confirm; ROM[0] = FLASH_Read_Status; timeout = 5000000; while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) { goto bad; } } // Jump out if there was an error if (stat & FLASH_ErrorMask) { goto bad; } // And verify the data - also increments the pointers. *BA = FLASH_Reset; for (i = 0; i < wc; i++) { if ( *addr++ != *data++ ) { stat = FLASH_ErrorNotVerified; goto bad; } } } #endif while (len > 0) { BA[0] = FLASH_Program; #ifdef CYGHWR_FLASH_WRITE_ELEM CYGHWR_FLASH_WRITE_ELEM(addr, data); #else *addr = *data; #endif timeout = 5000000; while(((stat = BA[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) { goto bad; } } if (stat & FLASH_ErrorMask) { break; } BA[0] = FLASH_Reset; if (*addr++ != *data++) { stat = FLASH_ErrorNotVerified; break; } len -= sizeof( flash_t ); } // Restore ROM to "normal" mode bad: BA[0] = FLASH_Reset; return stat; } #ifdef CYGOPT_DEVS_FLASH_STRATA_V2_LOCKING //---------------------------------------------------------------------------- // // The difficulty with this operation is that the hardware does not support // unlocking single blocks. However, the logical layer would like this to // be the case, so this routine emulates it. The hardware can clear all of // the locks in the device at once. This routine will use that approach and // then reset the regions which are known to be locked. // #define FLASH_LOCK_MASK 0x1 // which bit of the read query has the lock bit static int strata_unlock_block(struct cyg_flash_dev *dev, const cyg_flashaddr_t block_base) { volatile flash_t *ROM; flash_t stat; int timeout = 5000000; #ifndef CYGOPT_FLASH_IS_SYNCHRONOUS int i; volatile flash_t *bp, *bpv, *block; unsigned char is_locked[CYGNUM_DEVS_FLASH_STRATA_V2_MAX_BLOCKS]; #endif // Get base address and map addresses to virtual addresses ROM = FLASH_P2V( dev->start ); block = FLASH_P2V(block_base); // Clear any error conditions ROM[0] = FLASH_Clear_Status; #ifdef CYGOPT_FLASH_IS_SYNCHRONOUS // Clear lock bit block[0] = FLASH_Clear_Locks; block[0] = FLASH_Clear_Locks_Confirm; // Confirmation while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) break; } #else // Get current block lock state. This needs to access each block on // the device so currently locked blocks can be re-locked. bp = ROM; for (i = 0; i < dev->block_info[0].blocks; i++) { bpv = FLASH_P2V( bp ); *bpv = FLASH_Read_Query; if (bpv == block) { is_locked[i] = 0; } else { #if 8 == CYGNUM_FLASH_WIDTH is_locked[i] = bpv[4] & FLASH_LOCK_MASK; #else is_locked[i] = bpv[2] & FLASH_LOCK_MASK; # endif } bp += dev->block_info[0].block_size / sizeof(*bp); } // Clears all lock bits ROM[0] = FLASH_Clear_Locks; ROM[0] = FLASH_Clear_Locks_Confirm; // Confirmation timeout = 5000000; while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) break; } // Restore the lock state bp = ROM; for (i = 0; i < dev->block_info[0].blocks; i++) { bpv = FLASH_P2V( bp ); if (is_locked[i]) { *bpv = FLASH_Set_Lock; *bpv = FLASH_Set_Lock_Confirm; // Confirmation timeout = 5000000; while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) break; } } bp += dev->block_info[0].block_size / sizeof(*bp); } #endif // CYGOPT_FLASH_IS_SYNCHRONOUS // Restore ROM to "normal" mode ROM[0] = FLASH_Reset; return stat; } //---------------------------------------------------------------------------- static int strata_lock_block(struct cyg_flash_dev *dev, const cyg_flashaddr_t block_base) { volatile flash_t *ROM; flash_t stat; int timeout = 5000000; volatile flash_t *block; // Get base address and map addresses to virtual addresses ROM = FLASH_P2V(dev->start); block = FLASH_P2V(block_base); // Clear any error conditions ROM[0] = FLASH_Clear_Status; // Set lock bit block[0] = FLASH_Set_Lock; block[0] = FLASH_Set_Lock_Confirm; // Confirmation while(((stat = ROM[0]) & FLASH_Status_Ready) != FLASH_Status_Ready) { if (--timeout == 0) break; } // Restore ROM to "normal" mode ROM[0] = FLASH_Reset; return stat; } #endif //---------------------------------------------------------------------------- #ifdef CYGOPT_DEVS_FLASH_STRATA_V2_LOCKING static CYG_FLASH_FUNS (cyg_flash_strata_v2_funs, strata_init, strata_query_hwr, strata_erase_block, strata_program_buf, NULL, strata_hwr_map_error, strata_lock_block, strata_unlock_block); #else static CYG_FLASH_FUNS (cyg_flash_strata_v2_funs, strata_init, strata_query_hwr, strata_erase_block, strata_program_buf, NULL, strata_hwr_map_error, NULL, NULL); #endif #endif //CYGONCE_DEVS_FLASH_STRATA_V2_INL // EOF strata.c
