~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/pflash_cfi01.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.h"
 
42
#include "qemu-timer.h"
 
43
#include "exec-memory.h"
 
44
 
 
45
#define PFLASH_BUG(fmt, ...) \
 
46
do { \
 
47
    printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
 
48
    exit(1); \
 
49
} while(0)
 
50
 
 
51
/* #define PFLASH_DEBUG */
 
52
#ifdef PFLASH_DEBUG
 
53
#define DPRINTF(fmt, ...)                          \
 
54
do {                                               \
 
55
    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
 
56
} while (0)
 
57
#else
 
58
#define DPRINTF(fmt, ...) do { } while (0)
 
59
#endif
 
60
 
 
61
struct pflash_t {
 
62
    BlockDriverState *bs;
 
63
    target_phys_addr_t base;
 
64
    target_phys_addr_t sector_len;
 
65
    target_phys_addr_t 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_phys_addr_t counter;
 
76
    unsigned int writeblock_size;
 
77
    QEMUTimer *timer;
 
78
    MemoryRegion 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
        memory_region_rom_device_set_readable(&pfl->mem, true);
 
93
        pfl->wcycle = 0;
 
94
    }
 
95
    pfl->cmd = 0;
 
96
}
 
97
 
 
98
static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 
99
                             int width, int be)
 
100
{
 
101
    target_phys_addr_t boff;
 
102
    uint32_t ret;
 
103
    uint8_t *p;
 
104
 
 
105
    ret = -1;
 
106
    boff = offset & 0xFF; /* why this here ?? */
 
107
 
 
108
    if (pfl->width == 2)
 
109
        boff = boff >> 1;
 
110
    else if (pfl->width == 4)
 
111
        boff = boff >> 2;
 
112
 
 
113
#if 0
 
114
    DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
 
115
            __func__, offset, pfl->cmd, width);
 
116
#endif
 
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_plx " %02x\n",
 
125
                    __func__, offset, ret);
 
126
            break;
 
127
        case 2:
 
128
            if (be) {
 
129
                ret = p[offset] << 8;
 
130
                ret |= p[offset + 1];
 
131
            } else {
 
132
                ret = p[offset];
 
133
                ret |= p[offset + 1] << 8;
 
134
            }
 
135
            DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
 
136
                    __func__, offset, ret);
 
137
            break;
 
138
        case 4:
 
139
            if (be) {
 
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
            }
 
151
            DPRINTF("%s: data offset " TARGET_FMT_plx " %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 0x90:
 
169
        switch (boff) {
 
170
        case 0:
 
171
            ret = pfl->ident[0] << 8 | pfl->ident[1];
 
172
            DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
 
173
            break;
 
174
        case 1:
 
175
            ret = pfl->ident[2] << 8 | pfl->ident[3];
 
176
            DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
 
177
            break;
 
178
        default:
 
179
            DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff);
 
180
            ret = 0;
 
181
            break;
 
182
        }
 
183
        break;
 
184
    case 0x98: /* Query mode */
 
185
        if (boff > pfl->cfi_len)
 
186
            ret = 0;
 
187
        else
 
188
            ret = pfl->cfi_table[boff];
 
189
        break;
 
190
    default:
 
191
        /* This should never happen : reset state & treat it as a read */
 
192
        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
 
193
        pfl->wcycle = 0;
 
194
        pfl->cmd = 0;
 
195
    }
 
196
    return ret;
 
197
}
 
198
 
 
199
/* update flash content on disk */
 
200
static void pflash_update(pflash_t *pfl, int offset,
 
201
                          int size)
 
202
{
 
203
    int offset_end;
 
204
    if (pfl->bs) {
 
205
        offset_end = offset + size;
 
206
        /* round to sectors */
 
207
        offset = offset >> 9;
 
208
        offset_end = (offset_end + 511) >> 9;
 
209
        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
 
210
                   offset_end - offset);
 
211
    }
 
