Statistics
| Branch: | Revision:

root / hw / pflash_cfi01.c @ 737e150e

History | View | Annotate | Download (21.6 kB)

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, see <http://www.gnu.org/licenses/>.
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
 * - CFI queries
29
 *
30
 * It does not support timings
31
 * It does not support flash interleaving
32
 * It does not implement software data protection as found in many real chips
33
 * It does not implement erase suspend/resume commands
34
 * It does not implement multiple sectors erase
35
 *
36
 * It does not implement much more ...
37
 */
38

    
39
#include "hw.h"
40
#include "flash.h"
41
#include "block/block.h"
42
#include "qemu-timer.h"
43
#include "exec-memory.h"
44
#include "host-utils.h"
45
#include "sysbus.h"
46

    
47
#define PFLASH_BUG(fmt, ...) \
48
do { \
49
    printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
50
    exit(1); \
51
} while(0)
52

    
53
/* #define PFLASH_DEBUG */
54
#ifdef PFLASH_DEBUG
55
#define DPRINTF(fmt, ...)                          \
56
do {                                               \
57
    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
58
} while (0)
59
#else
60
#define DPRINTF(fmt, ...) do { } while (0)
61
#endif
62

    
63
struct pflash_t {
64
    SysBusDevice busdev;
65
    BlockDriverState *bs;
66
    uint32_t nb_blocs;
67
    uint64_t sector_len;
68
    uint8_t width;
69
    uint8_t be;
70
    int wcycle; /* if 0, the flash is read normally */
71
    int bypass;
72
    int ro;
73
    uint8_t cmd;
74
    uint8_t status;
75
    uint16_t ident0;
76
    uint16_t ident1;
77
    uint16_t ident2;
78
    uint16_t ident3;
79
    uint8_t cfi_len;
80
    uint8_t cfi_table[0x52];
81
    hwaddr counter;
82
    unsigned int writeblock_size;
83
    QEMUTimer *timer;
84
    MemoryRegion mem;
85
    char *name;
86
    void *storage;
87
};
88

    
89
static void pflash_timer (void *opaque)
90
{
91
    pflash_t *pfl = opaque;
92

    
93
    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
94
    /* Reset flash */
95
    pfl->status ^= 0x80;
96
    if (pfl->bypass) {
97
        pfl->wcycle = 2;
98
    } else {
99
        memory_region_rom_device_set_readable(&pfl->mem, true);
100
        pfl->wcycle = 0;
101
    }
102
    pfl->cmd = 0;
103
}
104

    
105
static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
106
                             int width, int be)
107
{
108
    hwaddr boff;
109
    uint32_t ret;
110
    uint8_t *p;
111

    
112
    ret = -1;
113
    boff = offset & 0xFF; /* why this here ?? */
114

    
115
    if (pfl->width == 2)
116
        boff = boff >> 1;
117
    else if (pfl->width == 4)
118
        boff = boff >> 2;
119

    
120
#if 0
121
    DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
122
            __func__, offset, pfl->cmd, width);
123
#endif
124
    switch (pfl->cmd) {
125
    case 0x00:
126
        /* Flash area read */
127
        p = pfl->storage;
128
        switch (width) {
129
        case 1:
130
            ret = p[offset];
131
            DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
132
                    __func__, offset, ret);
133
            break;
134
        case 2:
135
            if (be) {
136
                ret = p[offset] << 8;
137
                ret |= p[offset + 1];
138
            } else {
139
                ret = p[offset];
140
                ret |= p[offset + 1] << 8;
141
            }
142
            DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
143
                    __func__, offset, ret);
144
            break;
145
        case 4:
146
            if (be) {
147
                ret = p[offset] << 24;
148
                ret |= p[offset + 1] << 16;
149
                ret |= p[offset + 2] << 8;
150
                ret |= p[offset + 3];
151
            } else {
152
                ret = p[offset];
153
                ret |= p[offset + 1] << 8;
154
                ret |= p[offset + 2] << 16;
155
                ret |= p[offset + 3] << 24;
156
            }
