qemu/hw/pflash_cfi02.c
<<
>>
Prefs
   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, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20/*
  21 * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
  22 * Supported commands/modes are:
  23 * - flash read
  24 * - flash write
  25 * - flash ID read
  26 * - sector erase
  27 * - chip erase
  28 * - unlock bypass command
  29 * - CFI queries
  30 *
  31 * It does not support flash interleaving.
  32 * It does not implement boot blocs with reduced size
  33 * It does not implement software data protection as found in many real chips
  34 * It does not implement erase suspend/resume commands
  35 * It does not implement multiple sectors erase
  36 */
  37
  38#include "hw.h"
  39#include "flash.h"
  40#include "qemu-timer.h"
  41#include "block.h"
  42#include "exec-memory.h"
  43
  44//#define PFLASH_DEBUG
  45#ifdef PFLASH_DEBUG
  46#define DPRINTF(fmt, ...)                          \
  47do {                                               \
  48    printf("PFLASH: " fmt , ## __VA_ARGS__);       \
  49} while (0)
  50#else
  51#define DPRINTF(fmt, ...) do { } while (0)
  52#endif
  53
  54#define PFLASH_LAZY_ROMD_THRESHOLD 42
  55
  56struct pflash_t {
  57    BlockDriverState *bs;
  58    target_phys_addr_t base;
  59    uint32_t sector_len;
  60    uint32_t chip_len;
  61    int mappings;
  62    int width;
  63    int wcycle; /* if 0, the flash is read normally */
  64    int bypass;
  65    int ro;
  66    uint8_t cmd;
  67    uint8_t status;
  68    uint16_t ident[4];
  69    uint16_t unlock_addr[2];
  70    uint8_t cfi_len;
  71    uint8_t cfi_table[0x52];
  72    QEMUTimer *timer;
  73    /* The device replicates the flash memory across its memory space.  Emulate
  74     * that by having a container (.mem) filled with an array of aliases
  75     * (.mem_mappings) pointing to the flash memory (.orig_mem).
  76     */
  77    MemoryRegion mem;
  78    MemoryRegion *mem_mappings;    /* array; one per mapping */
  79    MemoryRegion orig_mem;
  80    int rom_mode;
  81    int read_counter; /* used for lazy switch-back to rom mode */
  82    void *storage;
  83};
  84
  85/*
  86 * Set up replicated mappings of the same region.
  87 */
  88static void pflash_setup_mappings(pflash_t *pfl)
  89{
  90    unsigned i;
  91    target_phys_addr_t size = memory_region_size(&pfl->orig_mem);
  92
  93    memory_region_init(&pfl->mem, "pflash", pfl->mappings * size);
  94    pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
  95    for (i = 0; i < pfl->mappings; ++i) {
  96        memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias",
  97                                 &pfl->orig_mem, 0, size);
  98        memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
  99    }
 100}
 101
 102static void pflash_register_memory(pflash_t *pfl, int rom_mode)
 103{
 104    memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
 105}
 106
 107static void pflash_timer (void *opaque)
 108{
 109    pflash_t *pfl = opaque;
 110
 111    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
 112    /* Reset flash */
 113    pfl->status ^= 0x80;
 114    if (pfl->bypass) {
 115        pfl->wcycle = 2;
 116    } else {
 117        pflash_register_memory(pfl, 1);
 118        pfl->wcycle = 0;
 119    }
 120    pfl->cmd = 0;
 121}
 122
 123static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 124                             int width, int be)
 125{
 126    target_phys_addr_t boff;
 127    uint32_t ret;
 128    uint8_t *p;
 129
 130    DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
 131    ret = -1;
 132    /* Lazy reset to ROMD mode after a certain amount of read accesses */
 133    if (!pfl->rom_mode && pfl->wcycle == 0 &&
 134        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
 135        pflash_register_memory(pfl, 1);
 136    }
 137    offset &= pfl->chip_len - 1;
 138    boff = offset & 0xFF;
 139    if (pfl->width == 2)
 140        boff = boff >> 1;
 141    else if (pfl->width == 4)
 142        boff = boff >> 2;
 143    switch (pfl->cmd) {
 144    default:
 145        /* This should never happen : reset state & treat it as a read*/
 146        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
 147        pfl->wcycle = 0;
 148        pfl->cmd = 0;
 149    case 0x80:
 150        /* We accept reads during second unlock sequence... */
 151    case 0x00:
 152    flash_read:
 153        /* Flash area read */
 154        p = pfl->storage;
 155        switch (width) {
 156        case 1:
 157            ret = p[offset];
 158//            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
 159            break;
 160        case 2:
 161            if (be) {
 162                ret = p[offset] << 8;
 163                ret |= p[offset + 1];
 164            } else {
 165                ret = p[offset];
 166                ret |= p[offset + 1] << 8;
 167            }
 168//            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
 169            break;
 170        case 4:
 171            if (be) {
 172                ret = p[offset] << 24;
 173                ret |= p[offset + 1] << 16;
 174                ret |= p[offset + 2] << 8;
 175                ret |= p[offset + 3];
 176            } else {
 177                ret = p[offset];
 178                ret |= p[offset + 1] << 8;
 179                ret |= p[offset + 2] << 16;
 180                ret |= p[offset + 3] << 24;
 181            }
 182//            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
 183            break;
 184        }
 185        break;
 186    case 0x90:
 187        /* flash ID read */
 188        switch (boff) {
 189        case 0x00:
 190        case 0x01:
 191            ret = pfl->ident[boff & 0x01];
 192            break;
 193        case 0x02:
 194            ret = 0x00; /* Pretend all sectors are unprotected */
 195            break;
 196        case 0x0E:
 197        case 0x0F:
 198            if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
 199                goto flash_read;
 200            ret = pfl->ident[2 + (boff & 0x01)];
 201            break;
 202        default:
 203            goto flash_read;
 204        }
 205        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
 206        break;
 207    case 0xA0:
 208    case 0x10:
 209    case 0x30:
 210        /* Status register read */
 211        ret = pfl->status;
 212        DPRINTF("%s: status %x\n", __func__, ret);
 213        /* Toggle bit 6 */
 214        pfl->status ^= 0x40;
 215        break;
 216    case 0x98:
 217        /* CFI query mode */
 218        if (boff > pfl->cfi_len)
 219            ret = 0;
 220        else
 221            ret = pfl->cfi_table[boff];
 222        break;
 223    }
 224
 225    return ret;
 226}
 227
 228/* update flash content on disk */
 229static void pflash_update(pflash_t *pfl, int offset,
 230                          int size)
 231{
 232    int offset_end;
 233    if (pfl->bs) {
 234        offset_end = offset + size;
 235        /* round to sectors */
 236        offset = offset >> 9;
 237        offset_end = (offset_end + 511) >> 9;
 238        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
 239                   offset_end - offset);
 240    }
 241}
 242
 243static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
 244                          uint32_t value, int width, int be)
 245{
 246    target_phys_addr_t boff;
 247    uint8_t *p;
 248    uint8_t cmd;
 249
 250    cmd = value;
 251    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
 252#if 0
 253        DPRINTF("%s: flash reset asked (%02x %02x)\n",
 254                __func__, pfl->cmd, cmd);
 255#endif
 256        goto reset_flash;
 257    }
 258    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
 259            offset, value, width, pfl->wcycle);
 260    offset &= pfl->chip_len - 1;
 261
 262    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
 263            offset, value, width);
 264    boff = offset & (pfl->sector_len - 1);
 265    if (pfl->width == 2)
 266        boff = boff >> 1;
 267    else if (pfl->width == 4)
 268        boff = boff >> 2;
 269    switch (pfl->wcycle) {
 270    case 0:
 271        /* Set the device in I/O access mode if required */
 272        if (pfl->rom_mode)
 273            pflash_register_memory(pfl, 0);
 274        pfl->read_counter = 0;
 275        /* We're in read mode */
 276    check_unlock0:
 277        if (boff == 0x55 && cmd == 0x98) {
 278        enter_CFI_mode:
 279            /* Enter CFI query mode */
 280            pfl->wcycle = 7;
 281            pfl->cmd = 0x98;
 282            return;
 283        }
 284        if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
 285            DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
 286                    __func__, boff, cmd, pfl->unlock_addr[0]);
 287            goto reset_flash;
 288        }
 289        DPRINTF("%s: unlock sequence started\n", __func__);
 290        break;
 291    case 1:
 292        /* We started an unlock sequence */
 293    check_unlock1:
 294        if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
 295            DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
 296                    boff, cmd);
 297            goto reset_flash;
 298        }
 299        DPRINTF("%s: unlock sequence done\n", __func__);
 300        break;
 301    case 2:
 302        /* We finished an unlock sequence */
 303        if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
 304            DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
 305                    boff, cmd);
 306            goto reset_flash;
 307        }
 308        switch (cmd) {
 309        case 0x20:
 310            pfl->bypass = 1;
 311            goto do_bypass;
 312        case 0x80:
 313        case 0x90:
 314        case 0xA0:
 315            pfl->cmd = cmd;
 316            DPRINTF("%s: starting command %02x\n", __func__, cmd);
 317            break;
 318        default:
 319            DPRINTF("%s: unknown command %02x\n", __func__, cmd);
 320            goto reset_flash;
 321        }
 322        break;
 323    case 3:
 324        switch (pfl->cmd) {
 325        case 0x80:
 326            /* We need another unlock sequence */
 327            goto check_unlock0;
 328        case 0xA0:
 329            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
 330                    __func__, offset, value, width);
 331            p = pfl->storage;
 332            switch (width) {
 333            case 1:
 334                p[offset] &= value;
 335                pflash_update(pfl, offset, 1);
 336                break;
 337            case 2:
 338                if (be) {
 339                    p[offset] &= value >> 8;
 340                    p[offset + 1] &= value;
 341                } else {
 342                    p[offset] &= value;
 343                    p[offset + 1] &= value >> 8;
 344                }
 345                pflash_update(pfl, offset, 2);
 346                break;
 347            case 4:
 348                if (be) {
 349                    p[offset] &= value >> 24;
 350                    p[offset + 1] &= value >> 16;
 351                    p[offset + 2] &= value >> 8;
 352                    p[offset + 3] &= value;
 353                } else {
 354                    p[offset] &= value;
 355                    p[offset + 1] &= value >> 8;
 356                    p[offset + 2] &= value >> 16;
 357                    p[offset + 3] &= value >> 24;
 358                }
 359                pflash_update(pfl, offset, 4);
 360                break;
 361            }
 362            pfl->status = 0x00 | ~(value & 0x80);
 363            /* Let's pretend write is immediate */
 364            if (pfl->bypass)
 365                goto do_bypass;
 366            goto reset_flash;
 367        case 0x90:
 368            if (pfl->bypass && cmd == 0x00) {
 369                /* Unlock bypass reset */
 370                goto reset_flash;
 371            }
 372            /* We can enter CFI query mode from autoselect mode */
 373            if (boff == 0x55 && cmd == 0x98)
 374                goto enter_CFI_mode;
 375            /* No break here */
 376        default:
 377            DPRINTF("%s: invalid write for command %02x\n",
 378                    __func__, pfl->cmd);
 379            goto reset_flash;
 380        }
 381    case 4:
 382        switch (pfl->cmd) {
 383        case 0xA0:
 384            /* Ignore writes while flash data write is occurring */
 385            /* As we suppose write is immediate, this should never happen */
 386            return;
 387        case 0x80:
 388            goto check_unlock1;
 389        default:
 390            /* Should never happen */
 391            DPRINTF("%s: invalid command state %02x (wc 4)\n",
 392                    __func__, pfl->cmd);
 393            goto reset_flash;
 394        }
 395        break;
 396    case 5:
 397        switch (cmd) {
 398        case 0x10:
 399            if (boff != pfl->unlock_addr[0]) {
 400                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
 401                        __func__, offset);
 402                goto reset_flash;
 403            }
 404            /* Chip erase */
 405            DPRINTF("%s: start chip erase\n", __func__);
 406            memset(pfl->storage, 0xFF, pfl->chip_len);
 407            pfl->status = 0x00;
 408            pflash_update(pfl, 0, pfl->chip_len);
 409            /* Let's wait 5 seconds before chip erase is done */
 410            qemu_mod_timer(pfl->timer,
 411                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
 412            break;
 413        case 0x30:
 414            /* Sector erase */
 415            p = pfl->storage;
 416            offset &= ~(pfl->sector_len - 1);
 417            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
 418                    offset);
 419            memset(p + offset, 0xFF, pfl->sector_len);
 420            pflash_update(pfl, offset, pfl->sector_len);
 421            pfl->status = 0x00;
 422            /* Let's wait 1/2 second before sector erase is done */
 423            qemu_mod_timer(pfl->timer,
 424                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
 425            break;
 426        default:
 427            DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
 428            goto reset_flash;
 429        }
 430        pfl->cmd = cmd;
 431        break;
 432    case 6:
 433        switch (pfl->cmd) {
 434        case 0x10:
 435            /* Ignore writes during chip erase */
 436            return;
 437        case 0x30:
 438            /* Ignore writes during sector erase */
 439            return;
 440        default:
 441            /* Should never happen */
 442            DPRINTF("%s: invalid command state %02x (wc 6)\n",
 443                    __func__, pfl->cmd);
 444            goto reset_flash;
 445        }
 446        break;
 447    case 7: /* Special value for CFI queries */
 448        DPRINTF("%s: invalid write in CFI query mode\n", __func__);
 449        goto reset_flash;
 450    default:
 451        /* Should never happen */
 452        DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
 453        goto reset_flash;
 454    }
 455    pfl->wcycle++;
 456
 457    return;
 458
 459    /* Reset flash */
 460 reset_flash:
 461    pfl->bypass = 0;
 462    pfl->wcycle = 0;
 463    pfl->cmd = 0;
 464    return;
 465
 466 do_bypass:
 467    pfl->wcycle = 2;
 468    pfl->cmd = 0;
 469    return;
 470}
 471
 472
 473static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
 474{
 475    return pflash_read(opaque, addr, 1, 1);
 476}
 477
 478static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
 479{
 480    return pflash_read(opaque, addr, 1, 0);
 481}
 482
 483static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
 484{
 485    pflash_t *pfl = opaque;
 486
 487    return pflash_read(pfl, addr, 2, 1);
 488}
 489
 490static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
 491{
 492    pflash_t *pfl = opaque;
 493
 494    return pflash_read(pfl, addr, 2, 0);
 495}
 496
 497static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
 498{
 499    pflash_t *pfl = opaque;
 500
 501    return pflash_read(pfl, addr, 4, 1);
 502}
 503
 504static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
 505{
 506    pflash_t *pfl = opaque;
 507
 508    return pflash_read(pfl, addr, 4, 0);
 509}
 510
 511static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
 512                             uint32_t value)
 513{
 514    pflash_write(opaque, addr, value, 1, 1);
 515}
 516
 517static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
 518                             uint32_t value)
 519{
 520    pflash_write(opaque, addr, value, 1, 0);
 521}
 522
 523static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
 524                             uint32_t value)
 525{
 526    pflash_t *pfl = opaque;
 527
 528    pflash_write(pfl, addr, value, 2, 1);
 529}
 530
 531static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
 532                             uint32_t value)
 533{
 534    pflash_t *pfl = opaque;
 535
 536    pflash_write(pfl, addr, value, 2, 0);
 537}
 538
 539static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
 540                             uint32_t value)
 541{
 542    pflash_t *pfl = opaque;
 543
 544    pflash_write(pfl, addr, value, 4, 1);
 545}
 546
 547static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
 548                             uint32_t value)
 549{
 550    pflash_t *pfl = opaque;
 551
 552    pflash_write(pfl, addr, value, 4, 0);
 553}
 554
 555static const MemoryRegionOps pflash_cfi02_ops_be = {
 556    .old_mmio = {
 557        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
 558        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
 559    },
 560    .endianness = DEVICE_NATIVE_ENDIAN,
 561};
 562
 563static const MemoryRegionOps pflash_cfi02_ops_le = {
 564    .old_mmio = {
 565        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
 566        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
 567    },
 568    .endianness = DEVICE_NATIVE_ENDIAN,
 569};
 570
 571/* Count trailing zeroes of a 32 bits quantity */
 572static int ctz32 (uint32_t n)
 573{
 574    int ret;
 575
 576    ret = 0;
 577    if (!(n & 0xFFFF)) {
 578        ret += 16;
 579        n = n >> 16;
 580    }
 581    if (!(n & 0xFF)) {
 582        ret += 8;
 583        n = n >> 8;
 584    }
 585    if (!(n & 0xF)) {
 586        ret += 4;
 587        n = n >> 4;
 588    }
 589    if (!(n & 0x3)) {
 590        ret += 2;
 591        n = n >> 2;
 592    }
 593    if (!(n & 0x1)) {
 594        ret++;
 595#if 0 /* This is not necessary as n is never 0 */
 596        n = n >> 1;
 597#endif
 598    }
 599#if 0 /* This is not necessary as n is never 0 */
 600    if (!n)
 601        ret++;
 602#endif
 603
 604    return ret;
 605}
 606
 607pflash_t *pflash_cfi02_register(target_phys_addr_t base,
 608                                DeviceState *qdev, const char *name,
 609                                target_phys_addr_t size,
 610                                BlockDriverState *bs, uint32_t sector_len,
 611                                int nb_blocs, int nb_mappings, int width,
 612                                uint16_t id0, uint16_t id1,
 613                                uint16_t id2, uint16_t id3,
 614                                uint16_t unlock_addr0, uint16_t unlock_addr1,
 615                                int be)
 616{
 617    pflash_t *pfl;
 618    int32_t chip_len;
 619    int ret;
 620
 621    chip_len = sector_len * nb_blocs;
 622    /* XXX: to be fixed */
 623#if 0
 624    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
 625        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
 626        return NULL;
 627#endif
 628    pfl = g_malloc0(sizeof(pflash_t));
 629    memory_region_init_rom_device(
 630        &pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
 631        qdev, name, size);
 632    pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
 633    pfl->base = base;
 634    pfl->chip_len = chip_len;
 635    pfl->mappings = nb_mappings;
 636    pfl->bs = bs;
 637    if (pfl->bs) {
 638        /* read the initial flash content */
 639        ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
 640        if (ret < 0) {
 641            g_free(pfl);
 642            return NULL;
 643        }
 644        bdrv_attach_dev_nofail(pfl->bs, pfl);
 645    }
 646    pflash_setup_mappings(pfl);
 647    pfl->rom_mode = 1;
 648    memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
 649#if 0 /* XXX: there should be a bit to set up read-only,
 650       *      the same way the hardware does (with WP pin).
 651       */
 652    pfl->ro = 1;
 653#else
 654    pfl->ro = 0;
 655#endif
 656    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
 657    pfl->sector_len = sector_len;
 658    pfl->width = width;
 659    pfl->wcycle = 0;
 660    pfl->cmd = 0;
 661    pfl->status = 0;
 662    pfl->ident[0] = id0;
 663    pfl->ident[1] = id1;
 664    pfl->ident[2] = id2;
 665    pfl->ident[3] = id3;
 666    pfl->unlock_addr[0] = unlock_addr0;
 667    pfl->unlock_addr[1] = unlock_addr1;
 668    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
 669    pfl->cfi_len = 0x52;
 670    /* Standard "QRY" string */
 671    pfl->cfi_table[0x10] = 'Q';
 672    pfl->cfi_table[0x11] = 'R';
 673    pfl->cfi_table[0x12] = 'Y';
 674    /* Command set (AMD/Fujitsu) */
 675    pfl->cfi_table[0x13] = 0x02;
 676    pfl->cfi_table[0x14] = 0x00;
 677    /* Primary extended table address */
 678    pfl->cfi_table[0x15] = 0x31;
 679    pfl->cfi_table[0x16] = 0x00;
 680    /* Alternate command set (none) */
 681    pfl->cfi_table[0x17] = 0x00;
 682    pfl->cfi_table[0x18] = 0x00;
 683    /* Alternate extended table (none) */
 684    pfl->cfi_table[0x19] = 0x00;
 685    pfl->cfi_table[0x1A] = 0x00;
 686    /* Vcc min */
 687    pfl->cfi_table[0x1B] = 0x27;
 688    /* Vcc max */
 689    pfl->cfi_table[0x1C] = 0x36;
 690    /* Vpp min (no Vpp pin) */
 691    pfl->cfi_table[0x1D] = 0x00;
 692    /* Vpp max (no Vpp pin) */
 693    pfl->cfi_table[0x1E] = 0x00;
 694    /* Reserved */
 695    pfl->cfi_table[0x1F] = 0x07;
 696    /* Timeout for min size buffer write (NA) */
 697    pfl->cfi_table[0x20] = 0x00;
 698    /* Typical timeout for block erase (512 ms) */
 699    pfl->cfi_table[0x21] = 0x09;
 700    /* Typical timeout for full chip erase (4096 ms) */
 701    pfl->cfi_table[0x22] = 0x0C;
 702    /* Reserved */
 703    pfl->cfi_table[0x23] = 0x01;
 704    /* Max timeout for buffer write (NA) */
 705    pfl->cfi_table[0x24] = 0x00;
 706    /* Max timeout for block erase */
 707    pfl->cfi_table[0x25] = 0x0A;
 708    /* Max timeout for chip erase */
 709    pfl->cfi_table[0x26] = 0x0D;
 710    /* Device size */
 711    pfl->cfi_table[0x27] = ctz32(chip_len);
 712    /* Flash device interface (8 & 16 bits) */
 713    pfl->cfi_table[0x28] = 0x02;
 714    pfl->cfi_table[0x29] = 0x00;
 715    /* Max number of bytes in multi-bytes write */
 716    /* XXX: disable buffered write as it's not supported */
 717    //    pfl->cfi_table[0x2A] = 0x05;
 718    pfl->cfi_table[0x2A] = 0x00;
 719    pfl->cfi_table[0x2B] = 0x00;
 720    /* Number of erase block regions (uniform) */
 721    pfl->cfi_table[0x2C] = 0x01;
 722    /* Erase block region 1 */
 723    pfl->cfi_table[0x2D] = nb_blocs - 1;
 724    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
 725    pfl->cfi_table[0x2F] = sector_len >> 8;
 726    pfl->cfi_table[0x30] = sector_len >> 16;
 727
 728    /* Extended */
 729    pfl->cfi_table[0x31] = 'P';
 730    pfl->cfi_table[0x32] = 'R';
 731    pfl->cfi_table[0x33] = 'I';
 732
 733    pfl->cfi_table[0x34] = '1';
 734    pfl->cfi_table[0x35] = '0';
 735
 736    pfl->cfi_table[0x36] = 0x00;
 737    pfl->cfi_table[0x37] = 0x00;
 738    pfl->cfi_table[0x38] = 0x00;
 739    pfl->cfi_table[0x39] = 0x00;
 740
 741    pfl->cfi_table[0x3a] = 0x00;
 742
 743    pfl->cfi_table[0x3b] = 0x00;
 744    pfl->cfi_table[0x3c] = 0x00;
 745
 746    return pfl;
 747}
 748