Savevm/loadvm bits for ARM core, the PXA2xx peripherals and Spitz hardware.
[qemu] / hw / nand.c
1 /*
2  * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
3  * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
4  * Samsung Electronic.
5  *
6  * Copyright (c) 2006 Openedhand Ltd.
7  * Written by Andrzej Zaborowski <balrog@zabor.org>
8  *
9  * This code is licensed under the GNU GPL v2.
10  */
11
12 #ifndef NAND_IO
13
14 # include "vl.h"
15
16 # define NAND_CMD_READ0         0x00
17 # define NAND_CMD_READ1         0x01
18 # define NAND_CMD_READ2         0x50
19 # define NAND_CMD_LPREAD2       0x30
20 # define NAND_CMD_NOSERIALREAD2 0x35
21 # define NAND_CMD_RANDOMREAD1   0x05
22 # define NAND_CMD_RANDOMREAD2   0xe0
23 # define NAND_CMD_READID        0x90
24 # define NAND_CMD_RESET         0xff
25 # define NAND_CMD_PAGEPROGRAM1  0x80
26 # define NAND_CMD_PAGEPROGRAM2  0x10
27 # define NAND_CMD_CACHEPROGRAM2 0x15
28 # define NAND_CMD_BLOCKERASE1   0x60
29 # define NAND_CMD_BLOCKERASE2   0xd0
30 # define NAND_CMD_READSTATUS    0x70
31 # define NAND_CMD_COPYBACKPRG1  0x85
32
33 # define NAND_IOSTATUS_ERROR    (1 << 0)
34 # define NAND_IOSTATUS_PLANE0   (1 << 1)
35 # define NAND_IOSTATUS_PLANE1   (1 << 2)
36 # define NAND_IOSTATUS_PLANE2   (1 << 3)
37 # define NAND_IOSTATUS_PLANE3   (1 << 4)
38 # define NAND_IOSTATUS_BUSY     (1 << 6)
39 # define NAND_IOSTATUS_UNPROTCT (1 << 7)
40
41 # define MAX_PAGE               0x800
42 # define MAX_OOB                0x40
43
44 struct nand_flash_s {
45     uint8_t manf_id, chip_id;
46     int size, pages;
47     int page_shift, oob_shift, erase_shift, addr_shift;
48     uint8_t *storage;
49     BlockDriverState *bdrv;
50     int mem_oob;
51
52     int cle, ale, ce, wp, gnd;
53
54     uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
55     uint8_t *ioaddr;
56     int iolen;
57
58     uint32_t cmd, addr;
59     int addrlen;
60     int status;
61     int offset;
62
63     void (*blk_write)(struct nand_flash_s *s);
64     void (*blk_erase)(struct nand_flash_s *s);
65     void (*blk_load)(struct nand_flash_s *s, uint32_t addr, int offset);
66 };
67
68 # define NAND_NO_AUTOINCR       0x00000001
69 # define NAND_BUSWIDTH_16       0x00000002
70 # define NAND_NO_PADDING        0x00000004
71 # define NAND_CACHEPRG          0x00000008
72 # define NAND_COPYBACK          0x00000010
73 # define NAND_IS_AND            0x00000020
74 # define NAND_4PAGE_ARRAY       0x00000040
75 # define NAND_NO_READRDY        0x00000100
76 # define NAND_SAMSUNG_LP        (NAND_NO_PADDING | NAND_COPYBACK)
77
78 # define NAND_IO
79
80 # define PAGE(addr)             ((addr) >> ADDR_SHIFT)
81 # define PAGE_START(page)       (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
82 # define PAGE_MASK              ((1 << ADDR_SHIFT) - 1)
83 # define OOB_SHIFT              (PAGE_SHIFT - 5)
84 # define OOB_SIZE               (1 << OOB_SHIFT)
85 # define SECTOR(addr)           ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
86 # define SECTOR_OFFSET(addr)    ((addr) & ((511 >> PAGE_SHIFT) << 8))
87
88 # define PAGE_SIZE              256
89 # define PAGE_SHIFT             8
90 # define PAGE_SECTORS           1
91 # define ADDR_SHIFT             8
92 # include "nand.c"
93 # define PAGE_SIZE              512
94 # define PAGE_SHIFT             9
95 # define PAGE_SECTORS           1
96 # define ADDR_SHIFT             8
97 # include "nand.c"
98 # define PAGE_SIZE              2048
99 # define PAGE_SHIFT             11
100 # define PAGE_SECTORS           4
101 # define ADDR_SHIFT             16
102 # include "nand.c"
103
104 /* Information based on Linux drivers/mtd/nand/nand_ids.c */
105 struct nand_info_s {
106     int size;
107     int width;
108     int page_shift;
109     int erase_shift;
110     uint32_t options;
111 } nand_flash_ids[0x100] = {
112     [0 ... 0xff] = { 0 },
113
114     [0x6e] = { 1,       8,      8, 4, 0 },
115     [0x64] = { 2,       8,      8, 4, 0 },
116     [0x6b] = { 4,       8,      9, 4, 0 },
117     [0xe8] = { 1,       8,      8, 4, 0 },
118     [0xec] = { 1,       8,      8, 4, 0 },
119     [0xea] = { 2,       8,      8, 4, 0 },
120     [0xd5] = { 4,       8,      9, 4, 0 },
121     [0xe3] = { 4,       8,      9, 4, 0 },
122     [0xe5] = { 4,       8,      9, 4, 0 },
123     [0xd6] = { 8,       8,      9, 4, 0 },
124
125     [0x39] = { 8,       8,      9, 4, 0 },
126     [0xe6] = { 8,       8,      9, 4, 0 },
127     [0x49] = { 8,       16,     9, 4, NAND_BUSWIDTH_16 },
128     [0x59] = { 8,       16,     9, 4, NAND_BUSWIDTH_16 },
129
130     [0x33] = { 16,      8,      9, 5, 0 },
131     [0x73] = { 16,      8,      9, 5, 0 },
132     [0x43] = { 16,      16,     9, 5, NAND_BUSWIDTH_16 },
133     [0x53] = { 16,      16,     9, 5, NAND_BUSWIDTH_16 },
134
135     [0x35] = { 32,      8,      9, 5, 0 },
136     [0x75] = { 32,      8,      9, 5, 0 },
137     [0x45] = { 32,      16,     9, 5, NAND_BUSWIDTH_16 },
138     [0x55] = { 32,      16,     9, 5, NAND_BUSWIDTH_16 },
139
140     [0x36] = { 64,      8,      9, 5, 0 },
141     [0x76] = { 64,      8,      9, 5, 0 },
142     [0x46] = { 64,      16,     9, 5, NAND_BUSWIDTH_16 },
143     [0x56] = { 64,      16,     9, 5, NAND_BUSWIDTH_16 },
144
145     [0x78] = { 128,     8,      9, 5, 0 },
146     [0x39] = { 128,     8,      9, 5, 0 },
147     [0x79] = { 128,     8,      9, 5, 0 },
148     [0x72] = { 128,     16,     9, 5, NAND_BUSWIDTH_16 },
149     [0x49] = { 128,     16,     9, 5, NAND_BUSWIDTH_16 },
150     [0x74] = { 128,     16,     9, 5, NAND_BUSWIDTH_16 },
151     [0x59] = { 128,     16,     9, 5, NAND_BUSWIDTH_16 },
152
153     [0x71] = { 256,     8,      9, 5, 0 },
154
155     /*
156      * These are the new chips with large page size. The pagesize and the
157      * erasesize is determined from the extended id bytes
158      */
159 # define LP_OPTIONS     (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
160 # define LP_OPTIONS16   (LP_OPTIONS | NAND_BUSWIDTH_16)
161
162     /* 512 Megabit */
163     [0xa2] = { 64,      8,      0, 0, LP_OPTIONS },
164     [0xf2] = { 64,      8,      0, 0, LP_OPTIONS },
165     [0xb2] = { 64,      16,     0, 0, LP_OPTIONS16 },
166     [0xc2] = { 64,      16,     0, 0, LP_OPTIONS16 },
167
168     /* 1 Gigabit */
169     [0xa1] = { 128,     8,      0, 0, LP_OPTIONS },
170     [0xf1] = { 128,     8,      0, 0, LP_OPTIONS },
171     [0xb1] = { 128,     16,     0, 0, LP_OPTIONS16 },
172     [0xc1] = { 128,     16,     0, 0, LP_OPTIONS16 },
173
174     /* 2 Gigabit */
175     [0xaa] = { 256,     8,      0, 0, LP_OPTIONS },
176     [0xda] = { 256,     8,      0, 0, LP_OPTIONS },
177     [0xba] = { 256,     16,     0, 0, LP_OPTIONS16 },
178     [0xca] = { 256,     16,     0, 0, LP_OPTIONS16 },
179
180     /* 4 Gigabit */
181     [0xac] = { 512,     8,      0, 0, LP_OPTIONS },
182     [0xdc] = { 512,     8,      0, 0, LP_OPTIONS },
183     [0xbc] = { 512,     16,     0, 0, LP_OPTIONS16 },
184     [0xcc] = { 512,     16,     0, 0, LP_OPTIONS16 },
185
186     /* 8 Gigabit */
187     [0xa3] = { 1024,    8,      0, 0, LP_OPTIONS },
188     [0xd3] = { 1024,    8,      0, 0, LP_OPTIONS },
189     [0xb3] = { 1024,    16,     0, 0, LP_OPTIONS16 },
190     [0xc3] = { 1024,    16,     0, 0, LP_OPTIONS16 },
191
192     /* 16 Gigabit */
193     [0xa5] = { 2048,    8,      0, 0, LP_OPTIONS },
194     [0xd5] = { 2048,    8,      0, 0, LP_OPTIONS },
195     [0xb5] = { 2048,    16,     0, 0, LP_OPTIONS16 },
196     [0xc5] = { 2048,    16,     0, 0, LP_OPTIONS16 },
197 };
198
199 static void nand_reset(struct nand_flash_s *s)
200 {
201     s->cmd = NAND_CMD_READ0;
202     s->addr = 0;
203     s->addrlen = 0;
204     s->iolen = 0;
205     s->offset = 0;
206     s->status &= NAND_IOSTATUS_UNPROTCT;
207 }
208
209 static void nand_command(struct nand_flash_s *s)
210 {
211     switch (s->cmd) {
212     case NAND_CMD_READ0:
213         s->iolen = 0;
214         break;
215
216     case NAND_CMD_READID:
217         s->io[0] = s->manf_id;
218         s->io[1] = s->chip_id;
219         s->io[2] = 'Q';         /* Don't-care byte (often 0xa5) */
220         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
221             s->io[3] = 0x15;    /* Page Size, Block Size, Spare Size.. */
222         else
223             s->io[3] = 0xc0;    /* Multi-plane */
224         s->ioaddr = s->io;
225         s->iolen = 4;
226         break;
227
228     case NAND_CMD_RANDOMREAD2:
229     case NAND_CMD_NOSERIALREAD2:
230         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
231             break;
232
233         s->blk_load(s, s->addr, s->addr & ((1 << s->addr_shift) - 1));
234         break;
235
236     case NAND_CMD_RESET:
237         nand_reset(s);
238         break;
239
240     case NAND_CMD_PAGEPROGRAM1:
241         s->ioaddr = s->io;
242         s->iolen = 0;
243         break;
244
245     case NAND_CMD_PAGEPROGRAM2:
246         if (s->wp) {
247             s->blk_write(s);
248         }
249         break;
250
251     case NAND_CMD_BLOCKERASE1:
252         break;
253
254     case NAND_CMD_BLOCKERASE2:
255         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
256             s->addr <<= 16;
257         else
258             s->addr <<= 8;
259
260         if (s->wp) {
261             s->blk_erase(s);
262         }
263         break;
264
265     case NAND_CMD_READSTATUS:
266         s->io[0] = s->status;
267         s->ioaddr = s->io;
268         s->iolen = 1;
269         break;
270
271     default:
272         printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
273     }
274 }
275
276 static void nand_save(QEMUFile *f, void *opaque)
277 {
278     struct nand_flash_s *s = (struct nand_flash_s *) opaque;
279     qemu_put_byte(f, s->cle);
280     qemu_put_byte(f, s->ale);
281     qemu_put_byte(f, s->ce);
282     qemu_put_byte(f, s->wp);
283     qemu_put_byte(f, s->gnd);
284     qemu_put_buffer(f, s->io, sizeof(s->io));
285     qemu_put_be32(f, s->ioaddr - s->io);
286     qemu_put_be32(f, s->iolen);
287
288     qemu_put_be32s(f, &s->cmd);
289     qemu_put_be32s(f, &s->addr);
290     qemu_put_be32(f, s->addrlen);
291     qemu_put_be32(f, s->status);
292     qemu_put_be32(f, s->offset);
293     /* XXX: do we want to save s->storage too? */
294 }
295
296 static int nand_load(QEMUFile *f, void *opaque, int version_id)
297 {
298     struct nand_flash_s *s = (struct nand_flash_s *) opaque;
299     s->cle = qemu_get_byte(f);
300     s->ale = qemu_get_byte(f);
301     s->ce = qemu_get_byte(f);
302     s->wp = qemu_get_byte(f);
303     s->gnd = qemu_get_byte(f);
304     qemu_get_buffer(f, s->io, sizeof(s->io));
305     s->ioaddr = s->io + qemu_get_be32(f);
306     s->iolen = qemu_get_be32(f);
307     if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io)
308         return -EINVAL;
309
310     qemu_get_be32s(f, &s->cmd);
311     qemu_get_be32s(f, &s->addr);
312     s->addrlen = qemu_get_be32(f);
313     s->status = qemu_get_be32(f);
314     s->offset = qemu_get_be32(f);
315     return 0;
316 }
317
318 static int nand_iid = 0;
319
320 /*
321  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
322  * outputs are R/B and eight I/O pins.
323  *
324  * CE, WP and R/B are active low.
325  */
326 void nand_setpins(struct nand_flash_s *s, 
327                 int cle, int ale, int ce, int wp, int gnd)
328 {
329     s->cle = cle;
330     s->ale = ale;
331     s->ce = ce;
332     s->wp = wp;
333     s->gnd = gnd;
334     if (wp)
335         s->status |= NAND_IOSTATUS_UNPROTCT;
336     else
337         s->status &= ~NAND_IOSTATUS_UNPROTCT;
338 }
339
340 void nand_getpins(struct nand_flash_s *s, int *rb)
341 {
342     *rb = 1;
343 }
344
345 void nand_setio(struct nand_flash_s *s, uint8_t value)
346 {
347     if (!s->ce && s->cle) {
348         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
349             if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
350                 return;
351             if (value == NAND_CMD_RANDOMREAD1) {
352                 s->addr &= ~((1 << s->addr_shift) - 1);
353                 s->addrlen = 0;
354                 return;
355             }
356         }
357         if (value == NAND_CMD_READ0)
358             s->offset = 0;
359         else if (value == NAND_CMD_READ1) {
360             s->offset = 0x100;
361             value = NAND_CMD_READ0;
362         }
363         else if (value == NAND_CMD_READ2) {
364             s->offset = 1 << s->page_shift;
365             value = NAND_CMD_READ0;
366         }
367
368         s->cmd = value;
369
370         if (s->cmd == NAND_CMD_READSTATUS ||
371                 s->cmd == NAND_CMD_PAGEPROGRAM2 ||
372                 s->cmd == NAND_CMD_BLOCKERASE1 ||
373                 s->cmd == NAND_CMD_BLOCKERASE2 ||
374                 s->cmd == NAND_CMD_NOSERIALREAD2 ||
375                 s->cmd == NAND_CMD_RANDOMREAD2 ||
376                 s->cmd == NAND_CMD_RESET)
377             nand_command(s);
378
379         if (s->cmd != NAND_CMD_RANDOMREAD2) {
380             s->addrlen = 0;
381             s->addr = 0;
382         }
383     }
384
385     if (s->ale) {
386         s->addr |= value << (s->addrlen * 8);
387         s->addrlen ++;
388
389         if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
390             nand_command(s);
391
392         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
393                 s->addrlen == 3 && (
394                     s->cmd == NAND_CMD_READ0 ||
395                     s->cmd == NAND_CMD_PAGEPROGRAM1))
396             nand_command(s);
397         if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
398                s->addrlen == 4 && (
399                     s->cmd == NAND_CMD_READ0 ||
400                     s->cmd == NAND_CMD_PAGEPROGRAM1))
401             nand_command(s);
402     }
403
404     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
405         if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
406             s->io[s->iolen ++] = value;
407     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
408         if ((s->addr & ((1 << s->addr_shift) - 1)) <
409                 (1 << s->page_shift) + (1 << s->oob_shift)) {
410             s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
411             s->addr ++;
412         }
413     }
414 }
415
416 uint8_t nand_getio(struct nand_flash_s *s)
417 {
418     int offset;
419  
420     /* Allow sequential reading */
421     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
422         offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
423         s->offset = 0;
424
425         s->blk_load(s, s->addr, offset);
426         if (s->gnd)
427             s->iolen = (1 << s->page_shift) - offset;
428         else
429             s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
430     }
431
432     if (s->ce || s->iolen <= 0)
433         return 0;
434
435     s->iolen --;
436     return *(s->ioaddr ++);
437 }
438
439 struct nand_flash_s *nand_init(int manf_id, int chip_id)
440 {
441     int pagesize;
442     struct nand_flash_s *s;
443
444     if (nand_flash_ids[chip_id].size == 0) {
445         cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n",
446                         __FUNCTION__);
447     }
448
449     s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s));
450     s->bdrv = mtd_bdrv;
451     s->manf_id = manf_id;
452     s->chip_id = chip_id;
453     s->size = nand_flash_ids[s->chip_id].size << 20;
454     if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
455         s->page_shift = 11;
456         s->erase_shift = 6;
457     } else {
458         s->page_shift = nand_flash_ids[s->chip_id].page_shift;
459         s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
460     }
461
462     switch (1 << s->page_shift) {
463     case 256:
464         nand_init_256(s);
465         break;
466     case 512:
467         nand_init_512(s);
468         break;
469     case 2048:
470         nand_init_2048(s);
471         break;
472     default:
473         cpu_abort(cpu_single_env, "%s: Unsupported NAND block size.\n",
474                         __FUNCTION__);
475     }
476
477     pagesize = 1 << s->oob_shift;
478     s->mem_oob = 1;
479     if (s->bdrv && bdrv_getlength(s->bdrv) >=
480                     (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
481         pagesize = 0;
482         s->mem_oob = 0;
483     }
484
485     if (!s->bdrv)
486         pagesize += 1 << s->page_shift;
487     if (pagesize)
488         s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
489                         0xff, s->pages * pagesize);
490
491     register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s);
492
493     return s;
494 }
495
496 void nand_done(struct nand_flash_s *s)
497 {
498     if (s->bdrv) {
499         bdrv_close(s->bdrv);
500         bdrv_delete(s->bdrv);
501     }
502
503     if (!s->bdrv || s->mem_oob)
504         free(s->storage);
505
506     free(s);
507 }
508
509 #else
510
511 /* Program a single page */
512 static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
513 {
514     uint32_t off, page, sector, soff;
515     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
516     if (PAGE(s->addr) >= s->pages)
517         return;
518
519     if (!s->bdrv) {
520         memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
521                         s->offset, s->io, s->iolen);
522     } else if (s->mem_oob) {
523         sector = SECTOR(s->addr);
524         off = (s->addr & PAGE_MASK) + s->offset;
525         soff = SECTOR_OFFSET(s->addr);
526         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
527             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
528             return;
529         }
530
531         memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
532         if (off + s->iolen > PAGE_SIZE) {
533             page = PAGE(s->addr);
534             memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
535                             MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
536         }
537
538         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
539             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
540     } else {
541         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
542         sector = off >> 9;
543         soff = off & 0x1ff;
544         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
545             printf("%s: read error in sector %i\n", __FUNCTION__, sector);
546             return;
547         }
548
549         memcpy(iobuf + soff, s->io, s->iolen);
550
551         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
552             printf("%s: write error in sector %i\n", __FUNCTION__, sector);
553     }
554     s->offset = 0;
555 }
556
557 /* Erase a single block */
558 static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s)
559 {
560     uint32_t i, page, addr;
561     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
562     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
563
564     if (PAGE(addr) >= s->pages)
565         return;
566
567     if (!s->bdrv) {
568         memset(s->storage + PAGE_START(addr),
569                         0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
570     } else if (s->mem_oob) {
571         memset(s->storage + (PAGE(addr) << OOB_SHIFT),
572                         0xff, OOB_SIZE << s->erase_shift);
573         i = SECTOR(addr);
574         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
575         for (; i < page; i ++)
576             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
577                 printf("%s: write error in sector %i\n", __FUNCTION__, i);
578     } else {
579         addr = PAGE_START(addr);
580         page = addr >> 9;
581         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
582             printf("%s: read error in sector %i\n", __FUNCTION__, page);
583         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
584         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
585             printf("%s: write error in sector %i\n", __FUNCTION__, page);
586
587         memset(iobuf, 0xff, 0x200);
588         i = (addr & ~0x1ff) + 0x200;
589         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
590                         i < addr; i += 0x200)
591             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
592                 printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
593
594         page = i >> 9;
595         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
596             printf("%s: read error in sector %i\n", __FUNCTION__, page);
597         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
598         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
599             printf("%s: write error in sector %i\n", __FUNCTION__, page);
600     }
601 }
602
603 static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
604                 uint32_t addr, int offset)
605 {
606     if (PAGE(addr) >= s->pages)
607         return;
608
609     if (s->bdrv) {
610         if (s->mem_oob) {
611             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
612                 printf("%s: read error in sector %i\n",
613                                 __FUNCTION__, SECTOR(addr));
614             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
615                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
616                             OOB_SIZE);
617             s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
618         } else {
619             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
620                                     s->io, (PAGE_SECTORS + 2)) == -1)
621                 printf("%s: read error in sector %i\n",
622                                 __FUNCTION__, PAGE_START(addr) >> 9);
623             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
624         }
625     } else {
626         memcpy(s->io, s->storage + PAGE_START(s->addr) +
627                         offset, PAGE_SIZE + OOB_SIZE - offset);
628         s->ioaddr = s->io;
629     }
630
631     s->addr &= PAGE_SIZE - 1;
632     s->addr += PAGE_SIZE;
633 }
634
635 static void glue(nand_init_, PAGE_SIZE)(struct nand_flash_s *s)
636 {
637     s->oob_shift = PAGE_SHIFT - 5;
638     s->pages = s->size >> PAGE_SHIFT;
639     s->addr_shift = ADDR_SHIFT;
640
641     s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
642     s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
643     s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
644 }
645
646 # undef PAGE_SIZE
647 # undef PAGE_SHIFT
648 # undef PAGE_SECTORS
649 # undef ADDR_SHIFT
650 #endif  /* NAND_IO */