157
            DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
158
                    __func__, offset, ret);
159
            break;
160
        default:
161
            DPRINTF("BUG in %s\n", __func__);
162
        }
163

    
164
        break;
165
    case 0x20: /* Block erase */
166
    case 0x50: /* Clear status register */
167
    case 0x60: /* Block /un)lock */
168
    case 0x70: /* Status Register */
169
    case 0xe8: /* Write block */
170
        /* Status register read */
171
        ret = pfl->status;
172
        DPRINTF("%s: status %x\n", __func__, ret);
173
        break;
174
    case 0x90:
175
        switch (boff) {
176
        case 0:
177
            ret = pfl->ident0 << 8 | pfl->ident1;
178
            DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
179
            break;
180
        case 1:
181
            ret = pfl->ident2 << 8 | pfl->ident3;
182
            DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
183
            break;
184
        default:
185
            DPRINTF("%s: Read Device Information boff=%x\n", __func__,
186
                    (unsigned)boff);
187
            ret = 0;
188
            break;
189
        }
190
        break;
191
    case 0x98: /* Query mode */
192
        if (boff > pfl->cfi_len)
193
            ret = 0;
194
        else
195
            ret = pfl->cfi_table[boff];
196
        break;
197
    default:
198
        /* This should never happen : reset state & treat it as a read */
199
        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
200
        pfl->wcycle = 0;
201
        pfl->cmd = 0;
202
    }
203
    return ret;
204
}
205

    
206
/* update flash content on disk */
207
static void pflash_update(pflash_t *pfl, int offset,
208
                          int size)
209
{
210
    int offset_end;
211
    if (pfl->bs) {
212
        offset_end = offset + size;
213
        /* round to sectors */
214
        offset = offset >> 9;
215
        offset_end = (offset_end + 511) >> 9;
216
        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
217
                   offset_end - offset);
218
    }
219
}
220

    
221
static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
222
                                     uint32_t value, int width, int be)
223
{
224
    uint8_t *p = pfl->storage;
225

    
226
    DPRINTF("%s: block write offset " TARGET_FMT_plx
227
            " value %x counter " TARGET_FMT_plx "\n",
228
            __func__, offset, value, pfl->counter);
229
    switch (width) {
230
    case 1:
231
        p[offset] = value;
232
        break;
233
    case 2:
234
        if (be) {
235
            p[offset] = value >> 8;
236
            p[offset + 1] = value;
237
        } else {
238
            p[offset] = value;
239
            p[offset + 1] = value >> 8;
240
        }
241
        break;
242
    case 4:
243
        if (be) {
244
            p[offset] = value >> 24;
245
            p[offset + 1] = value >> 16;
246
            p[offset + 2] = value >> 8;
247
            p[offset + 3] = value;
248
        } else {
249
            p[offset] = value;
250
            p[offset + 1] = value >> 8;
251
            p[offset + 2] = value >> 16;
252
            p[offset + 3] = value >> 24;
253
        }
254
        break;
255
    }
256

    
257
}
258

    
259
static void pflash_write(pflash_t *pfl, hwaddr offset,
260
                         uint32_t value, int width, int be)
261
{
262
    uint8_t *p;
263
    uint8_t cmd;
264

    
265
    cmd = value;
266

    
267
    DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
268
            __func__, offset, value, width, pfl->wcycle);
269

    
270
    if (!pfl->wcycle) {
271
        /* Set the device in I/O access mode */
272
        memory_region_rom_device_set_readable(&pfl->mem, false);
273
    }
