Mercurial > nand-ecoscentric
changeset 2133:6621a815b2a7
* src/at91_flash.c:
* cdl/flash_at91.cdl: .
* ChangeLog: Flash driver for the AT91 Embedded Flash controller,
e.g. the AT91SAM7S devices.
| author | asl |
|---|---|
| date | Sun, 19 Feb 2006 19:43:01 +0000 |
| parents | c672aadf933a |
| children | f018213654da |
| files | packages/devs/flash/arm/at91/current/ChangeLog packages/devs/flash/arm/at91/current/cdl/flash_at91.cdl packages/devs/flash/arm/at91/current/src/at91_flash.c |
| diffstat | 3 files changed, 501 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/devs/flash/arm/at91/current/ChangeLog @@ -0,0 +1,41 @@ +2006-02-19 Oliver Munz <munz@speag.ch> + Andrew Lunn <andrew.lunn@ascom.ch> + + * src/at91_flash.c: + * cdl/flash_at91.cdl: . + * ChangeLog: Flash driver for the AT91 Embedded Flash controller, + e.g. the AT91SAM7S devices. + +//=========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd +// Copyright (C) 2006 Andrew Lunn <andrew.lunn@ascom.ch> +// +// 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. +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//===========================================================================
new file mode 100644 --- /dev/null +++ b/packages/devs/flash/arm/at91/current/cdl/flash_at91.cdl @@ -0,0 +1,78 @@ +# ==================================================================== +# +# flash_at91.cdl +# +# FLASH programming for devices with the Embedded Flash Controller +# +# ==================================================================== +#####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +## Copyright (C) 2006 eCosCentric LTD +## Copyright (C) 2006 Andrew Lunn <andrew.lunn@ascom.ch> +## +## 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. +## ------------------------------------------- +#####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): dmoseley +# Original data: gthomas +# Contributors: Andrew Lunn, Oliver Munz +# Date: 2000-10-25 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_DEVS_FLASH_AT91 { + display "at91 FLASH memory support" + + parent CYGPKG_IO_FLASH + active_if CYGPKG_IO_FLASH + + implements CYGHWR_IO_FLASH_DEVICE + + include_dir . + description "FLASH memory device support for at91 EFC" + compile at91_flash.c + + cdl_option CYGBLD_DEV_FLASH_AT91_LOCKING { + display "Support block locking" + default_value 1 + implements CYGHWR_IO_FLASH_BLOCK_LOCKING + description " + The driver will implement flash block locking when this + option is enabled. Note that the device implements sector + locking, not block locking, where sectors are bigger than + blocks. So the sector which contains the block will be + locked/unlocked + + WARNING: The errata says that these lock bits only have + a life of 100 cycles for the AT91SAM7S devices." + } +} +
new file mode 100644 --- /dev/null +++ b/packages/devs/flash/arm/at91/current/src/at91_flash.c @@ -0,0 +1,382 @@ +//========================================================================== +// +// at91_flash.c +// +// Flash programming for the at91 devices which have the +// Embedded Flash Controller. +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd +// Copyright (C) 2006 Andrew Lunn (andrew.lunn@ascom.ch) +// +// 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. +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas, dmoseley, Andrew Lunn, Oliver Munz +// Date: 2000-07-26 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/hal.h> +#include <pkgconf/devs_flash_at91.h> + +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/infra/cyg_ass.h> + +#define _FLASH_PRIVATE_ +#include <cyg/io/flash.h> + +#include <string.h> + +#define FLASH_TIMEOUT 100000 + +#ifdef CYGBLD_DEV_FLASH_AT91_LOCKING +static cyg_uint32 sector_size; +#endif + +// Disable the flash controller from erasing the page before +// programming it +static void +flash_erase_before_write_disable (void) +{ + cyg_uint32 fmr; + + HAL_READ_UINT32(AT91_MC+AT91_MC_FMR, fmr); + fmr = fmr | AT91_MC_FMR_NEBP; + HAL_WRITE_UINT32(AT91_MC+AT91_MC_FMR, fmr); +} + +// Enable the flash controller to erase the page before programming +// it +static void +flash_erase_before_write_enable (void) +{ + + cyg_uint32 fmr; + + HAL_READ_UINT32(AT91_MC+AT91_MC_FMR, fmr); + fmr = fmr & ~((cyg_uint32) AT91_MC_FMR_NEBP); + HAL_WRITE_UINT32(AT91_MC+AT91_MC_FMR, fmr); +} + +// Is the flash controller ready to accept the next command? +static __inline__ cyg_bool +flash_controller_is_ready(void) +CYGBLD_ATTRIB_SECTION(".2ram.flash_run_command"); + +static __inline__ cyg_bool +flash_controller_is_ready(void) +{ + cyg_uint32 fsr; + + HAL_READ_UINT32(AT91_MC+AT91_MC_FSR, fsr); + return (fsr & AT91_MC_FSR_FRDY ? true : false); +} + +// Busy loop waiting for the controller to finish the command. +// Wait a maximum of timeout loops and then return an error. +static __inline__ int +flash_wait_for_controller (cyg_uint32 timeout) +CYGBLD_ATTRIB_SECTION(".2ram.flash_run_command"); + +static __inline__ int +flash_wait_for_controller (cyg_uint32 timeout) +{ + while (!flash_controller_is_ready()){ + timeout--; + if (!timeout) { + return FLASH_ERR_DRV_TIMEOUT; + } + } + return FLASH_ERR_OK; +} + +// Execute one command on the flash controller. This code should +// probably not be in flash + +static int +flash_run_command(cyg_uint32 page, + cyg_uint32 command, + cyg_uint32 timeout) +CYGBLD_ATTRIB_SECTION(".2ram.flash_run_command"); + +static int +flash_run_command(cyg_uint32 page, + cyg_uint32 command, + cyg_uint32 timeout) +{ + cyg_uint32 retcode; + cyg_uint32 fsr; + cyg_uint32 mask; + + // Wait for the last command to finish + retcode = flash_wait_for_controller(timeout); + if (retcode != FLASH_ERR_OK){ + return retcode; + } + + HAL_DISABLE_INTERRUPTS(mask); + + HAL_WRITE_UINT32(AT91_MC+AT91_MC_FCR, + command | + ((page & AT91_MC_FCR_PAGE_MASK) << AT91_MC_FCR_PAGE_SHIFT) | + AT91_MC_FCR_KEY); + + retcode = flash_wait_for_controller(timeout); + + HAL_RESTORE_INTERRUPTS(mask); + + if (retcode != FLASH_ERR_OK){ + return retcode; + } + + // Check for an error + HAL_READ_UINT32(AT91_MC+AT91_MC_FSR, fsr); + + if ((fsr & AT91_MC_FSR_LOCKE) == AT91_MC_FSR_LOCKE) + return FLASH_ERR_PROTECT; + if ((fsr & AT91_MC_FSR_PROGE) == AT91_MC_FSR_PROGE) + return FLASH_ERR_PROGRAM; + + return FLASH_ERR_OK; +} + +// The flash is embedded in the CPU package. So return the chip +// ID. This allows us to determine if the chip is one we support and +// the size of the flash +int flash_query(void *data) +{ + cyg_uint32 chipID1r; + + HAL_READ_UINT32(AT91_DBG+AT91_DBG_C1R, chipID1r); + + memcpy(data, &chipID1r, sizeof(chipID1r)); + return FLASH_ERR_OK; +} + +// Initialize the hardware. Make sure we have a flash device we know +// how to program and determine its size, the size of the blocks, and +// the number of blocks. The query function returns the chip ID 1 +// register which tells us about the CPU we are running on, the flash +// size etc. Use this information to determine we have a valid setup. +int +flash_hwr_init(void){ + + cyg_uint32 chipID1r; + cyg_uint32 flash_mode; + cyg_uint8 fmcn; + cyg_uint32 lock_bits; + + flash_query (&chipID1r); + + if ((chipID1r & AT91_DBG_C1R_CPU_MASK) != AT91_DBG_C1R_ARM7TDMI) + goto out; + + if ((chipID1r & AT91_DBG_C1R_ARCH_MASK) != AT91_DBG_C1R_ARCH_AT91SAM7Sxx) + goto out; + + if ((chipID1r & AT91_DBG_C1R_FLASH_MASK) == AT91_DBG_C1R_FLASH_0K) + goto out; + + switch (chipID1r & AT91_DBG_C1R_FLASH_MASK) { + case AT91_DBG_C1R_FLASH_32K: + flash_info.block_size = 128; + flash_info.blocks = 256; + lock_bits = 8; + break; + case AT91_DBG_C1R_FLASH_64K: + flash_info.block_size = 128; + flash_info.blocks = 512; + lock_bits = 16; + break; + case AT91_DBG_C1R_FLASH_128K: + flash_info.block_size = 256; + flash_info.blocks = 512; + lock_bits = 8; + break; + case AT91_DBG_C1R_FLASH_256K: + flash_info.block_size = 256; + flash_info.blocks = 1024; + lock_bits = 16; + break; + default: + goto out; + } + flash_info.buffer_size = 0; + flash_info.start = (void *) 0x00100000; + flash_info.end = (void *)(((cyg_uint32) flash_info.start) + + flash_info.block_size * flash_info.blocks); +#ifdef CYGBLD_DEV_FLASH_AT91_LOCKING + sector_size = flash_info.block_size * flash_info.blocks / lock_bits; +#endif + // Set the FLASH clock to 1.5 microseconds based on the MCLK. This + // assumes the CPU is still running from the PLL clock as defined in + // the HAL CDL and the HAL startup code. + fmcn = CYGNUM_HAL_ARM_AT91_CLOCK_SPEED / 1000000 * 1.5; + HAL_READ_UINT32(AT91_MC+AT91_MC_FMR, flash_mode); + flash_mode = flash_mode & ~AT91_MC_FMR_FMCN_MASK; + flash_mode = flash_mode | (fmcn << AT91_MC_FMR_FMCN_SHIFT); + HAL_WRITE_UINT32(AT91_MC+AT91_MC_FMR, flash_mode); + + return FLASH_ERR_OK; + + out: + (*flash_info.pf)("Can't identify FLASH, sorry, ChipID1 %x\n", + chipID1r ); + return FLASH_ERR_HWR; +} + +// Erase a block. The flash controller does not have a command to +// erase a block. So instead we setup the controller to do a program +// writing all 0xff with an erase operation first. +int +flash_erase_block (volatile unsigned long block) +{ + cyg_uint32 retcode; + cyg_uint32 *buffer; + cyg_uint32 *end; + cyg_uint32 page; + + buffer = (cyg_uint32 *) block; + end = (cyg_uint32 *) (block + flash_info.block_size); + + while (buffer < end){ + *buffer = (cyg_uint32) 0xffffffff; + buffer++; + } + + page = ((cyg_uint32) block - (cyg_uint32)flash_info.start) / + flash_info.block_size; + + flash_erase_before_write_enable(); + retcode = flash_run_command(page, + AT91_MC_FCR_START_PROG, + FLASH_TIMEOUT); + + return retcode; +} + +// Write into the flash. The datasheet says that performing 8 or 16bit +// accesses results in unpredictable corruption. So the current code +// checks that these conditions are upheld. It would be possible to +// perform extra reads and masking operation to support writing to +// none word assigned addresses or not multiple or a word length. +int +flash_program_buf (volatile unsigned long addr, unsigned long *data, int len) +{ + cyg_uint32 retcode; + volatile unsigned long *target; + cyg_uint32 page; + + CYG_ASSERT(len % 4 == 0, "Only word writes allowed by current code"); + CYG_ASSERT(addr % 4 == 0, "Address must be word aligned for current code"); + + target = (volatile unsigned long *)addr; + + while (len > 0) { + *target = *data; + data++; + target++; + len = len - sizeof(unsigned long); + } + + page = ((cyg_uint32) addr - (cyg_uint32)flash_info.start) / + flash_info.block_size; + + flash_erase_before_write_disable(); + retcode = flash_run_command(page, + AT91_MC_FCR_START_PROG, + FLASH_TIMEOUT); + + return retcode; +} + +#ifdef CYGBLD_DEV_FLASH_AT91_LOCKING +// Unlock a block. This is not strictly possible, we can only lock and +// unlock sectors. This will unlock the sector which contains the +// block. +int +flash_unlock_block(volatile unsigned long block, int block_size, int blocks) +{ + cyg_uint32 sector; + cyg_uint32 retcode; + + sector = ((cyg_uint32 )block) / sector_size; + + retcode = flash_run_command(sector << 4, + AT91_MC_FCR_UNLOCK, + FLASH_TIMEOUT); + + return retcode; +} + +// Lock a block. This is not strictly possible, we can only lock and +// unlock sectors. This will lock the sector which contains the +// block. +int +flash_lock_block(volatile unsigned long block, int block_size, int blocks) +{ + cyg_uint32 sector; + cyg_uint32 retcode; + + sector = ((cyg_uint32) block) / sector_size; + + retcode = flash_run_command(sector << 4, + AT91_MC_FCR_UNLOCK, + FLASH_TIMEOUT); + + return retcode; +} +#endif + +// Map a hardware status to a package error. NOP since the errors are +// already mapped. +int flash_hwr_map_error(int err){ + + return err; +} + +// See if a range of FLASH addresses overlaps currently running code +bool flash_code_overlaps(void *start, void *end){ + + extern 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))); +}
