blob: 2cf76cb65924aa978a1a67e140acc6a33056dbe7 [file] [log] [blame]
Dima Zavin03cf4312009-01-23 16:38:30 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <debug.h>
30#include <reg.h>
31#include <stdlib.h>
32#include <string.h>
33#include <dev/flash.h>
34#include <lib/ptable.h>
35
36#include "dmov.h"
37#include "nand.h"
38
39#define VERBOSE 0
40
41typedef struct dmov_ch dmov_ch;
42struct dmov_ch
43{
44 volatile unsigned cmd;
45 volatile unsigned result;
46 volatile unsigned status;
47 volatile unsigned config;
48};
49
50static void dmov_prep_ch(dmov_ch *ch, unsigned id)
51{
52 ch->cmd = DMOV_CMD_PTR(id);
53 ch->result = DMOV_RSLT(id);
54 ch->status = DMOV_STATUS(id);
55 ch->config = DMOV_CONFIG(id);
56}
57
58#define SRC_CRCI_NAND_CMD CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
59#define DST_CRCI_NAND_CMD CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
60#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
61#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
62
63static unsigned CFG0, CFG1;
64
65#define CFG1_WIDE_FLASH (1U << 1)
66
67#define paddr(n) ((unsigned) (n))
68
69static int dmov_exec_cmdptr(unsigned id, unsigned *ptr)
70{
71 dmov_ch ch;
72 unsigned n;
73
74 dmov_prep_ch(&ch, id);
75
76 writel(DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(paddr(ptr)), ch.cmd);
77
78 while(!(readl(ch.status) & DMOV_STATUS_RSLT_VALID)) ;
79
80 n = readl(ch.status);
81 while(DMOV_STATUS_RSLT_COUNT(n)) {
82 n = readl(ch.result);
83 if(n != 0x80000002) {
84 dprintf(CRITICAL, "ERROR: result: %x\n", n);
85 dprintf(CRITICAL, "ERROR: flush: %x %x %x %x\n",
86 readl(DMOV_FLUSH0(DMOV_NAND_CHAN)),
87 readl(DMOV_FLUSH1(DMOV_NAND_CHAN)),
88 readl(DMOV_FLUSH2(DMOV_NAND_CHAN)),
89 readl(DMOV_FLUSH3(DMOV_NAND_CHAN)));
90 }
91 n = readl(ch.status);
92 }
93
94 return 0;
95}
96
Dima Zavinca337f52009-03-02 16:41:44 -080097static struct flash_info flash_info;
Dima Zavin03cf4312009-01-23 16:38:30 -080098
99static void flash_read_id(dmov_s *cmdlist, unsigned *ptrlist)
100{
101 dmov_s *cmd = cmdlist;
102 unsigned *ptr = ptrlist;
103 unsigned *data = ptrlist + 4;
Dima Zavinca337f52009-03-02 16:41:44 -0800104 unsigned parms;
Dima Zavin03cf4312009-01-23 16:38:30 -0800105
106 data[0] = 0 | 4;
107 data[1] = NAND_CMD_FETCH_ID;
108 data[2] = 1;
109 data[3] = 0;
110 data[4] = 0;
111
112 cmd[0].cmd = 0 | CMD_OCB;
113 cmd[0].src = paddr(&data[0]);
114 cmd[0].dst = NAND_FLASH_CHIP_SELECT;
115 cmd[0].len = 4;
116
117 cmd[1].cmd = DST_CRCI_NAND_CMD;
118 cmd[1].src = paddr(&data[1]);
119 cmd[1].dst = NAND_FLASH_CMD;
120 cmd[1].len = 4;
121
122 cmd[2].cmd = 0;
123 cmd[2].src = paddr(&data[2]);
124 cmd[2].dst = NAND_EXEC_CMD;
125 cmd[2].len = 4;
126
127 cmd[3].cmd = SRC_CRCI_NAND_DATA;
128 cmd[3].src = NAND_FLASH_STATUS;
129 cmd[3].dst = paddr(&data[3]);
130 cmd[3].len = 4;
131
132 cmd[4].cmd = CMD_OCU | CMD_LC;
133 cmd[4].src = NAND_READ_ID;
134 cmd[4].dst = paddr(&data[4]);
135 cmd[4].len = 4;
136
137 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
138
139 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
140
141#if VERBOSE
142 dprintf(INFO, "status: %x\n", data[3]);
143#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800144
Dima Zavinca337f52009-03-02 16:41:44 -0800145 flash_info.vendor = data[4] & 0xff;
146 flash_info.device = (data[4] >> 8) & 0xff;
147 flash_info.num_blocks = 0;
148 parms = data[4] >> 24;
149
150 if (flash_info.vendor == 0xec && flash_info.device == 0xaa)
151 flash_info.num_blocks = 2048; /* 256 MB */
152 ASSERT(flash_info.num_blocks);
153
154 flash_info.page_size = 1024 << (parms & 0x3);
155 flash_info.block_size = (64*1024) << ((parms >> 4) & 0x3);
156 flash_info.spare_size = (8 << ((parms >> 2) & 0x1));
157 flash_info.spare_size *= flash_info.page_size >> 9;
158
159 dprintf(INFO, "nandid: 0x%x maker=0x%02x device=0x%02x page_size=%d\n",
160 data[4], flash_info.vendor, flash_info.device,
161 flash_info.page_size);
162 dprintf(INFO, " spare_size=%d block_size=%d num_blocks=%d\n",
163 flash_info.spare_size, flash_info.block_size,
164 flash_info.num_blocks);
Dima Zavin03cf4312009-01-23 16:38:30 -0800165}
166
167static int flash_erase_block(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
168{
169 dmov_s *cmd = cmdlist;
170 unsigned *ptr = ptrlist;
171 unsigned *data = ptrlist + 4;
172
173 /* only allow erasing on block boundaries */
174 if(page & 63) return -1;
175
176 data[0] = NAND_CMD_BLOCK_ERASE;
177 data[1] = page;
178 data[2] = 0;
179 data[3] = 0 | 4;
180 data[4] = 1;
181 data[5] = 0xeeeeeeee;
182 data[6] = CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
183 data[7] = CFG1;
184
185 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
186 cmd[0].src = paddr(&data[0]);
187 cmd[0].dst = NAND_FLASH_CMD;
188 cmd[0].len = 16;
189
190 cmd[1].cmd = 0;
191 cmd[1].src = paddr(&data[6]);
192 cmd[1].dst = NAND_DEV0_CFG0;
193 cmd[1].len = 8;
194
195 cmd[2].cmd = 0;
196 cmd[2].src = paddr(&data[4]);
197 cmd[2].dst = NAND_EXEC_CMD;
198 cmd[2].len = 4;
199
200 cmd[3].cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
201 cmd[3].src = NAND_FLASH_STATUS;
202 cmd[3].dst = paddr(&data[5]);
203 cmd[3].len = 4;
204
205 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
206
207 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
208
209#if VERBOSE
210 dprintf(INFO, "status: %x\n", data[5]);
211#endif
212
213 /* we fail if there was an operation error, a mpu error, or the
214 ** erase success bit was not set.
215 */
216 if(data[5] & 0x110) return -1;
217 if(!(data[5] & 0x80)) return -1;
218
219 return 0;
220}
221
222struct data_flash_io {
223 unsigned cmd;
224 unsigned addr0;
225 unsigned addr1;
226 unsigned chipsel;
227 unsigned cfg0;
228 unsigned cfg1;
229 unsigned exec;
230 unsigned ecc_cfg;
231 unsigned ecc_cfg_save;
232 struct {
233 unsigned flash_status;
234 unsigned buffer_status;
235 } result[4];
236};
237
238static int _flash_read_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page, void *_addr, void *_spareaddr)
239{
240 dmov_s *cmd = cmdlist;
241 unsigned *ptr = ptrlist;
242 struct data_flash_io *data = (void*) (ptrlist + 4);
243 unsigned addr = (unsigned) _addr;
244 unsigned spareaddr = (unsigned) _spareaddr;
245 unsigned n;
246
247 data->cmd = NAND_CMD_PAGE_READ_ECC;
248 data->addr0 = page << 16;
249 data->addr1 = (page >> 16) & 0xff;
250 data->chipsel = 0 | 4; /* flash0 + undoc bit */
251
252 /* GO bit for the EXEC register */
253 data->exec = 1;
254
255 data->cfg0 = CFG0;
256 data->cfg1 = CFG1;
257
258 data->ecc_cfg = 0x203;
259
260 /* save existing ecc config */
261 cmd->cmd = CMD_OCB;
262 cmd->src = NAND_EBI2_ECC_BUF_CFG;
263 cmd->dst = paddr(&data->ecc_cfg_save);
264 cmd->len = 4;
265 cmd++;
266
267 for(n = 0; n < 4; n++) {
268 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
269 cmd->cmd = DST_CRCI_NAND_CMD;
270 cmd->src = paddr(&data->cmd);
271 cmd->dst = NAND_FLASH_CMD;
272 cmd->len = ((n == 0) ? 16 : 4);
273 cmd++;
274
275 if (n == 0) {
276 /* block on cmd ready, set configuration */
277 cmd->cmd = 0;
278 cmd->src = paddr(&data->cfg0);
279 cmd->dst = NAND_DEV0_CFG0;
280 cmd->len = 8;
281 cmd++;
282
283 /* set our ecc config */
284 cmd->cmd = 0;
285 cmd->src = paddr(&data->ecc_cfg);
286 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
287 cmd->len = 4;
288 cmd++;
289 }
290 /* kick the execute register */
291 cmd->cmd = 0;
292 cmd->src = paddr(&data->exec);
293 cmd->dst = NAND_EXEC_CMD;
294 cmd->len = 4;
295 cmd++;
296
297 /* block on data ready, then read the status register */
298 cmd->cmd = SRC_CRCI_NAND_DATA;
299 cmd->src = NAND_FLASH_STATUS;
300 cmd->dst = paddr(&data->result[n]);
301 cmd->len = 8;
302 cmd++;
303
304 /* read data block */
305 cmd->cmd = 0;
306 cmd->src = NAND_FLASH_BUFFER;
307 cmd->dst = addr + n * 516;
308 cmd->len = ((n < 3) ? 516 : 500);
309 cmd++;
310 }
311
312 /* read extra data */
313 cmd->cmd = 0;
314 cmd->src = NAND_FLASH_BUFFER + 500;
315 cmd->dst = spareaddr;
316 cmd->len = 16;
317 cmd++;
318
319 /* restore saved ecc config */
320 cmd->cmd = CMD_OCU | CMD_LC;
321 cmd->src = paddr(&data->ecc_cfg_save);
322 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
323 cmd->len = 4;
324
325 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
326
327 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
328
329#if VERBOSE
330 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
331 page, data[5], data[6], data[7], data[8]);
332 for(n = 0; n < 4; n++) {
333 ptr = (unsigned*)(addr + 512 * n);
334 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
335 ptr = (unsigned*)(spareaddr + 16 * n);
336 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
337 }
338#endif
339
340 /* if any of the writes failed (0x10), or there was a
341 ** protection violation (0x100), we lose
342 */
343 for(n = 0; n < 4; n++) {
344 if (data->result[n].flash_status & 0x110) {
345 return -1;
346 }
347 }
348
349 return 0;
350}
351
352static int _flash_write_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page,
353 const void *_addr, const void *_spareaddr)
354{
355 dmov_s *cmd = cmdlist;
356 unsigned *ptr = ptrlist;
357 struct data_flash_io *data = (void*) (ptrlist + 4);
358 unsigned addr = (unsigned) _addr;
359 unsigned spareaddr = (unsigned) _spareaddr;
360 unsigned n;
361
362 data->cmd = NAND_CMD_PRG_PAGE;
363 data->addr0 = page << 16;
364 data->addr1 = (page >> 16) & 0xff;
365 data->chipsel = 0 | 4; /* flash0 + undoc bit */
366
367 data->cfg0 = CFG0;
368 data->cfg1 = CFG1;
369
370 /* GO bit for the EXEC register */
371 data->exec = 1;
372
373 data->ecc_cfg = 0x203;
374
375 /* save existing ecc config */
376 cmd->cmd = CMD_OCB;
377 cmd->src = NAND_EBI2_ECC_BUF_CFG;
378 cmd->dst = paddr(&data->ecc_cfg_save);
379 cmd->len = 4;
380 cmd++;
381
382 for(n = 0; n < 4; n++) {
383 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
384 cmd->cmd = DST_CRCI_NAND_CMD;
385 cmd->src = paddr(&data->cmd);
386 cmd->dst = NAND_FLASH_CMD;
387 cmd->len = ((n == 0) ? 16 : 4);
388 cmd++;
389
390 if (n == 0) {
391 /* set configuration */
392 cmd->cmd = 0;
393 cmd->src = paddr(&data->cfg0);
394 cmd->dst = NAND_DEV0_CFG0;
395 cmd->len = 8;
396 cmd++;
397
398 /* set our ecc config */
399 cmd->cmd = 0;
400 cmd->src = paddr(&data->ecc_cfg);
401 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
402 cmd->len = 4;
403 cmd++;
404 }
405
406 /* write data block */
407 cmd->cmd = 0;
408 cmd->src = addr + n * 516;
409 cmd->dst = NAND_FLASH_BUFFER;
410 cmd->len = ((n < 3) ? 516 : 510);
411 cmd++;
412
413 if (n == 3) {
414 /* write extra data */
415 cmd->cmd = 0;
416 cmd->src = spareaddr;
417 cmd->dst = NAND_FLASH_BUFFER + 500;
418 cmd->len = 16;
419 cmd++;
420 }
421
422 /* kick the execute register */
423 cmd->cmd = 0;
424 cmd->src = paddr(&data->exec);
425 cmd->dst = NAND_EXEC_CMD;
426 cmd->len = 4;
427 cmd++;
428
429 /* block on data ready, then read the status register */
430 cmd->cmd = SRC_CRCI_NAND_DATA;
431 cmd->src = NAND_FLASH_STATUS;
432 cmd->dst = paddr(&data->result[n]);
433 cmd->len = 8;
434 cmd++;
435 }
436
437 /* restore saved ecc config */
438 cmd->cmd = CMD_OCU | CMD_LC;
439 cmd->src = paddr(&data->ecc_cfg_save);
440 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
441 cmd->len = 4;
442
443 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
444
445 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
446
447#if VERBOSE
448 dprintf(INFO, "write page %d: status: %x %x %x %x\n",
449 page, data[5], data[6], data[7], data[8]);
450#endif
451
452 /* if any of the writes failed (0x10), or there was a
453 ** protection violation (0x100), or the program success
454 ** bit (0x80) is unset, we lose
455 */
456 for(n = 0; n < 4; n++) {
457 if(data->result[n].flash_status & 0x110) return -1;
458 if(!(data->result[n].flash_status & 0x80)) return -1;
459 }
460
461 return 0;
462}
463
464static int flash_read_config(dmov_s *cmdlist, unsigned *ptrlist)
465{
466 cmdlist[0].cmd = CMD_OCB;
467 cmdlist[0].src = NAND_DEV0_CFG0;
468 cmdlist[0].dst = paddr(&CFG0);
469 cmdlist[0].len = 4;
470
471 cmdlist[1].cmd = CMD_OCU | CMD_LC;
472 cmdlist[1].src = NAND_DEV0_CFG1;
473 cmdlist[1].dst = paddr(&CFG1);
474 cmdlist[1].len = 4;
475
476 *ptrlist = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
477
478 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptrlist);
479
480 if((CFG0 == 0) || (CFG1 == 0)) {
481 return -1;
482 }
483
484 dprintf(INFO, "nandcfg: %x %x (initial)\n", CFG0, CFG1);
485
486 CFG0 = (3 << 6) /* 4 codeword per page for 2k nand */
487 | (516 << 9) /* 516 user data bytes */
488 | (10 << 19) /* 10 parity bytes */
489 | (5 << 27) /* 5 address cycles */
490 | (1 << 30) /* Read status before data */
491 | (1 << 31) /* Send read cmd */
492 /* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
493 | ((CFG1 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
494 CFG1 = (0 << 0) /* Enable ecc */
495 | (7 << 2) /* 8 recovery cycles */
496 | (0 << 5) /* Allow CS deassertion */
497 | (465 << 6) /* Bad block marker location */
498 | (0 << 16) /* Bad block in user data area */
499 | (2 << 17) /* 6 cycle tWB/tRB */
500 | (CFG1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
501
502 dprintf(INFO, "nandcfg: %x %x (used)\n", CFG0, CFG1);
503
504 return 0;
505}
506
507static unsigned *flash_ptrlist;
508static dmov_s *flash_cmdlist;
509static void *flash_spare;
510static void *flash_data;
511
512static struct ptable *flash_ptable = NULL;
513
Dima Zavine5f64352009-03-02 16:04:20 -0800514void flash_init(void)
Dima Zavin03cf4312009-01-23 16:38:30 -0800515{
Dima Zavine5f64352009-03-02 16:04:20 -0800516 ASSERT(flash_ptable == NULL);
Dima Zavin03cf4312009-01-23 16:38:30 -0800517
518 flash_ptrlist = memalign(32, 1024);
519 flash_cmdlist = memalign(32, 1024);
520 flash_data = memalign(32, 2048);
521 flash_spare = memalign(32, 64);
522
523 if(flash_read_config(flash_cmdlist, flash_ptrlist)) {
524 dprintf(CRITICAL, "ERROR: could not read CFG0/CFG1 state\n");
525 ASSERT(0);
526 }
527
528 flash_read_id(flash_cmdlist, flash_ptrlist);
529}
530
531struct ptable *flash_get_ptable(void)
532{
533 return flash_ptable;
534}
535
Dima Zavine5f64352009-03-02 16:04:20 -0800536void flash_set_ptable(struct ptable *new_ptable)
537{
538 ASSERT(flash_ptable == NULL && new_ptable != NULL);
539 flash_ptable = new_ptable;
540}
541
Dima Zavinca337f52009-03-02 16:41:44 -0800542struct flash_info *flash_get_info(void)
543{
544 return &flash_info;
545}
546
Dima Zavin03cf4312009-01-23 16:38:30 -0800547int flash_erase(struct ptentry *ptn)
548{
549 unsigned block = ptn->start;
550 unsigned count = ptn->length;
551
552 while(count-- > 0) {
553 if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * 64)) {
554 dprintf(INFO, "cannot erase @ %d (bad block?)\n", block);
555 }
556 block++;
557 }
558 return 0;
559}
560
561int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page,
562 unsigned offset, void *data, unsigned bytes)
563{
564 unsigned page = (ptn->start * 64) + (offset / 2048);
565 unsigned lastpage = (ptn->start + ptn->length) * 64;
566 unsigned count = (bytes + 2047 + extra_per_page) / (2048 + extra_per_page);
567 unsigned *spare = (unsigned*) flash_spare;
568 unsigned errors = 0;
569 unsigned char *image = data;
570
571 if(offset & 2047)
572 return -1;
573
574 while(page < lastpage) {
575 if(count == 0) {
576 dprintf(INFO, "flash_read_image: success (%d errors)\n", errors);
577 return 0;
578 }
579
580 if(_flash_read_page(flash_cmdlist, flash_ptrlist, page++, image, spare)) {
581 errors++;
582 continue;
583 }
584 image += 2048;
585 memcpy(image, spare, extra_per_page);
586 image += extra_per_page;
587 count -= 1;
588 }
589
590 /* could not find enough valid pages before we hit the end */
591 dprintf(INFO, "flash_read_image: failed (%d errors)\n", errors);
592 return 0xffffffff;
593}
594
595int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data,
596 unsigned bytes)
597{
598 unsigned page = ptn->start * 64;
599 unsigned lastpage = (ptn->start + ptn->length) * 64;
600 unsigned *spare = (unsigned*) flash_spare;
601 const unsigned char *image = data;
602 unsigned wsize = 2048 + extra_per_page;
603 unsigned n;
604 int r;
605
606 for(n = 0; n < 16; n++) spare[n] = 0xffffffff;
607
608 while(bytes > 0) {
609 if(bytes < wsize) {
610 dprintf(CRITICAL, "flash_write_image: image undersized (%d < %d)\n", bytes, wsize);
611 return -1;
612 }
613 if(page >= lastpage) {
614 dprintf(CRITICAL, "flash_write_image: out of space\n");
615 return -1;
616 }
617
618 if((page & 63) == 0) {
619 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
620 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
621 page += 64;
622 continue;
623 }
624 }
625
626 if(extra_per_page) {
627 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, image + 2048);
628 } else {
629 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, spare);
630 }
631 if(r) {
632 dprintf(INFO, "flash_write_image: write failure @ page %d (src %d)\n", page, image - (const unsigned char *)data);
633 image -= (page & 63) * wsize;
634 bytes += (page & 63) * wsize;
635 page &= ~63;
636 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
637 dprintf(INFO, "flash_write_image: erase failure @ page %d\n", page);
638 }
639 dprintf(INFO, "flash_write_image: restart write @ page %d (src %d)\n", page, image - (const unsigned char *)data);
640 page += 64;
641 continue;
642 }
643
644 image += wsize;
645 bytes -= wsize;
646 }
647
648 /* erase any remaining pages in the partition */
649 page = (page + 63) & (~63);
650 while(page < lastpage){
651 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
652 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
653 }
654 page += 64;
655 }
656
657 dprintf(INFO, "flash_write_image: success\n");
658 return 0;
659}
660
661#if 0
662static int flash_read_page(unsigned page, void *data, void *extra)
663{
664 return _flash_read_page(flash_cmdlist, flash_ptrlist,
665 page, data, extra);
666}
667#endif