212
}
 
213
 
 
214
static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset,
 
215
                                     uint32_t value, int width, int be)
 
216
{
 
217
    uint8_t *p = pfl->storage;
 
218
 
 
219
    DPRINTF("%s: block write offset " TARGET_FMT_plx
 
220
            " value %x counter " TARGET_FMT_plx "\n",
 
221
            __func__, offset, value, pfl->counter);
 
222
    switch (width) {
 
223
    case 1:
 
224
        p[offset] = value;
 
225
        break;
 
226
    case 2:
 
227
        if (be) {
 
228
            p[offset] = value >> 8;
 
229
            p[offset + 1] = value;
 
230
        } else {
 
231
            p[offset] = value;
 
232
            p[offset + 1] = value >> 8;
 
233
        }
 
234
        break;
 
235
    case 4:
 
236
        if (be) {
 
237
            p[offset] = value >> 24;
 
238
            p[offset + 1] = value >> 16;
 
239
            p[offset + 2] = value >> 8;
 
240
            p[offset + 3] = value;
 
241
        } else {
 
242
            p[offset] = value;
 
243
            p[offset + 1] = value >> 8;
 
244
            p[offset + 2] = value >> 16;
 
245
            p[offset + 3] = value >> 24;
 
246
        }
 
247
        break;
 
248
    }
 
249
 
 
250
}
 
251
 
 
252
static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
 
253
                         uint32_t value, int width, int be)
 
254
{
 
255
    uint8_t *p;
 
256
    uint8_t cmd;
 
257
 
 
258
    cmd = value;
 
259
 
 
260
    DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
 
261
            __func__, offset, value, width, pfl->wcycle);
 
262
 
 
263
    if (!pfl->wcycle) {
 
264
        /* Set the device in I/O access mode */
 
265
        memory_region_rom_device_set_readable(&pfl->mem, false);
 
266
    }
 
267
 
 
268
    switch (pfl->wcycle) {
 
269
    case 0:
 
270
        /* read mode */
 
271
        switch (cmd) {
 
272
        case 0x00: /* ??? */
 
273
            goto reset_flash;
 
274
        case 0x10: /* Single Byte Program */
 
275
        case 0x40: /* Single Byte Program */
 
276
            DPRINTF("%s: Single Byte Program\n", __func__);
 
277
            break;
 
278
        case 0x20: /* Block erase */
 
279
            p = pfl->storage;
 
280
            offset &= ~(pfl->sector_len - 1);
 
281
 
 
282
            DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
 
283
                    TARGET_FMT_plx "\n",
 
284
                    __func__, offset, pfl->sector_len);
 
285
 
 
286
            memset(p + offset, 0xff, pfl->sector_len);
 
287
            pflash_update(pfl, offset, pfl->sector_len);
 
288
            pfl->status |= 0x80; /* Ready! */
 
289
            break;
 
290
        case 0x50: /* Clear status bits */
 
291
            DPRINTF("%s: Clear status bits\n", __func__);
 
292
            pfl->status = 0x0;
 
293
            goto reset_flash;
 
294
        case 0x60: /* Block (un)lock */
 
295
            DPRINTF("%s: Block unlock\n", __func__);
 
296
            break;
 
297
        case 0x70: /* Status Register */
 
298
            DPRINTF("%s: Read status register\n", __func__);
 
299
            pfl->cmd = cmd;
 
300
            return;
 
301
        case 0x90: /* Read Device ID */
 
302
            DPRINTF("%s: Read Device information\n", __func__);
 
303
            pfl->cmd = cmd;
 
304
            return;
 
305
        case 0x98: /* CFI query */
 
306
            DPRINTF("%s: CFI query\n", __func__);
 
307
            break;
 
308
        case 0xe8: /* Write to buffer */
 
309
            DPRINTF("%s: Write to buffer\n", __func__);
 
310
            pfl->status |= 0x80; /* Ready! */
 
311
            break;
 
312
        case 0xff: /* Read array mode */
 
313
            DPRINTF("%s: Read array mode\n", __func__);
 
314
            goto reset_flash;
 
315
        default:
 
316
            goto error_flash;
 
317
        }
 
