2011-07-01 Stephan Hoffmann <sho@reLinux.de>

Sebastian Huber <sebastian.huber@embedded-brains.de>

	* misc/nand-mlc-erase-block-safe.c: New file
	* Makefile.am: Reflect change from above.
	* misc/nand-mlc-write-blocks.c: Use lpc32xx_mlc_erase_block_safe_3().
	* include/nand-mlc.h: Bad block handling.
This commit is contained in:
Sebastian Huber
2011-07-01 13:05:06 +00:00
parent baa12f269c
commit 03d210895f
5 changed files with 174 additions and 73 deletions

View File

@@ -1,3 +1,11 @@
2011-07-01 Stephan Hoffmann <sho@reLinux.de>
Sebastian Huber <sebastian.huber@embedded-brains.de>
* misc/nand-mlc-erase-block-safe.c: New file
* Makefile.am: Reflect change from above.
* misc/nand-mlc-write-blocks.c: Use lpc32xx_mlc_erase_block_safe_3().
* include/nand-mlc.h: Bad block handling.
2011-06-19 Ralf Corsépius <ralf.corsepius@rtems.org>
* Makefile.am: Fix broken path to cache_.h.

View File

@@ -125,6 +125,7 @@ libbsp_a_SOURCES += misc/timer.c \
misc/nand-mlc.c \
misc/nand-mlc-read-blocks.c \
misc/nand-mlc-write-blocks.c \
misc/nand-mlc-erase-block-safe.c \
misc/restart.c \
misc/boot.c \
misc/emc.c \

View File

@@ -7,12 +7,15 @@
*/
/*
* Copyright (c) 2010
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (c) 2010-2011 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* Copyright (c) 2011 Stephan Hoffmann <sho@reLinux.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -165,6 +168,19 @@ extern "C" {
#define MLC_BAD_BLOCK_MASK ((uint32_t) 0xff00)
/**
* @brief Bad block mark.
*
* We define our own bad block mark to be able to recognize the blocks that
* have been marked bad during operation later.
*/
#define MLC_BAD_BLOCK_MARK ((uint32_t) 0xbadb)
/**
* @brief The bytes 4 and 5 are reserved for bad block handling.
*/
#define MLC_RESERVED ((uint32_t) 0xffff)
/**
* @name NAND Status Register
*
@@ -252,6 +268,32 @@ rtems_status_code lpc32xx_mlc_read_page(
*/
rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index);
/**
* @brief Erases the block with index @a block_index.
*
* In case of an erase error all pages and the spare areas of this block are
* programmed with zero values. This will mark the first and second page as
* bad.
*
* @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INCORRECT_STATE The first or second page of this block is bad.
* @retval RTEMS_INVALID_ID Invalid @a block_index value.
* @retval RTEMS_IO_ERROR Erase error.
*/
rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index);
/**
* @brief Erases the block with index @a block_index.
*
* Variant of lpc32xx_mlc_erase_block_safe() with more parameters for
* efficiency reasons.
*/
rtems_status_code lpc32xx_mlc_erase_block_safe_3(
uint32_t block_index,
uint32_t first_page_of_block,
uint32_t pages_per_block
);
/**
* @brief Writes the page with index @a page_index.
*
@@ -278,7 +320,7 @@ rtems_status_code lpc32xx_mlc_write_page_with_ecc(
*
* @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INVALID_ID Invalid @a block_begin or @a block_end value.
* @retval RTEMS_IO_ERROR To many bad blocks or source area to big.
* @retval RTEMS_IO_ERROR Too many bad blocks or source area too big.
*/
rtems_status_code lpc32xx_mlc_write_blocks(
uint32_t block_begin,
@@ -328,6 +370,16 @@ static inline bool lpc32xx_mlc_is_bad_page(const uint32_t *spare)
return (spare [1] & MLC_BAD_BLOCK_MASK) != MLC_BAD_BLOCK_MASK;
}
static inline void lpc32xx_mlc_set_bad_page(uint32_t *spare)
{
spare [1] = MLC_BAD_BLOCK_MARK;
}
static inline void lpc32xx_mlc_set_reserved(uint32_t *spare)
{
spare [1] = MLC_RESERVED;
}
/** @} */
#ifdef __cplusplus

View File

