blob: 62056b1d741ee4ff49f7dcce76f18c70f376ec4b [file] [log] [blame]
balrog05ee37e2007-11-17 11:50:55 +00001/*
2 * CFI parallel flash with Intel command set emulation
3 *
4 * Copyright (c) 2006 Thorsten Zitterell
5 * Copyright (c) 2005 Jocelyn Mayer
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
Chetan Pant3564a912020-10-23 12:30:34 +000010 * version 2.1 of the License, or (at your option) any later version.
balrog05ee37e2007-11-17 11:50:55 +000011 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
balrog05ee37e2007-11-17 11:50:55 +000019 */
20
21/*
22 * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
23 * Supported commands/modes are:
24 * - flash read
25 * - flash write
26 * - flash ID read
27 * - sector erase
28 * - CFI queries
29 *
30 * It does not support timings
31 * It does not support flash interleaving
32 * It does not implement software data protection as found in many real chips
33 * It does not implement erase suspend/resume commands
34 * It does not implement multiple sectors erase
35 *
36 * It does not implement much more ...
37 */
38
Peter Maydell80c71a22016-01-18 18:01:42 +000039#include "qemu/osdep.h"
Markus Armbruster06f15212019-03-19 17:35:50 +010040#include "hw/block/block.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010041#include "hw/block/flash.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020042#include "hw/qdev-properties.h"
Eduardo Habkostce35e222020-12-11 17:05:12 -050043#include "hw/qdev-properties-system.h"
Markus Armbruster4be74632014-10-07 13:59:18 +020044#include "sysemu/block-backend.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010045#include "qapi/error.h"
Mansour Ahmadi1857b9d2020-04-07 20:35:52 -040046#include "qemu/error-report.h"
Roy Franz1997b482013-12-17 19:42:26 +000047#include "qemu/bitops.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010048#include "qemu/host-utils.h"
Paolo Bonzini03dd0242015-12-15 13:16:16 +010049#include "qemu/log.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020050#include "qemu/module.h"
Markus Armbruster2d731db2019-05-07 12:55:02 +010051#include "qemu/option.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010052#include "hw/sysbus.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020053#include "migration/vmstate.h"
Markus Armbruster2d731db2019-05-07 12:55:02 +010054#include "sysemu/blockdev.h"
Markus Armbruster54d31232019-08-12 07:23:59 +020055#include "sysemu/runstate.h"
Philippe Mathieu-Daudé13019f12018-06-21 14:12:57 -030056#include "trace.h"
balrog05ee37e2007-11-17 11:50:55 +000057
Paolo Bonzinie9809422015-04-08 13:53:29 +020058#define PFLASH_BE 0
Paolo Bonzinif71e42a2015-04-08 14:09:43 +020059#define PFLASH_SECURE 1
Paolo Bonzinie9809422015-04-08 13:53:29 +020060
Markus Armbruster16434062019-03-08 10:45:56 +010061struct PFlashCFI01 {
Hu Taof1b44f02013-07-01 18:18:26 +080062 /*< private >*/
63 SysBusDevice parent_obj;
64 /*< public >*/
65
Markus Armbruster4be74632014-10-07 13:59:18 +020066 BlockBackend *blk;
Peter Crosthwaite368a3542012-10-30 07:45:11 +000067 uint32_t nb_blocs;
68 uint64_t sector_len;
Roy Franz4b6fedc2013-12-17 19:42:26 +000069 uint8_t bank_width;
Roy Franz1997b482013-12-17 19:42:26 +000070 uint8_t device_width; /* If 0, device width not specified. */
Roy Franzfa21a7b2013-12-17 19:42:27 +000071 uint8_t max_device_width; /* max device width in bytes */
Paolo Bonzinie9809422015-04-08 13:53:29 +020072 uint32_t features;
Peter Maydelld8d24fb2013-04-05 16:18:00 +010073 uint8_t wcycle; /* if 0, the flash is read normally */
David Edmondson2231bee2021-02-16 14:27:19 +000074 bool ro;
balrog05ee37e2007-11-17 11:50:55 +000075 uint8_t cmd;
76 uint8_t status;
Peter Crosthwaite368a3542012-10-30 07:45:11 +000077 uint16_t ident0;
78 uint16_t ident1;
79 uint16_t ident2;
80 uint16_t ident3;
balrog05ee37e2007-11-17 11:50:55 +000081 uint8_t cfi_table[0x52];
Peter Maydelld8d24fb2013-04-05 16:18:00 +010082 uint64_t counter;
Edgar E. Iglesiasb4bf0a92010-01-24 20:38:29 +010083 unsigned int writeblock_size;
Avi Kivitycfe5f012011-08-04 15:55:30 +030084 MemoryRegion mem;
Peter Crosthwaite368a3542012-10-30 07:45:11 +000085 char *name;
balrog05ee37e2007-11-17 11:50:55 +000086 void *storage;
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +010087 VMChangeStateEntry *vmstate;
Peter Maydellfeb0b1a2017-01-27 15:20:22 +000088 bool old_multiple_chip_handling;
balrog05ee37e2007-11-17 11:50:55 +000089};
90
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +020091static int pflash_post_load(void *opaque, int version_id);
92
Peter Maydelld8d24fb2013-04-05 16:18:00 +010093static const VMStateDescription vmstate_pflash = {
94 .name = "pflash_cfi01",
95 .version_id = 1,
96 .minimum_version_id = 1,
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +020097 .post_load = pflash_post_load,
Peter Maydelld8d24fb2013-04-05 16:18:00 +010098 .fields = (VMStateField[]) {
Markus Armbruster16434062019-03-08 10:45:56 +010099 VMSTATE_UINT8(wcycle, PFlashCFI01),
100 VMSTATE_UINT8(cmd, PFlashCFI01),
101 VMSTATE_UINT8(status, PFlashCFI01),
102 VMSTATE_UINT64(counter, PFlashCFI01),
Peter Maydelld8d24fb2013-04-05 16:18:00 +0100103 VMSTATE_END_OF_LIST()
104 }
105};
106
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100107/*
108 * Perform a CFI query based on the bank width of the flash.
Roy Franz4433e662013-12-17 19:42:27 +0000109 * If this code is called we know we have a device_width set for
110 * this flash.
111 */
Markus Armbruster16434062019-03-08 10:45:56 +0100112static uint32_t pflash_cfi_query(PFlashCFI01 *pfl, hwaddr offset)
Roy Franz4433e662013-12-17 19:42:27 +0000113{
114 int i;
115 uint32_t resp = 0;
116 hwaddr boff;
117
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100118 /*
119 * Adjust incoming offset to match expected device-width
Roy Franz4433e662013-12-17 19:42:27 +0000120 * addressing. CFI query addresses are always specified in terms of
121 * the maximum supported width of the device. This means that x8
122 * devices and x8/x16 devices in x8 mode behave differently. For
123 * devices that are not used at their max width, we will be
124 * provided with addresses that use higher address bits than
125 * expected (based on the max width), so we will shift them lower
126 * so that they will match the addresses used when
127 * device_width==max_device_width.
128 */
129 boff = offset >> (ctz32(pfl->bank_width) +
130 ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
131
Philippe Mathieu-Daudé07c13a72018-04-04 20:32:38 -0300132 if (boff >= sizeof(pfl->cfi_table)) {
Roy Franz4433e662013-12-17 19:42:27 +0000133 return 0;
134 }
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100135 /*
136 * Now we will construct the CFI response generated by a single
Roy Franz4433e662013-12-17 19:42:27 +0000137 * device, then replicate that for all devices that make up the
138 * bus. For wide parts used in x8 mode, CFI query responses
139 * are different than native byte-wide parts.
140 */
141 resp = pfl->cfi_table[boff];
142 if (pfl->device_width != pfl->max_device_width) {
143 /* The only case currently supported is x8 mode for a
144 * wider part.
145 */
146 if (pfl->device_width != 1 || pfl->bank_width > 4) {
David Edmondson91316cb2021-02-16 14:27:18 +0000147 trace_pflash_unsupported_device_configuration(pfl->name,
148 pfl->device_width, pfl->max_device_width);
Roy Franz4433e662013-12-17 19:42:27 +0000149 return 0;
150 }
151 /* CFI query data is repeated, rather than zero padded for
152 * wide devices used in x8 mode.
153 */
154 for (i = 1; i < pfl->max_device_width; i++) {
155 resp = deposit32(resp, 8 * i, 8, pfl->cfi_table[boff]);
156 }
157 }
158 /* Replicate responses for each device in bank. */
159 if (pfl->device_width < pfl->bank_width) {
160 for (i = pfl->device_width;
161 i < pfl->bank_width; i += pfl->device_width) {
162 resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
163 }
164 }
165
166 return resp;
167}
168
Roy Franz0163a2d2013-12-17 19:42:27 +0000169
170
171/* Perform a device id query based on the bank width of the flash. */
Markus Armbruster16434062019-03-08 10:45:56 +0100172static uint32_t pflash_devid_query(PFlashCFI01 *pfl, hwaddr offset)
Roy Franz0163a2d2013-12-17 19:42:27 +0000173{
174 int i;
175 uint32_t resp;
176 hwaddr boff;
177
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100178 /*
179 * Adjust incoming offset to match expected device-width
Roy Franz0163a2d2013-12-17 19:42:27 +0000180 * addressing. Device ID read addresses are always specified in
181 * terms of the maximum supported width of the device. This means
182 * that x8 devices and x8/x16 devices in x8 mode behave
183 * differently. For devices that are not used at their max width,
184 * we will be provided with addresses that use higher address bits
185 * than expected (based on the max width), so we will shift them
186 * lower so that they will match the addresses used when
187 * device_width==max_device_width.
188 */
189 boff = offset >> (ctz32(pfl->bank_width) +
190 ctz32(pfl->max_device_width) - ctz32(pfl->device_width));
191
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100192 /*
193 * Mask off upper bits which may be used in to query block
Roy Franz0163a2d2013-12-17 19:42:27 +0000194 * or sector lock status at other addresses.
195 * Offsets 2/3 are block lock status, is not emulated.
196 */
197 switch (boff & 0xFF) {
198 case 0:
199 resp = pfl->ident0;
David Edmondson91316cb2021-02-16 14:27:18 +0000200 trace_pflash_manufacturer_id(pfl->name, resp);
Roy Franz0163a2d2013-12-17 19:42:27 +0000201 break;
202 case 1:
203 resp = pfl->ident1;
David Edmondson91316cb2021-02-16 14:27:18 +0000204 trace_pflash_device_id(pfl->name, resp);
Roy Franz0163a2d2013-12-17 19:42:27 +0000205 break;
206 default:
David Edmondson91316cb2021-02-16 14:27:18 +0000207 trace_pflash_device_info(pfl->name, offset);
Roy Franz0163a2d2013-12-17 19:42:27 +0000208 return 0;
Roy Franz0163a2d2013-12-17 19:42:27 +0000209 }
210 /* Replicate responses for each device in bank. */
211 if (pfl->device_width < pfl->bank_width) {
212 for (i = pfl->device_width;
213 i < pfl->bank_width; i += pfl->device_width) {
214 resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp);
215 }
216 }
217
218 return resp;
219}
220
Markus Armbruster16434062019-03-08 10:45:56 +0100221static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200222 int width, int be)
223{
224 uint8_t *p;
225 uint32_t ret;
226
227 p = pfl->storage;
228 switch (width) {
229 case 1:
230 ret = p[offset];
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200231 break;
232 case 2:
233 if (be) {
234 ret = p[offset] << 8;
235 ret |= p[offset + 1];
236 } else {
237 ret = p[offset];
238 ret |= p[offset + 1] << 8;
239 }
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200240 break;
241 case 4:
242 if (be) {
243 ret = p[offset] << 24;
244 ret |= p[offset + 1] << 16;
245 ret |= p[offset + 2] << 8;
246 ret |= p[offset + 3];
247 } else {
248 ret = p[offset];
249 ret |= p[offset + 1] << 8;
250 ret |= p[offset + 2] << 16;
251 ret |= p[offset + 3] << 24;
252 }
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200253 break;
254 default:
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200255 abort();
256 }
David Edmondson91316cb2021-02-16 14:27:18 +0000257 trace_pflash_data_read(pfl->name, offset, width, ret);
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200258 return ret;
259}
260
Markus Armbruster16434062019-03-08 10:45:56 +0100261static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
262 int width, int be)
balrog05ee37e2007-11-17 11:50:55 +0000263{
Avi Kivitya8170e52012-10-23 12:30:10 +0200264 hwaddr boff;
balrog05ee37e2007-11-17 11:50:55 +0000265 uint32_t ret;
balrog05ee37e2007-11-17 11:50:55 +0000266
267 ret = -1;
balrog05ee37e2007-11-17 11:50:55 +0000268 switch (pfl->cmd) {
Peter Maydell1be97bf2013-02-28 18:23:12 +0000269 default:
270 /* This should never happen : reset state & treat it as a read */
David Edmondson91316cb2021-02-16 14:27:18 +0000271 trace_pflash_read_unknown_state(pfl->name, pfl->cmd);
Peter Maydell1be97bf2013-02-28 18:23:12 +0000272 pfl->wcycle = 0;
Philippe Mathieu-Daudéaba53a12019-07-16 19:06:56 +0200273 /*
274 * The command 0x00 is not assigned by the CFI open standard,
275 * but QEMU historically uses it for the READ_ARRAY command (0xff).
276 */
277 pfl->cmd = 0x00;
Peter Maydell1be97bf2013-02-28 18:23:12 +0000278 /* fall through to read code */
Philippe Mathieu-Daudéaba53a12019-07-16 19:06:56 +0200279 case 0x00: /* This model reset value for READ_ARRAY (not CFI compliant) */
balrog05ee37e2007-11-17 11:50:55 +0000280 /* Flash area read */
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200281 ret = pflash_data_read(pfl, offset, width, be);
balrog05ee37e2007-11-17 11:50:55 +0000282 break;
Peter Maydell6e392782013-02-28 18:23:12 +0000283 case 0x10: /* Single byte program */
balrog05ee37e2007-11-17 11:50:55 +0000284 case 0x20: /* Block erase */
Peter Maydell6e392782013-02-28 18:23:12 +0000285 case 0x28: /* Block erase */
286 case 0x40: /* single byte program */
balrog05ee37e2007-11-17 11:50:55 +0000287 case 0x50: /* Clear status register */
288 case 0x60: /* Block /un)lock */
289 case 0x70: /* Status Register */
290 case 0xe8: /* Write block */
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100291 /*
292 * Status register read. Return status from each device in
Roy Franz20038892013-12-17 19:42:26 +0000293 * bank.
294 */
balrog05ee37e2007-11-17 11:50:55 +0000295 ret = pfl->status;
Roy Franz20038892013-12-17 19:42:26 +0000296 if (pfl->device_width && width > pfl->device_width) {
297 int shift = pfl->device_width * 8;
298 while (shift + pfl->device_width * 8 <= width * 8) {
299 ret |= pfl->status << shift;
300 shift += pfl->device_width * 8;
301 }
302 } else if (!pfl->device_width && width > 2) {
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100303 /*
304 * Handle 32 bit flash cases where device width is not
Roy Franz20038892013-12-17 19:42:26 +0000305 * set. (Existing behavior before device width added.)
306 */
Paul Burtonea0a4f32013-06-14 08:30:48 +0100307 ret |= pfl->status << 16;
308 }
David Edmondson91316cb2021-02-16 14:27:18 +0000309 trace_pflash_read_status(pfl->name, ret);
balrog05ee37e2007-11-17 11:50:55 +0000310 break;
Michael Walle0b2ec6f2010-05-01 19:34:06 +0200311 case 0x90:
Roy Franz0163a2d2013-12-17 19:42:27 +0000312 if (!pfl->device_width) {
313 /* Preserve old behavior if device width not specified */
314 boff = offset & 0xFF;
315 if (pfl->bank_width == 2) {
316 boff = boff >> 1;
317 } else if (pfl->bank_width == 4) {
318 boff = boff >> 2;
319 }
Roy Franz4433e662013-12-17 19:42:27 +0000320
Roy Franz0163a2d2013-12-17 19:42:27 +0000321 switch (boff) {
322 case 0:
323 ret = pfl->ident0 << 8 | pfl->ident1;
David Edmondson91316cb2021-02-16 14:27:18 +0000324 trace_pflash_manufacturer_id(pfl->name, ret);
Roy Franz0163a2d2013-12-17 19:42:27 +0000325 break;
326 case 1:
327 ret = pfl->ident2 << 8 | pfl->ident3;
David Edmondson91316cb2021-02-16 14:27:18 +0000328 trace_pflash_device_id(pfl->name, ret);
Roy Franz0163a2d2013-12-17 19:42:27 +0000329 break;
330 default:
David Edmondson91316cb2021-02-16 14:27:18 +0000331 trace_pflash_device_info(pfl->name, boff);
Roy Franz0163a2d2013-12-17 19:42:27 +0000332 ret = 0;
333 break;
334 }
335 } else {
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100336 /*
337 * If we have a read larger than the bank_width, combine multiple
Roy Franz0163a2d2013-12-17 19:42:27 +0000338 * manufacturer/device ID queries into a single response.
339 */
340 int i;
341 for (i = 0; i < width; i += pfl->bank_width) {
342 ret = deposit32(ret, i * 8, pfl->bank_width * 8,
343 pflash_devid_query(pfl,
344 offset + i * pfl->bank_width));
345 }
Michael Walle0b2ec6f2010-05-01 19:34:06 +0200346 }
347 break;
balrog05ee37e2007-11-17 11:50:55 +0000348 case 0x98: /* Query mode */
Roy Franz4433e662013-12-17 19:42:27 +0000349 if (!pfl->device_width) {
350 /* Preserve old behavior if device width not specified */
351 boff = offset & 0xFF;
352 if (pfl->bank_width == 2) {
353 boff = boff >> 1;
354 } else if (pfl->bank_width == 4) {
355 boff = boff >> 2;
356 }
357
Philippe Mathieu-Daudé07c13a72018-04-04 20:32:38 -0300358 if (boff < sizeof(pfl->cfi_table)) {
Roy Franz4433e662013-12-17 19:42:27 +0000359 ret = pfl->cfi_table[boff];
Philippe Mathieu-Daudé07c13a72018-04-04 20:32:38 -0300360 } else {
361 ret = 0;
Roy Franz4433e662013-12-17 19:42:27 +0000362 }
363 } else {
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100364 /*
365 * If we have a read larger than the bank_width, combine multiple
Roy Franz4433e662013-12-17 19:42:27 +0000366 * CFI queries into a single response.
367 */
368 int i;
369 for (i = 0; i < width; i += pfl->bank_width) {
370 ret = deposit32(ret, i * 8, pfl->bank_width * 8,
371 pflash_cfi_query(pfl,
372 offset + i * pfl->bank_width));
373 }
374 }
375
balrog05ee37e2007-11-17 11:50:55 +0000376 break;
balrog05ee37e2007-11-17 11:50:55 +0000377 }
David Edmondson91316cb2021-02-16 14:27:18 +0000378 trace_pflash_io_read(pfl->name, offset, width, ret, pfl->cmd, pfl->wcycle);
Philippe Mathieu-Daudée8aa2d92019-06-26 18:39:10 +0200379
balrog05ee37e2007-11-17 11:50:55 +0000380 return ret;
381}
382
383/* update flash content on disk */
Markus Armbruster16434062019-03-08 10:45:56 +0100384static void pflash_update(PFlashCFI01 *pfl, int offset,
balrog05ee37e2007-11-17 11:50:55 +0000385 int size)
386{
387 int offset_end;
Mansour Ahmadi1857b9d2020-04-07 20:35:52 -0400388 int ret;
Markus Armbruster4be74632014-10-07 13:59:18 +0200389 if (pfl->blk) {
balrog05ee37e2007-11-17 11:50:55 +0000390 offset_end = offset + size;
Eric Blake098e7322016-05-06 10:26:38 -0600391 /* widen to sector boundaries */
392 offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE);
393 offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE);
Alberto Fariaa9262f52022-07-05 17:15:11 +0100394 ret = blk_pwrite(pfl->blk, offset, offset_end - offset,
395 pfl->storage + offset, 0);
Mansour Ahmadi1857b9d2020-04-07 20:35:52 -0400396 if (ret < 0) {
397 /* TODO set error bit in status */
398 error_report("Could not update PFLASH: %s", strerror(-ret));
399 }
balrog05ee37e2007-11-17 11:50:55 +0000400 }
401}
402
Markus Armbruster16434062019-03-08 10:45:56 +0100403static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
Blue Swirl3d08ff62010-03-29 19:23:56 +0000404 uint32_t value, int width, int be)
balrogd361be22008-12-07 12:36:28 +0000405{
406 uint8_t *p = pfl->storage;
407
David Edmondson91316cb2021-02-16 14:27:18 +0000408 trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter);
balrogd361be22008-12-07 12:36:28 +0000409 switch (width) {
410 case 1:
411 p[offset] = value;
balrogd361be22008-12-07 12:36:28 +0000412 break;
413 case 2:
Blue Swirl3d08ff62010-03-29 19:23:56 +0000414 if (be) {
415 p[offset] = value >> 8;
416 p[offset + 1] = value;
417 } else {
418 p[offset] = value;
419 p[offset + 1] = value >> 8;
420 }
balrogd361be22008-12-07 12:36:28 +0000421 break;
422 case 4:
Blue Swirl3d08ff62010-03-29 19:23:56 +0000423 if (be) {
424 p[offset] = value >> 24;
425 p[offset + 1] = value >> 16;
426 p[offset + 2] = value >> 8;
427 p[offset + 3] = value;
428 } else {
429 p[offset] = value;
430 p[offset + 1] = value >> 8;
431 p[offset + 2] = value >> 16;
432 p[offset + 3] = value >> 24;
433 }
balrogd361be22008-12-07 12:36:28 +0000434 break;
435 }
436
437}
438
Markus Armbruster16434062019-03-08 10:45:56 +0100439static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
Blue Swirl3d08ff62010-03-29 19:23:56 +0000440 uint32_t value, int width, int be)
balrog05ee37e2007-11-17 11:50:55 +0000441{
balrog05ee37e2007-11-17 11:50:55 +0000442 uint8_t *p;
443 uint8_t cmd;
444
balrog05ee37e2007-11-17 11:50:55 +0000445 cmd = value;
balrog05ee37e2007-11-17 11:50:55 +0000446
David Edmondson91316cb2021-02-16 14:27:18 +0000447 trace_pflash_io_write(pfl->name, offset, width, value, pfl->wcycle);
Edgar E. Iglesiase9cbbca2010-01-24 19:28:55 +0100448 if (!pfl->wcycle) {
449 /* Set the device in I/O access mode */
Jan Kiszka5f9a5ea2013-05-07 19:04:25 +0200450 memory_region_rom_device_set_romd(&pfl->mem, false);
Edgar E. Iglesiase9cbbca2010-01-24 19:28:55 +0100451 }
balrog05ee37e2007-11-17 11:50:55 +0000452
453 switch (pfl->wcycle) {
454 case 0:
455 /* read mode */
456 switch (cmd) {
Philippe Mathieu-Daudéaba53a12019-07-16 19:06:56 +0200457 case 0x00: /* This model reset value for READ_ARRAY (not CFI) */
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200458 goto mode_read_array;
balrogd361be22008-12-07 12:36:28 +0000459 case 0x10: /* Single Byte Program */
460 case 0x40: /* Single Byte Program */
David Edmondson91316cb2021-02-16 14:27:18 +0000461 trace_pflash_write(pfl->name, "single byte program (0)");
balrogd361be22008-12-07 12:36:28 +0000462 break;
balrog05ee37e2007-11-17 11:50:55 +0000463 case 0x20: /* Block erase */
464 p = pfl->storage;
465 offset &= ~(pfl->sector_len - 1);
466
David Edmondson91316cb2021-02-16 14:27:18 +0000467 trace_pflash_write_block_erase(pfl->name, offset, pfl->sector_len);
balrog05ee37e2007-11-17 11:50:55 +0000468
Jordan Justende8efe82012-02-21 23:18:49 -0800469 if (!pfl->ro) {
470 memset(p + offset, 0xff, pfl->sector_len);
471 pflash_update(pfl, offset, pfl->sector_len);
472 } else {
473 pfl->status |= 0x20; /* Block erase error */
474 }
balrog05ee37e2007-11-17 11:50:55 +0000475 pfl->status |= 0x80; /* Ready! */
476 break;
477 case 0x50: /* Clear status bits */
David Edmondson91316cb2021-02-16 14:27:18 +0000478 trace_pflash_write(pfl->name, "clear status bits");
balrog05ee37e2007-11-17 11:50:55 +0000479 pfl->status = 0x0;
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200480 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000481 case 0x60: /* Block (un)lock */
David Edmondson91316cb2021-02-16 14:27:18 +0000482 trace_pflash_write(pfl->name, "block unlock");
balrog05ee37e2007-11-17 11:50:55 +0000483 break;
484 case 0x70: /* Status Register */
David Edmondson91316cb2021-02-16 14:27:18 +0000485 trace_pflash_write(pfl->name, "read status register");
balrog05ee37e2007-11-17 11:50:55 +0000486 pfl->cmd = cmd;
487 return;
Michael Walle0b2ec6f2010-05-01 19:34:06 +0200488 case 0x90: /* Read Device ID */
David Edmondson91316cb2021-02-16 14:27:18 +0000489 trace_pflash_write(pfl->name, "read device information");
Michael Walle0b2ec6f2010-05-01 19:34:06 +0200490 pfl->cmd = cmd;
491 return;
balrog05ee37e2007-11-17 11:50:55 +0000492 case 0x98: /* CFI query */
David Edmondson91316cb2021-02-16 14:27:18 +0000493 trace_pflash_write(pfl->name, "CFI query");
balrog05ee37e2007-11-17 11:50:55 +0000494 break;
495 case 0xe8: /* Write to buffer */
David Edmondson91316cb2021-02-16 14:27:18 +0000496 trace_pflash_write(pfl->name, "write to buffer");
Markus Armbruster4dbda932019-03-08 10:45:58 +0100497 /* FIXME should save @offset, @width for case 1+ */
498 qemu_log_mask(LOG_UNIMP,
499 "%s: Write to buffer emulation is flawed\n",
500 __func__);
balrog05ee37e2007-11-17 11:50:55 +0000501 pfl->status |= 0x80; /* Ready! */
502 break;
Stefan Weil59280232012-11-24 23:03:13 +0100503 case 0xf0: /* Probe for AMD flash */
David Edmondson91316cb2021-02-16 14:27:18 +0000504 trace_pflash_write(pfl->name, "probe for AMD flash");
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200505 goto mode_read_array;
506 case 0xff: /* Read Array */
David Edmondson91316cb2021-02-16 14:27:18 +0000507 trace_pflash_write(pfl->name, "read array mode");
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200508 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000509 default:
510 goto error_flash;
511 }
512 pfl->wcycle++;
513 pfl->cmd = cmd;
Stefan Weil12dabc72012-09-01 13:00:48 +0200514 break;
balrog05ee37e2007-11-17 11:50:55 +0000515 case 1:
516 switch (pfl->cmd) {
balrogd361be22008-12-07 12:36:28 +0000517 case 0x10: /* Single Byte Program */
518 case 0x40: /* Single Byte Program */
David Edmondson91316cb2021-02-16 14:27:18 +0000519 trace_pflash_write(pfl->name, "single byte program (1)");
Jordan Justende8efe82012-02-21 23:18:49 -0800520 if (!pfl->ro) {
521 pflash_data_write(pfl, offset, value, width, be);
522 pflash_update(pfl, offset, width);
523 } else {
524 pfl->status |= 0x10; /* Programming error */
525 }
balrogd361be22008-12-07 12:36:28 +0000526 pfl->status |= 0x80; /* Ready! */
527 pfl->wcycle = 0;
528 break;
balrog05ee37e2007-11-17 11:50:55 +0000529 case 0x20: /* Block erase */
530 case 0x28:
531 if (cmd == 0xd0) { /* confirm */
balrog36567442008-10-03 23:00:09 +0000532 pfl->wcycle = 0;
balrog05ee37e2007-11-17 11:50:55 +0000533 pfl->status |= 0x80;
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200534 } else if (cmd == 0xff) { /* Read Array */
535 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000536 } else
537 goto error_flash;
538
539 break;
540 case 0xe8:
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100541 /*
542 * Mask writeblock size based on device width, or bank width if
Roy Franz1997b482013-12-17 19:42:26 +0000543 * device width not specified.
544 */
Markus Armbruster4dbda932019-03-08 10:45:58 +0100545 /* FIXME check @offset, @width */
Roy Franz1997b482013-12-17 19:42:26 +0000546 if (pfl->device_width) {
547 value = extract32(value, 0, pfl->device_width * 8);
548 } else {
549 value = extract32(value, 0, pfl->bank_width * 8);
550 }
David Edmondson91316cb2021-02-16 14:27:18 +0000551 trace_pflash_write_block(pfl->name, value);
balrog71fb2342008-10-11 09:19:57 +0000552 pfl->counter = value;
balrog05ee37e2007-11-17 11:50:55 +0000553 pfl->wcycle++;
554 break;
555 case 0x60:
556 if (cmd == 0xd0) {
557 pfl->wcycle = 0;
558 pfl->status |= 0x80;
559 } else if (cmd == 0x01) {
560 pfl->wcycle = 0;
561 pfl->status |= 0x80;
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200562 } else if (cmd == 0xff) { /* Read Array */
563 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000564 } else {
David Edmondson91316cb2021-02-16 14:27:18 +0000565 trace_pflash_write(pfl->name, "unknown (un)locking command");
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200566 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000567 }
568 break;
569 case 0x98:
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200570 if (cmd == 0xff) { /* Read Array */
571 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000572 } else {
David Edmondson91316cb2021-02-16 14:27:18 +0000573 trace_pflash_write(pfl->name, "leaving query mode");
balrog05ee37e2007-11-17 11:50:55 +0000574 }
575 break;
576 default:
577 goto error_flash;
578 }
Stefan Weil12dabc72012-09-01 13:00:48 +0200579 break;
balrog05ee37e2007-11-17 11:50:55 +0000580 case 2:
581 switch (pfl->cmd) {
582 case 0xe8: /* Block write */
Markus Armbruster4dbda932019-03-08 10:45:58 +0100583 /* FIXME check @offset, @width */
Jordan Justende8efe82012-02-21 23:18:49 -0800584 if (!pfl->ro) {
Markus Armbruster4dbda932019-03-08 10:45:58 +0100585 /*
586 * FIXME writing straight to memory is *wrong*. We
587 * should write to a buffer, and flush it to memory
588 * only on confirm command (see below).
589 */
Jordan Justende8efe82012-02-21 23:18:49 -0800590 pflash_data_write(pfl, offset, value, width, be);
591 } else {
592 pfl->status |= 0x10; /* Programming error */
593 }
balrog05ee37e2007-11-17 11:50:55 +0000594
595 pfl->status |= 0x80;
596
597 if (!pfl->counter) {
Avi Kivitya8170e52012-10-23 12:30:10 +0200598 hwaddr mask = pfl->writeblock_size - 1;
Edgar E. Iglesiasb4bf0a92010-01-24 20:38:29 +0100599 mask = ~mask;
600
David Edmondson91316cb2021-02-16 14:27:18 +0000601 trace_pflash_write(pfl->name, "block write finished");
balrog05ee37e2007-11-17 11:50:55 +0000602 pfl->wcycle++;
Jordan Justende8efe82012-02-21 23:18:49 -0800603 if (!pfl->ro) {
604 /* Flush the entire write buffer onto backing storage. */
Markus Armbruster4dbda932019-03-08 10:45:58 +0100605 /* FIXME premature! */
Jordan Justende8efe82012-02-21 23:18:49 -0800606 pflash_update(pfl, offset & mask, pfl->writeblock_size);
607 } else {
608 pfl->status |= 0x10; /* Programming error */
609 }
balrog05ee37e2007-11-17 11:50:55 +0000610 }
611
612 pfl->counter--;
613 break;
balrog7317b8c2007-11-18 02:09:36 +0000614 default:
615 goto error_flash;
balrog05ee37e2007-11-17 11:50:55 +0000616 }
Stefan Weil12dabc72012-09-01 13:00:48 +0200617 break;
balrog05ee37e2007-11-17 11:50:55 +0000618 case 3: /* Confirm mode */
619 switch (pfl->cmd) {
620 case 0xe8: /* Block write */
621 if (cmd == 0xd0) {
Markus Armbruster4dbda932019-03-08 10:45:58 +0100622 /* FIXME this is where we should write out the buffer */
balrog05ee37e2007-11-17 11:50:55 +0000623 pfl->wcycle = 0;
624 pfl->status |= 0x80;
balrog05ee37e2007-11-17 11:50:55 +0000625 } else {
Markus Armbruster2d93beb2019-03-08 10:45:57 +0100626 qemu_log_mask(LOG_UNIMP,
627 "%s: Aborting write to buffer not implemented,"
628 " the data is already written to storage!\n"
629 "Flash device reset into READ mode.\n",
630 __func__);
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200631 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000632 }
balrog7317b8c2007-11-18 02:09:36 +0000633 break;
634 default:
635 goto error_flash;
balrog05ee37e2007-11-17 11:50:55 +0000636 }
Stefan Weil12dabc72012-09-01 13:00:48 +0200637 break;
balrog05ee37e2007-11-17 11:50:55 +0000638 default:
639 /* Should never happen */
David Edmondson91316cb2021-02-16 14:27:18 +0000640 trace_pflash_write(pfl->name, "invalid write state");
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200641 goto mode_read_array;
balrog05ee37e2007-11-17 11:50:55 +0000642 }
643 return;
644
645 error_flash:
Peter Crosthwaited96fc512012-12-04 16:04:33 +1000646 qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence "
Philippe Mathieu-Daudé883f2c52023-01-10 22:29:47 +0100647 "(offset " HWADDR_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)"
Peter Crosthwaited96fc512012-12-04 16:04:33 +1000648 "\n", __func__, offset, pfl->wcycle, pfl->cmd, value);
balrog05ee37e2007-11-17 11:50:55 +0000649
Philippe Mathieu-Daudé30721822019-07-16 19:11:57 +0200650 mode_read_array:
David Edmondson91316cb2021-02-16 14:27:18 +0000651 trace_pflash_mode_read_array(pfl->name);
Jan Kiszka5f9a5ea2013-05-07 19:04:25 +0200652 memory_region_rom_device_set_romd(&pfl->mem, true);
balrog05ee37e2007-11-17 11:50:55 +0000653 pfl->wcycle = 0;
Philippe Mathieu-Daudéaba53a12019-07-16 19:06:56 +0200654 pfl->cmd = 0x00; /* This model reset value for READ_ARRAY (not CFI) */
balrog05ee37e2007-11-17 11:50:55 +0000655}
656
657
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200658static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value,
659 unsigned len, MemTxAttrs attrs)
balrog05ee37e2007-11-17 11:50:55 +0000660{
Markus Armbruster16434062019-03-08 10:45:56 +0100661 PFlashCFI01 *pfl = opaque;
Paolo Bonzini5aa113f2015-04-08 14:00:53 +0200662 bool be = !!(pfl->features & (1 << PFLASH_BE));
balrog05ee37e2007-11-17 11:50:55 +0000663
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200664 if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
665 *value = pflash_data_read(opaque, addr, len, be);
666 } else {
667 *value = pflash_read(opaque, addr, len, be);
668 }
669 return MEMTX_OK;
balrog05ee37e2007-11-17 11:50:55 +0000670}
671
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200672static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value,
673 unsigned len, MemTxAttrs attrs)
balrog05ee37e2007-11-17 11:50:55 +0000674{
Markus Armbruster16434062019-03-08 10:45:56 +0100675 PFlashCFI01 *pfl = opaque;
Paolo Bonzini5aa113f2015-04-08 14:00:53 +0200676 bool be = !!(pfl->features & (1 << PFLASH_BE));
balrog05ee37e2007-11-17 11:50:55 +0000677
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200678 if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) {
679 return MEMTX_ERROR;
680 } else {
681 pflash_write(opaque, addr, value, len, be);
682 return MEMTX_OK;
683 }
balrog05ee37e2007-11-17 11:50:55 +0000684}
685
Paolo Bonzini5aa113f2015-04-08 14:00:53 +0200686static const MemoryRegionOps pflash_cfi01_ops = {
Paolo Bonzinif71e42a2015-04-08 14:09:43 +0200687 .read_with_attrs = pflash_mem_read_with_attrs,
688 .write_with_attrs = pflash_mem_write_with_attrs,
Avi Kivitycfe5f012011-08-04 15:55:30 +0300689 .endianness = DEVICE_NATIVE_ENDIAN,
balrog05ee37e2007-11-17 11:50:55 +0000690};
691
Daniel Henrique Barbozaef7716c2022-11-08 15:00:32 +0100692static void pflash_cfi01_fill_cfi_table(PFlashCFI01 *pfl)
balrog05ee37e2007-11-17 11:50:55 +0000693{
Peter Maydellfeb0b1a2017-01-27 15:20:22 +0000694 uint64_t blocks_per_device, sector_len_per_device, device_len;
Peter Maydella0289b82014-06-19 18:06:25 +0100695 int num_devices;
balrog05ee37e2007-11-17 11:50:55 +0000696
Philippe Mathieu-Daudéccd80142021-03-09 16:24:50 +0100697 /*
698 * These are only used to expose the parameters of each device
Peter Maydella0289b82014-06-19 18:06:25 +0100699 * in the cfi_table[].
700 */
701 num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1;
Peter Maydellfeb0b1a2017-01-27 15:20:22 +0000702 if (pfl->old_multiple_chip_handling) {
703 blocks_per_device = pfl->nb_blocs / num_devices;
704 sector_len_per_device = pfl->sector_len;
705 } else {
706 blocks_per_device = pfl->nb_blocs;
707 sector_len_per_device = pfl->sector_len / num_devices;
708 }
709 device_len = sector_len_per_device * blocks_per_device;
Peter Maydella0289b82014-06-19 18:06:25 +0100710
balrog05ee37e2007-11-17 11:50:55 +0000711 /* Hardcoded CFI table */
balrog05ee37e2007-11-17 11:50:55 +0000712 /* Standard "QRY" string */
713 pfl->cfi_table[0x10] = 'Q';
714 pfl->cfi_table[0x11] = 'R';
715 pfl->cfi_table[0x12] = 'Y';
716 /* Command set (Intel) */
717 pfl->cfi_table[0x13] = 0x01;
718 pfl->cfi_table[0x14] = 0x00;
719 /* Primary extended table address (none) */
720 pfl->cfi_table[0x15] = 0x31;
721 pfl->cfi_table[0x16] = 0x00;
722 /* Alternate command set (none) */
723 pfl->cfi_table[0x17] = 0x00;
724 pfl->cfi_table[0x18] = 0x00;
725 /* Alternate extended table (none) */
726 pfl->cfi_table[0x19] = 0x00;
727 pfl->cfi_table[0x1A] = 0x00;
728 /* Vcc min */
729 pfl->cfi_table[0x1B] = 0x45;
730 /* Vcc max */
731 pfl->cfi_table[0x1C] = 0x55;
732 /* Vpp min (no Vpp pin) */
733 pfl->cfi_table[0x1D] = 0x00;
734 /* Vpp max (no Vpp pin) */
735 pfl->cfi_table[0x1E] = 0x00;
736 /* Reserved */
737 pfl->cfi_table[0x1F] = 0x07;
738 /* Timeout for min size buffer write */
739 pfl->cfi_table[0x20] = 0x07;
740 /* Typical timeout for block erase */
741 pfl->cfi_table[0x21] = 0x0a;
742 /* Typical timeout for full chip erase (4096 ms) */
743 pfl->cfi_table[0x22] = 0x00;
744 /* Reserved */
745 pfl->cfi_table[0x23] = 0x04;
746 /* Max timeout for buffer write */
747 pfl->cfi_table[0x24] = 0x04;
748 /* Max timeout for block erase */
749 pfl->cfi_table[0x25] = 0x04;
750 /* Max timeout for chip erase */
751 pfl->cfi_table[0x26] = 0x00;
752 /* Device size */
Peter Maydella0289b82014-06-19 18:06:25 +0100753 pfl->cfi_table[0x27] = ctz32(device_len); /* + 1; */
balrog05ee37e2007-11-17 11:50:55 +0000754 /* Flash device interface (8 & 16 bits) */
755 pfl->cfi_table[0x28] = 0x02;
756 pfl->cfi_table[0x29] = 0x00;
757 /* Max number of bytes in multi-bytes write */
Roy Franz4b6fedc2013-12-17 19:42:26 +0000758 if (pfl->bank_width == 1) {
Edgar E. Iglesias4737fa22010-01-24 18:39:51 +0100759 pfl->cfi_table[0x2A] = 0x08;
760 } else {
761 pfl->cfi_table[0x2A] = 0x0B;
762 }
Edgar E. Iglesiasb4bf0a92010-01-24 20:38:29 +0100763 pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
Peter Maydellfeb0b1a2017-01-27 15:20:22 +0000764 if (!pfl->old_multiple_chip_handling && num_devices > 1) {
765 pfl->writeblock_size *= num_devices;
766 }
Edgar E. Iglesiasb4bf0a92010-01-24 20:38:29 +0100767
balrog05ee37e2007-11-17 11:50:55 +0000768 pfl->cfi_table[0x2B] = 0x00;
769 /* Number of erase block regions (uniform) */
770 pfl->cfi_table[0x2C] = 0x01;
771 /* Erase block region 1 */
Peter Maydella0289b82014-06-19 18:06:25 +0100772 pfl->cfi_table[0x2D] = blocks_per_device - 1;
773 pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8;
Peter Maydellfeb0b1a2017-01-27 15:20:22 +0000774 pfl->cfi_table[0x2F] = sector_len_per_device >> 8;
775 pfl->cfi_table[0x30] = sector_len_per_device >> 16;
balrog05ee37e2007-11-17 11:50:55 +0000776
777 /* Extended */
778 pfl->cfi_table[0x31] = 'P';
779 pfl->cfi_table[0x32] = 'R';
780 pfl->cfi_table[0x33] = 'I';
781
782 pfl->cfi_table[0x34] = '1';
Aurelien Jarno262e1ea2012-09-03 22:47:03 +0200783 pfl->cfi_table[0x35] = '0';
balrog05ee37e2007-11-17 11:50:55 +0000784
785 pfl->cfi_table[0x36] = 0x00;
786 pfl->cfi_table[0x37] = 0x00;
787 pfl->cfi_table[0x38] = 0x00;
788 pfl->cfi_table[0x39] = 0x00;
789
790 pfl->cfi_table[0x3a] = 0x00;
791
792 pfl->cfi_table[0x3b] = 0x00;
793 pfl->cfi_table[0x3c] = 0x00;
794
Aurelien Jarno262e1ea2012-09-03 22:47:03 +0200795 pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000796}
797
Philippe Mathieu-Daudéa42cd112021-03-10 00:15:15 +0100798static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
799{
800 ERRP_GUARD();
801 PFlashCFI01 *pfl = PFLASH_CFI01(dev);
802 uint64_t total_len;
803 int ret;
804
805 if (pfl->sector_len == 0) {
806 error_setg(errp, "attribute \"sector-length\" not specified or zero.");
807 return;
808 }
809 if (pfl->nb_blocs == 0) {
810 error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
811 return;
812 }
813 if (pfl->name == NULL) {
814 error_setg(errp, "attribute \"name\" not specified.");
815 return;
816 }
817
818 total_len = pfl->sector_len * pfl->nb_blocs;
819
820 memory_region_init_rom_device(
821 &pfl->mem, OBJECT(dev),
822 &pflash_cfi01_ops,
823 pfl,
824 pfl->name, total_len, errp);
825 if (*errp) {
826 return;
827 }
828
829 pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
830 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
831
832 if (pfl->blk) {
833 uint64_t perm;
834 pfl->ro = !blk_supports_write_perm(pfl->blk);
835 perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
836 ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
837 if (ret < 0) {
838 return;
839 }
840 } else {
David Edmondson2231bee2021-02-16 14:27:19 +0000841 pfl->ro = false;
Philippe Mathieu-Daudéa42cd112021-03-10 00:15:15 +0100842 }
843
844 if (pfl->blk) {
845 if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, total_len,
846 errp)) {
847 vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
848 return;
849 }
850 }
851
852 /*
853 * Default to devices being used at their maximum device width. This was
854 * assumed before the device_width support was added.
855 */
856 if (!pfl->max_device_width) {
857 pfl->max_device_width = pfl->device_width;
858 }
859
860 pfl->wcycle = 0;
861 /*
862 * The command 0x00 is not assigned by the CFI open standard,
863 * but QEMU historically uses it for the READ_ARRAY command (0xff).
864 */
865 pfl->cmd = 0x00;
866 pfl->status = 0x80; /* WSM ready */
Daniel Henrique Barbozaef7716c2022-11-08 15:00:32 +0100867 pflash_cfi01_fill_cfi_table(pfl);
Philippe Mathieu-Daudéa42cd112021-03-10 00:15:15 +0100868}
869
Philippe Mathieu-Daudé3a283502019-07-02 00:38:38 +0200870static void pflash_cfi01_system_reset(DeviceState *dev)
871{
872 PFlashCFI01 *pfl = PFLASH_CFI01(dev);
873
David Edmondson91316cb2021-02-16 14:27:18 +0000874 trace_pflash_reset(pfl->name);
Philippe Mathieu-Daudé3a283502019-07-02 00:38:38 +0200875 /*
876 * The command 0x00 is not assigned by the CFI open standard,
877 * but QEMU historically uses it for the READ_ARRAY command (0xff).
878 */
879 pfl->cmd = 0x00;
880 pfl->wcycle = 0;
881 memory_region_rom_device_set_romd(&pfl->mem, true);
882 /*
883 * The WSM ready timer occurs at most 150ns after system reset.
884 * This model deliberately ignores this delay.
885 */
886 pfl->status = 0x80;
887}
888
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000889static Property pflash_cfi01_properties[] = {
Markus Armbruster16434062019-03-08 10:45:56 +0100890 DEFINE_PROP_DRIVE("drive", PFlashCFI01, blk),
Peter Maydella0289b82014-06-19 18:06:25 +0100891 /* num-blocks is the number of blocks actually visible to the guest,
892 * ie the total size of the device divided by the sector length.
893 * If we're emulating flash devices wired in parallel the actual
Michael Tokarev9b4b4e52023-07-14 14:32:24 +0300894 * number of blocks per individual device will differ.
Peter Maydella0289b82014-06-19 18:06:25 +0100895 */
Markus Armbruster16434062019-03-08 10:45:56 +0100896 DEFINE_PROP_UINT32("num-blocks", PFlashCFI01, nb_blocs, 0),
897 DEFINE_PROP_UINT64("sector-length", PFlashCFI01, sector_len, 0),
Roy Franzfa21a7b2013-12-17 19:42:27 +0000898 /* width here is the overall width of this QEMU device in bytes.
899 * The QEMU device may be emulating a number of flash devices
900 * wired up in parallel; the width of each individual flash
901 * device should be specified via device-width. If the individual
902 * devices have a maximum width which is greater than the width
903 * they are being used for, this maximum width should be set via
904 * max-device-width (which otherwise defaults to device-width).
905 * So for instance a 32-bit wide QEMU flash device made from four
906 * 16-bit flash devices used in 8-bit wide mode would be configured
907 * with width = 4, device-width = 1, max-device-width = 2.
908 *
909 * If device-width is not specified we default to backwards
910 * compatible behaviour which is a bad emulation of two
911 * 16 bit devices making up a 32 bit wide QEMU device. This
912 * is deprecated for new uses of this device.
913 */
Markus Armbruster16434062019-03-08 10:45:56 +0100914 DEFINE_PROP_UINT8("width", PFlashCFI01, bank_width, 0),
915 DEFINE_PROP_UINT8("device-width", PFlashCFI01, device_width, 0),
916 DEFINE_PROP_UINT8("max-device-width", PFlashCFI01, max_device_width, 0),
917 DEFINE_PROP_BIT("big-endian", PFlashCFI01, features, PFLASH_BE, 0),
918 DEFINE_PROP_BIT("secure", PFlashCFI01, features, PFLASH_SECURE, 0),
919 DEFINE_PROP_UINT16("id0", PFlashCFI01, ident0, 0),
920 DEFINE_PROP_UINT16("id1", PFlashCFI01, ident1, 0),
921 DEFINE_PROP_UINT16("id2", PFlashCFI01, ident2, 0),
922 DEFINE_PROP_UINT16("id3", PFlashCFI01, ident3, 0),
923 DEFINE_PROP_STRING("name", PFlashCFI01, name),
924 DEFINE_PROP_BOOL("old-multiple-chip-handling", PFlashCFI01,
Peter Maydellfeb0b1a2017-01-27 15:20:22 +0000925 old_multiple_chip_handling, false),
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000926 DEFINE_PROP_END_OF_LIST(),
927};
928
929static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
930{
931 DeviceClass *dc = DEVICE_CLASS(klass);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000932
Philippe Mathieu-Daudé3a283502019-07-02 00:38:38 +0200933 dc->reset = pflash_cfi01_system_reset;
Hu Taoe40b5f32013-07-01 18:18:27 +0800934 dc->realize = pflash_cfi01_realize;
Marc-André Lureau4f67d302020-01-10 19:30:32 +0400935 device_class_set_props(dc, pflash_cfi01_properties);
Peter Maydelld8d24fb2013-04-05 16:18:00 +0100936 dc->vmsd = &vmstate_pflash;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300937 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000938}
939
940
941static const TypeInfo pflash_cfi01_info = {
Markus Armbrustere7b62742019-03-08 10:45:59 +0100942 .name = TYPE_PFLASH_CFI01,
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000943 .parent = TYPE_SYS_BUS_DEVICE,
Markus Armbruster16434062019-03-08 10:45:56 +0100944 .instance_size = sizeof(PFlashCFI01),
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000945 .class_init = pflash_cfi01_class_init,
946};
947
948static void pflash_cfi01_register_types(void)
949{
950 type_register_static(&pflash_cfi01_info);
951}
952
953type_init(pflash_cfi01_register_types)
954
Markus Armbruster16434062019-03-08 10:45:56 +0100955PFlashCFI01 *pflash_cfi01_register(hwaddr base,
Markus Armbruster940d5b12019-03-08 10:46:09 +0100956 const char *name,
Markus Armbruster16434062019-03-08 10:45:56 +0100957 hwaddr size,
958 BlockBackend *blk,
Markus Armbrusterce147102019-03-08 10:46:10 +0100959 uint32_t sector_len,
Markus Armbruster16434062019-03-08 10:45:56 +0100960 int bank_width,
961 uint16_t id0, uint16_t id1,
962 uint16_t id2, uint16_t id3,
963 int be)
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000964{
Markus Armbruster3e80f692020-06-10 07:31:58 +0200965 DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000966
Markus Armbruster9b3d1112015-03-09 19:17:26 +0100967 if (blk) {
Markus Armbruster934df912020-06-22 11:42:24 +0200968 qdev_prop_set_drive(dev, "drive", blk);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000969 }
Philippe Mathieu-Daudé4cdd0a72020-05-11 22:52:46 +0200970 assert(QEMU_IS_ALIGNED(size, sector_len));
Markus Armbrusterce147102019-03-08 10:46:10 +0100971 qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000972 qdev_prop_set_uint64(dev, "sector-length", sector_len);
Roy Franz4b6fedc2013-12-17 19:42:26 +0000973 qdev_prop_set_uint8(dev, "width", bank_width);
Paolo Bonzinie9809422015-04-08 13:53:29 +0200974 qdev_prop_set_bit(dev, "big-endian", !!be);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000975 qdev_prop_set_uint16(dev, "id0", id0);
976 qdev_prop_set_uint16(dev, "id1", id1);
977 qdev_prop_set_uint16(dev, "id2", id2);
978 qdev_prop_set_uint16(dev, "id3", id3);
979 qdev_prop_set_string(dev, "name", name);
Markus Armbruster3c6ef472020-06-10 07:32:34 +0200980 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
Peter Crosthwaite368a3542012-10-30 07:45:11 +0000981
Hu Taof1b44f02013-07-01 18:18:26 +0800982 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
Markus Armbrustere7b62742019-03-08 10:45:59 +0100983 return PFLASH_CFI01(dev);
balrog05ee37e2007-11-17 11:50:55 +0000984}
Avi Kivitycfe5f012011-08-04 15:55:30 +0300985
Philippe Mathieu-Daudée60cf762019-03-08 14:14:41 +0100986BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl)
987{
988 return fl->blk;
989}
990
Markus Armbruster16434062019-03-08 10:45:56 +0100991MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl)
Avi Kivitycfe5f012011-08-04 15:55:30 +0300992{
993 return &fl->mem;
994}
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +0200995
Markus Armbruster2d731db2019-05-07 12:55:02 +0100996/*
997 * Handle -drive if=pflash for machines that use properties.
998 * If @dinfo is null, do nothing.
999 * Else if @fl's property "drive" is already set, fatal error.
1000 * Else set it to the BlockBackend with @dinfo.
1001 */
1002void pflash_cfi01_legacy_drive(PFlashCFI01 *fl, DriveInfo *dinfo)
1003{
1004 Location loc;
1005
1006 if (!dinfo) {
1007 return;
1008 }
1009
1010 loc_push_none(&loc);
1011 qemu_opts_loc_restore(dinfo->opts);
1012 if (fl->blk) {
1013 error_report("clashes with -machine");
1014 exit(1);
1015 }
Markus Armbruster934df912020-06-22 11:42:24 +02001016 qdev_prop_set_drive_err(DEVICE(fl), "drive", blk_by_legacy_dinfo(dinfo),
1017 &error_fatal);
Markus Armbruster2d731db2019-05-07 12:55:02 +01001018 loc_pop(&loc);
1019}
1020
Philippe Mathieu-Daudé538f0492021-01-11 16:20:20 +01001021static void postload_update_cb(void *opaque, bool running, RunState state)
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +01001022{
Markus Armbruster16434062019-03-08 10:45:56 +01001023 PFlashCFI01 *pfl = opaque;
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +01001024
Emanuele Giuseppe Esposito3b717192022-02-09 05:54:51 -05001025 /* This is called after bdrv_activate_all. */
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +01001026 qemu_del_vm_change_state_handler(pfl->vmstate);
1027 pfl->vmstate = NULL;
1028
David Edmondson91316cb2021-02-16 14:27:18 +00001029 trace_pflash_postload_cb(pfl->name);
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +01001030 pflash_update(pfl, 0, pfl->sector_len * pfl->nb_blocs);
1031}
1032
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +02001033static int pflash_post_load(void *opaque, int version_id)
1034{
Markus Armbruster16434062019-03-08 10:45:56 +01001035 PFlashCFI01 *pfl = opaque;
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +02001036
1037 if (!pfl->ro) {
Dr. David Alan Gilbert90c647d2016-04-15 12:41:30 +01001038 pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
1039 pfl);
Laszlo Ersek4c0cfc72014-08-23 12:19:07 +02001040 }
1041 return 0;
1042}