pflash_cfi02.c 21.4 KB
Newer Older
1 2
/*
 *  CFI parallel flash with AMD command set emulation
3
 *
4 5 6 7 8 9 10 11 12 13 14 15 16
 *  Copyright (c) 2005 Jocelyn Mayer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 */

/*
 * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
 * Supported commands/modes are:
 * - flash read
 * - flash write
 * - flash ID read
 * - sector erase
 * - chip erase
 * - unlock bypass command
 * - CFI queries
 *
 * It does not support flash interleaving.
 * It does not implement boot blocs with reduced size
 * It does not implement software data protection as found in many real chips
 * It does not implement erase suspend/resume commands
 * It does not implement multiple sectors erase
 */

P
pbrook 已提交
38 39 40 41
#include "hw.h"
#include "flash.h"
#include "qemu-timer.h"
#include "block.h"
42 43 44

//#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
45
#define DPRINTF(fmt, ...)                          \
46
do {                                               \
47
    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
48 49
} while (0)
#else
50
#define DPRINTF(fmt, ...) do { } while (0)
51 52
#endif

53 54
#define PFLASH_LAZY_ROMD_THRESHOLD 42

A
Anthony Liguori 已提交
55
struct pflash_t {
56
    BlockDriverState *bs;
A
Anthony Liguori 已提交
57
    target_phys_addr_t base;
58
    uint32_t sector_len;
59 60
    uint32_t chip_len;
    int mappings;
61 62 63 64 65 66 67
    int width;
    int wcycle; /* if 0, the flash is read normally */
    int bypass;
    int ro;
    uint8_t cmd;
    uint8_t status;
    uint16_t ident[4];
68
    uint16_t unlock_addr[2];
69 70 71
    uint8_t cfi_len;
    uint8_t cfi_table[0x52];
    QEMUTimer *timer;
72 73
    ram_addr_t off;
    int fl_mem;
74
    int rom_mode;
75
    int read_counter; /* used for lazy switch-back to rom mode */
76 77 78
    void *storage;
};

79 80
static void pflash_register_memory(pflash_t *pfl, int rom_mode)
{
81 82 83 84 85 86 87 88 89 90
    unsigned long phys_offset = pfl->fl_mem;
    int i;

    if (rom_mode)
        phys_offset |= pfl->off | IO_MEM_ROMD;
    pfl->rom_mode = rom_mode;

    for (i = 0; i < pfl->mappings; i++)
        cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
                                     pfl->chip_len, phys_offset);
91 92
}

93 94
static void pflash_timer (void *opaque)
{
A
Anthony Liguori 已提交
95
    pflash_t *pfl = opaque;
96 97 98 99 100 101 102

    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
    /* Reset flash */
    pfl->status ^= 0x80;
    if (pfl->bypass) {
        pfl->wcycle = 2;
    } else {
103
        pflash_register_memory(pfl, 1);
104 105 106 107 108
        pfl->wcycle = 0;
    }
    pfl->cmd = 0;
}

B
Blue Swirl 已提交
109 110
static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
                             int width, int be)
111
{
112
    target_phys_addr_t boff;
113 114 115
    uint32_t ret;
    uint8_t *p;

116
    DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
117
    ret = -1;
118 119 120 121
    /* Lazy reset to ROMD mode after a certain amount of read accesses */
    if (!pfl->rom_mode && pfl->wcycle == 0 &&
        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
        pflash_register_memory(pfl, 1);
P
pbrook 已提交
122
    }
123
    offset &= pfl->chip_len - 1;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    boff = offset & 0xFF;
    if (pfl->width == 2)
        boff = boff >> 1;
    else if (pfl->width == 4)
        boff = boff >> 2;
    switch (pfl->cmd) {
    default:
        /* This should never happen : reset state & treat it as a read*/
        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
        pfl->wcycle = 0;
        pfl->cmd = 0;
    case 0x80:
        /* We accept reads during second unlock sequence... */
    case 0x00:
    flash_read:
        /* Flash area read */
        p = pfl->storage;
        switch (width) {
        case 1:
            ret = p[offset];
//            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
            break;
        case 2:
B
Blue Swirl 已提交
147 148 149 150 151 152 153
            if (be) {
                ret = p[offset] << 8;
                ret |= p[offset + 1];
            } else {
                ret = p[offset];
                ret |= p[offset + 1] << 8;
            }
154 155 156
//            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
            break;
        case 4:
B
Blue Swirl 已提交
157 158 159 160 161 162 163 164 165 166 167
            if (be) {
                ret = p[offset] << 24;
                ret |= p[offset + 1] << 16;
                ret |= p[offset + 2] << 8;
                ret |= p[offset + 3];
            } else {
                ret = p[offset];
                ret |= p[offset + 1] << 8;
                ret |= p[offset + 2] << 16;
                ret |= p[offset + 3] << 24;
            }
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
//            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
            break;
        }
        break;
    case 0x90:
        /* flash ID read */
        switch (boff) {
        case 0x00:
        case 0x01:
            ret = pfl->ident[boff & 0x01];
            break;
        case 0x02:
            ret = 0x00; /* Pretend all sectors are unprotected */
            break;
        case 0x0E:
        case 0x0F:
            if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
                goto flash_read;
            ret = pfl->ident[2 + (boff & 0x01)];
            break;
        default:
            goto flash_read;
        }
191
        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
        break;
    case 0xA0:
    case 0x10:
    case 0x30:
        /* Status register read */
        ret = pfl->status;
        DPRINTF("%s: status %x\n", __func__, ret);
        /* Toggle bit 6 */
        pfl->status ^= 0x40;
        break;
    case 0x98:
        /* CFI query mode */
        if (boff > pfl->cfi_len)
            ret = 0;
        else
            ret = pfl->cfi_table[boff];
        break;
    }

    return ret;
}

