Commit de8efe8f authored by Jordan Justen's avatar Jordan Justen Committed by Anthony Liguori
Browse files

pflash_cfi01/02: support read-only pflash devices

parent 1e9eb78a
Loading
Loading
Loading
Loading
+30 −14
Original line number Diff line number Diff line
@@ -283,8 +283,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
                    TARGET_FMT_plx "\n",
                    __func__, offset, pfl->sector_len);

            if (!pfl->ro) {
                memset(p + offset, 0xff, pfl->sector_len);
                pflash_update(pfl, offset, pfl->sector_len);
            } else {
                pfl->status |= 0x20; /* Block erase error */
            }
            pfl->status |= 0x80; /* Ready! */
            break;
        case 0x50: /* Clear status bits */
@@ -323,8 +327,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
        case 0x10: /* Single Byte Program */
        case 0x40: /* Single Byte Program */
            DPRINTF("%s: Single Byte Program\n", __func__);
            if (!pfl->ro) {
                pflash_data_write(pfl, offset, value, width, be);
                pflash_update(pfl, offset, width);
            } else {
                pfl->status |= 0x10; /* Programming error */
            }
            pfl->status |= 0x80; /* Ready! */
            pfl->wcycle = 0;
        break;
@@ -372,7 +380,11 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
    case 2:
        switch (pfl->cmd) {
        case 0xe8: /* Block write */
            if (!pfl->ro) {
                pflash_data_write(pfl, offset, value, width, be);
            } else {
                pfl->status |= 0x10; /* Programming error */
            }

            pfl->status |= 0x80;

@@ -382,8 +394,12 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,

                DPRINTF("%s: block write finished\n", __func__);
                pfl->wcycle++;
                if (!pfl->ro) {
                    /* Flush the entire write buffer onto backing storage.  */
                    pflash_update(pfl, offset & mask, pfl->writeblock_size);
                } else {
                    pfl->status |= 0x10; /* Programming error */
                }
            }

            pfl->counter--;
@@ -607,13 +623,13 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
        }
        bdrv_attach_dev_nofail(pfl->bs, pfl);
    }
#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

    if (pfl->bs) {
        pfl->ro = bdrv_is_read_only(pfl->bs);
    } else {
        pfl->ro = 0;
#endif
    }

    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
    pfl->base = base;
    pfl->sector_len = sector_len;
+45 −38
Original line number Diff line number Diff line
@@ -330,6 +330,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
                    __func__, offset, value, width);
            p = pfl->storage;
            if (!pfl->ro) {
                switch (width) {
                case 1:
                    p[offset] &= value;
@@ -360,6 +361,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
                    pflash_update(pfl, offset, 4);
                    break;
                }
            }
            pfl->status = 0x00 | ~(value & 0x80);
            /* Let's pretend write is immediate */
            if (pfl->bypass)
@@ -404,9 +406,11 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
            }
            /* Chip erase */
            DPRINTF("%s: start chip erase\n", __func__);
            if (!pfl->ro) {
                memset(pfl->storage, 0xFF, pfl->chip_len);
            pfl->status = 0x00;
                pflash_update(pfl, 0, pfl->chip_len);
            }
            pfl->status = 0x00;
            /* Let's wait 5 seconds before chip erase is done */
            qemu_mod_timer(pfl->timer,
                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
@@ -417,8 +421,10 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
            offset &= ~(pfl->sector_len - 1);
            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
                    offset);
            if (!pfl->ro) {
                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 */
            qemu_mod_timer(pfl->timer,
@@ -645,16 +651,17 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base,
        }
        bdrv_attach_dev_nofail(pfl->bs, pfl);
    }

    pflash_setup_mappings(pfl);
    pfl->rom_mode = 1;
    memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
#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

    if (pfl->bs) {
        pfl->ro = bdrv_is_read_only(pfl->bs);
    } else {
        pfl->ro = 0;
#endif
    }

    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
    pfl->sector_len = sector_len;
    pfl->width = width;