blob: 7598ffa4eef6612416f62e1dc63d1e0c69261d0e [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
Dima Zavin5582c7d2009-03-03 15:17:59 -080040#define VERIFY_WRITE 0
41
42static void *flash_spare;
43static void *flash_data;
Dima Zavin03cf4312009-01-23 16:38:30 -080044
45typedef struct dmov_ch dmov_ch;
46struct dmov_ch
47{
48 volatile unsigned cmd;
49 volatile unsigned result;
50 volatile unsigned status;
51 volatile unsigned config;
52};
53
54static void dmov_prep_ch(dmov_ch *ch, unsigned id)
55{
56 ch->cmd = DMOV_CMD_PTR(id);
57 ch->result = DMOV_RSLT(id);
58 ch->status = DMOV_STATUS(id);
59 ch->config = DMOV_CONFIG(id);
60}
61
62#define SRC_CRCI_NAND_CMD CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
63#define DST_CRCI_NAND_CMD CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
64#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
65#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
66
67static unsigned CFG0, CFG1;
68
69#define CFG1_WIDE_FLASH (1U << 1)
70
71#define paddr(n) ((unsigned) (n))
72
73static int dmov_exec_cmdptr(unsigned id, unsigned *ptr)
74{
75 dmov_ch ch;
76 unsigned n;
77
78 dmov_prep_ch(&ch, id);
79
80 writel(DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(paddr(ptr)), ch.cmd);
81
82 while(!(readl(ch.status) & DMOV_STATUS_RSLT_VALID)) ;
83
84 n = readl(ch.status);
85 while(DMOV_STATUS_RSLT_COUNT(n)) {
86 n = readl(ch.result);
87 if(n != 0x80000002) {
88 dprintf(CRITICAL, "ERROR: result: %x\n", n);
89 dprintf(CRITICAL, "ERROR: flush: %x %x %x %x\n",
90 readl(DMOV_FLUSH0(DMOV_NAND_CHAN)),
91 readl(DMOV_FLUSH1(DMOV_NAND_CHAN)),
92 readl(DMOV_FLUSH2(DMOV_NAND_CHAN)),
93 readl(DMOV_FLUSH3(DMOV_NAND_CHAN)));
94 }
95 n = readl(ch.status);
96 }
97
98 return 0;
99}
100
Dima Zavinca337f52009-03-02 16:41:44 -0800101static struct flash_info flash_info;
Dima Zavin03cf4312009-01-23 16:38:30 -0800102
103static void flash_read_id(dmov_s *cmdlist, unsigned *ptrlist)
104{
105 dmov_s *cmd = cmdlist;
106 unsigned *ptr = ptrlist;
107 unsigned *data = ptrlist + 4;
Dima Zavinca337f52009-03-02 16:41:44 -0800108 unsigned parms;
Dima Zavin03cf4312009-01-23 16:38:30 -0800109
110 data[0] = 0 | 4;
111 data[1] = NAND_CMD_FETCH_ID;
112 data[2] = 1;
113 data[3] = 0;
114 data[4] = 0;
115
116 cmd[0].cmd = 0 | CMD_OCB;
117 cmd[0].src = paddr(&data[0]);
118 cmd[0].dst = NAND_FLASH_CHIP_SELECT;
119 cmd[0].len = 4;
120
121 cmd[1].cmd = DST_CRCI_NAND_CMD;
122 cmd[1].src = paddr(&data[1]);
123 cmd[1].dst = NAND_FLASH_CMD;
124 cmd[1].len = 4;
125
126 cmd[2].cmd = 0;
127 cmd[2].src = paddr(&data[2]);
128 cmd[2].dst = NAND_EXEC_CMD;
129 cmd[2].len = 4;
130
131 cmd[3].cmd = SRC_CRCI_NAND_DATA;
132 cmd[3].src = NAND_FLASH_STATUS;
133 cmd[3].dst = paddr(&data[3]);
134 cmd[3].len = 4;
135
136 cmd[4].cmd = CMD_OCU | CMD_LC;
137 cmd[4].src = NAND_READ_ID;
138 cmd[4].dst = paddr(&data[4]);
139 cmd[4].len = 4;
140
141 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
142
143 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
144
145#if VERBOSE
146 dprintf(INFO, "status: %x\n", data[3]);
147#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800148
Dima Zavinca337f52009-03-02 16:41:44 -0800149 flash_info.vendor = data[4] & 0xff;
150 flash_info.device = (data[4] >> 8) & 0xff;
151 flash_info.num_blocks = 0;
152 parms = data[4] >> 24;
153
154 if (flash_info.vendor == 0xec && flash_info.device == 0xaa)
155 flash_info.num_blocks = 2048; /* 256 MB */
156 ASSERT(flash_info.num_blocks);
157
158 flash_info.page_size = 1024 << (parms & 0x3);
159 flash_info.block_size = (64*1024) << ((parms >> 4) & 0x3);
160 flash_info.spare_size = (8 << ((parms >> 2) & 0x1));
161 flash_info.spare_size *= flash_info.page_size >> 9;
162
163 dprintf(INFO, "nandid: 0x%x maker=0x%02x device=0x%02x page_size=%d\n",
164 data[4], flash_info.vendor, flash_info.device,
165 flash_info.page_size);
166 dprintf(INFO, " spare_size=%d block_size=%d num_blocks=%d\n",
167 flash_info.spare_size, flash_info.block_size,
168 flash_info.num_blocks);
Dima Zavin03cf4312009-01-23 16:38:30 -0800169}
170
171static int flash_erase_block(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
172{
173 dmov_s *cmd = cmdlist;
174 unsigned *ptr = ptrlist;
175 unsigned *data = ptrlist + 4;
176
177 /* only allow erasing on block boundaries */
178 if(page & 63) return -1;
179
180 data[0] = NAND_CMD_BLOCK_ERASE;
181 data[1] = page;
182 data[2] = 0;
183 data[3] = 0 | 4;
184 data[4] = 1;
185 data[5] = 0xeeeeeeee;
186 data[6] = CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
187 data[7] = CFG1;
188
189 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
190 cmd[0].src = paddr(&data[0]);
191 cmd[0].dst = NAND_FLASH_CMD;
192 cmd[0].len = 16;
193
194 cmd[1].cmd = 0;
195 cmd[1].src = paddr(&data[6]);
196 cmd[1].dst = NAND_DEV0_CFG0;
197 cmd[1].len = 8;
198
199 cmd[2].cmd = 0;
200 cmd[2].src = paddr(&data[4]);
201 cmd[2].dst = NAND_EXEC_CMD;
202 cmd[2].len = 4;
203
204 cmd[3].cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
205 cmd[3].src = NAND_FLASH_STATUS;
206 cmd[3].dst = paddr(&data[5]);
207 cmd[3].len = 4;
208
209 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
210
211 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
212
213#if VERBOSE
214 dprintf(INFO, "status: %x\n", data[5]);
215#endif
216
217 /* we fail if there was an operation error, a mpu error, or the
218 ** erase success bit was not set.
219 */
220 if(data[5] & 0x110) return -1;
221 if(!(data[5] & 0x80)) return -1;
222
223 return 0;
224}
225
226struct data_flash_io {
227 unsigned cmd;
228 unsigned addr0;
229 unsigned addr1;
230 unsigned chipsel;
231 unsigned cfg0;
232 unsigned cfg1;
233 unsigned exec;
234 unsigned ecc_cfg;
235 unsigned ecc_cfg_save;
236 struct {
237 unsigned flash_status;
238 unsigned buffer_status;
239 } result[4];
240};
241
242static int _flash_read_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page, void *_addr, void *_spareaddr)
243{
244 dmov_s *cmd = cmdlist;
245 unsigned *ptr = ptrlist;
246 struct data_flash_io *data = (void*) (ptrlist + 4);
247 unsigned addr = (unsigned) _addr;
248 unsigned spareaddr = (unsigned) _spareaddr;
249 unsigned n;
250
251 data->cmd = NAND_CMD_PAGE_READ_ECC;
252 data->addr0 = page << 16;
253 data->addr1 = (page >> 16) & 0xff;
254 data->chipsel = 0 | 4; /* flash0 + undoc bit */
255
256 /* GO bit for the EXEC register */
257 data->exec = 1;
258
259 data->cfg0 = CFG0;
260 data->cfg1 = CFG1;
261
262 data->ecc_cfg = 0x203;
263
264 /* save existing ecc config */
265 cmd->cmd = CMD_OCB;
266 cmd->src = NAND_EBI2_ECC_BUF_CFG;
267 cmd->dst = paddr(&data->ecc_cfg_save);
268 cmd->len = 4;
269 cmd++;
270
271 for(n = 0; n < 4; n++) {
272 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
273 cmd->cmd = DST_CRCI_NAND_CMD;
274 cmd->src = paddr(&data->cmd);
275 cmd->dst = NAND_FLASH_CMD;
276 cmd->len = ((n == 0) ? 16 : 4);
277 cmd++;
278
279 if (n == 0) {
280 /* block on cmd ready, set configuration */
281 cmd->cmd = 0;
282 cmd->src = paddr(&data->cfg0);
283 cmd->dst = NAND_DEV0_CFG0;
284 cmd->len = 8;
285 cmd++;
286
287 /* set our ecc config */
288 cmd->cmd = 0;
289 cmd->src = paddr(&data->ecc_cfg);
290 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
291 cmd->len = 4;
292 cmd++;
293 }
294 /* kick the execute register */
295 cmd->cmd = 0;
296 cmd->src = paddr(&data->exec);
297 cmd->dst = NAND_EXEC_CMD;
298 cmd->len = 4;
299 cmd++;
300
301 /* block on data ready, then read the status register */
302 cmd->cmd = SRC_CRCI_NAND_DATA;
303 cmd->src = NAND_FLASH_STATUS;
304 cmd->dst = paddr(&data->result[n]);
305 cmd->len = 8;
306 cmd++;
307
308 /* read data block */
309 cmd->cmd = 0;
310 cmd->src = NAND_FLASH_BUFFER;
311 cmd->dst = addr + n * 516;
312 cmd->len = ((n < 3) ? 516 : 500);
313 cmd++;
314 }
315
316 /* read extra data */
317 cmd->cmd = 0;
318 cmd->src = NAND_FLASH_BUFFER + 500;
319 cmd->dst = spareaddr;
320 cmd->len = 16;
321 cmd++;
322
323 /* restore saved ecc config */
324 cmd->cmd = CMD_OCU | CMD_LC;
325 cmd->src = paddr(&data->ecc_cfg_save);
326 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
327 cmd->len = 4;
328
329 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
330
331 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
332
333#if VERBOSE
334 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
335 page, data[5], data[6], data[7], data[8]);
336 for(n = 0; n < 4; n++) {
337 ptr = (unsigned*)(addr + 512 * n);
338 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
339 ptr = (unsigned*)(spareaddr + 16 * n);
340 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
341 }
342#endif
343
344 /* if any of the writes failed (0x10), or there was a
345 ** protection violation (0x100), we lose
346 */
347 for(n = 0; n < 4; n++) {
348 if (data->result[n].flash_status & 0x110) {
349 return -1;
350 }
351 }
352
353 return 0;
354}
355
356static int _flash_write_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page,
357 const void *_addr, const void *_spareaddr)
358{
359 dmov_s *cmd = cmdlist;
360 unsigned *ptr = ptrlist;
361 struct data_flash_io *data = (void*) (ptrlist + 4);
362 unsigned addr = (unsigned) _addr;
363 unsigned spareaddr = (unsigned) _spareaddr;
364 unsigned n;
365
366 data->cmd = NAND_CMD_PRG_PAGE;
367 data->addr0 = page << 16;
368 data->addr1 = (page >> 16) & 0xff;
369 data->chipsel = 0 | 4; /* flash0 + undoc bit */
370
371 data->cfg0 = CFG0;
372 data->cfg1 = CFG1;
373
374 /* GO bit for the EXEC register */
375 data->exec = 1;
376
377 data->ecc_cfg = 0x203;
378
379 /* save existing ecc config */
380 cmd->cmd = CMD_OCB;
381 cmd->src = NAND_EBI2_ECC_BUF_CFG;
382 cmd->dst = paddr(&data->ecc_cfg_save);
383 cmd->len = 4;
384 cmd++;
385
386 for(n = 0; n < 4; n++) {
387 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
388 cmd->cmd = DST_CRCI_NAND_CMD;
389 cmd->src = paddr(&data->cmd);
390 cmd->dst = NAND_FLASH_CMD;
391 cmd->len = ((n == 0) ? 16 : 4);
392 cmd++;
393
394 if (n == 0) {
395 /* set configuration */
396 cmd->cmd = 0;
397 cmd->src = paddr(&data->cfg0);
398 cmd->dst = NAND_DEV0_CFG0;
399 cmd->len = 8;
400 cmd++;
401
402 /* set our ecc config */
403 cmd->cmd = 0;
404 cmd->src = paddr(&data->ecc_cfg);
405 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
406 cmd->len = 4;
407 cmd++;
408 }
409
410 /* write data block */
411 cmd->cmd = 0;
412 cmd->src = addr + n * 516;
413 cmd->dst = NAND_FLASH_BUFFER;
414 cmd->len = ((n < 3) ? 516 : 510);
415 cmd++;
416
417 if (n == 3) {
418 /* write extra data */
419 cmd->cmd = 0;
420 cmd->src = spareaddr;
421 cmd->dst = NAND_FLASH_BUFFER + 500;
422 cmd->len = 16;
423 cmd++;
424 }
425
426 /* kick the execute register */
427 cmd->cmd = 0;
428 cmd->src = paddr(&data->exec);
429 cmd->dst = NAND_EXEC_CMD;
430 cmd->len = 4;
431 cmd++;
432
433 /* block on data ready, then read the status register */
434 cmd->cmd = SRC_CRCI_NAND_DATA;
435 cmd->src = NAND_FLASH_STATUS;
436 cmd->dst = paddr(&data->result[n]);
437 cmd->len = 8;
438 cmd++;
439 }
440
441 /* restore saved ecc config */
442 cmd->cmd = CMD_OCU | CMD_LC;
443 cmd->src = paddr(&data->ecc_cfg_save);
444 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
445 cmd->len = 4;
446
447 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
448
449 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
450
451#if VERBOSE
452 dprintf(INFO, "write page %d: status: %x %x %x %x\n",
453 page, data[5], data[6], data[7], data[8]);
454#endif
455
456 /* if any of the writes failed (0x10), or there was a
457 ** protection violation (0x100), or the program success
458 ** bit (0x80) is unset, we lose
459 */
460 for(n = 0; n < 4; n++) {
461 if(data->result[n].flash_status & 0x110) return -1;
462 if(!(data->result[n].flash_status & 0x80)) return -1;
463 }
464
Dima Zavin5582c7d2009-03-03 15:17:59 -0800465#if VERIFY_WRITE
466 n = _flash_read_page(cmdlist, ptrlist, page, flash_data,
467 flash_data + 2048);
468 if (n != 0)
469 return -1;
470 if (memcmp(flash_data, _addr, 2048) ||
471 memcmp(flash_data + 2048, _spareaddr, 16)) {
472 dprintf(CRITICAL, "verify error @ page %d\n", page);
473 return -1;
474 }
475#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800476 return 0;
477}
478
479static int flash_read_config(dmov_s *cmdlist, unsigned *ptrlist)
480{
481 cmdlist[0].cmd = CMD_OCB;
482 cmdlist[0].src = NAND_DEV0_CFG0;
483 cmdlist[0].dst = paddr(&CFG0);
484 cmdlist[0].len = 4;
485
486 cmdlist[1].cmd = CMD_OCU | CMD_LC;
487 cmdlist[1].src = NAND_DEV0_CFG1;
488 cmdlist[1].dst = paddr(&CFG1);
489 cmdlist[1].len = 4;
490
491 *ptrlist = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
492
493 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptrlist);
494
495 if((CFG0 == 0) || (CFG1 == 0)) {
496 return -1;
497 }
498
499 dprintf(INFO, "nandcfg: %x %x (initial)\n", CFG0, CFG1);
500
501 CFG0 = (3 << 6) /* 4 codeword per page for 2k nand */
502 | (516 << 9) /* 516 user data bytes */
503 | (10 << 19) /* 10 parity bytes */
504 | (5 << 27) /* 5 address cycles */
505 | (1 << 30) /* Read status before data */
506 | (1 << 31) /* Send read cmd */
507 /* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
508 | ((CFG1 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
509 CFG1 = (0 << 0) /* Enable ecc */
510 | (7 << 2) /* 8 recovery cycles */
511 | (0 << 5) /* Allow CS deassertion */
512 | (465 << 6) /* Bad block marker location */
513 | (0 << 16) /* Bad block in user data area */
514 | (2 << 17) /* 6 cycle tWB/tRB */
515 | (CFG1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
516
517 dprintf(INFO, "nandcfg: %x %x (used)\n", CFG0, CFG1);
518
519 return 0;
520}
521
522static unsigned *flash_ptrlist;
523static dmov_s *flash_cmdlist;
Dima Zavin03cf4312009-01-23 16:38:30 -0800524
525static struct ptable *flash_ptable = NULL;
526
Dima Zavine5f64352009-03-02 16:04:20 -0800527void flash_init(void)
Dima Zavin03cf4312009-01-23 16:38:30 -0800528{
Dima Zavine5f64352009-03-02 16:04:20 -0800529 ASSERT(flash_ptable == NULL);
Dima Zavin03cf4312009-01-23 16:38:30 -0800530
531 flash_ptrlist = memalign(32, 1024);
532 flash_cmdlist = memalign(32, 1024);
Dima Zavin5582c7d2009-03-03 15:17:59 -0800533 flash_data = memalign(32, 2048 + 64);
Dima Zavin03cf4312009-01-23 16:38:30 -0800534 flash_spare = memalign(32, 64);
535
536 if(flash_read_config(flash_cmdlist, flash_ptrlist)) {
537 dprintf(CRITICAL, "ERROR: could not read CFG0/CFG1 state\n");
538 ASSERT(0);
539 }
540
541 flash_read_id(flash_cmdlist, flash_ptrlist);
542}
543
544struct ptable *flash_get_ptable(void)
545{
546 return flash_ptable;
547}
548
Dima Zavine5f64352009-03-02 16:04:20 -0800549void flash_set_ptable(struct ptable *new_ptable)
550{
551 ASSERT(flash_ptable == NULL && new_ptable != NULL);
552 flash_ptable = new_ptable;
553}
554
Dima Zavinca337f52009-03-02 16:41:44 -0800555struct flash_info *flash_get_info(void)
556{
557 return &flash_info;
558}
559
Dima Zavin03cf4312009-01-23 16:38:30 -0800560int flash_erase(struct ptentry *ptn)
561{
562 unsigned block = ptn->start;
563 unsigned count = ptn->length;
564
565 while(count-- > 0) {
566 if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * 64)) {
567 dprintf(INFO, "cannot erase @ %d (bad block?)\n", block);
568 }
569 block++;
570 }
571 return 0;
572}
573
574int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page,
575 unsigned offset, void *data, unsigned bytes)
576{
577 unsigned page = (ptn->start * 64) + (offset / 2048);
578 unsigned lastpage = (ptn->start + ptn->length) * 64;
579 unsigned count = (bytes + 2047 + extra_per_page) / (2048 + extra_per_page);
580 unsigned *spare = (unsigned*) flash_spare;
581 unsigned errors = 0;
582 unsigned char *image = data;
583
584 if(offset & 2047)
585 return -1;
586
587 while(page < lastpage) {
588 if(count == 0) {
589 dprintf(INFO, "flash_read_image: success (%d errors)\n", errors);
590 return 0;
591 }
592
593 if(_flash_read_page(flash_cmdlist, flash_ptrlist, page++, image, spare)) {
594 errors++;
595 continue;
596 }
597 image += 2048;
598 memcpy(image, spare, extra_per_page);
599 image += extra_per_page;
600 count -= 1;
601 }
602
603 /* could not find enough valid pages before we hit the end */
604 dprintf(INFO, "flash_read_image: failed (%d errors)\n", errors);
605 return 0xffffffff;
606}
607
608int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data,
609 unsigned bytes)
610{
611 unsigned page = ptn->start * 64;
612 unsigned lastpage = (ptn->start + ptn->length) * 64;
613 unsigned *spare = (unsigned*) flash_spare;
614 const unsigned char *image = data;
615 unsigned wsize = 2048 + extra_per_page;
616 unsigned n;
617 int r;
618
619 for(n = 0; n < 16; n++) spare[n] = 0xffffffff;
620
621 while(bytes > 0) {
622 if(bytes < wsize) {
623 dprintf(CRITICAL, "flash_write_image: image undersized (%d < %d)\n", bytes, wsize);
624 return -1;
625 }
626 if(page >= lastpage) {
627 dprintf(CRITICAL, "flash_write_image: out of space\n");
628 return -1;
629 }
630
631 if((page & 63) == 0) {
632 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
633 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
634 page += 64;
635 continue;
636 }
637 }
638
639 if(extra_per_page) {
640 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, image + 2048);
641 } else {
642 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page++, image, spare);
643 }
644 if(r) {
645 dprintf(INFO, "flash_write_image: write failure @ page %d (src %d)\n", page, image - (const unsigned char *)data);
646 image -= (page & 63) * wsize;
647 bytes += (page & 63) * wsize;
648 page &= ~63;
649 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
650 dprintf(INFO, "flash_write_image: erase failure @ page %d\n", page);
651 }
652 dprintf(INFO, "flash_write_image: restart write @ page %d (src %d)\n", page, image - (const unsigned char *)data);
653 page += 64;
654 continue;
655 }
656
657 image += wsize;
658 bytes -= wsize;
659 }
660
661 /* erase any remaining pages in the partition */
662 page = (page + 63) & (~63);
663 while(page < lastpage){
664 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
665 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
666 }
667 page += 64;
668 }
669
670 dprintf(INFO, "flash_write_image: success\n");
671 return 0;
672}
673
674#if 0
675static int flash_read_page(unsigned page, void *data, void *extra)
676{
677 return _flash_read_page(flash_cmdlist, flash_ptrlist,
678 page, data, extra);
679}
680#endif