eCos Product

eCos Net Distribution


RedBoot Product
 
RedBoot Net Distribution


Supported Hardware

Downloading and Installation

Documentation

FAQ

Keeping in Touch

Problems

Licensing

Anonymous CVS

Contributions and Third Party Projects

Red Hat eCos

Flash Driver


A flash device driver consists of two elements: a generic device driver which knows how to handle a particular part or family of flash devices, and a platform specific driver which contains information about how the devices are laid out on the particular platform. This allows the core device driver to be shared by multiple platforms which have different device configurations.

The below descriptions are based on the AMD AM29xxxxx generic driver and the PowerPC MBX platform driver.

Other device drivers (e.g. ethernet drivers) rely on the platform driver to provide a header file with details which is included when the generic driver object is built. But in the flash device drivers, the generic driver is provided as an .inl header file which is included when the driver object is built in the platform driver.

The reason for this is that the driver code needs compile-time configuration to handle different configurations of interleaved devices. Letting the platform driver build the object allows the same generic driver to be used in multiple different configurations on the same platform.

General Issues

Error values

Error values are defined in the IO flash driver. For the current list of errors, see the file flash.h. Here's the list at the time of writing:

#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
 

Void pointers

Different drivers will have different word widths, depending on device types and number of interleaved devices. Since the IO driver must be able to use them all, device and data addresses are passed as void pointers, and size arguments always denote bytes.

Flash interleaving

Different platforms may use the same flash parts in different interleaved configurations, e.g., platform A has one 16-bit device, while platform B has two interleaved (parallel) devices to create one virtual 32-bit wide device. For this reason, all access to the device is done using the flash_data_t type which takes on the correct width, and all device commands are defined to the correct width using the macro FLASHWORD.

Flash mapping

On some platforms the flash devices may not be linearly accessible. In order to let the driver work on such platforms, all addressing of the device should use the FLASH_P2V macro which does a physical address translation to a virtual address which works with the device on the particular platform.

Flash access

All access operations that take the flash device out of its normal random access data mode must be done from RAM. Therefore all such functions must be put in the special .2ram section which will get copied to RAM during system initialization.

Caching during access

Some architectures/platforms will access the flash area in burst mode, which spoils the flash interaction protocols. To counter this, the IO driver disables caches before calling the driver functions. This is done using the macro HAL_FLASH_CACHES_OFF and the matching HAL_FLASH_CACHES_ON for which there are generic definitions in the IO driver. Some architectures/platforms may have to override these macros though.

Generic Flash Driver

The generic driver package must contain CDL in the following style:

cdl_package CYGPKG_DEVS_FLASH_AMD_AM29XXXXX {
    display       "AMD AM29XXXXX FLASH memory support"
    description   "FLASH memory device support for AMD AM29XXXXX"
    parent        CYGPKG_IO_FLASH
    active_if	  CYGPKG_IO_FLASH

    active_if     CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED

    implements    CYGHWR_IO_FLASH_DEVICE

    include_dir   cyg/io
}

The package is only enabled if the IO flash driver is present and CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED is defined in the platform flash driver. There are no files to build, since the driver is provided in the form of an .inl header file.

The flash driver must provide the API described below. Note that this API is likely to change some time in the future to allow multiple flash drivers in the same system.

int flash_hwr_init(void)

Ensures that the device is indeed a supported device by querying the manufacturer and/or type codes. Also initializes flash driver data with flash size, location, number of regions and region sizes.

void flash_query(void* data)

Reads whatever information is needed from the flash device necessary to identify it. This is usually the manufacturer and part numbers which are written to data. This function should only be called from within the driver (which knows the size of the data stored). The function is only public because it needs to be called via the IO driver.

int flash_hwr_map_error(int err)

Translates a flash error code to an eCos flash error code. This is a null operation (legacy function) since the driver should always return eCos flash error codes anyway.

bool flash_code_overlaps(void *start, void *end)

Determines if the specified flash range overlaps with any running code, thus allowing an abort of the operation. FIXME: This function should be removed from the device driver.

int flash_erase_block(volatile void* block)

Erase the specified block. Returns FLASH_ERR_OK if the operation succeeded, otherwise an error code describing the failure.

int flash_program_buf(volatile void* addr, void* data, int len)

Program the flash starting at addr with the data pointed to by data. len specifies number of bytes to program. Returns FLASH_ERR_OK if the operation succeeded, otherwise an error code describing the failure.

Some drivers may also include functionality to lock and unlock areas of the flash device. In that case, the CDL must include a

implements CYGHWR_IO_FLASH_BLOCK_LOCKING
statement. [FIXME: These functions do not have a consistent interface yet -- or is there a reason for one taking a single block and the other a range?]

int flash_lock_block(volatile void* block)

Locks the block specified. Returns FLASH_ERR_OK if the operation succeeded, otherwise an error code describing the failure.

int flash_unlock_block(volatile void* block, int block_size, int blocks)

Unlocks specified range of blocks. Returns FLASH_ERR_OK if the operation succeeded, otherwise an error code describing the failure.

Platform Specific Driver

The platform driver package must contain CDL in the following style:

cdl_package CYGPKG_DEVS_FLASH_MBX {
    display       "Motorola PowerPC/860 FLASH memory support"

    parent        CYGPKG_IO_FLASH
    active_if	  CYGPKG_IO_FLASH
    requires	  CYGPKG_HAL_POWERPC_MBX

    implements    CYGHWR_IO_FLASH_DEVICE

    compile       powerpc_mbx_flash.c

    # Arguably this should do in the generic package
    # but then there is a logic loop so you can never enable it.
    cdl_interface CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED {
        display   "Generic AMD AM29F040 driver required"
    }

    implements    CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED
    requires      CYGHWR_DEVS_FLASH_AMD_AM29F040B
}

It enables the generic driver by providing the interface option, and by the requires statement ensures that the driver includes the necessary device support. The compile statement identifies the file which, when built, includes the generic driver code.

The platform driver file itself is quite simple, as all it has to do is specify device parameters and include the generic driver:

//--------------------------------------------------------------------------
// Device properties

// We use the single AM29F040B on the MBX board.
#define CYGNUM_FLASH_INTERLEAVE	(1)
#define CYGNUM_FLASH_SERIES	(1)
#define CYGNUM_FLASH_WIDTH      (8)
#define CYGNUM_FLASH_BASE 	(0xfe000000u)

//--------------------------------------------------------------------------
// Platform specific extras

//--------------------------------------------------------------------------
// Now include the driver code.
#include "cyg/io/flash_am29xxxxx.inl"

The definitions have the following meaning:

CYGNUM_FLASH_INTERLEAVE

Defines how many devices are interleaved (sits in parallel) for this region of flash. The flash_data_t supports various configurations up to a max width of 64 bits.

CYGNUM_FLASH_SERIES

Defines how many number of devices are in series. The total number of devices is then defined as (CYGNUM_FLASH_INTERLEAVE x CYGNUM_FLASH_SERIES).

CYGNUM_FLASH_WIDTH

Defines the width of the devices. Some devices support being used in more than one width configuration (i.e., some 16 bit wide devices can be configured to only use the 8 lowest data bits).

CYGNUM_FLASH_BASE

Defines the address base of the flash region.