summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-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