Mercurial > flash_v2
changeset 1706:3845779eca10
* src/flash.c: Major rewrite to implement a new API
* src/legacy_api.c: Support the legacy API
* src/legacy_drv.c: Support the legacy driver API
* src/flashiodev.c: Support the new API and multiple devices
* include/flash_priv.h: Interface devices should use
* cdl/io_flash.cdl: Updates for new interface and multiple devices.
| author | asl |
|---|---|
| date | Thu, 05 Aug 2004 13:50:00 +0000 |
| parents | 99834d6b6eeb |
| children | 0943943e5b80 |
| files | packages/io/flash/current/ChangeLog packages/io/flash/current/cdl/io_flash.cdl packages/io/flash/current/doc/flash.sgml packages/io/flash/current/include/flash.h packages/io/flash/current/include/flash_priv.h packages/io/flash/current/src/flash.c packages/io/flash/current/src/flashiodev.c packages/io/flash/current/src/legacy_api.c packages/io/flash/current/src/legacy_dev.c |
| diffstat | 9 files changed, 2393 insertions(+), 773 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/flash/current/ChangeLog +++ b/packages/io/flash/current/ChangeLog @@ -1,3 +1,12 @@ +2004-08-05 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/flash.c: Major rewrite to implement a new API + * src/legacy_api.c: Support the legacy API + * src/legacy_drv.c: Support the legacy driver API + * src/flashiodev.c: Support the new API and multiple devices + * include/flash_priv.h: Interface devices should use + * cdl/io_flash.cdl: Updates for new interface and multiple devices. + 2004-06-20 Andrew Lunn <andrew.lunn@ascom.ch> * src/flash.c (flash_read): Don't check if the flash is write
--- a/packages/io/flash/current/cdl/io_flash.cdl +++ b/packages/io/flash/current/cdl/io_flash.cdl @@ -10,6 +10,7 @@ ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. ## Copyright (C) 2003 Gary Thomas +## 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 @@ -83,7 +84,7 @@ cdl_package CYGPKG_IO_FLASH { Use of this interface is deprecated. Drivers should make sure that the functions are linked to RAM by putting them in .2ram sections." - requires !CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM + requires !CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM } cdl_interface CYGHWR_IO_FLASH_BLOCK_LOCKING { @@ -94,6 +95,22 @@ cdl_package CYGPKG_IO_FLASH { locking (write-protection) of individual blocks." } + cdl_interface CYGHWR_IO_FLASH_DEVICE_LEGACY { + display "Hardware driver uses the legacy interface" + flavor booldata + description " + The flash device driver implements the legacy interface to the + flash library" + } + + cdl_interface CYGHWR_IO_FLASH_DEVICE_V2 { + display "Hardware driver uses the V2 interface" + flavor booldata + description " + The flash device driver implements the V2 interface to the + flash library" + } + cdl_option CYGSEM_IO_FLASH_READ_INDIRECT { display "Hardware cannot support direct access to FLASH memory" flavor bool @@ -134,6 +151,27 @@ cdl_package CYGPKG_IO_FLASH { write-protected or not." } + + cdl_option CYGSEM_IO_FLASH_LEGACY_API { + display "Provide the legacy user API" + flavor bool + default_value 1 + compile legacy_api.c + description " + Provide an implementation of the lagacy user API. This is mapped + onto the new API via a small layer of code" + } + + cdl_option CYGSEM_IO_FLASH_LEGACY_DEVICE_API { + display "Provide the legacy device API" + flavor bool + default_value CYGHWR_IO_FLASH_DEVICE_LEGACY + compile -library=libextras.a legacy_dev.c + description " + Provide an implementation of the legacy device API. This can be + used to interface to one legacy device." + } + cdl_component CYGPKG_IO_FLASH_BLOCK_DEVICE { display "Instantiate in I/O block device API" flavor bool @@ -145,54 +183,164 @@ cdl_package CYGPKG_IO_FLASH { API ( cyg_io_read() etc. )" cdl_component CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1 { - display "Name of flash device 1 block device" + display "Name of flash device 1 block device" flavor data default_value { "\"/dev/flash1\"" } - cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_1 { - requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_1 - no_define - } + cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_1 { + requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_1 + no_define + } + + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_1 { + display "Static configuration via offset" + default_value 1 + implements CYGINT_IO_FLASH_BLOCK_CFG_1 + description " + This configures the flash device 1 block device + with static offset from the base of the first + flash device and length" + + cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_1 { + display "Start offset from flash base" + flavor data + default_value 0x100000 + description " + This gives the offset from the base of flash + of the first flash device which this block device + corresponds to." + } + cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_1 { + display "Length" + flavor data + default_value 0x100000 + description " + This gives the length of the region of flash given over + to this block device." + } + } + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_1 { + display "Absolute static configuration" + default_value 0 + implements CYGINT_IO_FLASH_BLOCK_CFG_1 + description " + This configures the flash device 1 block device + with absolute base address and a length" + + cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1 { + display "Start offset from flash base" + flavor data + default_value 0x4000000 + description " + This gives the absolute address in flash which this + block device corresponds to." + } + cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_1 { + display "Length" + flavor data + default_value 0x100000 + description " + This gives the length of the region of flash given over + to this block device." + } + } + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 { + display "Configuration from FIS" + default_value 0 + implements CYGINT_IO_FLASH_BLOCK_CFG_1 + description " + This configures the flash device 1 block device + from Redboot FIS" + + cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1 { + display "Name of FIS entry" + flavor data + default_value { "\"jffs2\"" } + } + } + } + cdl_component CYGSEM_IO_FLASH_BLOCK_DEVICE_2 { + display "Implements a second block device" + default_value 0 - cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_1 { - display "Static configuration" - default_value 1 - implements CYGINT_IO_FLASH_BLOCK_CFG_1 - description " - This configures the flash device 1 block device - with static base and length" - - cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_1 { - display "Start offset from flash base" - flavor data - default_value 0x100000 - description " - This gives the offset from the base of flash which this - block device corresponds to." - } - cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_1 { - display "Length" - flavor data - default_value 0x100000 - description " - This gives the length of the region of flash given over - to this block device." - } - } - cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 { - display "Configuration from FIS" - default_value 0 - implements CYGINT_IO_FLASH_BLOCK_CFG_1 - description " - This configures the flash device 1 block device - from Redboot FIS" - - cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1 { - display "Name of FIS entry" - flavor data - default_value { "\"jffs2\"" } - } - } - } - } -} + cdl_component CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2 { + display "Name of flash device 2 block device" + flavor data + default_value { "\"/dev/flash2\"" } + + cdl_interface CYGINT_IO_FLASH_BLOCK_CFG_2 { + requires 1 == CYGINT_IO_FLASH_BLOCK_CFG_2 + no_define + } + + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_2 { + display "Static configuration via offset" + default_value 1 + implements CYGINT_IO_FLASH_BLOCK_CFG_2 + description " + This configures the flash device 2 block device + with static offset from the base of the first + flash device and length" + + cdl_option CYGNUM_IO_FLASH_BLOCK_OFFSET_2 { + display "Start offset from flash base" + flavor data + default_value 0x100000 + description " + This gives the offset from the base of flash + of the first flash device which this block device + corresponds to." + } + cdl_option CYGNUM_IO_FLASH_BLOCK_LENGTH_2 { + display "Length" + flavor data + default_value 0x100000 + description " + This gives the length of the region of flash + given over to this block device." + } + } + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_2 { + display "Absolute static configuration" + default_value 0 + implements CYGINT_IO_FLASH_BLOCK_CFG_2 + description " + This configures the flash device 2 block device + with absolute base address and a length" + + cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2 { + display "Start offset from flash base" + flavor data + default_value 0x4000000 + description " + This gives the absolute address in flash which this + block device corresponds to." + } + cdl_option CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_2 { + display "Length" + flavor data + default_value 0x100000 + description " + This gives the length of the region of flash + given over to this block device." + } + } + + cdl_component CYGNUM_IO_FLASH_BLOCK_CFG_FIS_2 { + display "Configuration from FIS" + default_value 0 + implements CYGINT_IO_FLASH_BLOCK_CFG_2 + description " + This configures the flash device 2 block device + from Redboot FIS" + + cdl_component CYGDAT_IO_FLASH_BLOCK_FIS_NAME_2 { + display "Name of FIS entry" + flavor data + default_value { "\"jffs2-2\"" } + } + } + } + } + } +} \ No newline at end of file
--- a/packages/io/flash/current/doc/flash.sgml +++ b/packages/io/flash/current/doc/flash.sgml @@ -35,9 +35,6 @@ <TITLE>The eCos FLASH Library</TITLE> <PARA>The FLASH library is an optional part of eCos, and is only applicable to some platforms.</PARA> -<SECT1 id="flash-library"> -<TITLE>FLASH Library</TITLE> - <PARA>The eCos FLASH library provides the following functionality:</PARA> <orderedlist> @@ -50,6 +47,340 @@ <PARA></listitem> </orderedlist> +<PARA> There are two APIs with the flash library. The old API is +retained for backwards compatibility reasons, but should slowly be +replaced with the new API which is much more flexible and does not +pollute the name space as much. +</PARA> + +<SECT1> +<TITLE>Notes on using the FLASH library</TITLE> + +<PARA>FLASH devices cannot be read from when an erase or write +operation is active. This means it is not possible to execute code +from flash while an erase or write operation is active. It is possible +to use the library when the executable image is resident in FLASH. The +low level drivers are written such that the linker places the +functions that actually manipulate the flash into RAM. However the +library may not be interrupt safe. An interrupt must not cause +execution of code that is resident in FLASH. This may be the image +itself, or RedBoot. In some configurations of eCos, ^C on the serial +port or debugging via Ethernet may cause an interrupt handler to call +RedBoot. If RedBoot is resident in FLASH this will cause a crash. +Similarly, if another thread invokes a virtual vector function to +access RedBoot, eg to perform a <FUNCTION>diag_printf()</FUNCTION> a +crash could result. +</PARA> + +<PARA> Thus with a ROM based image or a ROM based Redboot it is +recommended to disable interrupts while erasing or programming +flash. Using both a ROMRAM or RAM images and a ROMRAM or RAM RedBoot +are safe and there is no need to disable interrupts. Similarly, +</PARA> +</SECT1> + +<SECT1> +<TITLE>Danger, Will Robinson! Danger!</TITLE> + +<PARA>Unlike nearly every other aspect of embedded system programming, +getting it wrong with FLASH devices can render your target system +useless. Most targets have a boot loader in the FLASH. Without this +boot loader the target will obviously not boot. So before starting to +play with this library its worth investigating a few things. How do +you recover your target if you delete the boot loader? Do you have the +necessary JTAG cable? Or is specialist hardware needed? Is it even +possible to recover the target boards or must it be thrown into the +rubbish bin? How does killing the board affect your project schedule? +</PARA> + +</SECT1> +</CHAPTER> + +<CHAPTER id="ecos-flash-v2"> +<TITLE>The Version 2 eCos FLASH API</TITLE> + +<PARA> There are two APIs described here. The first is the application +API which programs should use. The second API is that between the +FLASH IO library and the device drivers. </PARA> + +<SECT1 id="ecos-flash-v2-api"> +<TITLE>FLASH user API</TITLE> +<PARA> + +<PARA>All of the functions described below are declared in the header +file <filename><cyg/io/flash.h.h></filename> which all users of +the FLASH library should include.</PARA> + +<SECT2> +<TITLE>Initializing the FLASH library</TITLE> + +<PARA>The FLASH library needs to be initialized before other FLASH +operations can be performed. This only needs to be done once. The +following function will only do the initialization once so it's safe +to call multiple times: </PARA> + +<PROGRAMLISTING>__externC int cyg_flash_init(const cyg_flash_printf *pf); +typedef int cyg_flash__printf(const char *fmt, ...); </PROGRAMLISTING> + +<PARA> +The parameter <parameter>pf</parameter> is a pointer to a function +which is to be used for diagnostic output. Typically the function +<function>diag_printf()</function> will be passed. Normally this +function is not used by the higher layer of the library unless +<literal>CYGSEM_IO_FLASH_CHATTER</literal> is enabled. Passing a +<parameter>NULL</parameter> is not recommended, even when +CYGSEM_IO_FLASH_CHATTER is disabled. The lower layers of the library +may unconditionally call this function, especially when errors occur, +probably resulting in a more serious error/crash!.</PARA> +</SECT2> + +<SECT2> +<TITLE>Retrieving information about FLASH devices</TITLE> + +<PARA> +The following five functions return information about the FLASH. +</PARA> + +<PROGRAMLISTING> +__externC int cyg_flash_get_info(cyg_uint32 devno, cyg_flash_info_t * info); +__externC int cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, cyg_flash_info_t * info); +__externC int cyg_flash_verify_addr(const flashaddr_t address); +__externC int cyg_flash_code_overlaps(const flashaddr_t start, const flashaddr_t end); +__externC int cyg_flash_get_block_info(size_t *block_size, cyg_uint32 *blocks); +__externC int cyg_flash_get_limits(flashaddr_t *start, flashaddr_t *end); +__extern size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base); + +typedef struct cyg_block_info + size_t block_size; + cyg_unit32 blocks; +} cyg_block_info_t; + +typedef struct { + flashaddr_t start; // First address + flashaddr_t end; // Last address + cyg_uint32 num_block_infos // Number of entries + cyg_block_info_t *blocks_info; // Info about one block size +} cyg_flash_info_t; +</PROGRAMLISTING> + +<PARA><FUNCTION>cyg_flash_get_info()</FUNCTION> is the main function +to get information about installed flash devices. Parameter +<PARAMETER>devno</PARAMETER> is used to iterate over the available +flash devices, starting from 0. If the devno'th device exists, the +structure pointed to by <PARAMETER>info</PARAMETER> is filled in and +<LITERAL>CYG_FLASH_ERR_OK</LITERAL> is returned, otherwise +<LITERAL>CYG_FLASH_ERR_INVALID</LITERAL>. +<FUNCTION>cyg_flash_get_info()</FUNCTION> if similar, but returns the +information about the flash device at the given address. +<FUNCTION>cyg_flash_block_size()</FUNCTION> returns the size of the +block at the given address. <FUNCTION>cyg_flash_verify_addr() +</FUNCTION> tests if the target addresses is within one of the FLASH +devices, returning <LITERAL>CYG_FLASH_ERR_OK </LITERAL> if so. +<FUNCTION> cyg_flash_code_overlaps() </FUNCTION> checks if the +executing code is resident in the section of flash indicated by +<PARAMETER>start</PARAMETER> and <PARAMETER> end </PARAMETER>. If +this function returns <LITERAL>CYG_FLASH_ERR_OK</LITERAL> the code is +inside the address refion given. Erase and program operations within +this range are very likely to cause the target to crash and burn +horribly. Note the FLASH library does allow you to shoot yourself in +the foot in this way.</PARA> + +<PARA>To aid with backwards compatibility the following functions have +been retained from the V1 API. However the only operate on the first +FLASH driver. The function <FUNCTION>cyg_flash_get_block_info() +</FUNCTION> returns the size and number of blocks for the first +driver. When the device has a mixture of block sizes, the size of the +"normal" block will be returned. Please read the source code to +determine exactly what this means. <FUNCTION> cyg_flash_get_limits() +</FUNCTION> returns the lower and upper memory address the first FLASH +occupies. +</SECT2> + <SECT2> + +<TITLE>Reading from FLASH</TITLE> + +<PARA> +There are two methods for reading from FLASH. The first is to use the +following function. </PARA> + +<PROGRAMLISTING> +__externC int cyg_flash_read(flashaddr_t *flash_base, const void *ram_base, const size_t len, flashaddr_t **err_address); +</PROGRAMLISTING> + +<PARA> +<PARAMETER>flash_base</PARAMETER> is where in the flash to read +from. <PARAMETER>ram_base</PARAMETER> indicates where the data read +from flash should be placed into RAM. <PARAMETER>len</PARAMETER> is +the number of bytes to be read from the FLASH and +<PARAMETER>err_address</PARAMETER> is used to return the location in +FLASH that any error occurred while reading. +</PARA> + +<PARA> +The second method is to simply <FUNCTION>memcpy()</FUNCTION> directly +from the FLASH. This is not recommended since some types of device +cannot be read in this way, eg NAND FLASH. Using the FLASH library +function to read the FLASH will always work so making it easy to port +code from one FLASH device to another. +</PARA> + +</SECT2> +<SECT2> + +<TITLE>Erasing areas of FLASH</TITLE> + +<PARA> +Blocks of FLASH can be erased using the following function: +</PARA> + +<PROGRAMLISTING>__externC int cyg_flash_erase(flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address); +</PROGRAMLISTING> + +<PARA> +<PARAMETER>flash_base</PARAMETER> is where in the flash to erase +from. <PARAMETER>len</PARAMETER> is the minimum number of bytes to +erase in the FLASH and <PARAMETER>err_address</PARAMETER> is used to +return the location in FLASH that any error occurred while erasing. It +should be noted that FLASH devices are block oriented when erasing. It +is not possible to erase a few bytes within a block, the whole block +will be erased. <PARAMETER>flash_base</PARAMETER> may be anywhere +within the first block to be erased and <PARAMETER>flash_base+len +</PARAMETER> maybe anywhere in the last block to be erased. </PARA> + +</SECT2> +<SECT2> + +<TITLE>Programming the FLASH</TITLE> + +<PARA> Programming of the flash is achieved using the following +function.</PARA> + +<PROGRAMLISTING>__externC int cyg_flash_program(const flashaddr_t *flash_base, void *ram_base, const size_t len, flashaddr_t **err_address); +</PROGRAMLISTING> + +<PARA> +<PARAMETER>flash_base</PARAMETER> is where in the flash to program +from. <PARAMETER>ram_base</PARAMETER> indicates where the data to be +programmed into FLASH should be read from in RAM. <PARAMETER>len +</PARAMETER> is the number of bytes to be program into the FLASH and +<PARAMETER>err_address</PARAMETER> is used to return the location in +FLASH that any error occurred while programming. </PARA> + +</SECT2> +<SECT2> + +<TITLE>Locking and unlocking blocks</TITLE> + +<PARA> +Some flash devices have the ability to lock and unlock blocks. A +locked block cannot be erased or programmed without it first being +unlocked. For devices which support this feature and when <LITERAL> +CYGHWR_IO_FLASH_BLOCK_LOCKING</LITERAL> is enabled then the following +two functions are available:</PARA> + +<PROGRAMLISTING> +__externC int cyg_flash_lock(const flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address); +__externC int cyg_flash_unlock(const flashaddr_t *flash_base, const size_t len, flashaddr_t **err_address); +</PROGRAMLISTING> + +</SECT2> + +<SECT2> +<TITLE>Locking FLASH Mutex's</TITLE> + +<PARA>When the eCos kernel package is included in the eCos +configuration, the FLASH IO library will perform mutex locking on +FLASH operations. This makes the API defined here thread safe. However +applications may wish to directly access the contents of the FLASH. In +order for this to be thread safe it is necessary for the application +to use the following two functions to inform the FLASH IO library that +the FLASH devices are being used and other API calls should be +blocked.</PARA> + +<PROGRAMLISTING> +__externC int cyg_flash_mutex_lock(const flashaddr_t *from, const size_t len); +__externC int cyg_flash_mutex_unlock(const flashaddr_t *from, const size_t len); +</PROGRAMLISTING> + +<SECT2> + +<TITLE>Return values and errors</TITLE> + +<PARA>All the functions above, except <FUNCTION>cyg_flash_code_overlaps() +</FUNCTION> return one of the following return values.</PARA> + +<PROGRAMLISTING> +CYG_FLASH_ERR_OK No error - operation complete +CYG_FLASH_ERR_INVALID Invalid FLASH address +CYG_FLASH_ERR_ERASE Error trying to erase +CYG_FLASH_ERR_LOCK Error trying to lock/unlock +CYG_FLASH_ERR_PROGRAM Error trying to program +CYG_FLASH_ERR_PROTOCOL Generic error +CYG_FLASH_ERR_PROTECT Device/region is write-protected +CYG_FLASH_ERR_NOT_INIT FLASH info not yet initialized +CYG_FLASH_ERR_HWR Hardware (configuration?) problem +CYG_FLASH_ERR_ERASE_SUSPEND Device is in erase suspend mode +CYG_FLASH_ERR_PROGRAM_SUSPEND Device is in program suspend mode +CYG_FLASH_ERR_DRV_VERIFY Driver failed to verify data +CYG_FLASH_ERR_DRV_TIMEOUT Driver timed out waiting for device +CYG_FLASH_ERR_DRV_WRONG_PART Driver does not support device +CYG_FLASH_ERR_LOW_VOLTAGE Not enough juice to complete job +</PROGRAMLISTING> + +<PARA>To turn an error code into a human readable string the following +function can be used:</PARA> + +<PROGRAMLISTING>__externC const char *cyg_flash_errmsg(const int err); +</PROGRAMLISTING> +</SECT2> + +<SECT1 id="ecos-flash-v2-dev"> +<TITLE>FLASH device API</TITLE> <PARA>This section describes the API +between the FLASH IO library the FLASH device drivers.</PARA> + +<SECT2> +<TITLE>The FLASH device Structure</TITLE> + +<PARA>This structure keeps all the information about a single driver.</PARA> + +<PROGRAMLISTING>struct cyg_flash_dev { + struct cyg_flash_dev_funs *funs; // Function pointers + flashaddr_t *start; // First address + flashaddr_t *end; // Last address + void *priv; // Devices private data + cyg_uint32 num_block_infos; // Number of entries + cyg_block_info_t *blocks_info; // Info about one block size + + +// The following are only written to by the FLASH IO layer. + cyg_flash_printf *pf; // Pointer to diagnostic printf + cyg_bool init; // Device has been initialized +#ifdef CYG_KERNEL + cyg_mutex_t mutex; // Mutex for thread safeness +#endif + struct cyg_flash_dev *next; // Pointer to next device +} + +struct cyg_flash_dev_funs { + int (*flash_init) (struct cyg_flash_dev *dev); + size_t (*flash_query) (struct cyg_flash_dev *dev, void * data, const size_t len); + int (*flash_erase_block) (struct cyg_flash_dev *dev, const flashaddr_t *block_base); + int (*flash_program) (struct cyg_flash_dev *dev, flashaddr_t *base, const void* data, const size_t len); + int (*flash_read) (struct cyg_flash_dev *dev, const flashaddr_t *base, void* data, const size_t len); + int (*flash_hwr_map_error) (struct cyg_flash_dev *dev, int err); +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + int (*flash_block_lock) (struct cyg_flash_dev *dev, const flashaddr_t *block_base); + int (*flash_block_unlock) (struct cyg_flash_dev *dev, const flashaddr_t *block_base); +#endif +} +</PROGRAMLISTING> + +<PARA>The FLASH IO layer will only pass requests for operations on a single block. +</SECT1> +</CHAPTER> + +<CHAPTER id="ecos-flash-v1"> +<TITLE>The legacy Version 1 eCos FLASH API</TITLE> <PARA> The library has a number of limitations:</PARA> @@ -72,10 +403,18 @@ The library has a number of limitations: </listitem> </orderedlist> +<PARA> There are two APIs described here. The first is the application +API which programs should use. The second API is that between the +FLASH io library and the device drivers. </PARA> + +<SECT1 id="ecos-flash-v1-api"> +<TITLE>FLASH user API</TITLE> + <PARA>All of the functions described below are declared in the header file <filename><cyg/io/flash.h.h></filename> which all users of the FLASH library should include.</PARA> + <SECT2> <TITLE>Initializing the FLASH library</TITLE> @@ -84,8 +423,8 @@ operations can be performed. This only n following function will only do the initialization once so it's safe to call multiple times: </PARA> -<PROGRAMLISTING>externC int flash_init( _printf *pf ); typedef int -_printf(const char *fmt, ...); </PROGRAMLISTING> +<PROGRAMLISTING>externC int flash_init( _printf *pf ); +typedef int _printf(const char *fmt, ...); </PROGRAMLISTING> <PARA> The parameter <parameter>pf</parameter> is a pointer to a function @@ -266,45 +605,178 @@ its library functions will likely fail a the callers responsibility to use the necessary mutex's if needed. <PARA> -<PARA>FLASH devices cannot be read from when an erase or write -operation is active. This means it is not possible to execute code -from flash while an erase or write operation is active. It is possible -to use the library when the executable image is resident in FLASH. The -low level drivers are written such that the linker places the -functions that actually manipulate the flash into RAM. However the -library may not be interrupt safe. An interrupt must not cause -execution of code that is resident in FLASH. This may be the image -itself, or RedBoot. In some configurations of eCos, ^C on the serial -port or debugging via Ethernet may cause an interrupt handler to call -RedBoot. If RedBoot is resident in FLASH this will cause a crash. -Similarly, if another thread invokes a virtual vector function to -access RedBoot, eg to perform a <FUNCTION>diag_printf()</FUNCTION> a -crash could result. +</SECT2> +</SECT1> + +<SECT1 id="ecos-flash-v1-dev"> +<TITLE>FLASH device API</TITLE> <PARA>This section describes the API +between the FLASH IO library the FLASH device drivers.</PARA> + +<SECT2> +<TITLE>The flash_info structure</TITLE> + +<PARA> The <parameter>flash_info</parameter>structure is used by both +the FLASH IO library and the device driver.</PARA> +<PROGRAMLISTING>struct flash_info { + int block_size; // Assuming fixed size "blocks" + int blocks; // Number of blocks + int buffer_size; // Size of write buffer (only defined for some devices) + unsigned long block_mask; + void *start, *end; // Address range + int init; // FLASH API initialised + _printf *pf; // printf like function for diagnostics +}; +</PROGRAMLISTING> + +<PARA>block_mask is used internally in the FLASH IO library. It +contains a mask which can be used to turn an arbitrary address in +flash to the base address of the block which contains the +address.</PARA> + +<PARA>There exists one global instance of this structure with the name +<parameter>flash_info</parameter>. All calls into the device driver +makes use of this global structure to maintain state.</PARA> + +</SECT2> + +<SECT2> +<TITLE>Initializing the device driver</TITLE> + +<PARA>The FLASH IO library will call the following function to +initialize the device driver:</PARA> + +<PROGRAMLISTING>externC int flash_hwr_init(void); +</PROGRAMLISTING> + +<PARA>The device driver should probe the hardware to see if the FLASH +devices exist. If it does it should fill in <parameter>start, end, +blocks and block_size.</parameter>If the FLASH contains a write buffer +the size of this should be placed in <parameter>buffer_size +</parameter>. On successful probing the function should return +<literal>FLASH_ERR_OK</literal>. When things go wrong it can be +assumed that <parameter>pf</parameter> points to a printf like +function for outputting error messages. </PARA> +</SECT2> -<PARA> Thus with a ROM based image or a ROM based Redboot it is -recommended to disable interrupts while erasing or programming -flash. Using both a ROMRAM or RAM images and a ROMRAM or RAM RedBoot -are safe and there is no need to disable interrupts. Similarly, -</PARA> +<SECT2> +<TITLE>Querying the FLASH</TITLE> + +<PARA>FLASH devices can be queried to return there manufacture ID, +size etc. This function allows this information to be returned.</PARA> + +<PROGRAMLISTING>int flash_query(unsigned char *data);</PROGRAMLISTING> + +<PARA>The caller must know the size of data to be returned and provide +an appropriately sized buffer pointed to be parameter +<parameter>data</parameter>. This function is generally used by +<function>flash_hwr_init()</function>.</PARA> + +</SECT2> +<SECT2> +<TITLE>Erasing a block of FLASH</TITLE> + +<PARA>So that the FLASH IO layer can erase a block of FLASH the +following function should be provided.</PARA> + +<PROGRAMLISTING>int flash_erase_block(volatile flash_t *block, unsigned int block_size); +</PROGRAMLISTING> </SECT2> <SECT2> +<TITLE>Programming a region of FLASH</TITLE> -<TITLE>Danger, Will Robinson! Danger!</TITLE> +<PARA>The following function must be provided so that data can be +written into the FLASH.</PARA> + +<PROGRAMLISTING>int flash_program_buf(volatile flash_t *addr, flash_t *data, int len, + unsigned long block_mask, int buffer_size);</PROGRAMLISTING> + +<PARA>The device will only be asked to program data in one block of +the flash. The FLASH IO layer will break longer user requests into a +smaller writes.</PARA> + +<SECT2> +<TITLE>Reading a region from FLASH</TITLE> + +<PARA>Some FLASH devices are not memory mapped so it is not possible +to read there contents directly. The following function read a region +of FLASH.</PARA> + +<PROGRAMLISTING>int flash_read_buf(volatile flash_t* addr, flash_t* data, int len); +</PROGRAMLISTING> -<PARA>Unlike nearly every other aspect of embedded system programming, -getting it wrong with FLASH devices can render your target system -useless. Most targets have a boot loader in the FLASH. Without this -boot loader the target will obviously not boot. So before starting to -play with this library its worth investigating a few things. How do -you recover your target if you delete the boot loader? Do you have the -necessary JTAG cable? Or is specialist hardware needed? Is it even -possible to recover the target boards or must it be thrown into the -rubbish bin? How does killing the board affect your project schedule? -</PARA> +<PARA>As with writing to the flash, the FLASH IO layer will break +longer user requests for data into a number of reads which are at +maximum one block in size.</PARA> + +<PARA>A device which cannot be read directy should set +<LITERAL>CYGSEM_IO_FLASH_READ_INDIRECT</LITERAL> so that the IO layer +makes use of the <function>flash_read_buf()</function>function. + +</SECT2> + +<SECT2> +<TITLE>Locking and unlocking FLASH blocks</TITLE> + +<PARA>Some flash devices allow blocks to be locked so that they cannot +be written to. The device driver should provide the following +functions to manipulate these locks.</PARA> + +<PROGRAMLISTING>int flash_lock_block(volatile flash_t *block); +int flash_unlock_block(volatile flash_t *block, int block_size, int blocks); +</PROGRAMLISTING> + +<PARA>These functions are only used if +<LITERAL>CYGHWR_IO_FLASH_BLOCK_LOCKING</LITERAL></PARA> </SECT2> -</SECT1> + +<SECT2> +<TITLE>Mapping FLASH error codes to FLASH IO error codes</TITLE> + +<PARA>The functions <function>flash_erase_block(), +flash_program_buf(), flash_read_buf(), flash_lock_block() and +flash_unlock_block()</function> return an error code which is specific +to the flash device. To map this into a FLASH IO error code, the +driver should provide the following function: </PARA> + +<PROGRAMLISTING>int flash_hwr_map_error(int err);</PROGRAMLISTING> + +</SECT2> + +<SECT2> +<TITLE>Determining if code is in FLASH</TITLE> + +<PARA>Although a general function, the device driver is expected to +provide the implementation of the function +<function>flash_code_overlaps()</function>.</PARA> + +</SECT2> + +<SECT2> +<TITLE>Implementation Notes</TITLE> + +<PARA>The FLASH IO layer will manipulate the caches as required. The +device drivers do not need to enable/disable caches when performing +operations of the FLASH.<PARA> + +<PARA>Device drivers should keep all chatter to a minimum when +<literal>CYGSEM_IO_FLASH_CHATTER</literal> is not defined. All output +should use the print function in the <parameter>pf</parameter> in +<parameter>flash_info</parameter> and not +<function>diag_printf()</function></PARA> + +<PARA>Device driver functions which manipulate the state of the flash +so that it cannot be read from for program execute need to ensure +there code is placed into RAM. The linker will do this if the +appropriate attribute is added to the function. e.g:</PARA> + +<PROGRAMLISTING>int flash_program_buf(volatile flash_t *addr, flash_t *data, int len, + unsigned long block_mask, int buffer_size) + __attribute__ ((section (".2ram.flash_program_buf")));</PROGRAMLISTING> + +</SECT2> +</SECT1> </CHAPTER> </PART>
--- a/packages/io/flash/current/include/flash.h +++ b/packages/io/flash/current/include/flash.h @@ -10,6 +10,7 @@ // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2003 Gary Thomas +// 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 @@ -42,7 +43,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, Andrew Lunn // Date: 2000-07-14 // Purpose: // Description: @@ -54,15 +55,94 @@ #ifndef _IO_FLASH_H_ #define _IO_FLASH_H_ +#include <pkgconf/system.h> #include <pkgconf/io_flash.h> #include <cyg/hal/hal_cache.h> +#include <cyg/hal/hal_tables.h> +#ifdef CYGPKG_KERNEL +#include <cyg/kernel/kapi.h> +#endif +typedef CYG_ADDRESS cyg_flashaddr_t; + +typedef struct cyg_block_info +{ + size_t block_size; + cyg_uint32 blocks; +} cyg_block_info_t; + +// Information about what one device driver drives +typedef struct { + cyg_flashaddr_t start; // First address + cyg_flashaddr_t end; // Last address + cyg_uint32 num_block_infos; // Number of entries + cyg_block_info_t *block_info; // Info about block sizes +} cyg_flash_info_t; + +typedef int cyg_flash_printf(const char *fmt, ...); +__externC int cyg_flash_init( cyg_flash_printf *pf ); +__externC int cyg_flash_get_info(cyg_uint32 devno, + cyg_flash_info_t * info); +__externC int cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, + cyg_flash_info_t * info); +__externC int cyg_flash_verify_addr(const cyg_flashaddr_t address); +__externC bool cyg_flash_code_overlaps(const cyg_flashaddr_t start, + const cyg_flashaddr_t end); +__externC int cyg_flash_get_block_info(size_t *block_size, + cyg_uint32 *blocks); +__externC int cyg_flash_get_limits(cyg_flashaddr_t *start, + cyg_flashaddr_t *end); +__externC size_t cyg_flash_block_size(const cyg_flashaddr_t flash_base); +__externC int cyg_flash_read(cyg_flashaddr_t flash_base, + const void *ram_base, + const size_t len, + cyg_flashaddr_t *err_address); +__externC int cyg_flash_erase(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address); +__externC int cyg_flash_program(const cyg_flashaddr_t flash_base, + void *ram_base, + const size_t len, + cyg_flashaddr_t *err_address); +__externC int cyg_flash_lock(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address); +__externC int cyg_flash_unlock(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address); +__externC const char *cyg_flash_errmsg(const int err); +#ifdef CYGPKG_KERNEL +__externC int cyg_flash_mutex_lock(const cyg_flashaddr_t from, + const size_t len); +__externC int cyg_flash_mutex_unlock(const cyg_flashaddr_t from, + const size_t len); +#endif + +#define CYG_FLASH_ERR_OK 0x00 // No error - operation complete +#define CYG_FLASH_ERR_INVALID 0x01 // Invalid FLASH address +#define CYG_FLASH_ERR_ERASE 0x02 // Error trying to erase +#define CYG_FLASH_ERR_LOCK 0x03 // Error trying to lock/unlock +#define CYG_FLASH_ERR_PROGRAM 0x04 // Error trying to program +#define CYG_FLASH_ERR_PROTOCOL 0x05 // Generic error +#define CYG_FLASH_ERR_PROTECT 0x06 // Device/region is write-protected +#define CYG_FLASH_ERR_NOT_INIT 0x07 // FLASH info not yet initialized +#define CYG_FLASH_ERR_HWR 0x08 // Hardware (configuration?) problem +#define CYG_FLASH_ERR_ERASE_SUSPEND 0x09 // Device is in erase suspend mode +#define CYG_FLASH_ERR_PROGRAM_SUSPEND 0x0a // Device is in program suspend mode +#define CYG_FLASH_ERR_DRV_VERIFY 0x0b // Driver failed to verify data +#define CYG_FLASH_ERR_DRV_TIMEOUT 0x0c // Driver timed out +#define CYG_FLASH_ERR_DRV_WRONG_PART 0x0d // Driver does not support device +#define CYG_FLASH_ERR_LOW_VOLTAGE 0x0e // Not enough juice to complete job + +#ifdef CYGSEM_IO_FLASH_LEGACY_API typedef int _printf(const char *fmt, ...); externC int flash_init(_printf *pf); externC int flash_erase(void *base, int len, void **err_address); -externC int flash_program(void *flash_base, void *ram_base, int len, void **err_address); -externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address); +externC int flash_program(void *flash_base, void *ram_base, int len, + void **err_address); +externC int flash_read(void *flash_base, void *ram_base, int len, + void **err_address); externC void flash_dev_query(void *data); #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING externC int flash_lock(void *base, int len, void **err_address); @@ -73,169 +153,46 @@ externC int flash_get_limits(void *base, externC int flash_get_block_info(int *block_size, int *blocks); externC bool flash_code_overlaps(void *start, void *end); externC char *flash_errmsg(int err); +#endif // CYGSEM_IO_FLASH_LEGACY_API -#define FLASH_ERR_OK 0x00 // No error - operation complete -#define FLASH_ERR_INVALID 0x01 // Invalid FLASH address -#define FLASH_ERR_ERASE 0x02 // Error trying to erase -#define FLASH_ERR_LOCK 0x03 // Error trying to lock/unlock -#define FLASH_ERR_PROGRAM 0x04 // Error trying to program -#define FLASH_ERR_PROTOCOL 0x05 // Generic error -#define FLASH_ERR_PROTECT 0x06 // Device/region is write-protected -#define FLASH_ERR_NOT_INIT 0x07 // FLASH info not yet initialized -#define FLASH_ERR_HWR 0x08 // Hardware (configuration?) problem -#define FLASH_ERR_ERASE_SUSPEND 0x09 // Device is in erase suspend mode -#define FLASH_ERR_PROGRAM_SUSPEND 0x0a // Device is in in program suspend mode -#define FLASH_ERR_DRV_VERIFY 0x0b // Driver failed to verify data -#define FLASH_ERR_DRV_TIMEOUT 0x0c // Driver timed out waiting for device -#define FLASH_ERR_DRV_WRONG_PART 0x0d // Driver does not support device -#define FLASH_ERR_LOW_VOLTAGE 0x0e // Not enough juice to complete job +#if defined(CYGSEM_IO_FLASH_LEGACY_API) || defined(CYGSEM_IO_FLASH_LEGACY_DEVICE_API) +#define FLASH_ERR_OK CYG_FLASH_ERR_OK +#define FLASH_ERR_INVALID CYG_FLASH_ERR_INVALID +#define FLASH_ERR_ERASE CYG_FLASH_ERR_ERASE +#define FLASH_ERR_LOCK CYG_FLASH_ERR_LOCK +#define FLASH_ERR_PROGRAM CYG_FLASH_ERR_PROGRAM +#define FLASH_ERR_PROTOCOL CYG_FLASH_ERR_PROTOCOL +#define FLASH_ERR_PROTECT CYG_FLASH_ERR_PROTECT +#define FLASH_ERR_NOT_INIT CYG_FLASH_ERR_NOT_INIT +#define FLASH_ERR_HWR CYG_FLASH_ERR_HWR +#define FLASH_ERR_ERASE_SUSPEND CYG_FLASH_ERR_ERASE_SUSPEND +#define FLASH_ERR_PROGRAM_SUSPEND CYG_FLASH_ERR_PROGRAM_SUSPEND +#define FLASH_ERR_DRV_VERIFY CYG_FLASH_ERR_DRV_VERIFY +#define FLASH_ERR_DRV_TIMEOUT CYG_FLASH_ERR_DRV_TIMEOUT +#define FLASH_ERR_DRV_WRONG_PART CYG_FLASH_ERR_DRV_WRONG_PART +#define FLASH_ERR_LOW_VOLTAGE CYG_FLASH_ERR_LOW_VOLTAGE +#endif #ifdef CYGPKG_IO_FLASH_BLOCK_DEVICE typedef struct { CYG_ADDRESS offset; - int len; + size_t len; int flasherr; - void **err_address; + cyg_flashaddr_t *err_address; } cyg_io_flash_getconfig_erase_t; typedef struct { - int dev_size; + size_t dev_size; } cyg_io_flash_getconfig_devsize_t; typedef struct { CYG_ADDRESS offset; - int block_size; + size_t block_size; } cyg_io_flash_getconfig_blocksize_t; #endif #ifdef _FLASH_PRIVATE_ - -struct flash_info { - int block_size; // Assuming fixed size "blocks" - int blocks; // Number of blocks - int buffer_size; // Size of write buffer (only defined for some devices) - unsigned long block_mask; - void *start, *end; // Address range - int init; - _printf *pf; -}; - -externC struct flash_info flash_info; -externC int flash_hwr_init(void); -externC int flash_hwr_map_error(int err); - -// -// Some FLASH devices may require additional support, e.g. to turn on -// appropriate voltage drivers, before any operation. -// -#ifdef CYGIMP_FLASH_ENABLE -#define FLASH_Enable CYGIMP_FLASH_ENABLE -extern void CYGIMP_FLASH_ENABLE(void *, void *); -#else -#define FLASH_Enable(_start_, _end_) -#endif -#ifdef CYGIMP_FLASH_DISABLE -#define FLASH_Disable CYGIMP_FLASH_DISABLE -extern void CYGIMP_FLASH_DISABLE(void *, void *); -#else -#define FLASH_Disable(_start_, _end_) -#endif - -// -// Some platforms have a DIP switch or jumper that tells the software that -// the flash is write protected. -// -#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT -externC cyg_bool plf_flash_query_soft_wp(void *addr, int len); +#include <cyg/io/flash_priv.h> #endif -//--------------------------------------------------------------------------- -// Execution of flash code must be done inside a -// HAL_FLASH_CACHES_OFF/HAL_FLASH_CACHES_ON region - disabling the -// cache on unified cache systems is necessary to prevent burst access -// to the flash area being programmed. With Harvard style caches, only -// the data cache needs to be disabled, but the instruction cache is -// disabled for consistency. - -// Targets may provide alternative implementations for these macros in -// the hal_cache.h (or var/plf) files. - -// The first part below is a generic, optimal implementation. The -// second part is the old implementation that has been tested to work -// on some targets - but it is not be suitable for targets that would -// do burst access to the flash (it does not disable the data cache). - -// Both implementations must be called with interrupts disabled. - -// NOTE: Do _not_ change any of the below macros without checking that -// the changed code still works on _all_ platforms that rely on these -// macros. There is no such thing as logical and correct when dealing -// with different cache and IO models, so _do not_ mess with this code -// unless you test it properly afterwards. - -#ifndef HAL_FLASH_CACHES_OFF - -// Some drivers have only been tested with the old macros below. -#ifndef HAL_FLASH_CACHES_OLD_MACROS - -#ifdef HAL_CACHE_UNIFIED - -// Note: the ucache code has not been tested yet on any target. -#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ - CYG_MACRO_START \ - _i_ = 0; /* avoids warning */ \ - HAL_UCACHE_IS_ENABLED(_d_); \ - HAL_UCACHE_SYNC(); \ - HAL_UCACHE_INVALIDATE_ALL(); \ - HAL_UCACHE_DISABLE(); \ - CYG_MACRO_END - -#define HAL_FLASH_CACHES_ON(_d_, _i_) \ - CYG_MACRO_START \ - if (_d_) HAL_UCACHE_ENABLE(); \ - CYG_MACRO_END - -#else // HAL_CACHE_UNIFIED - -#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ - CYG_MACRO_START \ - _i_ = 0; /* avoids warning */ \ - HAL_DCACHE_IS_ENABLED(_d_); \ - HAL_DCACHE_SYNC(); \ - HAL_DCACHE_INVALIDATE_ALL(); \ - HAL_DCACHE_DISABLE(); \ - HAL_ICACHE_INVALIDATE_ALL(); \ - CYG_MACRO_END - -#define HAL_FLASH_CACHES_ON(_d_, _i_) \ - CYG_MACRO_START \ - if (_d_) HAL_DCACHE_ENABLE(); \ - CYG_MACRO_END - -#endif // HAL_CACHE_UNIFIED - -#else // HAL_FLASH_CACHES_OLD_MACROS - -// Note: This implementation is broken as it will always enable the i-cache -// even if it was not enabled before. It also doesn't work if the -// target uses burst access to flash since the d-cache is left enabled. -// However, this does not mean you can change this code! Leave it as -// is - if you want a different implementation, provide it in the -// arch/var/platform cache header file. - -#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ - _d_ = 0; /* avoids warning */ \ - _i_ = 0; /* avoids warning */ \ - HAL_DCACHE_SYNC(); \ - HAL_ICACHE_DISABLE(); - -#define HAL_FLASH_CACHES_ON(_d_, _i_) \ - HAL_ICACHE_ENABLE(); - -#endif // HAL_FLASH_CACHES_OLD_MACROS - -#endif // HAL_FLASH_CACHES_OFF - -#endif // _FLASH_PRIVATE_ - #endif // _IO_FLASH_H_
new file mode 100644 --- /dev/null +++ b/packages/io/flash/current/include/flash_priv.h @@ -0,0 +1,251 @@ +//========================================================================== +// +// flash.h +// +// Flash programming - external interfaces +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// 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 +// Contributors: gthomas, Andrew Lunn +// Date: 2000-07-14 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== +#ifndef _IO_FLASH_PRIV_H_ +#define _IO_FLASH_PRIV_H_ + +// Forward reference of the device structure +struct cyg_flash_dev; + +// Structure of pointers to functions in the device driver +struct cyg_flash_dev_funs { + int (*flash_init) (struct cyg_flash_dev *dev); + size_t (*flash_query) (struct cyg_flash_dev *dev, void * data, + const size_t len); + int (*flash_erase_block) (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base); + int (*flash_program) (struct cyg_flash_dev *dev, + cyg_flashaddr_t base, + const void* data, const size_t len); + int (*flash_read) (struct cyg_flash_dev *dev, + const cyg_flashaddr_t base, + void* data, const size_t len); + int (*flash_hwr_map_error) (struct cyg_flash_dev *dev, int err); + int (*flash_block_lock) (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base); + int (*flash_block_unlock) (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base); +}; + +// Structure each device places in the HAL table +struct cyg_flash_dev { + struct cyg_flash_dev_funs *funs; // Function pointers + cyg_flashaddr_t start; // First address + cyg_flashaddr_t end; // Last address + cyg_uint32 num_block_infos; // Number of entries + cyg_block_info_t *block_info; // Info about one block size + + void *priv; // Devices private data + void *config; // Configuration info + +// The following are only written to by the FLASH IO layer. + cyg_flash_printf *pf; // Pointer to diagnostic printf + bool init; // Device has been initialised +#ifdef CYGPKG_KERNEL + cyg_mutex_t mutex; // Mutex for thread safeness +#endif + struct cyg_flash_dev *next; // Pointer to next device +} CYG_HAL_TABLE_TYPE; + +#define CYG_FLASH_FUNS(funs,init,query,erase,prog,read,map,lock,unlock)\ +struct cyg_flash_dev_funs funs = \ + { \ + init, \ + query, \ + erase, \ + prog, \ + read, \ + map, \ + lock, \ + unlock \ + }; + +// We assume HAL tables are placed into RAM. +#define CYG_FLASH_DRIVER(name, _funs, _config, _start, _priv_size) \ +static char priv_ ## name [_priv_size]; \ +struct cyg_flash_dev name CYG_HAL_TABLE_ENTRY(cyg_flashdev) = { \ + .funs = _funs, \ + .config = _config, \ + .priv = priv_ ## name, \ + .start = _start, \ +}; + +#ifdef CYGSEM_IO_FLASH_LEGACY_DEVICE_API +struct flash_info { + int block_size; // Assuming fixed size "blocks" + int blocks; // Number of blocks + int buffer_size; // Size of write buffer (only defined for some devices) + unsigned long block_mask; + void *start, *end; // Address range + int init; + cyg_flash_printf *pf; +}; + +externC struct flash_info flash_info; +externC int flash_hwr_init(void); +externC int flash_hwr_map_error(int err); +externC void flash_dev_query(void *data); +#endif // CYGSEM_IO_FLASH_LEGACY_DEVICE_API +// +// Some FLASH devices may require additional support, e.g. to turn on +// appropriate voltage drivers, before any operation. +// +#ifdef CYGIMP_FLASH_ENABLE +#define FLASH_Enable CYGIMP_FLASH_ENABLE +extern void CYGIMP_FLASH_ENABLE(void *, void *); +#else +#define FLASH_Enable(_start_, _end_) +#endif +#ifdef CYGIMP_FLASH_DISABLE +#define FLASH_Disable CYGIMP_FLASH_DISABLE +extern void CYGIMP_FLASH_DISABLE(void *, void *); +#else +#define FLASH_Disable(_start_, _end_) +#endif + +// +// Some platforms have a DIP switch or jumper that tells the software that +// the flash is write protected. +// +#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT +externC cyg_bool plf_flash_query_soft_wp(void *addr, int len); +#endif + +//--------------------------------------------------------------------------- +// Execution of flash code must be done inside a +// HAL_FLASH_CACHES_OFF/HAL_FLASH_CACHES_ON region - disabling the +// cache on unified cache systems is necessary to prevent burst access +// to the flash area being programmed. With Harvard style caches, only +// the data cache needs to be disabled, but the instruction cache is +// disabled for consistency. + +// Targets may provide alternative implementations for these macros in +// the hal_cache.h (or var/plf) files. + +// The first part below is a generic, optimal implementation. The +// second part is the old implementation that has been tested to work +// on some targets - but it is not be suitable for targets that would +// do burst access to the flash (it does not disable the data cache). + +// Both implementations must be called with interrupts disabled. + +// NOTE: Do _not_ change any of the below macros without checking that +// the changed code still works on _all_ platforms that rely on these +// macros. There is no such thing as logical and correct when dealing +// with different cache and IO models, so _do not_ mess with this code +// unless you test it properly afterwards. + +#ifndef HAL_FLASH_CACHES_OFF + +// Some drivers have only been tested with the old macros below. +#ifndef HAL_FLASH_CACHES_OLD_MACROS + +#ifdef HAL_CACHE_UNIFIED + +// Note: the ucache code has not been tested yet on any target. +#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ + CYG_MACRO_START \ + _i_ = 0; /* avoids warning */ \ + HAL_UCACHE_IS_ENABLED(_d_); \ + HAL_UCACHE_SYNC(); \ + HAL_UCACHE_INVALIDATE_ALL(); \ + HAL_UCACHE_DISABLE(); \ + CYG_MACRO_END + +#define HAL_FLASH_CACHES_ON(_d_, _i_) \ + CYG_MACRO_START \ + if (_d_) HAL_UCACHE_ENABLE(); \ + CYG_MACRO_END + +#else // HAL_CACHE_UNIFIED + +#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ + CYG_MACRO_START \ + _i_ = 0; /* avoids warning */ \ + HAL_DCACHE_IS_ENABLED(_d_); \ + HAL_DCACHE_SYNC(); \ + HAL_DCACHE_INVALIDATE_ALL(); \ + HAL_DCACHE_DISABLE(); \ + HAL_ICACHE_INVALIDATE_ALL(); \ + CYG_MACRO_END + +#define HAL_FLASH_CACHES_ON(_d_, _i_) \ + CYG_MACRO_START \ + if (_d_) HAL_DCACHE_ENABLE(); \ + CYG_MACRO_END + +#endif // HAL_CACHE_UNIFIED + +#else // HAL_FLASH_CACHES_OLD_MACROS + +// Note: This implementation is broken as it will always enable the i-cache +// even if it was not enabled before. It also doesn't work if the +// target uses burst access to flash since the d-cache is left enabled. +// However, this does not mean you can change this code! Leave it as +// is - if you want a different implementation, provide it in the +// arch/var/platform cache header file. + +#define HAL_FLASH_CACHES_OFF(_d_, _i_) \ + _d_ = 0; /* avoids warning */ \ + _i_ = 0; /* avoids warning */ \ + HAL_DCACHE_SYNC(); \ + HAL_ICACHE_DISABLE(); + +#define HAL_FLASH_CACHES_ON(_d_, _i_) \ + HAL_ICACHE_ENABLE(); + +#endif // HAL_FLASH_CACHES_OLD_MACROS + +#endif // HAL_FLASH_CACHES_OFF + +#endif // _IO_FLASH_PRIV_H_
--- a/packages/io/flash/current/src/flash.c +++ b/packages/io/flash/current/src/flash.c @@ -10,6 +10,7 @@ // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2003 Gary Thomas +// 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 @@ -42,7 +43,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, Andrew Lunn // Date: 2000-07-26 // Purpose: // Description: @@ -53,503 +54,803 @@ #include <pkgconf/system.h> #include <pkgconf/io_flash.h> - +#ifdef CYGPKG_KERNEL +#include <cyg/kernel/kapi.h> +#endif #include <cyg/hal/hal_arch.h> #include <cyg/hal/hal_intr.h> #include <cyg/hal/hal_cache.h> +#include <cyg/hal/hal_tables.h> +#include <cyg/infra/cyg_ass.h> #include <string.h> #define _FLASH_PRIVATE_ #include <cyg/io/flash.h> // When this flag is set, do not actually jump to the relocated code. -// This can be used for running the function in place (RAM startup only), -// allowing calls to diag_printf() and similar. +// This can be used for running the function in place (RAM startup +// only), allowing calls to diag_printf() and similar. #undef RAM_FLASH_DEV_DEBUG #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG) # warning "Can only enable the flash debugging when configured for RAM startup" #endif - -struct flash_info flash_info; - -// These are the functions in the HW specific driver we need to call. -typedef void code_fun(void*); +#ifndef MIN +#define MIN(x,y) ((x)<(y) ? (x) : (y)) +#endif -externC code_fun flash_query; -externC code_fun flash_erase_block; -externC code_fun flash_program_buf; -externC code_fun flash_read_buf; -externC code_fun flash_lock_block; -externC code_fun flash_unlock_block; +// Has the FLASH IO library been initialise? +static bool init = false; +// We have a linked list of flash drivers. This is the head of the +// list +static struct cyg_flash_dev *flash_head = NULL; + +// This array contains entries for all flash devices that are +// installed in the system. +__externC struct cyg_flash_dev cyg_flashdevtab[]; +CYG_HAL_TABLE_BEGIN(cyg_flashdevtab, cyg_flashdev); + +// end of the flashdev table +__externC struct cyg_flash_dev cyg_flashdevtab_end; +CYG_HAL_TABLE_END(cyg_flashdevtab_end, cyg_flashdev); -int -flash_init(_printf *pf) +// Sort the linked list into ascending order of flash address. Use a +// primitive ripple sort, but since we don't expect to have many +// devices this should be OK. +static void flash_sort(void) { - int err; + bool moved; + struct cyg_flash_dev *dev, **previous_next; + + // If there is zero or one device, short cut + if (flash_head == NULL || flash_head->next == NULL) + return; + + do { + moved=false; + for (dev=flash_head, previous_next=&flash_head; + dev->next; + previous_next = &dev->next, dev=dev->next ){ + if (dev->start > dev->next->start) { + *previous_next=dev->next; + dev->next = (*previous_next)->next; + (*previous_next)->next = dev; + moved=true; + break; + } + } + } while (moved); +} - if (flash_info.init) return FLASH_ERR_OK; - flash_info.pf = pf; // Do this before calling into the driver - if ((err = flash_hwr_init()) != FLASH_ERR_OK) { - return err; - } - flash_info.block_mask = ~(flash_info.block_size-1); - flash_info.init = 1; - return FLASH_ERR_OK; +// Walk the linked list and see if there are any overlaps in the +// addresses the devices claim to use using. +static bool flash_check_overlap(void) +{ + struct cyg_flash_dev *dev; + + // If there is zero or one device, short cut + if (flash_head == NULL || flash_head->next == NULL) + return false; + + for (dev=flash_head; dev->next; dev=dev->next){ + if (dev->end >= dev->next->start) + return true; + } + return false; } -// Use this function to make function pointers anonymous - forcing the -// compiler to use jumps instead of branches when calling driver -// services. -static void* __anonymizer(void* p) +// Initialise all registered device. Any device that fails to +// initialise we leave dev->init as false. Then sort the devices into +// ascending order of address and put them into a linked list. Lastly +// check if we have any overlap of the addresses. +__externC int +cyg_flash_init(cyg_flash_printf *pf) { - return p; + int err; + struct cyg_flash_dev * dev; + + if (init) return CYG_FLASH_ERR_OK; + init = true; + + for (dev = &cyg_flashdevtab[0]; dev != &cyg_flashdevtab_end; dev++) { + dev->pf = pf; +#ifdef CYGPKG_KERNEL + cyg_mutex_init(&dev->mutex); +#endif + + err = dev->funs->flash_init(dev); + if (err != CYG_FLASH_ERR_OK) { + continue; + } + CYG_ASSERT(dev->funs, "No flash functions"); + CYG_ASSERT(dev->num_block_infos, "No number of block infoss"); + CYG_ASSERT(dev->block_info, "No block infos"); + CYG_ASSERT(!(((cyg_flashaddr_t)dev->block_info >= dev->start) && + ((cyg_flashaddr_t)dev->block_info < dev->end)), + "Block info is in the flash"); + CYG_ASSERT(dev->funs->flash_erase_block, "No erase function"); + CYG_ASSERT(dev->funs->flash_program, "No program function"); + CYG_ASSERT(dev->funs->flash_hwr_map_error, "No hwr map error function"); + + dev->init = true; + dev->next = flash_head; + flash_head = dev; + } + + flash_sort(); + + if (flash_check_overlap()) { + return CYG_FLASH_ERR_INVALID; + } + return CYG_FLASH_ERR_OK; } -// FIXME: Want to change all drivers to use this function. But it may -// make sense to wait till device structure pointer arguments get -// added as well. -void -flash_dev_query(void* data) +// Is the address within one of the flash drivers? +__externC int +cyg_flash_verify_addr(const cyg_flashaddr_t address) { - typedef void code_fun(void*); - code_fun *_flash_query; - int d_cache, i_cache; - - _flash_query = (code_fun*) __anonymizer(&flash_query); - - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - (*_flash_query)(data); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + struct cyg_flash_dev * dev; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; dev; dev=dev->next) { + if ((dev->start <= address) && (dev->end > address)) + return CYG_FLASH_ERR_OK; + } + return CYG_FLASH_ERR_INVALID; } -int -flash_verify_addr(void *target) +// See if a range of FLASH addresses overlaps currently running code +__externC bool cyg_flash_code_overlaps(const cyg_flashaddr_t start, + const cyg_flashaddr_t end) { - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) && - ((CYG_ADDRESS)target <= ( ((CYG_ADDRESS)flash_info.end) - 1) )) { - return FLASH_ERR_OK; - } else { - return FLASH_ERR_INVALID; - } + 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))); } -int -flash_get_limits(void *target, void **start, void **end) +// Get the start and end address of the first driver +__externC int +cyg_flash_get_limits(cyg_flashaddr_t *start, cyg_flashaddr_t *end) { - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; + if (!init) { + return CYG_FLASH_ERR_NOT_INIT; } - *start = flash_info.start; - *end = flash_info.end; - return FLASH_ERR_OK; + if (flash_head) { + *start = flash_head->start; + *end = flash_head->end; + return CYG_FLASH_ERR_OK; + } + return CYG_FLASH_ERR_INVALID; } -int -flash_get_block_info(int *block_size, int *blocks) +// Get the block size and number of blocks for the first driver. For +// devices with boot blocks, consolidate the boot blocks into the +// figure. +__externC int +cyg_flash_get_block_info(size_t *block_size, cyg_uint32 *blocks) { - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; + size_t biggest_size=0; + cyg_uint32 i; + + + if (!init) { + return CYG_FLASH_ERR_NOT_INIT; + } + if (!flash_head) return CYG_FLASH_ERR_INVALID; + + // Find the biggest size of blocks + for (i=0; i < flash_head->num_block_infos; i++) { + if (flash_head->block_info[i].block_size > biggest_size) { + biggest_size = flash_head->block_info[i].block_size; } - *block_size = flash_info.block_size; - *blocks = flash_info.blocks; - return FLASH_ERR_OK; + } + + // Calculate the number of biggest size blocks + *block_size = biggest_size; + *blocks = 0; + for (i=0; i < flash_head->num_block_infos; i++) { + *blocks += (flash_head->block_info[i].block_size * + flash_head->block_info[i].blocks) / + biggest_size; + } + return CYG_FLASH_ERR_OK; +} + +// Return information about the Nth driver +__externC int +cyg_flash_get_info(cyg_uint32 Nth, cyg_flash_info_t * info) +{ + struct cyg_flash_dev * dev; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; dev && Nth; dev=dev->next, Nth--) + ; + if (dev && !Nth) { + info->start = dev->start; + info->end = dev->end; + info->num_block_infos = dev->num_block_infos; + info->block_info = dev->block_info; + return CYG_FLASH_ERR_OK; + } + return CYG_FLASH_ERR_INVALID; } -int -flash_erase(void *addr, int len, void **err_addr) +// Return information about the flash at the given address +__externC int +cyg_flash_get_info_addr(cyg_flashaddr_t flash_base, cyg_flash_info_t * info) { - unsigned short *block, *end_addr; - int stat = 0; - typedef int code_fun(unsigned short *, unsigned int); - code_fun *_flash_erase_block; - int d_cache, i_cache; - - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; + struct cyg_flash_dev *dev; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; dev ; dev=dev->next) { + if ((dev->start <= flash_base) && ( dev->end > flash_base)) { + info->start = dev->start; + info->end = dev->end; + info->num_block_infos = dev->num_block_infos; + info->block_info = dev->block_info; + return CYG_FLASH_ERR_OK; } - -#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT - if (plf_flash_query_soft_wp(addr,len)) - return FLASH_ERR_PROTECT; -#endif - - _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block); - - block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); - end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); + } + return CYG_FLASH_ERR_INVALID; +} - /* Check to see if end_addr overflowed */ - if( (end_addr < block) && (len > 0) ){ - end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1); +#ifdef CYGPKG_KERNEL +//Lock the mutex's for a range of addresses +__externC int +cyg_flash_mutex_lock(const cyg_flashaddr_t from, const size_t len) +{ + struct cyg_flash_dev * dev; + int err; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; dev ; dev=dev->next) { + if ((dev->start <= from) && ( dev->end > from)) { + cyg_mutex_lock(&dev->mutex); + if (dev->end > from+len) { + return CYG_FLASH_ERR_OK; + } else { // Check off by one? + //The region is bigger than this driver. Recurse + err = cyg_flash_mutex_lock(dev->end+1, (len - (dev->end - from))); + if (err != CYG_FLASH_ERR_OK) { + // Something went wrong, unlock what we just locked + cyg_mutex_unlock(&dev->mutex); + } + return err; + } } - -#ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr); -#endif + } + return CYG_FLASH_ERR_INVALID; +} - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - FLASH_Enable(block, end_addr); - while (block < end_addr) { - // Supply the blocksize for a gross check for erase success - unsigned short *tmp_block; -#if !defined(CYGSEM_IO_FLASH_READ_INDIRECT) - int i; - unsigned char *dp; - bool erased = true; - - dp = (unsigned char *)block; - for (i = 0; i < flash_info.block_size; i++) { - if (*dp++ != (unsigned char)0xFF) { - erased = false; - break; - } - } -#else - bool erased = false; +//Unlock the mutex's for a range of addresses +__externC int +cyg_flash_mutex_unlock(const cyg_flashaddr_t from, const size_t len) +{ + struct cyg_flash_dev * dev; + int err; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; dev ; dev=dev->next) { + if ((dev->start <= from) && ( dev->end > from)) { + cyg_mutex_unlock(&dev->mutex); + if (dev->end > from+len) { + return CYG_FLASH_ERR_OK; + } else { // Check off by one? + //The region is bigger than this driver. Recurse + err = cyg_flash_mutex_unlock(dev->end+1, (len - (dev->end - from))); + return err; + } + } + } + return CYG_FLASH_ERR_INVALID; +} #endif - if (!erased) { - stat = (*_flash_erase_block)(block, flash_info.block_size); - stat = flash_hwr_map_error(stat); - } - if (stat) { - *err_addr = (void *)block; - break; - } +// Return the size of the block which is at the given address +static size_t +flash_block_size(struct cyg_flash_dev *dev, const cyg_flashaddr_t addr) +{ + int i; + size_t offset; + + + CYG_ASSERT((addr >= dev->start) && (addr <= dev->end), "Not inside device"); + + offset = addr - dev->start; + for (i=0; i < dev->num_block_infos; i++) { + if (offset < (dev->block_info[i].blocks * dev->block_info[i].block_size)) + return dev->block_info[i].block_size; + offset = offset - + (dev->block_info[i].blocks * dev->block_info[i].block_size); + } + CYG_FAIL("Programming error"); + return 0; +} + +// Return the size of the block which is at the given address +__externC size_t +cyg_flash_block_size(const cyg_flashaddr_t flash_base) +{ + struct cyg_flash_dev * dev; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; + + return flash_block_size(dev, flash_base); +} + - // Check to see if block will overflow - tmp_block = block + flash_info.block_size / sizeof(*block); - if(tmp_block < block){ - // If block address overflows, set block value to end on this loop - block = end_addr; - } - else{ - block = tmp_block; - } +__externC int +cyg_flash_erase(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address) +{ + cyg_flashaddr_t block, end_addr, addr; + struct cyg_flash_dev * dev; + size_t block_size; + int stat = CYG_FLASH_ERR_OK; + int d_cache, i_cache; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + +#ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT + if (plf_flash_query_soft_wp(addr,len)) + return CYG_FLASH_ERR_PROTECT; +#endif + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; + +#ifdef CYGPKG_KERNEL + cyg_mutex_lock(&dev->mutex); +#endif + addr = flash_base; + end_addr = flash_base + len - 1; + if (end_addr > dev->end) { + end_addr = dev->end; + } + + block_size = flash_block_size(dev, addr); + block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1)); + #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("."); + dev->pf("... Erase from %p-%p: ", (void*)block, (void*)end_addr); #endif + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable(block, end_addr); + while (block <= end_addr) { + int i; + unsigned char *dp; + bool erased = true; + + // If there is a read function it probably means the flash + // cannot be read directly. + if (!dev->funs->flash_read) { + dp = (unsigned char *)block; + for (i = 0; i < block_size; i++) { + if (*dp++ != (unsigned char)0xFF) { + erased = false; + break; + } + } + } else { + erased=false; + } + if (!erased) { + stat = dev->funs->flash_erase_block(dev,block); + stat = dev->funs->flash_hwr_map_error(dev,stat); } - FLASH_Disable(block, end_addr); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + if (CYG_FLASH_ERR_OK != stat && err_address) { + *err_address = block; + break; + } + block += flash_block_size(dev, block); +#ifdef CYGSEM_IO_FLASH_CHATTER + dev->pf("."); +#endif + } + FLASH_Disable(block, end_addr); + HAL_FLASH_CACHES_ON(d_cache, i_cache); #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("\n"); + dev->pf("\n"); +#endif +#ifdef CYGPKG_KERNEL + cyg_mutex_unlock(&dev->mutex); #endif - return (stat); + if (stat != CYG_FLASH_ERR_OK) { + return stat; + } + + if (flash_base + len - 1 > dev->end) { + // The region to erase if bigger than this driver handles. Recurse + return cyg_flash_erase(dev->end+1, + len - (dev->end - flash_base) - 1, + err_address); + } + return CYG_FLASH_ERR_OK; } -int -flash_program(void *_addr, void *_data, int len, void **err_addr) +__externC int +cyg_flash_program(const cyg_flashaddr_t flash_base, + void *ram_base, + const size_t len, + cyg_flashaddr_t *err_address) { - int stat = 0; - int size; - typedef int code_fun(void *, void *, int, unsigned long, int); - code_fun *_flash_program_buf; - unsigned char *addr = (unsigned char *)_addr; - unsigned char *data = (unsigned char *)_data; - CYG_ADDRESS tmp; - int d_cache, i_cache; - - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - + struct cyg_flash_dev * dev; + cyg_flashaddr_t addr, end_addr; + unsigned char * ram = ram_base; + size_t block_size, size, length, offset; + int stat = CYG_FLASH_ERR_OK; + int d_cache, i_cache; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT - if (plf_flash_query_soft_wp(addr,len)) - return FLASH_ERR_PROTECT; + if (plf_flash_query_soft_wp(addr,len)) + return CYG_FLASH_ERR_PROTECT; #endif - - _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf); - + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; + +#ifdef CYGPKG_KERNEL + cyg_mutex_lock(&dev->mutex); +#endif + addr = flash_base; + end_addr = flash_base + len - 1; + if (end_addr > dev->end) { + end_addr = dev->end; + } + length = end_addr - addr + 1; + #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, - (void*)(((CYG_ADDRESS)data)+len), (void*)addr); + dev->pf("... Program from %p-%p to %p: ", ram_base, + ((CYG_ADDRESS)ram_base)+length, addr); #endif - - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len)); - while (len > 0) { - size = len; - if (size > flash_info.block_size) size = flash_info.block_size; - - tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask; - if (tmp) { - tmp = flash_info.block_size - tmp; - if (size>tmp) size = tmp; - - } - - stat = (*_flash_program_buf)(addr, data, size, - flash_info.block_mask, flash_info.buffer_size); - stat = flash_hwr_map_error(stat); + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len)); + while (addr <= end_addr) { + block_size = flash_block_size(dev, addr); + size = length; + // Only one block at once + if (size > block_size) size = block_size; + + // Writing from the middle of a block? + offset = (size_t)addr & (block_size-1); + if (offset) + size = MIN(block_size - offset, size); + stat = dev->funs->flash_program(dev, addr, ram, size); + stat = dev->funs->flash_hwr_map_error(dev,stat); #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM - if (0 == stat) // Claims to be OK - if (memcmp(addr, data, size) != 0) { - stat = 0x0BAD; + if (CYG_FLASH_ERR_OK == stat) // Claims to be OK + if (!dev->funs->flash_read && memcmp((void *)addr, ram, size) != 0) { + stat = CYG_FLASH_ERR_DRV_VERIFY; #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("V"); + dev->pf("V"); #endif - } + } #endif - if (stat) { - *err_addr = (void *)addr; - break; - } + if (CYG_FLASH_ERR_OK != stat && err_address) { + *err_address = addr; + break; + } #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("."); + dev->pf("."); #endif - len -= size; - addr += size/sizeof(*addr); - data += size/sizeof(*data); - } - FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len)); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + length -= size; + addr += size; + ram += size; + } + FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len)); + HAL_FLASH_CACHES_ON(d_cache, i_cache); #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("\n"); + dev->pf("\n"); +#endif +#ifdef CYGPKG_KERNEL + cyg_mutex_unlock(&dev->mutex); #endif + if (stat != CYG_FLASH_ERR_OK) { return (stat); + } + if ( flash_base + len - 1 > dev->end) { + return cyg_flash_program(dev->end+1, ram, + len - (dev->end - flash_base) - 1, + err_address); + } + return CYG_FLASH_ERR_OK; } -int -flash_read(void *_addr, void *_data, int len, void **err_addr) +__externC int +cyg_flash_read(cyg_flashaddr_t flash_base, + const void *ram_base, + const size_t len, + cyg_flashaddr_t *err_address) { -#ifdef CYGSEM_IO_FLASH_READ_INDIRECT - int stat = 0; - int size; - typedef int code_fun(void *, void *, int, unsigned long, int); - code_fun *_flash_read_buf; - unsigned char *addr = (unsigned char *)_addr; - unsigned char *data = (unsigned char *)_data; - CYG_ADDRESS tmp; - int d_cache, i_cache; - - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - - _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf); - -#ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("... Read from %p-%p at %p: ", (void*)data, - (void*)(((CYG_ADDRESS)data)+len), (void*)addr); -#endif - - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len)); - while (len > 0) { - size = len; - if (size > flash_info.block_size) size = flash_info.block_size; - - tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask; - if (tmp) { - tmp = flash_info.block_size - tmp; - if (size>tmp) size = tmp; - - } + struct cyg_flash_dev * dev; + cyg_flashaddr_t addr, end_addr; + unsigned char * ram = (unsigned char *)ram_base; + size_t block_size, size, length, offset; + int stat = CYG_FLASH_ERR_OK; + int d_cache, i_cache; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; - stat = (*_flash_read_buf)(addr, data, size, - flash_info.block_mask, flash_info.buffer_size); - stat = flash_hwr_map_error(stat); -#ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM_ - if (0 == stat) // Claims to be OK - if (memcmp(addr, data, size) != 0) { - stat = 0x0BAD; +#ifdef CYGPKG_KERNEL + cyg_mutex_lock(&dev->mutex); +#endif + addr = flash_base; + end_addr = flash_base + len - 1; + if (end_addr > dev->end) { + end_addr = dev->end; + } + length = end_addr - addr + 1; + #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("V"); -#endif - } -#endif - if (stat) { - *err_addr = (void *)addr; - break; - } -#ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("."); + dev->pf("... Read from %p-%p to %p: ", addr, addr+len, ram_base); #endif - len -= size; - addr += size/sizeof(*addr); - data += size/sizeof(*data); + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len)); + while (addr <= end_addr) { + block_size = flash_block_size(dev, addr); + size = length; + // Only one block at once + if (size > block_size) size = block_size; + + // Reading from the middle of a block? + offset = (size_t)addr & (block_size-1); + if (offset) + size = MIN(block_size - offset, size); + if (dev->funs->flash_read) { + stat = dev->funs->flash_read(dev, addr, ram, size); + stat = dev->funs->flash_hwr_map_error(dev,stat); + } else { + memcpy(ram, (void *)addr, size); + stat = CYG_FLASH_ERR_OK; } - FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len)); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + if (CYG_FLASH_ERR_OK != stat && err_address) { + *err_address = addr; + break; + } #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("\n"); + dev->pf("."); #endif + length -= size; + addr += size; + ram += size; + } + FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len)); + HAL_FLASH_CACHES_ON(d_cache, i_cache); +#ifdef CYGSEM_IO_FLASH_CHATTER + dev->pf("\n"); +#endif +#ifdef CYGPKG_KERNEL + cyg_mutex_unlock(&dev->mutex); +#endif + if (stat != CYG_FLASH_ERR_OK) { return (stat); -#else // CYGSEM_IO_FLASH_READ_INDIRECT - // Direct access to FLASH memory is possible - just move the requested bytes - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - memcpy(_data, _addr, len); - return FLASH_ERR_OK; -#endif + } + if ( flash_base + len - 1 > dev->end) { + return cyg_flash_read(dev->end+1, ram, + len - (dev->end - flash_base) - 1, + err_address); + } + return CYG_FLASH_ERR_OK; } #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING - -int -flash_lock(void *addr, int len, void **err_addr) +__externC int +cyg_flash_lock(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address) { - unsigned short *block, *end_addr; - int stat = 0; - typedef int code_fun(unsigned short *); - code_fun *_flash_lock_block; - int d_cache, i_cache; - - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - + cyg_flashaddr_t block, end_addr, addr; + struct cyg_flash_dev * dev; + size_t block_size; + int stat = CYG_FLASH_ERR_OK; + int d_cache, i_cache; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT - if (plf_flash_query_soft_wp(addr,len)) - return FLASH_ERR_PROTECT; + if (plf_flash_query_soft_wp(addr,len)) + return CYG_FLASH_ERR_PROTECT; #endif - - _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block); + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; + if (!dev->funs->flash_block_lock) return CYG_FLASH_ERR_INVALID; - block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); - end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); - - /* Check to see if end_addr overflowed */ - if( (end_addr < block) && (len > 0) ){ - end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1); - } - -#ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr); +#ifdef CYGPKG_KERNEL + cyg_mutex_lock(&dev->mutex); #endif - - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - FLASH_Enable(block, end_addr); - while (block < end_addr) { - unsigned short *tmp_block; - stat = (*_flash_lock_block)(block); - stat = flash_hwr_map_error(stat); - if (stat) { - *err_addr = (void *)block; - break; - } - - // Check to see if block will overflow - tmp_block = block + flash_info.block_size / sizeof(*block); - if(tmp_block < block){ - // If block address overflows, set block value to end on this loop - block = end_addr; - } - else{ - block = tmp_block; - } + addr = flash_base; + end_addr = flash_base + len - 1; + if (end_addr > dev->end) { + end_addr = dev->end; + } + + block_size = flash_block_size(dev, addr); + block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1)); + #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("."); + dev->pf("... Locking from %p-%p: ", (void*)block, (void*)end_addr); #endif + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable(block, end_addr); + while (block <= end_addr) { + stat = dev->funs->flash_block_lock(dev,block); + stat = dev->funs->flash_hwr_map_error(dev,stat); + + if (CYG_FLASH_ERR_OK != stat && err_address) { + *err_address = (void *)block; + break; } - FLASH_Disable(block, end_addr); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + block += flash_block_size(dev, addr); +#ifdef CYGSEM_IO_FLASH_CHATTER + dev->pf("."); +#endif + } + FLASH_Disable(block, end_addr); + HAL_FLASH_CACHES_ON(d_cache, i_cache); #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("\n"); + dev->pf("\n"); +#endif +#ifdef CYGPKG_KERNEL + cyg_mutex_unlock(&dev->mutex); #endif - return (stat); + if (stat != CYG_FLASH_ERR_OK) { + return stat; + } + + if (flash_base + len - 1 > dev->end) { // Off by one? + // The region to erase if bigger than this driver handles. Recurse + return cyg_flash_lock(dev->end+1, + len - (dev->end - flash_base) - 1, + err_address); + } + return CYG_FLASH_ERR_OK; } -int -flash_unlock(void *addr, int len, void **err_addr) +__externC int +cyg_flash_unlock(const cyg_flashaddr_t flash_base, + const size_t len, + cyg_flashaddr_t *err_address) { - unsigned short *block, *end_addr; - int stat = 0; - typedef int code_fun(unsigned short *, int, int); - code_fun *_flash_unlock_block; - int d_cache, i_cache; - - if (!flash_info.init) { - return FLASH_ERR_NOT_INIT; - } - + cyg_flashaddr_t block, end_addr, addr; + struct cyg_flash_dev * dev; + size_t block_size; + int stat = CYG_FLASH_ERR_OK; + int d_cache, i_cache; + + if (!init) return CYG_FLASH_ERR_NOT_INIT; + #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT - if (plf_flash_query_soft_wp(addr,len)) - return FLASH_ERR_PROTECT; + if (plf_flash_query_soft_wp(addr,len)) + return CYG_FLASH_ERR_PROTECT; #endif - - _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block); - - block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); - end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); - - /* Check to see if end_addr overflowed */ - if( (end_addr < block) && (len > 0) ){ - end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1); - } - -#ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr); + + for (dev = flash_head; + dev && !((dev->start <= flash_base) && ( dev->end > flash_base)); + dev=dev->next) + ; + if (!dev) return CYG_FLASH_ERR_INVALID; + if (!dev->funs->flash_block_lock) return CYG_FLASH_ERR_INVALID; + +#ifdef CYGPKG_KERNEL + cyg_mutex_lock(&dev->mutex); #endif - - HAL_FLASH_CACHES_OFF(d_cache, i_cache); - FLASH_Enable(block, end_addr); - while (block < end_addr) { - unsigned short *tmp_block; - stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks); - stat = flash_hwr_map_error(stat); - if (stat) { - *err_addr = (void *)block; - break; - } - - tmp_block = block + flash_info.block_size / sizeof(*block); - if(tmp_block < block){ - // If block address overflows, set block value to end on this loop - block = end_addr; - } - else{ - block = tmp_block; - } + addr = flash_base; + end_addr = flash_base + len - 1; + if (end_addr > dev->end) { + end_addr = dev->end; + } + + block_size = flash_block_size(dev, addr); + block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1)); + #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("."); + dev->pf("... Unlocking from %p-%p: ", (void*)block, (void*)end_addr); #endif + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable(block, end_addr); + while (block <= end_addr) { + stat = dev->funs->flash_block_unlock(dev,block); + stat = dev->funs->flash_hwr_map_error(dev,stat); + + if (CYG_FLASH_ERR_OK != stat && err_address) { + *err_address = (void *)block; + break; } - FLASH_Disable(block, end_addr); - HAL_FLASH_CACHES_ON(d_cache, i_cache); + block += flash_block_size(dev, addr); +#ifdef CYGSEM_IO_FLASH_CHATTER + dev->pf("."); +#endif + } + FLASH_Disable(block, end_addr); + HAL_FLASH_CACHES_ON(d_cache, i_cache); #ifdef CYGSEM_IO_FLASH_CHATTER - (*flash_info.pf)("\n"); + dev->pf("\n"); +#endif +#ifdef CYGPKG_KERNEL + cyg_mutex_unlock(&dev->mutex); #endif - return (stat); + if (stat != CYG_FLASH_ERR_OK) { + return stat; + } + + if (flash_base + len - 1 > dev->end) { // Off by one? + // The region to erase if bigger than this driver handles. Recurse + return cyg_flash_lock(dev->end+1, + len - (dev->end - flash_base) - 1, + err_address); + } + return CYG_FLASH_ERR_OK; } #endif -char * -flash_errmsg(int err) +const char * +cyg_flash_errmsg(const int err) { switch (err) { - case FLASH_ERR_OK: + case CYG_FLASH_ERR_OK: return "No error - operation complete"; - case FLASH_ERR_ERASE_SUSPEND: + case CYG_FLASH_ERR_ERASE_SUSPEND: return "Device is in erase suspend state"; - case FLASH_ERR_PROGRAM_SUSPEND: + case CYG_FLASH_ERR_PROGRAM_SUSPEND: return "Device is in program suspend state"; - case FLASH_ERR_INVALID: + case CYG_FLASH_ERR_INVALID: return "Invalid FLASH address"; - case FLASH_ERR_ERASE: + case CYG_FLASH_ERR_ERASE: return "Error trying to erase"; - case FLASH_ERR_LOCK: + case CYG_FLASH_ERR_LOCK: return "Error trying to lock/unlock"; - case FLASH_ERR_PROGRAM: + case CYG_FLASH_ERR_PROGRAM: return "Error trying to program"; - case FLASH_ERR_PROTOCOL: + case CYG_FLASH_ERR_PROTOCOL: return "Generic error"; - case FLASH_ERR_PROTECT: + case CYG_FLASH_ERR_PROTECT: return "Device/region is write-protected"; - case FLASH_ERR_NOT_INIT: + case CYG_FLASH_ERR_NOT_INIT: return "FLASH sub-system not initialized"; - case FLASH_ERR_DRV_VERIFY: + case CYG_FLASH_ERR_DRV_VERIFY: return "Data verify failed after operation"; - case FLASH_ERR_DRV_TIMEOUT: + case CYG_FLASH_ERR_DRV_TIMEOUT: return "Driver timed out waiting for device"; - case FLASH_ERR_DRV_WRONG_PART: + case CYG_FLASH_ERR_DRV_WRONG_PART: return "Driver does not support device"; - case FLASH_ERR_LOW_VOLTAGE: + case CYG_FLASH_ERR_LOW_VOLTAGE: return "Device reports low voltage"; default: return "Unknown error";
--- a/packages/io/flash/current/src/flashiodev.c +++ b/packages/io/flash/current/src/flashiodev.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -41,7 +42,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): jlarmour -// Contributors: woehler +// Contributors: woehler, Andrew Lunn // Date: 2002-01-16 // Purpose: // Description: @@ -62,110 +63,121 @@ #include <cyg/hal/hal_if.h> #define MIN(x,y) ((x)<(y) ? (x) : (y)) +#define MAX(x,y) ((x)>(y) ? (x) : (y)) struct flashiodev_priv_t{ - char *start; - char *end; + cyg_flashaddr_t start; + cyg_flashaddr_t end; + cyg_bool use_fis; + cyg_bool use_absolute; + cyg_bool use_offset; + char * fis_name; + cyg_uint32 block_size; }; -static struct flashiodev_priv_t flashiodev_priv[1]; - static int dummy_printf( const char *fmt, ... ) {return 0;} static bool flashiodev_init( struct cyg_devtab_entry *tab ) { - struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; - int stat = flash_init( &dummy_printf ); - if ( stat == 0 ) { -#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 - CYG_ADDRESS flash_base; - unsigned long size; + struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; + cyg_flash_info_t info; + cyg_uint32 i; + + int stat = cyg_flash_init( &dummy_printf ); + if ( stat == 0 ) { + if (dev->use_fis) { + CYG_ADDRESS flash_base; + unsigned long size; + + if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, + dev->fis_name, + &flash_base)) + return false; + if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, + dev->fis_name, + &size)) + return false; + + dev->start = flash_base; + dev->end = flash_base + size; + } + if (dev->use_offset) { + // dev->start the contain the offset to the beginning of the block + // dev->end is the length of the block + cyg_flashaddr_t start, end; + cyg_flash_get_limits(&start, &end); + dev->start = dev->start + start; + dev->end = dev->start + dev->end; + } + if (dev->use_absolute) { + // dev->start is the absolute address of the start + // dev->end is the length; + dev->end = dev->start + dev->end; + } - if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, - CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1, - &flash_base)) - return false; - if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, - CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1, - &size)) - return false; - - dev->start = (char *)flash_base; - dev->end = (char *)flash_base + size; -#else - dev->start = (char *)flash_info.start + CYGNUM_IO_FLASH_BLOCK_OFFSET_1; - dev->end = (char *)flash_info.start + CYGNUM_IO_FLASH_BLOCK_OFFSET_1 + - CYGNUM_IO_FLASH_BLOCK_LENGTH_1; -#endif - return true; - } else - return false; + stat = cyg_flash_get_info_addr(dev->start, &info); + if (stat != CYG_FLASH_ERR_OK) { + return false; + } + dev->block_size = 0; + for (i=0; i < info.num_block_infos; i++){ + dev->block_size = MAX(dev->block_size, info.block_info[i].block_size); + } + + return true; + } else + return false; } // flashiodev_init() -#if 0 -static Cyg_ErrNo -flashiodev_lookup( struct cyg_devtab_entry **tab, - struct cyg_devtab_entry *sub_tab, - const char *name) -{ -} // flashiodev_lookup() -#endif - static Cyg_ErrNo flashiodev_bread( cyg_io_handle_t handle, void *buf, cyg_uint32 *len, cyg_uint32 pos) { - struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; - struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; - - char *startpos = dev->start + pos; - void *erraddr; - Cyg_ErrNo err = ENOERR; - - + struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; + struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; + + cyg_flashaddr_t startpos = dev->start + pos; + Cyg_ErrNo err; + + #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time - char *endpos = startpos + *len - 1; - char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1); - if ( startpos < dev->start ) - return -EINVAL; - if ( endpos > flashend ) - return -EINVAL; + cyg_flashaddr_t endpos = startpos + *len - 1; + if ( startpos < dev->start ) + return -EINVAL; + if ( endpos > dev->end ) + return -EINVAL; #endif - - err = flash_read( startpos, - (void *)buf, *len, &erraddr ); - - if ( err ) - err = -EIO; // just something sane - return err; + + err = cyg_flash_read( startpos,(void *)buf, *len, NULL ); + + if ( err != CYG_FLASH_ERR_OK ) + err = -EIO; // just something sane + return err; } // flashiodev_bread() static Cyg_ErrNo flashiodev_bwrite( cyg_io_handle_t handle, const void *buf, cyg_uint32 *len, cyg_uint32 pos ) -{ - struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; - struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; - - Cyg_ErrNo err = ENOERR; - void *erraddr; - char *startpos = dev->start + pos; - +{ + struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; + struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; + + Cyg_ErrNo err; + cyg_flashaddr_t startpos = dev->start + pos; + #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time - char *endpos = startpos + *len - 1; - char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1); - if ( startpos < dev->start ) - return -EINVAL; - if ( endpos > flashend ) - return -EINVAL; + cyg_flashaddr_t endpos = startpos + *len - 1; + if ( startpos < dev->start ) + return -EINVAL; + if ( endpos > dev->end ) + return -EINVAL; #endif - err = flash_program( startpos, - (void *)buf, *len, &erraddr ); - - if ( err ) - err = -EIO; // just something sane - return err; + err = cyg_flash_program( startpos, (void *)buf, *len, NULL ); + + if ( err ) + err = -EIO; // just something sane + return err; } // flashiodev_bwrite() static Cyg_ErrNo @@ -174,68 +186,65 @@ flashiodev_get_config( cyg_io_handle_t h void* buf, cyg_uint32* len) { - struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; - struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; - - switch (key) { - case CYG_IO_GET_CONFIG_FLASH_ERASE: + struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; + struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; + + switch (key) { + case CYG_IO_GET_CONFIG_FLASH_ERASE: { - if ( *len != sizeof( cyg_io_flash_getconfig_erase_t ) ) - return -EINVAL; - { - cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf; - char *startpos = dev->start + e->offset; - + if ( *len != sizeof( cyg_io_flash_getconfig_erase_t ) ) + return -EINVAL; + { + cyg_io_flash_getconfig_erase_t *e = (cyg_io_flash_getconfig_erase_t *)buf; + cyg_flashaddr_t startpos = dev->start + e->offset; + #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time - char *endpos = startpos + e->len - 1; - char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1); - if ( startpos < dev->start ) - return -EINVAL; - if ( endpos > flashend ) - return -EINVAL; + cyg_flashaddr_t endpos = startpos + e->len - 1; + if ( startpos < dev->start ) + return -EINVAL; + if ( endpos > dev->end ) + return -EINVAL; #endif - e->flasherr = flash_erase( startpos, e->len, e->err_address ); - } - return ENOERR; + e->flasherr = cyg_flash_erase( startpos, e->len, e->err_address ); + } + return ENOERR; } - case CYG_IO_GET_CONFIG_FLASH_DEVSIZE: + case CYG_IO_GET_CONFIG_FLASH_DEVSIZE: { - if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) ) - return -EINVAL; - { - cyg_io_flash_getconfig_devsize_t *d = - (cyg_io_flash_getconfig_devsize_t *)buf; - - //d->dev_size = flash_info.blocks * flash_info.block_size; - d->dev_size = dev->end - dev->start; - } - return ENOERR; + if ( *len != sizeof( cyg_io_flash_getconfig_devsize_t ) ) + return -EINVAL; + { + cyg_io_flash_getconfig_devsize_t *d = + (cyg_io_flash_getconfig_devsize_t *)buf; + + d->dev_size = dev->end - dev->start; + } + return ENOERR; } - - case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE: + + case CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE: { - cyg_io_flash_getconfig_blocksize_t *b = - (cyg_io_flash_getconfig_blocksize_t *)buf; + cyg_io_flash_getconfig_blocksize_t *b = + (cyg_io_flash_getconfig_blocksize_t *)buf; #ifdef CYGPKG_INFRA_DEBUG // don't bother checking this all the time - char *startpos = dev->start + b->offset; - char *flashend = MIN( (char *)flash_info.end - 1, dev->end - 1); - - if ( startpos < dev->start ) - return -EINVAL; - if ( startpos > flashend ) - return -EINVAL; + cyg_flashaddr_t startpos = dev->start + b->offset; + + if ( startpos < dev->start ) + return -EINVAL; + if ( startpos > dev->end ) + return -EINVAL; #endif - if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) ) - return -EINVAL; - - // offset unused for now - b->block_size = flash_info.block_size; - return ENOERR; + if ( *len != sizeof( cyg_io_flash_getconfig_blocksize_t ) ) + return -EINVAL; + + // offset unused for now + b->block_size = dev->block_size; + return ENOERR; } - - default: - return -EINVAL; - } + + default: + return -EINVAL; + } } // flashiodev_get_config() static Cyg_ErrNo @@ -244,46 +253,88 @@ flashiodev_set_config( cyg_io_handle_t h const void* buf, cyg_uint32* len) { -#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 - struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; - struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; -#endif - - switch (key) { -#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 - case CYG_IO_SET_CONFIG_FLASH_FIS_NAME: + struct cyg_devtab_entry *tab = (struct cyg_devtab_entry *)handle; + struct flashiodev_priv_t *dev = (struct flashiodev_priv_t *)tab->priv; + + switch (key) { + case CYG_IO_SET_CONFIG_FLASH_FIS_NAME: { - CYG_ADDRESS flash_base; - unsigned long size; + cyg_flashaddr_t flash_base; + unsigned long size; + cyg_flash_info_t info; + cyg_uint32 i; + int stat; + + if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, + (char *)buf, &flash_base)) + return -ENOENT; + if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, + (char *)buf, &size)) + return -ENOENT; + + dev->start = flash_base; + dev->end = flash_base + size; - if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE, - (char *)buf, &flash_base)) - return -ENOENT; - if(!CYGACC_CALL_IF_FLASH_FIS_OP(CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE, - (char *)buf, &size)) - return -ENOENT; - - dev->start = (char *)flash_base; - dev->end = (char *)flash_base + size; - return ENOERR; + stat = cyg_flash_get_info_addr(dev->start, &info); + if (stat != CYG_FLASH_ERR_OK) { + return -ENOENT; + } + dev->block_size = 0; + for (i=0; i < info.num_block_infos; i++){ + dev->block_size = MAX(dev->block_size, info.block_info[i].block_size); + } + return ENOERR; } -#endif - default: - return -EINVAL; - } + default: + return -EINVAL; + } } // flashiodev_set_config() // get_config/set_config should be added later to provide the other flash // operations possible, like erase etc. +#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_1 +static struct flashiodev_priv_t priv1 = { + 0, // start + 0, // end + 1, // use_fis + 0, // use_static + 0. // use_offset + CYGDAT_IO_FLASH_BLOCK_FIS_NAME_1, + 0 // blocksize +}; + +#endif +#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_1 +static struct flashiodev_priv_t priv1 = { + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1, // start + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_1 + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_1, + 0, // use_fis + 1, // use_static + 0, // use_offset + "", // fis_name + 0 // blocksize +}; +#else +static struct flashiodev_priv_t priv1 = { + CYGNUM_IO_FLASH_BLOCK_OFFSET_1, // start + CYGNUM_IO_FLASH_BLOCK_LENGTH_1, // end + 0, // use_fis + 0, // use_static + 1, // use_offset + "", // fis_name + 0 // blocksize +}; +#endif + BLOCK_DEVIO_TABLE( cyg_io_flashdev1_ops, &flashiodev_bwrite, &flashiodev_bread, 0, // no select &flashiodev_get_config, &flashiodev_set_config - ); - + ); + BLOCK_DEVTAB_ENTRY( cyg_io_flashdev1, CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, @@ -291,6 +342,51 @@ BLOCK_DEVTAB_ENTRY( cyg_io_flashdev1, &cyg_io_flashdev1_ops, &flashiodev_init, 0, // No lookup required - &flashiodev_priv[0] ); + &priv1 ); + + +#ifdef CYGSEM_IO_FLASH_BLOCK_DEVICE_2 +#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_FIS_2 +static struct flashiodev_priv_t priv2 = { + 0, // start + 0, // end + 1, // use_fis + 0, // use_static + 0. // use_offset + CYGDAT_IO_FLASH_BLOCK_FIS_NAME_2, + 0 // blocksize +}; + +#endif +#ifdef CYGNUM_IO_FLASH_BLOCK_CFG_STATIC_ABSOLUTE_2 +static struct flashiodev_priv_t priv2 = { + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2, // start + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_START_2 + CYGNUM_IO_FLASH_BLOCK_ABSOLUTE_LENGTH_2, + 0, // use_fis + 1, // use_static + 0, // use_offset + "", // fis_name + 0 // blocksize +}; +#else +static struct flashiodev_priv_t priv2 = { + CYGNUM_IO_FLASH_BLOCK_OFFSET_2, // start + CYGNUM_IO_FLASH_BLOCK_LENGTH_2, // end + 0, // use_fis + 0, // use_static + 1, // use_offset + "", // fis_name + 0 // blocksize +}; +#endif + +BLOCK_DEVTAB_ENTRY( cyg_io_flashdev2, + CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2, + 0, + &cyg_io_flashdev1_ops, + &flashiodev_init, + 0, // No lookup required + &priv2 ); +#endif // EOF flashiodev.c
new file mode 100644 --- /dev/null +++ b/packages/io/flash/current/src/legacy_api.c @@ -0,0 +1,102 @@ +//========================================================================== +// +// legacy_api.c +// +// Legacy API implementation on top of the new API +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// 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): Andrew Lunn +// Contributors: Andrew Lunn +// Date: 2004-07-02 +// Purpose: +// Description: Implement an interface to the legacy device drivers +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> +#include <pkgconf/io_flash.h> + +#define _FLASH_PRIVATE_ +#include <cyg/io/flash.h> + +int +flash_init(_printf *pf) +{ + return cyg_flash_init(pf); +} + +int +flash_verify_addr(void *target) +{ + return cyg_flash_verify_addr((cyg_flashaddr_t) target); +} + +int +flash_get_limits(void *target, void **start, void **end) +{ + return cyg_flash_get_limits((cyg_flashaddr_t *)start, + (cyg_flashaddr_t *)end); +} + +int +flash_get_block_info(int *block_size, int *blocks) +{ + return cyg_flash_get_block_info((size_t *)block_size, blocks); +} + +int +flash_erase(void *addr, int len, void **err_addr) +{ + return cyg_flash_erase((cyg_flashaddr_t)addr, len, + (cyg_flashaddr_t *)err_addr); +} + +int flash_program(void *flash_base, void *ram_base, int len, + void **err_address) +{ + return cyg_flash_program((cyg_flashaddr_t)flash_base, ram_base, + len, (cyg_flashaddr_t *)err_address); +} + +int flash_read(void *flash_base, void *ram_base, int len, void **err_address) +{ + return cyg_flash_read((cyg_flashaddr_t)flash_base, ram_base, + len, (cyg_flashaddr_t *)err_address); +}
new file mode 100644 --- /dev/null +++ b/packages/io/flash/current/src/legacy_dev.c @@ -0,0 +1,284 @@ +//========================================================================== +// +// legacy_dev.c +// +// Interface to the legacy device drivers +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// 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): Andrew Lunn +// Contributors: Andrew Lunn +// Date: 2004-07-02 +// Purpose: +// Description: Implement an interface to the legacy device drivers +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> +#include <pkgconf/io_flash.h> + +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/hal_cache.h> +#include <string.h> + +#define _FLASH_PRIVATE_ +#include <cyg/io/flash.h> + +// When this flag is set, do not actually jump to the relocated code. +// This can be used for running the function in place (RAM startup only), +// allowing calls to diag_printf() and similar. +#undef RAM_FLASH_DEV_DEBUG +#if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG) +# warning "Can only enable the flash debugging when configured for RAM startup" +#endif + +struct flash_info flash_info; + +// These are the functions in the HW specific driver we need to call. +typedef void code_fun(void*); + +externC code_fun flash_query; +externC code_fun flash_erase_block; +externC code_fun flash_program_buf; +externC code_fun flash_read_buf; +externC code_fun flash_lock_block; +externC code_fun flash_unlock_block; + +// Initialize the device +static int +legacy_flash_init (struct cyg_flash_dev *dev) +{ + int err; + static cyg_block_info_t block_info[1]; + + err=flash_hwr_init(); + + if (!err) { + dev->start = (cyg_flashaddr_t)flash_info.start; + dev->end = (cyg_flashaddr_t)flash_info.end; + dev->num_block_infos = 1; + dev->block_info = block_info; + block_info[0].block_size = flash_info.block_size; + block_info[0].blocks = flash_info.blocks; + } + return err; +} + +// Use this function to make function pointers anonymous - forcing the +// compiler to use jumps instead of branches when calling driver +// services. +static void* __anonymizer(void* p) +{ + return p; +} + +static size_t +legacy_flash_query (struct cyg_flash_dev *dev, + void * data, + const size_t len) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static size_t +legacy_flash_query (struct cyg_flash_dev *dev, + void * data, + const size_t len) +{ + typedef void code_fun(void*); + code_fun *_flash_query; + + _flash_query = (code_fun*) __anonymizer(&flash_query); + + (*_flash_query)(data); + + return len; +} + +static int +legacy_flash_erase_block (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_erase_block (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) +{ + typedef int code_fun(cyg_flashaddr_t, unsigned int); + code_fun *_flash_erase_block; + size_t block_size = dev->block_info[0].block_size; + + _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block); + + return (*_flash_erase_block)(block_base, block_size); +} + +static int +legacy_flash_program(struct cyg_flash_dev *dev, + cyg_flashaddr_t base, + const void* data, const size_t len) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_program(struct cyg_flash_dev *dev, + cyg_flashaddr_t base, + const void* data, const size_t len) +{ + typedef int code_fun(cyg_flashaddr_t, const void *, int, unsigned long, int); + code_fun *_flash_program_buf; + size_t block_size = dev->block_info[0].block_size; + size_t block_mask = ~(block_mask -1); + + _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf); + + return (*_flash_program_buf)(base, data, len, block_mask ,block_size); +} + +static int +legacy_flash_read (struct cyg_flash_dev *dev, + const cyg_flashaddr_t base, + void* data, const size_t len) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_read (struct cyg_flash_dev *dev, + const cyg_flashaddr_t base, + void* data, const size_t len) +{ +#ifdef CYGSEM_IO_FLASH_READ_INDIRECT + typedef int code_fun(void *, void *, int, unsigned long, int); + code_fun *_flash_read_buf; + size_t block_size = dev->block_info[0].block_size; + size_t block_mask = ~(block_mask -1); + + _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf); + + return = (*_flash_read_buf)(base, data, len, block_mask, buffer_size); +#else + memcpy(data,(void *)base, len); + return CYG_FLASH_ERR_OK; +#endif +} + + +static int +legacy_flash_block_lock (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_block_lock (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) +{ +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + typedef int code_fun(cyg_flashaddr_t); + code_fun *_flash_lock_block; + + _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block); + + return (*_flash_lock_block)(block_base); +#else + return CYG_FLASH_ERR_INVALID; +#endif +} + +static int +legacy_flash_block_unlock (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_block_unlock (struct cyg_flash_dev *dev, + const cyg_flashaddr_t block_base) +{ +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + typedef int code_fun(cyg_flashaddr_t, int, int); + code_fun *_flash_unlock_block; + size_t block_size = dev->block_info[0].block_size; + cyg_uint32 blocks = dev->block_info[0].blocks; + + _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block); + + return (*_flash_unlock_block)(block_base, block_size, blocks); +#else + return CYG_FLASH_ERR_INVALID; +#endif +} + +// Map a hardware status to a package error +static int +legacy_flash_hwr_map_error (struct cyg_flash_dev *dev, int err) + __attribute__ ((section (".2ram.flash_program_buf"))); + +static int +legacy_flash_hwr_map_error (struct cyg_flash_dev *dev, int err) +{ + return flash_hwr_map_error(err); +} + +void +flash_dev_query(void* data) +{ + typedef void code_fun(void*); + code_fun *_flash_query; + int d_cache, i_cache; + + _flash_query = (code_fun*) __anonymizer(&flash_query); + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + (*_flash_query)(data); + HAL_FLASH_CACHES_ON(d_cache, i_cache); +} + +CYG_FLASH_FUNS(cyg_legacy_funs, + legacy_flash_init, + legacy_flash_query, + legacy_flash_erase_block, + legacy_flash_program, + legacy_flash_read, + legacy_flash_hwr_map_error, + legacy_flash_block_lock, + legacy_flash_block_unlock +); + +CYG_FLASH_DRIVER(cyg_zzlegacy_flashdev, // zz so that it probably comes last. + &cyg_legacy_funs, + NULL, // Pointer to config structure + 0, // Start address of flash + 0); // Size of private structure +