274

    
275
    switch (pfl->wcycle) {
276
    case 0:
277
        /* read mode */
278
        switch (cmd) {
279
        case 0x00: /* ??? */
280
            goto reset_flash;
281
        case 0x10: /* Single Byte Program */
282
        case 0x40: /* Single Byte Program */
283
            DPRINTF("%s: Single Byte Program\n", __func__);
284
            break;
285
        case 0x20: /* Block erase */
286
            p = pfl->storage;
287
            offset &= ~(pfl->sector_len - 1);
288

    
289
            DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
290
                    __func__, offset, (unsigned)pfl->sector_len);
291

    
292
            if (!pfl->ro) {
293
                memset(p + offset, 0xff, pfl->sector_len);
294
                pflash_update(pfl, offset, pfl->sector_len);
295
            } else {
296
                pfl->status |= 0x20; /* Block erase error */
297
            }
298
            pfl->status |= 0x80; /* Ready! */
299
            break;
300
        case 0x50: /* Clear status bits */
301
            DPRINTF("%s: Clear status bits\n", __func__);
302
            pfl->status = 0x0;
303
            goto reset_flash;
304
        case 0x60: /* Block (un)lock */
305
            DPRINTF("%s: Block unlock\n", __func__);
306
            break;
307
        case 0x70: /* Status Register */
308
            DPRINTF("%s: Read status register\n", __func__);
309
            pfl->cmd = cmd;
310
            return;
311
        case 0x90: /* Read Device ID */
312
            DPRINTF("%s: Read Device information\n", __func__);
313
            pfl->cmd = cmd;
314
            return;
315
        case 0x98: /* CFI query */
316
            DPRINTF("%s: CFI query\n", __func__);
317
            break;
318
        case 0xe8: /* Write to buffer */
319
            DPRINTF("%s: Write to buffer\n", __func__);
320
            pfl->status |= 0x80; /* Ready! */
321
            break;
322
        case 0xff: /* Read array mode */
323
            DPRINTF("%s: Read array mode\n", __func__);
324
            goto reset_flash;
325
        default:
326
            goto error_flash;
327
        }
328
        pfl->wcycle++;
329
        pfl->cmd = cmd;
330
        break;
331
    case 1:
332
        switch (pfl->cmd) {
333
        case 0x10: /* Single Byte Program */
334
        case 0x40: /* Single Byte Program */
335
            DPRINTF("%s: Single Byte Program\n", __func__);
336
            if (!pfl->ro) {
337
                pflash_data_write(pfl, offset, value, width, be);
338
                pflash_update(pfl, offset, width);
339
            } else {
340
                pfl->status |= 0x10; /* Programming error */
341
            }
342
            pfl->status |= 0x80; /* Ready! */
343
            pfl->wcycle = 0;
344
        break;
345
        case 0x20: /* Block erase */
346
        case 0x28:
347
            if (cmd == 0xd0) { /* confirm */
348
                pfl->wcycle = 0;
349
                pfl->status |= 0x80;
350
            } else if (cmd == 0xff) { /* read array mode */
351
                goto reset_flash;
352
            } else
353
                goto error_flash;
354

    
355
            break;
356
        case 0xe8:
357
            DPRINTF("%s: block write of %x bytes\n", __func__, value);
358
            pfl->counter = value;
359
            pfl->wcycle++;
360
            break;
361
        case 0x60:
362
            if (cmd == 0xd0) {
363
                pfl->wcycle = 0;
364
                pfl->status |= 0x80;
365
            } else if (cmd == 0x01) {
366
                pfl->wcycle = 0;
367
                pfl->status |= 0x80;
368
            } else if (cmd == 0xff) {
369
                goto reset_flash;
370
            } else {
371
                DPRINTF("%s: Unknown (un)locking command\n", __func__);
372
                goto reset_flash;
373
            }
374
            break;
375
        case 0x98:
376
            if (cmd == 0xff) {
377
                goto reset_flash;
378
            } else {
379
                DPRINTF("%s: leaving query mode\n", __func__);
380
            }
381
            break;
382
        default:
383
            goto error_flash;
384
        }
385
        break;
386
    case 2:
