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