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