blob: 899c86f34c5c01f9ea5183946197ae13bc77e731 [file] [log] [blame]
hailfingera9df33c2009-05-09 00:54:55 +00001/*
2 * This file is part of the flashrom project.
3 *
hailfinger6ead7222010-11-01 22:07:04 +00004 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
hailfingera9df33c2009-05-09 00:54:55 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
hailfinger6ead7222010-11-01 22:07:04 +00008 * the Free Software Foundation; version 2 of the License.
hailfingera9df33c2009-05-09 00:54:55 +00009 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
hailfingera9df33c2009-05-09 00:54:55 +000015 */
16
David Hendricks84377002014-09-09 16:09:31 -070017#include <errno.h>
hailfingera9df33c2009-05-09 00:54:55 +000018#include <string.h>
19#include <stdlib.h>
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -070020#include <stdio.h>
21#include <ctype.h>
Patrick Georgi4befc162017-02-03 18:32:01 +010022#include <inttypes.h>
hailfingera9df33c2009-05-09 00:54:55 +000023#include "flash.h"
hailfingera8727712010-06-20 10:58:32 +000024#include "chipdrivers.h"
hailfinger428f6852010-07-27 22:41:39 +000025#include "programmer.h"
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080026#include "flashchips.h"
hailfingera9df33c2009-05-09 00:54:55 +000027
hailfinger6ead7222010-11-01 22:07:04 +000028/* Remove the #define below if you don't want SPI flash chip emulation. */
29#define EMULATE_SPI_CHIP 1
30
31#if EMULATE_SPI_CHIP
32#define EMULATE_CHIP 1
33#include "spi.h"
34#endif
35
36#if EMULATE_CHIP
37#include <sys/types.h>
38#include <sys/stat.h>
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080039
40#if EMULATE_SPI_CHIP
41/* The name of variable-size virtual chip. A 4MB flash example:
42 * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
43 */
44#define VARIABLE_SIZE_CHIP_NAME "VARIABLE_SIZE"
Edward O'Callaghanef4e28b2019-06-28 13:18:41 +100045static unsigned char spi_blacklist[256];
46static unsigned char spi_ignorelist[256];
47static int spi_blacklist_size = 0;
48static int spi_ignorelist_size = 0;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080049#endif
hailfinger6ead7222010-11-01 22:07:04 +000050#endif
51
52#if EMULATE_CHIP
53static uint8_t *flashchip_contents = NULL;
54enum emu_chip {
55 EMULATE_NONE,
56 EMULATE_ST_M25P10_RES,
57 EMULATE_SST_SST25VF040_REMS,
58 EMULATE_SST_SST25VF032B,
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080059 EMULATE_VARIABLE_SIZE,
hailfinger6ead7222010-11-01 22:07:04 +000060};
61static enum emu_chip emu_chip = EMULATE_NONE;
62static char *emu_persistent_image = NULL;
stefanctc5eb8a92011-11-23 09:13:48 +000063static unsigned int emu_chip_size = 0;
Simon Glasscf253a72013-07-10 21:10:11 -070064static int emu_modified; /* is the image modified since reading it? */
David Hendricks0eda2a82014-09-12 16:32:05 -070065static int erase_to_zero;
hailfinger6ead7222010-11-01 22:07:04 +000066#if EMULATE_SPI_CHIP
stefanctc5eb8a92011-11-23 09:13:48 +000067static unsigned int emu_max_byteprogram_size = 0;
68static unsigned int emu_max_aai_size = 0;
69static unsigned int emu_jedec_se_size = 0;
70static unsigned int emu_jedec_be_52_size = 0;
71static unsigned int emu_jedec_be_d8_size = 0;
72static unsigned int emu_jedec_ce_60_size = 0;
73static unsigned int emu_jedec_ce_c7_size = 0;
hailfinger6ead7222010-11-01 22:07:04 +000074#endif
75#endif
76
stefanctc5eb8a92011-11-23 09:13:48 +000077static unsigned int spi_write_256_chunksize = 256;
hailfinger6ead7222010-11-01 22:07:04 +000078
David Hendricks84377002014-09-09 16:09:31 -070079/* If "freq" parameter is passed in from command line, commands will delay
80 * for this period before returning. */
81static unsigned long int delay_us = 0;
82
Souvik Ghoshd75cd672016-06-17 14:21:39 -070083static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
Stuart langleyc98e43f2020-03-26 20:27:36 +110084 const unsigned char *writearr, unsigned char *readarr);
Patrick Georgiab8353e2017-02-03 18:32:01 +010085static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf,
stefanctc5eb8a92011-11-23 09:13:48 +000086 unsigned int start, unsigned int len);
Stuart langleyc98e43f2020-03-26 20:27:36 +110087static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
88static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
89static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
90static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len);
91static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr);
92static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr);
93static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr);
94static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
mkarcherd264e9e2011-05-11 17:07:07 +000095
Patrick Georgif4f1e2f2017-03-10 17:38:40 +010096static const struct spi_master spi_master_dummyflasher = {
uwe8d342eb2011-07-28 08:13:25 +000097 .type = SPI_CONTROLLER_DUMMY,
Edward O'Callaghana6673bd2019-06-24 15:22:28 +100098 .features = SPI_MASTER_4BA,
uwe8d342eb2011-07-28 08:13:25 +000099 .max_data_read = MAX_DATA_READ_UNLIMITED,
100 .max_data_write = MAX_DATA_UNSPECIFIED,
101 .command = dummy_spi_send_command,
102 .multicommand = default_spi_send_multicommand,
103 .read = default_spi_read,
104 .write_256 = dummy_spi_write_256,
mkarcherd264e9e2011-05-11 17:07:07 +0000105};
dhendrix0ffc2eb2011-06-14 01:35:36 +0000106
Patrick Georgi0a9533a2017-02-03 19:28:38 +0100107static const struct par_master par_master_dummy = {
hailfinger76bb7e92011-11-09 23:40:00 +0000108 .chip_readb = dummy_chip_readb,
109 .chip_readw = dummy_chip_readw,
110 .chip_readl = dummy_chip_readl,
111 .chip_readn = dummy_chip_readn,
112 .chip_writeb = dummy_chip_writeb,
113 .chip_writew = dummy_chip_writew,
114 .chip_writel = dummy_chip_writel,
115 .chip_writen = dummy_chip_writen,
116};
117
Edward O'Callaghanef4e28b2019-06-28 13:18:41 +1000118static enum chipbustype dummy_buses_supported = BUS_NONE;
hailfinger76bb7e92011-11-09 23:40:00 +0000119
David Hendricks93784b42016-08-09 17:00:38 -0700120static int dummy_shutdown(void *data)
dhendrix0ffc2eb2011-06-14 01:35:36 +0000121{
122 msg_pspew("%s\n", __func__);
123#if EMULATE_CHIP
124 if (emu_chip != EMULATE_NONE) {
Simon Glasscf253a72013-07-10 21:10:11 -0700125 if (emu_persistent_image && emu_modified) {
dhendrix0ffc2eb2011-06-14 01:35:36 +0000126 msg_pdbg("Writing %s\n", emu_persistent_image);
127 write_buf_to_file(flashchip_contents, emu_chip_size,
128 emu_persistent_image);
129 }
130 free(flashchip_contents);
131 }
132#endif
133 return 0;
134}
135
Simon Glassd2c64a22013-07-03 22:05:21 +0900136/* Values for the 'size' parameter */
137enum {
138 SIZE_UNKNOWN = -1,
139 SIZE_AUTO = -2,
140};
141
David Hendricksac1d25c2016-08-09 17:00:58 -0700142int dummy_init(void)
hailfingera9df33c2009-05-09 00:54:55 +0000143{
hailfinger1ef766d2010-07-06 09:55:48 +0000144 char *bustext = NULL;
hailfinger6ead7222010-11-01 22:07:04 +0000145 char *tmp = NULL;
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700146 int i;
hailfinger6ead7222010-11-01 22:07:04 +0000147#if EMULATE_CHIP
148 struct stat image_stat;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800149#if EMULATE_SPI_CHIP
Simon Glassd2c64a22013-07-03 22:05:21 +0900150 int size = SIZE_UNKNOWN; /* size for generic chip */
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800151#endif
hailfinger6ead7222010-11-01 22:07:04 +0000152#endif
Simon Glassd2c64a22013-07-03 22:05:21 +0900153 int image_size = SIZE_UNKNOWN;
hailfinger1ef766d2010-07-06 09:55:48 +0000154
hailfinger50c335f2010-01-09 04:32:23 +0000155 msg_pspew("%s\n", __func__);
hailfinger668f3502009-06-01 00:02:11 +0000156
hailfingerddeb4ac2010-07-08 10:13:37 +0000157 bustext = extract_programmer_param("bus");
hailfinger1ef766d2010-07-06 09:55:48 +0000158 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
159 if (!bustext)
160 bustext = strdup("parallel+lpc+fwh+spi");
hailfinger668f3502009-06-01 00:02:11 +0000161 /* Convert the parameters to lowercase. */
hailfinger1ef766d2010-07-06 09:55:48 +0000162 tolower_string(bustext);
hailfinger668f3502009-06-01 00:02:11 +0000163
hailfinger76bb7e92011-11-09 23:40:00 +0000164 dummy_buses_supported = BUS_NONE;
hailfinger1ef766d2010-07-06 09:55:48 +0000165 if (strstr(bustext, "parallel")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000166 dummy_buses_supported |= BUS_PARALLEL;
hailfinger50c335f2010-01-09 04:32:23 +0000167 msg_pdbg("Enabling support for %s flash.\n", "parallel");
hailfinger668f3502009-06-01 00:02:11 +0000168 }
hailfinger1ef766d2010-07-06 09:55:48 +0000169 if (strstr(bustext, "lpc")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000170 dummy_buses_supported |= BUS_LPC;
hailfinger50c335f2010-01-09 04:32:23 +0000171 msg_pdbg("Enabling support for %s flash.\n", "LPC");
hailfinger668f3502009-06-01 00:02:11 +0000172 }
hailfinger1ef766d2010-07-06 09:55:48 +0000173 if (strstr(bustext, "fwh")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000174 dummy_buses_supported |= BUS_FWH;
hailfinger50c335f2010-01-09 04:32:23 +0000175 msg_pdbg("Enabling support for %s flash.\n", "FWH");
hailfinger668f3502009-06-01 00:02:11 +0000176 }
hailfinger1ef766d2010-07-06 09:55:48 +0000177 if (strstr(bustext, "spi")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000178 dummy_buses_supported |= BUS_SPI;
hailfinger50c335f2010-01-09 04:32:23 +0000179 msg_pdbg("Enabling support for %s flash.\n", "SPI");
hailfinger668f3502009-06-01 00:02:11 +0000180 }
hailfinger76bb7e92011-11-09 23:40:00 +0000181 if (dummy_buses_supported == BUS_NONE)
hailfinger50c335f2010-01-09 04:32:23 +0000182 msg_pdbg("Support for all flash bus types disabled.\n");
hailfinger1ef766d2010-07-06 09:55:48 +0000183 free(bustext);
hailfinger6ead7222010-11-01 22:07:04 +0000184
185 tmp = extract_programmer_param("spi_write_256_chunksize");
186 if (tmp) {
187 spi_write_256_chunksize = atoi(tmp);
188 free(tmp);
189 if (spi_write_256_chunksize < 1) {
190 msg_perr("invalid spi_write_256_chunksize\n");
191 return 1;
192 }
193 }
194
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700195 tmp = extract_programmer_param("spi_blacklist");
196 if (tmp) {
197 i = strlen(tmp);
198 if (!strncmp(tmp, "0x", 2)) {
199 i -= 2;
200 memmove(tmp, tmp + 2, i + 1);
201 }
202 if ((i > 512) || (i % 2)) {
203 msg_perr("Invalid SPI command blacklist length\n");
204 free(tmp);
205 return 1;
206 }
207 spi_blacklist_size = i / 2;
208 for (i = 0; i < spi_blacklist_size * 2; i++) {
209 if (!isxdigit((unsigned char)tmp[i])) {
210 msg_perr("Invalid char \"%c\" in SPI command "
211 "blacklist\n", tmp[i]);
212 free(tmp);
213 return 1;
214 }
215 }
216 for (i = 0; i < spi_blacklist_size; i++) {
217 unsigned int tmp2;
218 /* SCNx8 is apparently not supported by MSVC (and thus
219 * MinGW), so work around it with an extra variable
220 */
221 sscanf(tmp + i * 2, "%2x", &tmp2);
222 spi_blacklist[i] = (uint8_t)tmp2;
223 }
224 msg_pdbg("SPI blacklist is ");
225 for (i = 0; i < spi_blacklist_size; i++)
226 msg_pdbg("%02x ", spi_blacklist[i]);
Stuart langleyc98e43f2020-03-26 20:27:36 +1100227 msg_pdbg(", size %u\n", spi_blacklist_size);
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700228 }
229 free(tmp);
230
231 tmp = extract_programmer_param("spi_ignorelist");
232 if (tmp) {
233 i = strlen(tmp);
234 if (!strncmp(tmp, "0x", 2)) {
235 i -= 2;
236 memmove(tmp, tmp + 2, i + 1);
237 }
238 if ((i > 512) || (i % 2)) {
239 msg_perr("Invalid SPI command ignorelist length\n");
240 free(tmp);
241 return 1;
242 }
243 spi_ignorelist_size = i / 2;
244 for (i = 0; i < spi_ignorelist_size * 2; i++) {
245 if (!isxdigit((unsigned char)tmp[i])) {
246 msg_perr("Invalid char \"%c\" in SPI command "
247 "ignorelist\n", tmp[i]);
248 free(tmp);
249 return 1;
250 }
251 }
252 for (i = 0; i < spi_ignorelist_size; i++) {
253 unsigned int tmp2;
254 /* SCNx8 is apparently not supported by MSVC (and thus
255 * MinGW), so work around it with an extra variable
256 */
257 sscanf(tmp + i * 2, "%2x", &tmp2);
258 spi_ignorelist[i] = (uint8_t)tmp2;
259 }
260 msg_pdbg("SPI ignorelist is ");
261 for (i = 0; i < spi_ignorelist_size; i++)
262 msg_pdbg("%02x ", spi_ignorelist[i]);
Stuart langleyc98e43f2020-03-26 20:27:36 +1100263 msg_pdbg(", size %u\n", spi_ignorelist_size);
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700264 }
265 free(tmp);
266
David Hendricks84377002014-09-09 16:09:31 -0700267 /* frequency to emulate in Hz (default), KHz, or MHz */
268 tmp = extract_programmer_param("freq");
269 if (tmp) {
270 unsigned long int freq;
271 char *units = tmp;
272 char *end = tmp + strlen(tmp);
273
274 errno = 0;
275 freq = strtoul(tmp, &units, 0);
276 if (errno) {
277 msg_perr("Invalid frequency \"%s\", %s\n",
278 tmp, strerror(errno));
279 goto dummy_init_out;
280 }
281
282 if ((units > tmp) && (units < end)) {
283 int units_valid = 0;
284
285 if (units < end - 3) {
286 ;
287 } else if (units == end - 2) {
288 if (!strcasecmp(units, "hz"))
289 units_valid = 1;
290 } else if (units == end - 3) {
291 if (!strcasecmp(units, "khz")) {
292 freq *= 1000;
293 units_valid = 1;
294 } else if (!strcasecmp(units, "mhz")) {
295 freq *= 1000000;
296 units_valid = 1;
297 }
298 }
299
300 if (!units_valid) {
301 msg_perr("Invalid units: %s\n", units);
302 return 1;
303 }
304 }
305
306 /* Assume we only work with bytes and transfer at 1 bit/Hz */
307 delay_us = (1000000 * 8) / freq;
308 }
309
hailfinger6ead7222010-11-01 22:07:04 +0000310#if EMULATE_CHIP
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800311#if EMULATE_SPI_CHIP
312 tmp = extract_programmer_param("size");
313 if (tmp) {
314 int multiplier = 1;
Simon Glassd2c64a22013-07-03 22:05:21 +0900315 if (!strcmp(tmp, "auto"))
316 size = SIZE_AUTO;
317 else if (strlen(tmp)) {
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800318 int remove_last_char = 1;
319 switch (tmp[strlen(tmp) - 1]) {
320 case 'k': case 'K':
321 multiplier = 1024;
322 break;
323 case 'm': case 'M':
324 multiplier = 1024 * 1024;
325 break;
326 default:
327 remove_last_char = 0;
328 break;
329 }
330 if (remove_last_char) tmp[strlen(tmp) - 1] = '\0';
Simon Glassd2c64a22013-07-03 22:05:21 +0900331 size = atoi(tmp) * multiplier;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800332 }
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800333 }
334#endif
335
hailfinger6ead7222010-11-01 22:07:04 +0000336 tmp = extract_programmer_param("emulate");
337 if (!tmp) {
338 msg_pdbg("Not emulating any flash chip.\n");
339 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000340 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000341 }
David Hendricks84377002014-09-09 16:09:31 -0700342
hailfinger6ead7222010-11-01 22:07:04 +0000343#if EMULATE_SPI_CHIP
344 if (!strcmp(tmp, "M25P10.RES")) {
345 emu_chip = EMULATE_ST_M25P10_RES;
346 emu_chip_size = 128 * 1024;
347 emu_max_byteprogram_size = 128;
348 emu_max_aai_size = 0;
349 emu_jedec_se_size = 0;
350 emu_jedec_be_52_size = 0;
351 emu_jedec_be_d8_size = 32 * 1024;
352 emu_jedec_ce_60_size = 0;
353 emu_jedec_ce_c7_size = emu_chip_size;
354 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
355 "write)\n");
356 }
357 if (!strcmp(tmp, "SST25VF040.REMS")) {
358 emu_chip = EMULATE_SST_SST25VF040_REMS;
359 emu_chip_size = 512 * 1024;
360 emu_max_byteprogram_size = 1;
361 emu_max_aai_size = 0;
362 emu_jedec_se_size = 4 * 1024;
363 emu_jedec_be_52_size = 32 * 1024;
364 emu_jedec_be_d8_size = 0;
365 emu_jedec_ce_60_size = emu_chip_size;
366 emu_jedec_ce_c7_size = 0;
367 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
368 "byte write)\n");
369 }
370 if (!strcmp(tmp, "SST25VF032B")) {
371 emu_chip = EMULATE_SST_SST25VF032B;
372 emu_chip_size = 4 * 1024 * 1024;
373 emu_max_byteprogram_size = 1;
374 emu_max_aai_size = 2;
375 emu_jedec_se_size = 4 * 1024;
376 emu_jedec_be_52_size = 32 * 1024;
377 emu_jedec_be_d8_size = 64 * 1024;
378 emu_jedec_ce_60_size = emu_chip_size;
379 emu_jedec_ce_c7_size = emu_chip_size;
380 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
381 "write)\n");
382 }
Simon Glassd2c64a22013-07-03 22:05:21 +0900383 emu_persistent_image = extract_programmer_param("image");
384 if (!stat(emu_persistent_image, &image_stat))
385 image_size = image_stat.st_size;
386
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800387 if (!strncmp(tmp, VARIABLE_SIZE_CHIP_NAME,
388 strlen(VARIABLE_SIZE_CHIP_NAME))) {
Simon Glassd2c64a22013-07-03 22:05:21 +0900389 if (size == SIZE_UNKNOWN) {
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800390 msg_perr("%s: the size parameter is not given.\n",
391 __func__);
392 free(tmp);
393 return 1;
Simon Glassd2c64a22013-07-03 22:05:21 +0900394 } else if (size == SIZE_AUTO) {
395 if (image_size == SIZE_UNKNOWN) {
396 msg_perr("%s: no image so cannot use automatic size.\n",
397 __func__);
398 free(tmp);
399 return 1;
400 }
401 size = image_size;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800402 }
403 emu_chip = EMULATE_VARIABLE_SIZE;
404 emu_chip_size = size;
405 emu_max_byteprogram_size = 256;
406 emu_max_aai_size = 0;
407 emu_jedec_se_size = 4 * 1024;
408 emu_jedec_be_52_size = 32 * 1024;
409 emu_jedec_be_d8_size = 64 * 1024;
410 emu_jedec_ce_60_size = emu_chip_size;
411 emu_jedec_ce_c7_size = emu_chip_size;
412 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
413 emu_chip_size);
414 }
hailfinger6ead7222010-11-01 22:07:04 +0000415#endif
416 if (emu_chip == EMULATE_NONE) {
417 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
418 free(tmp);
419 return 1;
420 }
David Hendricks0eda2a82014-09-12 16:32:05 -0700421
422 /* Should emulated flash erase to zero (yes/no)? */
423 tmp = extract_programmer_param("erase_to_zero");
424 if (tmp) {
425 if (!strcmp(tmp, "yes")) {
426 msg_pdbg("Emulated chip will erase to 0x00\n");
427 erase_to_zero = 1;
428 } else if (!strcmp(tmp, "no")) {
429 msg_pdbg("Emulated chip will erase to 0xff\n");
430 } else {
431 msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
432 return 1;
433 }
434 }
435
hailfinger6ead7222010-11-01 22:07:04 +0000436 free(tmp);
437 flashchip_contents = malloc(emu_chip_size);
438 if (!flashchip_contents) {
439 msg_perr("Out of memory!\n");
440 return 1;
441 }
dhendrix0ffc2eb2011-06-14 01:35:36 +0000442
David Hendricks0eda2a82014-09-12 16:32:05 -0700443 msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
444 erase_to_zero ? 0x00 : 0xff, emu_chip_size);
445 memset(flashchip_contents, erase_to_zero ? 0x00 : 0xff, emu_chip_size);
hailfinger6ead7222010-11-01 22:07:04 +0000446
hailfinger6ead7222010-11-01 22:07:04 +0000447 if (!emu_persistent_image) {
448 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000449 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000450 }
451 if (!stat(emu_persistent_image, &image_stat)) {
452 msg_pdbg("Found persistent image %s, size %li ",
453 emu_persistent_image, (long)image_stat.st_size);
454 if (image_stat.st_size == emu_chip_size) {
455 msg_pdbg("matches.\n");
456 msg_pdbg("Reading %s\n", emu_persistent_image);
457 read_buf_from_file(flashchip_contents, emu_chip_size,
458 emu_persistent_image);
459 } else {
460 msg_pdbg("doesn't match.\n");
461 }
462 }
463#endif
hailfingera9df33c2009-05-09 00:54:55 +0000464
dhendrix0ffc2eb2011-06-14 01:35:36 +0000465dummy_init_out:
466 if (register_shutdown(dummy_shutdown, NULL)) {
hailfinger6ead7222010-11-01 22:07:04 +0000467 free(flashchip_contents);
dhendrix0ffc2eb2011-06-14 01:35:36 +0000468 return 1;
hailfinger6ead7222010-11-01 22:07:04 +0000469 }
hailfinger76bb7e92011-11-09 23:40:00 +0000470 if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
Patrick Georgi0a9533a2017-02-03 19:28:38 +0100471 register_par_master(&par_master_dummy,
Stuart langleyc98e43f2020-03-26 20:27:36 +1100472 dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH));
hailfinger76bb7e92011-11-09 23:40:00 +0000473 if (dummy_buses_supported & BUS_SPI)
Patrick Georgif4f1e2f2017-03-10 17:38:40 +0100474 register_spi_master(&spi_master_dummyflasher);
hailfinger76bb7e92011-11-09 23:40:00 +0000475
hailfingera9df33c2009-05-09 00:54:55 +0000476 return 0;
477}
478
Patrick Georgi4befc162017-02-03 18:32:01 +0100479void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
hailfinger11ae3c42009-05-11 14:13:25 +0000480{
Stuart langleyc98e43f2020-03-26 20:27:36 +1100481 msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
482 __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000483 return (void *)phys_addr;
484}
485
486void dummy_unmap(void *virt_addr, size_t len)
487{
Stuart langleyc98e43f2020-03-26 20:27:36 +1100488 msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000489}
490
Stuart langleyc98e43f2020-03-26 20:27:36 +1100491static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000492{
Kangheui Won4974cc12019-10-18 12:59:01 +1100493 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000494}
495
Stuart langleyc98e43f2020-03-26 20:27:36 +1100496static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000497{
Kangheui Won4974cc12019-10-18 12:59:01 +1100498 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%04x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000499}
500
Stuart langleyc98e43f2020-03-26 20:27:36 +1100501static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000502{
Kangheui Won4974cc12019-10-18 12:59:01 +1100503 msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000504}
505
Stuart langleyc98e43f2020-03-26 20:27:36 +1100506static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
hailfinger9d987ef2009-06-05 18:32:07 +0000507{
508 size_t i;
Stuart langleyc98e43f2020-03-26 20:27:36 +1100509 msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, writing data (hex):", __func__, addr, len);
hailfinger9d987ef2009-06-05 18:32:07 +0000510 for (i = 0; i < len; i++) {
511 if ((i % 16) == 0)
hailfinger50c335f2010-01-09 04:32:23 +0000512 msg_pspew("\n");
513 msg_pspew("%02x ", buf[i]);
hailfinger9d987ef2009-06-05 18:32:07 +0000514 }
515}
516
Stuart langleyc98e43f2020-03-26 20:27:36 +1100517static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000518{
Kangheui Won4974cc12019-10-18 12:59:01 +1100519 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000520 return 0xff;
521}
522
Stuart langleyc98e43f2020-03-26 20:27:36 +1100523static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000524{
Kangheui Won4974cc12019-10-18 12:59:01 +1100525 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000526 return 0xffff;
527}
528
Stuart langleyc98e43f2020-03-26 20:27:36 +1100529static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000530{
Kangheui Won4974cc12019-10-18 12:59:01 +1100531 msg_pspew("%s: addr=0x%" PRIxPTR ", returning 0xffffffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000532 return 0xffffffff;
533}
534
Stuart langleyc98e43f2020-03-26 20:27:36 +1100535static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
hailfinger9d987ef2009-06-05 18:32:07 +0000536{
Stuart langleyc98e43f2020-03-26 20:27:36 +1100537 msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, returning array of 0xff\n", __func__, addr, len);
hailfinger9d987ef2009-06-05 18:32:07 +0000538 memset(buf, 0xff, len);
539 return;
540}
541
hailfinger6ead7222010-11-01 22:07:04 +0000542#if EMULATE_SPI_CHIP
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700543static int emulate_spi_chip_response(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
hailfinger6ead7222010-11-01 22:07:04 +0000544 const unsigned char *writearr, unsigned char *readarr)
545{
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700546 unsigned int offs, i;
stefanctc5eb8a92011-11-23 09:13:48 +0000547 static int unsigned aai_offs;
hailfinger6ead7222010-11-01 22:07:04 +0000548 static int aai_active = 0;
549
550 if (writecnt == 0) {
551 msg_perr("No command sent to the chip!\n");
552 return 1;
553 }
Stefan Tauner718d1eb2016-08-18 18:00:53 -0700554 /* spi_blacklist has precedence over spi_ignorelist. */
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700555 for (i = 0; i < spi_blacklist_size; i++) {
556 if (writearr[0] == spi_blacklist[i]) {
557 msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
558 spi_blacklist[i]);
559 return SPI_INVALID_OPCODE;
560 }
561 }
562 for (i = 0; i < spi_ignorelist_size; i++) {
563 if (writearr[0] == spi_ignorelist[i]) {
564 msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
565 spi_ignorelist[i]);
566 /* Return success because the command does not fail,
567 * it is simply ignored.
568 */
569 return 0;
570 }
571 }
hailfinger6ead7222010-11-01 22:07:04 +0000572 switch (writearr[0]) {
573 case JEDEC_RES:
574 if (emu_chip != EMULATE_ST_M25P10_RES)
575 break;
576 /* Respond with ST_M25P10_RES. */
577 if (readcnt > 0)
578 readarr[0] = 0x10;
579 break;
580 case JEDEC_REMS:
581 if (emu_chip != EMULATE_SST_SST25VF040_REMS)
582 break;
583 /* Respond with SST_SST25VF040_REMS. */
584 if (readcnt > 0)
585 readarr[0] = 0xbf;
586 if (readcnt > 1)
587 readarr[1] = 0x44;
588 break;
589 case JEDEC_RDID:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800590 if (emu_chip == EMULATE_SST_SST25VF032B) {
591 /* Respond with SST_SST25VF032B. */
592 if (readcnt > 0)
593 readarr[0] = 0xbf;
594 if (readcnt > 1)
595 readarr[1] = 0x25;
596 if (readcnt > 2)
597 readarr[2] = 0x4a;
598 } else if (emu_chip == EMULATE_VARIABLE_SIZE) {
599 const uint16_t man_id = VARIABLE_SIZE_MANUF_ID;
600 const uint16_t dev_id = VARIABLE_SIZE_DEVICE_ID;
601 if (readcnt > 0) readarr[0] = man_id >> 8;
602 if (readcnt > 1) readarr[1] = man_id & 0xff;
603 if (readcnt > 2) readarr[2] = dev_id >> 8;
604 if (readcnt > 3) readarr[3] = dev_id & 0xff;
605 }
hailfinger6ead7222010-11-01 22:07:04 +0000606 break;
607 case JEDEC_RDSR:
608 memset(readarr, 0, readcnt);
609 if (aai_active)
610 memset(readarr, 1 << 6, readcnt);
611 break;
612 case JEDEC_READ:
613 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
614 /* Truncate to emu_chip_size. */
615 offs %= emu_chip_size;
616 if (readcnt > 0)
617 memcpy(readarr, flashchip_contents + offs, readcnt);
618 break;
619 case JEDEC_BYTE_PROGRAM:
620 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
621 /* Truncate to emu_chip_size. */
622 offs %= emu_chip_size;
623 if (writecnt < 5) {
624 msg_perr("BYTE PROGRAM size too short!\n");
625 return 1;
626 }
627 if (writecnt - 4 > emu_max_byteprogram_size) {
628 msg_perr("Max BYTE PROGRAM size exceeded!\n");
629 return 1;
630 }
631 memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
Simon Glasscf253a72013-07-10 21:10:11 -0700632 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000633 break;
634 case JEDEC_AAI_WORD_PROGRAM:
635 if (!emu_max_aai_size)
636 break;
637 if (!aai_active) {
638 if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
639 msg_perr("Initial AAI WORD PROGRAM size too "
640 "short!\n");
641 return 1;
642 }
643 if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
644 msg_perr("Initial AAI WORD PROGRAM size too "
645 "long!\n");
646 return 1;
647 }
648 aai_active = 1;
649 aai_offs = writearr[1] << 16 | writearr[2] << 8 |
650 writearr[3];
651 /* Truncate to emu_chip_size. */
652 aai_offs %= emu_chip_size;
653 memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
654 aai_offs += 2;
655 } else {
656 if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
657 msg_perr("Continuation AAI WORD PROGRAM size "
658 "too short!\n");
659 return 1;
660 }
661 if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
662 msg_perr("Continuation AAI WORD PROGRAM size "
663 "too long!\n");
664 return 1;
665 }
666 memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
667 aai_offs += 2;
668 }
Simon Glasscf253a72013-07-10 21:10:11 -0700669 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000670 break;
671 case JEDEC_WRDI:
672 if (!emu_max_aai_size)
673 break;
674 aai_active = 0;
675 break;
676 case JEDEC_SE:
677 if (!emu_jedec_se_size)
678 break;
679 if (writecnt != JEDEC_SE_OUTSIZE) {
680 msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
681 return 1;
682 }
683 if (readcnt != JEDEC_SE_INSIZE) {
684 msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
685 return 1;
686 }
687 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
688 if (offs & (emu_jedec_se_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000689 msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000690 offs &= ~(emu_jedec_se_size - 1);
691 memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700692 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000693 break;
694 case JEDEC_BE_52:
695 if (!emu_jedec_be_52_size)
696 break;
697 if (writecnt != JEDEC_BE_52_OUTSIZE) {
698 msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
699 return 1;
700 }
701 if (readcnt != JEDEC_BE_52_INSIZE) {
702 msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
703 return 1;
704 }
705 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
706 if (offs & (emu_jedec_be_52_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000707 msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000708 offs &= ~(emu_jedec_be_52_size - 1);
709 memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700710 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000711 break;
712 case JEDEC_BE_D8:
713 if (!emu_jedec_be_d8_size)
714 break;
715 if (writecnt != JEDEC_BE_D8_OUTSIZE) {
716 msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
717 return 1;
718 }
719 if (readcnt != JEDEC_BE_D8_INSIZE) {
720 msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
721 return 1;
722 }
723 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
724 if (offs & (emu_jedec_be_d8_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000725 msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000726 offs &= ~(emu_jedec_be_d8_size - 1);
727 memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
728 break;
729 case JEDEC_CE_60:
730 if (!emu_jedec_ce_60_size)
731 break;
732 if (writecnt != JEDEC_CE_60_OUTSIZE) {
733 msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
734 return 1;
735 }
736 if (readcnt != JEDEC_CE_60_INSIZE) {
737 msg_perr("CHIP ERASE 0x60 insize invalid!\n");
738 return 1;
739 }
hailfingere53f5e42011-02-04 22:52:04 +0000740 /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000741 /* emu_jedec_ce_60_size is emu_chip_size. */
hailfingere53f5e42011-02-04 22:52:04 +0000742 memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700743 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000744 break;
745 case JEDEC_CE_C7:
746 if (!emu_jedec_ce_c7_size)
747 break;
748 if (writecnt != JEDEC_CE_C7_OUTSIZE) {
749 msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
750 return 1;
751 }
752 if (readcnt != JEDEC_CE_C7_INSIZE) {
753 msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
754 return 1;
755 }
hailfingere53f5e42011-02-04 22:52:04 +0000756 /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000757 /* emu_jedec_ce_c7_size is emu_chip_size. */
758 memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700759 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000760 break;
761 default:
762 /* No special response. */
763 break;
764 }
765 return 0;
766}
767#endif
768
Stuart langleyc98e43f2020-03-26 20:27:36 +1100769static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
770 unsigned int readcnt,
771 const unsigned char *writearr,
772 unsigned char *readarr)
hailfingerf91e3b52009-05-14 12:59:36 +0000773{
774 int i;
775
hailfinger50c335f2010-01-09 04:32:23 +0000776 msg_pspew("%s:", __func__);
hailfingerf91e3b52009-05-14 12:59:36 +0000777
hailfinger50c335f2010-01-09 04:32:23 +0000778 msg_pspew(" writing %u bytes:", writecnt);
hailfingerf91e3b52009-05-14 12:59:36 +0000779 for (i = 0; i < writecnt; i++)
hailfinger50c335f2010-01-09 04:32:23 +0000780 msg_pspew(" 0x%02x", writearr[i]);
hailfingerf91e3b52009-05-14 12:59:36 +0000781
hailfinger6ead7222010-11-01 22:07:04 +0000782 /* Response for unknown commands and missing chip is 0xff. */
783 memset(readarr, 0xff, readcnt);
784#if EMULATE_SPI_CHIP
785 switch (emu_chip) {
786 case EMULATE_ST_M25P10_RES:
787 case EMULATE_SST_SST25VF040_REMS:
788 case EMULATE_SST_SST25VF032B:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800789 case EMULATE_VARIABLE_SIZE:
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700790 if (emulate_spi_chip_response(flash, writecnt, readcnt, writearr,
hailfinger6ead7222010-11-01 22:07:04 +0000791 readarr)) {
Carl-Daniel Hailfingerc49783d2016-08-05 10:52:06 -0700792 msg_pdbg("Invalid command sent to flash chip!\n");
hailfinger6ead7222010-11-01 22:07:04 +0000793 return 1;
794 }
795 break;
796 default:
797 break;
798 }
799#endif
hailfinger50c335f2010-01-09 04:32:23 +0000800 msg_pspew(" reading %u bytes:", readcnt);
uwe8d342eb2011-07-28 08:13:25 +0000801 for (i = 0; i < readcnt; i++)
hailfinger6ead7222010-11-01 22:07:04 +0000802 msg_pspew(" 0x%02x", readarr[i]);
hailfinger50c335f2010-01-09 04:32:23 +0000803 msg_pspew("\n");
David Hendricks84377002014-09-09 16:09:31 -0700804
805 programmer_delay((writecnt + readcnt) * delay_us);
hailfingerf91e3b52009-05-14 12:59:36 +0000806 return 0;
807}
hailfingera8727712010-06-20 10:58:32 +0000808
Stuart langleyc98e43f2020-03-26 20:27:36 +1100809static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
hailfingerc7d06c62010-07-14 16:19:05 +0000810{
hailfinger6ead7222010-11-01 22:07:04 +0000811 return spi_write_chunked(flash, buf, start, len,
812 spi_write_256_chunksize);
hailfingerc7d06c62010-07-14 16:19:05 +0000813}
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800814
815#if EMULATE_CHIP && EMULATE_SPI_CHIP
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700816int probe_variable_size(struct flashctx *flash)
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800817{
818 int i;
819
820 /* Skip the probing if we don't emulate this chip. */
821 if (emu_chip != EMULATE_VARIABLE_SIZE)
822 return 0;
823
824 /*
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700825 * This will break if one day flashctx becomes read-only.
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800826 * Once that happens, we need to have special hacks in functions:
827 *
828 * erase_and_write_flash() in flashrom.c
829 * read_flash_to_file()
830 * handle_romentries()
831 * ...
832 *
833 * Search "total_size * 1024" in code.
834 */
835 if (emu_chip_size % 1024)
836 msg_perr("%s: emu_chip_size is not multipler of 1024.\n",
837 __func__);
Patrick Georgif3fa2992017-02-02 16:24:44 +0100838 flash->chip->total_size = emu_chip_size / 1024;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800839 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
Patrick Georgif3fa2992017-02-02 16:24:44 +0100840 flash->chip->total_size);
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800841
David Hendricks0eda2a82014-09-12 16:32:05 -0700842 if (erase_to_zero)
Alan Greendbeec2b2019-09-16 14:36:52 +1000843 flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
David Hendricks0eda2a82014-09-12 16:32:05 -0700844
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800845 /* Update eraser count */
846 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
Patrick Georgif3fa2992017-02-02 16:24:44 +0100847 struct block_eraser *eraser = &flash->chip->block_erasers[i];
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800848 if (eraser->block_erase == NULL)
849 break;
850
851 eraser->eraseblocks[0].count = emu_chip_size /
852 eraser->eraseblocks[0].size;
853 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
854 __func__, eraser->eraseblocks[0].size,
855 eraser->eraseblocks[0].count);
856 }
857
858 return 1;
859}
860#endif