blob: c80e0d2c4581abf25c46797546511dfdb95cc1bd [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
hailfingera9df33c2009-05-09 00:54:55 +000020#include <string.h>
21#include <stdlib.h>
hailfingera9df33c2009-05-09 00:54:55 +000022#include "flash.h"
hailfingera8727712010-06-20 10:58:32 +000023#include "chipdrivers.h"
hailfinger428f6852010-07-27 22:41:39 +000024#include "programmer.h"
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080025#include "flashchips.h"
hailfingera9df33c2009-05-09 00:54:55 +000026
hailfinger6ead7222010-11-01 22:07:04 +000027/* Remove the #define below if you don't want SPI flash chip emulation. */
28#define EMULATE_SPI_CHIP 1
29
30#if EMULATE_SPI_CHIP
31#define EMULATE_CHIP 1
32#include "spi.h"
33#endif
34
35#if EMULATE_CHIP
36#include <sys/types.h>
37#include <sys/stat.h>
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080038
39#if EMULATE_SPI_CHIP
40/* The name of variable-size virtual chip. A 4MB flash example:
41 * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
42 */
43#define VARIABLE_SIZE_CHIP_NAME "VARIABLE_SIZE"
44#endif
hailfinger6ead7222010-11-01 22:07:04 +000045#endif
46
47#if EMULATE_CHIP
48static uint8_t *flashchip_contents = NULL;
49enum emu_chip {
50 EMULATE_NONE,
51 EMULATE_ST_M25P10_RES,
52 EMULATE_SST_SST25VF040_REMS,
53 EMULATE_SST_SST25VF032B,
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +080054 EMULATE_VARIABLE_SIZE,
hailfinger6ead7222010-11-01 22:07:04 +000055};
56static enum emu_chip emu_chip = EMULATE_NONE;
57static char *emu_persistent_image = NULL;
58static int emu_chip_size = 0;
59#if EMULATE_SPI_CHIP
60static int emu_max_byteprogram_size = 0;
61static int emu_max_aai_size = 0;
62static int emu_jedec_se_size = 0;
63static int emu_jedec_be_52_size = 0;
64static int emu_jedec_be_d8_size = 0;
65static int emu_jedec_ce_60_size = 0;
66static int emu_jedec_ce_c7_size = 0;
67#endif
68#endif
69
70static int spi_write_256_chunksize = 256;
71
mkarcherd264e9e2011-05-11 17:07:07 +000072static int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
73 const unsigned char *writearr, unsigned char *readarr);
uwe8d342eb2011-07-28 08:13:25 +000074static int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf,
75 int start, int len);
mkarcherd264e9e2011-05-11 17:07:07 +000076
77static const struct spi_programmer spi_programmer_dummyflasher = {
uwe8d342eb2011-07-28 08:13:25 +000078 .type = SPI_CONTROLLER_DUMMY,
79 .max_data_read = MAX_DATA_READ_UNLIMITED,
80 .max_data_write = MAX_DATA_UNSPECIFIED,
81 .command = dummy_spi_send_command,
82 .multicommand = default_spi_send_multicommand,
83 .read = default_spi_read,
84 .write_256 = dummy_spi_write_256,
mkarcherd264e9e2011-05-11 17:07:07 +000085};
dhendrix0ffc2eb2011-06-14 01:35:36 +000086
87static int dummy_shutdown(void *data)
88{
89 msg_pspew("%s\n", __func__);
90#if EMULATE_CHIP
91 if (emu_chip != EMULATE_NONE) {
92 if (emu_persistent_image) {
93 msg_pdbg("Writing %s\n", emu_persistent_image);
94 write_buf_to_file(flashchip_contents, emu_chip_size,
95 emu_persistent_image);
96 }
97 free(flashchip_contents);
98 }
99#endif
100 return 0;
101}
102
hailfingera9df33c2009-05-09 00:54:55 +0000103int dummy_init(void)
104{
hailfinger1ef766d2010-07-06 09:55:48 +0000105 char *bustext = NULL;
hailfinger6ead7222010-11-01 22:07:04 +0000106 char *tmp = NULL;
107#if EMULATE_CHIP
108 struct stat image_stat;
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800109#if EMULATE_SPI_CHIP
110 int size = -1; /* size for generic chip */
111#endif
hailfinger6ead7222010-11-01 22:07:04 +0000112#endif
hailfinger1ef766d2010-07-06 09:55:48 +0000113
hailfinger50c335f2010-01-09 04:32:23 +0000114 msg_pspew("%s\n", __func__);
hailfinger668f3502009-06-01 00:02:11 +0000115
hailfingerddeb4ac2010-07-08 10:13:37 +0000116 bustext = extract_programmer_param("bus");
hailfinger1ef766d2010-07-06 09:55:48 +0000117 msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
118 if (!bustext)
119 bustext = strdup("parallel+lpc+fwh+spi");
hailfinger668f3502009-06-01 00:02:11 +0000120 /* Convert the parameters to lowercase. */
hailfinger1ef766d2010-07-06 09:55:48 +0000121 tolower_string(bustext);
hailfinger668f3502009-06-01 00:02:11 +0000122
hailfingere1e41ea2011-07-27 07:13:06 +0000123 buses_supported = BUS_NONE;
hailfinger1ef766d2010-07-06 09:55:48 +0000124 if (strstr(bustext, "parallel")) {
hailfingere1e41ea2011-07-27 07:13:06 +0000125 buses_supported |= BUS_PARALLEL;
hailfinger50c335f2010-01-09 04:32:23 +0000126 msg_pdbg("Enabling support for %s flash.\n", "parallel");
hailfinger668f3502009-06-01 00:02:11 +0000127 }
hailfinger1ef766d2010-07-06 09:55:48 +0000128 if (strstr(bustext, "lpc")) {
hailfingere1e41ea2011-07-27 07:13:06 +0000129 buses_supported |= BUS_LPC;
hailfinger50c335f2010-01-09 04:32:23 +0000130 msg_pdbg("Enabling support for %s flash.\n", "LPC");
hailfinger668f3502009-06-01 00:02:11 +0000131 }
hailfinger1ef766d2010-07-06 09:55:48 +0000132 if (strstr(bustext, "fwh")) {
hailfingere1e41ea2011-07-27 07:13:06 +0000133 buses_supported |= BUS_FWH;
hailfinger50c335f2010-01-09 04:32:23 +0000134 msg_pdbg("Enabling support for %s flash.\n", "FWH");
hailfinger668f3502009-06-01 00:02:11 +0000135 }
hailfinger1ef766d2010-07-06 09:55:48 +0000136 if (strstr(bustext, "spi")) {
mkarcherd264e9e2011-05-11 17:07:07 +0000137 register_spi_programmer(&spi_programmer_dummyflasher);
hailfinger50c335f2010-01-09 04:32:23 +0000138 msg_pdbg("Enabling support for %s flash.\n", "SPI");
hailfinger668f3502009-06-01 00:02:11 +0000139 }
hailfingere1e41ea2011-07-27 07:13:06 +0000140 if (buses_supported == BUS_NONE)
hailfinger50c335f2010-01-09 04:32:23 +0000141 msg_pdbg("Support for all flash bus types disabled.\n");
hailfinger1ef766d2010-07-06 09:55:48 +0000142 free(bustext);
hailfinger6ead7222010-11-01 22:07:04 +0000143
144 tmp = extract_programmer_param("spi_write_256_chunksize");
145 if (tmp) {
146 spi_write_256_chunksize = atoi(tmp);
147 free(tmp);
148 if (spi_write_256_chunksize < 1) {
149 msg_perr("invalid spi_write_256_chunksize\n");
150 return 1;
151 }
152 }
153
154#if EMULATE_CHIP
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800155#if EMULATE_SPI_CHIP
156 tmp = extract_programmer_param("size");
157 if (tmp) {
158 int multiplier = 1;
159 if (strlen(tmp)) {
160 int remove_last_char = 1;
161 switch (tmp[strlen(tmp) - 1]) {
162 case 'k': case 'K':
163 multiplier = 1024;
164 break;
165 case 'm': case 'M':
166 multiplier = 1024 * 1024;
167 break;
168 default:
169 remove_last_char = 0;
170 break;
171 }
172 if (remove_last_char) tmp[strlen(tmp) - 1] = '\0';
173 }
174 size = atoi(tmp) * multiplier;
175 }
176#endif
177
hailfinger6ead7222010-11-01 22:07:04 +0000178 tmp = extract_programmer_param("emulate");
179 if (!tmp) {
180 msg_pdbg("Not emulating any flash chip.\n");
181 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000182 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000183 }
184#if EMULATE_SPI_CHIP
185 if (!strcmp(tmp, "M25P10.RES")) {
186 emu_chip = EMULATE_ST_M25P10_RES;
187 emu_chip_size = 128 * 1024;
188 emu_max_byteprogram_size = 128;
189 emu_max_aai_size = 0;
190 emu_jedec_se_size = 0;
191 emu_jedec_be_52_size = 0;
192 emu_jedec_be_d8_size = 32 * 1024;
193 emu_jedec_ce_60_size = 0;
194 emu_jedec_ce_c7_size = emu_chip_size;
195 msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
196 "write)\n");
197 }
198 if (!strcmp(tmp, "SST25VF040.REMS")) {
199 emu_chip = EMULATE_SST_SST25VF040_REMS;
200 emu_chip_size = 512 * 1024;
201 emu_max_byteprogram_size = 1;
202 emu_max_aai_size = 0;
203 emu_jedec_se_size = 4 * 1024;
204 emu_jedec_be_52_size = 32 * 1024;
205 emu_jedec_be_d8_size = 0;
206 emu_jedec_ce_60_size = emu_chip_size;
207 emu_jedec_ce_c7_size = 0;
208 msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
209 "byte write)\n");
210 }
211 if (!strcmp(tmp, "SST25VF032B")) {
212 emu_chip = EMULATE_SST_SST25VF032B;
213 emu_chip_size = 4 * 1024 * 1024;
214 emu_max_byteprogram_size = 1;
215 emu_max_aai_size = 2;
216 emu_jedec_se_size = 4 * 1024;
217 emu_jedec_be_52_size = 32 * 1024;
218 emu_jedec_be_d8_size = 64 * 1024;
219 emu_jedec_ce_60_size = emu_chip_size;
220 emu_jedec_ce_c7_size = emu_chip_size;
221 msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
222 "write)\n");
223 }
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800224 if (!strncmp(tmp, VARIABLE_SIZE_CHIP_NAME,
225 strlen(VARIABLE_SIZE_CHIP_NAME))) {
226 if (size == -1) {
227 msg_perr("%s: the size parameter is not given.\n",
228 __func__);
229 free(tmp);
230 return 1;
231 }
232 emu_chip = EMULATE_VARIABLE_SIZE;
233 emu_chip_size = size;
234 emu_max_byteprogram_size = 256;
235 emu_max_aai_size = 0;
236 emu_jedec_se_size = 4 * 1024;
237 emu_jedec_be_52_size = 32 * 1024;
238 emu_jedec_be_d8_size = 64 * 1024;
239 emu_jedec_ce_60_size = emu_chip_size;
240 emu_jedec_ce_c7_size = emu_chip_size;
241 msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
242 emu_chip_size);
243 }
hailfinger6ead7222010-11-01 22:07:04 +0000244#endif
245 if (emu_chip == EMULATE_NONE) {
246 msg_perr("Invalid chip specified for emulation: %s\n", tmp);
247 free(tmp);
248 return 1;
249 }
250 free(tmp);
251 flashchip_contents = malloc(emu_chip_size);
252 if (!flashchip_contents) {
253 msg_perr("Out of memory!\n");
254 return 1;
255 }
dhendrix0ffc2eb2011-06-14 01:35:36 +0000256
hailfinger6ead7222010-11-01 22:07:04 +0000257 msg_pdbg("Filling fake flash chip with 0xff, size %i\n", emu_chip_size);
258 memset(flashchip_contents, 0xff, emu_chip_size);
259
260 emu_persistent_image = extract_programmer_param("image");
261 if (!emu_persistent_image) {
262 /* Nothing else to do. */
dhendrix0ffc2eb2011-06-14 01:35:36 +0000263 goto dummy_init_out;
hailfinger6ead7222010-11-01 22:07:04 +0000264 }
265 if (!stat(emu_persistent_image, &image_stat)) {
266 msg_pdbg("Found persistent image %s, size %li ",
267 emu_persistent_image, (long)image_stat.st_size);
268 if (image_stat.st_size == emu_chip_size) {
269 msg_pdbg("matches.\n");
270 msg_pdbg("Reading %s\n", emu_persistent_image);
271 read_buf_from_file(flashchip_contents, emu_chip_size,
272 emu_persistent_image);
273 } else {
274 msg_pdbg("doesn't match.\n");
275 }
276 }
277#endif
hailfingera9df33c2009-05-09 00:54:55 +0000278
dhendrix0ffc2eb2011-06-14 01:35:36 +0000279dummy_init_out:
280 if (register_shutdown(dummy_shutdown, NULL)) {
hailfinger6ead7222010-11-01 22:07:04 +0000281 free(flashchip_contents);
dhendrix0ffc2eb2011-06-14 01:35:36 +0000282 return 1;
hailfinger6ead7222010-11-01 22:07:04 +0000283 }
hailfingera9df33c2009-05-09 00:54:55 +0000284 return 0;
285}
286
hailfinger11ae3c42009-05-11 14:13:25 +0000287void *dummy_map(const char *descr, unsigned long phys_addr, size_t len)
288{
hailfinger50c335f2010-01-09 04:32:23 +0000289 msg_pspew("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n",
290 __func__, descr, (unsigned long)len, phys_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000291 return (void *)phys_addr;
292}
293
294void dummy_unmap(void *virt_addr, size_t len)
295{
hailfinger50c335f2010-01-09 04:32:23 +0000296 msg_pspew("%s: Unmapping 0x%lx bytes at %p\n",
297 __func__, (unsigned long)len, virt_addr);
hailfinger11ae3c42009-05-11 14:13:25 +0000298}
299
hailfinger82719632009-05-16 21:22:56 +0000300void dummy_chip_writeb(uint8_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000301{
hailfinger50c335f2010-01-09 04:32:23 +0000302 msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000303}
304
hailfinger82719632009-05-16 21:22:56 +0000305void dummy_chip_writew(uint16_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000306{
hailfinger50c335f2010-01-09 04:32:23 +0000307 msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000308}
309
hailfinger82719632009-05-16 21:22:56 +0000310void dummy_chip_writel(uint32_t val, chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000311{
hailfinger50c335f2010-01-09 04:32:23 +0000312 msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val);
hailfingera9df33c2009-05-09 00:54:55 +0000313}
314
hailfinger9d987ef2009-06-05 18:32:07 +0000315void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len)
316{
317 size_t i;
hailfinger50c335f2010-01-09 04:32:23 +0000318 msg_pspew("%s: addr=0x%lx, len=0x%08lx, writing data (hex):",
319 __func__, addr, (unsigned long)len);
hailfinger9d987ef2009-06-05 18:32:07 +0000320 for (i = 0; i < len; i++) {
321 if ((i % 16) == 0)
hailfinger50c335f2010-01-09 04:32:23 +0000322 msg_pspew("\n");
323 msg_pspew("%02x ", buf[i]);
hailfinger9d987ef2009-06-05 18:32:07 +0000324 }
325}
326
hailfinger82719632009-05-16 21:22:56 +0000327uint8_t dummy_chip_readb(const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000328{
hailfinger50c335f2010-01-09 04:32:23 +0000329 msg_pspew("%s: addr=0x%lx, returning 0xff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000330 return 0xff;
331}
332
hailfinger82719632009-05-16 21:22:56 +0000333uint16_t dummy_chip_readw(const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000334{
hailfinger50c335f2010-01-09 04:32:23 +0000335 msg_pspew("%s: addr=0x%lx, returning 0xffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000336 return 0xffff;
337}
338
hailfinger82719632009-05-16 21:22:56 +0000339uint32_t dummy_chip_readl(const chipaddr addr)
hailfingera9df33c2009-05-09 00:54:55 +0000340{
hailfinger50c335f2010-01-09 04:32:23 +0000341 msg_pspew("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr);
hailfingera9df33c2009-05-09 00:54:55 +0000342 return 0xffffffff;
343}
344
hailfinger9d987ef2009-06-05 18:32:07 +0000345void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len)
346{
hailfinger50c335f2010-01-09 04:32:23 +0000347 msg_pspew("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n",
348 __func__, addr, (unsigned long)len);
hailfinger9d987ef2009-06-05 18:32:07 +0000349 memset(buf, 0xff, len);
350 return;
351}
352
hailfinger6ead7222010-11-01 22:07:04 +0000353#if EMULATE_SPI_CHIP
354static int emulate_spi_chip_response(unsigned int writecnt, unsigned int readcnt,
355 const unsigned char *writearr, unsigned char *readarr)
356{
357 int offs;
358 static int aai_offs;
359 static int aai_active = 0;
360
361 if (writecnt == 0) {
362 msg_perr("No command sent to the chip!\n");
363 return 1;
364 }
365 /* TODO: Implement command blacklists here. */
366 switch (writearr[0]) {
367 case JEDEC_RES:
368 if (emu_chip != EMULATE_ST_M25P10_RES)
369 break;
370 /* Respond with ST_M25P10_RES. */
371 if (readcnt > 0)
372 readarr[0] = 0x10;
373 break;
374 case JEDEC_REMS:
375 if (emu_chip != EMULATE_SST_SST25VF040_REMS)
376 break;
377 /* Respond with SST_SST25VF040_REMS. */
378 if (readcnt > 0)
379 readarr[0] = 0xbf;
380 if (readcnt > 1)
381 readarr[1] = 0x44;
382 break;
383 case JEDEC_RDID:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800384 if (emu_chip == EMULATE_SST_SST25VF032B) {
385 /* Respond with SST_SST25VF032B. */
386 if (readcnt > 0)
387 readarr[0] = 0xbf;
388 if (readcnt > 1)
389 readarr[1] = 0x25;
390 if (readcnt > 2)
391 readarr[2] = 0x4a;
392 } else if (emu_chip == EMULATE_VARIABLE_SIZE) {
393 const uint16_t man_id = VARIABLE_SIZE_MANUF_ID;
394 const uint16_t dev_id = VARIABLE_SIZE_DEVICE_ID;
395 if (readcnt > 0) readarr[0] = man_id >> 8;
396 if (readcnt > 1) readarr[1] = man_id & 0xff;
397 if (readcnt > 2) readarr[2] = dev_id >> 8;
398 if (readcnt > 3) readarr[3] = dev_id & 0xff;
399 }
hailfinger6ead7222010-11-01 22:07:04 +0000400 break;
401 case JEDEC_RDSR:
402 memset(readarr, 0, readcnt);
403 if (aai_active)
404 memset(readarr, 1 << 6, readcnt);
405 break;
406 case JEDEC_READ:
407 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
408 /* Truncate to emu_chip_size. */
409 offs %= emu_chip_size;
410 if (readcnt > 0)
411 memcpy(readarr, flashchip_contents + offs, readcnt);
412 break;
413 case JEDEC_BYTE_PROGRAM:
414 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
415 /* Truncate to emu_chip_size. */
416 offs %= emu_chip_size;
417 if (writecnt < 5) {
418 msg_perr("BYTE PROGRAM size too short!\n");
419 return 1;
420 }
421 if (writecnt - 4 > emu_max_byteprogram_size) {
422 msg_perr("Max BYTE PROGRAM size exceeded!\n");
423 return 1;
424 }
425 memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
426 break;
427 case JEDEC_AAI_WORD_PROGRAM:
428 if (!emu_max_aai_size)
429 break;
430 if (!aai_active) {
431 if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
432 msg_perr("Initial AAI WORD PROGRAM size too "
433 "short!\n");
434 return 1;
435 }
436 if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
437 msg_perr("Initial AAI WORD PROGRAM size too "
438 "long!\n");
439 return 1;
440 }
441 aai_active = 1;
442 aai_offs = writearr[1] << 16 | writearr[2] << 8 |
443 writearr[3];
444 /* Truncate to emu_chip_size. */
445 aai_offs %= emu_chip_size;
446 memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
447 aai_offs += 2;
448 } else {
449 if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
450 msg_perr("Continuation AAI WORD PROGRAM size "
451 "too short!\n");
452 return 1;
453 }
454 if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
455 msg_perr("Continuation AAI WORD PROGRAM size "
456 "too long!\n");
457 return 1;
458 }
459 memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
460 aai_offs += 2;
461 }
462 break;
463 case JEDEC_WRDI:
464 if (!emu_max_aai_size)
465 break;
466 aai_active = 0;
467 break;
468 case JEDEC_SE:
469 if (!emu_jedec_se_size)
470 break;
471 if (writecnt != JEDEC_SE_OUTSIZE) {
472 msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
473 return 1;
474 }
475 if (readcnt != JEDEC_SE_INSIZE) {
476 msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
477 return 1;
478 }
479 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
480 if (offs & (emu_jedec_se_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000481 msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000482 offs &= ~(emu_jedec_se_size - 1);
483 memset(flashchip_contents + offs, 0xff, emu_jedec_se_size);
484 break;
485 case JEDEC_BE_52:
486 if (!emu_jedec_be_52_size)
487 break;
488 if (writecnt != JEDEC_BE_52_OUTSIZE) {
489 msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
490 return 1;
491 }
492 if (readcnt != JEDEC_BE_52_INSIZE) {
493 msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
494 return 1;
495 }
496 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
497 if (offs & (emu_jedec_be_52_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000498 msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000499 offs &= ~(emu_jedec_be_52_size - 1);
500 memset(flashchip_contents + offs, 0xff, emu_jedec_be_52_size);
501 break;
502 case JEDEC_BE_D8:
503 if (!emu_jedec_be_d8_size)
504 break;
505 if (writecnt != JEDEC_BE_D8_OUTSIZE) {
506 msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
507 return 1;
508 }
509 if (readcnt != JEDEC_BE_D8_INSIZE) {
510 msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
511 return 1;
512 }
513 offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
514 if (offs & (emu_jedec_be_d8_size - 1))
hailfingere53f5e42011-02-04 22:52:04 +0000515 msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
hailfinger6ead7222010-11-01 22:07:04 +0000516 offs &= ~(emu_jedec_be_d8_size - 1);
517 memset(flashchip_contents + offs, 0xff, emu_jedec_be_d8_size);
518 break;
519 case JEDEC_CE_60:
520 if (!emu_jedec_ce_60_size)
521 break;
522 if (writecnt != JEDEC_CE_60_OUTSIZE) {
523 msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
524 return 1;
525 }
526 if (readcnt != JEDEC_CE_60_INSIZE) {
527 msg_perr("CHIP ERASE 0x60 insize invalid!\n");
528 return 1;
529 }
hailfingere53f5e42011-02-04 22:52:04 +0000530 /* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000531 /* emu_jedec_ce_60_size is emu_chip_size. */
hailfingere53f5e42011-02-04 22:52:04 +0000532 memset(flashchip_contents, 0xff, emu_jedec_ce_60_size);
hailfinger6ead7222010-11-01 22:07:04 +0000533 break;
534 case JEDEC_CE_C7:
535 if (!emu_jedec_ce_c7_size)
536 break;
537 if (writecnt != JEDEC_CE_C7_OUTSIZE) {
538 msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
539 return 1;
540 }
541 if (readcnt != JEDEC_CE_C7_INSIZE) {
542 msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
543 return 1;
544 }
hailfingere53f5e42011-02-04 22:52:04 +0000545 /* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
hailfinger6ead7222010-11-01 22:07:04 +0000546 /* emu_jedec_ce_c7_size is emu_chip_size. */
547 memset(flashchip_contents, 0xff, emu_jedec_ce_c7_size);
548 break;
549 default:
550 /* No special response. */
551 break;
552 }
553 return 0;
554}
555#endif
556
mkarcherd264e9e2011-05-11 17:07:07 +0000557static int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt,
hailfingerf91e3b52009-05-14 12:59:36 +0000558 const unsigned char *writearr, unsigned char *readarr)
559{
560 int i;
561
hailfinger50c335f2010-01-09 04:32:23 +0000562 msg_pspew("%s:", __func__);
hailfingerf91e3b52009-05-14 12:59:36 +0000563
hailfinger50c335f2010-01-09 04:32:23 +0000564 msg_pspew(" writing %u bytes:", writecnt);
hailfingerf91e3b52009-05-14 12:59:36 +0000565 for (i = 0; i < writecnt; i++)
hailfinger50c335f2010-01-09 04:32:23 +0000566 msg_pspew(" 0x%02x", writearr[i]);
hailfingerf91e3b52009-05-14 12:59:36 +0000567
hailfinger6ead7222010-11-01 22:07:04 +0000568 /* Response for unknown commands and missing chip is 0xff. */
569 memset(readarr, 0xff, readcnt);
570#if EMULATE_SPI_CHIP
571 switch (emu_chip) {
572 case EMULATE_ST_M25P10_RES:
573 case EMULATE_SST_SST25VF040_REMS:
574 case EMULATE_SST_SST25VF032B:
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800575 case EMULATE_VARIABLE_SIZE:
hailfinger6ead7222010-11-01 22:07:04 +0000576 if (emulate_spi_chip_response(writecnt, readcnt, writearr,
577 readarr)) {
578 msg_perr("Invalid command sent to flash chip!\n");
579 return 1;
580 }
581 break;
582 default:
583 break;
584 }
585#endif
hailfinger50c335f2010-01-09 04:32:23 +0000586 msg_pspew(" reading %u bytes:", readcnt);
uwe8d342eb2011-07-28 08:13:25 +0000587 for (i = 0; i < readcnt; i++)
hailfinger6ead7222010-11-01 22:07:04 +0000588 msg_pspew(" 0x%02x", readarr[i]);
hailfinger50c335f2010-01-09 04:32:23 +0000589 msg_pspew("\n");
hailfingerf91e3b52009-05-14 12:59:36 +0000590 return 0;
591}
hailfingera8727712010-06-20 10:58:32 +0000592
uwe8d342eb2011-07-28 08:13:25 +0000593static int dummy_spi_write_256(struct flashchip *flash, uint8_t *buf,
594 int start, int len)
hailfingerc7d06c62010-07-14 16:19:05 +0000595{
hailfinger6ead7222010-11-01 22:07:04 +0000596 return spi_write_chunked(flash, buf, start, len,
597 spi_write_256_chunksize);
hailfingerc7d06c62010-07-14 16:19:05 +0000598}
Louis Yung-Chieh Loe53fa0f2011-04-11 17:18:41 +0800599
600#if EMULATE_CHIP && EMULATE_SPI_CHIP
601int probe_variable_size(struct flashchip *flash)
602{
603 int i;
604
605 /* Skip the probing if we don't emulate this chip. */
606 if (emu_chip != EMULATE_VARIABLE_SIZE)
607 return 0;
608
609 /*
610 * This will break if one day flashchip becomes read-only.
611 * Once that happens, we need to have special hacks in functions:
612 *
613 * erase_and_write_flash() in flashrom.c
614 * read_flash_to_file()
615 * handle_romentries()
616 * ...
617 *
618 * Search "total_size * 1024" in code.
619 */
620 if (emu_chip_size % 1024)
621 msg_perr("%s: emu_chip_size is not multipler of 1024.\n",
622 __func__);
623 flash->total_size = emu_chip_size / 1024;
624 msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
625 flash->total_size);
626
627 /* Update eraser count */
628 for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
629 struct block_eraser *eraser = &flash->block_erasers[i];
630 if (eraser->block_erase == NULL)
631 break;
632
633 eraser->eraseblocks[0].count = emu_chip_size /
634 eraser->eraseblocks[0].size;
635 msg_cdbg("%s: eraser.size=%d, .count=%d\n",
636 __func__, eraser->eraseblocks[0].size,
637 eraser->eraseblocks[0].count);
638 }
639
640 return 1;
641}
642#endif