Changeset 82525a75 in rtems


Ignore:
Timestamp:
Sep 22, 2011, 7:09:07 AM (9 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, 5, master
Children:
f40139b
Parents:
74416035
Message:

2011-09-22 Sebastian Huber <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.
Location:
c/src/lib/libbsp/arm/lpc32xx
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/arm/lpc32xx/ChangeLog

    r74416035 r82525a75  
     12011-09-22      Sebastian Huber <sebastian.huber@embedded-brains.de>
     2
     3        * make/custom/lpc32xx.inc: Workaround for GCC bug 50106.
     4        * include/lpc32xx.h: Fixed register map for NAND MLC.
     5        * include/boot.h: Declare lpc32xx_set_boot_block_bad().
     6        * misc/boot.c: Define lpc32xx_set_boot_block_bad().
     7        * include/nand-mlc.h, misc/nand-mlc-erase-block-safe.c,
     8        misc/nand-mlc-read-blocks.c, misc/nand-mlc-write-blocks.c,
     9        misc/nand-mlc.c: Changed bad block handling.  Support for non-aligned
     10        data.  Documentation.
     11
    1122011-08-08      Sebastian Huber <sebastian.huber@embedded-brains.de>
    213
  • c/src/lib/libbsp/arm/lpc32xx/include/boot.h

    r74416035 r82525a75  
    102102);
    103103
     104void lpc32xx_set_boot_block_bad(
     105  lpc32xx_boot_block *boot_block
     106);
     107
    104108/** @} */
    105109
  • c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h

    r74416035 r82525a75  
    527527  uint32_t irq_mr;
    528528  uint32_t irq_sr;
     529  uint32_t reserved_2;
    529530  uint32_t lock_pr;
    530531  uint32_t isr;
  • c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h

    r74416035 r82525a75  
    7575#define MLC_SMALL_DATA_SIZE 512
    7676#define MLC_SMALL_SPARE_SIZE 16
     77#define MLC_SMALL_USER_SPARE_SIZE 6
     78#define MLC_SMALL_ECC_SPARE_SIZE 10
    7779#define MLC_SMALL_DATA_WORD_COUNT (MLC_SMALL_DATA_SIZE / 4)
    7880#define MLC_SMALL_SPARE_WORD_COUNT (MLC_SMALL_SPARE_SIZE / 4)
     
    137139
    138140#define MLC_ISR_DECODER_FAILURE BSP_BIT32(6)
     141#define MLC_ISR_SYMBOL_ERRORS(reg) BSP_FLD32GET(reg, 4, 5)
    139142#define MLC_ISR_ERRORS_DETECTED BSP_BIT32(3)
    140143#define MLC_ISR_ECC_READY BSP_BIT32(2)
     
    166169
    167170/** @} */
    168 
    169 #define MLC_BAD_BLOCK_MASK ((uint32_t) 0xff00)
    170 
    171 /**
    172  * @brief Bad block mark.
    173  *
    174  * We define our own bad block mark to be able to recognize the blocks that
    175  * have been marked bad during operation later.
    176  */
    177 #define MLC_BAD_BLOCK_MARK ((uint32_t) 0xbadb)
    178 
    179 /**
    180  * @brief The bytes 4 and 5 are reserved for bad block handling.
    181  */
    182 #define MLC_RESERVED ((uint32_t) 0xffff)
    183171
    184172/**
     
    210198/**
    211199 * @brief Selects small pages (512 Bytes user data and 16 Bytes spare data)
    212  * or large pages (2048 Bytes user data and 64 Bytes spare data).
     200 * or large pages (2048 Bytes user data and 64 Bytes spare data) if not set.
    213201 */
    214202#define MLC_SMALL_PAGES 0x1U
    215203
    216204/**
    217  * @Brief Selects 3/4 address cycles for small pages/large pages or 4/5
    218  * address cycles.
     205 * @Brief Selects 4/5 address cycles for small/large pages or 3/4 address
     206 * cycles if not set.
    219207 */
    220208#define MLC_MANY_ADDRESS_CYCLES 0x2U
    221209
    222210/**
    223  * @brief Selects 64 or 128 pages per block in case of large pages.
     211 * @brief Selects 64 pages per block or 128 pages per block if not set.
     212 *
     213 * This flag is only valid for large pages.
    224214 */
    225215#define MLC_NORMAL_BLOCKS 0x4U
    226216
    227217/**
     218 * @brief Selects 16-bit IO width or 8-bit IO width if not set.
     219 */
     220#define MLC_IO_WIDTH_16_BIT 0x8U
     221
     222/**
    228223 * @brief Initializes the MLC NAND controller according to @a cfg.
    229224 */
     
    235230
    236231uint32_t lpc32xx_mlc_block_count(void);
     232
     233uint32_t lpc32xx_mlc_io_width(void);
    237234
    238235void lpc32xx_mlc_write_protection(
     
    246243 * @brief Reads the page with index @a page_index.
    247244 *
    248  * 32-bit reads will be performed.
    249  *
    250  * Bytes 7 to 15 of the spare area will contain the ECC.
     245 * Bytes 6 to 15 of the spare area will contain the ECC.
     246 *
     247 * If the read is successful, then the @a symbol_error_count will contain the
     248 * number of detected symbol errors (0, 1, 2, 3, or 4), else the value will be
     249 * 0xffffffff.  The @a symbol_error_count pointer may be @c NULL.
    251250 *
    252251 * @retval RTEMS_SUCCESSFUL Successful operation.
     
    256255rtems_status_code lpc32xx_mlc_read_page(
    257256  uint32_t page_index,
    258   uint32_t *data,
    259   uint32_t *spare
    260 );
     257  void *data,
     258  void *spare,
     259  uint32_t *symbol_error_count
     260);
     261
     262/**
     263 * @brief Checks if the block with index @a block_index is valid.
     264 *
     265 * The initial valid block information of the manufacturer will be used.
     266 * Unfortunatly there seems to be no standard for this.  A block will be
     267 * considered as bad if the first or second page of this block does not contain
     268 * 0xff at the 6th byte of the spare area.  This should work for flashes with
     269 * small pages and a 8-bit IO width.
     270 *
     271 * @retval RTEMS_SUCCESSFUL The block is valid.
     272 * @retval RTEMS_INVALID_ID Invalid @a block_index value.
     273 * @retval RTEMS_IO_ERROR Uncorrectable bit error.
     274 * @retval RTEMS_INCORRECT_STATE The block is bad.
     275 * @retval RTEMS_NOT_IMPLEMENTED No implementation available for this flash
     276 * type.
     277 */
     278rtems_status_code lpc32xx_mlc_is_valid_block(uint32_t block_index);
    261279
    262280/**
     
    265283 * @retval RTEMS_SUCCESSFUL Successful operation.
    266284 * @retval RTEMS_INVALID_ID Invalid @a block_index value.
    267  * @retval RTEMS_IO_ERROR Erase error.
     285 * @retval RTEMS_UNSATISFIED Erase error.
    268286 */
    269287rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index);
     
    273291 *
    274292 * In case of an erase error all pages and the spare areas of this block are
    275  * programmed with zero values.  This will mark the first and second page as
    276  * bad.
     293 * programmed with zero values.  This will hopefully mark the block as bad.
    277294 *
    278295 * @retval RTEMS_SUCCESSFUL Successful operation.
    279  * @retval RTEMS_INCORRECT_STATE The first or second page of this block is bad.
     296 * @retval RTEMS_INCORRECT_STATE The block is bad.
    280297 * @retval RTEMS_INVALID_ID Invalid @a block_index value.
    281  * @retval RTEMS_IO_ERROR Erase error.
     298 * @retval RTEMS_UNSATISFIED Erase error.
     299 * @retval RTEMS_NOT_IMPLEMENTED No implementation available for this flash
     300 * type.
    282301 */
    283302rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index);
     
    308327 * @brief Writes the page with index @a page_index.
    309328 *
    310  * 32-bit writes will be performed.
    311  *
    312  * Bytes 7 to 15 of the spare area will be used for the automatically generated
    313  * ECC.
     329 * Only the bytes 0 to 5 of the spare area can be used for user data, the bytes
     330 * 6 to 15 will be used for the automatically generated ECC.
    314331 *
    315332 * @retval RTEMS_SUCCESSFUL Successful operation.
     
    319336rtems_status_code lpc32xx_mlc_write_page_with_ecc(
    320337  uint32_t page_index,
    321   const uint32_t *data,
    322   const uint32_t *spare
     338  const void *data,
     339  const void *spare
    323340);
    324341
     
    378395static inline bool lpc32xx_mlc_is_bad_page(const uint32_t *spare)
    379396{
    380   return (spare [1] & MLC_BAD_BLOCK_MASK) != MLC_BAD_BLOCK_MASK;
    381 }
    382 
    383 static inline void lpc32xx_mlc_set_bad_page(uint32_t *spare)
    384 {
    385   spare [1] = MLC_BAD_BLOCK_MARK;
    386 }
    387 
    388 static inline void lpc32xx_mlc_set_reserved(uint32_t *spare)
    389 {
    390   spare [1] = MLC_RESERVED;
     397  uint32_t valid_block_mask = 0xff00;
     398  return (spare [1] & valid_block_mask) != valid_block_mask;
    391399}
    392400
  • c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc

    r74416035 r82525a75  
    1212        -fno-schedule-insns2
    1313
    14 CFLAGS_OPTIMIZE_V = -Os -g
     14CFLAGS_OPTIMIZE_V = -O2 -g
  • c/src/lib/libbsp/arm/lpc32xx/misc/boot.c

    r74416035 r82525a75  
    5353  boot_block->field.d12 = 0xaa;
    5454}
     55
     56void lpc32xx_set_boot_block_bad(
     57  lpc32xx_boot_block *boot_block
     58)
     59{
     60  boot_block->field.d12 = 0;
     61}
  • c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-erase-block-safe.c

    r74416035 r82525a75  
    4141}
    4242
    43 static bool is_bad_page(
     43static rtems_status_code is_valid_page(
    4444  uint32_t page_begin,
    4545  uint32_t page_offset
    4646)
    4747{
     48  rtems_status_code sc = RTEMS_SUCCESSFUL;
    4849  uint32_t spare [MLC_LARGE_SPARE_WORD_COUNT];
    4950
    5051  memset(spare, 0, MLC_LARGE_SPARE_SIZE);
    51   lpc32xx_mlc_read_page(
     52
     53  sc = lpc32xx_mlc_read_page(
    5254    page_begin + page_offset,
    5355    lpc32xx_magic_zero_begin,
    54     spare
     56    spare,
     57    NULL
    5558  );
    56   return lpc32xx_mlc_is_bad_page(spare);
     59  if (sc == RTEMS_SUCCESSFUL) {
     60    if (lpc32xx_mlc_is_bad_page(spare)) {
     61      sc = RTEMS_INCORRECT_STATE;
     62    }
     63  }
     64
     65  return sc;
     66}
     67
     68static rtems_status_code is_valid_block(uint32_t page_begin)
     69{
     70  rtems_status_code sc = RTEMS_SUCCESSFUL;
     71
     72  if (lpc32xx_mlc_page_size() == 512 && lpc32xx_mlc_io_width() == 8) {
     73    sc = is_valid_page(page_begin, 0);
     74    if (sc == RTEMS_SUCCESSFUL) {
     75      sc = is_valid_page(page_begin, 1);
     76    }
     77  } else {
     78    sc = RTEMS_NOT_IMPLEMENTED;
     79  }
     80
     81  return sc;
     82}
     83
     84rtems_status_code lpc32xx_mlc_is_valid_block(uint32_t block_index)
     85{
     86  uint32_t pages_per_block = lpc32xx_mlc_pages_per_block();
     87  uint32_t page_begin = block_index * pages_per_block;
     88
     89  return is_valid_block(page_begin);
    5790}
    5891
     
    6598  rtems_status_code sc = RTEMS_SUCCESSFUL;
    6699
    67   if (is_bad_page(page_begin, 0)) {
    68     return RTEMS_INCORRECT_STATE;
     100  sc = is_valid_block(page_begin);
     101  if (sc == RTEMS_SUCCESSFUL) {
     102    sc = lpc32xx_mlc_erase_block(block_index);
     103    if (sc == RTEMS_UNSATISFIED) {
     104      lpc32xx_mlc_zero_pages(page_begin, page_end);
     105    }
    69106  }
    70107
    71   if (is_bad_page(page_begin, 1)) {
    72     return RTEMS_INCORRECT_STATE;
    73   }
    74 
    75   sc = lpc32xx_mlc_erase_block(block_index);
    76   if (sc != RTEMS_SUCCESSFUL) {
    77     lpc32xx_mlc_zero_pages(page_begin, page_end);
    78 
    79     return RTEMS_IO_ERROR;
    80   }
    81 
    82   return RTEMS_SUCCESSFUL;
     108  return sc;
    83109}
    84110
  • c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c

    r74416035 r82525a75  
    3737  }
    3838
    39   sc = lpc32xx_mlc_read_page(page_index, page_data, page_spare);
     39  sc = lpc32xx_mlc_read_page(page_index, page_data, page_spare, NULL);
    4040  if (possible_bad_page && lpc32xx_mlc_is_bad_page(page_spare)) {
    4141    return RTEMS_UNSATISFIED;
  • c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c

    r74416035 r82525a75  
    8585        );
    8686        if (sc != RTEMS_SUCCESSFUL) {
    87           lpc32xx_mlc_erase_block_safe_3(block, page_begin, page_end);
     87          lpc32xx_mlc_erase_block(block);
    8888          lpc32xx_mlc_zero_pages(page_begin, page_end);
    8989          current = last;
  • c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c

    r74416035 r82525a75  
    88
    99/*
    10  * Copyright (c) 2010
    11  * embedded brains GmbH
    12  * Obere Lagerstr. 30
    13  * D-82178 Puchheim
    14  * Germany
    15  * <rtems@embedded-brains.de>
     10 * Copyright (c) 2010-2011 embedded brains GmbH.  All rights reserved.
     11 *
     12 *  embedded brains GmbH
     13 *  Obere Lagerstr. 30
     14 *  82178 Puchheim
     15 *  Germany
     16 *  <rtems@embedded-brains.de>
    1617 *
    1718 * The license and distribution terms for this file may be
     
    7172{
    7273  return mlc_block_count;
     74}
     75
     76uint32_t lpc32xx_mlc_io_width(void)
     77{
     78  if ((mlc_flags & MLC_IO_WIDTH_16_BIT) == 0) {
     79    return 8;
     80  } else {
     81    return 16;
     82  }
    7383}
    7484
     
    194204}
    195205
     206bool is_word_aligned(const void *data, const void *spare)
     207{
     208  return (((uintptr_t) data) | ((uintptr_t) spare)) % 4 == 0;
     209}
     210
    196211rtems_status_code lpc32xx_mlc_read_page(
    197212  uint32_t page_index,
    198   uint32_t *data,
    199   uint32_t *spare
     213  void *data,
     214  void *spare,
     215  uint32_t *symbol_error_count_ptr
    200216)
    201217{
     
    205221  size_t i = 0;
    206222  uint32_t isr = 0;
     223  uint32_t symbol_error_count = 0xffffffff;
     224  bool aligned = is_word_aligned(data, spare);
     225  uint8_t *current_data = data;
     226  uint8_t *current_spare = spare;
    207227
    208228  if (page_index >= mlc_page_count) {
     
    219239
    220240  for (sp = 0; sc == RTEMS_SUCCESSFUL && sp < small_pages_count; ++sp) {
     241    uint32_t *aligned_data = (uint32_t *) current_data;
     242    uint32_t *aligned_spare = (uint32_t *) current_spare;
     243
    221244    mlc->ecc_dec = 0;
    222245
    223     for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
    224       data [i] = mlc->data.w32;
    225     }
    226     for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
    227       spare [i] = mlc->data.w32;
     246    if (aligned) {
     247      for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
     248        aligned_data [i] = mlc->data.w32;
     249      }
     250      for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
     251        aligned_spare [i] = mlc->data.w32;
     252      }
     253    } else {
     254      for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
     255        current_data [i] = mlc->data.w8;
     256      }
     257      for (i = 0; i < MLC_SMALL_SPARE_SIZE; ++i) {
     258        current_spare [i] = mlc->data.w8;
     259      }
    228260    }
    229261
     
    231263
    232264    isr = mlc->isr;
    233     if ((isr & MLC_ISR_ERRORS_DETECTED) != 0) {
     265    if ((isr & MLC_ISR_ERRORS_DETECTED) == 0) {
     266      symbol_error_count = 0;
     267    } else {
    234268      if ((isr & MLC_ISR_DECODER_FAILURE) == 0) {
    235         mlc->rubp = 0;
    236         for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
    237           data [i] = mlc->buff.w32;
    238         }
    239         mlc->robp = 0;
    240         for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
    241           spare [i] = mlc->buff.w32;
     269        symbol_error_count = MLC_ISR_SYMBOL_ERRORS(isr);
     270        if (aligned) {
     271          mlc->rubp = 0;
     272          for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
     273            aligned_data [i] = mlc->buff.w32;
     274          }
     275          mlc->robp = 0;
     276          for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
     277            aligned_spare [i] = mlc->buff.w32;
     278          }
     279        } else {
     280          mlc->rubp = 0;
     281          for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
     282            current_data [i] = mlc->buff.w8;
     283          }
     284          mlc->robp = 0;
     285          for (i = 0; i < MLC_SMALL_SPARE_SIZE; ++i) {
     286            current_spare [i] = mlc->buff.w8;
     287          }
    242288        }
    243289      } else {
     
    246292    }
    247293
    248     data += MLC_SMALL_DATA_WORD_COUNT;
    249     spare += MLC_SMALL_SPARE_WORD_COUNT;
     294    current_data += MLC_SMALL_DATA_SIZE;
     295    current_spare += MLC_SMALL_SPARE_SIZE;
     296  }
     297
     298  if (symbol_error_count_ptr != NULL) {
     299    *symbol_error_count_ptr = symbol_error_count;
    250300  }
    251301
     
    269319rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index)
    270320{
    271   rtems_status_code sc = RTEMS_IO_ERROR;
     321  rtems_status_code sc = RTEMS_UNSATISFIED;
    272322
    273323  if (block_index >= mlc_block_count) {
     
    289339rtems_status_code lpc32xx_mlc_write_page_with_ecc(
    290340  uint32_t page_index,
    291   const uint32_t *data,
    292   const uint32_t *spare
     341  const void *data,
     342  const void *spare
    293343)
    294344{
    295345  rtems_status_code sc = RTEMS_IO_ERROR;
    296   size_t small_pages_count = mlc_small_pages() ? 1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
     346  size_t small_pages_count = mlc_small_pages() ?
     347    1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
    297348  size_t sp = 0;
    298349  size_t i = 0;
     350  bool aligned = is_word_aligned(data, spare);
     351  const uint8_t *current_data = data;
     352  const uint8_t *current_spare = spare;
    299353
    300354  if (page_index >= mlc_page_count) {
     
    309363    mlc->ecc_enc = 0;
    310364
    311     for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
    312       mlc->data.w32 = data [i];
    313     }
    314     mlc->data.w32 = spare [0];
    315     mlc->data.w16 = (uint16_t) spare [1];
     365    if (aligned) {
     366      const uint32_t *aligned_data = (const uint32_t *) current_data;
     367      const uint32_t *aligned_spare = (const uint32_t *) current_spare;
     368
     369      for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
     370        mlc->data.w32 = aligned_data [i];
     371      }
     372      mlc->data.w32 = aligned_spare [0];
     373      mlc->data.w16 = (uint16_t) aligned_spare [1];
     374    } else {
     375      for (i = 0; i < MLC_SMALL_DATA_SIZE; ++i) {
     376        mlc->data.w8 = current_data [i];
     377      }
     378      for (i = 0; i < MLC_SMALL_USER_SPARE_SIZE; ++i) {
     379        mlc->data.w8 = current_spare [i];
     380      }
     381    }
    316382    mlc->wpr = 0;
    317383
    318384    mlc_wait(MLC_ISR_CONTROLLER_READY);
    319385
    320     data += MLC_SMALL_DATA_WORD_COUNT;
    321     spare += MLC_SMALL_SPARE_WORD_COUNT;
     386    current_data += MLC_SMALL_DATA_SIZE;
     387    current_spare += MLC_SMALL_SPARE_SIZE;
    322388  }
    323389
Note: See TracChangeset for help on using the changeset viewer.