/* update flash content on disk */
A
Anthony Liguori 已提交
215
static void pflash_update(pflash_t *pfl, int offset,
216 217 218 219 220 221 222 223
                          int size)
{
    int offset_end;
    if (pfl->bs) {
        offset_end = offset + size;
        /* round to sectors */
        offset = offset >> 9;
        offset_end = (offset_end + 511) >> 9;
224
        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
225 226 227 228
                   offset_end - offset);
    }
}

229
static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
B
Blue Swirl 已提交
230
                          uint32_t value, int width, int be)
231
{
232
    target_phys_addr_t boff;
233 234 235
    uint8_t *p;
    uint8_t cmd;

J
j_mayer 已提交
236 237 238 239 240 241 242 243
    cmd = value;
    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
#if 0
        DPRINTF("%s: flash reset asked (%02x %02x)\n",
                __func__, pfl->cmd, cmd);
#endif
        goto reset_flash;
    }
244
    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
J
j_mayer 已提交
245
            offset, value, width, pfl->wcycle);
246
    offset &= pfl->chip_len - 1;
247

248
    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
249
            offset, value, width);
250 251 252 253 254 255 256
    boff = offset & (pfl->sector_len - 1);
    if (pfl->width == 2)
        boff = boff >> 1;
    else if (pfl->width == 4)
        boff = boff >> 2;
    switch (pfl->wcycle) {
    case 0:
257 258 259
        /* Set the device in I/O access mode if required */
        if (pfl->rom_mode)
            pflash_register_memory(pfl, 0);
260
        pfl->read_counter = 0;
261 262 263 264 265 266 267 268 269
        /* We're in read mode */
    check_unlock0:
        if (boff == 0x55 && cmd == 0x98) {
        enter_CFI_mode:
            /* Enter CFI query mode */
            pfl->wcycle = 7;
            pfl->cmd = 0x98;
            return;
        }
270
        if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
271
            DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
272
                    __func__, boff, cmd, pfl->unlock_addr[0]);
273 274 275 276 277 278 279
            goto reset_flash;
        }
        DPRINTF("%s: unlock sequence started\n", __func__);
        break;
    case 1:
        /* We started an unlock sequence */
    check_unlock1:
280
        if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
281
            DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
282
                    boff, cmd);
283 284 285 286 287 288
            goto reset_flash;
        }
        DPRINTF("%s: unlock sequence done\n", __func__);
        break;
    case 2:
        /* We finished an unlock sequence */
289
        if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
290
            DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