@@ -0,0 +1,94 @@
/**
* @file
*
* @ingroup lpc32xx_nand_mlc
*
* @brief lpc32xx_mlc_erase_block_safe() and lpc32xx_mlc_erase_block_safe_3()
* implementation.
*/
/*
* Copyright (c) 2011 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <bsp/nand-mlc.h>
#include <string.h>
#include <bsp.h>
static void zero_block(uint32_t first_page_of_block, uint32_t pages_per_block)
{
uint32_t page = 0;
for (page = 0; page < pages_per_block; ++page) {
lpc32xx_mlc_write_page_with_ecc(
first_page_of_block + page,
lpc32xx_magic_zero_begin,
lpc32xx_magic_zero_begin
);
}
}
static bool is_bad_page(
uint32_t first_page_of_block,
uint32_t page
)
{
uint32_t spare [MLC_LARGE_SPARE_WORD_COUNT];
memset(spare, 0, MLC_LARGE_SPARE_SIZE);
lpc32xx_mlc_read_page(
first_page_of_block + page,
lpc32xx_magic_zero_begin,
spare
);
return lpc32xx_mlc_is_bad_page(spare);
}
rtems_status_code lpc32xx_mlc_erase_block_safe_3(
uint32_t block_index,
uint32_t first_page_of_block,
uint32_t pages_per_block
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
if (is_bad_page(first_page_of_block, 0)) {
return RTEMS_INCORRECT_STATE;
}
if (is_bad_page(first_page_of_block, 1)) {
return RTEMS_INCORRECT_STATE;
}
sc = lpc32xx_mlc_erase_block(block_index);
if (sc != RTEMS_SUCCESSFUL) {
zero_block(first_page_of_block, pages_per_block);
return RTEMS_IO_ERROR;
}
return RTEMS_SUCCESSFUL;
}
rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index)
{
uint32_t pages_per_block = lpc32xx_mlc_pages_per_block();
return lpc32xx_mlc_erase_block_safe_3(
block_index,
block_index * pages_per_block,
pages_per_block
);
}

View File

@@ -7,12 +7,13 @@
*/
/*
* Copyright (c) 2010
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (c) 2010-2011 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -21,10 +22,6 @@
#include <bsp/nand-mlc.h>
#include <string.h>
#include <bsp.h>
static const uint32_t ones_spare [MLC_LARGE_SPARE_WORD_COUNT] = {
0xffffffff,
0xffffffff,
@@ -44,61 +41,6 @@ static const uint32_t ones_spare [MLC_LARGE_SPARE_WORD_COUNT] = {
0xffffffff
};
static void zero_block(uint32_t first_page_of_block, uint32_t pages_per_block)
{
uint32_t page = 0;
for (page = 0; page < pages_per_block; ++page) {
lpc32xx_mlc_write_page_with_ecc(
first_page_of_block + page,
lpc32xx_magic_zero_begin,
lpc32xx_magic_zero_begin
);
}
}
static bool is_bad_page(
uint32_t first_page_of_block,
uint32_t page
)
{
uint32_t spare [MLC_LARGE_SPARE_WORD_COUNT];
memset(spare, 0, MLC_LARGE_SPARE_SIZE);
lpc32xx_mlc_read_page(
first_page_of_block + page,
lpc32xx_magic_zero_begin,
spare
);
return lpc32xx_mlc_is_bad_page(spare);
}
static rtems_status_code erase_block(
uint32_t block,
uint32_t first_page_of_block,
uint32_t pages_per_block
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
if (is_bad_page(first_page_of_block, 0)) {
return RTEMS_IO_ERROR;
}
if (is_bad_page(first_page_of_block, 1)) {
return RTEMS_IO_ERROR;
}
sc = lpc32xx_mlc_erase_block(block);
if (sc != RTEMS_SUCCESSFUL) {
zero_block(first_page_of_block, pages_per_block);
return RTEMS_IO_ERROR;
}
return RTEMS_SUCCESSFUL;
}
rtems_status_code lpc32xx_mlc_write_blocks(
uint32_t block_begin,
uint32_t block_end,
@@ -124,7 +66,11 @@ rtems_status_code lpc32xx_mlc_write_blocks(
uint32_t first_page_of_block = block * pages_per_block;
uint32_t page = 0;
sc = erase_block(block, first_page_of_block, pages_per_block);
sc = lpc32xx_mlc_erase_block_safe_3(
block,
first_page_of_block,
pages_per_block
);
if (sc != RTEMS_SUCCESSFUL) {
continue;
}