blob: cd26f9da8317fcf6926d7c32a2b2f740e241692e [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 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
David Hendricks84377002014-09-09 16:09:31 -070020#include <errno.h>
hailfingera9df33c2009-05-09 00:54:55 +000021#include <string.h>
22#include <stdlib.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"
45#endif
hailfinger6ead7222010-11-01 22:07:04 +000046#endif
47
48#if EMULATE_CHIP
49static uint8_t *flashchip_contents = NULL;
50enum emu_chip {
51 EMULATE_NONE,
52 EMULATE_ST_M25P10_RES,
53 EMULATE_SST_SST25VF040_REMS,
54 EMULATE_SST_SST25VF032B,
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080055 EMULATE_VARIABLE_SIZE,
hailfinger6ead7222010-11-01 22:07:04 +000056};
57static enum emu_chip emu_chip = EMULATE_NONE;
58static char *emu_persistent_image = NULL;
stefanctc5eb8a92011-11-23 09:13:48 +000059static unsigned int emu_chip_size = 0;
Simon Glasscf253a72013-07-10 21:10:11 -070060static int emu_modified; /* is the image modified since reading it? */
David Hendricks0eda2a82014-09-12 16:32:05 -070061static int erase_to_zero;
hailfinger6ead7222010-11-01 22:07:04 +000062#if EMULATE_SPI_CHIP
stefanctc5eb8a92011-11-23 09:13:48 +000063static unsigned int emu_max_byteprogram_size = 0;
64static unsigned int emu_max_aai_size = 0;
65static unsigned int emu_jedec_se_size = 0;
66static unsigned int emu_jedec_be_52_size = 0;
67static unsigned int emu_jedec_be_d8_size = 0;
68static unsigned int emu_jedec_ce_60_size = 0;
69static unsigned int emu_jedec_ce_c7_size = 0;
hailfinger6ead7222010-11-01 22:07:04 +000070#endif
71#endif
72
stefanctc5eb8a92011-11-23 09:13:48 +000073static unsigned int spi_write_256_chunksize = 256;
hailfinger6ead7222010-11-01 22:07:04 +000074
David Hendricks84377002014-09-09 16:09:31 -070075/* If "freq" parameter is passed in from command line, commands will delay
76 * for this period before returning. */
77static unsigned long int delay_us = 0;
78
Souvik Ghoshd75cd672016-06-17 14:21:39 -070079static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
mkarcherd264e9e2011-05-11 17:07:07 +000080 const unsigned char *writearr, unsigned char *readarr);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070081static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
stefanctc5eb8a92011-11-23 09:13:48 +000082 unsigned int start, unsigned int len);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070083static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val,
84 chipaddr addr);
85static void dummy_chip_writew(const struct flashctx *flash, uint16_t val,
86 chipaddr addr);
87static void dummy_chip_writel(const struct flashctx *flash, uint32_t val,
88 chipaddr addr);
89static void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf,
90 chipaddr addr, size_t len);
91static uint8_t dummy_chip_readb(const struct flashctx *flash,
92 const chipaddr addr);
93static uint16_t dummy_chip_readw(const struct flashctx *flash,
94 const chipaddr addr);
95static uint32_t dummy_chip_readl(const struct flashctx *flash,
96 const chipaddr addr);
97static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf,
98 const chipaddr addr, size_t len);
mkarcherd264e9e2011-05-11 17:07:07 +000099
100static const struct spi_programmer spi_programmer_dummyflasher = {
uwe8d342eb2011-07-28 08:13:25 +0000101 .type = SPI_CONTROLLER_DUMMY,
102 .max_data_read = MAX_DATA_READ_UNLIMITED,
103 .max_data_write = MAX_DATA_UNSPECIFIED,
104 .command = dummy_spi_send_command,
105 .multicommand = default_spi_send_multicommand,
106 .read = default_spi_read,
107 .write_256 = dummy_spi_write_256,
mkarcherd264e9e2011-05-11 17:07:07 +0000108};
dhendrix0ffc2eb2011-06-14 01:35:36 +0000109
hailfinger76bb7e92011-11-09 23:40:00 +0000110static const struct par_programmer par_programmer_dummy = {
111 .chip_readb = dummy_chip_readb,
112 .chip_readw = dummy_chip_readw,
113 .chip_readl = dummy_chip_readl,
114 .chip_readn = dummy_chip_readn,
115 .chip_writeb = dummy_chip_writeb,
116 .chip_writew = dummy_chip_writew,
117 .chip_writel = dummy_chip_writel,
118 .chip_writen = dummy_chip_writen,
119};
120
121enum chipbustype dummy_buses_supported = BUS_NONE;
122
David Hendricks93784b42016-08-09 17:00:38 -0700123static int dummy_shutdown(void *data)
dhendrix0ffc2eb2011-06-14 01:35:36 +0000124{
125 msg_pspew("%s\n", __func__);
126#if EMULATE_CHIP
127 if (emu_chip != EMULATE_NONE) {
Simon Glasscf253a72013-07-10 21:10:11 -0700128 if (emu_persistent_image && emu_modified) {
dhendrix0ffc2eb2011-06-14 01:35:36 +0000129 msg_pdbg("Writing %s\n", emu_persistent_image);
130 write_buf_to_file(flashchip_contents, emu_chip_size,
131 emu_persistent_image);
132 }
133 free(flashchip_contents);
134 }
135#endif
136 return 0;
137}
138
Simon Glassd2c64a22013-07-03 22:05:21 +0900139/* Values for the 'size' parameter */
140enum {
141 SIZE_UNKNOWN = -1,
142 SIZE_AUTO = -2,
143};
144
David Hendricksac1d25c2016-08-09 17:00:58 -0700145int dummy_init(void)
hailfingera9df33c2009-05-09 00:54:55 +0000146{
hailfinger1ef766d2010-07-06 09:55:48 +0000147 char *bustext = NULL;
hailfinger6ead7222010-11-01 22:07:04 +0000148 char *tmp = NULL;
149#if EMULATE_CHIP
150 struct stat image_stat;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800151#if EMULATE_SPI_CHIP
Simon Glassd2c64a22013-07-03 22:05:21 +0900152 int size = SIZE_UNKNOWN; /* size for generic chip */
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800153#endif
hailfinger6ead7222010-11-01 22:07:04 +0000154#endif
Simon Glassd2c64a22013-07-03 22:05:21 +0900155 int image_size = SIZE_UNKNOWN;
hailfinger1ef766d2010-07-06 09:55:48 +0000156
hailfinger50c335f2010-01-09 04:32:23 +0000157 msg_pspew("%s\n", __func__);
hailfinger668f3502009-06-01 00:02:11 +0000158
hailfingerddeb4ac2010-07-08 10:13:37 +0000159 bustext = extract_programmer_param("bus");
hailfinger1ef766d2010-07-06 09:55:48 +0000160 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
161 if (!bustext)
162 bustext = strdup("parallel+lpc+fwh+spi");
hailfinger668f3502009-06-01 00:02:11 +0000163 /* Convert the parameters to lowercase. */
hailfinger1ef766d2010-07-06 09:55:48 +0000164 tolower_string(bustext);
hailfinger668f3502009-06-01 00:02:11 +0000165
hailfinger76bb7e92011-11-09 23:40:00 +0000166 dummy_buses_supported = BUS_NONE;
hailfinger1ef766d2010-07-06 09:55:48 +0000167 if (strstr(bustext, "parallel")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000168 dummy_buses_supported |= BUS_PARALLEL;
hailfinger50c335f2010-01-09 04:32:23 +0000169 msg_pdbg("Enabling support for %s flash.\n", "parallel");
hailfinger668f3502009-06-01 00:02:11 +0000170 }
hailfinger1ef766d2010-07-06 09:55:48 +0000171 if (strstr(bustext, "lpc")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000172 dummy_buses_supported |= BUS_LPC;
hailfinger50c335f2010-01-09 04:32:23 +0000173 msg_pdbg("Enabling support for %s flash.\n", "LPC");
hailfinger668f3502009-06-01 00:02:11 +0000174 }
hailfinger1ef766d2010-07-06 09:55:48 +0000175 if (strstr(bustext, "fwh")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000176 dummy_buses_supported |= BUS_FWH;
hailfinger50c335f2010-01-09 04:32:23 +0000177 msg_pdbg("Enabling support for %s flash.\n", "FWH");
hailfinger668f3502009-06-01 00:02:11 +0000178 }
hailfinger1ef766d2010-07-06 09:55:48 +0000179 if (strstr(bustext, "spi")) {
hailfinger76bb7e92011-11-09 23:40:00 +0000180 dummy_buses_supported |= BUS_SPI;
hailfinger50c335f2010-01-09 04:32:23 +0000181 msg_pdbg("Enabling support for %s flash.\n", "SPI");
hailfinger668f3502009-06-01 00:02:11 +0000182 }
hailfinger76bb7e92011-11-09 23:40:00 +0000183 if (dummy_buses_supported == BUS_NONE)
hailfinger50c335f2010-01-09 04:32:23 +0000184 msg_pdbg("Support for all flash bus types disabled.\n");
hailfinger1ef766d2010-07-06 09:55:48 +0000185 free(bustext);
hailfinger6ead7222010-11-01 22:07:04 +0000186
187 tmp = extract_programmer_param("spi_write_256_chunksize");
188 if (tmp) {
189 spi_write_256_chunksize = atoi(tmp);
190 free(tmp);
191 if (spi_write_256_chunksize < 1) {
192 msg_perr("invalid spi_write_256_chunksize\n");
193 return 1;
194 }
195 }
196
David Hendricks84377002014-09-09 16:09:31 -0700197 /* frequency to emulate in Hz (default), KHz, or MHz */
198 tmp = extract_programmer_param("freq");
199 if (tmp) {
200 unsigned long int freq;
201 char *units = tmp;
202 char *end = tmp + strlen(tmp);
203
204 errno = 0;
205 freq = strtoul(tmp, &units, 0);
206 if (errno) {
207 msg_perr("Invalid frequency \"%s\", %s\n",
208 tmp, strerror(errno));
209 goto dummy_init_out;
210 }
211
212 if ((units > tmp) && (units < end)) {
213 int units_valid = 0;
214
215 if (units < end - 3) {
216 ;
217 } else if (units == end - 2) {
218 if (!strcasecmp(units, "hz"))
219 units_valid = 1;
220 } else if (units == end - 3) {
221 if (!strcasecmp(units, "khz")) {
222 freq *= 1000;
223 units_valid = 1;
224 } else if (!strcasecmp(units, "mhz")) {
225 freq *= 1000000;
226 units_valid = 1;
227 }
228 }
229
230 if (!units_valid) {
231 msg_perr("Invalid units: %s\n", units);
232 return 1;
233 }
234 }
235
236 /* Assume we only work with bytes and transfer at 1 bit/Hz */
237 delay_us = (1000000 * 8) / freq;
238 }
239
hailfinger6ead7222010-11-01 22:07:04 +0000240#if EMULATE_CHIP
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800241#if EMULATE_SPI_CHIP
242 tmp = extract_programmer_param("size");
243 if (tmp) {
244 int multiplier = 1;
Simon Glassd2c64a22013-07-03 22:05:21 +0900245 if (!strcmp(tmp, "auto"))
246 size = SIZE_AUTO;
247 else if (strlen(tmp)) {
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800248 int remove_last_char = 1;
249 switch (tmp[strlen(tmp) - 1]) {
250 case 'k': case 'K':
251 multiplier = 1024;
252 break;
253 case 'm': case 'M':
254 multiplier = 1024 * 1024;
255 break;
256 default:
257 remove_last_char = 0;
258 break;
259 }
260 if (remove_last_char) tmp[strlen(tmp) - 1] = '\0';
Simon Glassd2c64a22013-07-03 22:05:21 +0900261 size = atoi(tmp) * multiplier;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800262 }
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800263 }
264#endif
265
hailfinger6ead7222010-11-01 22:07:04 +0000266 tmp = extract_programmer_param("emulate");
267 if (!tmp) {
268 msg_pdbg("Not emulating any flash chip.\n");
269 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000270 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000271 }
David Hendricks84377002014-09-09 16:09:31 -0700272
hailfinger6ead7222010-11-01 22:07:04 +0000273#if EMULATE_SPI_CHIP
274 if (!strcmp(tmp, "M25P10.RES")) {
275 emu_chip = EMULATE_ST_M25P10_RES;
276 emu_chip_size = 128 * 1024;
277 emu_max_byteprogram_size = 128;
278 emu_max_aai_size = 0;
279 emu_jedec_se_size = 0;
280 emu_jedec_be_52_size = 0;
281 emu_jedec_be_d8_size = 32 * 1024;
282 emu_jedec_ce_60_size = 0;
283 emu_jedec_ce_c7_size = emu_chip_size;
284 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
285 "write)\n");
286 }
287 if (!strcmp(tmp, "SST25VF040.REMS")) {
288 emu_chip = EMULATE_SST_SST25VF040_REMS;
289 emu_chip_size = 512 * 1024;
290 emu_max_byteprogram_size = 1;
291 emu_max_aai_size = 0;
292 emu_jedec_se_size = 4 * 1024;
293 emu_jedec_be_52_size = 32 * 1024;
294 emu_jedec_be_d8_size = 0;
295 emu_jedec_ce_60_size = emu_chip_size;
296 emu_jedec_ce_c7_size = 0;
297 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
298 "byte write)\n");
299 }
300 if (!strcmp(tmp, "SST25VF032B")) {
301 emu_chip = EMULATE_SST_SST25VF032B;
302 emu_chip_size = 4 * 1024 * 1024;
303 emu_max_byteprogram_size = 1;
304 emu_max_aai_size = 2;
305 emu_jedec_se_size = 4 * 1024;
306 emu_jedec_be_52_size = 32 * 1024;
307 emu_jedec_be_d8_size = 64 * 1024;
308 emu_jedec_ce_60_size = emu_chip_size;
309 emu_jedec_ce_c7_size = emu_chip_size;
310 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
311 "write)\n");
312 }
Simon Glassd2c64a22013-07-03 22:05:21 +0900313 emu_persistent_image = extract_programmer_param("image");
314 if (!stat(emu_persistent_image, &image_stat))
315 image_size = image_stat.st_size;
316
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800317 if (!strncmp(tmp, VARIABLE_SIZE_CHIP_NAME,
318 strlen(VARIABLE_SIZE_CHIP_NAME))) {
Simon Glassd2c64a22013-07-03 22:05:21 +0900319 if (size == SIZE_UNKNOWN) {
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800320 msg_perr("%s: the size parameter is not given.\n",
321 __func__);
322 free(tmp);
323 return 1;
Simon Glassd2c64a22013-07-03 22:05:21 +0900324 } else if (size == SIZE_AUTO) {
325 if (image_size == SIZE_UNKNOWN) {
326 msg_perr("%s: no image so cannot use automatic size.\n",
327 __func__);
328 free(tmp);
329 return 1;
330 }
331 size = image_size;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800332 }
333 emu_chip = EMULATE_VARIABLE_SIZE;
334 emu_chip_size = size;
335 emu_max_byteprogram_size = 256;
336 emu_max_aai_size = 0;
337 emu_jedec_se_size = 4 * 1024;
338 emu_jedec_be_52_size = 32 * 1024;
339 emu_jedec_be_d8_size = 64 * 1024;
340 emu_jedec_ce_60_size = emu_chip_size;
341 emu_jedec_ce_c7_size = emu_chip_size;
342 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
343 emu_chip_size);
344 }
hailfinger6ead7222010-11-01 22:07:04 +0000345#endif
346 if (emu_chip == EMULATE_NONE) {
347 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
348 free(tmp);
349 return 1;
350 }
David Hendricks0eda2a82014-09-12 16:32:05 -0700351
352 /* Should emulated flash erase to zero (yes/no)? */
353 tmp = extract_programmer_param("erase_to_zero");
354 if (tmp) {
355 if (!strcmp(tmp, "yes")) {
356 msg_pdbg("Emulated chip will erase to 0x00\n");
357 erase_to_zero = 1;
358 } else if (!strcmp(tmp, "no")) {
359 msg_pdbg("Emulated chip will erase to 0xff\n");
360 } else {
361 msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
362 return 1;
363 }
364 }
365
hailfinger6ead7222010-11-01 22:07:04 +0000366 free(tmp);
367 flashchip_contents = malloc(emu_chip_size);
368 if (!flashchip_contents) {
369 msg_perr("Out of memory!\n");
370 return 1;
371 }
dhendrix0ffc2eb2011-06-14 01:35:36 +0000372
David Hendricks0eda2a82014-09-12 16:32:05 -0700373 msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
374 erase_to_zero ? 0x00 : 0xff, emu_chip_size);
375 memset(flashchip_contents, erase_to_zero ? 0x00 : 0xff, emu_chip_size);
hailfinger6ead7222010-11-01 22:07:04 +0000376
hailfinger6ead7222010-11-01 22:07:04 +0000377 if (!emu_persistent_image) {
378 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000379 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000380 }
381 if (!stat(emu_persistent_image, &image_stat)) {
382 msg_pdbg("Found persistent image %s, size %li ",
383 emu_persistent_image, (long)image_stat.st_size);
384 if (image_stat.st_size == emu_chip_size) {
385 msg_pdbg("matches.\n");
386 msg_pdbg("Reading %s\n", emu_persistent_image);
387 read_buf_from_file(flashchip_contents, emu_chip_size,
388 emu_persistent_image);
389 } else {
390 msg_pdbg("doesn't match.\n");
391 }
392 }
393#endif
hailfingera9df33c2009-05-09 00:54:55 +0000394
dhendrix0ffc2eb2011-06-14 01:35:36 +0000395dummy_init_out:
396 if (register_shutdown(dummy_shutdown, NULL)) {
hailfinger6ead7222010-11-01 22:07:04 +0000397 free(flashchip_contents);
dhendrix0ffc2eb2011-06-14 01:35:36 +0000398 return 1;
hailfinger6ead7222010-11-01 22:07:04 +0000399 }
hailfinger76bb7e92011-11-09 23:40:00 +0000400 if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
401 register_par_programmer(&par_programmer_dummy,
402 dummy_buses_supported &
403 (BUS_PARALLEL | BUS_LPC |
404 BUS_FWH));
405 if (dummy_buses_supported & BUS_SPI)
406 register_spi_programmer(&spi_programmer_dummyflasher);
407
hailfingera9df33c2009-05-09 00:54:55 +0000408 return 0;
409}
410
hailfinger11ae3c42009-05-11 14:13:25 +0000411void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
412{
hailfinger50c335f2010-01-09 04:32:23 +0000413 msg_pspew("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
414 __func__, descr, (unsigned long)len, phys_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000415 return (void *)phys_addr;
416}
417
418void dummy_unmap(void *virt_addr, size_t len)
419{
hailfinger50c335f2010-01-09 04:32:23 +0000420 msg_pspew("%s: Unmapping 0x%lx bytes at %p\n",
421 __func__, (unsigned long)len, virt_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000422}
423
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700424void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000425{
hailfinger50c335f2010-01-09 04:32:23 +0000426 msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000427}
428
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700429void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000430{
hailfinger50c335f2010-01-09 04:32:23 +0000431 msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000432}
433
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700434void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000435{
hailfinger50c335f2010-01-09 04:32:23 +0000436 msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000437}
438
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700439void dummy_chip_writen(const struct flashctx *flash, uint8_t *buf, chipaddr addr, size_t len)
hailfinger9d987ef2009-06-05 18:32:07 +0000440{
441 size_t i;
hailfinger50c335f2010-01-09 04:32:23 +0000442 msg_pspew("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
443 __func__, addr, (unsigned long)len);
hailfinger9d987ef2009-06-05 18:32:07 +0000444 for (i = 0; i < len; i++) {
445 if ((i % 16) == 0)
hailfinger50c335f2010-01-09 04:32:23 +0000446 msg_pspew("\n");
447 msg_pspew("%02x ", buf[i]);
hailfinger9d987ef2009-06-05 18:32:07 +0000448 }
449}
450
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700451uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000452{
hailfinger50c335f2010-01-09 04:32:23 +0000453 msg_pspew("%s: addr=0x%lx, returning 0xff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000454 return 0xff;
455}
456
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700457uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000458{
hailfinger50c335f2010-01-09 04:32:23 +0000459 msg_pspew("%s: addr=0x%lx, returning 0xffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000460 return 0xffff;
461}
462
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700463uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000464{
hailfinger50c335f2010-01-09 04:32:23 +0000465 msg_pspew("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000466 return 0xffffffff;
467}
468
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700469void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
hailfinger9d987ef2009-06-05 18:32:07 +0000470{
hailfinger50c335f2010-01-09 04:32:23 +0000471 msg_pspew("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n",
472 __func__, addr, (unsigned long)len);
hailfinger9d987ef2009-06-05 18:32:07 +0000473 memset(buf, 0xff, len);
474 return;
475}
476
hailfinger6ead7222010-11-01 22:07:04 +0000477#if EMULATE_SPI_CHIP
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700478static int emulate_spi_chip_response(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
hailfinger6ead7222010-11-01 22:07:04 +0000479 const unsigned char *writearr, unsigned char *readarr)
480{
stefanctc5eb8a92011-11-23 09:13:48 +0000481 unsigned int offs;
482 static int unsigned aai_offs;
hailfinger6ead7222010-11-01 22:07:04 +0000483 static int aai_active = 0;
484
485 if (writecnt == 0) {
486 msg_perr("No command sent to the chip!\n");
487 return 1;
488 }
489 /* TODO: Implement command blacklists here. */
490 switch (writearr[0]) {
491 case JEDEC_RES:
492 if (emu_chip != EMULATE_ST_M25P10_RES)
493 break;
494 /* Respond with ST_M25P10_RES. */
495 if (readcnt > 0)
496 readarr[0] = 0x10;
497 break;
498 case JEDEC_REMS:
499 if (emu_chip != EMULATE_SST_SST25VF040_REMS)
500 break;
501 /* Respond with SST_SST25VF040_REMS. */
502 if (readcnt > 0)
503 readarr[0] = 0xbf;
504 if (readcnt > 1)
505 readarr[1] = 0x44;
506 break;
507 case JEDEC_RDID:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800508 if (emu_chip == EMULATE_SST_SST25VF032B) {
509 /* Respond with SST_SST25VF032B. */
510 if (readcnt > 0)
511 readarr[0] = 0xbf;
512 if (readcnt > 1)
513 readarr[1] = 0x25;
514 if (readcnt > 2)
515 readarr[2] = 0x4a;
516 } else if (emu_chip == EMULATE_VARIABLE_SIZE) {
517 const uint16_t man_id = VARIABLE_SIZE_MANUF_ID;
518 const uint16_t dev_id = VARIABLE_SIZE_DEVICE_ID;
519 if (readcnt > 0) readarr[0] = man_id >> 8;
520 if (readcnt > 1) readarr[1] = man_id & 0xff;
521 if (readcnt > 2) readarr[2] = dev_id >> 8;
522 if (readcnt > 3) readarr[3] = dev_id & 0xff;
523 }
hailfinger6ead7222010-11-01 22:07:04 +0000524 break;
525 case JEDEC_RDSR:
526 memset(readarr, 0, readcnt);
527 if (aai_active)
528 memset(readarr, 1 << 6, readcnt);
529 break;
530 case JEDEC_READ:
531 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
532 /* Truncate to emu_chip_size. */
533 offs %= emu_chip_size;
534 if (readcnt > 0)
535 memcpy(readarr, flashchip_contents + offs, readcnt);
536 break;
537 case JEDEC_BYTE_PROGRAM:
538 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
539 /* Truncate to emu_chip_size. */
540 offs %= emu_chip_size;
541 if (writecnt < 5) {
542 msg_perr("BYTE PROGRAM size too short!\n");
543 return 1;
544 }
545 if (writecnt - 4 > emu_max_byteprogram_size) {
546 msg_perr("Max BYTE PROGRAM size exceeded!\n");
547 return 1;
548 }
549 memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
Simon Glasscf253a72013-07-10 21:10:11 -0700550 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000551 break;
552 case JEDEC_AAI_WORD_PROGRAM:
553 if (!emu_max_aai_size)
554 break;
555 if (!aai_active) {
556 if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
557 msg_perr("Initial AAI WORD PROGRAM size too "
558 "short!\n");
559 return 1;
560 }
561 if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
562 msg_perr("Initial AAI WORD PROGRAM size too "
563 "long!\n");
564 return 1;
565 }
566 aai_active = 1;
567 aai_offs = writearr[1] << 16 | writearr[2] << 8 |
568 writearr[3];
569 /* Truncate to emu_chip_size. */
570 aai_offs %= emu_chip_size;
571 memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
572 aai_offs += 2;
573 } else {
574 if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
575 msg_perr("Continuation AAI WORD PROGRAM size "
576 "too short!\n");
577 return 1;
578 }
579 if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
580 msg_perr("Continuation AAI WORD PROGRAM size "
581 "too long!\n");
582 return 1;
583 }
584 memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
585 aai_offs += 2;
586 }
Simon Glasscf253a72013-07-10 21:10:11 -0700587 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000588 break;
589 case JEDEC_WRDI:
590 if (!emu_max_aai_size)
591 break;
592 aai_active = 0;
593 break;
594 case JEDEC_SE:
595 if (!emu_jedec_se_size)
596 break;
597 if (writecnt != JEDEC_SE_OUTSIZE) {
598 msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
599 return 1;
600 }
601 if (readcnt != JEDEC_SE_INSIZE) {
602 msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
603 return 1;
604 }
605 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
606 if (offs & (emu_jedec_se_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000607 msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000608 offs &= ~(emu_jedec_se_size - 1);
609 memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700610 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000611 break;
612 case JEDEC_BE_52:
613 if (!emu_jedec_be_52_size)
614 break;
615 if (writecnt != JEDEC_BE_52_OUTSIZE) {
616 msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
617 return 1;
618 }
619 if (readcnt != JEDEC_BE_52_INSIZE) {
620 msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
621 return 1;
622 }
623 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
624 if (offs & (emu_jedec_be_52_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000625 msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000626 offs &= ~(emu_jedec_be_52_size - 1);
627 memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700628 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000629 break;
630 case JEDEC_BE_D8:
631 if (!emu_jedec_be_d8_size)
632 break;
633 if (writecnt != JEDEC_BE_D8_OUTSIZE) {
634 msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
635 return 1;
636 }
637 if (readcnt != JEDEC_BE_D8_INSIZE) {
638 msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
639 return 1;
640 }
641 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
642 if (offs & (emu_jedec_be_d8_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000643 msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000644 offs &= ~(emu_jedec_be_d8_size - 1);
645 memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
646 break;
647 case JEDEC_CE_60:
648 if (!emu_jedec_ce_60_size)
649 break;
650 if (writecnt != JEDEC_CE_60_OUTSIZE) {
651 msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
652 return 1;
653 }
654 if (readcnt != JEDEC_CE_60_INSIZE) {
655 msg_perr("CHIP ERASE 0x60 insize invalid!\n");
656 return 1;
657 }
hailfingere53f5e42011-02-04 22:52:04 +0000658 /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000659 /* emu_jedec_ce_60_size is emu_chip_size. */
hailfingere53f5e42011-02-04 22:52:04 +0000660 memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700661 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000662 break;
663 case JEDEC_CE_C7:
664 if (!emu_jedec_ce_c7_size)
665 break;
666 if (writecnt != JEDEC_CE_C7_OUTSIZE) {
667 msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
668 return 1;
669 }
670 if (readcnt != JEDEC_CE_C7_INSIZE) {
671 msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
672 return 1;
673 }
hailfingere53f5e42011-02-04 22:52:04 +0000674 /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000675 /* emu_jedec_ce_c7_size is emu_chip_size. */
676 memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
Simon Glasscf253a72013-07-10 21:10:11 -0700677 emu_modified = 1;
hailfinger6ead7222010-11-01 22:07:04 +0000678 break;
679 default:
680 /* No special response. */
681 break;
682 }
683 return 0;
684}
685#endif
686
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700687static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
hailfingerf91e3b52009-05-14 12:59:36 +0000688 const unsigned char *writearr, unsigned char *readarr)
689{
690 int i;
691
hailfinger50c335f2010-01-09 04:32:23 +0000692 msg_pspew("%s:", __func__);
hailfingerf91e3b52009-05-14 12:59:36 +0000693
hailfinger50c335f2010-01-09 04:32:23 +0000694 msg_pspew(" writing %u bytes:", writecnt);
hailfingerf91e3b52009-05-14 12:59:36 +0000695 for (i = 0; i < writecnt; i++)
hailfinger50c335f2010-01-09 04:32:23 +0000696 msg_pspew(" 0x%02x", writearr[i]);
hailfingerf91e3b52009-05-14 12:59:36 +0000697
hailfinger6ead7222010-11-01 22:07:04 +0000698 /* Response for unknown commands and missing chip is 0xff. */
699 memset(readarr, 0xff, readcnt);
700#if EMULATE_SPI_CHIP
701 switch (emu_chip) {
702 case EMULATE_ST_M25P10_RES:
703 case EMULATE_SST_SST25VF040_REMS:
704 case EMULATE_SST_SST25VF032B:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800705 case EMULATE_VARIABLE_SIZE:
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700706 if (emulate_spi_chip_response(flash, writecnt, readcnt, writearr,
hailfinger6ead7222010-11-01 22:07:04 +0000707 readarr)) {
708 msg_perr("Invalid command sent to flash chip!\n");
709 return 1;
710 }
711 break;
712 default:
713 break;
714 }
715#endif
hailfinger50c335f2010-01-09 04:32:23 +0000716 msg_pspew(" reading %u bytes:", readcnt);
uwe8d342eb2011-07-28 08:13:25 +0000717 for (i = 0; i < readcnt; i++)
hailfinger6ead7222010-11-01 22:07:04 +0000718 msg_pspew(" 0x%02x", readarr[i]);
hailfinger50c335f2010-01-09 04:32:23 +0000719 msg_pspew("\n");
David Hendricks84377002014-09-09 16:09:31 -0700720
721 programmer_delay((writecnt + readcnt) * delay_us);
hailfingerf91e3b52009-05-14 12:59:36 +0000722 return 0;
723}
hailfingera8727712010-06-20 10:58:32 +0000724
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700725static int dummy_spi_write_256(struct flashctx *flash, uint8_t *buf,
stefanctc5eb8a92011-11-23 09:13:48 +0000726 unsigned int start, unsigned int len)
hailfingerc7d06c62010-07-14 16:19:05 +0000727{
hailfinger6ead7222010-11-01 22:07:04 +0000728 return spi_write_chunked(flash, buf, start, len,
729 spi_write_256_chunksize);
hailfingerc7d06c62010-07-14 16:19:05 +0000730}
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800731
732#if EMULATE_CHIP && EMULATE_SPI_CHIP
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700733int probe_variable_size(struct flashctx *flash)
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800734{
735 int i;
736
737 /* Skip the probing if we don't emulate this chip. */
738 if (emu_chip != EMULATE_VARIABLE_SIZE)
739 return 0;
740
741 /*
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700742 * This will break if one day flashctx becomes read-only.
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800743 * Once that happens, we need to have special hacks in functions:
744 *
745 * erase_and_write_flash() in flashrom.c
746 * read_flash_to_file()
747 * handle_romentries()
748 * ...
749 *
750 * Search "total_size * 1024" in code.
751 */
752 if (emu_chip_size % 1024)
753 msg_perr("%s: emu_chip_size is not multipler of 1024.\n",
754 __func__);
755 flash->total_size = emu_chip_size / 1024;
756 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
757 flash->total_size);
758
David Hendricks0eda2a82014-09-12 16:32:05 -0700759 if (erase_to_zero)
760 flash->feature_bits |= FEATURE_ERASE_TO_ZERO;
761
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800762 /* Update eraser count */
763 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
764 struct block_eraser *eraser = &flash->block_erasers[i];
765 if (eraser->block_erase == NULL)
766 break;
767
768 eraser->eraseblocks[0].count = emu_chip_size /
769 eraser->eraseblocks[0].size;
770 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
771 __func__, eraser->eraseblocks[0].size,
772 eraser->eraseblocks[0].count);
773 }
774
775 return 1;
776}
777#endif