Name

CYGPKG_DEVS_FLASH_M68K_MCFxxxx_CFM — eCos Flash Driver for MCFxxxx CFM On-chip Flash

Description

Some members of the Freescale MCFxxxx family, for example the MCF5213, come with on-chip flash in the form of a ColdFire Flash Module or CFM. This package CYGPKG_DEVS_FLASH_M68K_MCFxxxx_CFM provides an eCos flash device driver for CFM hardware. Normally the driver is not accessed directly. Instead application code will use the API provided by the generic flash driver package CYGPKG_IO_FLASH, for example by calling functions like cyg_flash_program.

Configuration Options

The CFM flash driver package will be loaded automatically when configuring eCos for a target with suitable hardware. However the driver will be inactive unless the generic flash package CYGPKG_IO_FLASH is loaded. It may be necesary to add this generic package to the configuration explicitly before the driver functionality becomes available. There should never be any need to load or unload the CFM driver package.

The driver contains a small number of configuration options which application developers may wish to tweak.

Misaligned Writes

The CFM hardware only supports writes of a whole 32-bit integer at a time. For most applications this is not a problem and the driver imposes this restriction on higher-level code, so when calling cyg_flash_program the destination address must be on a 32-bit boundary and the length must be a multiple of four bytes. If this restriction is unacceptable then support for misaligned writes of arbitrary lengths can be enabled via configuration option CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_MISALIGNED_WRITES. The implementation involves reading in the existing flash contents and or'ing in the new data. The default behaviour is to leave this disabled since most applications do not require the functionality and it just adds to the code size.

Locking

CFM has a somewhat unusual approach to implementing lock and unlock support. The first 1K of on-chip flash is normally reserved for the M68K exception vectors, on the assumption that the processor will or may boot from here. This is immediately followed by a hal_mcfxxxx_cfm_security_settings data structure at offset 0x400. The structure has a 32-bit field cfm_prot which determines the initial locking status. The whole CFM flash array is split into 32 sectors. Each bit in cfm_prot determines the initial locked state of all blocks within that sector, with 1 for locked and 0 for unlocked. Locking and unlocking can only affect a whole sector at a time, not individual flash blocks (unless of course the flash is organized such that there exactly 32 flash blocks).

In typical usage the on-chip flash will be used for bootstrap and hence the security settings are part of the boot image. The default security settings are supplied by the processor or platform HAL and will be such that all flash sectors are unlocked. This is the most convenient setting when developing software. However an application can override this and thus lock part or all of the flash.

The driver provides two configuration options related to flash locking. CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_AUTO_UNLOCK causes all of flash to be unlocked automatically during driver initialization. This gives simple and deterministic behaviour irrespective of the current contents of the flash security settings structure. However it leaves the flash more vulnerable to accidental corruption by an errant application. CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_SUPPORT_LOCKING enables support for fine-grained locking using the generic functions cyg_flash_lock and cyg_flash_unlock. This provides more protection against errant applications, at the cost of increased application complexity.

RAM Functions and Interrupts

When performing a flash erase or program operation part or all of the flash may become inaccessible. The exact details of this vary between ColdFire processors. Obviously this means that the low-level functions which manipulate the flash cannot reside in the same area of flash as any blocks that may get erased or programmed. Worse, if an interrupt happens during an erase or program operation and the interrupt handler involves code or data in the same area of flash, or may cause a higher priority thread to wake up which accesses that area of flash, then the system is likely to fail. To avoid problems the flash driver takes two precautions by default:

  1. The low-level flash functions are located in RAM. If necessary they are copied from ROM from RAM during system initialization.
  2. The low-level flash functions disable interrupts around any code which may leave parts of the flash inaccessible.

This combination avoids problems but at the cost of increased RAM usage and often increased interrupt latency. In some circumstances these precautions are unnecessary. For example suppose there is 512K of flash split into two logical blocks of 256K each, such that an erase or program operation affects all of one logical block but not the other. If the application has been arranged such that all code and constant data resides in the bottom 256K and flash operations are only performed on the remaining 256K then there is no need to place the low-level flash functions in RAM. The configuration option CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_FUNCTIONS_IN_RAM can then be disabled. In a similar scenario, if the top 256K of flash are only ever accessed via the flash API then there is no need to disable interrupts: the generic flash layer ensures only one thread can perform flash operations on a given device via a mutex. The configuration option CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_LEAVE_INTERRUPTS_ENABLED can then be enabled.

Additional Functionality

The driver exports two functions which offer functionality not accessible via the standard flash API:

#include <cyg/io/mcfxxxx_cfm_dev.h>

externC void     cyg_mcfxxxx_cfm_unlockall(void);
externC cyg_bool cyg_mcfxxxx_cfm_is_locked(const cyg_flashaddr_t addr);

The first can be used to unlock all flash sectors, effectively bypassing any locking set by the hal_mcfxxxx_cfm_security_settings structure. The second can be used to query whether or not the block containing the specified address is currently locked. Both functions should be called only after flash has been initialized.

Instantiating a CFM Flash device

The CFM package only provides the device driver functions needed for manipulating CFM flash. It does not actually create a device instance. The amount of on-chip flash varies between ColdFire processors and the driver package does not maintain any central repository about the characteristics of each processor. Instead it is left to other code, usually the processor HAL, to instantiate the flash device. That makes it possible to add support for new processors simply by adding a new processor HAL, with no need to change the flash driver package.

The CFM package provides a utility macro for instantiating a device. Typical usage would be:

#include <cyg/io/mcfxxxx_cfm_dev.h>

CYG_MCFxxxx_CFM_INSTANCE(0x00000000, 0x0003FFFF, 2048);

The first two arguments specify the base and end address of the flash in the memory map. In this example there is 256K of flash mapped to location 0. Typically the base address is set via the FLASHBAR system register and the size is of course determined by the specific ColdFire processor being used. The final argument is the size of a flash block, in other words the unit of erase operations. This will have to obtained from the processor documentation.

The CYG_MCFxxxx_CFM_INSTANCE macro may instantiate a device with or without software locking support, as determined by the driver configuration option CYGIMP_DEVS_FLASH_M68K_MCFxxxx_CFM_SUPPORT_LOCKING .

If for some reason the CYG_MCFxxxx_CFM_INSTANCE is inappropriate for a specific processor then the mcfxxxx_cfm_dev.h header file exports all the device driver functions, so code can create a flash device instance explicitly.