Changeset 82525a75 in rtems
- Timestamp:
- 09/22/11 07:09:07 (12 years ago)
- Branches:
- 4.11, 5, master
- Children:
- f40139b
- Parents:
- 74416035
- Location:
- c/src/lib/libbsp/arm/lpc32xx
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/lib/libbsp/arm/lpc32xx/ChangeLog
r74416035 r82525a75 1 2011-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 1 12 2011-08-08 Sebastian Huber <sebastian.huber@embedded-brains.de> 2 13 -
c/src/lib/libbsp/arm/lpc32xx/include/boot.h
r74416035 r82525a75 102 102 ); 103 103 104 void lpc32xx_set_boot_block_bad( 105 lpc32xx_boot_block *boot_block 106 ); 107 104 108 /** @} */ 105 109 -
c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h
r74416035 r82525a75 527 527 uint32_t irq_mr; 528 528 uint32_t irq_sr; 529 uint32_t reserved_2; 529 530 uint32_t lock_pr; 530 531 uint32_t isr; -
c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h
r74416035 r82525a75 75 75 #define MLC_SMALL_DATA_SIZE 512 76 76 #define MLC_SMALL_SPARE_SIZE 16 77 #define MLC_SMALL_USER_SPARE_SIZE 6 78 #define MLC_SMALL_ECC_SPARE_SIZE 10 77 79 #define MLC_SMALL_DATA_WORD_COUNT (MLC_SMALL_DATA_SIZE / 4) 78 80 #define MLC_SMALL_SPARE_WORD_COUNT (MLC_SMALL_SPARE_SIZE / 4) … … 137 139 138 140 #define MLC_ISR_DECODER_FAILURE BSP_BIT32(6) 141 #define MLC_ISR_SYMBOL_ERRORS(reg) BSP_FLD32GET(reg, 4, 5) 139 142 #define MLC_ISR_ERRORS_DETECTED BSP_BIT32(3) 140 143 #define MLC_ISR_ECC_READY BSP_BIT32(2) … … 166 169 167 170 /** @} */ 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 that175 * 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)183 171 184 172 /** … … 210 198 /** 211 199 * @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. 213 201 */ 214 202 #define MLC_SMALL_PAGES 0x1U 215 203 216 204 /** 217 * @Brief Selects 3/4 address cycles for small pages/large pages or 4/5218 * address cycles.205 * @Brief Selects 4/5 address cycles for small/large pages or 3/4 address 206 * cycles if not set. 219 207 */ 220 208 #define MLC_MANY_ADDRESS_CYCLES 0x2U 221 209 222 210 /** 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. 224 214 */ 225 215 #define MLC_NORMAL_BLOCKS 0x4U 226 216 227 217 /** 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 /** 228 223 * @brief Initializes the MLC NAND controller according to @a cfg. 229 224 */ … … 235 230 236 231 uint32_t lpc32xx_mlc_block_count(void); 232 233 uint32_t lpc32xx_mlc_io_width(void); 237 234 238 235 void lpc32xx_mlc_write_protection( … … 246 243 * @brief Reads the page with index @a page_index. 247 244 * 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. 251 250 * 252 251 * @retval RTEMS_SUCCESSFUL Successful operation. … … 256 255 rtems_status_code lpc32xx_mlc_read_page( 257 256 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 */ 278 rtems_status_code lpc32xx_mlc_is_valid_block(uint32_t block_index); 261 279 262 280 /** … … 265 283 * @retval RTEMS_SUCCESSFUL Successful operation. 266 284 * @retval RTEMS_INVALID_ID Invalid @a block_index value. 267 * @retval RTEMS_ IO_ERRORErase error.285 * @retval RTEMS_UNSATISFIED Erase error. 268 286 */ 269 287 rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index); … … 273 291 * 274 292 * 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. 277 294 * 278 295 * @retval RTEMS_SUCCESSFUL Successful operation. 279 * @retval RTEMS_INCORRECT_STATE The first or second page of thisblock is bad.296 * @retval RTEMS_INCORRECT_STATE The block is bad. 280 297 * @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. 282 301 */ 283 302 rtems_status_code lpc32xx_mlc_erase_block_safe(uint32_t block_index); … … 308 327 * @brief Writes the page with index @a page_index. 309 328 * 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. 314 331 * 315 332 * @retval RTEMS_SUCCESSFUL Successful operation. … … 319 336 rtems_status_code lpc32xx_mlc_write_page_with_ecc( 320 337 uint32_t page_index, 321 const uint32_t*data,322 const uint32_t*spare338 const void *data, 339 const void *spare 323 340 ); 324 341 … … 378 395 static inline bool lpc32xx_mlc_is_bad_page(const uint32_t *spare) 379 396 { 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; 391 399 } 392 400 -
c/src/lib/libbsp/arm/lpc32xx/make/custom/lpc32xx.inc
r74416035 r82525a75 12 12 -fno-schedule-insns2 13 13 14 CFLAGS_OPTIMIZE_V = -O s-g14 CFLAGS_OPTIMIZE_V = -O2 -g -
c/src/lib/libbsp/arm/lpc32xx/misc/boot.c
r74416035 r82525a75 53 53 boot_block->field.d12 = 0xaa; 54 54 } 55 56 void 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 41 41 } 42 42 43 static bool is_bad_page(43 static rtems_status_code is_valid_page( 44 44 uint32_t page_begin, 45 45 uint32_t page_offset 46 46 ) 47 47 { 48 rtems_status_code sc = RTEMS_SUCCESSFUL; 48 49 uint32_t spare [MLC_LARGE_SPARE_WORD_COUNT]; 49 50 50 51 memset(spare, 0, MLC_LARGE_SPARE_SIZE); 51 lpc32xx_mlc_read_page( 52 53 sc = lpc32xx_mlc_read_page( 52 54 page_begin + page_offset, 53 55 lpc32xx_magic_zero_begin, 54 spare 56 spare, 57 NULL 55 58 ); 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 68 static 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 84 rtems_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); 57 90 } 58 91 … … 65 98 rtems_status_code sc = RTEMS_SUCCESSFUL; 66 99 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 } 69 106 } 70 107 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; 83 109 } 84 110 -
c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-read-blocks.c
r74416035 r82525a75 37 37 } 38 38 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); 40 40 if (possible_bad_page && lpc32xx_mlc_is_bad_page(page_spare)) { 41 41 return RTEMS_UNSATISFIED; -
c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc-write-blocks.c
r74416035 r82525a75 85 85 ); 86 86 if (sc != RTEMS_SUCCESSFUL) { 87 lpc32xx_mlc_erase_block _safe_3(block, page_begin, page_end);87 lpc32xx_mlc_erase_block(block); 88 88 lpc32xx_mlc_zero_pages(page_begin, page_end); 89 89 current = last; -
c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c
r74416035 r82525a75 8 8 9 9 /* 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> 16 17 * 17 18 * The license and distribution terms for this file may be … … 71 72 { 72 73 return mlc_block_count; 74 } 75 76 uint32_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 } 73 83 } 74 84 … … 194 204 } 195 205 206 bool is_word_aligned(const void *data, const void *spare) 207 { 208 return (((uintptr_t) data) | ((uintptr_t) spare)) % 4 == 0; 209 } 210 196 211 rtems_status_code lpc32xx_mlc_read_page( 197 212 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 200 216 ) 201 217 { … … 205 221 size_t i = 0; 206 222 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; 207 227 208 228 if (page_index >= mlc_page_count) { … … 219 239 220 240 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 221 244 mlc->ecc_dec = 0; 222 245 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 } 228 260 } 229 261 … … 231 263 232 264 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 { 234 268 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 } 242 288 } 243 289 } else { … … 246 292 } 247 293 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; 250 300 } 251 301 … … 269 319 rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index) 270 320 { 271 rtems_status_code sc = RTEMS_ IO_ERROR;321 rtems_status_code sc = RTEMS_UNSATISFIED; 272 322 273 323 if (block_index >= mlc_block_count) { … … 289 339 rtems_status_code lpc32xx_mlc_write_page_with_ecc( 290 340 uint32_t page_index, 291 const uint32_t*data,292 const uint32_t*spare341 const void *data, 342 const void *spare 293 343 ) 294 344 { 295 345 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; 297 348 size_t sp = 0; 298 349 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; 299 353 300 354 if (page_index >= mlc_page_count) { … … 309 363 mlc->ecc_enc = 0; 310 364 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 } 316 382 mlc->wpr = 0; 317 383 318 384 mlc_wait(MLC_ISR_CONTROLLER_READY); 319 385 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; 322 388 } 323 389
Note: See TracChangeset
for help on using the changeset viewer.