318
        pfl->wcycle++;
 
319
        pfl->cmd = cmd;
 
320
        return;
 
321
    case 1:
 
322
        switch (pfl->cmd) {
 
323
        case 0x10: /* Single Byte Program */
 
324
        case 0x40: /* Single Byte Program */
 
325
            DPRINTF("%s: Single Byte Program\n", __func__);
 
326
            pflash_data_write(pfl, offset, value, width, be);
 
327
            pflash_update(pfl, offset, width);
 
328
            pfl->status |= 0x80; /* Ready! */
 
329
            pfl->wcycle = 0;
 
330
        break;
 
331
        case 0x20: /* Block erase */
 
332
        case 0x28:
 
333
            if (cmd == 0xd0) { /* confirm */
 
334
                pfl->wcycle = 0;
 
335
                pfl->status |= 0x80;
 
336
            } else if (cmd == 0xff) { /* read array mode */
 
337
                goto reset_flash;
 
338
            } else
 
339
                goto error_flash;
 
340
 
 
341
            break;
 
342
        case 0xe8:
 
343
            DPRINTF("%s: block write of %x bytes\n", __func__, value);
 
344
            pfl->counter = value;
 
345
            pfl->wcycle++;
 
346
            break;
 
347
        case 0x60:
 
348
            if (cmd == 0xd0) {
 
349
                pfl->wcycle = 0;
 
350
                pfl->status |= 0x80;
 
351
            } else if (cmd == 0x01) {
 
352
                pfl->wcycle = 0;
 
353
                pfl->status |= 0x80;
 
354
            } else if (cmd == 0xff) {
 
355
                goto reset_flash;
 
356
            } else {
 
357
                DPRINTF("%s: Unknown (un)locking command\n", __func__);
 
358
                goto reset_flash;
 
359
            }
 
360
            break;
 
361
        case 0x98:
 
362
            if (cmd == 0xff) {
 
363
                goto reset_flash;
 
364
            } else {
 
365
                DPRINTF("%s: leaving query mode\n", __func__);
 
366
            }
 
367
            break;
 
368
        default:
 
369
            goto error_flash;
 
370
        }
 
371
        return;
 
372
    case 2:
 
373
        switch (pfl->cmd) {
 
374
        case 0xe8: /* Block write */
 
375
            pflash_data_write(pfl, offset, value, width, be);
 
376
 
 
377
            pfl->status |= 0x80;
 
378
 
 
379
            if (!pfl->counter) {
 
380
                target_phys_addr_t mask = pfl->writeblock_size - 1;
 
381
                mask = ~mask;
 
382
 
 
383
                DPRINTF("%s: block write finished\n", __func__);
 
384
                pfl->wcycle++;
 
385
                /* Flush the entire write buffer onto backing storage.  */
 
386
                pflash_update(pfl, offset & mask, pfl->writeblock_size);
 
387
            }
 
388
 
 
389
            pfl->counter--;
 
390
            break;
 
391
        default:
 
392
            goto error_flash;
 
393
        }
 
394
        return;
 
395
    case 3: /* Confirm mode */
 
396
        switch (pfl->cmd) {
 
397
        case 0xe8: /* Block write */
 
398
            if (cmd == 0xd0) {
 
399
                pfl->wcycle = 0;
 
400
                pfl->status |= 0x80;
 
401
            } else {
 
402
                DPRINTF("%s: unknown command for \"write block\"\n", __func__);
 
403
                PFLASH_BUG("Write block confirm");
 
404
                goto reset_flash;
 
405
            }
 
406
            break;
 
407
        default:
 
408
            goto error_flash;
 
409
        }
 
