Commit 29133e9a0fff5775f8a1bef8671802a8624fc2c4

Authored by bellard
1 parent 9d42037b

AMD NOR flash device support (initial patch by Jocelyn Mayer)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2022 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 636 additions and 0 deletions
hw/pflash_cfi02.c 0 → 100644
  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, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  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 + * - chip erase
  29 + * - unlock bypass command
  30 + * - CFI queries
  31 + *
  32 + * It does not support flash interleaving.
  33 + * It does not implement boot blocs with reduced size
  34 + * It does not implement software data protection as found in many real chips
  35 + * It does not implement erase suspend/resume commands
  36 + * It does not implement multiple sectors erase
  37 + */
  38 +
  39 +#include "vl.h"
  40 +
  41 +//#define PFLASH_DEBUG
  42 +#ifdef PFLASH_DEBUG
  43 +#define DPRINTF(fmt, args...) \
  44 +do { \
  45 + if (loglevel) \
  46 + fprintf(logfile, "PFLASH: " fmt , ##args); \
  47 + else \
  48 + printf("PFLASH: " fmt , ##args); \
  49 +} while (0)
  50 +#else
  51 +#define DPRINTF(fmt, args...) do { } while (0)
  52 +#endif
  53 +
  54 +struct pflash_t {
  55 + BlockDriverState *bs;
  56 + target_ulong base;
  57 + target_ulong sector_len;
  58 + target_ulong total_len;
  59 + int width;
  60 + int wcycle; /* if 0, the flash is read normally */
  61 + int bypass;
  62 + int ro;
  63 + uint8_t cmd;
  64 + uint8_t status;
  65 + uint16_t ident[4];
  66 + uint8_t cfi_len;
  67 + uint8_t cfi_table[0x52];
  68 + QEMUTimer *timer;
  69 + ram_addr_t off;
  70 + int fl_mem;
  71 + void *storage;
  72 +};
  73 +
  74 +static void pflash_timer (void *opaque)
  75 +{
  76 + pflash_t *pfl = opaque;
  77 +
  78 + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
  79 + /* Reset flash */
  80 + pfl->status ^= 0x80;
  81 + if (pfl->bypass) {
  82 + pfl->wcycle = 2;
  83 + } else {
  84 + cpu_register_physical_memory(pfl->base, pfl->total_len,
  85 + pfl->off | IO_MEM_ROMD | pfl->fl_mem);
  86 + pfl->wcycle = 0;
  87 + }
  88 + pfl->cmd = 0;
  89 +}
  90 +
  91 +static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
  92 +{
  93 + target_ulong boff;
  94 + uint32_t ret;
  95 + uint8_t *p;
  96 +
  97 + DPRINTF("%s: offset %08x\n", __func__, offset);
  98 + ret = -1;
  99 + offset -= pfl->base;
  100 + boff = offset & 0xFF;
  101 + if (pfl->width == 2)
  102 + boff = boff >> 1;
  103 + else if (pfl->width == 4)
  104 + boff = boff >> 2;
  105 + switch (pfl->cmd) {
  106 + default:
  107 + /* This should never happen : reset state & treat it as a read*/
  108 + DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
  109 + pfl->wcycle = 0;
  110 + pfl->cmd = 0;
  111 + case 0x80:
  112 + /* We accept reads during second unlock sequence... */
  113 + case 0x00:
  114 + flash_read:
  115 + /* Flash area read */
  116 + p = pfl->storage;
  117 + switch (width) {
  118 + case 1:
  119 + ret = p[offset];
  120 +// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
  121 + break;
  122 + case 2:
  123 +#if defined(TARGET_WORDS_BIGENDIAN)
  124 + ret = p[offset] << 8;
  125 + ret |= p[offset + 1];
  126 +#else
  127 + ret = p[offset];
  128 + ret |= p[offset + 1] << 8;
  129 +#endif
  130 +// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
  131 + break;
  132 + case 4:
  133 +#if defined(TARGET_WORDS_BIGENDIAN)
  134 + ret = p[offset] << 24;
  135 + ret |= p[offset + 1] << 16;
  136 + ret |= p[offset + 2] << 8;
  137 + ret |= p[offset + 3];
  138 +#else
  139 + ret = p[offset];
  140 + ret |= p[offset + 1] << 8;
  141 + ret |= p[offset + 1] << 8;
  142 + ret |= p[offset + 2] << 16;
  143 + ret |= p[offset + 3] << 24;
  144 +#endif
  145 +// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
  146 + break;
  147 + }
  148 + break;
  149 + case 0x90:
  150 + /* flash ID read */
  151 + switch (boff) {
  152 + case 0x00:
  153 + case 0x01:
  154 + ret = pfl->ident[boff & 0x01];
  155 + break;
  156 + case 0x02:
  157 + ret = 0x00; /* Pretend all sectors are unprotected */
  158 + break;
  159 + case 0x0E:
  160 + case 0x0F:
  161 + if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
  162 + goto flash_read;
  163 + ret = pfl->ident[2 + (boff & 0x01)];
  164 + break;
  165 + default:
  166 + goto flash_read;
  167 + }
  168 + DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
  169 + break;
  170 + case 0xA0:
  171 + case 0x10:
  172 + case 0x30:
  173 + /* Status register read */
  174 + ret = pfl->status;
  175 + DPRINTF("%s: status %x\n", __func__, ret);
  176 + /* Toggle bit 6 */
  177 + pfl->status ^= 0x40;
  178 + break;
  179 + case 0x98:
  180 + /* CFI query mode */
  181 + if (boff > pfl->cfi_len)
  182 + ret = 0;
  183 + else
  184 + ret = pfl->cfi_table[boff];
  185 + break;
  186 + }
  187 +
  188 + return ret;
  189 +}
  190 +
  191 +/* update flash content on disk */
  192 +static void pflash_update(pflash_t *pfl, int offset,
  193 + int size)
  194 +{
  195 + int offset_end;
  196 + if (pfl->bs) {
  197 + offset_end = offset + size;
  198 + /* round to sectors */
  199 + offset = offset >> 9;
  200 + offset_end = (offset_end + 511) >> 9;
  201 + bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
  202 + offset_end - offset);
  203 + }
  204 +}
  205 +
  206 +static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
  207 + int width)
  208 +{
  209 + target_ulong boff;
  210 + uint8_t *p;
  211 + uint8_t cmd;
  212 +
  213 + /* WARNING: when the memory area is in ROMD mode, the offset is a
  214 + ram offset, not a physical address */
  215 + if (pfl->wcycle == 0)
  216 + offset -= pfl->off;
  217 + else
  218 + offset -= pfl->base;
  219 +
  220 + cmd = value;
  221 + DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
  222 + if (pfl->cmd != 0xA0 && cmd == 0xF0) {
  223 + DPRINTF("%s: flash reset asked (%02x %02x)\n",
  224 + __func__, pfl->cmd, cmd);
  225 + goto reset_flash;
  226 + }
  227 + /* Set the device in I/O access mode */
  228 + cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
  229 + boff = offset & (pfl->sector_len - 1);
  230 + if (pfl->width == 2)
  231 + boff = boff >> 1;
  232 + else if (pfl->width == 4)
  233 + boff = boff >> 2;
  234 + switch (pfl->wcycle) {
  235 + case 0:
  236 + /* We're in read mode */
  237 + check_unlock0:
  238 + if (boff == 0x55 && cmd == 0x98) {
  239 + enter_CFI_mode:
  240 + /* Enter CFI query mode */
  241 + pfl->wcycle = 7;
  242 + pfl->cmd = 0x98;
  243 + return;
  244 + }
  245 + if (boff != 0x555 || cmd != 0xAA) {
  246 + DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
  247 + __func__, boff, cmd, 0x555);
  248 + goto reset_flash;
  249 + }
  250 + DPRINTF("%s: unlock sequence started\n", __func__);
  251 + break;
  252 + case 1:
  253 + /* We started an unlock sequence */
  254 + check_unlock1:
  255 + if (boff != 0x2AA || cmd != 0x55) {
  256 + DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
  257 + goto reset_flash;
  258 + }
  259 + DPRINTF("%s: unlock sequence done\n", __func__);
  260 + break;
  261 + case 2:
  262 + /* We finished an unlock sequence */
  263 + if (!pfl->bypass && boff != 0x555) {
  264 + DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
  265 + goto reset_flash;
  266 + }
  267 + switch (cmd) {
  268 + case 0x20:
  269 + pfl->bypass = 1;
  270 + goto do_bypass;
  271 + case 0x80:
  272 + case 0x90:
  273 + case 0xA0:
  274 + pfl->cmd = cmd;
  275 + DPRINTF("%s: starting command %02x\n", __func__, cmd);
  276 + break;
  277 + default:
  278 + DPRINTF("%s: unknown command %02x\n", __func__, cmd);
  279 + goto reset_flash;
  280 + }
  281 + break;
  282 + case 3:
  283 + switch (pfl->cmd) {
  284 + case 0x80:
  285 + /* We need another unlock sequence */
  286 + goto check_unlock0;
  287 + case 0xA0:
  288 + DPRINTF("%s: write data offset %08x %08x %d\n",
  289 + __func__, offset, value, width);
  290 + p = pfl->storage;
  291 + switch (width) {
  292 + case 1:
  293 + p[offset] &= value;
  294 + pflash_update(pfl, offset, 1);
  295 + break;
  296 + case 2:
  297 +#if defined(TARGET_WORDS_BIGENDIAN)
  298 + p[offset] &= value >> 8;
  299 + p[offset + 1] &= value;
  300 +#else
  301 + p[offset] &= value;
  302 + p[offset + 1] &= value >> 8;
  303 +#endif
  304 + pflash_update(pfl, offset, 2);
  305 + break;
  306 + case 4:
  307 +#if defined(TARGET_WORDS_BIGENDIAN)
  308 + p[offset] &= value >> 24;
  309 + p[offset + 1] &= value >> 16;
  310 + p[offset + 2] &= value >> 8;
  311 + p[offset + 3] &= value;
  312 +#else
  313 + p[offset] &= value;
  314 + p[offset + 1] &= value >> 8;
  315 + p[offset + 2] &= value >> 16;
  316 + p[offset + 3] &= value >> 24;
  317 +#endif
  318 + pflash_update(pfl, offset, 4);
  319 + break;
  320 + }
  321 + pfl->status = 0x00 | ~(value & 0x80);
  322 + /* Let's pretend write is immediate */
  323 + if (pfl->bypass)
  324 + goto do_bypass;
  325 + goto reset_flash;
  326 + case 0x90:
  327 + if (pfl->bypass && cmd == 0x00) {
  328 + /* Unlock bypass reset */
  329 + goto reset_flash;
  330 + }
  331 + /* We can enter CFI query mode from autoselect mode */
  332 + if (boff == 0x55 && cmd == 0x98)
  333 + goto enter_CFI_mode;
  334 + /* No break here */
  335 + default:
  336 + DPRINTF("%s: invalid write for command %02x\n",
  337 + __func__, pfl->cmd);
  338 + goto reset_flash;
  339 + }
  340 + case 4:
  341 + switch (pfl->cmd) {
  342 + case 0xA0:
  343 + /* Ignore writes while flash data write is occuring */
  344 + /* As we suppose write is immediate, this should never happen */
  345 + return;
  346 + case 0x80:
  347 + goto check_unlock1;
  348 + default:
  349 + /* Should never happen */
  350 + DPRINTF("%s: invalid command state %02x (wc 4)\n",
  351 + __func__, pfl->cmd);
  352 + goto reset_flash;
  353 + }
  354 + break;
  355 + case 5:
  356 + switch (cmd) {
  357 + case 0x10:
  358 + if (boff != 0x555) {
  359 + DPRINTF("%s: chip erase: invalid address %04x\n",
  360 + __func__, offset);
  361 + goto reset_flash;
  362 + }
  363 + /* Chip erase */
  364 + DPRINTF("%s: start chip erase\n", __func__);
  365 + memset(pfl->storage, 0xFF, pfl->total_len);
  366 + pfl->status = 0x00;
  367 + pflash_update(pfl, 0, pfl->total_len);
  368 + /* Let's wait 5 seconds before chip erase is done */
  369 + qemu_mod_timer(pfl->timer,
  370 + qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
  371 + break;
  372 + case 0x30:
  373 + /* Sector erase */
  374 + p = pfl->storage;
  375 + offset &= ~(pfl->sector_len - 1);
  376 + DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
  377 + memset(p + offset, 0xFF, pfl->sector_len);
  378 + pflash_update(pfl, offset, pfl->sector_len);
  379 + pfl->status = 0x00;
  380 + /* Let's wait 1/2 second before sector erase is done */
  381 + qemu_mod_timer(pfl->timer,
  382 + qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
  383 + break;
  384 + default:
  385 + DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
  386 + goto reset_flash;
  387 + }
  388 + pfl->cmd = cmd;
  389 + break;
  390 + case 6:
  391 + switch (pfl->cmd) {
  392 + case 0x10:
  393 + /* Ignore writes during chip erase */
  394 + return;
  395 + case 0x30:
  396 + /* Ignore writes during sector erase */
  397 + return;
  398 + default:
  399 + /* Should never happen */
  400 + DPRINTF("%s: invalid command state %02x (wc 6)\n",
  401 + __func__, pfl->cmd);
  402 + goto reset_flash;
  403 + }
  404 + break;
  405 + case 7: /* Special value for CFI queries */
  406 + DPRINTF("%s: invalid write in CFI query mode\n", __func__);
  407 + goto reset_flash;
  408 + default:
  409 + /* Should never happen */
  410 + DPRINTF("%s: invalid write state (wc 7)\n", __func__);
  411 + goto reset_flash;
  412 + }
  413 + pfl->wcycle++;
  414 +
  415 + return;
  416 +
  417 + /* Reset flash */
  418 + reset_flash:
  419 + if (pfl->wcycle != 0) {
  420 + cpu_register_physical_memory(pfl->base, pfl->total_len,
  421 + pfl->off | IO_MEM_ROMD | pfl->fl_mem);
  422 + }
  423 + pfl->bypass = 0;
  424 + pfl->wcycle = 0;
  425 + pfl->cmd = 0;
  426 + return;
  427 +
  428 + do_bypass:
  429 + pfl->wcycle = 2;
  430 + pfl->cmd = 0;
  431 + return;
  432 +}
  433 +
  434 +
  435 +static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
  436 +{
  437 + return pflash_read(opaque, addr, 1);
  438 +}
  439 +
  440 +static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
  441 +{
  442 + pflash_t *pfl = opaque;
  443 +
  444 + return pflash_read(pfl, addr, 2);
  445 +}
  446 +
  447 +static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
  448 +{
  449 + pflash_t *pfl = opaque;
  450 +
  451 + return pflash_read(pfl, addr, 4);
  452 +}
  453 +
  454 +static void pflash_writeb (void *opaque, target_phys_addr_t addr,
  455 + uint32_t value)
  456 +{
  457 + pflash_write(opaque, addr, value, 1);
  458 +}
  459 +
  460 +static void pflash_writew (void *opaque, target_phys_addr_t addr,
  461 + uint32_t value)
  462 +{
  463 + pflash_t *pfl = opaque;
  464 +
  465 + pflash_write(pfl, addr, value, 2);
  466 +}
  467 +
  468 +static void pflash_writel (void *opaque, target_phys_addr_t addr,
  469 + uint32_t value)
  470 +{
  471 + pflash_t *pfl = opaque;
  472 +
  473 + pflash_write(pfl, addr, value, 4);
  474 +}
  475 +
  476 +static CPUWriteMemoryFunc *pflash_write_ops[] = {
  477 + &pflash_writeb,
  478 + &pflash_writew,
  479 + &pflash_writel,
  480 +};
  481 +
  482 +static CPUReadMemoryFunc *pflash_read_ops[] = {
  483 + &pflash_readb,
  484 + &pflash_readw,
  485 + &pflash_readl,
  486 +};
  487 +
  488 +/* Count trailing zeroes of a 32 bits quantity */
  489 +static int ctz32 (uint32_t n)
  490 +{
  491 + int ret;
  492 +
  493 + ret = 0;
  494 + if (!(n & 0xFFFF)) {
  495 + ret += 16;
  496 + n = n >> 16;
  497 + }
  498 + if (!(n & 0xFF)) {
  499 + ret += 8;
  500 + n = n >> 8;
  501 + }
  502 + if (!(n & 0xF)) {
  503 + ret += 4;
  504 + n = n >> 4;
  505 + }
  506 + if (!(n & 0x3)) {
  507 + ret += 2;
  508 + n = n >> 2;
  509 + }
  510 + if (!(n & 0x1)) {
  511 + ret++;
  512 + n = n >> 1;
  513 + }
  514 +#if 0 /* This is not necessary as n is never 0 */
  515 + if (!n)
  516 + ret++;
  517 +#endif
  518 +
  519 + return ret;
  520 +}
  521 +
  522 +pflash_t *pflash_register (target_ulong base, ram_addr_t off,
  523 + BlockDriverState *bs,
  524 + target_ulong sector_len, int nb_blocs, int width,
  525 + uint16_t id0, uint16_t id1,
  526 + uint16_t id2, uint16_t id3)
  527 +{
  528 + pflash_t *pfl;
  529 + target_long total_len;
  530 +
  531 + total_len = sector_len * nb_blocs;
  532 + /* XXX: to be fixed */
  533 + if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
  534 + total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
  535 + return NULL;
  536 + pfl = qemu_mallocz(sizeof(pflash_t));
  537 + if (pfl == NULL)
  538 + return NULL;
  539 + pfl->storage = phys_ram_base + off;
  540 + pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
  541 + pfl->off = off;
  542 + cpu_register_physical_memory(base, total_len,
  543 + off | pfl->fl_mem | IO_MEM_ROMD);
  544 + pfl->bs = bs;
  545 + if (pfl->bs) {
  546 + /* read the initial flash content */
  547 + bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
  548 + }
  549 +#if 0 /* XXX: there should be a bit to set up read-only,
  550 + * the same way the hardware does (with WP pin).
  551 + */
  552 + pfl->ro = 1;
  553 +#else
  554 + pfl->ro = 0;
  555 +#endif
  556 + pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
  557 + pfl->base = base;
  558 + pfl->sector_len = sector_len;
  559 + pfl->total_len = total_len;
  560 + pfl->width = width;
  561 + pfl->wcycle = 0;
  562 + pfl->cmd = 0;
  563 + pfl->status = 0;
  564 + pfl->ident[0] = id0;
  565 + pfl->ident[1] = id1;
  566 + pfl->ident[2] = id2;
  567 + pfl->ident[3] = id3;
  568 + /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
  569 + pfl->cfi_len = 0x52;
  570 + /* Standard "QRY" string */
  571 + pfl->cfi_table[0x10] = 'Q';
  572 + pfl->cfi_table[0x11] = 'R';
  573 + pfl->cfi_table[0x12] = 'Y';
  574 + /* Command set (AMD/Fujitsu) */
  575 + pfl->cfi_table[0x13] = 0x02;
  576 + pfl->cfi_table[0x14] = 0x00;
  577 + /* Primary extended table address (none) */
  578 + pfl->cfi_table[0x15] = 0x00;
  579 + pfl->cfi_table[0x16] = 0x00;
  580 + /* Alternate command set (none) */
  581 + pfl->cfi_table[0x17] = 0x00;
  582 + pfl->cfi_table[0x18] = 0x00;
  583 + /* Alternate extended table (none) */
  584 + pfl->cfi_table[0x19] = 0x00;
  585 + pfl->cfi_table[0x1A] = 0x00;
  586 + /* Vcc min */
  587 + pfl->cfi_table[0x1B] = 0x27;
  588 + /* Vcc max */
  589 + pfl->cfi_table[0x1C] = 0x36;
  590 + /* Vpp min (no Vpp pin) */
  591 + pfl->cfi_table[0x1D] = 0x00;
  592 + /* Vpp max (no Vpp pin) */
  593 + pfl->cfi_table[0x1E] = 0x00;
  594 + /* Reserved */
  595 + pfl->cfi_table[0x1F] = 0x07;
  596 + /* Timeout for min size buffer write (16 µs) */
  597 + pfl->cfi_table[0x20] = 0x04;
  598 + /* Typical timeout for block erase (512 ms) */
  599 + pfl->cfi_table[0x21] = 0x09;
  600 + /* Typical timeout for full chip erase (4096 ms) */
  601 + pfl->cfi_table[0x22] = 0x0C;
  602 + /* Reserved */
  603 + pfl->cfi_table[0x23] = 0x01;
  604 + /* Max timeout for buffer write */
  605 + pfl->cfi_table[0x24] = 0x04;
  606 + /* Max timeout for block erase */
  607 + pfl->cfi_table[0x25] = 0x0A;
  608 + /* Max timeout for chip erase */
  609 + pfl->cfi_table[0x26] = 0x0D;
  610 + /* Device size */
  611 + pfl->cfi_table[0x27] = ctz32(total_len) + 1;
  612 + /* Flash device interface (8 & 16 bits) */
  613 + pfl->cfi_table[0x28] = 0x02;
  614 + pfl->cfi_table[0x29] = 0x00;
  615 + /* Max number of bytes in multi-bytes write */
  616 + pfl->cfi_table[0x2A] = 0x05;
  617 + pfl->cfi_table[0x2B] = 0x00;
  618 + /* Number of erase block regions (uniform) */
  619 + pfl->cfi_table[0x2C] = 0x01;
  620 + /* Erase block region 1 */
  621 + pfl->cfi_table[0x2D] = nb_blocs - 1;
  622 + pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
  623 + pfl->cfi_table[0x2F] = sector_len >> 8;
  624 + pfl->cfi_table[0x30] = sector_len >> 16;
  625 +
  626 + return pfl;
  627 +}
... ...
... ... @@ -1137,6 +1137,15 @@ int sh7750_register_io_device(struct SH7750State *s,
1137 1137 /* tc58128.c */
1138 1138 int tc58128_init(struct SH7750State *s, char *zone1, char *zone2);
1139 1139  
  1140 +/* NOR flash devices */
  1141 +typedef struct pflash_t pflash_t;
  1142 +
  1143 +pflash_t *pflash_register (target_ulong base, ram_addr_t off,
  1144 + BlockDriverState *bs,
  1145 + target_ulong sector_len, int nb_blocs, int width,
  1146 + uint16_t id0, uint16_t id1,
  1147 + uint16_t id2, uint16_t id3);
  1148 +
1140 1149 #endif /* defined(QEMU_TOOL) */
1141 1150  
1142 1151 /* monitor.c */
... ...