291
                    boff, cmd);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
            goto reset_flash;
        }
        switch (cmd) {
        case 0x20:
            pfl->bypass = 1;
            goto do_bypass;
        case 0x80:
        case 0x90:
        case 0xA0:
            pfl->cmd = cmd;
            DPRINTF("%s: starting command %02x\n", __func__, cmd);
            break;
        default:
            DPRINTF("%s: unknown command %02x\n", __func__, cmd);
            goto reset_flash;
        }
        break;
    case 3:
        switch (pfl->cmd) {
        case 0x80:
            /* We need another unlock sequence */
            goto check_unlock0;
        case 0xA0:
315
            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
316 317 318 319 320 321 322 323
                    __func__, offset, value, width);
            p = pfl->storage;
            switch (width) {
            case 1:
                p[offset] &= value;
                pflash_update(pfl, offset, 1);
                break;
            case 2:
B
Blue Swirl 已提交
324 325 326 327 328 329 330
                if (be) {
                    p[offset] &= value >> 8;
                    p[offset + 1] &= value;
                } else {
                    p[offset] &= value;
                    p[offset + 1] &= value >> 8;
                }
331 332 333
                pflash_update(pfl, offset, 2);
                break;
            case 4:
B
Blue Swirl 已提交
334 335 336 337 338 339 340 341 342 343 344
                if (be) {
                    p[offset] &= value >> 24;
                    p[offset + 1] &= value >> 16;
                    p[offset + 2] &= value >> 8;
                    p[offset + 3] &= value;
                } else {
                    p[offset] &= value;
                    p[offset + 1] &= value >> 8;
                    p[offset + 2] &= value >> 16;
                    p[offset + 3] &= value >> 24;
                }
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
                pflash_update(pfl, offset, 4);
                break;
            }
            pfl->status = 0x00 | ~(value & 0x80);
            /* Let's pretend write is immediate */
            if (pfl->bypass)
                goto do_bypass;
            goto reset_flash;
        case 0x90:
            if (pfl->bypass && cmd == 0x00) {
                /* Unlock bypass reset */
                goto reset_flash;
            }
            /* We can enter CFI query mode from autoselect mode */
            if (boff == 0x55 && cmd == 0x98)
                goto enter_CFI_mode;
            /* No break here */
        default:
            DPRINTF("%s: invalid write for command %02x\n",
                    __func__, pfl->cmd);
            goto reset_flash;
        }
    case 4:
        switch (pfl->cmd) {
        case 0xA0:
370
            /* Ignore writes while flash data write is occurring */
371 372 373 374 375 376 377 378 379 380 381 382 383 384
            /* As we suppose write is immediate, this should never happen */
            return;
        case 0x80:
            goto check_unlock1;
        default:
            /* Should never happen */
            DPRINTF("%s: invalid command state %02x (wc 4)\n",
                    __func__, pfl->cmd);
            goto reset_flash;
        }
        break;
    case 5:
        switch (cmd) {
        case 0x10:
385
            if (boff != pfl->unlock_addr[0]) {
386
                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
387 388 389 390 391
                        __func__, offset);
                goto reset_flash;
            }
            /* Chip erase */
            DPRINTF("%s: start chip erase\n", __func__);
392
            memset(pfl->storage, 0xFF, pfl->chip_len);
393
            pfl->status = 0x00;
394
            pflash_update(pfl, 0, pfl->chip_len);
395
            /* Let's wait 5 seconds before chip erase is done */
396
            qemu_mod_timer(pfl->timer,
397
                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
398 399 400 401 402
            break;
        case 0x30:
            /* Sector erase */
            p = pfl->storage;
            offset &= ~(pfl->sector_len - 1);
403
            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
404
                    offset);
405 406 407 408
            memset(p + offset, 0xFF, pfl->sector_len);
            pflash_update(pfl, offset, pfl->sector_len);
            pfl->status = 0x00;
            /* Let's wait 1/2 second before sector erase is done */
409
            qemu_mod_timer(pfl->timer,
410
                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
            break;
        default:
            DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
            goto reset_flash;
        }
        pfl->cmd = cmd;
        break;
    case 6:
        switch (pfl->cmd) {
        case 0x10:
            /* Ignore writes during chip erase */
            return;
        case 0x30:
            /* Ignore writes during sector erase */
            return;
        default:
            /* Should never happen */
            DPRINTF("%s: invalid command state %02x (wc 6)\n",
                    __func__, pfl->cmd);
            goto reset_flash;
        }
        break;
    case 7: /* Special value for CFI queries */
        DPRINTF("%s: invalid write in CFI query mode\n", __func__);
        goto reset_flash;
    default:
        /* Should never happen */
        DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
        goto reset_flash;
    }
    pfl->wcycle++;

    return;

    /* Reset flash */
 reset_flash:
    pfl->bypass = 0;
    pfl->wcycle = 0;
    pfl->cmd = 0;
    return;

 do_bypass:
    pfl->wcycle = 2;
    pfl->cmd = 0;
    return;
}


B
Blue Swirl 已提交
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
{
    return pflash_read(opaque, addr, 1, 1);
}

static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
{
    return pflash_read(opaque, addr, 1, 0);
}

static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
{
    pflash_t *pfl = opaque;

    return pflash_read(pfl, addr, 2, 1);
}

static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
{
    pflash_t *pfl = opaque;

    return pflash_read(pfl, addr, 2, 0);
}

static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
484
{
B
Blue Swirl 已提交
485 486 487
    pflash_t *pfl = opaque;

    return pflash_read(pfl, addr, 4, 1);
488 489
}

