| OVERVIEW |
| ======== |
| It is useful to be able to access partitions on block devices in a general |
| purpose fashion, however to do so can require device specific knowledge. For |
| example, some devices require erases before writes and some partitions need to |
| have the hardware in a different configuration (e.g. different forms of ECC |
| for different partitions stored in NAND). To allow such things to be handled |
| in a generic fashion, the following functions are provided: |
| |
| int get_partition_by_name(block_dev_desc_t *dev, const char *partition_name, |
| disk_partition_t *partition); |
| |
| int partition_erase_blks(block_dev_desc_t *dev, disk_partition_t *partition, |
| lbaint_t *blkcnt); |
| int partition_erase_bytes(block_dev_desc_t *dev, disk_partition_t *partition, |
| loff_t *bytecnt); |
| |
| int partition_read_blks(block_dev_desc_t *dev, disk_partition_t *partition, |
| lbaint_t *blkcnt, void *buffer); |
| int partition_read_bytes(block_dev_desc_t *dev, disk_partition_t *partition, |
| loff_t *bytecnt, void *buffer); |
| |
| int partition_write_blks(block_dev_desc_t *dev, disk_partition_t *partition, |
| lbaint_t *blkcnt, const void *buffer); |
| int partition_write_bytes(block_dev_desc_t *dev, disk_partition_t *partition, |
| loff_t *bytecnt, const void *buffer); |
| |
| An important note is that all of these functions round up the sizes that are |
| passed to them to the next logical boundary. |
| |
| Example 1: If you ask for a single byte to be read from a partition, |
| an entire block of data is going to be placed in the buffer. The |
| caller must ensure that enough space is available in the buffer to |
| prevent overflow. |
| |
| Example 2: For a NAND flash the size of a block for the partition |
| functions is equivalent to the size of the NAND's "write page". However, |
| the smallest unit that can be erased on a NAND is an "erase block" which |
| is made up of multiple "write pages". This means that if you use the |
| partition_erase_* functions to erase a single byte or a single block on a |
| NAND, it will round up to erasing an entire "erase block" which will be |
| multiple "write pages". |
| |
| PRE_ AND POST_ ENVIRONMENT VARIABLES |
| ==================================== |
| To accomplish the partition dependent configuration, these functions will use |
| environment variables to specify what commands need to be executed before and |
| after the operation is performed. The names of the environment variables that |
| will be used are of the form: |
| |
| <when>_<operation>.<partition_name> |
| |
| where: |
| |
| <when> is "pre" or "post" |
| <operation> is "erase", "read" or "write" |
| <partition_name> is the name of the partition that the commands apply to. |
| |
| As an example of using these, some boards use NAND memory but require |
| different ECC methods for different MTD partitions. Historically, these |
| partitions were written using something like the following sequence of |
| commands: |
| |
| nandecc hw |
| nand erase.part x-loader |
| nand write 0x80000000 x-loader # Write x-loader from memory at 0x80000000 |
| nandecc sw |
| |
| To use the partition functions for doing this, your board configuration should |
| include: |
| |
| "pre_write.xloader=nandecc hw\0post_write.xloader=nandecc sw\0" |
| |
| in the CONFIG_EXTRA_ENV_SETTINGS or else have executed the commands: |
| |
| setenv pre_write.x-loader nandecc hw |
| setenv post_write.x-loader nandecc sw |
| |
| With those environment variables set and using the blk command, you can simply |
| do: |
| |
| blk write 0x80000000 x-loader |
| |
| The blk write command will call partition_write_blks() which in turn takes |
| care of fetching the values of the environment variables, and if they are set, |
| executing them as U-Boot commands. In this case, that means that the NAND's |
| ECC will be set to use hardware ECC before the partition is written and then |
| set back to software ECC after the partition is written. |
| |
| |
| ERASE BEFORE WRITE |
| ================== |
| It should be noted that whether or not an erase is done before a write is |
| controlled by the C preprocessor define CONFIG_ERASE_PARTITION_ALWAYS. If it |
| is defined in the board configuration file, the following sequence will be |
| followed when a write is done: |
| |
| pre_write.<partition_name> commands |
| erase |
| write |
| post_write.<partition_name> commands |
| |
| Note that this means that if you need to set pre_erase and/or post_erase, |
| you'll probably need pre_write and post_write to contain those same commands. |
| |
| |
| CALLING BLOCK FUNCTIONS DIRECTLY |
| ================================ |
| |
| There are times where it is required to access portions of the partition |
| instead of reading or writing the entire partition. For example, a header |
| needs to be read to know how much of the partition needs to be read. To do |
| this, the code should use the block_read or block_write function pointers |
| within the struct block_dev_desc and wrap those with calls to execute the pre_ |
| and post_ environment variables. The following functions are provided for |
| that purpose: |
| |
| int partition_erase_pre(disk_partition_t *ptn); |
| int partition_erase_post(disk_partition_t *ptn); |
| int partition_read_pre(disk_partition_t *ptn); |
| int partition_read_post(disk_partition_t *ptn); |
| int partition_write_pre(disk_partition_t *ptn); |
| int partition_write_post(disk_partition_t *ptn); |