diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/nand-x1000.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.c | 122 |
1 files changed, 72 insertions, 50 deletions
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index df86bebf4d..e6d5b6e4c7 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c | |||
@@ -79,7 +79,7 @@ int nand_open(void) | |||
79 | int status = 0; | 79 | int status = 0; |
80 | int nandid = nandcmd_read_id(&nand_driver); | 80 | int nandid = nandcmd_read_id(&nand_driver); |
81 | if(nandid < 0) { | 81 | if(nandid < 0) { |
82 | status = -1; | 82 | status = NANDERR_CHIP_UNSUPPORTED; |
83 | goto _err; | 83 | goto _err; |
84 | } | 84 | } |
85 | 85 | ||
@@ -88,7 +88,7 @@ int nand_open(void) | |||
88 | const nand_chip_desc* desc = &target_nand_chip_descs[0]; | 88 | const nand_chip_desc* desc = &target_nand_chip_descs[0]; |
89 | while(1) { | 89 | while(1) { |
90 | if(desc->data == NULL || desc->ops == NULL) { | 90 | if(desc->data == NULL || desc->ops == NULL) { |
91 | status = -1; | 91 | status = NANDERR_CHIP_UNSUPPORTED; |
92 | goto _err; | 92 | goto _err; |
93 | } | 93 | } |
94 | 94 | ||
@@ -105,10 +105,8 @@ int nand_open(void) | |||
105 | sfc_set_dev_conf(desc->data->dev_conf); | 105 | sfc_set_dev_conf(desc->data->dev_conf); |
106 | sfc_set_clock(NAND_CLOCK_SOURCE, desc->data->clock_freq); | 106 | sfc_set_clock(NAND_CLOCK_SOURCE, desc->data->clock_freq); |
107 | 107 | ||
108 | if(desc->ops->open(&nand_driver) < 0) { | 108 | if((status = desc->ops->open(&nand_driver)) < 0) |
109 | status = -1; | ||
110 | goto _err; | 109 | goto _err; |
111 | } | ||
112 | 110 | ||
113 | _exit: | 111 | _exit: |
114 | sfc_unlock(); | 112 | sfc_unlock(); |
@@ -158,12 +156,12 @@ extern int nand_read_bytes(uint32_t byteaddr, int count, void* buf) | |||
158 | sfc_lock(); | 156 | sfc_lock(); |
159 | do { | 157 | do { |
160 | if(d->chip_ops->read_page(d, rowaddr, d->pagebuf) < 0) { | 158 | if(d->chip_ops->read_page(d, rowaddr, d->pagebuf) < 0) { |
161 | status = -1; | 159 | status = NANDERR_READ_FAILED; |
162 | goto _end; | 160 | goto _end; |
163 | } | 161 | } |
164 | 162 | ||
165 | if(d->chip_ops->ecc_read(d, d->pagebuf) < 0) { | 163 | if(d->chip_ops->ecc_read(d, d->pagebuf) < 0) { |
166 | status = -1; | 164 | status = NANDERR_ECC_FAILED; |
167 | goto _end; | 165 | goto _end; |
168 | } | 166 | } |
169 | 167 | ||
@@ -188,7 +186,7 @@ int nand_write_bytes(uint32_t byteaddr, int count, const void* buf) | |||
188 | nand_drv* d = &nand_driver; | 186 | nand_drv* d = &nand_driver; |
189 | 187 | ||
190 | if((d->flags & NAND_DRV_FLAG_WRITEABLE) == 0) | 188 | if((d->flags & NAND_DRV_FLAG_WRITEABLE) == 0) |
191 | return -1; | 189 | return NANDERR_WRITE_PROTECTED; |
192 | 190 | ||
193 | if(count <= 0) | 191 | if(count <= 0) |
194 | return 0; | 192 | return 0; |
@@ -198,9 +196,9 @@ int nand_write_bytes(uint32_t byteaddr, int count, const void* buf) | |||
198 | 196 | ||
199 | /* Only support whole page writes right now */ | 197 | /* Only support whole page writes right now */ |
200 | if(coladdr != 0) | 198 | if(coladdr != 0) |
201 | return -1; | 199 | return NANDERR_UNALIGNED_ADDRESS; |
202 | if(count % d->chip_data->page_size) | 200 | if(count % d->chip_data->page_size) |
203 | return -1; | 201 | return NANDERR_UNALIGNED_LENGTH; |
204 | 202 | ||
205 | const unsigned char* srcbuf = (const unsigned char*)buf; | 203 | const unsigned char* srcbuf = (const unsigned char*)buf; |
206 | int status = 0; | 204 | int status = 0; |
@@ -211,7 +209,7 @@ int nand_write_bytes(uint32_t byteaddr, int count, const void* buf) | |||
211 | d->chip_ops->ecc_write(d, d->pagebuf); | 209 | d->chip_ops->ecc_write(d, d->pagebuf); |
212 | 210 | ||
213 | if(d->chip_ops->write_page(d, rowaddr, d->pagebuf) < 0) { | 211 | if(d->chip_ops->write_page(d, rowaddr, d->pagebuf) < 0) { |
214 | status = -1; | 212 | status = NANDERR_PROGRAM_FAILED; |
215 | goto _end; | 213 | goto _end; |
216 | } | 214 | } |
217 | 215 | ||
@@ -225,24 +223,42 @@ int nand_write_bytes(uint32_t byteaddr, int count, const void* buf) | |||
225 | return status; | 223 | return status; |
226 | } | 224 | } |
227 | 225 | ||
228 | int nand_erase_block(uint32_t byteaddr) | 226 | int nand_erase_bytes(uint32_t byteaddr, int count) |
229 | { | 227 | { |
230 | nand_drv* d = &nand_driver; | 228 | nand_drv* d = &nand_driver; |
231 | 229 | ||
232 | if((d->flags & NAND_DRV_FLAG_WRITEABLE) == 0) | 230 | if((d->flags & NAND_DRV_FLAG_WRITEABLE) == 0) |
233 | return -1; | 231 | return NANDERR_WRITE_PROTECTED; |
234 | 232 | ||
235 | /* Ensure address is aligned to a block boundary */ | 233 | /* Ensure address is aligned to a block boundary */ |
234 | if(byteaddr % d->chip_data->page_size) | ||
235 | return NANDERR_UNALIGNED_ADDRESS; | ||
236 | |||
236 | uint32_t blockaddr = byteaddr / d->chip_data->page_size; | 237 | uint32_t blockaddr = byteaddr / d->chip_data->page_size; |
237 | if(blockaddr % d->chip_data->block_size) | 238 | if(blockaddr % d->chip_data->block_size) |
238 | return -1; | 239 | return NANDERR_UNALIGNED_ADDRESS; |
240 | |||
241 | /* Ensure length is also aligned to the size of a block */ | ||
242 | if(count % d->chip_data->page_size) | ||
243 | return NANDERR_UNALIGNED_LENGTH; | ||
244 | |||
245 | count /= d->chip_data->page_size; | ||
246 | if(count % d->chip_data->block_size) | ||
247 | return NANDERR_UNALIGNED_LENGTH; | ||
248 | |||
249 | count /= d->chip_data->block_size; | ||
239 | 250 | ||
240 | int status = 0; | 251 | int status = 0; |
241 | sfc_lock(); | 252 | sfc_lock(); |
242 | 253 | ||
243 | if(d->chip_ops->erase_block(d, blockaddr)) { | 254 | for(int i = 0; i < count; ++i) { |
244 | status = -1; | 255 | if(d->chip_ops->erase_block(d, blockaddr)) { |
245 | goto _end; | 256 | status = NANDERR_ERASE_FAILED; |
257 | goto _end; | ||
258 | } | ||
259 | |||
260 | /* Advance to next block */ | ||
261 | blockaddr += d->chip_data->block_size; | ||
246 | } | 262 | } |
247 | 263 | ||
248 | _end: | 264 | _end: |
@@ -260,7 +276,7 @@ int nandcmd_read_id(nand_drv* d) | |||
260 | op.data_bytes = 2; | 276 | op.data_bytes = 2; |
261 | op.buffer = d->auxbuf; | 277 | op.buffer = d->auxbuf; |
262 | if(sfc_exec(&op)) | 278 | if(sfc_exec(&op)) |
263 | return -1; | 279 | return NANDERR_COMMAND_FAILED; |
264 | 280 | ||
265 | return (d->auxbuf[0] << 8) | d->auxbuf[1]; | 281 | return (d->auxbuf[0] << 8) | d->auxbuf[1]; |
266 | } | 282 | } |
@@ -272,7 +288,7 @@ int nandcmd_write_enable(nand_drv* d) | |||
272 | sfc_op op = {0}; | 288 | sfc_op op = {0}; |
273 | op.command = NAND_CMD_WRITE_ENABLE; | 289 | op.command = NAND_CMD_WRITE_ENABLE; |
274 | if(sfc_exec(&op)) | 290 | if(sfc_exec(&op)) |
275 | return -1; | 291 | return NANDERR_COMMAND_FAILED; |
276 | 292 | ||
277 | return 0; | 293 | return 0; |
278 | } | 294 | } |
@@ -287,7 +303,7 @@ int nandcmd_get_feature(nand_drv* d, int reg) | |||
287 | op.data_bytes = 1; | 303 | op.data_bytes = 1; |
288 | op.buffer = d->auxbuf; | 304 | op.buffer = d->auxbuf; |
289 | if(sfc_exec(&op)) | 305 | if(sfc_exec(&op)) |
290 | return -1; | 306 | return NANDERR_COMMAND_FAILED; |
291 | 307 | ||
292 | return d->auxbuf[0]; | 308 | return d->auxbuf[0]; |
293 | } | 309 | } |
@@ -303,7 +319,7 @@ int nandcmd_set_feature(nand_drv* d, int reg, int val) | |||
303 | op.buffer = d->auxbuf; | 319 | op.buffer = d->auxbuf; |
304 | d->auxbuf[0] = val & 0xff; | 320 | d->auxbuf[0] = val & 0xff; |
305 | if(sfc_exec(&op)) | 321 | if(sfc_exec(&op)) |
306 | return -1; | 322 | return NANDERR_COMMAND_FAILED; |
307 | 323 | ||
308 | return 0; | 324 | return 0; |
309 | } | 325 | } |
@@ -315,7 +331,7 @@ int nandcmd_page_read_to_cache(nand_drv* d, uint32_t rowaddr) | |||
315 | op.addr_bytes = d->chip_data->rowaddr_width; | 331 | op.addr_bytes = d->chip_data->rowaddr_width; |
316 | op.addr_lo = rowaddr; | 332 | op.addr_lo = rowaddr; |
317 | if(sfc_exec(&op)) | 333 | if(sfc_exec(&op)) |
318 | return -1; | 334 | return NANDERR_COMMAND_FAILED; |
319 | 335 | ||
320 | return 0; | 336 | return 0; |
321 | } | 337 | } |
@@ -338,7 +354,7 @@ int nandcmd_read_from_cache(nand_drv* d, unsigned char* buf) | |||
338 | op.data_bytes = d->raw_page_size; | 354 | op.data_bytes = d->raw_page_size; |
339 | op.buffer = buf; | 355 | op.buffer = buf; |
340 | if(sfc_exec(&op)) | 356 | if(sfc_exec(&op)) |
341 | return -1; | 357 | return NANDERR_COMMAND_FAILED; |
342 | 358 | ||
343 | return 0; | 359 | return 0; |
344 | } | 360 | } |
@@ -360,7 +376,7 @@ int nandcmd_program_load(nand_drv* d, const unsigned char* buf) | |||
360 | op.data_bytes = d->raw_page_size; | 376 | op.data_bytes = d->raw_page_size; |
361 | op.buffer = (void*)buf; | 377 | op.buffer = (void*)buf; |
362 | if(sfc_exec(&op)) | 378 | if(sfc_exec(&op)) |
363 | return -1; | 379 | return NANDERR_COMMAND_FAILED; |
364 | 380 | ||
365 | return 0; | 381 | return 0; |
366 | } | 382 | } |
@@ -372,7 +388,7 @@ int nandcmd_program_execute(nand_drv* d, uint32_t rowaddr) | |||
372 | op.addr_bytes = d->chip_data->rowaddr_width; | 388 | op.addr_bytes = d->chip_data->rowaddr_width; |
373 | op.addr_lo = rowaddr; | 389 | op.addr_lo = rowaddr; |
374 | if(sfc_exec(&op)) | 390 | if(sfc_exec(&op)) |
375 | return -1; | 391 | return NANDERR_COMMAND_FAILED; |
376 | 392 | ||
377 | return 0; | 393 | return 0; |
378 | } | 394 | } |
@@ -384,7 +400,7 @@ int nandcmd_block_erase(nand_drv* d, uint32_t blockaddr) | |||
384 | op.addr_bytes = d->chip_data->rowaddr_width; | 400 | op.addr_bytes = d->chip_data->rowaddr_width; |
385 | op.addr_lo = blockaddr; | 401 | op.addr_lo = blockaddr; |
386 | if(sfc_exec(&op)) | 402 | if(sfc_exec(&op)) |
387 | return 01; | 403 | return NANDERR_COMMAND_FAILED; |
388 | 404 | ||
389 | return 0; | 405 | return 0; |
390 | } | 406 | } |
@@ -407,11 +423,11 @@ static int nandop_std_wait_status(nand_drv* d, int errbit) | |||
407 | do { | 423 | do { |
408 | reg = nandcmd_get_feature(d, NAND_FREG_STATUS); | 424 | reg = nandcmd_get_feature(d, NAND_FREG_STATUS); |
409 | if(reg < 0) | 425 | if(reg < 0) |
410 | return -1; | 426 | return reg; |
411 | } while(reg & NAND_FREG_STATUS_OIP); | 427 | } while(reg & NAND_FREG_STATUS_OIP); |
412 | 428 | ||
413 | if(reg & errbit) | 429 | if(reg & errbit) |
414 | return -1; | 430 | return NANDERR_OTHER; |
415 | 431 | ||
416 | return reg; | 432 | return reg; |
417 | } | 433 | } |
@@ -429,38 +445,44 @@ void nandop_std_close(nand_drv* d) | |||
429 | 445 | ||
430 | int nandop_std_read_page(nand_drv* d, uint32_t rowaddr, unsigned char* buf) | 446 | int nandop_std_read_page(nand_drv* d, uint32_t rowaddr, unsigned char* buf) |
431 | { | 447 | { |
432 | if(nandcmd_page_read_to_cache(d, rowaddr) < 0) | 448 | int status; |
433 | return -1; | 449 | |
434 | if(nandop_std_wait_status(d, 0) < 0) | 450 | if((status = nandcmd_page_read_to_cache(d, rowaddr)) < 0) |
435 | return -1; | 451 | return status; |
436 | if(nandcmd_read_from_cache(d, buf) < 0) | 452 | if((status = nandop_std_wait_status(d, 0)) < 0) |
437 | return -1; | 453 | return status; |
454 | if((status = nandcmd_read_from_cache(d, buf)) < 0) | ||
455 | return status; | ||
438 | 456 | ||
439 | return 0; | 457 | return 0; |
440 | } | 458 | } |
441 | 459 | ||
442 | int nandop_std_write_page(nand_drv* d, uint32_t rowaddr, const unsigned char* buf) | 460 | int nandop_std_write_page(nand_drv* d, uint32_t rowaddr, const unsigned char* buf) |
443 | { | 461 | { |
444 | if(nandcmd_write_enable(d) < 0) | 462 | int status; |
445 | return -1; | 463 | |
446 | if(nandcmd_program_load(d, buf) < 0) | 464 | if((status = nandcmd_write_enable(d)) < 0) |
447 | return -1; | 465 | return status; |
448 | if(nandcmd_program_execute(d, rowaddr) < 0) | 466 | if((status = nandcmd_program_load(d, buf)) < 0) |
449 | return -1; | 467 | return status; |
450 | if(nandop_std_wait_status(d, NAND_FREG_STATUS_P_FAIL) < 0) | 468 | if((status = nandcmd_program_execute(d, rowaddr)) < 0) |
451 | return -1; | 469 | return status; |
470 | if((status = nandop_std_wait_status(d, NAND_FREG_STATUS_P_FAIL)) < 0) | ||
471 | return status; | ||
452 | 472 | ||
453 | return 0; | 473 | return 0; |
454 | } | 474 | } |
455 | 475 | ||
456 | int nandop_std_erase_block(nand_drv* d, uint32_t blockaddr) | 476 | int nandop_std_erase_block(nand_drv* d, uint32_t blockaddr) |
457 | { | 477 | { |
458 | if(nandcmd_write_enable(d) < 0) | 478 | int status; |
459 | return -1; | 479 | |
460 | if(nandcmd_block_erase(d, blockaddr) < 0) | 480 | if((status = nandcmd_write_enable(d)) < 0) |
461 | return -1; | 481 | return status; |
462 | if(nandop_std_wait_status(d, NAND_FREG_STATUS_E_FAIL) < 0) | 482 | if((status = nandcmd_block_erase(d, blockaddr)) < 0) |
463 | return -1; | 483 | return status; |
484 | if((status = nandop_std_wait_status(d, NAND_FREG_STATUS_E_FAIL) < 0)) | ||
485 | return status; | ||
464 | 486 | ||
465 | return 0; | 487 | return 0; |
466 | } | 488 | } |
@@ -469,7 +491,7 @@ int nandop_std_set_wp_enable(nand_drv* d, bool en) | |||
469 | { | 491 | { |
470 | int val = nandcmd_get_feature(d, NAND_FREG_PROTECTION); | 492 | int val = nandcmd_get_feature(d, NAND_FREG_PROTECTION); |
471 | if(val < 0) | 493 | if(val < 0) |
472 | return -1; | 494 | return val; |
473 | 495 | ||
474 | if(en) { | 496 | if(en) { |
475 | val &= ~NAND_FREG_PROTECTION_ALLBP; | 497 | val &= ~NAND_FREG_PROTECTION_ALLBP; |
@@ -486,7 +508,7 @@ int nandop_std_set_wp_enable(nand_drv* d, bool en) | |||
486 | sfc_set_wp_enable(true); | 508 | sfc_set_wp_enable(true); |
487 | 509 | ||
488 | if(status < 0) | 510 | if(status < 0) |
489 | return -1; | 511 | return status; |
490 | 512 | ||
491 | return 0; | 513 | return 0; |
492 | } | 514 | } |