387
        switch (pfl->cmd) {
388
        case 0xe8: /* Block write */
389
            if (!pfl->ro) {
390
                pflash_data_write(pfl, offset, value, width, be);
391
            } else {
392
                pfl->status |= 0x10; /* Programming error */
393
            }
394

    
395
            pfl->status |= 0x80;
396

    
397
            if (!pfl->counter) {
398
                hwaddr mask = pfl->writeblock_size - 1;
399
                mask = ~mask;
400

    
401
                DPRINTF("%s: block write finished\n", __func__);
402
                pfl->wcycle++;
403
                if (!pfl->ro) {
404
                    /* Flush the entire write buffer onto backing storage.  */
405
                    pflash_update(pfl, offset & mask, pfl->writeblock_size);
406
                } else {
407
                    pfl->status |= 0x10; /* Programming error */
408
                }
409
            }
410

    
411
            pfl->counter--;
412
            break;
413
        default:
414
            goto error_flash;
415
        }
416
        break;
417
    case 3: /* Confirm mode */
418
        switch (pfl->cmd) {
419
        case 0xe8: /* Block write */
420
            if (cmd == 0xd0) {
421
                pfl->wcycle = 0;
422
                pfl->status |= 0x80;
423
            } else {
424
                DPRINTF("%s: unknown command for \"write block\"\n", __func__);
425
                PFLASH_BUG("Write block confirm");
426
                goto reset_flash;
427
            }
428
            break;
429
        default:
430
            goto error_flash;
431
        }
432
        break;
433
    default:
434
        /* Should never happen */
435
        DPRINTF("%s: invalid write state\n",  __func__);
436
        goto reset_flash;
437
    }
438
    return;
439

    
440
 error_flash:
441
    printf("%s: Unimplemented flash cmd sequence "
442
           "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
443
           __func__, offset, pfl->wcycle, pfl->cmd, value);
444

    
445
 reset_flash:
446
    memory_region_rom_device_set_readable(&pfl->mem, true);
447

    
448
    pfl->bypass = 0;
449
    pfl->wcycle = 0;
450
    pfl->cmd = 0;
451
}
452

    
453

    
454
static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
455
{
456
    return pflash_read(opaque, addr, 1, 1);
457
}
458

    
459
static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
460
{
461
    return pflash_read(opaque, addr, 1, 0);
462
}
463

    
464
static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
465
{
466
    pflash_t *pfl = opaque;
467

    
468
    return pflash_read(pfl, addr, 2, 1);
469
}
470

    
471
static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
472
{
473
    pflash_t *pfl = opaque;
474

    
475
    return pflash_read(pfl, addr, 2, 0);
476
}
477

    
478
static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
479
{
480
    pflash_t *pfl = opaque;
481

    
482
    return pflash_read(pfl, addr, 4, 1);
483
}
484

    
485
static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
486
{
487
    pflash_t *pfl = opaque;
488

    
489
    return pflash_read(pfl, addr, 4, 0);
490
}
491

    
492
static void pflash_writeb_be(void *opaque, hwaddr addr,
493
                             uint32_t value)
494
{
495
    pflash_write(opaque, addr, value, 1, 1);
496
}
497

    
498
static void pflash_writeb_le(void *opaque, hwaddr addr,
499
                             uint32_t value)
500
{
501
    pflash_write(opaque, addr, value, 1, 0);
502
}
503

    
504
static void pflash_writew_be(void *opaque, hwaddr addr,
505
                             uint32_t value)
506
{
507
    pflash_t *pfl = opaque;
508

    
509
    pflash_write(pfl, addr, value, 2, 1);
510
}
511

    
512
static void pflash_writew_le(void *opaque, hwaddr addr,
513
                             uint32_t value)
514
{
515
    pflash_t *pfl = opaque;
516

    
517
    pflash_write(pfl, addr, value, 2, 0);
518
}
519

    
520
static void pflash_writel_be(void *opaque, hwaddr addr,
521
                             uint32_t value)
522
{
523
    pflash_t *pfl = opaque;
524

    
525
    pflash_write(pfl, addr, value, 4, 1);
526
}
527

    
528
static void pflash_writel_le(void *opaque, hwaddr addr,
529
                             uint32_t value)
