source: trunk/packages/xen-common/xen-common/tools/ioemu/hw/pflash_cfi02.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

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