149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * CFI parallel flash with Intel command set emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2006 Thorsten Zitterell
549ab747fSPaolo Bonzini * Copyright (c) 2005 Jocelyn Mayer
649ab747fSPaolo Bonzini *
749ab747fSPaolo Bonzini * This library is free software; you can redistribute it and/or
849ab747fSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
949ab747fSPaolo Bonzini * License as published by the Free Software Foundation; either
103564a919SChetan Pant * version 2.1 of the License, or (at your option) any later version.
1149ab747fSPaolo Bonzini *
1249ab747fSPaolo Bonzini * This library is distributed in the hope that it will be useful,
1349ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
1449ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1549ab747fSPaolo Bonzini * Lesser General Public License for more details.
1649ab747fSPaolo Bonzini *
1749ab747fSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
1849ab747fSPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1949ab747fSPaolo Bonzini */
2049ab747fSPaolo Bonzini
2149ab747fSPaolo Bonzini /*
2249ab747fSPaolo Bonzini * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
2349ab747fSPaolo Bonzini * Supported commands/modes are:
2449ab747fSPaolo Bonzini * - flash read
2549ab747fSPaolo Bonzini * - flash write
2649ab747fSPaolo Bonzini * - flash ID read
2749ab747fSPaolo Bonzini * - sector erase
2849ab747fSPaolo Bonzini * - CFI queries
2949ab747fSPaolo Bonzini *
3049ab747fSPaolo Bonzini * It does not support timings
3149ab747fSPaolo Bonzini * It does not support flash interleaving
3249ab747fSPaolo Bonzini * It does not implement software data protection as found in many real chips
3349ab747fSPaolo Bonzini * It does not implement erase suspend/resume commands
3449ab747fSPaolo Bonzini * It does not implement multiple sectors erase
3549ab747fSPaolo Bonzini *
3649ab747fSPaolo Bonzini * It does not implement much more ...
3749ab747fSPaolo Bonzini */
3849ab747fSPaolo Bonzini
3980c71a24SPeter Maydell #include "qemu/osdep.h"
4006f15217SMarkus Armbruster #include "hw/block/block.h"
4149ab747fSPaolo Bonzini #include "hw/block/flash.h"
42a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
43ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
444be74634SMarkus Armbruster #include "sysemu/block-backend.h"
45da34e65cSMarkus Armbruster #include "qapi/error.h"
461857b9dbSMansour Ahmadi #include "qemu/error-report.h"
471997b485SRoy Franz #include "qemu/bitops.h"
4849ab747fSPaolo Bonzini #include "qemu/host-utils.h"
4903dd024fSPaolo Bonzini #include "qemu/log.h"
502d731dbdSMarkus Armbruster #include "qemu/option.h"
5149ab747fSPaolo Bonzini #include "hw/sysbus.h"
52d6454270SMarkus Armbruster #include "migration/vmstate.h"
532d731dbdSMarkus Armbruster #include "sysemu/blockdev.h"
5454d31236SMarkus Armbruster #include "sysemu/runstate.h"
5513019f1fSPhilippe Mathieu-Daudé #include "trace.h"
5649ab747fSPaolo Bonzini
57e9809422SPaolo Bonzini #define PFLASH_BE 0
58f71e42a5SPaolo Bonzini #define PFLASH_SECURE 1
59e9809422SPaolo Bonzini
6016434065SMarkus Armbruster struct PFlashCFI01 {
61f1b44f0eSHu Tao /*< private >*/
62f1b44f0eSHu Tao SysBusDevice parent_obj;
63f1b44f0eSHu Tao /*< public >*/
64f1b44f0eSHu Tao
654be74634SMarkus Armbruster BlockBackend *blk;
6649ab747fSPaolo Bonzini uint32_t nb_blocs;
6749ab747fSPaolo Bonzini uint64_t sector_len;
684b6fedcaSRoy Franz uint8_t bank_width;
691997b485SRoy Franz uint8_t device_width; /* If 0, device width not specified. */
70fa21a7b1SRoy Franz uint8_t max_device_width; /* max device width in bytes */
71e9809422SPaolo Bonzini uint32_t features;
7249ab747fSPaolo Bonzini uint8_t wcycle; /* if 0, the flash is read normally */
732231bee2SDavid Edmondson bool ro;
7449ab747fSPaolo Bonzini uint8_t cmd;
7549ab747fSPaolo Bonzini uint8_t status;
7649ab747fSPaolo Bonzini uint16_t ident0;
7749ab747fSPaolo Bonzini uint16_t ident1;
7849ab747fSPaolo Bonzini uint16_t ident2;
7949ab747fSPaolo Bonzini uint16_t ident3;
8049ab747fSPaolo Bonzini uint8_t cfi_table[0x52];
8149ab747fSPaolo Bonzini uint64_t counter;
82284a7ee2SGerd Hoffmann uint32_t writeblock_size;
8349ab747fSPaolo Bonzini MemoryRegion mem;
8449ab747fSPaolo Bonzini char *name;
8549ab747fSPaolo Bonzini void *storage;
8690c647dbSDr. David Alan Gilbert VMChangeStateEntry *vmstate;
87feb0b1aaSPeter Maydell bool old_multiple_chip_handling;
88284a7ee2SGerd Hoffmann
89284a7ee2SGerd Hoffmann /* block update buffer */
90284a7ee2SGerd Hoffmann unsigned char *blk_bytes;
91284a7ee2SGerd Hoffmann uint32_t blk_offset;
9249ab747fSPaolo Bonzini };
9349ab747fSPaolo Bonzini
944c0cfc72SLaszlo Ersek static int pflash_post_load(void *opaque, int version_id);
954c0cfc72SLaszlo Ersek
pflash_blk_write_state_needed(void * opaque)96284a7ee2SGerd Hoffmann static bool pflash_blk_write_state_needed(void *opaque)
97284a7ee2SGerd Hoffmann {
98284a7ee2SGerd Hoffmann PFlashCFI01 *pfl = opaque;
99284a7ee2SGerd Hoffmann
100284a7ee2SGerd Hoffmann return (pfl->blk_offset != -1);
101284a7ee2SGerd Hoffmann }
102284a7ee2SGerd Hoffmann
103284a7ee2SGerd Hoffmann static const VMStateDescription vmstate_pflash_blk_write = {
104284a7ee2SGerd Hoffmann .name = "pflash_cfi01_blk_write",
105284a7ee2SGerd Hoffmann .version_id = 1,
106284a7ee2SGerd Hoffmann .minimum_version_id = 1,
107284a7ee2SGerd Hoffmann .needed = pflash_blk_write_state_needed,
108284a7ee2SGerd Hoffmann .fields = (const VMStateField[]) {
109284a7ee2SGerd Hoffmann VMSTATE_VBUFFER_UINT32(blk_bytes, PFlashCFI01, 0, NULL, writeblock_size),
110284a7ee2SGerd Hoffmann VMSTATE_UINT32(blk_offset, PFlashCFI01),
111284a7ee2SGerd Hoffmann VMSTATE_END_OF_LIST()
112284a7ee2SGerd Hoffmann }
113284a7ee2SGerd Hoffmann };
114284a7ee2SGerd Hoffmann
11549ab747fSPaolo Bonzini static const VMStateDescription vmstate_pflash = {
11649ab747fSPaolo Bonzini .name = "pflash_cfi01",
11749ab747fSPaolo Bonzini .version_id = 1,
11849ab747fSPaolo Bonzini .minimum_version_id = 1,
1194c0cfc72SLaszlo Ersek .post_load = pflash_post_load,
1207d5dc0a3SRichard Henderson .fields = (const VMStateField[]) {
12116434065SMarkus Armbruster VMSTATE_UINT8(wcycle, PFlashCFI01),
12216434065SMarkus Armbruster VMSTATE_UINT8(cmd, PFlashCFI01),
12316434065SMarkus Armbruster VMSTATE_UINT8(status, PFlashCFI01),
12416434065SMarkus Armbruster VMSTATE_UINT64(counter, PFlashCFI01),
12549ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
126284a7ee2SGerd Hoffmann },
127284a7ee2SGerd Hoffmann .subsections = (const VMStateDescription * const []) {
128284a7ee2SGerd Hoffmann &vmstate_pflash_blk_write,
129284a7ee2SGerd Hoffmann NULL
13049ab747fSPaolo Bonzini }
13149ab747fSPaolo Bonzini };
13249ab747fSPaolo Bonzini
133ccd8014bSPhilippe Mathieu-Daudé /*
134ccd8014bSPhilippe Mathieu-Daudé * Perform a CFI query based on the bank width of the flash.
1354433e660SRoy Franz * If this code is called we know we have a device_width set for
1364433e660SRoy Franz * this flash.
1374433e660SRoy Franz */
pflash_cfi_query(PFlashCFI01 * pfl,hwaddr offset)13816434065SMarkus Armbruster static uint32_t pflash_cfi_query(PFlashCFI01 *pfl, hwaddr offset)
1394433e660SRoy Franz {
1404433e660SRoy Franz int i;
1414433e660SRoy Franz uint32_t resp = 0;
1424433e660SRoy Franz hwaddr boff;
1434433e660SRoy Franz
144ccd8014bSPhilippe Mathieu-Daudé /*
145ccd8014bSPhilippe Mathieu-Daudé * Adjust incoming offset to match expected device-width
1464433e660SRoy Franz * addressing. CFI query addresses are always specified in terms of
1474433e660SRoy Franz * the maximum supported width of the device. This means that x8
1484433e660SRoy Franz * devices and x8/x16 devices in x8 mode behave differently. For
1494433e660SRoy Franz * devices that are not used at their max width, we will be
1504433e660SRoy Franz * provided with addresses that use higher address bits than
1514433e660SRoy Franz * expected (based on the max width), so we will shift them lower
1524433e660SRoy Franz * so that they will match the addresses used when
1534433e660SRoy Franz * device_width==max_device_width.
1544433e660SRoy Franz */
1554433e660SRoy Franz boff = offset >> (ctz32(pfl->bank_width) +
1564433e660SRoy Franz ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
1574433e660SRoy Franz
15807c13a71SPhilippe Mathieu-Daudé if (boff >= sizeof(pfl->cfi_table)) {
1594433e660SRoy Franz return 0;
1604433e660SRoy Franz }
161ccd8014bSPhilippe Mathieu-Daudé /*
162ccd8014bSPhilippe Mathieu-Daudé * Now we will construct the CFI response generated by a single
1634433e660SRoy Franz * device, then replicate that for all devices that make up the
1644433e660SRoy Franz * bus. For wide parts used in x8 mode, CFI query responses
1654433e660SRoy Franz * are different than native byte-wide parts.
1664433e660SRoy Franz */
1674433e660SRoy Franz resp = pfl->cfi_table[boff];
1684433e660SRoy Franz if (pfl->device_width != pfl->max_device_width) {
1694433e660SRoy Franz /* The only case currently supported is x8 mode for a
1704433e660SRoy Franz * wider part.
1714433e660SRoy Franz */
1724433e660SRoy Franz if (pfl->device_width != 1 || pfl->bank_width > 4) {
17391316cbbSDavid Edmondson trace_pflash_unsupported_device_configuration(pfl->name,
17491316cbbSDavid Edmondson pfl->device_width, pfl->max_device_width);
1754433e660SRoy Franz return 0;
1764433e660SRoy Franz }
1774433e660SRoy Franz /* CFI query data is repeated, rather than zero padded for
1784433e660SRoy Franz * wide devices used in x8 mode.
1794433e660SRoy Franz */
1804433e660SRoy Franz for (i = 1; i < pfl->max_device_width; i++) {
1814433e660SRoy Franz resp = deposit32(resp, 8 * i, 8, pfl->cfi_table[boff]);
1824433e660SRoy Franz }
1834433e660SRoy Franz }
1844433e660SRoy Franz /* Replicate responses for each device in bank. */
1854433e660SRoy Franz if (pfl->device_width < pfl->bank_width) {
1864433e660SRoy Franz for (i = pfl->device_width;
1874433e660SRoy Franz i < pfl->bank_width; i += pfl->device_width) {
1884433e660SRoy Franz resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
1894433e660SRoy Franz }
1904433e660SRoy Franz }
1914433e660SRoy Franz
1924433e660SRoy Franz return resp;
1934433e660SRoy Franz }
1944433e660SRoy Franz
1950163a2dcSRoy Franz
1960163a2dcSRoy Franz
1970163a2dcSRoy Franz /* Perform a device id query based on the bank width of the flash. */
pflash_devid_query(PFlashCFI01 * pfl,hwaddr offset)19816434065SMarkus Armbruster static uint32_t pflash_devid_query(PFlashCFI01 *pfl, hwaddr offset)
1990163a2dcSRoy Franz {
2000163a2dcSRoy Franz int i;
2010163a2dcSRoy Franz uint32_t resp;
2020163a2dcSRoy Franz hwaddr boff;
2030163a2dcSRoy Franz
204ccd8014bSPhilippe Mathieu-Daudé /*
205ccd8014bSPhilippe Mathieu-Daudé * Adjust incoming offset to match expected device-width
2060163a2dcSRoy Franz * addressing. Device ID read addresses are always specified in
2070163a2dcSRoy Franz * terms of the maximum supported width of the device. This means
2080163a2dcSRoy Franz * that x8 devices and x8/x16 devices in x8 mode behave
2090163a2dcSRoy Franz * differently. For devices that are not used at their max width,
2100163a2dcSRoy Franz * we will be provided with addresses that use higher address bits
2110163a2dcSRoy Franz * than expected (based on the max width), so we will shift them
2120163a2dcSRoy Franz * lower so that they will match the addresses used when
2130163a2dcSRoy Franz * device_width==max_device_width.
2140163a2dcSRoy Franz */
2150163a2dcSRoy Franz boff = offset >> (ctz32(pfl->bank_width) +
2160163a2dcSRoy Franz ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
2170163a2dcSRoy Franz
218ccd8014bSPhilippe Mathieu-Daudé /*
219ccd8014bSPhilippe Mathieu-Daudé * Mask off upper bits which may be used in to query block
2200163a2dcSRoy Franz * or sector lock status at other addresses.
2210163a2dcSRoy Franz * Offsets 2/3 are block lock status, is not emulated.
2220163a2dcSRoy Franz */
2230163a2dcSRoy Franz switch (boff & 0xFF) {
2240163a2dcSRoy Franz case 0:
2250163a2dcSRoy Franz resp = pfl->ident0;
22691316cbbSDavid Edmondson trace_pflash_manufacturer_id(pfl->name, resp);
2270163a2dcSRoy Franz break;
2280163a2dcSRoy Franz case 1:
2290163a2dcSRoy Franz resp = pfl->ident1;
23091316cbbSDavid Edmondson trace_pflash_device_id(pfl->name, resp);
2310163a2dcSRoy Franz break;
2320163a2dcSRoy Franz default:
23391316cbbSDavid Edmondson trace_pflash_device_info(pfl->name, offset);
2340163a2dcSRoy Franz return 0;
2350163a2dcSRoy Franz }
2360163a2dcSRoy Franz /* Replicate responses for each device in bank. */
2370163a2dcSRoy Franz if (pfl->device_width < pfl->bank_width) {
2380163a2dcSRoy Franz for (i = pfl->device_width;
2390163a2dcSRoy Franz i < pfl->bank_width; i += pfl->device_width) {
2400163a2dcSRoy Franz resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
2410163a2dcSRoy Franz }
2420163a2dcSRoy Franz }
2430163a2dcSRoy Franz
2440163a2dcSRoy Franz return resp;
2450163a2dcSRoy Franz }
2460163a2dcSRoy Franz
pflash_data_read(PFlashCFI01 * pfl,hwaddr offset,int width,int be)24716434065SMarkus Armbruster static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
24849ab747fSPaolo Bonzini int width, int be)
24949ab747fSPaolo Bonzini {
25049ab747fSPaolo Bonzini uint8_t *p;
251f71e42a5SPaolo Bonzini uint32_t ret;
25249ab747fSPaolo Bonzini
25349ab747fSPaolo Bonzini p = pfl->storage;
25449ab747fSPaolo Bonzini if (be) {
2555dd58358SGerd Hoffmann ret = ldn_be_p(p + offset, width);
25649ab747fSPaolo Bonzini } else {
2575dd58358SGerd Hoffmann ret = ldn_le_p(p + offset, width);
258f71e42a5SPaolo Bonzini }
25991316cbbSDavid Edmondson trace_pflash_data_read(pfl->name, offset, width, ret);
260f71e42a5SPaolo Bonzini return ret;
26149ab747fSPaolo Bonzini }
26249ab747fSPaolo Bonzini
pflash_read(PFlashCFI01 * pfl,hwaddr offset,int width,int be)26316434065SMarkus Armbruster static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
264f71e42a5SPaolo Bonzini int width, int be)
265f71e42a5SPaolo Bonzini {
266f71e42a5SPaolo Bonzini hwaddr boff;
267f71e42a5SPaolo Bonzini uint32_t ret;
268f71e42a5SPaolo Bonzini
269f71e42a5SPaolo Bonzini ret = -1;
270f71e42a5SPaolo Bonzini switch (pfl->cmd) {
271f71e42a5SPaolo Bonzini default:
272f71e42a5SPaolo Bonzini /* This should never happen : reset state & treat it as a read */
27391316cbbSDavid Edmondson trace_pflash_read_unknown_state(pfl->name, pfl->cmd);
274f71e42a5SPaolo Bonzini pfl->wcycle = 0;
275aba53a12SPhilippe Mathieu-Daudé /*
276aba53a12SPhilippe Mathieu-Daudé * The command 0x00 is not assigned by the CFI open standard,
277aba53a12SPhilippe Mathieu-Daudé * but QEMU historically uses it for the READ_ARRAY command (0xff).
278aba53a12SPhilippe Mathieu-Daudé */
279aba53a12SPhilippe Mathieu-Daudé pfl->cmd = 0x00;
280f71e42a5SPaolo Bonzini /* fall through to read code */
281aba53a12SPhilippe Mathieu-Daudé case 0x00: /* This model reset value for READ_ARRAY (not CFI compliant) */
282f71e42a5SPaolo Bonzini /* Flash area read */
283f71e42a5SPaolo Bonzini ret = pflash_data_read(pfl, offset, width, be);
28449ab747fSPaolo Bonzini break;
28549ab747fSPaolo Bonzini case 0x10: /* Single byte program */
28649ab747fSPaolo Bonzini case 0x20: /* Block erase */
28749ab747fSPaolo Bonzini case 0x28: /* Block erase */
28849ab747fSPaolo Bonzini case 0x40: /* single byte program */
28949ab747fSPaolo Bonzini case 0x50: /* Clear status register */
29049ab747fSPaolo Bonzini case 0x60: /* Block /un)lock */
29149ab747fSPaolo Bonzini case 0x70: /* Status Register */
29249ab747fSPaolo Bonzini case 0xe8: /* Write block */
293ccd8014bSPhilippe Mathieu-Daudé /*
294ccd8014bSPhilippe Mathieu-Daudé * Status register read. Return status from each device in
2952003889fSRoy Franz * bank.
2962003889fSRoy Franz */
29749ab747fSPaolo Bonzini ret = pfl->status;
2982003889fSRoy Franz if (pfl->device_width && width > pfl->device_width) {
2992003889fSRoy Franz int shift = pfl->device_width * 8;
3002003889fSRoy Franz while (shift + pfl->device_width * 8 <= width * 8) {
3012003889fSRoy Franz ret |= pfl->status << shift;
3022003889fSRoy Franz shift += pfl->device_width * 8;
3032003889fSRoy Franz }
3042003889fSRoy Franz } else if (!pfl->device_width && width > 2) {
305ccd8014bSPhilippe Mathieu-Daudé /*
306ccd8014bSPhilippe Mathieu-Daudé * Handle 32 bit flash cases where device width is not
3072003889fSRoy Franz * set. (Existing behavior before device width added.)
3082003889fSRoy Franz */
309ea0a4f34SPaul Burton ret |= pfl->status << 16;
310ea0a4f34SPaul Burton }
31191316cbbSDavid Edmondson trace_pflash_read_status(pfl->name, ret);
31249ab747fSPaolo Bonzini break;
31349ab747fSPaolo Bonzini case 0x90:
3140163a2dcSRoy Franz if (!pfl->device_width) {
3150163a2dcSRoy Franz /* Preserve old behavior if device width not specified */
3164433e660SRoy Franz boff = offset & 0xFF;
3174433e660SRoy Franz if (pfl->bank_width == 2) {
3184433e660SRoy Franz boff = boff >> 1;
3194433e660SRoy Franz } else if (pfl->bank_width == 4) {
3204433e660SRoy Franz boff = boff >> 2;
3214433e660SRoy Franz }
3224433e660SRoy Franz
32349ab747fSPaolo Bonzini switch (boff) {
32449ab747fSPaolo Bonzini case 0:
32549ab747fSPaolo Bonzini ret = pfl->ident0 << 8 | pfl->ident1;
32691316cbbSDavid Edmondson trace_pflash_manufacturer_id(pfl->name, ret);
32749ab747fSPaolo Bonzini break;
32849ab747fSPaolo Bonzini case 1:
32949ab747fSPaolo Bonzini ret = pfl->ident2 << 8 | pfl->ident3;
33091316cbbSDavid Edmondson trace_pflash_device_id(pfl->name, ret);
33149ab747fSPaolo Bonzini break;
33249ab747fSPaolo Bonzini default:
33391316cbbSDavid Edmondson trace_pflash_device_info(pfl->name, boff);
33449ab747fSPaolo Bonzini ret = 0;
33549ab747fSPaolo Bonzini break;
33649ab747fSPaolo Bonzini }
3370163a2dcSRoy Franz } else {
338ccd8014bSPhilippe Mathieu-Daudé /*
339ccd8014bSPhilippe Mathieu-Daudé * If we have a read larger than the bank_width, combine multiple
3400163a2dcSRoy Franz * manufacturer/device ID queries into a single response.
3410163a2dcSRoy Franz */
3420163a2dcSRoy Franz int i;
3430163a2dcSRoy Franz for (i = 0; i < width; i += pfl->bank_width) {
3440163a2dcSRoy Franz ret = deposit32(ret, i * 8, pfl->bank_width * 8,
3450163a2dcSRoy Franz pflash_devid_query(pfl,
3460163a2dcSRoy Franz offset + i * pfl->bank_width));
3470163a2dcSRoy Franz }
3480163a2dcSRoy Franz }
34949ab747fSPaolo Bonzini break;
35049ab747fSPaolo Bonzini case 0x98: /* Query mode */
3514433e660SRoy Franz if (!pfl->device_width) {
3524433e660SRoy Franz /* Preserve old behavior if device width not specified */
3534433e660SRoy Franz boff = offset & 0xFF;
3544433e660SRoy Franz if (pfl->bank_width == 2) {
3554433e660SRoy Franz boff = boff >> 1;
3564433e660SRoy Franz } else if (pfl->bank_width == 4) {
3574433e660SRoy Franz boff = boff >> 2;
3584433e660SRoy Franz }
3594433e660SRoy Franz
36007c13a71SPhilippe Mathieu-Daudé if (boff < sizeof(pfl->cfi_table)) {
36149ab747fSPaolo Bonzini ret = pfl->cfi_table[boff];
36207c13a71SPhilippe Mathieu-Daudé } else {
36307c13a71SPhilippe Mathieu-Daudé ret = 0;
3644433e660SRoy Franz }
3654433e660SRoy Franz } else {
366ccd8014bSPhilippe Mathieu-Daudé /*
367ccd8014bSPhilippe Mathieu-Daudé * If we have a read larger than the bank_width, combine multiple
3684433e660SRoy Franz * CFI queries into a single response.
3694433e660SRoy Franz */
3704433e660SRoy Franz int i;
3714433e660SRoy Franz for (i = 0; i < width; i += pfl->bank_width) {
3724433e660SRoy Franz ret = deposit32(ret, i * 8, pfl->bank_width * 8,
3734433e660SRoy Franz pflash_cfi_query(pfl,
3744433e660SRoy Franz offset + i * pfl->bank_width));
3754433e660SRoy Franz }
3764433e660SRoy Franz }
3774433e660SRoy Franz
37849ab747fSPaolo Bonzini break;
37949ab747fSPaolo Bonzini }
38091316cbbSDavid Edmondson trace_pflash_io_read(pfl->name, offset, width, ret, pfl->cmd, pfl->wcycle);
381e8aa2d95SPhilippe Mathieu-Daudé
38249ab747fSPaolo Bonzini return ret;
38349ab747fSPaolo Bonzini }
38449ab747fSPaolo Bonzini
38549ab747fSPaolo Bonzini /* update flash content on disk */
pflash_update(PFlashCFI01 * pfl,int offset,int size)38616434065SMarkus Armbruster static void pflash_update(PFlashCFI01 *pfl, int offset,
38749ab747fSPaolo Bonzini int size)
38849ab747fSPaolo Bonzini {
38949ab747fSPaolo Bonzini int offset_end;
3901857b9dbSMansour Ahmadi int ret;
3914be74634SMarkus Armbruster if (pfl->blk) {
39249ab747fSPaolo Bonzini offset_end = offset + size;
393098e732dSEric Blake /* widen to sector boundaries */
394098e732dSEric Blake offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
395098e732dSEric Blake offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
396a9262f55SAlberto Faria ret = blk_pwrite(pfl->blk, offset, offset_end - offset,
397a9262f55SAlberto Faria pfl->storage + offset, 0);
3981857b9dbSMansour Ahmadi if (ret < 0) {
3991857b9dbSMansour Ahmadi /* TODO set error bit in status */
4001857b9dbSMansour Ahmadi error_report("Could not update PFLASH: %s", strerror(-ret));
4011857b9dbSMansour Ahmadi }
40249ab747fSPaolo Bonzini }
40349ab747fSPaolo Bonzini }
40449ab747fSPaolo Bonzini
405284a7ee2SGerd Hoffmann /* copy current flash content to block update buffer */
pflash_blk_write_start(PFlashCFI01 * pfl,hwaddr offset)406284a7ee2SGerd Hoffmann static void pflash_blk_write_start(PFlashCFI01 *pfl, hwaddr offset)
407284a7ee2SGerd Hoffmann {
408284a7ee2SGerd Hoffmann hwaddr mask = ~(pfl->writeblock_size - 1);
409284a7ee2SGerd Hoffmann
410284a7ee2SGerd Hoffmann trace_pflash_write_block_start(pfl->name, pfl->counter);
411284a7ee2SGerd Hoffmann pfl->blk_offset = offset & mask;
412284a7ee2SGerd Hoffmann memcpy(pfl->blk_bytes, pfl->storage + pfl->blk_offset,
413284a7ee2SGerd Hoffmann pfl->writeblock_size);
414284a7ee2SGerd Hoffmann }
415284a7ee2SGerd Hoffmann
416284a7ee2SGerd Hoffmann /* commit block update buffer changes */
pflash_blk_write_flush(PFlashCFI01 * pfl)417284a7ee2SGerd Hoffmann static void pflash_blk_write_flush(PFlashCFI01 *pfl)
418284a7ee2SGerd Hoffmann {
419284a7ee2SGerd Hoffmann g_assert(pfl->blk_offset != -1);
420284a7ee2SGerd Hoffmann trace_pflash_write_block_flush(pfl->name);
421284a7ee2SGerd Hoffmann memcpy(pfl->storage + pfl->blk_offset, pfl->blk_bytes,
422284a7ee2SGerd Hoffmann pfl->writeblock_size);
423284a7ee2SGerd Hoffmann pflash_update(pfl, pfl->blk_offset, pfl->writeblock_size);
424284a7ee2SGerd Hoffmann pfl->blk_offset = -1;
425284a7ee2SGerd Hoffmann }
426284a7ee2SGerd Hoffmann
427284a7ee2SGerd Hoffmann /* discard block update buffer changes */
pflash_blk_write_abort(PFlashCFI01 * pfl)428284a7ee2SGerd Hoffmann static void pflash_blk_write_abort(PFlashCFI01 *pfl)
429284a7ee2SGerd Hoffmann {
430284a7ee2SGerd Hoffmann trace_pflash_write_block_abort(pfl->name);
431284a7ee2SGerd Hoffmann pfl->blk_offset = -1;
432284a7ee2SGerd Hoffmann }
433284a7ee2SGerd Hoffmann
pflash_data_write(PFlashCFI01 * pfl,hwaddr offset,uint32_t value,int width,int be)43416434065SMarkus Armbruster static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
43549ab747fSPaolo Bonzini uint32_t value, int width, int be)
43649ab747fSPaolo Bonzini {
4373b14a555SGerd Hoffmann uint8_t *p;
43849ab747fSPaolo Bonzini
439284a7ee2SGerd Hoffmann if (pfl->blk_offset != -1) {
440284a7ee2SGerd Hoffmann /* block write: redirect writes to block update buffer */
441284a7ee2SGerd Hoffmann if ((offset < pfl->blk_offset) ||
442284a7ee2SGerd Hoffmann (offset + width > pfl->blk_offset + pfl->writeblock_size)) {
443284a7ee2SGerd Hoffmann pfl->status |= 0x10; /* Programming error */
444284a7ee2SGerd Hoffmann return;
445284a7ee2SGerd Hoffmann }
446284a7ee2SGerd Hoffmann trace_pflash_data_write_block(pfl->name, offset, width, value,
447284a7ee2SGerd Hoffmann pfl->counter);
448284a7ee2SGerd Hoffmann p = pfl->blk_bytes + (offset - pfl->blk_offset);
449284a7ee2SGerd Hoffmann } else {
450284a7ee2SGerd Hoffmann /* write directly to storage */
451284a7ee2SGerd Hoffmann trace_pflash_data_write(pfl->name, offset, width, value);
4523b14a555SGerd Hoffmann p = pfl->storage + offset;
453284a7ee2SGerd Hoffmann }
4543b14a555SGerd Hoffmann
45549ab747fSPaolo Bonzini if (be) {
4565dd58358SGerd Hoffmann stn_be_p(p, width, value);
45749ab747fSPaolo Bonzini } else {
4585dd58358SGerd Hoffmann stn_le_p(p, width, value);
45949ab747fSPaolo Bonzini }
46049ab747fSPaolo Bonzini }
46149ab747fSPaolo Bonzini
pflash_write(PFlashCFI01 * pfl,hwaddr offset,uint32_t value,int width,int be)46216434065SMarkus Armbruster static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
46349ab747fSPaolo Bonzini uint32_t value, int width, int be)
46449ab747fSPaolo Bonzini {
46549ab747fSPaolo Bonzini uint8_t *p;
46649ab747fSPaolo Bonzini uint8_t cmd;
46749ab747fSPaolo Bonzini
46849ab747fSPaolo Bonzini cmd = value;
46949ab747fSPaolo Bonzini
47091316cbbSDavid Edmondson trace_pflash_io_write(pfl->name, offset, width, value, pfl->wcycle);
47149ab747fSPaolo Bonzini if (!pfl->wcycle) {
47249ab747fSPaolo Bonzini /* Set the device in I/O access mode */
4735f9a5ea1SJan Kiszka memory_region_rom_device_set_romd(&pfl->mem, false);
47449ab747fSPaolo Bonzini }
47549ab747fSPaolo Bonzini
47649ab747fSPaolo Bonzini switch (pfl->wcycle) {
47749ab747fSPaolo Bonzini case 0:
47849ab747fSPaolo Bonzini /* read mode */
47949ab747fSPaolo Bonzini switch (cmd) {
480aba53a12SPhilippe Mathieu-Daudé case 0x00: /* This model reset value for READ_ARRAY (not CFI) */
4813072182dSPhilippe Mathieu-Daudé goto mode_read_array;
48249ab747fSPaolo Bonzini case 0x10: /* Single Byte Program */
48349ab747fSPaolo Bonzini case 0x40: /* Single Byte Program */
48491316cbbSDavid Edmondson trace_pflash_write(pfl->name, "single byte program (0)");
48549ab747fSPaolo Bonzini break;
48649ab747fSPaolo Bonzini case 0x20: /* Block erase */
48749ab747fSPaolo Bonzini p = pfl->storage;
48849ab747fSPaolo Bonzini offset &= ~(pfl->sector_len - 1);
48949ab747fSPaolo Bonzini
49091316cbbSDavid Edmondson trace_pflash_write_block_erase(pfl->name, offset, pfl->sector_len);
49149ab747fSPaolo Bonzini
49249ab747fSPaolo Bonzini if (!pfl->ro) {
49349ab747fSPaolo Bonzini memset(p + offset, 0xff, pfl->sector_len);
49449ab747fSPaolo Bonzini pflash_update(pfl, offset, pfl->sector_len);
49549ab747fSPaolo Bonzini } else {
49649ab747fSPaolo Bonzini pfl->status |= 0x20; /* Block erase error */
49749ab747fSPaolo Bonzini }
49849ab747fSPaolo Bonzini pfl->status |= 0x80; /* Ready! */
49949ab747fSPaolo Bonzini break;
50049ab747fSPaolo Bonzini case 0x50: /* Clear status bits */
50191316cbbSDavid Edmondson trace_pflash_write(pfl->name, "clear status bits");
50249ab747fSPaolo Bonzini pfl->status = 0x0;
5033072182dSPhilippe Mathieu-Daudé goto mode_read_array;
50449ab747fSPaolo Bonzini case 0x60: /* Block (un)lock */
50591316cbbSDavid Edmondson trace_pflash_write(pfl->name, "block unlock");
50649ab747fSPaolo Bonzini break;
50749ab747fSPaolo Bonzini case 0x70: /* Status Register */
50891316cbbSDavid Edmondson trace_pflash_write(pfl->name, "read status register");
50949ab747fSPaolo Bonzini pfl->cmd = cmd;
51049ab747fSPaolo Bonzini return;
51149ab747fSPaolo Bonzini case 0x90: /* Read Device ID */
51291316cbbSDavid Edmondson trace_pflash_write(pfl->name, "read device information");
51349ab747fSPaolo Bonzini pfl->cmd = cmd;
51449ab747fSPaolo Bonzini return;
51549ab747fSPaolo Bonzini case 0x98: /* CFI query */
51691316cbbSDavid Edmondson trace_pflash_write(pfl->name, "CFI query");
51749ab747fSPaolo Bonzini break;
51849ab747fSPaolo Bonzini case 0xe8: /* Write to buffer */
51991316cbbSDavid Edmondson trace_pflash_write(pfl->name, "write to buffer");
52049ab747fSPaolo Bonzini pfl->status |= 0x80; /* Ready! */
52149ab747fSPaolo Bonzini break;
52249ab747fSPaolo Bonzini case 0xf0: /* Probe for AMD flash */
52391316cbbSDavid Edmondson trace_pflash_write(pfl->name, "probe for AMD flash");
5243072182dSPhilippe Mathieu-Daudé goto mode_read_array;
5253072182dSPhilippe Mathieu-Daudé case 0xff: /* Read Array */
52691316cbbSDavid Edmondson trace_pflash_write(pfl->name, "read array mode");
5273072182dSPhilippe Mathieu-Daudé goto mode_read_array;
52849ab747fSPaolo Bonzini default:
52949ab747fSPaolo Bonzini goto error_flash;
53049ab747fSPaolo Bonzini }
53149ab747fSPaolo Bonzini pfl->wcycle++;
53249ab747fSPaolo Bonzini pfl->cmd = cmd;
53349ab747fSPaolo Bonzini break;
53449ab747fSPaolo Bonzini case 1:
53549ab747fSPaolo Bonzini switch (pfl->cmd) {
53649ab747fSPaolo Bonzini case 0x10: /* Single Byte Program */
53749ab747fSPaolo Bonzini case 0x40: /* Single Byte Program */
53891316cbbSDavid Edmondson trace_pflash_write(pfl->name, "single byte program (1)");
53949ab747fSPaolo Bonzini if (!pfl->ro) {
54049ab747fSPaolo Bonzini pflash_data_write(pfl, offset, value, width, be);
54149ab747fSPaolo Bonzini pflash_update(pfl, offset, width);
54249ab747fSPaolo Bonzini } else {
54349ab747fSPaolo Bonzini pfl->status |= 0x10; /* Programming error */
54449ab747fSPaolo Bonzini }
54549ab747fSPaolo Bonzini pfl->status |= 0x80; /* Ready! */
54649ab747fSPaolo Bonzini pfl->wcycle = 0;
54749ab747fSPaolo Bonzini break;
54849ab747fSPaolo Bonzini case 0x20: /* Block erase */
54949ab747fSPaolo Bonzini case 0x28:
55049ab747fSPaolo Bonzini if (cmd == 0xd0) { /* confirm */
55149ab747fSPaolo Bonzini pfl->wcycle = 0;
55249ab747fSPaolo Bonzini pfl->status |= 0x80;
5533072182dSPhilippe Mathieu-Daudé } else if (cmd == 0xff) { /* Read Array */
5543072182dSPhilippe Mathieu-Daudé goto mode_read_array;
55549ab747fSPaolo Bonzini } else
55649ab747fSPaolo Bonzini goto error_flash;
55749ab747fSPaolo Bonzini
55849ab747fSPaolo Bonzini break;
55949ab747fSPaolo Bonzini case 0xe8:
560ccd8014bSPhilippe Mathieu-Daudé /*
561ccd8014bSPhilippe Mathieu-Daudé * Mask writeblock size based on device width, or bank width if
5621997b485SRoy Franz * device width not specified.
5631997b485SRoy Franz */
5644dbda935SMarkus Armbruster /* FIXME check @offset, @width */
5651997b485SRoy Franz if (pfl->device_width) {
5661997b485SRoy Franz value = extract32(value, 0, pfl->device_width * 8);
5671997b485SRoy Franz } else {
5681997b485SRoy Franz value = extract32(value, 0, pfl->bank_width * 8);
5691997b485SRoy Franz }
57049ab747fSPaolo Bonzini pfl->counter = value;
57149ab747fSPaolo Bonzini pfl->wcycle++;
57249ab747fSPaolo Bonzini break;
57349ab747fSPaolo Bonzini case 0x60:
57449ab747fSPaolo Bonzini if (cmd == 0xd0) {
57549ab747fSPaolo Bonzini pfl->wcycle = 0;
57649ab747fSPaolo Bonzini pfl->status |= 0x80;
57749ab747fSPaolo Bonzini } else if (cmd == 0x01) {
57849ab747fSPaolo Bonzini pfl->wcycle = 0;
57949ab747fSPaolo Bonzini pfl->status |= 0x80;
5803072182dSPhilippe Mathieu-Daudé } else if (cmd == 0xff) { /* Read Array */
5813072182dSPhilippe Mathieu-Daudé goto mode_read_array;
58249ab747fSPaolo Bonzini } else {
58391316cbbSDavid Edmondson trace_pflash_write(pfl->name, "unknown (un)locking command");
5843072182dSPhilippe Mathieu-Daudé goto mode_read_array;
58549ab747fSPaolo Bonzini }
58649ab747fSPaolo Bonzini break;
58749ab747fSPaolo Bonzini case 0x98:
5883072182dSPhilippe Mathieu-Daudé if (cmd == 0xff) { /* Read Array */
5893072182dSPhilippe Mathieu-Daudé goto mode_read_array;
59049ab747fSPaolo Bonzini } else {
59191316cbbSDavid Edmondson trace_pflash_write(pfl->name, "leaving query mode");
59249ab747fSPaolo Bonzini }
59349ab747fSPaolo Bonzini break;
59449ab747fSPaolo Bonzini default:
59549ab747fSPaolo Bonzini goto error_flash;
59649ab747fSPaolo Bonzini }
59749ab747fSPaolo Bonzini break;
59849ab747fSPaolo Bonzini case 2:
59949ab747fSPaolo Bonzini switch (pfl->cmd) {
60049ab747fSPaolo Bonzini case 0xe8: /* Block write */
6014dbda935SMarkus Armbruster /* FIXME check @offset, @width */
6022563be63SGerd Hoffmann if (pfl->blk_offset == -1 && pfl->counter) {
6032563be63SGerd Hoffmann pflash_blk_write_start(pfl, offset);
6042563be63SGerd Hoffmann }
605284a7ee2SGerd Hoffmann if (!pfl->ro && (pfl->blk_offset != -1)) {
60649ab747fSPaolo Bonzini pflash_data_write(pfl, offset, value, width, be);
60749ab747fSPaolo Bonzini } else {
60849ab747fSPaolo Bonzini pfl->status |= 0x10; /* Programming error */
60949ab747fSPaolo Bonzini }
61049ab747fSPaolo Bonzini
61149ab747fSPaolo Bonzini pfl->status |= 0x80;
61249ab747fSPaolo Bonzini
61349ab747fSPaolo Bonzini if (!pfl->counter) {
61491316cbbSDavid Edmondson trace_pflash_write(pfl->name, "block write finished");
61549ab747fSPaolo Bonzini pfl->wcycle++;
6168f64e744SPeter Maydell break;
61749ab747fSPaolo Bonzini }
61849ab747fSPaolo Bonzini
61949ab747fSPaolo Bonzini pfl->counter--;
62049ab747fSPaolo Bonzini break;
62149ab747fSPaolo Bonzini default:
62249ab747fSPaolo Bonzini goto error_flash;
62349ab747fSPaolo Bonzini }
62449ab747fSPaolo Bonzini break;
62549ab747fSPaolo Bonzini case 3: /* Confirm mode */
62649ab747fSPaolo Bonzini switch (pfl->cmd) {
62749ab747fSPaolo Bonzini case 0xe8: /* Block write */
628284a7ee2SGerd Hoffmann if ((cmd == 0xd0) && !(pfl->status & 0x10)) {
629284a7ee2SGerd Hoffmann pflash_blk_write_flush(pfl);
63049ab747fSPaolo Bonzini pfl->wcycle = 0;
63149ab747fSPaolo Bonzini pfl->status |= 0x80;
63249ab747fSPaolo Bonzini } else {
633284a7ee2SGerd Hoffmann pflash_blk_write_abort(pfl);
6343072182dSPhilippe Mathieu-Daudé goto mode_read_array;
63549ab747fSPaolo Bonzini }
63649ab747fSPaolo Bonzini break;
63749ab747fSPaolo Bonzini default:
638284a7ee2SGerd Hoffmann pflash_blk_write_abort(pfl);
63949ab747fSPaolo Bonzini goto error_flash;
64049ab747fSPaolo Bonzini }
64149ab747fSPaolo Bonzini break;
64249ab747fSPaolo Bonzini default:
64349ab747fSPaolo Bonzini /* Should never happen */
64491316cbbSDavid Edmondson trace_pflash_write(pfl->name, "invalid write state");
6453072182dSPhilippe Mathieu-Daudé goto mode_read_array;
64649ab747fSPaolo Bonzini }
64749ab747fSPaolo Bonzini return;
64849ab747fSPaolo Bonzini
64949ab747fSPaolo Bonzini error_flash:
65049ab747fSPaolo Bonzini qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence "
651883f2c59SPhilippe Mathieu-Daudé "(offset " HWADDR_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)"
65249ab747fSPaolo Bonzini "\n", __func__, offset, pfl->wcycle, pfl->cmd, value);
65349ab747fSPaolo Bonzini
6543072182dSPhilippe Mathieu-Daudé mode_read_array:
65591316cbbSDavid Edmondson trace_pflash_mode_read_array(pfl->name);
6565f9a5ea1SJan Kiszka memory_region_rom_device_set_romd(&pfl->mem, true);
65749ab747fSPaolo Bonzini pfl->wcycle = 0;
658aba53a12SPhilippe Mathieu-Daudé pfl->cmd = 0x00; /* This model reset value for READ_ARRAY (not CFI) */
65949ab747fSPaolo Bonzini }
66049ab747fSPaolo Bonzini
66149ab747fSPaolo Bonzini
pflash_mem_read_with_attrs(void * opaque,hwaddr addr,uint64_t * value,unsigned len,MemTxAttrs attrs)662f71e42a5SPaolo Bonzini static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value,
663f71e42a5SPaolo Bonzini unsigned len, MemTxAttrs attrs)
66449ab747fSPaolo Bonzini {
66516434065SMarkus Armbruster PFlashCFI01 *pfl = opaque;
6665aa113f0SPaolo Bonzini bool be = !!(pfl->features & (1 << PFLASH_BE));
66749ab747fSPaolo Bonzini
668f71e42a5SPaolo Bonzini if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
669f71e42a5SPaolo Bonzini *value = pflash_data_read(opaque, addr, len, be);
670f71e42a5SPaolo Bonzini } else {
671f71e42a5SPaolo Bonzini *value = pflash_read(opaque, addr, len, be);
672f71e42a5SPaolo Bonzini }
673f71e42a5SPaolo Bonzini return MEMTX_OK;
67449ab747fSPaolo Bonzini }
67549ab747fSPaolo Bonzini
pflash_mem_write_with_attrs(void * opaque,hwaddr addr,uint64_t value,unsigned len,MemTxAttrs attrs)676f71e42a5SPaolo Bonzini static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value,
677f71e42a5SPaolo Bonzini unsigned len, MemTxAttrs attrs)
67849ab747fSPaolo Bonzini {
67916434065SMarkus Armbruster PFlashCFI01 *pfl = opaque;
6805aa113f0SPaolo Bonzini bool be = !!(pfl->features & (1 << PFLASH_BE));
68149ab747fSPaolo Bonzini
682f71e42a5SPaolo Bonzini if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
683f71e42a5SPaolo Bonzini return MEMTX_ERROR;
684f71e42a5SPaolo Bonzini } else {
685f71e42a5SPaolo Bonzini pflash_write(opaque, addr, value, len, be);
686f71e42a5SPaolo Bonzini return MEMTX_OK;
687f71e42a5SPaolo Bonzini }
68849ab747fSPaolo Bonzini }
68949ab747fSPaolo Bonzini
6905aa113f0SPaolo Bonzini static const MemoryRegionOps pflash_cfi01_ops = {
691f71e42a5SPaolo Bonzini .read_with_attrs = pflash_mem_read_with_attrs,
692f71e42a5SPaolo Bonzini .write_with_attrs = pflash_mem_write_with_attrs,
69349ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
69449ab747fSPaolo Bonzini };
69549ab747fSPaolo Bonzini
pflash_cfi01_fill_cfi_table(PFlashCFI01 * pfl)696ef7716caSDaniel Henrique Barboza static void pflash_cfi01_fill_cfi_table(PFlashCFI01 *pfl)
69749ab747fSPaolo Bonzini {
698feb0b1aaSPeter Maydell uint64_t blocks_per_device, sector_len_per_device, device_len;
699a0289b8aSPeter Maydell int num_devices;
70049ab747fSPaolo Bonzini
701ccd8014bSPhilippe Mathieu-Daudé /*
702ccd8014bSPhilippe Mathieu-Daudé * These are only used to expose the parameters of each device
703a0289b8aSPeter Maydell * in the cfi_table[].
704a0289b8aSPeter Maydell */
705a0289b8aSPeter Maydell num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1;
706feb0b1aaSPeter Maydell if (pfl->old_multiple_chip_handling) {
707a0289b8aSPeter Maydell blocks_per_device = pfl->nb_blocs / num_devices;
708feb0b1aaSPeter Maydell sector_len_per_device = pfl->sector_len;
709feb0b1aaSPeter Maydell } else {
710feb0b1aaSPeter Maydell blocks_per_device = pfl->nb_blocs;
711feb0b1aaSPeter Maydell sector_len_per_device = pfl->sector_len / num_devices;
712feb0b1aaSPeter Maydell }
713feb0b1aaSPeter Maydell device_len = sector_len_per_device * blocks_per_device;
714a0289b8aSPeter Maydell
71549ab747fSPaolo Bonzini /* Hardcoded CFI table */
71649ab747fSPaolo Bonzini /* Standard "QRY" string */
71749ab747fSPaolo Bonzini pfl->cfi_table[0x10] = 'Q';
71849ab747fSPaolo Bonzini pfl->cfi_table[0x11] = 'R';
71949ab747fSPaolo Bonzini pfl->cfi_table[0x12] = 'Y';
72049ab747fSPaolo Bonzini /* Command set (Intel) */
72149ab747fSPaolo Bonzini pfl->cfi_table[0x13] = 0x01;
72249ab747fSPaolo Bonzini pfl->cfi_table[0x14] = 0x00;
72349ab747fSPaolo Bonzini /* Primary extended table address (none) */
72449ab747fSPaolo Bonzini pfl->cfi_table[0x15] = 0x31;
72549ab747fSPaolo Bonzini pfl->cfi_table[0x16] = 0x00;
72649ab747fSPaolo Bonzini /* Alternate command set (none) */
72749ab747fSPaolo Bonzini pfl->cfi_table[0x17] = 0x00;
72849ab747fSPaolo Bonzini pfl->cfi_table[0x18] = 0x00;
72949ab747fSPaolo Bonzini /* Alternate extended table (none) */
73049ab747fSPaolo Bonzini pfl->cfi_table[0x19] = 0x00;
73149ab747fSPaolo Bonzini pfl->cfi_table[0x1A] = 0x00;
73249ab747fSPaolo Bonzini /* Vcc min */
73349ab747fSPaolo Bonzini pfl->cfi_table[0x1B] = 0x45;
73449ab747fSPaolo Bonzini /* Vcc max */
73549ab747fSPaolo Bonzini pfl->cfi_table[0x1C] = 0x55;
73649ab747fSPaolo Bonzini /* Vpp min (no Vpp pin) */
73749ab747fSPaolo Bonzini pfl->cfi_table[0x1D] = 0x00;
73849ab747fSPaolo Bonzini /* Vpp max (no Vpp pin) */
73949ab747fSPaolo Bonzini pfl->cfi_table[0x1E] = 0x00;
74049ab747fSPaolo Bonzini /* Reserved */
74149ab747fSPaolo Bonzini pfl->cfi_table[0x1F] = 0x07;
74249ab747fSPaolo Bonzini /* Timeout for min size buffer write */
74349ab747fSPaolo Bonzini pfl->cfi_table[0x20] = 0x07;
74449ab747fSPaolo Bonzini /* Typical timeout for block erase */
74549ab747fSPaolo Bonzini pfl->cfi_table[0x21] = 0x0a;
74649ab747fSPaolo Bonzini /* Typical timeout for full chip erase (4096 ms) */
74749ab747fSPaolo Bonzini pfl->cfi_table[0x22] = 0x00;
74849ab747fSPaolo Bonzini /* Reserved */
74949ab747fSPaolo Bonzini pfl->cfi_table[0x23] = 0x04;
75049ab747fSPaolo Bonzini /* Max timeout for buffer write */
75149ab747fSPaolo Bonzini pfl->cfi_table[0x24] = 0x04;
75249ab747fSPaolo Bonzini /* Max timeout for block erase */
75349ab747fSPaolo Bonzini pfl->cfi_table[0x25] = 0x04;
75449ab747fSPaolo Bonzini /* Max timeout for chip erase */
75549ab747fSPaolo Bonzini pfl->cfi_table[0x26] = 0x00;
75649ab747fSPaolo Bonzini /* Device size */
757a0289b8aSPeter Maydell pfl->cfi_table[0x27] = ctz32(device_len); /* + 1; */
75849ab747fSPaolo Bonzini /* Flash device interface (8 & 16 bits) */
75949ab747fSPaolo Bonzini pfl->cfi_table[0x28] = 0x02;
76049ab747fSPaolo Bonzini pfl->cfi_table[0x29] = 0x00;
76149ab747fSPaolo Bonzini /* Max number of bytes in multi-bytes write */
7624b6fedcaSRoy Franz if (pfl->bank_width == 1) {
76349ab747fSPaolo Bonzini pfl->cfi_table[0x2A] = 0x08;
76449ab747fSPaolo Bonzini } else {
76549ab747fSPaolo Bonzini pfl->cfi_table[0x2A] = 0x0B;
76649ab747fSPaolo Bonzini }
76749ab747fSPaolo Bonzini pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
768feb0b1aaSPeter Maydell if (!pfl->old_multiple_chip_handling && num_devices > 1) {
769feb0b1aaSPeter Maydell pfl->writeblock_size *= num_devices;
770feb0b1aaSPeter Maydell }
77149ab747fSPaolo Bonzini
77249ab747fSPaolo Bonzini pfl->cfi_table[0x2B] = 0x00;
77349ab747fSPaolo Bonzini /* Number of erase block regions (uniform) */
77449ab747fSPaolo Bonzini pfl->cfi_table[0x2C] = 0x01;
77549ab747fSPaolo Bonzini /* Erase block region 1 */
776a0289b8aSPeter Maydell pfl->cfi_table[0x2D] = blocks_per_device - 1;
777a0289b8aSPeter Maydell pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8;
778feb0b1aaSPeter Maydell pfl->cfi_table[0x2F] = sector_len_per_device >> 8;
779feb0b1aaSPeter Maydell pfl->cfi_table[0x30] = sector_len_per_device >> 16;
78049ab747fSPaolo Bonzini
78149ab747fSPaolo Bonzini /* Extended */
78249ab747fSPaolo Bonzini pfl->cfi_table[0x31] = 'P';
78349ab747fSPaolo Bonzini pfl->cfi_table[0x32] = 'R';
78449ab747fSPaolo Bonzini pfl->cfi_table[0x33] = 'I';
78549ab747fSPaolo Bonzini
78649ab747fSPaolo Bonzini pfl->cfi_table[0x34] = '1';
78749ab747fSPaolo Bonzini pfl->cfi_table[0x35] = '0';
78849ab747fSPaolo Bonzini
78949ab747fSPaolo Bonzini pfl->cfi_table[0x36] = 0x00;
79049ab747fSPaolo Bonzini pfl->cfi_table[0x37] = 0x00;
79149ab747fSPaolo Bonzini pfl->cfi_table[0x38] = 0x00;
79249ab747fSPaolo Bonzini pfl->cfi_table[0x39] = 0x00;
79349ab747fSPaolo Bonzini
79449ab747fSPaolo Bonzini pfl->cfi_table[0x3a] = 0x00;
79549ab747fSPaolo Bonzini
79649ab747fSPaolo Bonzini pfl->cfi_table[0x3b] = 0x00;
79749ab747fSPaolo Bonzini pfl->cfi_table[0x3c] = 0x00;
79849ab747fSPaolo Bonzini
79949ab747fSPaolo Bonzini pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
80049ab747fSPaolo Bonzini }
80149ab747fSPaolo Bonzini
pflash_cfi01_realize(DeviceState * dev,Error ** errp)802a42cd11bSPhilippe Mathieu-Daudé static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
803a42cd11bSPhilippe Mathieu-Daudé {
804a42cd11bSPhilippe Mathieu-Daudé ERRP_GUARD();
805a42cd11bSPhilippe Mathieu-Daudé PFlashCFI01 *pfl = PFLASH_CFI01(dev);
806a42cd11bSPhilippe Mathieu-Daudé uint64_t total_len;
807a42cd11bSPhilippe Mathieu-Daudé int ret;
808a42cd11bSPhilippe Mathieu-Daudé
809a42cd11bSPhilippe Mathieu-Daudé if (pfl->sector_len == 0) {
810a42cd11bSPhilippe Mathieu-Daudé error_setg(errp, "attribute \"sector-length\" not specified or zero.");
811a42cd11bSPhilippe Mathieu-Daudé return;
812a42cd11bSPhilippe Mathieu-Daudé }
813a42cd11bSPhilippe Mathieu-Daudé if (pfl->nb_blocs == 0) {
814a42cd11bSPhilippe Mathieu-Daudé error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
815a42cd11bSPhilippe Mathieu-Daudé return;
816a42cd11bSPhilippe Mathieu-Daudé }
817a42cd11bSPhilippe Mathieu-Daudé if (pfl->name == NULL) {
818a42cd11bSPhilippe Mathieu-Daudé error_setg(errp, "attribute \"name\" not specified.");
819a42cd11bSPhilippe Mathieu-Daudé return;
820a42cd11bSPhilippe Mathieu-Daudé }
821a42cd11bSPhilippe Mathieu-Daudé
822a42cd11bSPhilippe Mathieu-Daudé total_len = pfl->sector_len * pfl->nb_blocs;
823a42cd11bSPhilippe Mathieu-Daudé
824a42cd11bSPhilippe Mathieu-Daudé memory_region_init_rom_device(
825a42cd11bSPhilippe Mathieu-Daudé &pfl->mem, OBJECT(dev),
826a42cd11bSPhilippe Mathieu-Daudé &pflash_cfi01_ops,
827a42cd11bSPhilippe Mathieu-Daudé pfl,
828a42cd11bSPhilippe Mathieu-Daudé pfl->name, total_len, errp);
829a42cd11bSPhilippe Mathieu-Daudé if (*errp) {
830a42cd11bSPhilippe Mathieu-Daudé return;
831a42cd11bSPhilippe Mathieu-Daudé }
832a42cd11bSPhilippe Mathieu-Daudé
833a42cd11bSPhilippe Mathieu-Daudé pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
834a42cd11bSPhilippe Mathieu-Daudé sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
835a42cd11bSPhilippe Mathieu-Daudé
836a42cd11bSPhilippe Mathieu-Daudé if (pfl->blk) {
837a42cd11bSPhilippe Mathieu-Daudé uint64_t perm;
838a42cd11bSPhilippe Mathieu-Daudé pfl->ro = !blk_supports_write_perm(pfl->blk);
839a42cd11bSPhilippe Mathieu-Daudé perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
840a42cd11bSPhilippe Mathieu-Daudé ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
841a42cd11bSPhilippe Mathieu-Daudé if (ret < 0) {
842a42cd11bSPhilippe Mathieu-Daudé return;
843a42cd11bSPhilippe Mathieu-Daudé }
844a42cd11bSPhilippe Mathieu-Daudé } else {
8452231bee2SDavid Edmondson pfl->ro = false;
846a42cd11bSPhilippe Mathieu-Daudé }
847a42cd11bSPhilippe Mathieu-Daudé
848a42cd11bSPhilippe Mathieu-Daudé if (pfl->blk) {
849954b33daSManos Pitsidianakis if (!blk_check_size_and_read_all(pfl->blk, dev, pfl->storage,
850954b33daSManos Pitsidianakis total_len, errp)) {
851a42cd11bSPhilippe Mathieu-Daudé vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
852a42cd11bSPhilippe Mathieu-Daudé return;
853a42cd11bSPhilippe Mathieu-Daudé }
854a42cd11bSPhilippe Mathieu-Daudé }
855a42cd11bSPhilippe Mathieu-Daudé
856a42cd11bSPhilippe Mathieu-Daudé /*
857a42cd11bSPhilippe Mathieu-Daudé * Default to devices being used at their maximum device width. This was
858a42cd11bSPhilippe Mathieu-Daudé * assumed before the device_width support was added.
859a42cd11bSPhilippe Mathieu-Daudé */
860a42cd11bSPhilippe Mathieu-Daudé if (!pfl->max_device_width) {
861a42cd11bSPhilippe Mathieu-Daudé pfl->max_device_width = pfl->device_width;
862a42cd11bSPhilippe Mathieu-Daudé }
863a42cd11bSPhilippe Mathieu-Daudé
864a42cd11bSPhilippe Mathieu-Daudé pfl->wcycle = 0;
865a42cd11bSPhilippe Mathieu-Daudé /*
866a42cd11bSPhilippe Mathieu-Daudé * The command 0x00 is not assigned by the CFI open standard,
867a42cd11bSPhilippe Mathieu-Daudé * but QEMU historically uses it for the READ_ARRAY command (0xff).
868a42cd11bSPhilippe Mathieu-Daudé */
869a42cd11bSPhilippe Mathieu-Daudé pfl->cmd = 0x00;
870a42cd11bSPhilippe Mathieu-Daudé pfl->status = 0x80; /* WSM ready */
871ef7716caSDaniel Henrique Barboza pflash_cfi01_fill_cfi_table(pfl);
872284a7ee2SGerd Hoffmann
873284a7ee2SGerd Hoffmann pfl->blk_bytes = g_malloc(pfl->writeblock_size);
874284a7ee2SGerd Hoffmann pfl->blk_offset = -1;
875a42cd11bSPhilippe Mathieu-Daudé }
876a42cd11bSPhilippe Mathieu-Daudé
pflash_cfi01_system_reset(DeviceState * dev)8773a283507SPhilippe Mathieu-Daudé static void pflash_cfi01_system_reset(DeviceState *dev)
8783a283507SPhilippe Mathieu-Daudé {
8793a283507SPhilippe Mathieu-Daudé PFlashCFI01 *pfl = PFLASH_CFI01(dev);
8803a283507SPhilippe Mathieu-Daudé
88191316cbbSDavid Edmondson trace_pflash_reset(pfl->name);
8823a283507SPhilippe Mathieu-Daudé /*
8833a283507SPhilippe Mathieu-Daudé * The command 0x00 is not assigned by the CFI open standard,
8843a283507SPhilippe Mathieu-Daudé * but QEMU historically uses it for the READ_ARRAY command (0xff).
8853a283507SPhilippe Mathieu-Daudé */
8863a283507SPhilippe Mathieu-Daudé pfl->cmd = 0x00;
8873a283507SPhilippe Mathieu-Daudé pfl->wcycle = 0;
8883a283507SPhilippe Mathieu-Daudé memory_region_rom_device_set_romd(&pfl->mem, true);
8893a283507SPhilippe Mathieu-Daudé /*
8903a283507SPhilippe Mathieu-Daudé * The WSM ready timer occurs at most 150ns after system reset.
8913a283507SPhilippe Mathieu-Daudé * This model deliberately ignores this delay.
8923a283507SPhilippe Mathieu-Daudé */
8933a283507SPhilippe Mathieu-Daudé pfl->status = 0x80;
894284a7ee2SGerd Hoffmann
895284a7ee2SGerd Hoffmann pfl->blk_offset = -1;
8963a283507SPhilippe Mathieu-Daudé }
8973a283507SPhilippe Mathieu-Daudé
89849ab747fSPaolo Bonzini static Property pflash_cfi01_properties[] = {
89916434065SMarkus Armbruster DEFINE_PROP_DRIVE("drive", PFlashCFI01, blk),
900a0289b8aSPeter Maydell /* num-blocks is the number of blocks actually visible to the guest,
901a0289b8aSPeter Maydell * ie the total size of the device divided by the sector length.
902a0289b8aSPeter Maydell * If we're emulating flash devices wired in parallel the actual
9039b4b4e51SMichael Tokarev * number of blocks per individual device will differ.
904a0289b8aSPeter Maydell */
90516434065SMarkus Armbruster DEFINE_PROP_UINT32("num-blocks", PFlashCFI01, nb_blocs, 0),
90616434065SMarkus Armbruster DEFINE_PROP_UINT64("sector-length", PFlashCFI01, sector_len, 0),
907fa21a7b1SRoy Franz /* width here is the overall width of this QEMU device in bytes.
908fa21a7b1SRoy Franz * The QEMU device may be emulating a number of flash devices
909fa21a7b1SRoy Franz * wired up in parallel; the width of each individual flash
910fa21a7b1SRoy Franz * device should be specified via device-width. If the individual
911fa21a7b1SRoy Franz * devices have a maximum width which is greater than the width
912fa21a7b1SRoy Franz * they are being used for, this maximum width should be set via
913fa21a7b1SRoy Franz * max-device-width (which otherwise defaults to device-width).
914fa21a7b1SRoy Franz * So for instance a 32-bit wide QEMU flash device made from four
915fa21a7b1SRoy Franz * 16-bit flash devices used in 8-bit wide mode would be configured
916fa21a7b1SRoy Franz * with width = 4, device-width = 1, max-device-width = 2.
917fa21a7b1SRoy Franz *
918fa21a7b1SRoy Franz * If device-width is not specified we default to backwards
919fa21a7b1SRoy Franz * compatible behaviour which is a bad emulation of two
920fa21a7b1SRoy Franz * 16 bit devices making up a 32 bit wide QEMU device. This
921fa21a7b1SRoy Franz * is deprecated for new uses of this device.
922fa21a7b1SRoy Franz */
92316434065SMarkus Armbruster DEFINE_PROP_UINT8("width", PFlashCFI01, bank_width, 0),
92416434065SMarkus Armbruster DEFINE_PROP_UINT8("device-width", PFlashCFI01, device_width, 0),
92516434065SMarkus Armbruster DEFINE_PROP_UINT8("max-device-width", PFlashCFI01, max_device_width, 0),
92616434065SMarkus Armbruster DEFINE_PROP_BIT("big-endian", PFlashCFI01, features, PFLASH_BE, 0),
92716434065SMarkus Armbruster DEFINE_PROP_BIT("secure", PFlashCFI01, features, PFLASH_SECURE, 0),
92816434065SMarkus Armbruster DEFINE_PROP_UINT16("id0", PFlashCFI01, ident0, 0),
92916434065SMarkus Armbruster DEFINE_PROP_UINT16("id1", PFlashCFI01, ident1, 0),
93016434065SMarkus Armbruster DEFINE_PROP_UINT16("id2", PFlashCFI01, ident2, 0),
93116434065SMarkus Armbruster DEFINE_PROP_UINT16("id3", PFlashCFI01, ident3, 0),
93216434065SMarkus Armbruster DEFINE_PROP_STRING("name", PFlashCFI01, name),
93316434065SMarkus Armbruster DEFINE_PROP_BOOL("old-multiple-chip-handling", PFlashCFI01,
934feb0b1aaSPeter Maydell old_multiple_chip_handling, false),
93549ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
93649ab747fSPaolo Bonzini };
93749ab747fSPaolo Bonzini
pflash_cfi01_class_init(ObjectClass * klass,void * data)93849ab747fSPaolo Bonzini static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
93949ab747fSPaolo Bonzini {
94049ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
94149ab747fSPaolo Bonzini
942e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pflash_cfi01_system_reset);
943e40b5f3eSHu Tao dc->realize = pflash_cfi01_realize;
9444f67d30bSMarc-André Lureau device_class_set_props(dc, pflash_cfi01_properties);
94549ab747fSPaolo Bonzini dc->vmsd = &vmstate_pflash;
946125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
94749ab747fSPaolo Bonzini }
94849ab747fSPaolo Bonzini
949*2b88cd17SBernhard Beschow static const TypeInfo pflash_cfi01_types[] = {
950*2b88cd17SBernhard Beschow {
951e7b62741SMarkus Armbruster .name = TYPE_PFLASH_CFI01,
95249ab747fSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
95316434065SMarkus Armbruster .instance_size = sizeof(PFlashCFI01),
95449ab747fSPaolo Bonzini .class_init = pflash_cfi01_class_init,
955*2b88cd17SBernhard Beschow },
95649ab747fSPaolo Bonzini };
95749ab747fSPaolo Bonzini
DEFINE_TYPES(pflash_cfi01_types)958*2b88cd17SBernhard Beschow DEFINE_TYPES(pflash_cfi01_types)
95949ab747fSPaolo Bonzini
96016434065SMarkus Armbruster PFlashCFI01 *pflash_cfi01_register(hwaddr base,
961940d5b13SMarkus Armbruster const char *name,
96249ab747fSPaolo Bonzini hwaddr size,
9634be74634SMarkus Armbruster BlockBackend *blk,
964ce14710fSMarkus Armbruster uint32_t sector_len,
96516434065SMarkus Armbruster int bank_width,
96616434065SMarkus Armbruster uint16_t id0, uint16_t id1,
96716434065SMarkus Armbruster uint16_t id2, uint16_t id3,
96816434065SMarkus Armbruster int be)
96949ab747fSPaolo Bonzini {
9703e80f690SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
97149ab747fSPaolo Bonzini
9729b3d111aSMarkus Armbruster if (blk) {
973934df912SMarkus Armbruster qdev_prop_set_drive(dev, "drive", blk);
97449ab747fSPaolo Bonzini }
9754cdd0a77SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(size, sector_len));
976ce14710fSMarkus Armbruster qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
97749ab747fSPaolo Bonzini qdev_prop_set_uint64(dev, "sector-length", sector_len);
9784b6fedcaSRoy Franz qdev_prop_set_uint8(dev, "width", bank_width);
979e9809422SPaolo Bonzini qdev_prop_set_bit(dev, "big-endian", !!be);
98049ab747fSPaolo Bonzini qdev_prop_set_uint16(dev, "id0", id0);
98149ab747fSPaolo Bonzini qdev_prop_set_uint16(dev, "id1", id1);
98249ab747fSPaolo Bonzini qdev_prop_set_uint16(dev, "id2", id2);
98349ab747fSPaolo Bonzini qdev_prop_set_uint16(dev, "id3", id3);
98449ab747fSPaolo Bonzini qdev_prop_set_string(dev, "name", name);
9853c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
98649ab747fSPaolo Bonzini
987f1b44f0eSHu Tao sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
988e7b62741SMarkus Armbruster return PFLASH_CFI01(dev);
98949ab747fSPaolo Bonzini }
99049ab747fSPaolo Bonzini
pflash_cfi01_get_blk(PFlashCFI01 * fl)991e60cf765SPhilippe Mathieu-Daudé BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl)
992e60cf765SPhilippe Mathieu-Daudé {
993e60cf765SPhilippe Mathieu-Daudé return fl->blk;
994e60cf765SPhilippe Mathieu-Daudé }
995e60cf765SPhilippe Mathieu-Daudé
pflash_cfi01_get_memory(PFlashCFI01 * fl)99616434065SMarkus Armbruster MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl)
99749ab747fSPaolo Bonzini {
99849ab747fSPaolo Bonzini return &fl->mem;
99949ab747fSPaolo Bonzini }
10004c0cfc72SLaszlo Ersek
10012d731dbdSMarkus Armbruster /*
10022d731dbdSMarkus Armbruster * Handle -drive if=pflash for machines that use properties.
10032d731dbdSMarkus Armbruster * If @dinfo is null, do nothing.
10042d731dbdSMarkus Armbruster * Else if @fl's property "drive" is already set, fatal error.
10052d731dbdSMarkus Armbruster * Else set it to the BlockBackend with @dinfo.
10062d731dbdSMarkus Armbruster */
pflash_cfi01_legacy_drive(PFlashCFI01 * fl,DriveInfo * dinfo)10072d731dbdSMarkus Armbruster void pflash_cfi01_legacy_drive(PFlashCFI01 *fl, DriveInfo *dinfo)
10082d731dbdSMarkus Armbruster {
10092d731dbdSMarkus Armbruster Location loc;
10102d731dbdSMarkus Armbruster
10112d731dbdSMarkus Armbruster if (!dinfo) {
10122d731dbdSMarkus Armbruster return;
10132d731dbdSMarkus Armbruster }
10142d731dbdSMarkus Armbruster
10152d731dbdSMarkus Armbruster loc_push_none(&loc);
10162d731dbdSMarkus Armbruster qemu_opts_loc_restore(dinfo->opts);
10172d731dbdSMarkus Armbruster if (fl->blk) {
10182d731dbdSMarkus Armbruster error_report("clashes with -machine");
10192d731dbdSMarkus Armbruster exit(1);
10202d731dbdSMarkus Armbruster }
1021934df912SMarkus Armbruster qdev_prop_set_drive_err(DEVICE(fl), "drive", blk_by_legacy_dinfo(dinfo),
1022934df912SMarkus Armbruster &error_fatal);
10232d731dbdSMarkus Armbruster loc_pop(&loc);
10242d731dbdSMarkus Armbruster }
10252d731dbdSMarkus Armbruster
postload_update_cb(void * opaque,bool running,RunState state)1026538f0497SPhilippe Mathieu-Daudé static void postload_update_cb(void *opaque, bool running, RunState state)
102790c647dbSDr. David Alan Gilbert {
102816434065SMarkus Armbruster PFlashCFI01 *pfl = opaque;
102990c647dbSDr. David Alan Gilbert
10303b717194SEmanuele Giuseppe Esposito /* This is called after bdrv_activate_all. */
103190c647dbSDr. David Alan Gilbert qemu_del_vm_change_state_handler(pfl->vmstate);
103290c647dbSDr. David Alan Gilbert pfl->vmstate = NULL;
103390c647dbSDr. David Alan Gilbert
103491316cbbSDavid Edmondson trace_pflash_postload_cb(pfl->name);
103590c647dbSDr. David Alan Gilbert pflash_update(pfl, 0, pfl->sector_len * pfl->nb_blocs);
103690c647dbSDr. David Alan Gilbert }
103790c647dbSDr. David Alan Gilbert
pflash_post_load(void * opaque,int version_id)10384c0cfc72SLaszlo Ersek static int pflash_post_load(void *opaque, int version_id)
10394c0cfc72SLaszlo Ersek {
104016434065SMarkus Armbruster PFlashCFI01 *pfl = opaque;
10414c0cfc72SLaszlo Ersek
10424c0cfc72SLaszlo Ersek if (!pfl->ro) {
104390c647dbSDr. David Alan Gilbert pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
104490c647dbSDr. David Alan Gilbert pfl);
10454c0cfc72SLaszlo Ersek }
10464c0cfc72SLaszlo Ersek return 0;
10474c0cfc72SLaszlo Ersek }
1048