530
{
531
    pflash_t *pfl = opaque;
532

    
533
    pflash_write(pfl, addr, value, 4, 0);
534
}
535

    
536
static const MemoryRegionOps pflash_cfi01_ops_be = {
537
    .old_mmio = {
538
        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
539
        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
540
    },
541
    .endianness = DEVICE_NATIVE_ENDIAN,
542
};
543

    
544
static const MemoryRegionOps pflash_cfi01_ops_le = {
545
    .old_mmio = {
546
        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
547
        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
548
    },
549
    .endianness = DEVICE_NATIVE_ENDIAN,
550
};
551

    
552
static int pflash_cfi01_init(SysBusDevice *dev)
553
{
554
    pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
555
    uint64_t total_len;
556
    int ret;
557

    
558
    total_len = pfl->sector_len * pfl->nb_blocs;
559

    
560
    /* XXX: to be fixed */
561
#if 0
562
    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
563
        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
564
        return NULL;
565
#endif
566

    
567
    memory_region_init_rom_device(
568
        &pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
569
        pfl->name, total_len);
570
    vmstate_register_ram(&pfl->mem, DEVICE(pfl));
571
    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
572
    sysbus_init_mmio(dev, &pfl->mem);
573

    
574
    if (pfl->bs) {
575
        /* read the initial flash content */
576
        ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
577

    
578
        if (ret < 0) {
579
            vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
580
            memory_region_destroy(&pfl->mem);
581
            return 1;
582
        }
583
    }
584

    
585
    if (pfl->bs) {
586
        pfl->ro = bdrv_is_read_only(pfl->bs);
587
    } else {
588
        pfl->ro = 0;
589
    }
590

    
591
    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
592
    pfl->wcycle = 0;
593
    pfl->cmd = 0;
594
    pfl->status = 0;
595
    /* Hardcoded CFI table */
596
    pfl->cfi_len = 0x52;
597
    /* Standard "QRY" string */
598
    pfl->cfi_table[0x10] = 'Q';
599
    pfl->cfi_table[0x11] = 'R';
600
    pfl->cfi_table[0x12] = 'Y';
601
    /* Command set (Intel) */
602
    pfl->cfi_table[0x13] = 0x01;
603
    pfl->cfi_table[0x14] = 0x00;
604
    /* Primary extended table address (none) */
605
    pfl->cfi_table[0x15] = 0x31;
606
    pfl->cfi_table[0x16] = 0x00;
607
    /* Alternate command set (none) */
608
    pfl->cfi_table[0x17] = 0x00;
609
    pfl->cfi_table[0x18] = 0x00;
610
    /* Alternate extended table (none) */
611
    pfl->cfi_table[0x19] = 0x00;
612
    pfl->cfi_table[0x1A] = 0x00;
613
    /* Vcc min */
614
    pfl->cfi_table[0x1B] = 0x45;
615
    /* Vcc max */
616
    pfl->cfi_table[0x1C] = 0x55;
617
    /* Vpp min (no Vpp pin) */
618
    pfl->cfi_table[0x1D] = 0x00;
619
    /* Vpp max (no Vpp pin) */
620
    pfl->cfi_table[0x1E] = 0x00;
621
    /* Reserved */
622
    pfl->cfi_table[0x1F] = 0x07;
623
    /* Timeout for min size buffer write */
624
    pfl->cfi_table[0x20] = 0x07;
625
    /* Typical timeout for block erase */
626
    pfl->cfi_table[0x21] = 0x0a;
627
    /* Typical timeout for full chip erase (4096 ms) */
628
    pfl->cfi_table[0x22] = 0x00;
629
    /* Reserved */
630
    pfl->cfi_table[0x23] = 0x04;
631
    /* Max timeout for buffer write */
632
    pfl->cfi_table[0x24] = 0x04;
633
    /* Max timeout for block erase */
634
    pfl->cfi_table[0x25] = 0x04;
635
    /* Max timeout for chip erase */
636
    pfl->cfi_table[0x26] = 0x00;
637
    /* Device size */
638
    pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
639
    /* Flash device interface (8 & 16 bits) */
640
    pfl->cfi_table[0x28] = 0x02;
641
    pfl->cfi_table[0x29] = 0x00;
642
    /* Max number of bytes in multi-bytes write */
643
    if (pfl->width == 1) {
644
        pfl->cfi_table[0x2A] = 0x08;
645
    } else {
646
        pfl->cfi_table[0x2A] = 0x0B;
647
    }
648
    pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
649

    
650
    pfl->cfi_table[0x2B] = 0x00;
651
    /* Number of erase block regions (uniform) */
652
    pfl->cfi_table[0x2C] = 0x01;
653
    /* Erase block region 1 */
654
    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
655
    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
656
    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
657
    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
658

    
659
    /* Extended */
660
    pfl->cfi_table[0x31] = 'P';
661
    pfl->cfi_table[0x32] = 'R';
662
    pfl->cfi_table[0x33] = 'I';
663

    
664
    pfl->cfi_table[0x34] = '1';
665
    pfl->cfi_table[0x35] = '0';
666

    
667
    pfl->cfi_table[0x36] = 0x00;
668
    pfl->cfi_table[0x37] = 0x00;
669
    pfl->cfi_table[0x38] = 0x00;
670
    pfl->cfi_table[0x39] = 0x00;
671

    
672
    pfl->cfi_table[0x3a] = 0x00;
673

    
674
    pfl->cfi_table[0x3b] = 0x00;
675
    pfl->cfi_table[0x3c] = 0x00;
676

    
677
    pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
678

    
679
    return 0;
680
}
681

    
682
static Property pflash_cfi01_properties[] = {
683
    DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
684
    DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
685
    DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
686
    DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
687
    DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
688
    DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
689
    DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
690
    DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
691
    DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
692
    DEFINE_PROP_STRING("name", struct pflash_t, name),
693
    DEFINE_PROP_END_OF_LIST(),
694
};
695

    
696
static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
697
{
698
    DeviceClass *dc = DEVICE_CLASS(klass);
699
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
700

    
701
    k->init = pflash_cfi01_init;
702
    dc->props = pflash_cfi01_properties;
703
}
704

    
705

    
706
static const TypeInfo pflash_cfi01_info = {
707
    .name           = "cfi.pflash01",
708
    .parent         = TYPE_SYS_BUS_DEVICE,
709
    .instance_size  = sizeof(struct pflash_t),
710
    .class_init     = pflash_cfi01_class_init,
711
};
712

    
713
static void pflash_cfi01_register_types(void)
714
{
715
    type_register_static(&pflash_cfi01_info);
716
}
717

    
718
type_init(pflash_cfi01_register_types)
719

    
720
pflash_t *pflash_cfi01_register(hwaddr base,
721
                                DeviceState *qdev, const char *name,
722
                                hwaddr size,
723
                                BlockDriverState *bs,
724
                                uint32_t sector_len, int nb_blocs, int width,
725
                                uint16_t id0, uint16_t id1,
726
                                uint16_t id2, uint16_t id3, int be)
727
{
728
    DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
729
    SysBusDevice *busdev = sysbus_from_qdev(dev);
730
    pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
731
                                                    "cfi.pflash01");
732

    
733
    if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
734
        abort();
735
    }
736
    qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
737
    qdev_prop_set_uint64(dev, "sector-length", sector_len);
738
    qdev_prop_set_uint8(dev, "width", width);
739
    qdev_prop_set_uint8(dev, "big-endian", !!be);
740
    qdev_prop_set_uint16(dev, "id0", id0);
741
    qdev_prop_set_uint16(dev, "id1", id1);
742
    qdev_prop_set_uint16(dev, "id2", id2);
743
    qdev_prop_set_uint16(dev, "id3", id3);
744
    qdev_prop_set_string(dev, "name", name);
745
    qdev_init_nofail(dev);
746

    
747
    sysbus_mmio_map(busdev, 0, base);
748
    return pfl;
749
}
750

    
751
MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
752
{
753
    return &fl->mem;
754
}