summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramachronic <amachronic@protonmail.com>2021-04-06 01:10:01 +0100
committeramachronic <amachronic@protonmail.com>2021-04-06 17:27:12 +0100
commit28c89386af8ea9d002bcc25483233053fe0e7525 (patch)
treeac25a1cbf09d7bc2dadea89002943c722fbd8806
parentb5558c1cf968f0fcff072456408b14f130f29ce3 (diff)
downloadrockbox-28c89386af8ea9d002bcc25483233053fe0e7525.tar.gz
rockbox-28c89386af8ea9d002bcc25483233053fe0e7525.zip
x1000: Improve NAND driver API
- Proper error codes are now returned from all functions. These codes will be used by a host-side flash tool for error reporting. - nand_erase_block() was replaced by nand_erase_bytes(). The caller can't know how big an eraseblock is with the current API, so next best thing is to verify the correct alignment inside the call and reject the erase if it isn't properly aligned. - Fixed typo in nandcmd_block_erase() which would cause an SFC error to be interpreted as success. Yikes. Change-Id: Id4ac9b44fa7fc2fcb81ff19ba730df78457c0383
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c2
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000-err.h18
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.c122
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.h3
4 files changed, 93 insertions, 52 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
index c794da4000..cdd7276bee 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
@@ -50,7 +50,7 @@ static int install_from_buffer(const void* buf)
50 goto _exit; 50 goto _exit;
51 } 51 }
52 52
53 if(nand_erase_block(0)) { 53 if(nand_erase_bytes(0, BOOT_IMAGE_SIZE)) {
54 status = ERR_FLASH_ERASE_FAILED; 54 status = ERR_FLASH_ERASE_FAILED;
55 goto _exit; 55 goto _exit;
56 } 56 }
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000-err.h b/firmware/target/mips/ingenic_x1000/nand-x1000-err.h
new file mode 100644
index 0000000000..252d591062
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000-err.h
@@ -0,0 +1,18 @@
1#ifndef __NAND_X1000_ERR_H__
2#define __NAND_X1000_ERR_H__
3
4/* Error codes which can be returned by the nand-x1000 API. These codes are
5 * also used by host-side tools, so we define them here to avoid polluting
6 * the namespace with useless X1000 APIs. */
7#define NANDERR_CHIP_UNSUPPORTED (-1)
8#define NANDERR_WRITE_PROTECTED (-2)
9#define NANDERR_UNALIGNED_ADDRESS (-3)
10#define NANDERR_UNALIGNED_LENGTH (-4)
11#define NANDERR_READ_FAILED (-5)
12#define NANDERR_ECC_FAILED (-6)
13#define NANDERR_ERASE_FAILED (-7)
14#define NANDERR_PROGRAM_FAILED (-8)
15#define NANDERR_COMMAND_FAILED (-9)
16#define NANDERR_OTHER (-99)
17
18#endif /* __NAND_X1000_ERR_H__ */
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
228int nand_erase_block(uint32_t byteaddr) 226int 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
430int nandop_std_read_page(nand_drv* d, uint32_t rowaddr, unsigned char* buf) 446int 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
442int nandop_std_write_page(nand_drv* d, uint32_t rowaddr, const unsigned char* buf) 460int 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
456int nandop_std_erase_block(nand_drv* d, uint32_t blockaddr) 476int 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}
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h
index 865feb38c5..f6709aaaf9 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h
@@ -31,6 +31,7 @@
31#include <stdint.h> 31#include <stdint.h>
32#include <stdbool.h> 32#include <stdbool.h>
33#include <stddef.h> 33#include <stddef.h>
34#include "nand-x1000-err.h"
34 35
35/* Chip supports quad I/O for page read/write */ 36/* Chip supports quad I/O for page read/write */
36#define NANDCHIP_FLAG_QUAD 0x01 37#define NANDCHIP_FLAG_QUAD 0x01
@@ -123,7 +124,7 @@ extern int nand_enable_writes(bool en);
123/* Byte-based NAND operations */ 124/* Byte-based NAND operations */
124extern int nand_read_bytes(uint32_t byteaddr, int count, void* buf); 125extern int nand_read_bytes(uint32_t byteaddr, int count, void* buf);
125extern int nand_write_bytes(uint32_t byteaddr, int count, const void* buf); 126extern int nand_write_bytes(uint32_t byteaddr, int count, const void* buf);
126extern int nand_erase_block(uint32_t byteaddr); 127extern int nand_erase_bytes(uint32_t byteaddr, int count);
127 128
128/* NAND command numbers */ 129/* NAND command numbers */
129#define NAND_CMD_READ_ID 0x9f 130#define NAND_CMD_READ_ID 0x9f