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