410
        return;
 
411
    default:
 
412
        /* Should never happen */
 
413
        DPRINTF("%s: invalid write state\n",  __func__);
 
414
        goto reset_flash;
 
415
    }
 
416
    return;
 
417
 
 
418
 error_flash:
 
419
    printf("%s: Unimplemented flash cmd sequence "
 
420
           "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
 
421
           __func__, offset, pfl->wcycle, pfl->cmd, value);
 
422
 
 
423
 reset_flash:
 
424
    memory_region_rom_device_set_readable(&pfl->mem, true);
 
425
 
 
426
    pfl->bypass = 0;
 
427
    pfl->wcycle = 0;
 
428
    pfl->cmd = 0;
 
429
    return;
 
430
}
 
431
 
 
432
 
 
433
static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
 
434
{
 
435
    return pflash_read(opaque, addr, 1, 1);
 
436
}
 
437
 
 
438
static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
 
439
{
 
440
    return pflash_read(opaque, addr, 1, 0);
 
441
}
 
442
 
 
443
static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
 
444
{
 
445
    pflash_t *pfl = opaque;
 
446
 
 
447
    return pflash_read(pfl, addr, 2, 1);
 
448
}
 
449
 
 
450
static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
 
451
{
 
452
    pflash_t *pfl = opaque;
 
453
 
 
454
    return pflash_read(pfl, addr, 2, 0);
 
455
}
 
456
 
 
457
static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
 
458
{
 
459
    pflash_t *pfl = opaque;
 
460
 
 
461
    return pflash_read(pfl, addr, 4, 1);
 
462
}
 
463
 
 
464
static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
 
465
{
 
466
    pflash_t *pfl = opaque;
 
467
 
 
468
    return pflash_read(pfl, addr, 4, 0);
 
469
}
 
470
 
 
471
static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
 
472
                             uint32_t value)
 
473
{
 
474
    pflash_write(opaque, addr, value, 1, 1);
 
475
}
 
476
 
 
477
static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
 
478
                             uint32_t value)
 
479
{
 
480
    pflash_write(opaque, addr, value, 1, 0);
 
481
}
 
482
 
 
483
static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
 
484
                             uint32_t value)
 
485
{
 
486
    pflash_t *pfl = opaque;
 
487
 
 
488
    pflash_write(pfl, addr, value, 2, 1);
 
489
}
 
490
 
 
491
static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
 
492
                             uint32_t value)
 
493
{
 
494
    pflash_t *pfl = opaque;
 
495
 
 
496
    pflash_write(pfl, addr, value, 2, 0);
 
497
}
 
498
 
 
499
static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
 
500
                             uint32_t value)
 
501
{
 
502
    pflash_t *pfl = opaque;
 
503
 
 
504
    pflash_write(pfl, addr, value, 4, 1);
 
505
}
 
506
 
 
507
static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
 
508
                             uint32_t value)
 
509
{
 
510
    pflash_t *pfl = opaque;
 
511
 
 
512
    pflash_write(pfl, addr, value, 4, 0);
 
513
}
 
514
 
 
515
static const MemoryRegionOps pflash_cfi01_ops_be = {
 
516
    .old_mmio = {
 
517
        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
 
518
        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
 
519
    },
 
520
    .endianness = DEVICE_NATIVE_ENDIAN,
 
521
};
 
522
 
 
523
static const MemoryRegionOps pflash_cfi01_ops_le = {
 
524
    .old_mmio = {
 
525
        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
 
526
        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
 
527
    },
 
528
    .endianness = DEVICE_NATIVE_ENDIAN,
 
529
};
 
530
 
 
531
/* Count trailing zeroes of a 32 bits quantity */
 
532
static int ctz32 (uint32_t n)
 
