diff options
Diffstat (limited to 'ecos/packages/devs/flash/arm/lpc2xxx/current/src/flash_arm_lpc2xxx.c')
-rw-r--r-- | ecos/packages/devs/flash/arm/lpc2xxx/current/src/flash_arm_lpc2xxx.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/ecos/packages/devs/flash/arm/lpc2xxx/current/src/flash_arm_lpc2xxx.c b/ecos/packages/devs/flash/arm/lpc2xxx/current/src/flash_arm_lpc2xxx.c new file mode 100644 index 0000000..85b6dcc --- /dev/null +++ b/ecos/packages/devs/flash/arm/lpc2xxx/current/src/flash_arm_lpc2xxx.c @@ -0,0 +1,218 @@ +//========================================================================== +// +// flash_arm_lpc2xxx.c +// +// Flash programming for LPC2xxx +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> +// Contributors: +// Date: 2007-07-12 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> +#include <pkgconf/devs_flash_arm_lpc2xxx.h> +#include <pkgconf/hal.h> +#include <pkgconf/hal_arm.h> +#include <cyg/hal/hal_intr.h> + +#include <cyg/io/flash.h> +#include <cyg/io/flash_dev.h> + +#include "flash_arm_lpc2xxx.h" + +/* gcc builtins */ +extern void* memcpy(void *, const void *, size_t); +extern void* memset(void *, int, size_t); + +/* wrapper for simpler IAP access */ +static void +iap(struct iap_param *param, struct iap_param *result) +{ + static void (* const iap)(struct iap_param *, struct iap_param *) + = (void (*)(struct iap_param *, struct iap_param *)) IAP_LOCATION; + cyg_uint32 cpsr; + + HAL_DISABLE_INTERRUPTS(cpsr); + iap(param, result); + HAL_RESTORE_INTERRUPTS(cpsr); +} + +void +flash_query(void *data) +{ + /* nothing to do here */ +} + +/* + * 248k in 31 blocks by 8k there actually less blocks since two of + * them are 64k, but accessing anything but the last few 8k blocks is + * not supported anyway + */ +int +flash_hwr_init(void) +{ + flash_info.block_size = 8 * 1024; + flash_info.blocks = 31; + flash_info.start = (void *) 0; + flash_info.end = (void *) (248 * 1024); + + return FLASH_ERR_OK; +} + + +static const cyg_uint8 flash_errors[12] = { + FLASH_ERR_OK, /* IAP_CMD_SUCCESS */ + FLASH_ERR_PROTOCOL, /* IAP_INV_COMMAND */ + FLASH_ERR_INVALID, /* IAP_SRC_ADDRERR */ + FLASH_ERR_INVALID, /* IAP_DST_ADDRERR */ + FLASH_ERR_INVALID, /* IAP_SRC_ADDRMAP */ + FLASH_ERR_INVALID, /* IAP_DST_ADDRMAP */ + FLASH_ERR_INVALID, /* IAP_CNT_INVALID */ + FLASH_ERR_INVALID, /* IAP_SEC_INVALID */ + FLASH_ERR_PROTOCOL, /* IAP_SEC_NOTBLNK */ + FLASH_ERR_PROTOCOL, /* IAP_SEC_NOTPREP */ + FLASH_ERR_DRV_VERIFY, /* IAP_CMP_INEQUAL */ + FLASH_ERR_DRV_TIMEOUT, /* IAP_BSY */ +}; + +int +flash_hwr_map_error(e) +{ + if(e > 11) + return FLASH_ERR_PROTOCOL; + return flash_errors[e]; +} + +/* this will not work for flash addresses < 0x30000 */ +static int +block_by_addr(cyg_uint32 addr) +{ + int block; + + block = (addr >> 13) & 0x1f; + block -= 14; + + return block; +} + +int +flash_erase_block(void *block, unsigned int size) +{ + struct iap_param param, result; + + param.code = IAP_PREPARE; + + param.p[0] = param.p[1] = block_by_addr((cyg_uint32) block); + if(param.p[0] < 10) + return FLASH_ERR_INVALID; + + /* prepare sector(s) */ + iap(¶m, &result); + if(result.code != IAP_CMD_SUCCESS) + return result.code; + + param.code = IAP_ERASE; + param.p[2] = CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / 1000; + + /* erase sector(s) */ + iap(¶m, &result); + return result.code; +} + +int +flash_program_buf(void *addr, void *data, int len) +{ + static const int size = CYGPKG_DEVS_FLASH_ARM_LPC2XXX_BUFSIZE; + static const cyg_uint32 b = (0x40004000 - 32 - + CYGPKG_DEVS_FLASH_ARM_LPC2XXX_BUFSIZE); + static void * const buf = (void *) (0x40004000 - 32 - + CYGPKG_DEVS_FLASH_ARM_LPC2XXX_BUFSIZE); + cyg_uint32 a = (cyg_uint32) addr; + char *d = (char *) data; + struct iap_param param, result; + + param.code = IAP_PREPARE; + param.p[0] = block_by_addr(a); + param.p[1] = block_by_addr(a + len - 1); + if(param.p[0] < 10 || param.p[1] > 16) + return FLASH_ERR_INVALID; + + do { + /* prepare sector(s) */ + iap(¶m, &result); + if(result.code != IAP_CMD_SUCCESS) + return result.code; + + if(len < size) + memset(buf, 0xff, size); + memcpy(buf, d, size); + + param.code = IAP_COPY; + param.p[0] = a; + param.p[1] = b; + param.p[2] = size; + param.p[3] = CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / 1000; + + /* copy ram to flash */ + iap(¶m, &result); + if(result.code != IAP_CMD_SUCCESS) + return result.code; + + len -= size; + a += size; + d += size; + } while(len > 0); + + return(result.code); +} + +bool +flash_code_overlaps(void *start, void *end) +{ + extern unsigned char _stext[], _etext[]; + + return ((((unsigned long)&_stext >= (unsigned long)start) && + ((unsigned long)&_stext < (unsigned long)end)) || + (((unsigned long)&_etext >= (unsigned long)start) && + ((unsigned long)&_etext < (unsigned long)end))); +} |