B
Blue Swirl 已提交
490
static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
491
{
A
Anthony Liguori 已提交
492
    pflash_t *pfl = opaque;
493

B
Blue Swirl 已提交
494 495 496 497 498 499 500
    return pflash_read(pfl, addr, 4, 0);
}

static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
{
    pflash_write(opaque, addr, value, 1, 1);
501 502
}

B
Blue Swirl 已提交
503 504 505 506 507 508 509 510
static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
{
    pflash_write(opaque, addr, value, 1, 0);
}

static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
511
{
A
Anthony Liguori 已提交
512
    pflash_t *pfl = opaque;
513

B
Blue Swirl 已提交
514
    pflash_write(pfl, addr, value, 2, 1);
515 516
}

B
Blue Swirl 已提交
517 518
static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
519
{
B
Blue Swirl 已提交
520 521 522
    pflash_t *pfl = opaque;

    pflash_write(pfl, addr, value, 2, 0);
523 524
}

B
Blue Swirl 已提交
525 526
static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
527
{
A
Anthony Liguori 已提交
528
    pflash_t *pfl = opaque;
529

B
Blue Swirl 已提交
530
    pflash_write(pfl, addr, value, 4, 1);
531 532
}

B
Blue Swirl 已提交
533 534
static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
535
{
A
Anthony Liguori 已提交
536
    pflash_t *pfl = opaque;
537

B
Blue Swirl 已提交
538
    pflash_write(pfl, addr, value, 4, 0);
539 540
}

541 542 543 544 545 546 547 548 549 550
static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
    &pflash_writeb_be,
    &pflash_writew_be,
    &pflash_writel_be,
};

static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
    &pflash_readb_be,
    &pflash_readw_be,
    &pflash_readl_be,
B
Blue Swirl 已提交
551 552
};

553 554 555 556 557 558 559 560 561 562
static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
    &pflash_writeb_le,
    &pflash_writew_le,
    &pflash_writel_le,
};

static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
    &pflash_readb_le,
    &pflash_readw_le,
    &pflash_readl_le,
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
};

/* Count trailing zeroes of a 32 bits quantity */
static int ctz32 (uint32_t n)
{
    int ret;

    ret = 0;
    if (!(n & 0xFFFF)) {
        ret += 16;
        n = n >> 16;
    }
    if (!(n & 0xFF)) {
        ret += 8;
        n = n >> 8;
    }
    if (!(n & 0xF)) {
        ret += 4;
        n = n >> 4;
    }
    if (!(n & 0x3)) {
        ret += 2;
        n = n >> 2;
    }
    if (!(n & 0x1)) {
        ret++;
589
#if 0 /* This is not necessary as n is never 0 */
590
        n = n >> 1;
591
#endif
592 593 594 595 596 597 598 599 600
    }
#if 0 /* This is not necessary as n is never 0 */
    if (!n)
        ret++;
#endif

    return ret;
}

601
pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
602
                                BlockDriverState *bs, uint32_t sector_len,
603
                                int nb_blocs, int nb_mappings, int width,
B
balrog 已提交
604
                                uint16_t id0, uint16_t id1,
605
                                uint16_t id2, uint16_t id3,
606 607
                                uint16_t unlock_addr0, uint16_t unlock_addr1,
                                int be)
608
{
A
Anthony Liguori 已提交
609
    pflash_t *pfl;
610
    int32_t chip_len;
611
    int ret;
612

613
    chip_len = sector_len * nb_blocs;
614
    /* XXX: to be fixed */
J
j_mayer 已提交
615
#if 0
616 617 618
    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
        return NULL;
J
j_mayer 已提交
619
#endif
620
    pfl = g_malloc0(sizeof(pflash_t));
P
pbrook 已提交
621
    /* FIXME: Allocate ram ourselves.  */
622 623 624 625 626 627 628 629 630 631 632
    pfl->storage = qemu_get_ram_ptr(off);
    if (be) {
        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
                                             pflash_write_ops_be,
                                             pfl, DEVICE_NATIVE_ENDIAN);
    } else {
        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
                                             pflash_write_ops_le,
                                             pfl, DEVICE_NATIVE_ENDIAN);
    }
    pfl->off = off;
633 634 635
    pfl->base = base;
    pfl->chip_len = chip_len;
    pfl->mappings = nb_mappings;
636
    pflash_register_memory(pfl, 1);
637 638 639
    pfl->bs = bs;
    if (pfl->bs) {
        /* read the initial flash content */
640 641
        ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
        if (ret < 0) {
642
            cpu_unregister_io_memory(pfl->fl_mem);
643
            g_free(pfl);
644 645
            return NULL;
        }
646 647 648 649 650 651 652 653
    }
