xref: /aosp_15_r20/external/flashrom/dummyflasher.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
5*0d6140beSAndroid Build Coastguard Worker  *
6*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
7*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
8*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; version 2 of the License.
9*0d6140beSAndroid Build Coastguard Worker  *
10*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
11*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
14*0d6140beSAndroid Build Coastguard Worker  */
15*0d6140beSAndroid Build Coastguard Worker 
16*0d6140beSAndroid Build Coastguard Worker #include <assert.h>
17*0d6140beSAndroid Build Coastguard Worker #include <string.h>
18*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
19*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
20*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
21*0d6140beSAndroid Build Coastguard Worker #include <ctype.h>
22*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
23*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
24*0d6140beSAndroid Build Coastguard Worker #include <sys/stat.h>
25*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
26*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
27*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
28*0d6140beSAndroid Build Coastguard Worker #include "flashchips.h"
29*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
30*0d6140beSAndroid Build Coastguard Worker #include "writeprotect.h"
31*0d6140beSAndroid Build Coastguard Worker 
32*0d6140beSAndroid Build Coastguard Worker enum emu_chip {
33*0d6140beSAndroid Build Coastguard Worker 	EMULATE_NONE,
34*0d6140beSAndroid Build Coastguard Worker 	EMULATE_ST_M25P10_RES,
35*0d6140beSAndroid Build Coastguard Worker 	EMULATE_SST_SST25VF040_REMS,
36*0d6140beSAndroid Build Coastguard Worker 	EMULATE_SST_SST25VF032B,
37*0d6140beSAndroid Build Coastguard Worker 	EMULATE_MACRONIX_MX25L6436,
38*0d6140beSAndroid Build Coastguard Worker 	EMULATE_WINBOND_W25Q128FV,
39*0d6140beSAndroid Build Coastguard Worker 	EMULATE_SPANSION_S25FL128L,
40*0d6140beSAndroid Build Coastguard Worker 	EMULATE_VARIABLE_SIZE,
41*0d6140beSAndroid Build Coastguard Worker };
42*0d6140beSAndroid Build Coastguard Worker 
43*0d6140beSAndroid Build Coastguard Worker struct emu_data {
44*0d6140beSAndroid Build Coastguard Worker 	enum emu_chip emu_chip;
45*0d6140beSAndroid Build Coastguard Worker 	char *emu_persistent_image;
46*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_chip_size;
47*0d6140beSAndroid Build Coastguard Worker 	/* Note: W25Q128FV doesn't change value of SR2 if it's not provided, but
48*0d6140beSAndroid Build Coastguard Worker 	 *       even its previous generations do, so don't forget to update
49*0d6140beSAndroid Build Coastguard Worker 	 *       WRSR code on enabling WRSR_EXT2 for more chips. */
50*0d6140beSAndroid Build Coastguard Worker 	bool emu_wrsr_ext2;
51*0d6140beSAndroid Build Coastguard Worker 	bool emu_wrsr_ext3;
52*0d6140beSAndroid Build Coastguard Worker 	bool erase_to_zero;
53*0d6140beSAndroid Build Coastguard Worker 	bool emu_modified;	/* is the image modified since reading it? */
54*0d6140beSAndroid Build Coastguard Worker 	uint8_t emu_status[3];
55*0d6140beSAndroid Build Coastguard Worker 	uint8_t emu_status_len;	/* number of emulated status registers */
56*0d6140beSAndroid Build Coastguard Worker 	/* If "freq" parameter is passed in from command line, commands will delay
57*0d6140beSAndroid Build Coastguard Worker 	 * for this period before returning. */
58*0d6140beSAndroid Build Coastguard Worker 	unsigned long long delay_ns;
59*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_max_byteprogram_size;
60*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_max_aai_size;
61*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_jedec_se_size;
62*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_jedec_be_52_size;
63*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_jedec_be_d8_size;
64*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_jedec_ce_60_size;
65*0d6140beSAndroid Build Coastguard Worker 	unsigned int emu_jedec_ce_c7_size;
66*0d6140beSAndroid Build Coastguard Worker 	unsigned char spi_blacklist[256];
67*0d6140beSAndroid Build Coastguard Worker 	unsigned char spi_ignorelist[256];
68*0d6140beSAndroid Build Coastguard Worker 	unsigned int spi_blacklist_size;
69*0d6140beSAndroid Build Coastguard Worker 	unsigned int spi_ignorelist_size;
70*0d6140beSAndroid Build Coastguard Worker 
71*0d6140beSAndroid Build Coastguard Worker 	bool hwwp;	/* state of hardware write protection */
72*0d6140beSAndroid Build Coastguard Worker 	/* wp_start == wp_end when write-protection is disabled */
73*0d6140beSAndroid Build Coastguard Worker 	uint32_t wp_start;
74*0d6140beSAndroid Build Coastguard Worker 	uint32_t wp_end;
75*0d6140beSAndroid Build Coastguard Worker 
76*0d6140beSAndroid Build Coastguard Worker 	unsigned int spi_write_256_chunksize;
77*0d6140beSAndroid Build Coastguard Worker 	uint8_t *flashchip_contents;
78*0d6140beSAndroid Build Coastguard Worker 
79*0d6140beSAndroid Build Coastguard Worker 	/* An instance of this structure is shared between multiple masters, so
80*0d6140beSAndroid Build Coastguard Worker 	 * store the number of references to clean up only once at shutdown time. */
81*0d6140beSAndroid Build Coastguard Worker 	uint8_t refs_cnt;
82*0d6140beSAndroid Build Coastguard Worker };
83*0d6140beSAndroid Build Coastguard Worker 
84*0d6140beSAndroid Build Coastguard Worker /* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
85*0d6140beSAndroid Build Coastguard Worker static const uint8_t sfdp_table[] = {
86*0d6140beSAndroid Build Coastguard Worker 	0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
87*0d6140beSAndroid Build Coastguard Worker 	0x00, 0x01, 0x01, 0xFF, // @0x04: revision 1.0, 2 headers
88*0d6140beSAndroid Build Coastguard Worker 	0x00, 0x00, 0x01, 0x09, // @0x08: JEDEC SFDP header rev. 1.0, 9 DW long
89*0d6140beSAndroid Build Coastguard Worker 	0x1C, 0x00, 0x00, 0xFF, // @0x0C: PTP0 = 0x1C (instead of 0x30)
90*0d6140beSAndroid Build Coastguard Worker 	0xC2, 0x00, 0x01, 0x04, // @0x10: Macronix header rev. 1.0, 4 DW long
91*0d6140beSAndroid Build Coastguard Worker 	0x48, 0x00, 0x00, 0xFF, // @0x14: PTP1 = 0x48 (instead of 0x60)
92*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0xFF, 0xFF, // @0x18: hole.
93*0d6140beSAndroid Build Coastguard Worker 	0xE5, 0x20, 0xC9, 0xFF, // @0x1C: SFDP parameter table start
94*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0xFF, 0x03, // @0x20
95*0d6140beSAndroid Build Coastguard Worker 	0x00, 0xFF, 0x08, 0x6B, // @0x24
96*0d6140beSAndroid Build Coastguard Worker 	0x08, 0x3B, 0x00, 0xFF, // @0x28
97*0d6140beSAndroid Build Coastguard Worker 	0xEE, 0xFF, 0xFF, 0xFF, // @0x2C
98*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0x00, 0x00, // @0x30
99*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0x00, 0xFF, // @0x34
100*0d6140beSAndroid Build Coastguard Worker 	0x0C, 0x20, 0x0F, 0x52, // @0x38
101*0d6140beSAndroid Build Coastguard Worker 	0x10, 0xD8, 0x00, 0xFF, // @0x3C: SFDP parameter table end
102*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0xFF, 0xFF, // @0x40: hole.
103*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0xFF, 0xFF, // @0x44: hole.
104*0d6140beSAndroid Build Coastguard Worker 	0x00, 0x36, 0x00, 0x27, // @0x48: Macronix parameter table start
105*0d6140beSAndroid Build Coastguard Worker 	0xF4, 0x4F, 0xFF, 0xFF, // @0x4C
106*0d6140beSAndroid Build Coastguard Worker 	0xD9, 0xC8, 0xFF, 0xFF, // @0x50
107*0d6140beSAndroid Build Coastguard Worker 	0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
108*0d6140beSAndroid Build Coastguard Worker };
109*0d6140beSAndroid Build Coastguard Worker 
dummy_map(const char * descr,uintptr_t phys_addr,size_t len)110*0d6140beSAndroid Build Coastguard Worker static void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
111*0d6140beSAndroid Build Coastguard Worker {
112*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
113*0d6140beSAndroid Build Coastguard Worker 		  __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
114*0d6140beSAndroid Build Coastguard Worker 	return (void *)phys_addr;
115*0d6140beSAndroid Build Coastguard Worker }
116*0d6140beSAndroid Build Coastguard Worker 
dummy_unmap(void * virt_addr,size_t len)117*0d6140beSAndroid Build Coastguard Worker static void dummy_unmap(void *virt_addr, size_t len)
118*0d6140beSAndroid Build Coastguard Worker {
119*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
120*0d6140beSAndroid Build Coastguard Worker }
121*0d6140beSAndroid Build Coastguard Worker 
dummy_spi_write_256(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)122*0d6140beSAndroid Build Coastguard Worker static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
123*0d6140beSAndroid Build Coastguard Worker {
124*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *emu_data = flash->mst->spi.data;
125*0d6140beSAndroid Build Coastguard Worker 	return spi_write_chunked(flash, buf, start, len,
126*0d6140beSAndroid Build Coastguard Worker 				 emu_data->spi_write_256_chunksize);
127*0d6140beSAndroid Build Coastguard Worker }
128*0d6140beSAndroid Build Coastguard Worker 
dummy_spi_probe_opcode(const struct flashctx * flash,uint8_t opcode)129*0d6140beSAndroid Build Coastguard Worker static bool dummy_spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
130*0d6140beSAndroid Build Coastguard Worker {
131*0d6140beSAndroid Build Coastguard Worker 	size_t i;
132*0d6140beSAndroid Build Coastguard Worker 	const struct emu_data *emu_data = flash->mst->spi.data;
133*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < emu_data->spi_blacklist_size; i++) {
134*0d6140beSAndroid Build Coastguard Worker 		if (emu_data->spi_blacklist[i] == opcode)
135*0d6140beSAndroid Build Coastguard Worker 			return false;
136*0d6140beSAndroid Build Coastguard Worker 	}
137*0d6140beSAndroid Build Coastguard Worker 	return true;
138*0d6140beSAndroid Build Coastguard Worker }
139*0d6140beSAndroid Build Coastguard Worker 
probe_variable_size(struct flashctx * flash)140*0d6140beSAndroid Build Coastguard Worker static int probe_variable_size(struct flashctx *flash)
141*0d6140beSAndroid Build Coastguard Worker {
142*0d6140beSAndroid Build Coastguard Worker 	const struct emu_data *emu_data = flash->mst->opaque.data;
143*0d6140beSAndroid Build Coastguard Worker 
144*0d6140beSAndroid Build Coastguard Worker 	/* Skip the probing if we don't emulate "variable size" chip. */
145*0d6140beSAndroid Build Coastguard Worker 	if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
146*0d6140beSAndroid Build Coastguard Worker 		return 0;
147*0d6140beSAndroid Build Coastguard Worker 
148*0d6140beSAndroid Build Coastguard Worker 	flash->chip->total_size = emu_data->emu_chip_size / 1024;
149*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
150*0d6140beSAndroid Build Coastguard Worker 	         flash->chip->total_size);
151*0d6140beSAndroid Build Coastguard Worker 
152*0d6140beSAndroid Build Coastguard Worker 	flash->chip->tested = TEST_OK_PREWB;
153*0d6140beSAndroid Build Coastguard Worker 
154*0d6140beSAndroid Build Coastguard Worker 	if (emu_data->erase_to_zero)
155*0d6140beSAndroid Build Coastguard Worker 		flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
156*0d6140beSAndroid Build Coastguard Worker 
157*0d6140beSAndroid Build Coastguard Worker 	/*
158*0d6140beSAndroid Build Coastguard Worker 	 * Update the first count of the block_eraser.
159*0d6140beSAndroid Build Coastguard Worker 	 * Opaque flash chip entry in flashchips.c has only one block eraser.
160*0d6140beSAndroid Build Coastguard Worker 	 *
161*0d6140beSAndroid Build Coastguard Worker 	 * If this changes in future, the code below needs to be adjusted
162*0d6140beSAndroid Build Coastguard Worker 	 * to update all block erasers.
163*0d6140beSAndroid Build Coastguard Worker 	 */
164*0d6140beSAndroid Build Coastguard Worker 	struct block_eraser *eraser = &flash->chip->block_erasers[0];
165*0d6140beSAndroid Build Coastguard Worker 	if (!eraser->block_erase)
166*0d6140beSAndroid Build Coastguard Worker 		return 1;
167*0d6140beSAndroid Build Coastguard Worker 
168*0d6140beSAndroid Build Coastguard Worker 	eraser->eraseblocks[0].count = 1;
169*0d6140beSAndroid Build Coastguard Worker 	eraser->eraseblocks[0].size = emu_data->emu_chip_size;
170*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: eraser.size=%d, .count=%d\n",
171*0d6140beSAndroid Build Coastguard Worker 		 __func__, eraser->eraseblocks[0].size,
172*0d6140beSAndroid Build Coastguard Worker 		 eraser->eraseblocks[0].count);
173*0d6140beSAndroid Build Coastguard Worker 
174*0d6140beSAndroid Build Coastguard Worker 	return 1;
175*0d6140beSAndroid Build Coastguard Worker }
176*0d6140beSAndroid Build Coastguard Worker 
dummy_opaque_read(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)177*0d6140beSAndroid Build Coastguard Worker static int dummy_opaque_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
178*0d6140beSAndroid Build Coastguard Worker {
179*0d6140beSAndroid Build Coastguard Worker 	const struct emu_data *emu_data = flash->mst->opaque.data;
180*0d6140beSAndroid Build Coastguard Worker 
181*0d6140beSAndroid Build Coastguard Worker 	memcpy(buf, emu_data->flashchip_contents + start, len);
182*0d6140beSAndroid Build Coastguard Worker 
183*0d6140beSAndroid Build Coastguard Worker 	return 0;
184*0d6140beSAndroid Build Coastguard Worker }
185*0d6140beSAndroid Build Coastguard Worker 
dummy_opaque_write(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)186*0d6140beSAndroid Build Coastguard Worker static int dummy_opaque_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
187*0d6140beSAndroid Build Coastguard Worker {
188*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *emu_data = flash->mst->opaque.data;
189*0d6140beSAndroid Build Coastguard Worker 
190*0d6140beSAndroid Build Coastguard Worker 	memcpy(emu_data->flashchip_contents + start, buf, len);
191*0d6140beSAndroid Build Coastguard Worker 	emu_data->emu_modified = true;
192*0d6140beSAndroid Build Coastguard Worker 
193*0d6140beSAndroid Build Coastguard Worker 	return 0;
194*0d6140beSAndroid Build Coastguard Worker }
195*0d6140beSAndroid Build Coastguard Worker 
dummy_opaque_erase(struct flashctx * flash,unsigned int blockaddr,unsigned int blocklen)196*0d6140beSAndroid Build Coastguard Worker static int dummy_opaque_erase(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
197*0d6140beSAndroid Build Coastguard Worker {
198*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *emu_data = flash->mst->opaque.data;
199*0d6140beSAndroid Build Coastguard Worker 
200*0d6140beSAndroid Build Coastguard Worker 	memset(emu_data->flashchip_contents + blockaddr, emu_data->erase_to_zero ? 0x00 : 0xff, blocklen);
201*0d6140beSAndroid Build Coastguard Worker 	emu_data->emu_modified = true;
202*0d6140beSAndroid Build Coastguard Worker 
203*0d6140beSAndroid Build Coastguard Worker 	return 0;
204*0d6140beSAndroid Build Coastguard Worker }
205*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_writeb(const struct flashctx * flash,uint8_t val,chipaddr addr)206*0d6140beSAndroid Build Coastguard Worker static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
207*0d6140beSAndroid Build Coastguard Worker {
208*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%02x\n", __func__, addr, val);
209*0d6140beSAndroid Build Coastguard Worker }
210*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_writew(const struct flashctx * flash,uint16_t val,chipaddr addr)211*0d6140beSAndroid Build Coastguard Worker static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
212*0d6140beSAndroid Build Coastguard Worker {
213*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%04x\n", __func__, addr, val);
214*0d6140beSAndroid Build Coastguard Worker }
215*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_writel(const struct flashctx * flash,uint32_t val,chipaddr addr)216*0d6140beSAndroid Build Coastguard Worker static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
217*0d6140beSAndroid Build Coastguard Worker {
218*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08"PRIx32"\n", __func__, addr, val);
219*0d6140beSAndroid Build Coastguard Worker }
220*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_writen(const struct flashctx * flash,const uint8_t * buf,chipaddr addr,size_t len)221*0d6140beSAndroid Build Coastguard Worker static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
222*0d6140beSAndroid Build Coastguard Worker {
223*0d6140beSAndroid Build Coastguard Worker 	size_t i;
224*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: addr=0x%" PRIxPTR ", len=0x%zx, writing data (hex):", __func__, addr, len);
225*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
226*0d6140beSAndroid Build Coastguard Worker 		if ((i % 16) == 0)
227*0d6140beSAndroid Build Coastguard Worker 			msg_pspew("\n");
228*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("%02x ", buf[i]);
229*0d6140beSAndroid Build Coastguard Worker 	}
230*0d6140beSAndroid Build Coastguard Worker }
231*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_readb(const struct flashctx * flash,const chipaddr addr)232*0d6140beSAndroid Build Coastguard Worker static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr)
233*0d6140beSAndroid Build Coastguard Worker {
234*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s:  addr=0x%" PRIxPTR ", returning 0xff\n", __func__, addr);
235*0d6140beSAndroid Build Coastguard Worker 	return 0xff;
236*0d6140beSAndroid Build Coastguard Worker }
237*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_readw(const struct flashctx * flash,const chipaddr addr)238*0d6140beSAndroid Build Coastguard Worker static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr)
239*0d6140beSAndroid Build Coastguard Worker {
240*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s:  addr=0x%" PRIxPTR ", returning 0xffff\n", __func__, addr);
241*0d6140beSAndroid Build Coastguard Worker 	return 0xffff;
242*0d6140beSAndroid Build Coastguard Worker }
243*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_readl(const struct flashctx * flash,const chipaddr addr)244*0d6140beSAndroid Build Coastguard Worker static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr)
245*0d6140beSAndroid Build Coastguard Worker {
246*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s:  addr=0x%" PRIxPTR ", returning 0xffffffff\n", __func__, addr);
247*0d6140beSAndroid Build Coastguard Worker 	return 0xffffffff;
248*0d6140beSAndroid Build Coastguard Worker }
249*0d6140beSAndroid Build Coastguard Worker 
dummy_chip_readn(const struct flashctx * flash,uint8_t * buf,const chipaddr addr,size_t len)250*0d6140beSAndroid Build Coastguard Worker static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len)
251*0d6140beSAndroid Build Coastguard Worker {
252*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s:  addr=0x%" PRIxPTR ", len=0x%zx, returning array of 0xff\n", __func__, addr, len);
253*0d6140beSAndroid Build Coastguard Worker 	memset(buf, 0xff, len);
254*0d6140beSAndroid Build Coastguard Worker 	return;
255*0d6140beSAndroid Build Coastguard Worker }
256*0d6140beSAndroid Build Coastguard Worker 
get_reg_ro_bit_mask(const struct emu_data * data,enum flash_reg reg)257*0d6140beSAndroid Build Coastguard Worker static uint8_t get_reg_ro_bit_mask(const struct emu_data *data, enum flash_reg reg)
258*0d6140beSAndroid Build Coastguard Worker {
259*0d6140beSAndroid Build Coastguard Worker 	/* Whoever adds a new register must not forget to update this function
260*0d6140beSAndroid Build Coastguard Worker 	   or at least shouldn't use it incorrectly. */
261*0d6140beSAndroid Build Coastguard Worker 	assert(reg == STATUS1 || reg == STATUS2 || reg == STATUS3);
262*0d6140beSAndroid Build Coastguard Worker 
263*0d6140beSAndroid Build Coastguard Worker 	uint8_t ro_bits = reg == STATUS1 ? SPI_SR_WIP : 0;
264*0d6140beSAndroid Build Coastguard Worker 
265*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_chip == EMULATE_WINBOND_W25Q128FV) {
266*0d6140beSAndroid Build Coastguard Worker 		const bool srp0 = (data->emu_status[0] >> 7);
267*0d6140beSAndroid Build Coastguard Worker 		const bool srp1 = (data->emu_status[1] & 1);
268*0d6140beSAndroid Build Coastguard Worker 
269*0d6140beSAndroid Build Coastguard Worker 		const bool wp_active = (srp1 || (srp0 && data->hwwp));
270*0d6140beSAndroid Build Coastguard Worker 
271*0d6140beSAndroid Build Coastguard Worker 		if (wp_active) {
272*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0xff;
273*0d6140beSAndroid Build Coastguard Worker 		} else if (reg == STATUS2) {
274*0d6140beSAndroid Build Coastguard Worker 			/* SUS (bit_7) and (R) (bit_2). */
275*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0x84;
276*0d6140beSAndroid Build Coastguard Worker 			/* Once any of the lock bits (LB[1..3]) are set, they
277*0d6140beSAndroid Build Coastguard Worker 			   can't be unset. */
278*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 3);
279*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 4);
280*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 5);
281*0d6140beSAndroid Build Coastguard Worker 		} else if (reg == STATUS3) {
282*0d6140beSAndroid Build Coastguard Worker 			/* Four reserved bits. */
283*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0x1b;
284*0d6140beSAndroid Build Coastguard Worker 		}
285*0d6140beSAndroid Build Coastguard Worker 	}
286*0d6140beSAndroid Build Coastguard Worker 
287*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_chip == EMULATE_SPANSION_S25FL128L) {
288*0d6140beSAndroid Build Coastguard Worker 		const bool srp0 = (data->emu_status[0] >> 7);
289*0d6140beSAndroid Build Coastguard Worker 		const bool srp1 = (data->emu_status[1] & 1);
290*0d6140beSAndroid Build Coastguard Worker 
291*0d6140beSAndroid Build Coastguard Worker 		const bool wp_active = (srp1 || (srp0 && data->hwwp));
292*0d6140beSAndroid Build Coastguard Worker 
293*0d6140beSAndroid Build Coastguard Worker 		if (wp_active) {
294*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0xff;
295*0d6140beSAndroid Build Coastguard Worker 		} else if (reg == STATUS2) {
296*0d6140beSAndroid Build Coastguard Worker 			/* SUS (bit_7) */
297*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0x80;
298*0d6140beSAndroid Build Coastguard Worker 			/* Once any of the lock bits (LB[0..3]) are set, they
299*0d6140beSAndroid Build Coastguard Worker 			   can't be unset. */
300*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 2);
301*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 3);
302*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 4);
303*0d6140beSAndroid Build Coastguard Worker 			ro_bits |= data->emu_status[1] & (1 << 5);
304*0d6140beSAndroid Build Coastguard Worker 		} else if (reg == STATUS3) {
305*0d6140beSAndroid Build Coastguard Worker 			/* Two reserved bits. */
306*0d6140beSAndroid Build Coastguard Worker 			ro_bits = 0x11;
307*0d6140beSAndroid Build Coastguard Worker 		}
308*0d6140beSAndroid Build Coastguard Worker 	}
309*0d6140beSAndroid Build Coastguard Worker 
310*0d6140beSAndroid Build Coastguard Worker 	return ro_bits;
311*0d6140beSAndroid Build Coastguard Worker }
312*0d6140beSAndroid Build Coastguard Worker 
update_write_protection(struct emu_data * data)313*0d6140beSAndroid Build Coastguard Worker static void update_write_protection(struct emu_data *data)
314*0d6140beSAndroid Build Coastguard Worker {
315*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_chip != EMULATE_WINBOND_W25Q128FV &&
316*0d6140beSAndroid Build Coastguard Worker 	    data->emu_chip != EMULATE_SPANSION_S25FL128L)
317*0d6140beSAndroid Build Coastguard Worker 		return;
318*0d6140beSAndroid Build Coastguard Worker 
319*0d6140beSAndroid Build Coastguard Worker 	const struct wp_bits bits = {
320*0d6140beSAndroid Build Coastguard Worker 		.srp = data->emu_status[0] >> 7,
321*0d6140beSAndroid Build Coastguard Worker 		.srl = data->emu_status[1] & 1,
322*0d6140beSAndroid Build Coastguard Worker 
323*0d6140beSAndroid Build Coastguard Worker 		.bp_bit_count = 3,
324*0d6140beSAndroid Build Coastguard Worker 		.bp =
325*0d6140beSAndroid Build Coastguard Worker 		{
326*0d6140beSAndroid Build Coastguard Worker 			(data->emu_status[0] >> 2) & 1,
327*0d6140beSAndroid Build Coastguard Worker 			(data->emu_status[0] >> 3) & 1,
328*0d6140beSAndroid Build Coastguard Worker 			(data->emu_status[0] >> 4) & 1
329*0d6140beSAndroid Build Coastguard Worker 		},
330*0d6140beSAndroid Build Coastguard Worker 
331*0d6140beSAndroid Build Coastguard Worker 		.tb_bit_present = true,
332*0d6140beSAndroid Build Coastguard Worker 		.tb = (data->emu_status[0] >> 5) & 1,
333*0d6140beSAndroid Build Coastguard Worker 
334*0d6140beSAndroid Build Coastguard Worker 		.sec_bit_present = true,
335*0d6140beSAndroid Build Coastguard Worker 		.sec = (data->emu_status[0] >> 6) & 1,
336*0d6140beSAndroid Build Coastguard Worker 
337*0d6140beSAndroid Build Coastguard Worker 		.cmp_bit_present = true,
338*0d6140beSAndroid Build Coastguard Worker 		.cmp = (data->emu_status[1] >> 6) & 1,
339*0d6140beSAndroid Build Coastguard Worker 	};
340*0d6140beSAndroid Build Coastguard Worker 
341*0d6140beSAndroid Build Coastguard Worker 	size_t start;
342*0d6140beSAndroid Build Coastguard Worker 	size_t len;
343*0d6140beSAndroid Build Coastguard Worker 	decode_range_spi25(&start, &len, &bits, data->emu_chip_size);
344*0d6140beSAndroid Build Coastguard Worker 
345*0d6140beSAndroid Build Coastguard Worker 	data->wp_start = start;
346*0d6140beSAndroid Build Coastguard Worker 	data->wp_end = start + len;
347*0d6140beSAndroid Build Coastguard Worker }
348*0d6140beSAndroid Build Coastguard Worker 
349*0d6140beSAndroid Build Coastguard Worker /* Checks whether range intersects a write-protected area of the flash if one is
350*0d6140beSAndroid Build Coastguard Worker  * defined. */
is_write_protected(const struct emu_data * data,uint32_t start,uint32_t len)351*0d6140beSAndroid Build Coastguard Worker static bool is_write_protected(const struct emu_data *data, uint32_t start, uint32_t len)
352*0d6140beSAndroid Build Coastguard Worker {
353*0d6140beSAndroid Build Coastguard Worker 	if (len == 0)
354*0d6140beSAndroid Build Coastguard Worker 		return false;
355*0d6140beSAndroid Build Coastguard Worker 
356*0d6140beSAndroid Build Coastguard Worker 	const uint32_t last = start + len - 1;
357*0d6140beSAndroid Build Coastguard Worker 	return (start < data->wp_end && last >= data->wp_start);
358*0d6140beSAndroid Build Coastguard Worker }
359*0d6140beSAndroid Build Coastguard Worker 
360*0d6140beSAndroid Build Coastguard Worker /* Returns non-zero on error. */
write_flash_data(struct emu_data * data,uint32_t start,uint32_t len,const uint8_t * buf)361*0d6140beSAndroid Build Coastguard Worker static int write_flash_data(struct emu_data *data, uint32_t start, uint32_t len, const uint8_t *buf)
362*0d6140beSAndroid Build Coastguard Worker {
363*0d6140beSAndroid Build Coastguard Worker 	if (is_write_protected(data, start, len)) {
364*0d6140beSAndroid Build Coastguard Worker 		msg_perr("At least part of the write range is write protected!\n");
365*0d6140beSAndroid Build Coastguard Worker 		return 1;
366*0d6140beSAndroid Build Coastguard Worker 	}
367*0d6140beSAndroid Build Coastguard Worker 
368*0d6140beSAndroid Build Coastguard Worker 	memcpy(data->flashchip_contents + start, buf, len);
369*0d6140beSAndroid Build Coastguard Worker 	data->emu_modified = true;
370*0d6140beSAndroid Build Coastguard Worker 	return 0;
371*0d6140beSAndroid Build Coastguard Worker }
372*0d6140beSAndroid Build Coastguard Worker 
373*0d6140beSAndroid Build Coastguard Worker /* Returns non-zero on error. */
erase_flash_data(struct emu_data * data,uint32_t start,uint32_t len)374*0d6140beSAndroid Build Coastguard Worker static int erase_flash_data(struct emu_data *data, uint32_t start, uint32_t len)
375*0d6140beSAndroid Build Coastguard Worker {
376*0d6140beSAndroid Build Coastguard Worker 	if (is_write_protected(data, start, len)) {
377*0d6140beSAndroid Build Coastguard Worker 		msg_perr("At least part of the erase range is write protected!\n");
378*0d6140beSAndroid Build Coastguard Worker 		return 1;
379*0d6140beSAndroid Build Coastguard Worker 	}
380*0d6140beSAndroid Build Coastguard Worker 
381*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: Maybe use ERASED_VALUE(flash) instead of 0xff ? */
382*0d6140beSAndroid Build Coastguard Worker 	memset(data->flashchip_contents + start, 0xff, len);
383*0d6140beSAndroid Build Coastguard Worker 	data->emu_modified = true;
384*0d6140beSAndroid Build Coastguard Worker 	return 0;
385*0d6140beSAndroid Build Coastguard Worker }
386*0d6140beSAndroid Build Coastguard Worker 
emulate_spi_chip_response(unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr,struct emu_data * data)387*0d6140beSAndroid Build Coastguard Worker static int emulate_spi_chip_response(unsigned int writecnt,
388*0d6140beSAndroid Build Coastguard Worker 				     unsigned int readcnt,
389*0d6140beSAndroid Build Coastguard Worker 				     const unsigned char *writearr,
390*0d6140beSAndroid Build Coastguard Worker 				     unsigned char *readarr,
391*0d6140beSAndroid Build Coastguard Worker 				     struct emu_data *data)
392*0d6140beSAndroid Build Coastguard Worker {
393*0d6140beSAndroid Build Coastguard Worker 	unsigned int offs, i, toread;
394*0d6140beSAndroid Build Coastguard Worker 	uint8_t ro_bits;
395*0d6140beSAndroid Build Coastguard Worker 	bool wrsr_ext2, wrsr_ext3;
396*0d6140beSAndroid Build Coastguard Worker 	static int unsigned aai_offs;
397*0d6140beSAndroid Build Coastguard Worker 	const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
398*0d6140beSAndroid Build Coastguard Worker 	const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
399*0d6140beSAndroid Build Coastguard Worker 	const unsigned char mx25l6436_rems_response[2] = {0xc2, 0x16};
400*0d6140beSAndroid Build Coastguard Worker 	const unsigned char w25q128fv_rems_response[2] = {0xef, 0x17};
401*0d6140beSAndroid Build Coastguard Worker 
402*0d6140beSAndroid Build Coastguard Worker 	if (writecnt == 0) {
403*0d6140beSAndroid Build Coastguard Worker 		msg_perr("No command sent to the chip!\n");
404*0d6140beSAndroid Build Coastguard Worker 		return 1;
405*0d6140beSAndroid Build Coastguard Worker 	}
406*0d6140beSAndroid Build Coastguard Worker 	/* spi_blacklist has precedence over spi_ignorelist. */
407*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < data->spi_blacklist_size; i++) {
408*0d6140beSAndroid Build Coastguard Worker 		if (writearr[0] == data->spi_blacklist[i]) {
409*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
410*0d6140beSAndroid Build Coastguard Worker 				 data->spi_blacklist[i]);
411*0d6140beSAndroid Build Coastguard Worker 			return SPI_INVALID_OPCODE;
412*0d6140beSAndroid Build Coastguard Worker 		}
413*0d6140beSAndroid Build Coastguard Worker 	}
414*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < data->spi_ignorelist_size; i++) {
415*0d6140beSAndroid Build Coastguard Worker 		if (writearr[0] == data->spi_ignorelist[i]) {
416*0d6140beSAndroid Build Coastguard Worker 			msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
417*0d6140beSAndroid Build Coastguard Worker 				 data->spi_ignorelist[i]);
418*0d6140beSAndroid Build Coastguard Worker 			/* Return success because the command does not fail,
419*0d6140beSAndroid Build Coastguard Worker 			 * it is simply ignored.
420*0d6140beSAndroid Build Coastguard Worker 			 */
421*0d6140beSAndroid Build Coastguard Worker 			return 0;
422*0d6140beSAndroid Build Coastguard Worker 		}
423*0d6140beSAndroid Build Coastguard Worker 	}
424*0d6140beSAndroid Build Coastguard Worker 
425*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_max_aai_size && (data->emu_status[0] & SPI_SR_AAI)) {
426*0d6140beSAndroid Build Coastguard Worker 		if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
427*0d6140beSAndroid Build Coastguard Worker 		    writearr[0] != JEDEC_WRDI &&
428*0d6140beSAndroid Build Coastguard Worker 		    writearr[0] != JEDEC_RDSR) {
429*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Forbidden opcode (0x%02x) attempted during "
430*0d6140beSAndroid Build Coastguard Worker 				 "AAI sequence!\n", writearr[0]);
431*0d6140beSAndroid Build Coastguard Worker 			return 0;
432*0d6140beSAndroid Build Coastguard Worker 		}
433*0d6140beSAndroid Build Coastguard Worker 	}
434*0d6140beSAndroid Build Coastguard Worker 
435*0d6140beSAndroid Build Coastguard Worker 	switch (writearr[0]) {
436*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_RES:
437*0d6140beSAndroid Build Coastguard Worker 		if (writecnt < JEDEC_RES_OUTSIZE)
438*0d6140beSAndroid Build Coastguard Worker 			break;
439*0d6140beSAndroid Build Coastguard Worker 		/* offs calculation is only needed for SST chips which treat RES like REMS. */
440*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
441*0d6140beSAndroid Build Coastguard Worker 		offs += writecnt - JEDEC_REMS_OUTSIZE;
442*0d6140beSAndroid Build Coastguard Worker 		switch (data->emu_chip) {
443*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_ST_M25P10_RES:
444*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
445*0d6140beSAndroid Build Coastguard Worker 				memset(readarr, 0x10, readcnt);
446*0d6140beSAndroid Build Coastguard Worker 			break;
447*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SST_SST25VF040_REMS:
448*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
449*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
450*0d6140beSAndroid Build Coastguard Worker 			break;
451*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SST_SST25VF032B:
452*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
453*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
454*0d6140beSAndroid Build Coastguard Worker 			break;
455*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_MACRONIX_MX25L6436:
456*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
457*0d6140beSAndroid Build Coastguard Worker 				memset(readarr, 0x16, readcnt);
458*0d6140beSAndroid Build Coastguard Worker 			break;
459*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_WINBOND_W25Q128FV:
460*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
461*0d6140beSAndroid Build Coastguard Worker 				memset(readarr, 0x17, readcnt);
462*0d6140beSAndroid Build Coastguard Worker 			break;
463*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SPANSION_S25FL128L:
464*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
465*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = 0x60;
466*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
467*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = 0x18;
468*0d6140beSAndroid Build Coastguard Worker 			break;
469*0d6140beSAndroid Build Coastguard Worker 		default: /* ignore */
470*0d6140beSAndroid Build Coastguard Worker 			break;
471*0d6140beSAndroid Build Coastguard Worker 		}
472*0d6140beSAndroid Build Coastguard Worker 		break;
473*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_REMS:
474*0d6140beSAndroid Build Coastguard Worker 		/* REMS response has wraparound and uses an address parameter. */
475*0d6140beSAndroid Build Coastguard Worker 		if (writecnt < JEDEC_REMS_OUTSIZE)
476*0d6140beSAndroid Build Coastguard Worker 			break;
477*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
478*0d6140beSAndroid Build Coastguard Worker 		offs += writecnt - JEDEC_REMS_OUTSIZE;
479*0d6140beSAndroid Build Coastguard Worker 		switch (data->emu_chip) {
480*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SST_SST25VF040_REMS:
481*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
482*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = sst25vf040_rems_response[(offs + i) % 2];
483*0d6140beSAndroid Build Coastguard Worker 			break;
484*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SST_SST25VF032B:
485*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
486*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = sst25vf032b_rems_response[(offs + i) % 2];
487*0d6140beSAndroid Build Coastguard Worker 			break;
488*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_MACRONIX_MX25L6436:
489*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
490*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = mx25l6436_rems_response[(offs + i) % 2];
491*0d6140beSAndroid Build Coastguard Worker 			break;
492*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_WINBOND_W25Q128FV:
493*0d6140beSAndroid Build Coastguard Worker 			for (i = 0; i < readcnt; i++)
494*0d6140beSAndroid Build Coastguard Worker 				readarr[i] = w25q128fv_rems_response[(offs + i) % 2];
495*0d6140beSAndroid Build Coastguard Worker 			break;
496*0d6140beSAndroid Build Coastguard Worker 		default: /* ignore */
497*0d6140beSAndroid Build Coastguard Worker 			break;
498*0d6140beSAndroid Build Coastguard Worker 		}
499*0d6140beSAndroid Build Coastguard Worker 		break;
500*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_RDID:
501*0d6140beSAndroid Build Coastguard Worker 		switch (data->emu_chip) {
502*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SST_SST25VF032B:
503*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
504*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = 0xbf;
505*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
506*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = 0x25;
507*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 2)
508*0d6140beSAndroid Build Coastguard Worker 				readarr[2] = 0x4a;
509*0d6140beSAndroid Build Coastguard Worker 			break;
510*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_MACRONIX_MX25L6436:
511*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
512*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = 0xc2;
513*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
514*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = 0x20;
515*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 2)
516*0d6140beSAndroid Build Coastguard Worker 				readarr[2] = 0x17;
517*0d6140beSAndroid Build Coastguard Worker 			break;
518*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_WINBOND_W25Q128FV:
519*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
520*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = 0xef;
521*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
522*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = 0x40;
523*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 2)
524*0d6140beSAndroid Build Coastguard Worker 				readarr[2] = 0x18;
525*0d6140beSAndroid Build Coastguard Worker 			break;
526*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_SPANSION_S25FL128L:
527*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
528*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = 0x01;
529*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
530*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = 0x60;
531*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 2)
532*0d6140beSAndroid Build Coastguard Worker 				readarr[2] = 0x18;
533*0d6140beSAndroid Build Coastguard Worker 			break;
534*0d6140beSAndroid Build Coastguard Worker 		case EMULATE_VARIABLE_SIZE:
535*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 0)
536*0d6140beSAndroid Build Coastguard Worker 				readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
537*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 1)
538*0d6140beSAndroid Build Coastguard Worker 				readarr[1] = PROGMANUF_ID & 0xff;
539*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 2)
540*0d6140beSAndroid Build Coastguard Worker 				readarr[2] = (PROGDEV_ID >> 8) & 0xff;
541*0d6140beSAndroid Build Coastguard Worker 			if (readcnt > 3)
542*0d6140beSAndroid Build Coastguard Worker 				readarr[3] = PROGDEV_ID & 0xff;
543*0d6140beSAndroid Build Coastguard Worker 			break;
544*0d6140beSAndroid Build Coastguard Worker 		default: /* ignore */
545*0d6140beSAndroid Build Coastguard Worker 			break;
546*0d6140beSAndroid Build Coastguard Worker 		}
547*0d6140beSAndroid Build Coastguard Worker 		break;
548*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_RDSR:
549*0d6140beSAndroid Build Coastguard Worker 		memset(readarr, data->emu_status[0], readcnt);
550*0d6140beSAndroid Build Coastguard Worker 		break;
551*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_RDSR2:
552*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_status_len >= 2)
553*0d6140beSAndroid Build Coastguard Worker 			memset(readarr, data->emu_status[1], readcnt);
554*0d6140beSAndroid Build Coastguard Worker 		break;
555*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_RDSR3:
556*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_status_len >= 3)
557*0d6140beSAndroid Build Coastguard Worker 			memset(readarr, data->emu_status[2], readcnt);
558*0d6140beSAndroid Build Coastguard Worker 		break;
559*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: this should be chip-specific. */
560*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_EWSR:
561*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_WREN:
562*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[0] |= SPI_SR_WEL;
563*0d6140beSAndroid Build Coastguard Worker 		break;
564*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_WRSR:
565*0d6140beSAndroid Build Coastguard Worker 		if (!(data->emu_status[0] & SPI_SR_WEL)) {
566*0d6140beSAndroid Build Coastguard Worker 			msg_perr("WRSR attempted, but WEL is 0!\n");
567*0d6140beSAndroid Build Coastguard Worker 			break;
568*0d6140beSAndroid Build Coastguard Worker 		}
569*0d6140beSAndroid Build Coastguard Worker 
570*0d6140beSAndroid Build Coastguard Worker 		wrsr_ext2 = (writecnt == 3 && data->emu_wrsr_ext2);
571*0d6140beSAndroid Build Coastguard Worker 		wrsr_ext3 = (writecnt == 4 && data->emu_wrsr_ext3);
572*0d6140beSAndroid Build Coastguard Worker 
573*0d6140beSAndroid Build Coastguard Worker 		/* FIXME: add some reasonable simulation of the busy flag */
574*0d6140beSAndroid Build Coastguard Worker 
575*0d6140beSAndroid Build Coastguard Worker 		ro_bits = get_reg_ro_bit_mask(data, STATUS1);
576*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[0] &= ro_bits;
577*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[0] |= writearr[1] & ~ro_bits;
578*0d6140beSAndroid Build Coastguard Worker 		if (wrsr_ext2 || wrsr_ext3) {
579*0d6140beSAndroid Build Coastguard Worker 			ro_bits = get_reg_ro_bit_mask(data, STATUS2);
580*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[1] &= ro_bits;
581*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[1] |= writearr[2] & ~ro_bits;
582*0d6140beSAndroid Build Coastguard Worker 		}
583*0d6140beSAndroid Build Coastguard Worker 		if (wrsr_ext3) {
584*0d6140beSAndroid Build Coastguard Worker 			ro_bits = get_reg_ro_bit_mask(data, STATUS3);
585*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[2] &= ro_bits;
586*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[2] |= writearr[3] & ~ro_bits;
587*0d6140beSAndroid Build Coastguard Worker 		}
588*0d6140beSAndroid Build Coastguard Worker 
589*0d6140beSAndroid Build Coastguard Worker 		if (wrsr_ext3)
590*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg2("WRSR wrote 0x%02x%02x%02x.\n", data->emu_status[2], data->emu_status[1], data->emu_status[0]);
591*0d6140beSAndroid Build Coastguard Worker 		else if (wrsr_ext2)
592*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg2("WRSR wrote 0x%02x%02x.\n", data->emu_status[1], data->emu_status[0]);
593*0d6140beSAndroid Build Coastguard Worker 		else
594*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status[0]);
595*0d6140beSAndroid Build Coastguard Worker 
596*0d6140beSAndroid Build Coastguard Worker 		update_write_protection(data);
597*0d6140beSAndroid Build Coastguard Worker 		break;
598*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_WRSR2:
599*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_status_len < 2)
600*0d6140beSAndroid Build Coastguard Worker 			break;
601*0d6140beSAndroid Build Coastguard Worker 		if (!(data->emu_status[0] & SPI_SR_WEL)) {
602*0d6140beSAndroid Build Coastguard Worker 			msg_perr("WRSR2 attempted, but WEL is 0!\n");
603*0d6140beSAndroid Build Coastguard Worker 			break;
604*0d6140beSAndroid Build Coastguard Worker 		}
605*0d6140beSAndroid Build Coastguard Worker 
606*0d6140beSAndroid Build Coastguard Worker 		ro_bits = get_reg_ro_bit_mask(data, STATUS2);
607*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[1] &= ro_bits;
608*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[1] |= (writearr[1] & ~ro_bits);
609*0d6140beSAndroid Build Coastguard Worker 
610*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("WRSR2 wrote 0x%02x.\n", data->emu_status[1]);
611*0d6140beSAndroid Build Coastguard Worker 
612*0d6140beSAndroid Build Coastguard Worker 		update_write_protection(data);
613*0d6140beSAndroid Build Coastguard Worker 		break;
614*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_WRSR3:
615*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_status_len < 3)
616*0d6140beSAndroid Build Coastguard Worker 			break;
617*0d6140beSAndroid Build Coastguard Worker 		if (!(data->emu_status[0] & SPI_SR_WEL)) {
618*0d6140beSAndroid Build Coastguard Worker 			msg_perr("WRSR3 attempted, but WEL is 0!\n");
619*0d6140beSAndroid Build Coastguard Worker 			break;
620*0d6140beSAndroid Build Coastguard Worker 		}
621*0d6140beSAndroid Build Coastguard Worker 
622*0d6140beSAndroid Build Coastguard Worker 		ro_bits = get_reg_ro_bit_mask(data, STATUS3);
623*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[2] &= ro_bits;
624*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[2] |= (writearr[1] & ~ro_bits);
625*0d6140beSAndroid Build Coastguard Worker 
626*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg2("WRSR3 wrote 0x%02x.\n", data->emu_status[2]);
627*0d6140beSAndroid Build Coastguard Worker 		break;
628*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_READ:
629*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
630*0d6140beSAndroid Build Coastguard Worker 		/* Truncate to emu_chip_size. */
631*0d6140beSAndroid Build Coastguard Worker 		offs %= data->emu_chip_size;
632*0d6140beSAndroid Build Coastguard Worker 		if (readcnt > 0)
633*0d6140beSAndroid Build Coastguard Worker 			memcpy(readarr, data->flashchip_contents + offs, readcnt);
634*0d6140beSAndroid Build Coastguard Worker 		break;
635*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_READ_4BA:
636*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
637*0d6140beSAndroid Build Coastguard Worker 		/* Truncate to emu_chip_size. */
638*0d6140beSAndroid Build Coastguard Worker 		offs %= data->emu_chip_size;
639*0d6140beSAndroid Build Coastguard Worker 		if (readcnt > 0)
640*0d6140beSAndroid Build Coastguard Worker 			memcpy(readarr, data->flashchip_contents + offs, readcnt);
641*0d6140beSAndroid Build Coastguard Worker 		break;
642*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_BYTE_PROGRAM:
643*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
644*0d6140beSAndroid Build Coastguard Worker 		/* Truncate to emu_chip_size. */
645*0d6140beSAndroid Build Coastguard Worker 		offs %= data->emu_chip_size;
646*0d6140beSAndroid Build Coastguard Worker 		if (writecnt < 5) {
647*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BYTE PROGRAM size too short!\n");
648*0d6140beSAndroid Build Coastguard Worker 			return 1;
649*0d6140beSAndroid Build Coastguard Worker 		}
650*0d6140beSAndroid Build Coastguard Worker 		if (writecnt - 4 > data->emu_max_byteprogram_size) {
651*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Max BYTE PROGRAM size exceeded!\n");
652*0d6140beSAndroid Build Coastguard Worker 			return 1;
653*0d6140beSAndroid Build Coastguard Worker 		}
654*0d6140beSAndroid Build Coastguard Worker 		if (write_flash_data(data, offs, writecnt - 4, writearr + 4)) {
655*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to program flash!\n");
656*0d6140beSAndroid Build Coastguard Worker 			return 1;
657*0d6140beSAndroid Build Coastguard Worker 		}
658*0d6140beSAndroid Build Coastguard Worker 		break;
659*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_BYTE_PROGRAM_4BA:
660*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
661*0d6140beSAndroid Build Coastguard Worker 		/* Truncate to emu_chip_size. */
662*0d6140beSAndroid Build Coastguard Worker 		offs %= data->emu_chip_size;
663*0d6140beSAndroid Build Coastguard Worker 		if (writecnt < 6) {
664*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BYTE PROGRAM size too short!\n");
665*0d6140beSAndroid Build Coastguard Worker 			return 1;
666*0d6140beSAndroid Build Coastguard Worker 		}
667*0d6140beSAndroid Build Coastguard Worker 		if (writecnt - 5 > data->emu_max_byteprogram_size) {
668*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Max BYTE PROGRAM size exceeded!\n");
669*0d6140beSAndroid Build Coastguard Worker 			return 1;
670*0d6140beSAndroid Build Coastguard Worker 		}
671*0d6140beSAndroid Build Coastguard Worker 		if (write_flash_data(data, offs, writecnt - 5, writearr + 5)) {
672*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to program flash!\n");
673*0d6140beSAndroid Build Coastguard Worker 			return 1;
674*0d6140beSAndroid Build Coastguard Worker 		}
675*0d6140beSAndroid Build Coastguard Worker 		break;
676*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_AAI_WORD_PROGRAM:
677*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_max_aai_size)
678*0d6140beSAndroid Build Coastguard Worker 			break;
679*0d6140beSAndroid Build Coastguard Worker 		if (!(data->emu_status[0] & SPI_SR_AAI)) {
680*0d6140beSAndroid Build Coastguard Worker 			if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
681*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Initial AAI WORD PROGRAM size too "
682*0d6140beSAndroid Build Coastguard Worker 					 "short!\n");
683*0d6140beSAndroid Build Coastguard Worker 				return 1;
684*0d6140beSAndroid Build Coastguard Worker 			}
685*0d6140beSAndroid Build Coastguard Worker 			if (writecnt > JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
686*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Initial AAI WORD PROGRAM size too "
687*0d6140beSAndroid Build Coastguard Worker 					 "long!\n");
688*0d6140beSAndroid Build Coastguard Worker 				return 1;
689*0d6140beSAndroid Build Coastguard Worker 			}
690*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[0] |= SPI_SR_AAI;
691*0d6140beSAndroid Build Coastguard Worker 			aai_offs = writearr[1] << 16 | writearr[2] << 8 |
692*0d6140beSAndroid Build Coastguard Worker 				   writearr[3];
693*0d6140beSAndroid Build Coastguard Worker 			/* Truncate to emu_chip_size. */
694*0d6140beSAndroid Build Coastguard Worker 			aai_offs %= data->emu_chip_size;
695*0d6140beSAndroid Build Coastguard Worker 			if (write_flash_data(data, aai_offs, 2, writearr + 4)) {
696*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Failed to program flash!\n");
697*0d6140beSAndroid Build Coastguard Worker 				return 1;
698*0d6140beSAndroid Build Coastguard Worker 			}
699*0d6140beSAndroid Build Coastguard Worker 			aai_offs += 2;
700*0d6140beSAndroid Build Coastguard Worker 		} else {
701*0d6140beSAndroid Build Coastguard Worker 			if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
702*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Continuation AAI WORD PROGRAM size "
703*0d6140beSAndroid Build Coastguard Worker 					 "too short!\n");
704*0d6140beSAndroid Build Coastguard Worker 				return 1;
705*0d6140beSAndroid Build Coastguard Worker 			}
706*0d6140beSAndroid Build Coastguard Worker 			if (writecnt > JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
707*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Continuation AAI WORD PROGRAM size "
708*0d6140beSAndroid Build Coastguard Worker 					 "too long!\n");
709*0d6140beSAndroid Build Coastguard Worker 				return 1;
710*0d6140beSAndroid Build Coastguard Worker 			}
711*0d6140beSAndroid Build Coastguard Worker 			if (write_flash_data(data, aai_offs, 2, writearr + 1)) {
712*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Failed to program flash!\n");
713*0d6140beSAndroid Build Coastguard Worker 				return 1;
714*0d6140beSAndroid Build Coastguard Worker 			}
715*0d6140beSAndroid Build Coastguard Worker 			aai_offs += 2;
716*0d6140beSAndroid Build Coastguard Worker 		}
717*0d6140beSAndroid Build Coastguard Worker 		break;
718*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_WRDI:
719*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_max_aai_size)
720*0d6140beSAndroid Build Coastguard Worker 			data->emu_status[0] &= ~SPI_SR_AAI;
721*0d6140beSAndroid Build Coastguard Worker 		break;
722*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_SE:
723*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_jedec_se_size)
724*0d6140beSAndroid Build Coastguard Worker 			break;
725*0d6140beSAndroid Build Coastguard Worker 		if (writecnt != JEDEC_SE_OUTSIZE) {
726*0d6140beSAndroid Build Coastguard Worker 			msg_perr("SECTOR ERASE 0x20 outsize invalid!\n");
727*0d6140beSAndroid Build Coastguard Worker 			return 1;
728*0d6140beSAndroid Build Coastguard Worker 		}
729*0d6140beSAndroid Build Coastguard Worker 		if (readcnt != JEDEC_SE_INSIZE) {
730*0d6140beSAndroid Build Coastguard Worker 			msg_perr("SECTOR ERASE 0x20 insize invalid!\n");
731*0d6140beSAndroid Build Coastguard Worker 			return 1;
732*0d6140beSAndroid Build Coastguard Worker 		}
733*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
734*0d6140beSAndroid Build Coastguard Worker 		if (offs & (data->emu_jedec_se_size - 1))
735*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
736*0d6140beSAndroid Build Coastguard Worker 		offs &= ~(data->emu_jedec_se_size - 1);
737*0d6140beSAndroid Build Coastguard Worker 		if (erase_flash_data(data, offs, data->emu_jedec_se_size)) {
738*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to erase flash!\n");
739*0d6140beSAndroid Build Coastguard Worker 			return 1;
740*0d6140beSAndroid Build Coastguard Worker 		}
741*0d6140beSAndroid Build Coastguard Worker 		break;
742*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_BE_52:
743*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_jedec_be_52_size)
744*0d6140beSAndroid Build Coastguard Worker 			break;
745*0d6140beSAndroid Build Coastguard Worker 		if (writecnt != JEDEC_BE_52_OUTSIZE) {
746*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BLOCK ERASE 0x52 outsize invalid!\n");
747*0d6140beSAndroid Build Coastguard Worker 			return 1;
748*0d6140beSAndroid Build Coastguard Worker 		}
749*0d6140beSAndroid Build Coastguard Worker 		if (readcnt != JEDEC_BE_52_INSIZE) {
750*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BLOCK ERASE 0x52 insize invalid!\n");
751*0d6140beSAndroid Build Coastguard Worker 			return 1;
752*0d6140beSAndroid Build Coastguard Worker 		}
753*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
754*0d6140beSAndroid Build Coastguard Worker 		if (offs & (data->emu_jedec_be_52_size - 1))
755*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
756*0d6140beSAndroid Build Coastguard Worker 		offs &= ~(data->emu_jedec_be_52_size - 1);
757*0d6140beSAndroid Build Coastguard Worker 		if (erase_flash_data(data, offs, data->emu_jedec_be_52_size)) {
758*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to erase flash!\n");
759*0d6140beSAndroid Build Coastguard Worker 			return 1;
760*0d6140beSAndroid Build Coastguard Worker 		}
761*0d6140beSAndroid Build Coastguard Worker 		break;
762*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_BE_D8:
763*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_jedec_be_d8_size)
764*0d6140beSAndroid Build Coastguard Worker 			break;
765*0d6140beSAndroid Build Coastguard Worker 		if (writecnt != JEDEC_BE_D8_OUTSIZE) {
766*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BLOCK ERASE 0xd8 outsize invalid!\n");
767*0d6140beSAndroid Build Coastguard Worker 			return 1;
768*0d6140beSAndroid Build Coastguard Worker 		}
769*0d6140beSAndroid Build Coastguard Worker 		if (readcnt != JEDEC_BE_D8_INSIZE) {
770*0d6140beSAndroid Build Coastguard Worker 			msg_perr("BLOCK ERASE 0xd8 insize invalid!\n");
771*0d6140beSAndroid Build Coastguard Worker 			return 1;
772*0d6140beSAndroid Build Coastguard Worker 		}
773*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
774*0d6140beSAndroid Build Coastguard Worker 		if (offs & (data->emu_jedec_be_d8_size - 1))
775*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
776*0d6140beSAndroid Build Coastguard Worker 		offs &= ~(data->emu_jedec_be_d8_size - 1);
777*0d6140beSAndroid Build Coastguard Worker 		if (erase_flash_data(data, offs, data->emu_jedec_be_d8_size)) {
778*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to erase flash!\n");
779*0d6140beSAndroid Build Coastguard Worker 			return 1;
780*0d6140beSAndroid Build Coastguard Worker 		}
781*0d6140beSAndroid Build Coastguard Worker 		break;
782*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_CE_60:
783*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_jedec_ce_60_size)
784*0d6140beSAndroid Build Coastguard Worker 			break;
785*0d6140beSAndroid Build Coastguard Worker 		if (writecnt != JEDEC_CE_60_OUTSIZE) {
786*0d6140beSAndroid Build Coastguard Worker 			msg_perr("CHIP ERASE 0x60 outsize invalid!\n");
787*0d6140beSAndroid Build Coastguard Worker 			return 1;
788*0d6140beSAndroid Build Coastguard Worker 		}
789*0d6140beSAndroid Build Coastguard Worker 		if (readcnt != JEDEC_CE_60_INSIZE) {
790*0d6140beSAndroid Build Coastguard Worker 			msg_perr("CHIP ERASE 0x60 insize invalid!\n");
791*0d6140beSAndroid Build Coastguard Worker 			return 1;
792*0d6140beSAndroid Build Coastguard Worker 		}
793*0d6140beSAndroid Build Coastguard Worker 		/* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
794*0d6140beSAndroid Build Coastguard Worker 		/* emu_jedec_ce_60_size is emu_chip_size. */
795*0d6140beSAndroid Build Coastguard Worker 		if (erase_flash_data(data, 0, data->emu_jedec_ce_60_size)) {
796*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to erase flash!\n");
797*0d6140beSAndroid Build Coastguard Worker 			return 1;
798*0d6140beSAndroid Build Coastguard Worker 		}
799*0d6140beSAndroid Build Coastguard Worker 		break;
800*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_CE_C7:
801*0d6140beSAndroid Build Coastguard Worker 		if (!data->emu_jedec_ce_c7_size)
802*0d6140beSAndroid Build Coastguard Worker 			break;
803*0d6140beSAndroid Build Coastguard Worker 		if (writecnt != JEDEC_CE_C7_OUTSIZE) {
804*0d6140beSAndroid Build Coastguard Worker 			msg_perr("CHIP ERASE 0xc7 outsize invalid!\n");
805*0d6140beSAndroid Build Coastguard Worker 			return 1;
806*0d6140beSAndroid Build Coastguard Worker 		}
807*0d6140beSAndroid Build Coastguard Worker 		if (readcnt != JEDEC_CE_C7_INSIZE) {
808*0d6140beSAndroid Build Coastguard Worker 			msg_perr("CHIP ERASE 0xc7 insize invalid!\n");
809*0d6140beSAndroid Build Coastguard Worker 			return 1;
810*0d6140beSAndroid Build Coastguard Worker 		}
811*0d6140beSAndroid Build Coastguard Worker 		/* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
812*0d6140beSAndroid Build Coastguard Worker 		/* emu_jedec_ce_c7_size is emu_chip_size. */
813*0d6140beSAndroid Build Coastguard Worker 		if (erase_flash_data(data, 0, data->emu_jedec_ce_c7_size)) {
814*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Failed to erase flash!\n");
815*0d6140beSAndroid Build Coastguard Worker 			return 1;
816*0d6140beSAndroid Build Coastguard Worker 		}
817*0d6140beSAndroid Build Coastguard Worker 		break;
818*0d6140beSAndroid Build Coastguard Worker 	case JEDEC_SFDP:
819*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
820*0d6140beSAndroid Build Coastguard Worker 			break;
821*0d6140beSAndroid Build Coastguard Worker 		if (writecnt < 4)
822*0d6140beSAndroid Build Coastguard Worker 			break;
823*0d6140beSAndroid Build Coastguard Worker 		offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
824*0d6140beSAndroid Build Coastguard Worker 
825*0d6140beSAndroid Build Coastguard Worker 		/* SFDP expects one dummy byte after the address. */
826*0d6140beSAndroid Build Coastguard Worker 		if (writecnt == 4) {
827*0d6140beSAndroid Build Coastguard Worker 			/* The dummy byte was not written, make sure it is read instead.
828*0d6140beSAndroid Build Coastguard Worker 			 * Shifting and shortening the read array does achieve this goal.
829*0d6140beSAndroid Build Coastguard Worker 			 */
830*0d6140beSAndroid Build Coastguard Worker 			readarr++;
831*0d6140beSAndroid Build Coastguard Worker 			readcnt--;
832*0d6140beSAndroid Build Coastguard Worker 		} else {
833*0d6140beSAndroid Build Coastguard Worker 			/* The response is shifted if more than 5 bytes are written, because SFDP data is
834*0d6140beSAndroid Build Coastguard Worker 			 * already shifted out by the chip while those superfluous bytes are written. */
835*0d6140beSAndroid Build Coastguard Worker 			offs += writecnt - 5;
836*0d6140beSAndroid Build Coastguard Worker 		}
837*0d6140beSAndroid Build Coastguard Worker 
838*0d6140beSAndroid Build Coastguard Worker 		/* The SFDP spec implies that the start address of an SFDP read may be truncated to fit in the
839*0d6140beSAndroid Build Coastguard Worker 		 * SFDP table address space, i.e. the start address may be wrapped around at SFDP table size.
840*0d6140beSAndroid Build Coastguard Worker 		 * This is a reasonable implementation choice in hardware because it saves a few gates. */
841*0d6140beSAndroid Build Coastguard Worker 		if (offs >= sizeof(sfdp_table)) {
842*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Wrapping the start address around the SFDP table boundary (using 0x%x "
843*0d6140beSAndroid Build Coastguard Worker 				 "instead of 0x%x).\n", (unsigned int)(offs % sizeof(sfdp_table)), offs);
844*0d6140beSAndroid Build Coastguard Worker 			offs %= sizeof(sfdp_table);
845*0d6140beSAndroid Build Coastguard Worker 		}
846*0d6140beSAndroid Build Coastguard Worker 		toread = min(sizeof(sfdp_table) - offs, readcnt);
847*0d6140beSAndroid Build Coastguard Worker 		memcpy(readarr, sfdp_table + offs, toread);
848*0d6140beSAndroid Build Coastguard Worker 		if (toread < readcnt)
849*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Crossing the SFDP table boundary in a single "
850*0d6140beSAndroid Build Coastguard Worker 				 "continuous chunk produces undefined results "
851*0d6140beSAndroid Build Coastguard Worker 				 "after that point.\n");
852*0d6140beSAndroid Build Coastguard Worker 		break;
853*0d6140beSAndroid Build Coastguard Worker 	default:
854*0d6140beSAndroid Build Coastguard Worker 		/* No special response. */
855*0d6140beSAndroid Build Coastguard Worker 		break;
856*0d6140beSAndroid Build Coastguard Worker 	}
857*0d6140beSAndroid Build Coastguard Worker 	if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
858*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[0] &= ~SPI_SR_WEL;
859*0d6140beSAndroid Build Coastguard Worker 	return 0;
860*0d6140beSAndroid Build Coastguard Worker }
861*0d6140beSAndroid Build Coastguard Worker 
dummy_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)862*0d6140beSAndroid Build Coastguard Worker static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
863*0d6140beSAndroid Build Coastguard Worker 				  unsigned int readcnt,
864*0d6140beSAndroid Build Coastguard Worker 				  const unsigned char *writearr,
865*0d6140beSAndroid Build Coastguard Worker 				  unsigned char *readarr)
866*0d6140beSAndroid Build Coastguard Worker {
867*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
868*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *emu_data = flash->mst->spi.data;
869*0d6140beSAndroid Build Coastguard Worker 	if (!emu_data) {
870*0d6140beSAndroid Build Coastguard Worker 		msg_perr("No data in flash context!\n");
871*0d6140beSAndroid Build Coastguard Worker 		return 1;
872*0d6140beSAndroid Build Coastguard Worker 	}
873*0d6140beSAndroid Build Coastguard Worker 
874*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s:", __func__);
875*0d6140beSAndroid Build Coastguard Worker 
876*0d6140beSAndroid Build Coastguard Worker 	msg_pspew(" writing %u bytes:", writecnt);
877*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < writecnt; i++)
878*0d6140beSAndroid Build Coastguard Worker 		msg_pspew(" 0x%02x", writearr[i]);
879*0d6140beSAndroid Build Coastguard Worker 
880*0d6140beSAndroid Build Coastguard Worker 	/* Response for unknown commands and missing chip is 0xff. */
881*0d6140beSAndroid Build Coastguard Worker 	memset(readarr, 0xff, readcnt);
882*0d6140beSAndroid Build Coastguard Worker 	switch (emu_data->emu_chip) {
883*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_ST_M25P10_RES:
884*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_SST_SST25VF040_REMS:
885*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_SST_SST25VF032B:
886*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_MACRONIX_MX25L6436:
887*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_WINBOND_W25Q128FV:
888*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_SPANSION_S25FL128L:
889*0d6140beSAndroid Build Coastguard Worker 	case EMULATE_VARIABLE_SIZE:
890*0d6140beSAndroid Build Coastguard Worker 		if (emulate_spi_chip_response(writecnt, readcnt, writearr,
891*0d6140beSAndroid Build Coastguard Worker 					      readarr, emu_data)) {
892*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Invalid command sent to flash chip!\n");
893*0d6140beSAndroid Build Coastguard Worker 			return 1;
894*0d6140beSAndroid Build Coastguard Worker 		}
895*0d6140beSAndroid Build Coastguard Worker 		break;
896*0d6140beSAndroid Build Coastguard Worker 	default:
897*0d6140beSAndroid Build Coastguard Worker 		break;
898*0d6140beSAndroid Build Coastguard Worker 	}
899*0d6140beSAndroid Build Coastguard Worker 	msg_pspew(" reading %u bytes:", readcnt);
900*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < readcnt; i++)
901*0d6140beSAndroid Build Coastguard Worker 		msg_pspew(" 0x%02x", readarr[i]);
902*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("\n");
903*0d6140beSAndroid Build Coastguard Worker 
904*0d6140beSAndroid Build Coastguard Worker 	default_delay(((writecnt + readcnt) * emu_data->delay_ns) / 1000);
905*0d6140beSAndroid Build Coastguard Worker 	return 0;
906*0d6140beSAndroid Build Coastguard Worker }
907*0d6140beSAndroid Build Coastguard Worker 
dummy_shutdown(void * data)908*0d6140beSAndroid Build Coastguard Worker static int dummy_shutdown(void *data)
909*0d6140beSAndroid Build Coastguard Worker {
910*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s\n", __func__);
911*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *emu_data = (struct emu_data *)data;
912*0d6140beSAndroid Build Coastguard Worker 
913*0d6140beSAndroid Build Coastguard Worker 	emu_data->refs_cnt--;
914*0d6140beSAndroid Build Coastguard Worker 	if (emu_data->refs_cnt != 0)
915*0d6140beSAndroid Build Coastguard Worker 		return 0;
916*0d6140beSAndroid Build Coastguard Worker 
917*0d6140beSAndroid Build Coastguard Worker 	if (emu_data->emu_chip != EMULATE_NONE) {
918*0d6140beSAndroid Build Coastguard Worker 		if (emu_data->emu_persistent_image && emu_data->emu_modified) {
919*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Writing %s\n", emu_data->emu_persistent_image);
920*0d6140beSAndroid Build Coastguard Worker 			write_buf_to_file(emu_data->flashchip_contents,
921*0d6140beSAndroid Build Coastguard Worker 					  emu_data->emu_chip_size,
922*0d6140beSAndroid Build Coastguard Worker 					  emu_data->emu_persistent_image);
923*0d6140beSAndroid Build Coastguard Worker 		}
924*0d6140beSAndroid Build Coastguard Worker 		free(emu_data->emu_persistent_image);
925*0d6140beSAndroid Build Coastguard Worker 		free(emu_data->flashchip_contents);
926*0d6140beSAndroid Build Coastguard Worker 	}
927*0d6140beSAndroid Build Coastguard Worker 	free(data);
928*0d6140beSAndroid Build Coastguard Worker 	return 0;
929*0d6140beSAndroid Build Coastguard Worker }
930*0d6140beSAndroid Build Coastguard Worker 
dummy_nop_delay(const struct flashctx * flash,unsigned int usecs)931*0d6140beSAndroid Build Coastguard Worker static void dummy_nop_delay(const struct flashctx *flash, unsigned int usecs)
932*0d6140beSAndroid Build Coastguard Worker {
933*0d6140beSAndroid Build Coastguard Worker }
934*0d6140beSAndroid Build Coastguard Worker 
dummy_wp_read_cfg(struct flashrom_wp_cfg * cfg,struct flashctx * flash)935*0d6140beSAndroid Build Coastguard Worker static enum flashrom_wp_result dummy_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
936*0d6140beSAndroid Build Coastguard Worker {
937*0d6140beSAndroid Build Coastguard Worker 	cfg->mode = FLASHROM_WP_MODE_DISABLED;
938*0d6140beSAndroid Build Coastguard Worker 	cfg->range.start = 0;
939*0d6140beSAndroid Build Coastguard Worker 	cfg->range.len = 0;
940*0d6140beSAndroid Build Coastguard Worker 
941*0d6140beSAndroid Build Coastguard Worker 	return FLASHROM_WP_OK;
942*0d6140beSAndroid Build Coastguard Worker }
943*0d6140beSAndroid Build Coastguard Worker 
dummy_wp_write_cfg(struct flashctx * flash,const struct flashrom_wp_cfg * cfg)944*0d6140beSAndroid Build Coastguard Worker static enum flashrom_wp_result dummy_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
945*0d6140beSAndroid Build Coastguard Worker {
946*0d6140beSAndroid Build Coastguard Worker 	if (cfg->mode != FLASHROM_WP_MODE_DISABLED)
947*0d6140beSAndroid Build Coastguard Worker 		return FLASHROM_WP_ERR_MODE_UNSUPPORTED;
948*0d6140beSAndroid Build Coastguard Worker 
949*0d6140beSAndroid Build Coastguard Worker 	if (cfg->range.start != 0 || cfg->range.len != 0)
950*0d6140beSAndroid Build Coastguard Worker 		return FLASHROM_WP_ERR_RANGE_UNSUPPORTED;
951*0d6140beSAndroid Build Coastguard Worker 
952*0d6140beSAndroid Build Coastguard Worker 	return FLASHROM_WP_OK;
953*0d6140beSAndroid Build Coastguard Worker }
954*0d6140beSAndroid Build Coastguard Worker 
dummy_wp_get_available_ranges(struct flashrom_wp_ranges ** list,struct flashctx * flash)955*0d6140beSAndroid Build Coastguard Worker static enum flashrom_wp_result dummy_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashctx *flash)
956*0d6140beSAndroid Build Coastguard Worker {
957*0d6140beSAndroid Build Coastguard Worker 	/* Not supported */
958*0d6140beSAndroid Build Coastguard Worker 	return FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE;
959*0d6140beSAndroid Build Coastguard Worker }
960*0d6140beSAndroid Build Coastguard Worker 
961*0d6140beSAndroid Build Coastguard Worker 
962*0d6140beSAndroid Build Coastguard Worker static const struct spi_master spi_master_dummyflasher = {
963*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= dummy_map,
964*0d6140beSAndroid Build Coastguard Worker 	.unmap_flash_region	= dummy_unmap,
965*0d6140beSAndroid Build Coastguard Worker 	.features	= SPI_MASTER_4BA,
966*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= MAX_DATA_READ_UNLIMITED,
967*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= MAX_DATA_UNSPECIFIED,
968*0d6140beSAndroid Build Coastguard Worker 	.command	= dummy_spi_send_command,
969*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
970*0d6140beSAndroid Build Coastguard Worker 	.write_256	= dummy_spi_write_256,
971*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= dummy_shutdown,
972*0d6140beSAndroid Build Coastguard Worker 	.probe_opcode	= dummy_spi_probe_opcode,
973*0d6140beSAndroid Build Coastguard Worker 	.delay		= dummy_nop_delay,
974*0d6140beSAndroid Build Coastguard Worker };
975*0d6140beSAndroid Build Coastguard Worker 
976*0d6140beSAndroid Build Coastguard Worker static const struct par_master par_master_dummyflasher = {
977*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= dummy_map,
978*0d6140beSAndroid Build Coastguard Worker 	.unmap_flash_region	= dummy_unmap,
979*0d6140beSAndroid Build Coastguard Worker 	.chip_readb	= dummy_chip_readb,
980*0d6140beSAndroid Build Coastguard Worker 	.chip_readw	= dummy_chip_readw,
981*0d6140beSAndroid Build Coastguard Worker 	.chip_readl	= dummy_chip_readl,
982*0d6140beSAndroid Build Coastguard Worker 	.chip_readn	= dummy_chip_readn,
983*0d6140beSAndroid Build Coastguard Worker 	.chip_writeb	= dummy_chip_writeb,
984*0d6140beSAndroid Build Coastguard Worker 	.chip_writew	= dummy_chip_writew,
985*0d6140beSAndroid Build Coastguard Worker 	.chip_writel	= dummy_chip_writel,
986*0d6140beSAndroid Build Coastguard Worker 	.chip_writen	= dummy_chip_writen,
987*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= dummy_shutdown,
988*0d6140beSAndroid Build Coastguard Worker 	.delay		= dummy_nop_delay,
989*0d6140beSAndroid Build Coastguard Worker };
990*0d6140beSAndroid Build Coastguard Worker 
991*0d6140beSAndroid Build Coastguard Worker static const struct opaque_master opaque_master_dummyflasher = {
992*0d6140beSAndroid Build Coastguard Worker 	.probe		= probe_variable_size,
993*0d6140beSAndroid Build Coastguard Worker 	.read		= dummy_opaque_read,
994*0d6140beSAndroid Build Coastguard Worker 	.write		= dummy_opaque_write,
995*0d6140beSAndroid Build Coastguard Worker 	.erase		= dummy_opaque_erase,
996*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= dummy_shutdown,
997*0d6140beSAndroid Build Coastguard Worker 	.delay		= dummy_nop_delay,
998*0d6140beSAndroid Build Coastguard Worker 	.wp_read_cfg	= dummy_wp_read_cfg,
999*0d6140beSAndroid Build Coastguard Worker 	.wp_write_cfg	= dummy_wp_write_cfg,
1000*0d6140beSAndroid Build Coastguard Worker 	.wp_get_ranges	= dummy_wp_get_available_ranges,
1001*0d6140beSAndroid Build Coastguard Worker };
1002*0d6140beSAndroid Build Coastguard Worker 
init_data(const struct programmer_cfg * cfg,struct emu_data * data,enum chipbustype * dummy_buses_supported)1003*0d6140beSAndroid Build Coastguard Worker static int init_data(const struct programmer_cfg *cfg,
1004*0d6140beSAndroid Build Coastguard Worker 		struct emu_data *data, enum chipbustype *dummy_buses_supported)
1005*0d6140beSAndroid Build Coastguard Worker {
1006*0d6140beSAndroid Build Coastguard Worker 	char *bustext = NULL;
1007*0d6140beSAndroid Build Coastguard Worker 	char *tmp = NULL;
1008*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
1009*0d6140beSAndroid Build Coastguard Worker 	char *endptr;
1010*0d6140beSAndroid Build Coastguard Worker 	char *status = NULL;
1011*0d6140beSAndroid Build Coastguard Worker 	int size = -1;  /* size for VARIABLE_SIZE chip device */
1012*0d6140beSAndroid Build Coastguard Worker 
1013*0d6140beSAndroid Build Coastguard Worker 	bustext = extract_programmer_param_str(cfg, "bus");
1014*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
1015*0d6140beSAndroid Build Coastguard Worker 	if (!bustext)
1016*0d6140beSAndroid Build Coastguard Worker 		bustext = strdup("parallel+lpc+fwh+spi+prog");
1017*0d6140beSAndroid Build Coastguard Worker 	/* Convert the parameters to lowercase. */
1018*0d6140beSAndroid Build Coastguard Worker 	tolower_string(bustext);
1019*0d6140beSAndroid Build Coastguard Worker 
1020*0d6140beSAndroid Build Coastguard Worker 	*dummy_buses_supported = BUS_NONE;
1021*0d6140beSAndroid Build Coastguard Worker 	if (strstr(bustext, "parallel")) {
1022*0d6140beSAndroid Build Coastguard Worker 		*dummy_buses_supported |= BUS_PARALLEL;
1023*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling support for %s flash.\n", "parallel");
1024*0d6140beSAndroid Build Coastguard Worker 	}
1025*0d6140beSAndroid Build Coastguard Worker 	if (strstr(bustext, "lpc")) {
1026*0d6140beSAndroid Build Coastguard Worker 		*dummy_buses_supported |= BUS_LPC;
1027*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling support for %s flash.\n", "LPC");
1028*0d6140beSAndroid Build Coastguard Worker 	}
1029*0d6140beSAndroid Build Coastguard Worker 	if (strstr(bustext, "fwh")) {
1030*0d6140beSAndroid Build Coastguard Worker 		*dummy_buses_supported |= BUS_FWH;
1031*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling support for %s flash.\n", "FWH");
1032*0d6140beSAndroid Build Coastguard Worker 	}
1033*0d6140beSAndroid Build Coastguard Worker 	if (strstr(bustext, "spi")) {
1034*0d6140beSAndroid Build Coastguard Worker 		*dummy_buses_supported |= BUS_SPI;
1035*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling support for %s flash.\n", "SPI");
1036*0d6140beSAndroid Build Coastguard Worker 	}
1037*0d6140beSAndroid Build Coastguard Worker 	if (strstr(bustext, "prog")) {
1038*0d6140beSAndroid Build Coastguard Worker 		*dummy_buses_supported |= BUS_PROG;
1039*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Enabling support for %s flash.\n", "PROG");
1040*0d6140beSAndroid Build Coastguard Worker 	}
1041*0d6140beSAndroid Build Coastguard Worker 	if (*dummy_buses_supported == BUS_NONE)
1042*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Support for all flash bus types disabled.\n");
1043*0d6140beSAndroid Build Coastguard Worker 	free(bustext);
1044*0d6140beSAndroid Build Coastguard Worker 
1045*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "spi_write_256_chunksize");
1046*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1047*0d6140beSAndroid Build Coastguard Worker 		data->spi_write_256_chunksize = strtoul(tmp, &endptr, 0);
1048*0d6140beSAndroid Build Coastguard Worker 		if (*endptr != '\0' || data->spi_write_256_chunksize < 1) {
1049*0d6140beSAndroid Build Coastguard Worker 			msg_perr("invalid spi_write_256_chunksize\n");
1050*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1051*0d6140beSAndroid Build Coastguard Worker 			return 1;
1052*0d6140beSAndroid Build Coastguard Worker 		}
1053*0d6140beSAndroid Build Coastguard Worker 	}
1054*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1055*0d6140beSAndroid Build Coastguard Worker 
1056*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "spi_blacklist");
1057*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1058*0d6140beSAndroid Build Coastguard Worker 		i = strlen(tmp);
1059*0d6140beSAndroid Build Coastguard Worker 		if (!strncmp(tmp, "0x", 2)) {
1060*0d6140beSAndroid Build Coastguard Worker 			i -= 2;
1061*0d6140beSAndroid Build Coastguard Worker 			memmove(tmp, tmp + 2, i + 1);
1062*0d6140beSAndroid Build Coastguard Worker 		}
1063*0d6140beSAndroid Build Coastguard Worker 		if ((i > 512) || (i % 2)) {
1064*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid SPI command blacklist length\n");
1065*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1066*0d6140beSAndroid Build Coastguard Worker 			return 1;
1067*0d6140beSAndroid Build Coastguard Worker 		}
1068*0d6140beSAndroid Build Coastguard Worker 		data->spi_blacklist_size = i / 2;
1069*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_blacklist_size * 2; i++) {
1070*0d6140beSAndroid Build Coastguard Worker 			if (!isxdigit((unsigned char)tmp[i])) {
1071*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Invalid char \"%c\" in SPI command "
1072*0d6140beSAndroid Build Coastguard Worker 					 "blacklist\n", tmp[i]);
1073*0d6140beSAndroid Build Coastguard Worker 				free(tmp);
1074*0d6140beSAndroid Build Coastguard Worker 				return 1;
1075*0d6140beSAndroid Build Coastguard Worker 			}
1076*0d6140beSAndroid Build Coastguard Worker 		}
1077*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_blacklist_size; i++) {
1078*0d6140beSAndroid Build Coastguard Worker 			unsigned int tmp2;
1079*0d6140beSAndroid Build Coastguard Worker 			/* SCNx8 is apparently not supported by MSVC (and thus
1080*0d6140beSAndroid Build Coastguard Worker 			 * MinGW), so work around it with an extra variable
1081*0d6140beSAndroid Build Coastguard Worker 			 */
1082*0d6140beSAndroid Build Coastguard Worker 			sscanf(tmp + i * 2, "%2x", &tmp2);
1083*0d6140beSAndroid Build Coastguard Worker 			data->spi_blacklist[i] = (uint8_t)tmp2;
1084*0d6140beSAndroid Build Coastguard Worker 		}
1085*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("SPI blacklist is ");
1086*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_blacklist_size; i++)
1087*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("%02x ", data->spi_blacklist[i]);
1088*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg(", size %u\n", data->spi_blacklist_size);
1089*0d6140beSAndroid Build Coastguard Worker 	}
1090*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1091*0d6140beSAndroid Build Coastguard Worker 
1092*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "spi_ignorelist");
1093*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1094*0d6140beSAndroid Build Coastguard Worker 		i = strlen(tmp);
1095*0d6140beSAndroid Build Coastguard Worker 		if (!strncmp(tmp, "0x", 2)) {
1096*0d6140beSAndroid Build Coastguard Worker 			i -= 2;
1097*0d6140beSAndroid Build Coastguard Worker 			memmove(tmp, tmp + 2, i + 1);
1098*0d6140beSAndroid Build Coastguard Worker 		}
1099*0d6140beSAndroid Build Coastguard Worker 		if ((i > 512) || (i % 2)) {
1100*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid SPI command ignorelist length\n");
1101*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1102*0d6140beSAndroid Build Coastguard Worker 			return 1;
1103*0d6140beSAndroid Build Coastguard Worker 		}
1104*0d6140beSAndroid Build Coastguard Worker 		data->spi_ignorelist_size = i / 2;
1105*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
1106*0d6140beSAndroid Build Coastguard Worker 			if (!isxdigit((unsigned char)tmp[i])) {
1107*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Invalid char \"%c\" in SPI command "
1108*0d6140beSAndroid Build Coastguard Worker 					 "ignorelist\n", tmp[i]);
1109*0d6140beSAndroid Build Coastguard Worker 				free(tmp);
1110*0d6140beSAndroid Build Coastguard Worker 				return 1;
1111*0d6140beSAndroid Build Coastguard Worker 			}
1112*0d6140beSAndroid Build Coastguard Worker 		}
1113*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_ignorelist_size; i++) {
1114*0d6140beSAndroid Build Coastguard Worker 			unsigned int tmp2;
1115*0d6140beSAndroid Build Coastguard Worker 			/* SCNx8 is apparently not supported by MSVC (and thus
1116*0d6140beSAndroid Build Coastguard Worker 			 * MinGW), so work around it with an extra variable
1117*0d6140beSAndroid Build Coastguard Worker 			 */
1118*0d6140beSAndroid Build Coastguard Worker 			sscanf(tmp + i * 2, "%2x", &tmp2);
1119*0d6140beSAndroid Build Coastguard Worker 			data->spi_ignorelist[i] = (uint8_t)tmp2;
1120*0d6140beSAndroid Build Coastguard Worker 		}
1121*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("SPI ignorelist is ");
1122*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < data->spi_ignorelist_size; i++)
1123*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("%02x ", data->spi_ignorelist[i]);
1124*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg(", size %u\n", data->spi_ignorelist_size);
1125*0d6140beSAndroid Build Coastguard Worker 	}
1126*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1127*0d6140beSAndroid Build Coastguard Worker 
1128*0d6140beSAndroid Build Coastguard Worker 	/* frequency to emulate in Hz (default), KHz, or MHz */
1129*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "freq");
1130*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1131*0d6140beSAndroid Build Coastguard Worker 		unsigned long long freq;
1132*0d6140beSAndroid Build Coastguard Worker 		char *units = tmp;
1133*0d6140beSAndroid Build Coastguard Worker 		char *end = tmp + strlen(tmp);
1134*0d6140beSAndroid Build Coastguard Worker 
1135*0d6140beSAndroid Build Coastguard Worker 		errno = 0;
1136*0d6140beSAndroid Build Coastguard Worker 		freq = strtoul(tmp, &units, 0);
1137*0d6140beSAndroid Build Coastguard Worker 		if (errno) {
1138*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Invalid frequency \"%s\", %s\n",
1139*0d6140beSAndroid Build Coastguard Worker 					tmp, strerror(errno));
1140*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1141*0d6140beSAndroid Build Coastguard Worker 			return 1;
1142*0d6140beSAndroid Build Coastguard Worker 		}
1143*0d6140beSAndroid Build Coastguard Worker 
1144*0d6140beSAndroid Build Coastguard Worker 		if ((units > tmp) && (units < end)) {
1145*0d6140beSAndroid Build Coastguard Worker 			bool units_valid = false;
1146*0d6140beSAndroid Build Coastguard Worker 
1147*0d6140beSAndroid Build Coastguard Worker 			if (units < end - 3) {
1148*0d6140beSAndroid Build Coastguard Worker 				;
1149*0d6140beSAndroid Build Coastguard Worker 			} else if (units == end - 2) {
1150*0d6140beSAndroid Build Coastguard Worker 				if (!strcasecmp(units, "hz"))
1151*0d6140beSAndroid Build Coastguard Worker 					units_valid = true;
1152*0d6140beSAndroid Build Coastguard Worker 			} else if (units == end - 3) {
1153*0d6140beSAndroid Build Coastguard Worker 				if (!strcasecmp(units, "khz")) {
1154*0d6140beSAndroid Build Coastguard Worker 					freq *= 1000;
1155*0d6140beSAndroid Build Coastguard Worker 					units_valid = true;
1156*0d6140beSAndroid Build Coastguard Worker 				} else if (!strcasecmp(units, "mhz")) {
1157*0d6140beSAndroid Build Coastguard Worker 					freq *= 1000000;
1158*0d6140beSAndroid Build Coastguard Worker 					units_valid = true;
1159*0d6140beSAndroid Build Coastguard Worker 				}
1160*0d6140beSAndroid Build Coastguard Worker 			}
1161*0d6140beSAndroid Build Coastguard Worker 
1162*0d6140beSAndroid Build Coastguard Worker 			if (!units_valid) {
1163*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Invalid units: %s\n", units);
1164*0d6140beSAndroid Build Coastguard Worker 				free(tmp);
1165*0d6140beSAndroid Build Coastguard Worker 				return 1;
1166*0d6140beSAndroid Build Coastguard Worker 			}
1167*0d6140beSAndroid Build Coastguard Worker 		}
1168*0d6140beSAndroid Build Coastguard Worker 
1169*0d6140beSAndroid Build Coastguard Worker 		if (freq == 0 || freq > 8000000000) {
1170*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: invalid value %llu for freq parameter\n", __func__, freq);
1171*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1172*0d6140beSAndroid Build Coastguard Worker 			return 1;
1173*0d6140beSAndroid Build Coastguard Worker 		}
1174*0d6140beSAndroid Build Coastguard Worker 		/* Assume we only work with bytes and transfer at 1 bit/Hz */
1175*0d6140beSAndroid Build Coastguard Worker 		data->delay_ns = (1000000000ull * 8) / freq;
1176*0d6140beSAndroid Build Coastguard Worker 	}
1177*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1178*0d6140beSAndroid Build Coastguard Worker 
1179*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "size");
1180*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1181*0d6140beSAndroid Build Coastguard Worker 		size = strtol(tmp, NULL, 10);
1182*0d6140beSAndroid Build Coastguard Worker 		if (size <= 0 || (size % 1024 != 0)) {
1183*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: Chip size is not a multiple of 1024: %s\n",
1184*0d6140beSAndroid Build Coastguard Worker 					 __func__, tmp);
1185*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1186*0d6140beSAndroid Build Coastguard Worker 			return 1;
1187*0d6140beSAndroid Build Coastguard Worker 		}
1188*0d6140beSAndroid Build Coastguard Worker 		free(tmp);
1189*0d6140beSAndroid Build Coastguard Worker 	}
1190*0d6140beSAndroid Build Coastguard Worker 
1191*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "hwwp");
1192*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1193*0d6140beSAndroid Build Coastguard Worker 		if (!strcmp(tmp, "yes")) {
1194*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Emulated chip will have hardware WP enabled\n");
1195*0d6140beSAndroid Build Coastguard Worker 			data->hwwp = true;
1196*0d6140beSAndroid Build Coastguard Worker 		} else if (!strcmp(tmp, "no")) {
1197*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Emulated chip will have hardware WP disabled\n");
1198*0d6140beSAndroid Build Coastguard Worker 		} else {
1199*0d6140beSAndroid Build Coastguard Worker 			msg_perr("hwwp can be \"yes\" or \"no\"\n");
1200*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1201*0d6140beSAndroid Build Coastguard Worker 			return 1;
1202*0d6140beSAndroid Build Coastguard Worker 		}
1203*0d6140beSAndroid Build Coastguard Worker 		free(tmp);
1204*0d6140beSAndroid Build Coastguard Worker 	}
1205*0d6140beSAndroid Build Coastguard Worker 
1206*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "emulate");
1207*0d6140beSAndroid Build Coastguard Worker 	if (!tmp) {
1208*0d6140beSAndroid Build Coastguard Worker 		if (size != -1) {
1209*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__);
1210*0d6140beSAndroid Build Coastguard Worker 			return 1;
1211*0d6140beSAndroid Build Coastguard Worker 		}
1212*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Not emulating any flash chip.\n");
1213*0d6140beSAndroid Build Coastguard Worker 		/* Nothing else to do. */
1214*0d6140beSAndroid Build Coastguard Worker 		return 0;
1215*0d6140beSAndroid Build Coastguard Worker 	}
1216*0d6140beSAndroid Build Coastguard Worker 
1217*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "M25P10.RES")) {
1218*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_ST_M25P10_RES;
1219*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 128 * 1024;
1220*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 128;
1221*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 0;
1222*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 1;
1223*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 0;
1224*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 0;
1225*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 32 * 1024;
1226*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = 0;
1227*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
1228*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
1229*0d6140beSAndroid Build Coastguard Worker 			 "write)\n");
1230*0d6140beSAndroid Build Coastguard Worker 	}
1231*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "SST25VF040.REMS")) {
1232*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_SST_SST25VF040_REMS;
1233*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 512 * 1024;
1234*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 1;
1235*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 0;
1236*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 1;
1237*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 4 * 1024;
1238*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 32 * 1024;
1239*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 0;
1240*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = data->emu_chip_size;
1241*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = 0;
1242*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
1243*0d6140beSAndroid Build Coastguard Worker 			 "byte write)\n");
1244*0d6140beSAndroid Build Coastguard Worker 	}
1245*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "SST25VF032B")) {
1246*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_SST_SST25VF032B;
1247*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 4 * 1024 * 1024;
1248*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 1;
1249*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 2;
1250*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 1;
1251*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 4 * 1024;
1252*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 32 * 1024;
1253*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 64 * 1024;
1254*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = data->emu_chip_size;
1255*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
1256*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
1257*0d6140beSAndroid Build Coastguard Worker 			 "write)\n");
1258*0d6140beSAndroid Build Coastguard Worker 	}
1259*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "MX25L6436")) {
1260*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_MACRONIX_MX25L6436;
1261*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 8 * 1024 * 1024;
1262*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 256;
1263*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 0;
1264*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 1;
1265*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 4 * 1024;
1266*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 32 * 1024;
1267*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 64 * 1024;
1268*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = data->emu_chip_size;
1269*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
1270*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
1271*0d6140beSAndroid Build Coastguard Worker 			 "SFDP)\n");
1272*0d6140beSAndroid Build Coastguard Worker 	}
1273*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "W25Q128FV")) {
1274*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_WINBOND_W25Q128FV;
1275*0d6140beSAndroid Build Coastguard Worker 		data->emu_wrsr_ext2 = true;
1276*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 16 * 1024 * 1024;
1277*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 256;
1278*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 0;
1279*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 3;
1280*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 4 * 1024;
1281*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 32 * 1024;
1282*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 64 * 1024;
1283*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = data->emu_chip_size;
1284*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
1285*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
1286*0d6140beSAndroid Build Coastguard Worker 	}
1287*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "S25FL128L")) {
1288*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_SPANSION_S25FL128L;
1289*0d6140beSAndroid Build Coastguard Worker 		data->emu_wrsr_ext2 = true;
1290*0d6140beSAndroid Build Coastguard Worker 		data->emu_wrsr_ext3 = true;
1291*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = 16 * 1024 * 1024;
1292*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_byteprogram_size = 256;
1293*0d6140beSAndroid Build Coastguard Worker 		data->emu_max_aai_size = 0;
1294*0d6140beSAndroid Build Coastguard Worker 		data->emu_status_len = 3;
1295*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_se_size = 4 * 1024;
1296*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_52_size = 32 * 1024;
1297*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_be_d8_size = 64 * 1024;
1298*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_60_size = data->emu_chip_size;
1299*0d6140beSAndroid Build Coastguard Worker 		data->emu_jedec_ce_c7_size = data->emu_chip_size;
1300*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating Spansion S25FL128L SPI flash chip (RES, RDID, WP)\n");
1301*0d6140beSAndroid Build Coastguard Worker 	}
1302*0d6140beSAndroid Build Coastguard Worker 
1303*0d6140beSAndroid Build Coastguard Worker 	/* The name of variable-size virtual chip. A 4 MiB flash example:
1304*0d6140beSAndroid Build Coastguard Worker 	 *   flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
1305*0d6140beSAndroid Build Coastguard Worker 	 */
1306*0d6140beSAndroid Build Coastguard Worker 	if (!strcmp(tmp, "VARIABLE_SIZE")) {
1307*0d6140beSAndroid Build Coastguard Worker 		if (size == -1) {
1308*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: the size parameter is not given.\n", __func__);
1309*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1310*0d6140beSAndroid Build Coastguard Worker 			return 1;
1311*0d6140beSAndroid Build Coastguard Worker 		}
1312*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip = EMULATE_VARIABLE_SIZE;
1313*0d6140beSAndroid Build Coastguard Worker 		data->emu_chip_size = size;
1314*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
1315*0d6140beSAndroid Build Coastguard Worker 		         data->emu_chip_size);
1316*0d6140beSAndroid Build Coastguard Worker 	} else if (size != -1) {
1317*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__);
1318*0d6140beSAndroid Build Coastguard Worker 		free(tmp);
1319*0d6140beSAndroid Build Coastguard Worker 		return 1;
1320*0d6140beSAndroid Build Coastguard Worker 	}
1321*0d6140beSAndroid Build Coastguard Worker 
1322*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_chip == EMULATE_NONE) {
1323*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Invalid chip specified for emulation: %s\n", tmp);
1324*0d6140beSAndroid Build Coastguard Worker 		free(tmp);
1325*0d6140beSAndroid Build Coastguard Worker 		return 1;
1326*0d6140beSAndroid Build Coastguard Worker 	}
1327*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1328*0d6140beSAndroid Build Coastguard Worker 
1329*0d6140beSAndroid Build Coastguard Worker 	/* Should emulated flash erase to zero (yes/no)? */
1330*0d6140beSAndroid Build Coastguard Worker 	tmp = extract_programmer_param_str(cfg, "erase_to_zero");
1331*0d6140beSAndroid Build Coastguard Worker 	if (tmp) {
1332*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_chip != EMULATE_VARIABLE_SIZE) {
1333*0d6140beSAndroid Build Coastguard Worker 			msg_perr("%s: erase_to_zero parameter is not valid for real chip.\n", __func__);
1334*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1335*0d6140beSAndroid Build Coastguard Worker 			return 1;
1336*0d6140beSAndroid Build Coastguard Worker 		}
1337*0d6140beSAndroid Build Coastguard Worker 		if (!strcmp(tmp, "yes")) {
1338*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Emulated chip will erase to 0x00\n");
1339*0d6140beSAndroid Build Coastguard Worker 			data->erase_to_zero = true;
1340*0d6140beSAndroid Build Coastguard Worker 		} else if (!strcmp(tmp, "no")) {
1341*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Emulated chip will erase to 0xff\n");
1342*0d6140beSAndroid Build Coastguard Worker 		} else {
1343*0d6140beSAndroid Build Coastguard Worker 			msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
1344*0d6140beSAndroid Build Coastguard Worker 			free(tmp);
1345*0d6140beSAndroid Build Coastguard Worker 			return 1;
1346*0d6140beSAndroid Build Coastguard Worker 		}
1347*0d6140beSAndroid Build Coastguard Worker 	}
1348*0d6140beSAndroid Build Coastguard Worker 	free(tmp);
1349*0d6140beSAndroid Build Coastguard Worker 
1350*0d6140beSAndroid Build Coastguard Worker 	status = extract_programmer_param_str(cfg, "spi_status");
1351*0d6140beSAndroid Build Coastguard Worker 	if (status) {
1352*0d6140beSAndroid Build Coastguard Worker 		unsigned int emu_status;
1353*0d6140beSAndroid Build Coastguard Worker 
1354*0d6140beSAndroid Build Coastguard Worker 		errno = 0;
1355*0d6140beSAndroid Build Coastguard Worker 		emu_status = strtoul(status, &endptr, 0);
1356*0d6140beSAndroid Build Coastguard Worker 		if (errno != 0 || status == endptr) {
1357*0d6140beSAndroid Build Coastguard Worker 			free(status);
1358*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: initial status register specified, "
1359*0d6140beSAndroid Build Coastguard Worker 				 "but the value could not be converted.\n");
1360*0d6140beSAndroid Build Coastguard Worker 			return 1;
1361*0d6140beSAndroid Build Coastguard Worker 		}
1362*0d6140beSAndroid Build Coastguard Worker 		free(status);
1363*0d6140beSAndroid Build Coastguard Worker 
1364*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[0] = emu_status;
1365*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[1] = emu_status >> 8;
1366*0d6140beSAndroid Build Coastguard Worker 		data->emu_status[2] = emu_status >> 16;
1367*0d6140beSAndroid Build Coastguard Worker 
1368*0d6140beSAndroid Build Coastguard Worker 		if (data->emu_status_len == 3) {
1369*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Initial status registers:\n"
1370*0d6140beSAndroid Build Coastguard Worker 				 "\tSR1 is set to 0x%02x\n"
1371*0d6140beSAndroid Build Coastguard Worker 				 "\tSR2 is set to 0x%02x\n"
1372*0d6140beSAndroid Build Coastguard Worker 				 "\tSR3 is set to 0x%02x\n",
1373*0d6140beSAndroid Build Coastguard Worker 				 data->emu_status[0], data->emu_status[1], data->emu_status[2]);
1374*0d6140beSAndroid Build Coastguard Worker 		} else if (data->emu_status_len == 2) {
1375*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Initial status registers:\n"
1376*0d6140beSAndroid Build Coastguard Worker 				 "\tSR1 is set to 0x%02x\n"
1377*0d6140beSAndroid Build Coastguard Worker 				 "\tSR2 is set to 0x%02x\n",
1378*0d6140beSAndroid Build Coastguard Worker 				 data->emu_status[0], data->emu_status[1]);
1379*0d6140beSAndroid Build Coastguard Worker 		} else {
1380*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Initial status register is set to 0x%02x.\n",
1381*0d6140beSAndroid Build Coastguard Worker 				 data->emu_status[0]);
1382*0d6140beSAndroid Build Coastguard Worker 		}
1383*0d6140beSAndroid Build Coastguard Worker 	}
1384*0d6140beSAndroid Build Coastguard Worker 
1385*0d6140beSAndroid Build Coastguard Worker 	data->flashchip_contents = malloc(data->emu_chip_size);
1386*0d6140beSAndroid Build Coastguard Worker 	if (!data->flashchip_contents) {
1387*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Out of memory!\n");
1388*0d6140beSAndroid Build Coastguard Worker 		return 1;
1389*0d6140beSAndroid Build Coastguard Worker 	}
1390*0d6140beSAndroid Build Coastguard Worker 
1391*0d6140beSAndroid Build Coastguard Worker 	return 0;
1392*0d6140beSAndroid Build Coastguard Worker }
1393*0d6140beSAndroid Build Coastguard Worker 
dummy_init(const struct programmer_cfg * cfg)1394*0d6140beSAndroid Build Coastguard Worker static int dummy_init(const struct programmer_cfg *cfg)
1395*0d6140beSAndroid Build Coastguard Worker {
1396*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
1397*0d6140beSAndroid Build Coastguard Worker 	struct stat image_stat;
1398*0d6140beSAndroid Build Coastguard Worker 
1399*0d6140beSAndroid Build Coastguard Worker 	struct emu_data *data = calloc(1, sizeof(*data));
1400*0d6140beSAndroid Build Coastguard Worker 	if (!data) {
1401*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Out of memory!\n");
1402*0d6140beSAndroid Build Coastguard Worker 		return 1;
1403*0d6140beSAndroid Build Coastguard Worker 	}
1404*0d6140beSAndroid Build Coastguard Worker 	data->emu_chip = EMULATE_NONE;
1405*0d6140beSAndroid Build Coastguard Worker 	data->delay_ns = 0;
1406*0d6140beSAndroid Build Coastguard Worker 	data->spi_write_256_chunksize = 256;
1407*0d6140beSAndroid Build Coastguard Worker 
1408*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s\n", __func__);
1409*0d6140beSAndroid Build Coastguard Worker 
1410*0d6140beSAndroid Build Coastguard Worker 	enum chipbustype dummy_buses_supported;
1411*0d6140beSAndroid Build Coastguard Worker 	if (init_data(cfg, data, &dummy_buses_supported)) {
1412*0d6140beSAndroid Build Coastguard Worker 		free(data);
1413*0d6140beSAndroid Build Coastguard Worker 		return 1;
1414*0d6140beSAndroid Build Coastguard Worker 	}
1415*0d6140beSAndroid Build Coastguard Worker 
1416*0d6140beSAndroid Build Coastguard Worker 	if (data->emu_chip == EMULATE_NONE) {
1417*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Not emulating any flash chip.\n");
1418*0d6140beSAndroid Build Coastguard Worker 		/* Nothing else to do. */
1419*0d6140beSAndroid Build Coastguard Worker 		goto dummy_init_out;
1420*0d6140beSAndroid Build Coastguard Worker 	}
1421*0d6140beSAndroid Build Coastguard Worker 
1422*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
1423*0d6140beSAndroid Build Coastguard Worker 			data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
1424*0d6140beSAndroid Build Coastguard Worker 	memset(data->flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
1425*0d6140beSAndroid Build Coastguard Worker 
1426*0d6140beSAndroid Build Coastguard Worker 	/* Will be freed by shutdown function if necessary. */
1427*0d6140beSAndroid Build Coastguard Worker 	data->emu_persistent_image = extract_programmer_param_str(cfg, "image");
1428*0d6140beSAndroid Build Coastguard Worker 	if (!data->emu_persistent_image) {
1429*0d6140beSAndroid Build Coastguard Worker 		/* Nothing else to do. */
1430*0d6140beSAndroid Build Coastguard Worker 		goto dummy_init_out;
1431*0d6140beSAndroid Build Coastguard Worker 	}
1432*0d6140beSAndroid Build Coastguard Worker 	/* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
1433*0d6140beSAndroid Build Coastguard Worker 	 * not match the emulated chip. */
1434*0d6140beSAndroid Build Coastguard Worker 	if (!stat(data->emu_persistent_image, &image_stat)) {
1435*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Found persistent image %s, %jd B ",
1436*0d6140beSAndroid Build Coastguard Worker 			 data->emu_persistent_image, (intmax_t)image_stat.st_size);
1437*0d6140beSAndroid Build Coastguard Worker 		if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
1438*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("matches.\n");
1439*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("Reading %s\n", data->emu_persistent_image);
1440*0d6140beSAndroid Build Coastguard Worker 			if (read_buf_from_file(data->flashchip_contents, data->emu_chip_size,
1441*0d6140beSAndroid Build Coastguard Worker 					   data->emu_persistent_image)) {
1442*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Unable to read %s\n", data->emu_persistent_image);
1443*0d6140beSAndroid Build Coastguard Worker 				free(data->emu_persistent_image);
1444*0d6140beSAndroid Build Coastguard Worker 				free(data->flashchip_contents);
1445*0d6140beSAndroid Build Coastguard Worker 				free(data);
1446*0d6140beSAndroid Build Coastguard Worker 				return 1;
1447*0d6140beSAndroid Build Coastguard Worker 			}
1448*0d6140beSAndroid Build Coastguard Worker 		} else {
1449*0d6140beSAndroid Build Coastguard Worker 			msg_pdbg("doesn't match.\n");
1450*0d6140beSAndroid Build Coastguard Worker 		}
1451*0d6140beSAndroid Build Coastguard Worker 	}
1452*0d6140beSAndroid Build Coastguard Worker 
1453*0d6140beSAndroid Build Coastguard Worker dummy_init_out:
1454*0d6140beSAndroid Build Coastguard Worker 	if (dummy_buses_supported & BUS_PROG) {
1455*0d6140beSAndroid Build Coastguard Worker 		data->refs_cnt++;
1456*0d6140beSAndroid Build Coastguard Worker 		ret |= register_opaque_master(&opaque_master_dummyflasher, data);
1457*0d6140beSAndroid Build Coastguard Worker 	}
1458*0d6140beSAndroid Build Coastguard Worker 	if ((dummy_buses_supported & BUS_NONSPI) && !ret) {
1459*0d6140beSAndroid Build Coastguard Worker 		data->refs_cnt++;
1460*0d6140beSAndroid Build Coastguard Worker 		ret |= register_par_master(&par_master_dummyflasher,
1461*0d6140beSAndroid Build Coastguard Worker 					   dummy_buses_supported & BUS_NONSPI,
1462*0d6140beSAndroid Build Coastguard Worker 					   data);
1463*0d6140beSAndroid Build Coastguard Worker 	}
1464*0d6140beSAndroid Build Coastguard Worker 	if ((dummy_buses_supported & BUS_SPI) && !ret) {
1465*0d6140beSAndroid Build Coastguard Worker 		data->refs_cnt++;
1466*0d6140beSAndroid Build Coastguard Worker 		ret |= register_spi_master(&spi_master_dummyflasher, data);
1467*0d6140beSAndroid Build Coastguard Worker 	}
1468*0d6140beSAndroid Build Coastguard Worker 
1469*0d6140beSAndroid Build Coastguard Worker 	return ret;
1470*0d6140beSAndroid Build Coastguard Worker }
1471*0d6140beSAndroid Build Coastguard Worker 
1472*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_dummy = {
1473*0d6140beSAndroid Build Coastguard Worker 	.name			= "dummy",
1474*0d6140beSAndroid Build Coastguard Worker 	.type			= OTHER,
1475*0d6140beSAndroid Build Coastguard Worker 				/* FIXME */
1476*0d6140beSAndroid Build Coastguard Worker 	.devs.note		= "Dummy device, does nothing and logs all accesses\n",
1477*0d6140beSAndroid Build Coastguard Worker 	.init			= dummy_init,
1478*0d6140beSAndroid Build Coastguard Worker };
1479