|
|
1.1 root 1: /*
2: * CFI parallel flash with Intel command set emulation
3: *
4: * Copyright (c) 2006 Thorsten Zitterell
5: * Copyright (c) 2005 Jocelyn Mayer
6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * Lesser General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: /*
23: * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
24: * Supported commands/modes are:
25: * - flash read
26: * - flash write
27: * - flash ID read
28: * - sector erase
29: * - CFI queries
30: *
31: * It does not support timings
32: * It does not support flash interleaving
33: * It does not implement software data protection as found in many real chips
34: * It does not implement erase suspend/resume commands
35: * It does not implement multiple sectors erase
36: *
37: * It does not implement much more ...
38: */
39:
40: #include "hw.h"
41: #include "flash.h"
42: #include "block.h"
43: #include "qemu-timer.h"
44:
45: #define PFLASH_BUG(fmt, args...) \
46: do { \
47: printf("PFLASH: Possible BUG - " fmt, ##args); \
48: exit(1); \
49: } while(0)
50:
51: /* #define PFLASH_DEBUG */
52: #ifdef PFLASH_DEBUG
53: #define DPRINTF(fmt, args...) \
54: do { \
55: printf("PFLASH: " fmt , ##args); \
56: } while (0)
57: #else
58: #define DPRINTF(fmt, args...) do { } while (0)
59: #endif
60:
61: struct pflash_t {
62: BlockDriverState *bs;
63: target_ulong base;
64: target_ulong sector_len;
65: target_ulong total_len;
66: int width;
67: int wcycle; /* if 0, the flash is read normally */
68: int bypass;
69: int ro;
70: uint8_t cmd;
71: uint8_t status;
72: uint16_t ident[4];
73: uint8_t cfi_len;
74: uint8_t cfi_table[0x52];
75: target_ulong counter;
76: QEMUTimer *timer;
77: ram_addr_t off;
78: int fl_mem;
79: void *storage;
80: };
81:
82: static void pflash_timer (void *opaque)
83: {
84: pflash_t *pfl = opaque;
85:
86: DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
87: /* Reset flash */
88: pfl->status ^= 0x80;
89: if (pfl->bypass) {
90: pfl->wcycle = 2;
91: } else {
92: cpu_register_physical_memory(pfl->base, pfl->total_len,
93: pfl->off | IO_MEM_ROMD | pfl->fl_mem);
94: pfl->wcycle = 0;
95: }
96: pfl->cmd = 0;
97: }
98:
99: static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
100: {
101: target_ulong boff;
102: uint32_t ret;
103: uint8_t *p;
104:
105: ret = -1;
106: offset -= pfl->base;
107: boff = offset & 0xFF; /* why this here ?? */
108:
109: if (pfl->width == 2)
110: boff = boff >> 1;
111: else if (pfl->width == 4)
112: boff = boff >> 2;
113:
114: DPRINTF("%s: reading offset " TARGET_FMT_lx " under cmd %02x\n",
115: __func__, boff, pfl->cmd);
116:
117: switch (pfl->cmd) {
118: case 0x00:
119: /* Flash area read */
120: p = pfl->storage;
121: switch (width) {
122: case 1:
123: ret = p[offset];
124: DPRINTF("%s: data offset " TARGET_FMT_lx " %02x\n",
125: __func__, offset, ret);
126: break;
127: case 2:
128: #if defined(TARGET_WORDS_BIGENDIAN)
129: ret = p[offset] << 8;
130: ret |= p[offset + 1];
131: #else
132: ret = p[offset];
133: ret |= p[offset + 1] << 8;
134: #endif
135: DPRINTF("%s: data offset " TARGET_FMT_lx " %04x\n",
136: __func__, offset, ret);
137: break;
138: case 4:
139: #if defined(TARGET_WORDS_BIGENDIAN)
140: ret = p[offset] << 24;
141: ret |= p[offset + 1] << 16;
142: ret |= p[offset + 2] << 8;
143: ret |= p[offset + 3];
144: #else
145: ret = p[offset];
146: ret |= p[offset + 1] << 8;
147: ret |= p[offset + 1] << 8;
148: ret |= p[offset + 2] << 16;
149: ret |= p[offset + 3] << 24;
150: #endif
151: DPRINTF("%s: data offset " TARGET_FMT_lx " %08x\n",
152: __func__, offset, ret);
153: break;
154: default:
155: DPRINTF("BUG in %s\n", __func__);
156: }
157:
158: break;
159: case 0x20: /* Block erase */
160: case 0x50: /* Clear status register */
161: case 0x60: /* Block /un)lock */
162: case 0x70: /* Status Register */
163: case 0xe8: /* Write block */
164: /* Status register read */
165: ret = pfl->status;
166: DPRINTF("%s: status %x\n", __func__, ret);
167: break;
168: case 0x98: /* Query mode */
169: if (boff > pfl->cfi_len)
170: ret = 0;
171: else
172: ret = pfl->cfi_table[boff];
173: break;
174: default:
175: /* This should never happen : reset state & treat it as a read */
176: DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
177: pfl->wcycle = 0;
178: pfl->cmd = 0;
179: }
180: return ret;
181: }
182:
183: /* update flash content on disk */
184: static void pflash_update(pflash_t *pfl, int offset,
185: int size)
186: {
187: int offset_end;
188: if (pfl->bs) {
189: offset_end = offset + size;
190: /* round to sectors */
191: offset = offset >> 9;
192: offset_end = (offset_end + 511) >> 9;
193: bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
194: offset_end - offset);
195: }
196: }
197:
198: static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
199: int width)
200: {
201: target_ulong boff;
202: uint8_t *p;
203: uint8_t cmd;
204:
205: /* WARNING: when the memory area is in ROMD mode, the offset is a
206: ram offset, not a physical address */
207: cmd = value;
208:
209: if (pfl->wcycle == 0)
210: offset -= (target_ulong)(long)pfl->storage;
211: else
212: offset -= pfl->base;
213:
214: DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d wcycle 0x%x\n",
215: __func__, offset, value, width, pfl->wcycle);
216:
217: /* Set the device in I/O access mode */
218: cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
219: boff = offset & (pfl->sector_len - 1);
220:
221: if (pfl->width == 2)
222: boff = boff >> 1;
223: else if (pfl->width == 4)
224: boff = boff >> 2;
225:
226: switch (pfl->wcycle) {
227: case 0:
228: /* read mode */
229: switch (cmd) {
230: case 0x00: /* ??? */
231: goto reset_flash;
232: case 0x20: /* Block erase */
233: p = pfl->storage;
234: offset &= ~(pfl->sector_len - 1);
235:
236: DPRINTF("%s: block erase at " TARGET_FMT_lx " bytes "
237: TARGET_FMT_lx "\n",
238: __func__, offset, pfl->sector_len);
239:
240: memset(p + offset, 0xff, pfl->sector_len);
241: pflash_update(pfl, offset, pfl->sector_len);
242: pfl->status |= 0x80; /* Ready! */
243: break;
244: case 0x50: /* Clear status bits */
245: DPRINTF("%s: Clear status bits\n", __func__);
246: pfl->status = 0x0;
247: goto reset_flash;
248: case 0x60: /* Block (un)lock */
249: DPRINTF("%s: Block unlock\n", __func__);
250: break;
251: case 0x70: /* Status Register */
252: DPRINTF("%s: Read status register\n", __func__);
253: pfl->cmd = cmd;
254: return;
255: case 0x98: /* CFI query */
256: DPRINTF("%s: CFI query\n", __func__);
257: break;
258: case 0xe8: /* Write to buffer */
259: DPRINTF("%s: Write to buffer\n", __func__);
260: pfl->status |= 0x80; /* Ready! */
261: break;
262: case 0xff: /* Read array mode */
263: DPRINTF("%s: Read array mode\n", __func__);
264: goto reset_flash;
265: default:
266: goto error_flash;
267: }
268: pfl->wcycle++;
269: pfl->cmd = cmd;
270: return;
271: case 1:
272: switch (pfl->cmd) {
273: case 0x20: /* Block erase */
274: case 0x28:
275: if (cmd == 0xd0) { /* confirm */
276: pfl->wcycle = 1;
277: pfl->status |= 0x80;
278: } if (cmd == 0xff) { /* read array mode */
279: goto reset_flash;
280: } else
281: goto error_flash;
282:
283: break;
284: case 0xe8:
285: DPRINTF("%s: block write of %x bytes\n", __func__, cmd);
286: pfl->counter = cmd;
287: pfl->wcycle++;
288: break;
289: case 0x60:
290: if (cmd == 0xd0) {
291: pfl->wcycle = 0;
292: pfl->status |= 0x80;
293: } else if (cmd == 0x01) {
294: pfl->wcycle = 0;
295: pfl->status |= 0x80;
296: } else if (cmd == 0xff) {
297: goto reset_flash;
298: } else {
299: DPRINTF("%s: Unknown (un)locking command\n", __func__);
300: goto reset_flash;
301: }
302: break;
303: case 0x98:
304: if (cmd == 0xff) {
305: goto reset_flash;
306: } else {
307: DPRINTF("%s: leaving query mode\n", __func__);
308: }
309: break;
310: default:
311: goto error_flash;
312: }
313: return;
314: case 2:
315: switch (pfl->cmd) {
316: case 0xe8: /* Block write */
317: p = pfl->storage;
318: DPRINTF("%s: block write offset " TARGET_FMT_lx
319: " value %x counter " TARGET_FMT_lx "\n",
320: __func__, offset, value, pfl->counter);
321: switch (width) {
322: case 1:
323: p[offset] = value;
324: pflash_update(pfl, offset, 1);
325: break;
326: case 2:
327: #if defined(TARGET_WORDS_BIGENDIAN)
328: p[offset] = value >> 8;
329: p[offset + 1] = value;
330: #else
331: p[offset] = value;
332: p[offset + 1] = value >> 8;
333: #endif
334: pflash_update(pfl, offset, 2);
335: break;
336: case 4:
337: #if defined(TARGET_WORDS_BIGENDIAN)
338: p[offset] = value >> 24;
339: p[offset + 1] = value >> 16;
340: p[offset + 2] = value >> 8;
341: p[offset + 3] = value;
342: #else
343: p[offset] = value;
344: p[offset + 1] = value >> 8;
345: p[offset + 2] = value >> 16;
346: p[offset + 3] = value >> 24;
347: #endif
348: pflash_update(pfl, offset, 4);
349: break;
350: }
351:
352: pfl->status |= 0x80;
353:
354: if (!pfl->counter) {
355: DPRINTF("%s: block write finished\n", __func__);
356: pfl->wcycle++;
357: }
358:
359: pfl->counter--;
360: break;
361: default:
362: goto error_flash;
363: }
364: return;
365: case 3: /* Confirm mode */
366: switch (pfl->cmd) {
367: case 0xe8: /* Block write */
368: if (cmd == 0xd0) {
369: pfl->wcycle = 0;
370: pfl->status |= 0x80;
371: } else {
372: DPRINTF("%s: unknown command for \"write block\"\n", __func__);
373: PFLASH_BUG("Write block confirm");
374: goto reset_flash;
375: }
376: break;
377: default:
378: goto error_flash;
379: }
380: return;
381: default:
382: /* Should never happen */
383: DPRINTF("%s: invalid write state\n", __func__);
384: goto reset_flash;
385: }
386: return;
387:
388: error_flash:
389: printf("%s: Unimplemented flash cmd sequence "
390: "(offset " TARGET_FMT_lx ", wcycle 0x%x cmd 0x%x value 0x%x\n",
391: __func__, offset, pfl->wcycle, pfl->cmd, value);
392:
393: reset_flash:
394: cpu_register_physical_memory(pfl->base, pfl->total_len,
395: pfl->off | IO_MEM_ROMD | pfl->fl_mem);
396:
397: pfl->bypass = 0;
398: pfl->wcycle = 0;
399: pfl->cmd = 0;
400: return;
401: }
402:
403:
404: static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
405: {
406: return pflash_read(opaque, addr, 1);
407: }
408:
409: static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
410: {
411: pflash_t *pfl = opaque;
412:
413: return pflash_read(pfl, addr, 2);
414: }
415:
416: static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
417: {
418: pflash_t *pfl = opaque;
419:
420: return pflash_read(pfl, addr, 4);
421: }
422:
423: static void pflash_writeb (void *opaque, target_phys_addr_t addr,
424: uint32_t value)
425: {
426: pflash_write(opaque, addr, value, 1);
427: }
428:
429: static void pflash_writew (void *opaque, target_phys_addr_t addr,
430: uint32_t value)
431: {
432: pflash_t *pfl = opaque;
433:
434: pflash_write(pfl, addr, value, 2);
435: }
436:
437: static void pflash_writel (void *opaque, target_phys_addr_t addr,
438: uint32_t value)
439: {
440: pflash_t *pfl = opaque;
441:
442: pflash_write(pfl, addr, value, 4);
443: }
444:
445: static CPUWriteMemoryFunc *pflash_write_ops[] = {
446: &pflash_writeb,
447: &pflash_writew,
448: &pflash_writel,
449: };
450:
451: static CPUReadMemoryFunc *pflash_read_ops[] = {
452: &pflash_readb,
453: &pflash_readw,
454: &pflash_readl,
455: };
456:
457: /* Count trailing zeroes of a 32 bits quantity */
458: static int ctz32 (uint32_t n)
459: {
460: int ret;
461:
462: ret = 0;
463: if (!(n & 0xFFFF)) {
464: ret += 16;
465: n = n >> 16;
466: }
467: if (!(n & 0xFF)) {
468: ret += 8;
469: n = n >> 8;
470: }
471: if (!(n & 0xF)) {
472: ret += 4;
473: n = n >> 4;
474: }
475: if (!(n & 0x3)) {
476: ret += 2;
477: n = n >> 2;
478: }
479: if (!(n & 0x1)) {
480: ret++;
481: n = n >> 1;
482: }
483: #if 0 /* This is not necessary as n is never 0 */
484: if (!n)
485: ret++;
486: #endif
487:
488: return ret;
489: }
490:
491: pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
492: BlockDriverState *bs, uint32_t sector_len,
493: int nb_blocs, int width,
494: uint16_t id0, uint16_t id1,
495: uint16_t id2, uint16_t id3)
496: {
497: pflash_t *pfl;
498: target_long total_len;
499:
500: total_len = sector_len * nb_blocs;
501:
502: /* XXX: to be fixed */
503: #if 0
504: if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
505: total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
506: return NULL;
507: #endif
508:
509: pfl = qemu_mallocz(sizeof(pflash_t));
510:
511: if (pfl == NULL)
512: return NULL;
513: pfl->storage = phys_ram_base + off;
514: pfl->fl_mem = cpu_register_io_memory(0,
515: pflash_read_ops, pflash_write_ops, pfl);
516: pfl->off = off;
517: cpu_register_physical_memory(base, total_len,
518: off | pfl->fl_mem | IO_MEM_ROMD);
519:
520: pfl->bs = bs;
521: if (pfl->bs) {
522: /* read the initial flash content */
523: bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
524: }
525: #if 0 /* XXX: there should be a bit to set up read-only,
526: * the same way the hardware does (with WP pin).
527: */
528: pfl->ro = 1;
529: #else
530: pfl->ro = 0;
531: #endif
532: pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
533: pfl->base = base;
534: pfl->sector_len = sector_len;
535: pfl->total_len = total_len;
536: pfl->width = width;
537: pfl->wcycle = 0;
538: pfl->cmd = 0;
539: pfl->status = 0;
540: pfl->ident[0] = id0;
541: pfl->ident[1] = id1;
542: pfl->ident[2] = id2;
543: pfl->ident[3] = id3;
544: /* Hardcoded CFI table */
545: pfl->cfi_len = 0x52;
546: /* Standard "QRY" string */
547: pfl->cfi_table[0x10] = 'Q';
548: pfl->cfi_table[0x11] = 'R';
549: pfl->cfi_table[0x12] = 'Y';
550: /* Command set (Intel) */
551: pfl->cfi_table[0x13] = 0x01;
552: pfl->cfi_table[0x14] = 0x00;
553: /* Primary extended table address (none) */
554: pfl->cfi_table[0x15] = 0x31;
555: pfl->cfi_table[0x16] = 0x00;
556: /* Alternate command set (none) */
557: pfl->cfi_table[0x17] = 0x00;
558: pfl->cfi_table[0x18] = 0x00;
559: /* Alternate extended table (none) */
560: pfl->cfi_table[0x19] = 0x00;
561: pfl->cfi_table[0x1A] = 0x00;
562: /* Vcc min */
563: pfl->cfi_table[0x1B] = 0x45;
564: /* Vcc max */
565: pfl->cfi_table[0x1C] = 0x55;
566: /* Vpp min (no Vpp pin) */
567: pfl->cfi_table[0x1D] = 0x00;
568: /* Vpp max (no Vpp pin) */
569: pfl->cfi_table[0x1E] = 0x00;
570: /* Reserved */
571: pfl->cfi_table[0x1F] = 0x07;
572: /* Timeout for min size buffer write */
573: pfl->cfi_table[0x20] = 0x07;
574: /* Typical timeout for block erase */
575: pfl->cfi_table[0x21] = 0x0a;
576: /* Typical timeout for full chip erase (4096 ms) */
577: pfl->cfi_table[0x22] = 0x00;
578: /* Reserved */
579: pfl->cfi_table[0x23] = 0x04;
580: /* Max timeout for buffer write */
581: pfl->cfi_table[0x24] = 0x04;
582: /* Max timeout for block erase */
583: pfl->cfi_table[0x25] = 0x04;
584: /* Max timeout for chip erase */
585: pfl->cfi_table[0x26] = 0x00;
586: /* Device size */
587: pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
588: /* Flash device interface (8 & 16 bits) */
589: pfl->cfi_table[0x28] = 0x02;
590: pfl->cfi_table[0x29] = 0x00;
591: /* Max number of bytes in multi-bytes write */
592: pfl->cfi_table[0x2A] = 0x04;
593: pfl->cfi_table[0x2B] = 0x00;
594: /* Number of erase block regions (uniform) */
595: pfl->cfi_table[0x2C] = 0x01;
596: /* Erase block region 1 */
597: pfl->cfi_table[0x2D] = nb_blocs - 1;
598: pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
599: pfl->cfi_table[0x2F] = sector_len >> 8;
600: pfl->cfi_table[0x30] = sector_len >> 16;
601:
602: /* Extended */
603: pfl->cfi_table[0x31] = 'P';
604: pfl->cfi_table[0x32] = 'R';
605: pfl->cfi_table[0x33] = 'I';
606:
607: pfl->cfi_table[0x34] = '1';
608: pfl->cfi_table[0x35] = '1';
609:
610: pfl->cfi_table[0x36] = 0x00;
611: pfl->cfi_table[0x37] = 0x00;
612: pfl->cfi_table[0x38] = 0x00;
613: pfl->cfi_table[0x39] = 0x00;
614:
615: pfl->cfi_table[0x3a] = 0x00;
616:
617: pfl->cfi_table[0x3b] = 0x00;
618: pfl->cfi_table[0x3c] = 0x00;
619:
620: return pfl;
621: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.