nand: Write multiple copies of UBL and U-Boot

The NAND might have more bit flips than can be recovered. The way
to deal with it is to write multiple copies on multiple pages. The
probability of all pages failing depends on the specific NAND flash
used and was not calculated so far. The RBL is capable of trying to
load several copies and we should be more safe now.

This requires a new partioning inside the U-Boot or other bootloader.
This commit is contained in:
Holger Hans Peter Freyther 2014-05-19 08:20:46 +02:00
parent 1cfc889457
commit e564034a60
4 changed files with 42 additions and 22 deletions

4
nand.c
View File

@ -935,10 +935,10 @@ nand_write_prog(struct nand_image_descriptor_t *im_desc, const uint8_t *src,
uart_send_lf();
/* Check whether writing UBL or APP (based on destination block) */
if (im_desc->block_num == START_UBL_BLOCK_NUM)
if (im_desc->block_num <= END_UBL_BLOCK_NUM)
max_block_num = END_UBL_BLOCK_NUM;
else
max_block_num = nand_info.num_blocks - 1;
max_block_num = im_desc->block_num + MAX_BLOCK_PER_UBOOT - 1;
NAND_WRITE_RETRY:
if (im_desc->block_num > max_block_num) {

11
nand.h
View File

@ -27,10 +27,15 @@
#include "common.h"
#include "davinci.h"
/* Define which blocks are valid for writing UBL and APP data */
/* Define which blocks are valid for writing UBL data */
#define START_UBL_BLOCK_NUM 1
#define END_UBL_BLOCK_NUM (START_APP_BLOCK_NUM - 1)
#define START_APP_BLOCK_NUM ((nand_get_bytes_per_block() == 16384) ? 32 : 4)
#define END_UBL_BLOCK_NUM ((nand_get_bytes_per_block() == 16384) ? 32 : 5)
/* Define which blocks are valid for writing U-BOOT data */
/* NUTAQ: Adjust it according to your requirements */
#define START_UBOOT_BLOCK_NUM (END_UBL_BLOCK_NUM + 1)
#define MAX_BLOCK_PER_UBOOT 6
#define END_UBOOT_BLOCK_NUM 31
#define MAX_PAGE_SIZE (2048+64) /* Data bytes + spare area */

View File

@ -46,12 +46,14 @@ nand_copy(uint32_t *jump_entry_point)
struct nand_image_descriptor_t im_desc;
int last_header_block;
start_block = START_APP_BLOCK_NUM;
last_header_block = start_block + 10;
start_block = START_UBOOT_BLOCK_NUM;
last_header_block = END_UBOOT_BLOCK_NUM;
NAND_startAgain:
/* Read header about application starting at START_APP_BLOCK_NUM, Page 0
* and try 10 blocks. */
failedOnceAlready = false;
/* Read header about application starting at START_UBOOT_BLOCK_NUM, Page 0
* and try 50 blocks. */
for (count = start_block; count <= last_header_block; count++) {
if (nand_read_page(count, 0, nand_header) != E_PASS)
continue;
@ -79,6 +81,8 @@ NAND_startAgain:
uart_send_hexnum(im_desc.size_in_pages, 8);
uart_send_str(", Load = ");
uart_send_hexnum(im_desc.load_address, 8);
uart_send_str(", Block = ");
uart_send_hexnum(im_desc.block_num, 8);
uart_send_lf();
rxBuf = (uint8_t *) im_desc.load_address;

View File

@ -86,6 +86,8 @@ void
uart_boot(uint32_t *jump_entry_point)
{
#if defined(FLASH_TYPE_NAND)
int prog_ok = 0;
int block_num;
struct nand_image_descriptor_t im_desc;
#elif defined(FLASH_TYPE_NOR)
struct nor_boot_t norBoot;
@ -128,13 +130,16 @@ uart_boot(uint32_t *jump_entry_point)
NOR_WriteBytes(nor_get_flashbase(), uart_ack_header.size,
(uint32_t) uart_ack_header.recv_buffer);
#elif defined(FLASH_TYPE_NAND)
im_desc.magic = uart_ack_header.magic;
im_desc.entry_point = uart_ack_header.entry_point;
im_desc.block_num = START_UBL_BLOCK_NUM;
im_desc.load_address = 0; /* Load address not used by RBL */
for (block_num = START_UBL_BLOCK_NUM; block_num <= END_UBL_BLOCK_NUM; block_num++) {
im_desc.magic = uart_ack_header.magic;
im_desc.block_num = block_num;
im_desc.entry_point = uart_ack_header.entry_point;
im_desc.load_address = 0; /* Load address not used by RBL */
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer,
uart_ack_header.size) != E_PASS)
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer, uart_ack_header.size) == E_PASS)
prog_ok = 1;
}
if (!prog_ok)
goto uartboot_error;
#endif
@ -186,14 +191,20 @@ uart_boot(uint32_t *jump_entry_point)
uart_ack_header.entry_point) != E_PASS)
goto uartboot_error;
#elif defined(FLASH_TYPE_NAND)
im_desc.magic = uart_ack_header.magic;
im_desc.entry_point = uart_ack_header.entry_point;
im_desc.block_num = START_APP_BLOCK_NUM;
/* Assuming load address is identical to entry point. */
im_desc.load_address = uart_ack_header.entry_point;
/* Write multiple copy of U-Boot (depending on the defines in NAND.h) */
prog_ok = 0;
for (block_num = START_UBOOT_BLOCK_NUM; (block_num+MAX_BLOCK_PER_UBOOT-1) <= END_UBOOT_BLOCK_NUM; block_num += MAX_BLOCK_PER_UBOOT) {
im_desc.magic = uart_ack_header.magic;
im_desc.block_num = block_num;
im_desc.entry_point = uart_ack_header.entry_point;
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer,
uart_ack_header.size) != E_PASS)
/* Assuming load address is identical to entry point. */
im_desc.load_address = uart_ack_header.entry_point;
if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer, uart_ack_header.size) == E_PASS)
prog_ok = 1;
}
if (!prog_ok)
goto uartboot_error;
#endif