#if 0 /* XXX: there should be a bit to set up read-only,
       *      the same way the hardware does (with WP pin).
       */
    pfl->ro = 1;
#else
    pfl->ro = 0;
#endif
654
    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
655 656 657 658 659 660 661 662 663
    pfl->sector_len = sector_len;
    pfl->width = width;
    pfl->wcycle = 0;
    pfl->cmd = 0;
    pfl->status = 0;
    pfl->ident[0] = id0;
    pfl->ident[1] = id1;
    pfl->ident[2] = id2;
    pfl->ident[3] = id3;
664 665
    pfl->unlock_addr[0] = unlock_addr0;
    pfl->unlock_addr[1] = unlock_addr1;
666 667 668 669 670 671 672 673 674
    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
    pfl->cfi_len = 0x52;
    /* Standard "QRY" string */
    pfl->cfi_table[0x10] = 'Q';
    pfl->cfi_table[0x11] = 'R';
    pfl->cfi_table[0x12] = 'Y';
    /* Command set (AMD/Fujitsu) */
    pfl->cfi_table[0x13] = 0x02;
    pfl->cfi_table[0x14] = 0x00;
E
edgar_igl 已提交
675 676
    /* Primary extended table address */
    pfl->cfi_table[0x15] = 0x31;
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
    pfl->cfi_table[0x16] = 0x00;
    /* Alternate command set (none) */
    pfl->cfi_table[0x17] = 0x00;
    pfl->cfi_table[0x18] = 0x00;
    /* Alternate extended table (none) */
    pfl->cfi_table[0x19] = 0x00;
    pfl->cfi_table[0x1A] = 0x00;
    /* Vcc min */
    pfl->cfi_table[0x1B] = 0x27;
    /* Vcc max */
    pfl->cfi_table[0x1C] = 0x36;
    /* Vpp min (no Vpp pin) */
    pfl->cfi_table[0x1D] = 0x00;
    /* Vpp max (no Vpp pin) */
    pfl->cfi_table[0x1E] = 0x00;
    /* Reserved */
    pfl->cfi_table[0x1F] = 0x07;
E
edgar_igl 已提交
694 695
    /* Timeout for min size buffer write (NA) */
    pfl->cfi_table[0x20] = 0x00;
696 697 698 699 700 701
    /* Typical timeout for block erase (512 ms) */
    pfl->cfi_table[0x21] = 0x09;
    /* Typical timeout for full chip erase (4096 ms) */
    pfl->cfi_table[0x22] = 0x0C;
    /* Reserved */
    pfl->cfi_table[0x23] = 0x01;
E
edgar_igl 已提交
702 703
    /* Max timeout for buffer write (NA) */
    pfl->cfi_table[0x24] = 0x00;
704 705 706 707 708
    /* Max timeout for block erase */
    pfl->cfi_table[0x25] = 0x0A;
    /* Max timeout for chip erase */
    pfl->cfi_table[0x26] = 0x0D;
    /* Device size */
E
edgar_igl 已提交
709
    pfl->cfi_table[0x27] = ctz32(chip_len);
710 711 712 713
    /* Flash device interface (8 & 16 bits) */
    pfl->cfi_table[0x28] = 0x02;
    pfl->cfi_table[0x29] = 0x00;
    /* Max number of bytes in multi-bytes write */
J
j_mayer 已提交
714 715 716
    /* XXX: disable buffered write as it's not supported */
    //    pfl->cfi_table[0x2A] = 0x05;
    pfl->cfi_table[0x2A] = 0x00;
717 718 719 720 721 722 723 724 725
    pfl->cfi_table[0x2B] = 0x00;
    /* Number of erase block regions (uniform) */
    pfl->cfi_table[0x2C] = 0x01;
    /* Erase block region 1 */
    pfl->cfi_table[0x2D] = nb_blocs - 1;
    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
    pfl->cfi_table[0x2F] = sector_len >> 8;
    pfl->cfi_table[0x30] = sector_len >> 16;

E
edgar_igl 已提交
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
    /* Extended */
    pfl->cfi_table[0x31] = 'P';
    pfl->cfi_table[0x32] = 'R';
    pfl->cfi_table[0x33] = 'I';

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

    pfl->cfi_table[0x36] = 0x00;
    pfl->cfi_table[0x37] = 0x00;
    pfl->cfi_table[0x38] = 0x00;
    pfl->cfi_table[0x39] = 0x00;

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

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

744 745
    return pfl;
}