533
{
 
534
    int ret;
 
535
 
 
536
    ret = 0;
 
537
    if (!(n & 0xFFFF)) {
 
538
        ret += 16;
 
539
        n = n >> 16;
 
540
    }
 
541
    if (!(n & 0xFF)) {
 
542
        ret += 8;
 
543
        n = n >> 8;
 
544
    }
 
545
    if (!(n & 0xF)) {
 
546
        ret += 4;
 
547
        n = n >> 4;
 
548
    }
 
549
    if (!(n & 0x3)) {
 
550
        ret += 2;
 
551
        n = n >> 2;
 
552
    }
 
553
    if (!(n & 0x1)) {
 
554
        ret++;
 
555
#if 0 /* This is not necessary as n is never 0 */
 
556
        n = n >> 1;
 
557
#endif
 
558
    }
 
559
#if 0 /* This is not necessary as n is never 0 */
 
560
    if (!n)
 
561
        ret++;
 
562
#endif
 
563
 
 
564
    return ret;
 
565
}
 
566
 
 
567
pflash_t *pflash_cfi01_register(target_phys_addr_t base,
 
568
                                DeviceState *qdev, const char *name,
 
569
                                target_phys_addr_t size,
 
570
                                BlockDriverState *bs, uint32_t sector_len,
 
571
                                int nb_blocs, int width,
 
572
                                uint16_t id0, uint16_t id1,
 
573
                                uint16_t id2, uint16_t id3, int be)
 
