X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fpflash_cfi02.c;h=135c85079761bb1e499668c9f5a54770d2879c4b;hb=22a0e04b9bb5a02e13b3e5cf5ea8abfac5f34120;hp=08f88900f074b54f40f8899f241b06ccfe859a4e;hpb=3b46e6242767a2c770c0aba0a6595e9511623c92;p=qemu.git diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 08f88900f..135c85079 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with this library; if not, see . */ /* @@ -36,23 +35,27 @@ * It does not implement multiple sectors erase */ -#include "vl.h" +#include "hw.h" +#include "flash.h" +#include "qemu-timer.h" +#include "block.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG -#define DPRINTF(fmt, args...) \ +#define DPRINTF(fmt, ...) \ do { \ - printf("PFLASH: " fmt , ##args); \ + printf("PFLASH: " fmt , ## __VA_ARGS__); \ } while (0) #else -#define DPRINTF(fmt, args...) do { } while (0) +#define DPRINTF(fmt, ...) do { } while (0) #endif struct pflash_t { BlockDriverState *bs; target_phys_addr_t base; uint32_t sector_len; - uint32_t total_len; + uint32_t chip_len; + int mappings; int width; int wcycle; /* if 0, the flash is read normally */ int bypass; @@ -60,14 +63,30 @@ struct pflash_t { uint8_t cmd; uint8_t status; uint16_t ident[4]; + uint16_t unlock_addr[2]; uint8_t cfi_len; uint8_t cfi_table[0x52]; QEMUTimer *timer; ram_addr_t off; int fl_mem; + int rom_mode; void *storage; }; +static void pflash_register_memory(pflash_t *pfl, int rom_mode) +{ + 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); +} + static void pflash_timer (void *opaque) { pflash_t *pfl = opaque; @@ -78,8 +97,7 @@ static void pflash_timer (void *opaque) if (pfl->bypass) { pfl->wcycle = 2; } else { - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); + pflash_register_memory(pfl, 1); pfl->wcycle = 0; } pfl->cmd = 0; @@ -93,7 +111,12 @@ static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width) DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset); ret = -1; - offset -= pfl->base; + if (pfl->rom_mode) { + /* Lazy reset of to ROMD mode */ + if (pfl->wcycle == 0) + pflash_register_memory(pfl, 1); + } + offset &= pfl->chip_len - 1; boff = offset & 0xFF; if (pfl->width == 2) boff = boff >> 1; @@ -206,8 +229,6 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, uint8_t *p; uint8_t cmd; - /* WARNING: when the memory area is in ROMD mode, the offset is a - ram offset, not a physical address */ cmd = value; if (pfl->cmd != 0xA0 && cmd == 0xF0) { #if 0 @@ -218,15 +239,10 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, } DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__, offset, value, width, pfl->wcycle); - if (pfl->wcycle == 0) - offset -= (uint32_t)(long)pfl->storage; - else - offset -= pfl->base; + offset &= pfl->chip_len - 1; DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); - /* Set the device in I/O access mode */ - cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); boff = offset & (pfl->sector_len - 1); if (pfl->width == 2) boff = boff >> 1; @@ -234,6 +250,9 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, boff = boff >> 2; switch (pfl->wcycle) { case 0: + /* Set the device in I/O access mode if required */ + if (pfl->rom_mode) + pflash_register_memory(pfl, 0); /* We're in read mode */ check_unlock0: if (boff == 0x55 && cmd == 0x98) { @@ -243,9 +262,9 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, pfl->cmd = 0x98; return; } - if (boff != 0x555 || cmd != 0xAA) { + if (boff != pfl->unlock_addr[0] || cmd != 0xAA) { DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n", - __func__, boff, cmd, 0x555); + __func__, boff, cmd, pfl->unlock_addr[0]); goto reset_flash; } DPRINTF("%s: unlock sequence started\n", __func__); @@ -253,7 +272,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, case 1: /* We started an unlock sequence */ check_unlock1: - if (boff != 0x2AA || cmd != 0x55) { + if (boff != pfl->unlock_addr[1] || cmd != 0x55) { DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -262,7 +281,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, break; case 2: /* We finished an unlock sequence */ - if (!pfl->bypass && boff != 0x555) { + if (!pfl->bypass && boff != pfl->unlock_addr[0]) { DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -358,19 +377,19 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, case 5: switch (cmd) { case 0x10: - if (boff != 0x555) { + if (boff != pfl->unlock_addr[0]) { DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n", __func__, offset); goto reset_flash; } /* Chip erase */ DPRINTF("%s: start chip erase\n", __func__); - memset(pfl->storage, 0xFF, pfl->total_len); + memset(pfl->storage, 0xFF, pfl->chip_len); pfl->status = 0x00; - pflash_update(pfl, 0, pfl->total_len); + pflash_update(pfl, 0, pfl->chip_len); /* Let's wait 5 seconds before chip erase is done */ qemu_mod_timer(pfl->timer, - qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); + qemu_get_clock(vm_clock) + (get_ticks_per_sec() * 5)); break; case 0x30: /* Sector erase */ @@ -383,7 +402,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, pfl->status = 0x00; /* Let's wait 1/2 second before sector erase is done */ qemu_mod_timer(pfl->timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 2)); + qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 2)); break; default: DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd); @@ -420,8 +439,6 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, /* Reset flash */ reset_flash: - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; @@ -475,13 +492,13 @@ static void pflash_writel (void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 4); } -static CPUWriteMemoryFunc *pflash_write_ops[] = { +static CPUWriteMemoryFunc * const pflash_write_ops[] = { &pflash_writeb, &pflash_writew, &pflash_writel, }; -static CPUReadMemoryFunc *pflash_read_ops[] = { +static CPUReadMemoryFunc * const pflash_read_ops[] = { &pflash_readb, &pflash_readw, &pflash_readl, @@ -521,16 +538,18 @@ static int ctz32 (uint32_t n) return ret; } -pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3) +pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, uint32_t sector_len, + int nb_blocs, int nb_mappings, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, + uint16_t unlock_addr0, uint16_t unlock_addr1) { pflash_t *pfl; - int32_t total_len; + int32_t chip_len; + int ret; - total_len = sector_len * nb_blocs; + chip_len = sector_len * nb_blocs; /* XXX: to be fixed */ #if 0 if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && @@ -538,18 +557,24 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, return NULL; #endif pfl = qemu_mallocz(sizeof(pflash_t)); - if (pfl == NULL) - return NULL; - pfl->storage = phys_ram_base + off; - pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, + /* FIXME: Allocate ram ourselves. */ + pfl->storage = qemu_get_ram_ptr(off); + pfl->fl_mem = cpu_register_io_memory(pflash_read_ops, pflash_write_ops, pfl); pfl->off = off; - cpu_register_physical_memory(base, total_len, - off | pfl->fl_mem | IO_MEM_ROMD); + pfl->base = base; + pfl->chip_len = chip_len; + pfl->mappings = nb_mappings; + pflash_register_memory(pfl, 1); pfl->bs = bs; if (pfl->bs) { /* read the initial flash content */ - bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9); + if (ret < 0) { + cpu_unregister_io_memory(pfl->fl_mem); + qemu_free(pfl); + return NULL; + } } #if 0 /* XXX: there should be a bit to set up read-only, * the same way the hardware does (with WP pin). @@ -559,9 +584,7 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, pfl->ro = 0; #endif pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); - pfl->base = base; pfl->sector_len = sector_len; - pfl->total_len = total_len; pfl->width = width; pfl->wcycle = 0; pfl->cmd = 0; @@ -570,6 +593,8 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, pfl->ident[1] = id1; pfl->ident[2] = id2; pfl->ident[3] = id3; + pfl->unlock_addr[0] = unlock_addr0; + pfl->unlock_addr[1] = unlock_addr1; /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ pfl->cfi_len = 0x52; /* Standard "QRY" string */ @@ -579,8 +604,8 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, /* Command set (AMD/Fujitsu) */ pfl->cfi_table[0x13] = 0x02; pfl->cfi_table[0x14] = 0x00; - /* Primary extended table address (none) */ - pfl->cfi_table[0x15] = 0x00; + /* Primary extended table address */ + pfl->cfi_table[0x15] = 0x31; pfl->cfi_table[0x16] = 0x00; /* Alternate command set (none) */ pfl->cfi_table[0x17] = 0x00; @@ -598,22 +623,22 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, pfl->cfi_table[0x1E] = 0x00; /* Reserved */ pfl->cfi_table[0x1F] = 0x07; - /* Timeout for min size buffer write (16 µs) */ - pfl->cfi_table[0x20] = 0x04; + /* Timeout for min size buffer write (NA) */ + pfl->cfi_table[0x20] = 0x00; /* 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; - /* Max timeout for buffer write */ - pfl->cfi_table[0x24] = 0x04; + /* Max timeout for buffer write (NA) */ + pfl->cfi_table[0x24] = 0x00; /* Max timeout for block erase */ pfl->cfi_table[0x25] = 0x0A; /* Max timeout for chip erase */ pfl->cfi_table[0x26] = 0x0D; /* Device size */ - pfl->cfi_table[0x27] = ctz32(total_len) + 1; + pfl->cfi_table[0x27] = ctz32(chip_len); /* Flash device interface (8 & 16 bits) */ pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; @@ -630,5 +655,23 @@ pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, pfl->cfi_table[0x2F] = sector_len >> 8; pfl->cfi_table[0x30] = sector_len >> 16; + /* 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; + return pfl; }