forked from Imagelibrary/rtems
2011-09-22 Sebastian Huber <sebastian.huber@embedded-brains.de>
* make/custom/lpc32xx.inc: Workaround for GCC bug 50106. * include/lpc32xx.h: Fixed register map for NAND MLC. * include/boot.h: Declare lpc32xx_set_boot_block_bad(). * misc/boot.c: Define lpc32xx_set_boot_block_bad(). * include/nand-mlc.h, misc/nand-mlc-erase-block-safe.c, misc/nand-mlc-read-blocks.c, misc/nand-mlc-write-blocks.c, misc/nand-mlc.c: Changed bad block handling. Support for non-aligned data. Documentation.
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
2011-09-22 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
||||
|
||||
* make/custom/lpc32xx.inc: Workaround for GCC bug 50106.
|
||||
* include/lpc32xx.h: Fixed register map for NAND MLC.
|
||||
* include/boot.h: Declare lpc32xx_set_boot_block_bad().
|
||||
* misc/boot.c: Define lpc32xx_set_boot_block_bad().
|
||||
* include/nand-mlc.h, misc/nand-mlc-erase-block-safe.c,
|
||||
misc/nand-mlc-read-blocks.c, misc/nand-mlc-write-blocks.c,
|
||||
misc/nand-mlc.c: Changed bad block handling. Support for non-aligned
|
||||
data. Documentation.
|
||||
|
||||
2011-08-08 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
||||
|
||||
* misc/i2c.c: Bugfix.
|
||||
|
||||
@@ -101,6 +101,10 @@ void lpc32xx_setup_boot_block(
|
||||
uint8_t page_count
|
||||
);
|
||||
|
||||
void lpc32xx_set_boot_block_bad(
|
||||
lpc32xx_boot_block *boot_block
|
||||
);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -526,6 +526,7 @@ typedef struct {
|
||||
uint32_t time;
|
||||
uint32_t irq_mr;
|
||||
uint32_t irq_sr;
|
||||
uint32_t reserved_2;
|
||||
uint32_t lock_pr;
|
||||
uint32_t isr;
|
||||
uint32_t ceh;
|
||||
|
||||
@@ -74,6 +74,8 @@ extern "C" {
|
||||
#define MLC_SMALL_PAGE_SIZE 528
|
||||
#define MLC_SMALL_DATA_SIZE 512
|
||||
#define MLC_SMALL_SPARE_SIZE 16
|
||||
#define MLC_SMALL_USER_SPARE_SIZE 6
|
||||
#define MLC_SMALL_ECC_SPARE_SIZE 10
|
||||
#define MLC_SMALL_DATA_WORD_COUNT (MLC_SMALL_DATA_SIZE / 4)
|
||||
#define MLC_SMALL_SPARE_WORD_COUNT (MLC_SMALL_SPARE_SIZE / 4)
|
||||
#define MLC_SMALL_PAGES_PER_LARGE_PAGE 4
|
||||
@@ -136,6 +138,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
#define MLC_ISR_DECODER_FAILURE BSP_BIT32(6)
|
||||
#define MLC_ISR_SYMBOL_ERRORS(reg) BSP_FLD32GET(reg, 4, 5)
|
||||
#define MLC_ISR_ERRORS_DETECTED BSP_BIT32(3)
|
||||
#define MLC_ISR_ECC_READY BSP_BIT32(2)
|
||||
#define MLC_ISR_CONTROLLER_READY BSP_BIT32(1)
|
||||
@@ -166,21 +169,6 @@ 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
|
||||
*
|
||||
@@ -209,21 +197,28 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* @brief Selects small pages (512 Bytes user data and 16 Bytes spare data)
|
||||
* or large pages (2048 Bytes user data and 64 Bytes spare data).
|
||||
* or large pages (2048 Bytes user data and 64 Bytes spare data) if not set.
|
||||
*/
|
||||
#define MLC_SMALL_PAGES 0x1U
|
||||
|
||||
/**
|
||||
* @Brief Selects 3/4 address cycles for small pages/large pages or 4/5
|
||||
* address cycles.
|
||||
* @Brief Selects 4/5 address cycles for small/large pages or 3/4 address
|
||||
* cycles if not set.
|
||||
*/
|
||||
#define MLC_MANY_ADDRESS_CYCLES 0x2U
|
||||
|
||||
/**
|
||||
* @brief Selects 64 or 128 pages per block in case of large pages.
|
||||
* @brief Selects 64 pages per block or 128 pages per block if not set.
|
||||
*
|
||||
* This flag is only valid for large pages.
|
||||
*/
|
||||
#define MLC_NORMAL_BLOCKS 0x4U
|
||||
|
||||
/**
|
||||
* @brief Selects 16-bit IO width or 8-bit IO width if not set.
|
||||
*/
|
||||
#define MLC_IO_WIDTH_16_BIT 0x8U
|
||||
|
||||
/**
|
||||
* @brief Initializes the MLC NAND controller according to @a cfg.
|
||||
*/
|
||||
@@ -235,6 +230,8 @@ uint32_t lpc32xx_mlc_pages_per_block(void);
|
||||
|
||||
uint32_t lpc32xx_mlc_block_count(void);
|
||||
|
||||
uint32_t lpc32xx_mlc_io_width(void);
|
||||
|
||||
void lpc32xx_mlc_write_protection(
|
||||
uint32_t page_index_low,
|
||||
uint32_t page_index_high
|
||||
@@ -245,9 +242,11 @@ void lpc32xx_mlc_read_id(uint8_t *id, size_t n);
|
||||
/**
|
||||
* @brief Reads the page with index @a page_index.
|
||||
*
|
||||
* 32-bit reads will be performed.
|
||||
* Bytes 6 to 15 of the spare area will contain the ECC.
|
||||
*
|
||||
* Bytes 7 to 15 of the spare area will contain the ECC.
|
||||
* If the read is successful, then the @a symbol_error_count will contain the
|
||||
* number of detected symbol errors (0, 1, 2, 3, or 4), else the value will be
|
||||
* 0xffffffff. The @a symbol_error_count pointer may be @c NULL.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INVALID_ID Invalid @a page_index value.
|
||||
@@ -255,16 +254,35 @@ void lpc32xx_mlc_read_id(uint8_t *id, size_t n);
|
||||
*/
|
||||
rtems_status_code lpc32xx_mlc_read_page(
|
||||
uint32_t page_index,
|
||||
uint32_t *data,
|
||||
uint32_t *spare
|
||||
void *data,
|
||||
void *spare,
|
||||
uint32_t *symbol_error_count
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Checks if the block with index @a block_index is valid.
|
||||
*
|
||||
* The initial valid block information of the manufacturer will be used.
|
||||
* Unfortunatly there seems to be no standard for this. A block will be
|
||||
* considered as bad if the first or second page of this block does not contain
|
||||
* 0xff at the 6th byte of the spare area. This should work for flashes with
|
||||
* small pages and a 8-bit IO width.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL The block is valid.
|
||||
* @retval RTEMS_INVALID_ID Invalid @a block_index value.
|
||||
* @retval RTEMS_IO_ERROR Uncorrectable bit error.
|
||||
* @retval RTEMS_INCORRECT_STATE The block is bad.
|
||||
* @retval RTEMS_NOT_IMPLEMENTED No implementation available for this flash
|
||||
* type.
|
||||
*/
|
||||
rtems_status_code lpc32xx_mlc_is_valid_block(uint32_t block_index);
|
||||
|
||||
/**
|
||||
* @brief Erases the block with index @a block_index.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INVALID_ID Invalid @a block_index value.
|
||||
* @retval RTEMS_IO_ERROR Erase error.
|
||||
* @retval RTEMS_UNSATISFIED Erase error.
|
||||
*/
|
||||
rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index);
|
||||
|
||||
@@ -272,13 +290,14 @@ 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.
|
||||
* programmed with zero values. This will hopefully mark the block as bad.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INCORRECT_STATE The first or second page of this block is bad.
|
||||
* @retval RTEMS_INCORRECT_STATE The block is bad.
|
||||
* @retval RTEMS_INVALID_ID Invalid @a block_index value.
|
||||
* @retval RTEMS_IO_ERROR Erase error.
|
||||
* @retval RTEMS_UNSATISFIED Erase error.
|
||||
* @retval RTEMS_NOT_IMPLEMENTED No implementation available for this flash
|
||||
* type.
|
||||
*/
|
||||
rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index);
|
||||
|
||||
@@ -307,10 +326,8 @@ void lpc32xx_mlc_zero_pages(uint32_t page_begin, uint32_t page_end);
|
||||
/**
|
||||
* @brief Writes the page with index @a page_index.
|
||||
*
|
||||
* 32-bit writes will be performed.
|
||||
*
|
||||
* Bytes 7 to 15 of the spare area will be used for the automatically generated
|
||||
* ECC.
|
||||
* Only the bytes 0 to 5 of the spare area can be used for user data, the bytes
|
||||
* 6 to 15 will be used for the automatically generated ECC.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INVALID_ID Invalid @a page_index value.
|
||||
@@ -318,8 +335,8 @@ void lpc32xx_mlc_zero_pages(uint32_t page_begin, uint32_t page_end);
|
||||
*/
|
||||
rtems_status_code lpc32xx_mlc_write_page_with_ecc(
|
||||
uint32_t page_index,
|
||||
const uint32_t *data,
|
||||
const uint32_t *spare
|
||||
const void *data,
|
||||
const void *spare
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -377,17 +394,8 @@ rtems_status_code lpc32xx_mlc_read_blocks(
|
||||
|
||||
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;
|
||||
uint32_t valid_block_mask = 0xff00;
|
||||
return (spare [1] & valid_block_mask) != valid_block_mask;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -11,4 +11,4 @@ RTEMS_CPU = arm
|
||||
CPU_CFLAGS = -mstructure-size-boundary=8 -mcpu=arm926ej-s -mfpu=vfp -mfloat-abi=soft -mthumb \
|
||||
-fno-schedule-insns2
|
||||
|
||||
CFLAGS_OPTIMIZE_V = -Os -g
|
||||
CFLAGS_OPTIMIZE_V = -O2 -g
|
||||
|
||||
@@ -52,3 +52,10 @@ void lpc32xx_setup_boot_block(
|
||||
|
||||
boot_block->field.d12 = 0xaa;
|
||||
}
|
||||
|
||||
void lpc32xx_set_boot_block_bad(
|
||||
lpc32xx_boot_block *boot_block
|
||||
)
|
||||
{
|
||||
boot_block->field.d12 = 0;
|
||||
}
|
||||
|
||||
@@ -40,20 +40,53 @@ void lpc32xx_mlc_zero_pages(uint32_t page_begin, uint32_t page_end)
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_bad_page(
|
||||
static rtems_status_code is_valid_page(
|
||||
uint32_t page_begin,
|
||||
uint32_t page_offset
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
uint32_t spare [MLC_LARGE_SPARE_WORD_COUNT];
|
||||
|
||||
memset(spare, 0, MLC_LARGE_SPARE_SIZE);
|
||||
lpc32xx_mlc_read_page(
|
||||
|
||||
sc = lpc32xx_mlc_read_page(
|
||||
page_begin + page_offset,
|
||||
lpc32xx_magic_zero_begin,
|
||||
spare
|
||||
spare,
|
||||
NULL
|
||||
);
|
||||
return lpc32xx_mlc_is_bad_page(spare);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
if (lpc32xx_mlc_is_bad_page(spare)) {
|
||||
sc = RTEMS_INCORRECT_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
static rtems_status_code is_valid_block(uint32_t page_begin)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
|
||||
if (lpc32xx_mlc_page_size() == 512 && lpc32xx_mlc_io_width() == 8) {
|
||||
sc = is_valid_page(page_begin, 0);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
sc = is_valid_page(page_begin, 1);
|
||||
}
|
||||
} else {
|
||||
sc = RTEMS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code lpc32xx_mlc_is_valid_block(uint32_t block_index)
|
||||
{
|
||||
uint32_t pages_per_block = lpc32xx_mlc_pages_per_block();
|
||||
uint32_t page_begin = block_index * pages_per_block;
|
||||
|
||||
return is_valid_block(page_begin);
|
||||
}
|
||||
|
||||
rtems_status_code lpc32xx_mlc_erase_block_safe_3(
|
||||
@@ -64,22 +97,15 @@ rtems_status_code lpc32xx_mlc_erase_block_safe_3(
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
|
||||
if (is_bad_page(page_begin, 0)) {
|
||||
return RTEMS_INCORRECT_STATE;
|
||||
sc = is_valid_block(page_begin);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
sc = lpc32xx_mlc_erase_block(block_index);
|
||||
if (sc == RTEMS_UNSATISFIED) {
|
||||
lpc32xx_mlc_zero_pages(page_begin, page_end);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_bad_page(page_begin, 1)) {
|
||||
return RTEMS_INCORRECT_STATE;
|
||||
}
|
||||
|
||||
sc = lpc32xx_mlc_erase_block(block_index);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
lpc32xx_mlc_zero_pages(page_begin, page_end);
|
||||
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index)
|
||||
|
||||
@@ -36,7 +36,7 @@ static rtems_status_code read_page(
|
||||
memset(page_spare, 0, MLC_LARGE_SPARE_SIZE);
|
||||
}
|
||||
|
||||
sc = lpc32xx_mlc_read_page(page_index, page_data, page_spare);
|
||||
sc = lpc32xx_mlc_read_page(page_index, page_data, page_spare, NULL);
|
||||
if (possible_bad_page && lpc32xx_mlc_is_bad_page(page_spare)) {
|
||||
return RTEMS_UNSATISFIED;
|
||||
} else if (sc == RTEMS_SUCCESSFUL) {
|
||||
|
||||
@@ -84,7 +84,7 @@ rtems_status_code lpc32xx_mlc_write_blocks(
|
||||
ones_spare
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
lpc32xx_mlc_erase_block_safe_3(block, page_begin, page_end);
|
||||
lpc32xx_mlc_erase_block(block);
|
||||
lpc32xx_mlc_zero_pages(page_begin, page_end);
|
||||
current = last;
|
||||
continue;
|
||||
|
||||
@@ -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
|
||||
@@ -72,6 +73,15 @@ uint32_t lpc32xx_mlc_block_count(void)
|
||||
return mlc_block_count;
|
||||
}
|
||||
|
||||
uint32_t lpc32xx_mlc_io_width(void)
|
||||
{
|
||||
if ((mlc_flags & MLC_IO_WIDTH_16_BIT) == 0) {
|
||||
return 8;
|
||||
} else {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
static void mlc_unlock(void)
|
||||
{
|
||||
mlc->lock_pr = MLC_UNLOCK_PROT;
|
||||
@@ -193,10 +203,16 @@ void lpc32xx_mlc_write_protection(
|
||||
mlc->icr |= MLC_ICR_SOFT_WRITE_PROT;
|
||||
}
|
||||
|
||||
bool is_word_aligned(const void *data, const void *spare)
|
||||
{
|
||||
return (((uintptr_t) data) | ((uintptr_t) spare)) % 4 == 0;
|
||||
}
|
||||
|
||||
rtems_status_code lpc32xx_mlc_read_page(
|
||||
uint32_t page_index,
|
||||
uint32_t *data,
|
||||
uint32_t *spare
|
||||
void *data,
|
||||
void *spare,
|
||||
uint32_t *symbol_error_count_ptr
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
@@ -204,6 +220,10 @@ rtems_status_code lpc32xx_mlc_read_page(
|
||||
size_t sp = 0;
|
||||
size_t i = 0;
|
||||
uint32_t isr = 0;
|
||||
uint32_t symbol_error_count = 0xffffffff;
|
||||
bool aligned = is_word_aligned(data, spare);
|
||||
uint8_t *current_data = data;
|
||||
uint8_t *current_spare = spare;
|
||||
|
||||
if (page_index >= mlc_page_count) {
|
||||
return RTEMS_INVALID_ID;
|
||||
@@ -218,35 +238,65 @@ rtems_status_code lpc32xx_mlc_read_page(
|
||||
mlc_wait(MLC_ISR_NAND_READY);
|
||||
|
||||
for (sp = 0; sc == RTEMS_SUCCESSFUL && sp < small_pages_count; ++sp) {
|
||||
uint32_t *aligned_data = (uint32_t *) current_data;
|
||||
uint32_t *aligned_spare = (uint32_t *) current_spare;
|
||||
|
||||
mlc->ecc_dec = 0;
|
||||
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
data [i] = mlc->data.w32;
|
||||
}
|
||||
for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
|
||||
spare [i] = mlc->data.w32;
|
||||
if (aligned) {
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
aligned_data [i] = mlc->data.w32;
|
||||
}
|
||||
for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
|
||||
aligned_spare [i] = mlc->data.w32;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
|
||||
current_data [i] = mlc->data.w8;
|
||||
}
|
||||
for (i = 0; i < MLC_SMALL_SPARE_SIZE; ++i) {
|
||||
current_spare [i] = mlc->data.w8;
|
||||
}
|
||||
}
|
||||
|
||||
mlc_wait(MLC_ISR_ECC_READY);
|
||||
|
||||
isr = mlc->isr;
|
||||
if ((isr & MLC_ISR_ERRORS_DETECTED) != 0) {
|
||||
if ((isr & MLC_ISR_ERRORS_DETECTED) == 0) {
|
||||
symbol_error_count = 0;
|
||||
} else {
|
||||
if ((isr & MLC_ISR_DECODER_FAILURE) == 0) {
|
||||
mlc->rubp = 0;
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
data [i] = mlc->buff.w32;
|
||||
}
|
||||
mlc->robp = 0;
|
||||
for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
|
||||
spare [i] = mlc->buff.w32;
|
||||
symbol_error_count = MLC_ISR_SYMBOL_ERRORS(isr);
|
||||
if (aligned) {
|
||||
mlc->rubp = 0;
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
aligned_data [i] = mlc->buff.w32;
|
||||
}
|
||||
mlc->robp = 0;
|
||||
for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
|
||||
aligned_spare [i] = mlc->buff.w32;
|
||||
}
|
||||
} else {
|
||||
mlc->rubp = 0;
|
||||
for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
|
||||
current_data [i] = mlc->buff.w8;
|
||||
}
|
||||
mlc->robp = 0;
|
||||
for (i = 0; i < MLC_SMALL_SPARE_SIZE; ++i) {
|
||||
current_spare [i] = mlc->buff.w8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sc = RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
data += MLC_SMALL_DATA_WORD_COUNT;
|
||||
spare += MLC_SMALL_SPARE_WORD_COUNT;
|
||||
current_data += MLC_SMALL_DATA_SIZE;
|
||||
current_spare += MLC_SMALL_SPARE_SIZE;
|
||||
}
|
||||
|
||||
if (symbol_error_count_ptr != NULL) {
|
||||
*symbol_error_count_ptr = symbol_error_count;
|
||||
}
|
||||
|
||||
return sc;
|
||||
@@ -268,7 +318,7 @@ void lpc32xx_mlc_read_id(uint8_t *id, size_t n)
|
||||
|
||||
rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
rtems_status_code sc = RTEMS_UNSATISFIED;
|
||||
|
||||
if (block_index >= mlc_block_count) {
|
||||
return RTEMS_INVALID_ID;
|
||||
@@ -288,14 +338,18 @@ rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index)
|
||||
|
||||
rtems_status_code lpc32xx_mlc_write_page_with_ecc(
|
||||
uint32_t page_index,
|
||||
const uint32_t *data,
|
||||
const uint32_t *spare
|
||||
const void *data,
|
||||
const void *spare
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
size_t small_pages_count = mlc_small_pages() ? 1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
|
||||
size_t small_pages_count = mlc_small_pages() ?
|
||||
1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
|
||||
size_t sp = 0;
|
||||
size_t i = 0;
|
||||
bool aligned = is_word_aligned(data, spare);
|
||||
const uint8_t *current_data = data;
|
||||
const uint8_t *current_spare = spare;
|
||||
|
||||
if (page_index >= mlc_page_count) {
|
||||
return RTEMS_INVALID_ID;
|
||||
@@ -308,17 +362,29 @@ rtems_status_code lpc32xx_mlc_write_page_with_ecc(
|
||||
for (sp = 0; sp < small_pages_count; ++sp) {
|
||||
mlc->ecc_enc = 0;
|
||||
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
mlc->data.w32 = data [i];
|
||||
if (aligned) {
|
||||
const uint32_t *aligned_data = (const uint32_t *) current_data;
|
||||
const uint32_t *aligned_spare = (const uint32_t *) current_spare;
|
||||
|
||||
for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
|
||||
mlc->data.w32 = aligned_data [i];
|
||||
}
|
||||
mlc->data.w32 = aligned_spare [0];
|
||||
mlc->data.w16 = (uint16_t) aligned_spare [1];
|
||||
} else {
|
||||
for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
|
||||
mlc->data.w8 = current_data [i];
|
||||
}
|
||||
for (i = 0; i < MLC_SMALL_USER_SPARE_SIZE; ++i) {
|
||||
mlc->data.w8 = current_spare [i];
|
||||
}
|
||||
}
|
||||
mlc->data.w32 = spare [0];
|
||||
mlc->data.w16 = (uint16_t) spare [1];
|
||||
mlc->wpr = 0;
|
||||
|
||||
mlc_wait(MLC_ISR_CONTROLLER_READY);
|
||||
|
||||
data += MLC_SMALL_DATA_WORD_COUNT;
|
||||
spare += MLC_SMALL_SPARE_WORD_COUNT;
|
||||
current_data += MLC_SMALL_DATA_SIZE;
|
||||
current_spare += MLC_SMALL_SPARE_SIZE;
|
||||
}
|
||||
|
||||
mlc->cmd = 0x10;
|
||||
|
||||
Reference in New Issue
Block a user