574
{
 
575
    pflash_t *pfl;
 
576
    target_phys_addr_t total_len;
 
577
    int ret;
 
578
 
 
579
    total_len = sector_len * nb_blocs;
 
580
 
 
581
    /* XXX: to be fixed */
 
582
#if 0
 
583
    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
 
584
        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
 
585
        return NULL;
 
586
#endif
 
587
 
 
588
    pfl = g_malloc0(sizeof(pflash_t));
 
589
 
 
590
    memory_region_init_rom_device(
 
591
        &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
 
592
        qdev, name, size);
 
593
    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
 
594
    memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
 
595
 
 
596
    pfl->bs = bs;
 
597
    if (pfl->bs) {
 
598
        /* read the initial flash content */
 
599
        ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
 
600
        if (ret < 0) {
 
601
            memory_region_del_subregion(get_system_memory(), &pfl->mem);
 
602
            memory_region_destroy(&pfl->mem);
 
603
            g_free(pfl);
 
604
            return NULL;
 
605
        }
 
606
        bdrv_attach_dev_nofail(pfl->bs, pfl);
 
607
    }
 
608
#if 0 /* XXX: there should be a bit to set up read-only,
 
609
       *      the same way the hardware does (with WP pin).
 
610
       */
 
611
    pfl->ro = 1;
 
612
#else
 
613
    pfl->ro = 0;
 
614
#endif
 
615
    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
 
616
    pfl->base = base;
 
617
    pfl->sector_len = sector_len;
 
618
    pfl->total_len = total_len;
 
619
    pfl->width = width;
 
620
    pfl->wcycle = 0;
 
621
    pfl->cmd = 0;
 
622
    pfl->status = 0;
 
623
    pfl->ident[0] = id0;
 
624
    pfl->ident[1] = id1;
 
625
    pfl->ident[2] = id2;
 
626
    pfl->ident[3] = id3;
 
627
    /* Hardcoded CFI table */
 
628
    pfl->cfi_len = 0x52;
 
629
    /* Standard "QRY" string */
 
630
    pfl->cfi_table[0x10] = 'Q';
 
631
    pfl->cfi_table[0x11] = 'R';
 
632
    pfl->cfi_table[0x12] = 'Y';
 
633
    /* Command set (Intel) */
 
634
    pfl->cfi_table[0x13] = 0x01;
 
635
    pfl->cfi_table[0x14] = 0x00;
 
636
    /* Primary extended table address (none) */
 
637
    pfl->cfi_table[0x15] = 0x31;
 
638
    pfl->cfi_table[0x16] = 0x00;
 
639
    /* Alternate command set (none) */
 
640
    pfl->cfi_table[0x17] = 0x00;
 
641
    pfl->cfi_table[0x18] = 0x00;
 
642
    /* Alternate extended table (none) */
 
643
    pfl->cfi_table[0x19] = 0x00;
 
644
    pfl->cfi_table[0x1A] = 0x00;
 
645
    /* Vcc min */
 
646
    pfl->cfi_table[0x1B] = 0x45;
 
647
    /* Vcc max */
 
648
    pfl->cfi_table[0x1C] = 0x55;
 
649
    /* Vpp min (no Vpp pin) */
 
650
    pfl->cfi_table[0x1D] = 0x00;
 
651
    /* Vpp max (no Vpp pin) */
 
652
    pfl->cfi_table[0x1E] = 0x00;
 
653
    /* Reserved */
 
654
    pfl->cfi_table[0x1F] = 0x07;
 
655
    /* Timeout for min size buffer write */
 
656
    pfl->cfi_table[0x20] = 0x07;
 
657
    /* Typical timeout for block erase */
 
658
    pfl->cfi_table[0x21] = 0x0a;
 
659
    /* Typical timeout for full chip erase (4096 ms) */
 
660
    pfl->cfi_table[0x22] = 0x00;
 
661
    /* Reserved */
 
662
    pfl->cfi_table[0x23] = 0x04;
 
663
    /* Max timeout for buffer write */
 
664
    pfl->cfi_table[0x24] = 0x04;
 
665
    /* Max timeout for block erase */
 
666
    pfl->cfi_table[0x25] = 0x04;
 
667
    /* Max timeout for chip erase */
 
668
    pfl->cfi_table[0x26] = 0x00;
 
669
    /* Device size */
 
670
    pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
 
671
    /* Flash device interface (8 & 16 bits) */
 
672
    pfl->cfi_table[0x28] = 0x02;
 
673
    pfl->cfi_table[0x29] = 0x00;
 
674
    /* Max number of bytes in multi-bytes write */
 
675
    if (width == 1) {
 
676
        pfl->cfi_table[0x2A] = 0x08;
 
677
    } else {
 
678
        pfl->cfi_table[0x2A] = 0x0B;
 
679
    }
 
680
    pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
 
681
 
 
682
    pfl->cfi_table[0x2B] = 0x00;
 
683
    /* Number of erase block regions (uniform) */
 
684
    pfl->cfi_table[0x2C] = 0x01;
 
685
    /* Erase block region 1 */
 
686
    pfl->cfi_table[0x2D] = nb_blocs - 1;
 
687
    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
 
688
    pfl->cfi_table[0x2F] = sector_len >> 8;
 
689
    pfl->cfi_table[0x30] = sector_len >> 16;
 
690
 
 
691
    /* Extended */
 
692
    pfl->cfi_table[0x31] = 'P';
 
693
    pfl->cfi_table[0x32] = 'R';
 
694
    pfl->cfi_table[0x33] = 'I';
 
695
 
 
696
    pfl->cfi_table[0x34] = '1';
 
697
    pfl->cfi_table[0x35] = '1';
 
698
 
 
699
    pfl->cfi_table[0x36] = 0x00;
 
700
    pfl->cfi_table[0x37] = 0x00;
 
701
    pfl->cfi_table[0x38] = 0x00;
 
702
    pfl->cfi_table[0x39] = 0x00;
 
703
 
 
704
    pfl->cfi_table[0x3a] = 0x00;
 
705
 
 
706
    pfl->cfi_table[0x3b] = 0x00;
 
707
    pfl->cfi_table[0x3c] = 0x00;
 
708
 
 
709
    return pfl;
 
710
}
 
711
 
 
712
MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
 
713
{
 
714
    return &fl->mem;
 
715
}