diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c')
-rw-r--r-- | c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c b/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c deleted file mode 100644 index f87c59b133..0000000000 --- a/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c +++ /dev/null @@ -1,397 +0,0 @@ -/** - * @file - * - * @ingroup lpc32xx_nand_mlc - * - * @brief NAND MLC controller implementation. - */ - -/* - * 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 - * http://www.rtems.org/license/LICENSE. - */ - -#include <bsp/lpc32xx.h> -#include <bsp/nand-mlc.h> - -static volatile lpc32xx_nand_mlc *const mlc = &lpc32xx.nand_mlc; - -static uint32_t mlc_flags; - -static uint32_t mlc_block_count; - -static uint32_t mlc_page_count; - -static bool mlc_small_pages(void) -{ - return (mlc_flags & MLC_SMALL_PAGES) != 0; -} - -static bool mlc_many_address_cycles(void) -{ - return (mlc_flags & MLC_MANY_ADDRESS_CYCLES) != 0; -} - -static bool mlc_normal_blocks(void) -{ - return (mlc_flags & MLC_NORMAL_BLOCKS) != 0; -} - -uint32_t lpc32xx_mlc_page_size(void) -{ - if (mlc_small_pages()) { - return 512; - } else { - return 2048; - } -} - -uint32_t lpc32xx_mlc_pages_per_block(void) -{ - if (mlc_small_pages()) { - return 32; - } else { - if (mlc_normal_blocks()) { - return 64; - } else { - return 128; - } - } -} - -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; -} - -static void mlc_wait(uint32_t flags) -{ - while ((mlc->isr & flags) != flags) { - /* Wait */ - } -} - -static void mlc_wait_until_ready(void) -{ - mlc_wait(MLC_ISR_CONTROLLER_READY | MLC_ISR_NAND_READY); -} - -static void mlc_reset(void) -{ - mlc->cmd = 0xff; -} - -static uint32_t mlc_status(void) -{ - mlc_wait_until_ready(); - mlc->cmd = 0x70; - - return mlc->data.w8; -} - -static bool mlc_was_operation_successful(void) -{ - return (mlc_status() & (NAND_STATUS_READY | NAND_STATUS_ERROR)) - == NAND_STATUS_READY; -} - -static void mlc_set_block_address(uint32_t block_index) -{ - if (mlc_small_pages()) { - mlc->addr = (uint8_t) (block_index << 5); - mlc->addr = (uint8_t) (block_index >> 3); - if (mlc_many_address_cycles()) { - mlc->addr = (uint8_t) (block_index >> 11); - } - } else { - if (mlc_normal_blocks()) { - mlc->addr = (uint8_t) (block_index << 6); - mlc->addr = (uint8_t) (block_index >> 2); - if (mlc_many_address_cycles()) { - mlc->addr = (uint8_t) (block_index >> 10); - } - } else { - mlc->addr = (uint8_t) (block_index << 7); - mlc->addr = (uint8_t) (block_index >> 1); - if (mlc_many_address_cycles()) { - mlc->addr = (uint8_t) (block_index >> 9); - } - } - } -} - -static void mlc_set_page_address(uint32_t page_index) -{ - mlc->addr = 0; - if (mlc_small_pages()) { - mlc->addr = (uint8_t) page_index; - mlc->addr = (uint8_t) (page_index >> 8); - if (mlc_many_address_cycles()) { - mlc->addr = (uint8_t) (page_index >> 16); - } - } else { - mlc->addr = 0; - mlc->addr = (uint8_t) page_index; - mlc->addr = (uint8_t) (page_index >> 8); - if (mlc_many_address_cycles()) { - mlc->addr = (uint8_t) (page_index >> 16); - } - } -} - -void lpc32xx_mlc_init(const lpc32xx_mlc_config *cfg) -{ - uint32_t icr = 0; - - mlc_flags = cfg->flags; - mlc_block_count = cfg->block_count; - mlc_page_count = cfg->block_count * lpc32xx_mlc_pages_per_block(); - - /* Clock */ - LPC32XX_FLASHCLK_CTRL = FLASHCLK_IRQ_MLC | FLASHCLK_MLC_CLK_ENABLE; - - /* Timing settings */ - mlc_unlock(); - mlc->time = cfg->time; - - /* Configuration */ - if (!mlc_small_pages()) { - icr |= MLC_ICR_LARGE_PAGES; - } - if (mlc_many_address_cycles()) { - icr |= MLC_ICR_ADDR_WORD_COUNT_4_5; - } - mlc_unlock(); - mlc->icr = icr; - - mlc_reset(); -} - -void lpc32xx_mlc_write_protection( - uint32_t page_index_low, - uint32_t page_index_high -) -{ - mlc_unlock(); - mlc->sw_wp_add_low = page_index_low; - mlc_unlock(); - mlc->sw_wp_add_hig = page_index_high; - mlc_unlock(); - mlc->icr |= MLC_ICR_SOFT_WRITE_PROT; -} - -static 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, - void *data, - void *spare, - uint32_t *symbol_error_count_ptr -) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - size_t small_pages_count = mlc_small_pages() ? 1 : MLC_SMALL_PAGES_PER_LARGE_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; - } - - mlc_wait_until_ready(); - mlc->cmd = 0x00; - if (!mlc_small_pages()) { - mlc->cmd = 0x30; - } - mlc_set_page_address(page_index); - 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; - - 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) { - symbol_error_count = 0; - } else { - if ((isr & MLC_ISR_DECODER_FAILURE) == 0) { - 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; - } - } - - 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; -} - -void lpc32xx_mlc_read_id(uint8_t *id, size_t n) -{ - size_t i = 0; - - mlc_wait_until_ready(); - mlc->cmd = 0x90; - mlc->addr = 0; - mlc_wait(MLC_ISR_NAND_READY); - - for (i = 0; i < n; ++i) { - id [i] = mlc->data.w8; - } -} - -rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index) -{ - rtems_status_code sc = RTEMS_UNSATISFIED; - - if (block_index >= mlc_block_count) { - return RTEMS_INVALID_ID; - } - - mlc_wait_until_ready(); - mlc->cmd = 0x60; - mlc_set_block_address(block_index); - mlc->cmd = 0xd0; - - if (mlc_was_operation_successful()) { - sc = RTEMS_SUCCESSFUL; - } - - return sc; -} - -rtems_status_code lpc32xx_mlc_write_page_with_ecc( - uint32_t page_index, - 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 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; - } - - mlc_wait_until_ready(); - mlc->cmd = 0x80; - mlc_set_page_address(page_index); - - for (sp = 0; sp < small_pages_count; ++sp) { - mlc->ecc_enc = 0; - - 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->wpr = 0; - - mlc_wait(MLC_ISR_CONTROLLER_READY); - - current_data += MLC_SMALL_DATA_SIZE; - current_spare += MLC_SMALL_SPARE_SIZE; - } - - mlc->cmd = 0x10; - - if (mlc_was_operation_successful()) { - sc = RTEMS_SUCCESSFUL; - } - - return sc; -} |