From 82525a756dbb42af35d4815e064254dc298ad3bc Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 22 Sep 2011 07:09:07 +0000 Subject: 2011-09-22 Sebastian Huber * 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. --- c/src/lib/libbsp/arm/lpc32xx/ChangeLog | 11 ++ c/src/lib/libbsp/arm/lpc32xx/include/boot.h | 4 + c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h | 1 + c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h | 98 ++++++++------- .../lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc | 2 +- c/src/lib/libbsp/arm/lpc32xx/misc/boot.c | 7 ++ .../arm/lpc32xx/misc/nand-mlc-erase-block-safe.c | 62 +++++++--- .../libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c | 2 +- .../arm/lpc32xx/misc/nand-mlc-write-blocks.c | 2 +- c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c | 132 +++++++++++++++------ 10 files changed, 222 insertions(+), 99 deletions(-) (limited to 'c') diff --git a/c/src/lib/libbsp/arm/lpc32xx/ChangeLog b/c/src/lib/libbsp/arm/lpc32xx/ChangeLog index d7817a353c..526811e9a6 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/ChangeLog +++ b/c/src/lib/libbsp/arm/lpc32xx/ChangeLog @@ -1,3 +1,14 @@ +2011-09-22 Sebastian Huber + + * 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 * misc/i2c.c: Bugfix. diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/boot.h b/c/src/lib/libbsp/arm/lpc32xx/include/boot.h index 3d11da47d1..1f841761a7 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/boot.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/boot.h @@ -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 diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h b/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h index 0d3bbbc974..b4ad928ca5 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h @@ -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; diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h b/c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h index f4512aba3b..61d035bb94 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h @@ -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; } /** @} */ diff --git a/c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc b/c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc index b79183ae9c..79fdd7ce68 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc +++ b/c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc @@ -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 diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/boot.c b/c/src/lib/libbsp/arm/lpc32xx/misc/boot.c index 0f624114f3..7cca65d39e 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/boot.c +++ b/c/src/lib/libbsp/arm/lpc32xx/misc/boot.c @@ -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; +} diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-erase-block-safe.c b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-erase-block-safe.c index 07820ebc67..425ed464ef 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-erase-block-safe.c +++ b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-erase-block-safe.c @@ -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; - } - - 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; + 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); + } } - return RTEMS_SUCCESSFUL; + return sc; } rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index) diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c index 7d00d0e52a..348b780d9c 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c +++ b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c @@ -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) { diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c index 4a2af491c1..b387888e11 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c +++ b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c @@ -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; diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c index 643987a52a..2e2982f250 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c +++ b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c @@ -7,12 +7,13 @@ */ /* - * Copyright (c) 2010 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * + * Copyright (c) 2010-2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * * * 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; -- cgit v1.2.3