forked from Imagelibrary/rtems
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:
@@ -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.
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user