xref: /aosp_15_r20/external/flashrom/spi25.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) 2007, 2008, 2009, 2010 Carl-Daniel Hailfinger
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2008 coresystems GmbH
6*0d6140beSAndroid Build Coastguard Worker  *
7*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
8*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
9*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; version 2 of the License.
10*0d6140beSAndroid Build Coastguard Worker  *
11*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
12*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
15*0d6140beSAndroid Build Coastguard Worker  */
16*0d6140beSAndroid Build Coastguard Worker 
17*0d6140beSAndroid Build Coastguard Worker /*
18*0d6140beSAndroid Build Coastguard Worker  * Contains the common SPI chip driver functions
19*0d6140beSAndroid Build Coastguard Worker  */
20*0d6140beSAndroid Build Coastguard Worker 
21*0d6140beSAndroid Build Coastguard Worker #include <stddef.h>
22*0d6140beSAndroid Build Coastguard Worker #include <string.h>
23*0d6140beSAndroid Build Coastguard Worker #include <stdbool.h>
24*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
25*0d6140beSAndroid Build Coastguard Worker #include "flashchips.h"
26*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
27*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
28*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
29*0d6140beSAndroid Build Coastguard Worker 
30*0d6140beSAndroid Build Coastguard Worker enum id_type {
31*0d6140beSAndroid Build Coastguard Worker 	RDID,
32*0d6140beSAndroid Build Coastguard Worker 	RDID4,
33*0d6140beSAndroid Build Coastguard Worker 	REMS,
34*0d6140beSAndroid Build Coastguard Worker 	RES2,
35*0d6140beSAndroid Build Coastguard Worker 	RES3,
36*0d6140beSAndroid Build Coastguard Worker 	NUM_ID_TYPES,
37*0d6140beSAndroid Build Coastguard Worker };
38*0d6140beSAndroid Build Coastguard Worker 
39*0d6140beSAndroid Build Coastguard Worker static struct {
40*0d6140beSAndroid Build Coastguard Worker 	bool is_cached;
41*0d6140beSAndroid Build Coastguard Worker 	unsigned char bytes[4];		/* enough to hold largest ID type */
42*0d6140beSAndroid Build Coastguard Worker } id_cache[NUM_ID_TYPES];
43*0d6140beSAndroid Build Coastguard Worker 
clear_spi_id_cache(void)44*0d6140beSAndroid Build Coastguard Worker void clear_spi_id_cache(void)
45*0d6140beSAndroid Build Coastguard Worker {
46*0d6140beSAndroid Build Coastguard Worker 	memset(id_cache, 0, sizeof(id_cache));
47*0d6140beSAndroid Build Coastguard Worker 	return;
48*0d6140beSAndroid Build Coastguard Worker }
49*0d6140beSAndroid Build Coastguard Worker 
spi_rdid(struct flashctx * flash,unsigned char * readarr,int bytes)50*0d6140beSAndroid Build Coastguard Worker static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
51*0d6140beSAndroid Build Coastguard Worker {
52*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
53*0d6140beSAndroid Build Coastguard Worker 	int ret;
54*0d6140beSAndroid Build Coastguard Worker 	int i;
55*0d6140beSAndroid Build Coastguard Worker 
56*0d6140beSAndroid Build Coastguard Worker 	ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
57*0d6140beSAndroid Build Coastguard Worker 	if (ret)
58*0d6140beSAndroid Build Coastguard Worker 		return ret;
59*0d6140beSAndroid Build Coastguard Worker 	msg_cspew("RDID returned");
60*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < bytes; i++)
61*0d6140beSAndroid Build Coastguard Worker 		msg_cspew(" 0x%02x", readarr[i]);
62*0d6140beSAndroid Build Coastguard Worker 	msg_cspew(". ");
63*0d6140beSAndroid Build Coastguard Worker 	return 0;
64*0d6140beSAndroid Build Coastguard Worker }
65*0d6140beSAndroid Build Coastguard Worker 
spi_rems(struct flashctx * flash,unsigned char * readarr)66*0d6140beSAndroid Build Coastguard Worker static int spi_rems(struct flashctx *flash, unsigned char *readarr)
67*0d6140beSAndroid Build Coastguard Worker {
68*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, };
69*0d6140beSAndroid Build Coastguard Worker 	int ret;
70*0d6140beSAndroid Build Coastguard Worker 
71*0d6140beSAndroid Build Coastguard Worker 	ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
72*0d6140beSAndroid Build Coastguard Worker 	if (ret)
73*0d6140beSAndroid Build Coastguard Worker 		return ret;
74*0d6140beSAndroid Build Coastguard Worker 	msg_cspew("REMS returned 0x%02x 0x%02x. ", readarr[0], readarr[1]);
75*0d6140beSAndroid Build Coastguard Worker 	return 0;
76*0d6140beSAndroid Build Coastguard Worker }
77*0d6140beSAndroid Build Coastguard Worker 
spi_res(struct flashctx * flash,unsigned char * readarr,int bytes)78*0d6140beSAndroid Build Coastguard Worker static int spi_res(struct flashctx *flash, unsigned char *readarr, int bytes)
79*0d6140beSAndroid Build Coastguard Worker {
80*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, };
81*0d6140beSAndroid Build Coastguard Worker 	int ret;
82*0d6140beSAndroid Build Coastguard Worker 	int i;
83*0d6140beSAndroid Build Coastguard Worker 
84*0d6140beSAndroid Build Coastguard Worker 	ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
85*0d6140beSAndroid Build Coastguard Worker 	if (ret)
86*0d6140beSAndroid Build Coastguard Worker 		return ret;
87*0d6140beSAndroid Build Coastguard Worker 	msg_cspew("RES returned");
88*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < bytes; i++)
89*0d6140beSAndroid Build Coastguard Worker 		msg_cspew(" 0x%02x", readarr[i]);
90*0d6140beSAndroid Build Coastguard Worker 	msg_cspew(". ");
91*0d6140beSAndroid Build Coastguard Worker 	return 0;
92*0d6140beSAndroid Build Coastguard Worker }
93*0d6140beSAndroid Build Coastguard Worker 
spi_write_enable(struct flashctx * flash)94*0d6140beSAndroid Build Coastguard Worker int spi_write_enable(struct flashctx *flash)
95*0d6140beSAndroid Build Coastguard Worker {
96*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
97*0d6140beSAndroid Build Coastguard Worker 	int result;
98*0d6140beSAndroid Build Coastguard Worker 
99*0d6140beSAndroid Build Coastguard Worker 	/* Send WREN (Write Enable) */
100*0d6140beSAndroid Build Coastguard Worker 	result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
101*0d6140beSAndroid Build Coastguard Worker 
102*0d6140beSAndroid Build Coastguard Worker 	if (result)
103*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed\n", __func__);
104*0d6140beSAndroid Build Coastguard Worker 
105*0d6140beSAndroid Build Coastguard Worker 	return result;
106*0d6140beSAndroid Build Coastguard Worker }
107*0d6140beSAndroid Build Coastguard Worker 
spi_write_disable(struct flashctx * flash)108*0d6140beSAndroid Build Coastguard Worker int spi_write_disable(struct flashctx *flash)
109*0d6140beSAndroid Build Coastguard Worker {
110*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
111*0d6140beSAndroid Build Coastguard Worker 
112*0d6140beSAndroid Build Coastguard Worker 	/* Send WRDI (Write Disable) */
113*0d6140beSAndroid Build Coastguard Worker 	return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
114*0d6140beSAndroid Build Coastguard Worker }
115*0d6140beSAndroid Build Coastguard Worker 
rdid_get_ids(unsigned char * readarr,int bytes,uint32_t * id1,uint32_t * id2)116*0d6140beSAndroid Build Coastguard Worker static void rdid_get_ids(unsigned char *readarr, int bytes,
117*0d6140beSAndroid Build Coastguard Worker 		uint32_t *id1, uint32_t *id2)
118*0d6140beSAndroid Build Coastguard Worker {
119*0d6140beSAndroid Build Coastguard Worker 	if (!oddparity(readarr[0]))
120*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("RDID byte 0 parity violation. ");
121*0d6140beSAndroid Build Coastguard Worker 
122*0d6140beSAndroid Build Coastguard Worker 	/* Check if this is a continuation vendor ID.
123*0d6140beSAndroid Build Coastguard Worker 	 * FIXME: Handle continuation device IDs.
124*0d6140beSAndroid Build Coastguard Worker 	 */
125*0d6140beSAndroid Build Coastguard Worker 	if (readarr[0] == 0x7f) {
126*0d6140beSAndroid Build Coastguard Worker 		if (!oddparity(readarr[1]))
127*0d6140beSAndroid Build Coastguard Worker 			msg_cdbg("RDID byte 1 parity violation. ");
128*0d6140beSAndroid Build Coastguard Worker 		*id1 = (readarr[0] << 8) | readarr[1];
129*0d6140beSAndroid Build Coastguard Worker 		*id2 = readarr[2];
130*0d6140beSAndroid Build Coastguard Worker 		if (bytes > 3) {
131*0d6140beSAndroid Build Coastguard Worker 			*id2 <<= 8;
132*0d6140beSAndroid Build Coastguard Worker 			*id2 |= readarr[3];
133*0d6140beSAndroid Build Coastguard Worker 		}
134*0d6140beSAndroid Build Coastguard Worker 	} else {
135*0d6140beSAndroid Build Coastguard Worker 		*id1 = readarr[0];
136*0d6140beSAndroid Build Coastguard Worker 		*id2 = (readarr[1] << 8) | readarr[2];
137*0d6140beSAndroid Build Coastguard Worker 	}
138*0d6140beSAndroid Build Coastguard Worker }
139*0d6140beSAndroid Build Coastguard Worker 
compare_id(const struct flashctx * flash,uint32_t id1,uint32_t id2)140*0d6140beSAndroid Build Coastguard Worker static int compare_id(const struct flashctx *flash, uint32_t id1, uint32_t id2)
141*0d6140beSAndroid Build Coastguard Worker {
142*0d6140beSAndroid Build Coastguard Worker 	const struct flashchip *chip = flash->chip;
143*0d6140beSAndroid Build Coastguard Worker 
144*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2);
145*0d6140beSAndroid Build Coastguard Worker 	if (id1 == chip->manufacture_id && id2 == chip->model_id)
146*0d6140beSAndroid Build Coastguard Worker 		return 1;
147*0d6140beSAndroid Build Coastguard Worker 
148*0d6140beSAndroid Build Coastguard Worker 	/* Test if this is a pure vendor match. */
149*0d6140beSAndroid Build Coastguard Worker 	if (id1 == chip->manufacture_id && GENERIC_DEVICE_ID == chip->model_id)
150*0d6140beSAndroid Build Coastguard Worker 		return 1;
151*0d6140beSAndroid Build Coastguard Worker 
152*0d6140beSAndroid Build Coastguard Worker 	/* Test if there is any vendor ID. */
153*0d6140beSAndroid Build Coastguard Worker 	if (GENERIC_MANUF_ID == chip->manufacture_id && id1 != 0xff && id1 != 0x00)
154*0d6140beSAndroid Build Coastguard Worker 		return 1;
155*0d6140beSAndroid Build Coastguard Worker 
156*0d6140beSAndroid Build Coastguard Worker 	return 0;
157*0d6140beSAndroid Build Coastguard Worker }
158*0d6140beSAndroid Build Coastguard Worker 
probe_spi_rdid_generic(struct flashctx * flash,int bytes)159*0d6140beSAndroid Build Coastguard Worker static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
160*0d6140beSAndroid Build Coastguard Worker {
161*0d6140beSAndroid Build Coastguard Worker 	uint32_t id1, id2;
162*0d6140beSAndroid Build Coastguard Worker 	enum id_type idty = bytes == 3 ? RDID : RDID4;
163*0d6140beSAndroid Build Coastguard Worker 
164*0d6140beSAndroid Build Coastguard Worker 	if (!id_cache[idty].is_cached) {
165*0d6140beSAndroid Build Coastguard Worker 		const int ret = spi_rdid(flash, id_cache[idty].bytes, bytes);
166*0d6140beSAndroid Build Coastguard Worker 		if (ret == SPI_INVALID_LENGTH)
167*0d6140beSAndroid Build Coastguard Worker 			msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes);
168*0d6140beSAndroid Build Coastguard Worker 		if (ret)
169*0d6140beSAndroid Build Coastguard Worker 			return 0;
170*0d6140beSAndroid Build Coastguard Worker 		id_cache[idty].is_cached = true;
171*0d6140beSAndroid Build Coastguard Worker 	}
172*0d6140beSAndroid Build Coastguard Worker 
173*0d6140beSAndroid Build Coastguard Worker 	rdid_get_ids(id_cache[idty].bytes, bytes, &id1, &id2);
174*0d6140beSAndroid Build Coastguard Worker 	return compare_id(flash, id1, id2);
175*0d6140beSAndroid Build Coastguard Worker }
176*0d6140beSAndroid Build Coastguard Worker 
probe_spi_rdid(struct flashctx * flash)177*0d6140beSAndroid Build Coastguard Worker int probe_spi_rdid(struct flashctx *flash)
178*0d6140beSAndroid Build Coastguard Worker {
179*0d6140beSAndroid Build Coastguard Worker 	return probe_spi_rdid_generic(flash, 3);
180*0d6140beSAndroid Build Coastguard Worker }
181*0d6140beSAndroid Build Coastguard Worker 
probe_spi_rdid4(struct flashctx * flash)182*0d6140beSAndroid Build Coastguard Worker int probe_spi_rdid4(struct flashctx *flash)
183*0d6140beSAndroid Build Coastguard Worker {
184*0d6140beSAndroid Build Coastguard Worker 	return probe_spi_rdid_generic(flash, 4);
185*0d6140beSAndroid Build Coastguard Worker }
186*0d6140beSAndroid Build Coastguard Worker 
probe_spi_rems(struct flashctx * flash)187*0d6140beSAndroid Build Coastguard Worker int probe_spi_rems(struct flashctx *flash)
188*0d6140beSAndroid Build Coastguard Worker {
189*0d6140beSAndroid Build Coastguard Worker 	uint32_t id1, id2;
190*0d6140beSAndroid Build Coastguard Worker 
191*0d6140beSAndroid Build Coastguard Worker 	if (!id_cache[REMS].is_cached) {
192*0d6140beSAndroid Build Coastguard Worker 		if (spi_rems(flash, id_cache[REMS].bytes))
193*0d6140beSAndroid Build Coastguard Worker 			return 0;
194*0d6140beSAndroid Build Coastguard Worker 		id_cache[REMS].is_cached = true;
195*0d6140beSAndroid Build Coastguard Worker 	}
196*0d6140beSAndroid Build Coastguard Worker 
197*0d6140beSAndroid Build Coastguard Worker 	id1 = id_cache[REMS].bytes[0];
198*0d6140beSAndroid Build Coastguard Worker 	id2 = id_cache[REMS].bytes[1];
199*0d6140beSAndroid Build Coastguard Worker 	return compare_id(flash, id1, id2);
200*0d6140beSAndroid Build Coastguard Worker }
201*0d6140beSAndroid Build Coastguard Worker 
probe_spi_res1(struct flashctx * flash)202*0d6140beSAndroid Build Coastguard Worker int probe_spi_res1(struct flashctx *flash)
203*0d6140beSAndroid Build Coastguard Worker {
204*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char allff[] = {0xff, 0xff, 0xff};
205*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char all00[] = {0x00, 0x00, 0x00};
206*0d6140beSAndroid Build Coastguard Worker 	unsigned char readarr[3];
207*0d6140beSAndroid Build Coastguard Worker 	uint32_t id2;
208*0d6140beSAndroid Build Coastguard Worker 
209*0d6140beSAndroid Build Coastguard Worker 	/* We only want one-byte RES if RDID and REMS are unusable. */
210*0d6140beSAndroid Build Coastguard Worker 
211*0d6140beSAndroid Build Coastguard Worker 	/* Check if RDID is usable and does not return 0xff 0xff 0xff or
212*0d6140beSAndroid Build Coastguard Worker 	 * 0x00 0x00 0x00. In that case, RES is pointless.
213*0d6140beSAndroid Build Coastguard Worker 	 */
214*0d6140beSAndroid Build Coastguard Worker 	if (!spi_rdid(flash, readarr, 3) && memcmp(readarr, allff, 3) &&
215*0d6140beSAndroid Build Coastguard Worker 	    memcmp(readarr, all00, 3)) {
216*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("Ignoring RES in favour of RDID.\n");
217*0d6140beSAndroid Build Coastguard Worker 		return 0;
218*0d6140beSAndroid Build Coastguard Worker 	}
219*0d6140beSAndroid Build Coastguard Worker 	/* Check if REMS is usable and does not return 0xff 0xff or
220*0d6140beSAndroid Build Coastguard Worker 	 * 0x00 0x00. In that case, RES is pointless.
221*0d6140beSAndroid Build Coastguard Worker 	 */
222*0d6140beSAndroid Build Coastguard Worker 	if (!spi_rems(flash, readarr) &&
223*0d6140beSAndroid Build Coastguard Worker 	    memcmp(readarr, allff, JEDEC_REMS_INSIZE) &&
224*0d6140beSAndroid Build Coastguard Worker 	    memcmp(readarr, all00, JEDEC_REMS_INSIZE)) {
225*0d6140beSAndroid Build Coastguard Worker 		msg_cdbg("Ignoring RES in favour of REMS.\n");
226*0d6140beSAndroid Build Coastguard Worker 		return 0;
227*0d6140beSAndroid Build Coastguard Worker 	}
228*0d6140beSAndroid Build Coastguard Worker 
229*0d6140beSAndroid Build Coastguard Worker 	if (spi_res(flash, readarr, 1)) {
230*0d6140beSAndroid Build Coastguard Worker 		return 0;
231*0d6140beSAndroid Build Coastguard Worker 	}
232*0d6140beSAndroid Build Coastguard Worker 
233*0d6140beSAndroid Build Coastguard Worker 	id2 = readarr[0];
234*0d6140beSAndroid Build Coastguard Worker 
235*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: id 0x%"PRIx32"\n", __func__, id2);
236*0d6140beSAndroid Build Coastguard Worker 
237*0d6140beSAndroid Build Coastguard Worker 	if (id2 != flash->chip->model_id)
238*0d6140beSAndroid Build Coastguard Worker 		return 0;
239*0d6140beSAndroid Build Coastguard Worker 
240*0d6140beSAndroid Build Coastguard Worker 	return 1;
241*0d6140beSAndroid Build Coastguard Worker }
242*0d6140beSAndroid Build Coastguard Worker 
probe_spi_res2(struct flashctx * flash)243*0d6140beSAndroid Build Coastguard Worker int probe_spi_res2(struct flashctx *flash)
244*0d6140beSAndroid Build Coastguard Worker {
245*0d6140beSAndroid Build Coastguard Worker 	uint32_t id1, id2;
246*0d6140beSAndroid Build Coastguard Worker 
247*0d6140beSAndroid Build Coastguard Worker 	if (!id_cache[RES2].is_cached) {
248*0d6140beSAndroid Build Coastguard Worker 		if (spi_res(flash, id_cache[RES2].bytes, 2))
249*0d6140beSAndroid Build Coastguard Worker 			return 0;
250*0d6140beSAndroid Build Coastguard Worker 		id_cache[RES2].is_cached = true;
251*0d6140beSAndroid Build Coastguard Worker 	}
252*0d6140beSAndroid Build Coastguard Worker 
253*0d6140beSAndroid Build Coastguard Worker 	id1 = id_cache[RES2].bytes[0];
254*0d6140beSAndroid Build Coastguard Worker 	id2 = id_cache[RES2].bytes[1];
255*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2);
256*0d6140beSAndroid Build Coastguard Worker 
257*0d6140beSAndroid Build Coastguard Worker 	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
258*0d6140beSAndroid Build Coastguard Worker 		return 0;
259*0d6140beSAndroid Build Coastguard Worker 
260*0d6140beSAndroid Build Coastguard Worker 	return 1;
261*0d6140beSAndroid Build Coastguard Worker }
262*0d6140beSAndroid Build Coastguard Worker 
probe_spi_res3(struct flashctx * flash)263*0d6140beSAndroid Build Coastguard Worker int probe_spi_res3(struct flashctx *flash)
264*0d6140beSAndroid Build Coastguard Worker {
265*0d6140beSAndroid Build Coastguard Worker 	uint32_t id1, id2;
266*0d6140beSAndroid Build Coastguard Worker 
267*0d6140beSAndroid Build Coastguard Worker 	if (!id_cache[RES3].is_cached) {
268*0d6140beSAndroid Build Coastguard Worker 		if (spi_res(flash, id_cache[RES3].bytes, 3))
269*0d6140beSAndroid Build Coastguard Worker 			return 0;
270*0d6140beSAndroid Build Coastguard Worker 		id_cache[RES3].is_cached = true;
271*0d6140beSAndroid Build Coastguard Worker 	}
272*0d6140beSAndroid Build Coastguard Worker 
273*0d6140beSAndroid Build Coastguard Worker 	id1 = (id_cache[RES3].bytes[0] << 8) | id_cache[RES3].bytes[1];
274*0d6140beSAndroid Build Coastguard Worker 	id2 = id_cache[RES3].bytes[3];
275*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2);
276*0d6140beSAndroid Build Coastguard Worker 
277*0d6140beSAndroid Build Coastguard Worker 	if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
278*0d6140beSAndroid Build Coastguard Worker 		return 0;
279*0d6140beSAndroid Build Coastguard Worker 
280*0d6140beSAndroid Build Coastguard Worker 	return 1;
281*0d6140beSAndroid Build Coastguard Worker }
282*0d6140beSAndroid Build Coastguard Worker 
283*0d6140beSAndroid Build Coastguard Worker /* Only used for some Atmel chips. */
probe_spi_at25f(struct flashctx * flash)284*0d6140beSAndroid Build Coastguard Worker int probe_spi_at25f(struct flashctx *flash)
285*0d6140beSAndroid Build Coastguard Worker {
286*0d6140beSAndroid Build Coastguard Worker 	static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
287*0d6140beSAndroid Build Coastguard Worker 	unsigned char readarr[AT25F_RDID_INSIZE];
288*0d6140beSAndroid Build Coastguard Worker 	uint32_t id1;
289*0d6140beSAndroid Build Coastguard Worker 	uint32_t id2;
290*0d6140beSAndroid Build Coastguard Worker 
291*0d6140beSAndroid Build Coastguard Worker 	if (spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr))
292*0d6140beSAndroid Build Coastguard Worker 		return 0;
293*0d6140beSAndroid Build Coastguard Worker 
294*0d6140beSAndroid Build Coastguard Worker 	id1 = readarr[0];
295*0d6140beSAndroid Build Coastguard Worker 	id2 = readarr[1];
296*0d6140beSAndroid Build Coastguard Worker 
297*0d6140beSAndroid Build Coastguard Worker 	msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2);
298*0d6140beSAndroid Build Coastguard Worker 
299*0d6140beSAndroid Build Coastguard Worker 	if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
300*0d6140beSAndroid Build Coastguard Worker 		return 1;
301*0d6140beSAndroid Build Coastguard Worker 
302*0d6140beSAndroid Build Coastguard Worker 	return 0;
303*0d6140beSAndroid Build Coastguard Worker }
304*0d6140beSAndroid Build Coastguard Worker 
spi_poll_wip(struct flashctx * const flash,const unsigned int poll_delay)305*0d6140beSAndroid Build Coastguard Worker static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
306*0d6140beSAndroid Build Coastguard Worker {
307*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: We don't time out. */
308*0d6140beSAndroid Build Coastguard Worker 	while (true) {
309*0d6140beSAndroid Build Coastguard Worker 		uint8_t status;
310*0d6140beSAndroid Build Coastguard Worker 		int ret = spi_read_register(flash, STATUS1, &status);
311*0d6140beSAndroid Build Coastguard Worker 		if (ret)
312*0d6140beSAndroid Build Coastguard Worker 			return ret;
313*0d6140beSAndroid Build Coastguard Worker 		if (!(status & SPI_SR_WIP))
314*0d6140beSAndroid Build Coastguard Worker 			return 0;
315*0d6140beSAndroid Build Coastguard Worker 
316*0d6140beSAndroid Build Coastguard Worker 		programmer_delay(flash, poll_delay);
317*0d6140beSAndroid Build Coastguard Worker 	}
318*0d6140beSAndroid Build Coastguard Worker }
319*0d6140beSAndroid Build Coastguard Worker 
320*0d6140beSAndroid Build Coastguard Worker /**
321*0d6140beSAndroid Build Coastguard Worker  * Execute WREN plus another one byte `op`, optionally poll WIP afterwards.
322*0d6140beSAndroid Build Coastguard Worker  *
323*0d6140beSAndroid Build Coastguard Worker  * @param flash       the flash chip's context
324*0d6140beSAndroid Build Coastguard Worker  * @param op          the operation to execute
325*0d6140beSAndroid Build Coastguard Worker  * @param poll_delay  interval in us for polling WIP, don't poll if zero
326*0d6140beSAndroid Build Coastguard Worker  * @return 0 on success, non-zero otherwise
327*0d6140beSAndroid Build Coastguard Worker  */
spi_simple_write_cmd(struct flashctx * const flash,const uint8_t op,const unsigned int poll_delay)328*0d6140beSAndroid Build Coastguard Worker static int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, const unsigned int poll_delay)
329*0d6140beSAndroid Build Coastguard Worker {
330*0d6140beSAndroid Build Coastguard Worker 	struct spi_command cmds[] = {
331*0d6140beSAndroid Build Coastguard Worker 	{
332*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
333*0d6140beSAndroid Build Coastguard Worker 		.writecnt = JEDEC_WREN_OUTSIZE,
334*0d6140beSAndroid Build Coastguard Worker 		.writearr = (const unsigned char[]){ JEDEC_WREN },
335*0d6140beSAndroid Build Coastguard Worker 	}, {
336*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
337*0d6140beSAndroid Build Coastguard Worker 		.writecnt = 1,
338*0d6140beSAndroid Build Coastguard Worker 		.writearr = (const unsigned char[]){ op },
339*0d6140beSAndroid Build Coastguard Worker 	},
340*0d6140beSAndroid Build Coastguard Worker 		NULL_SPI_CMD,
341*0d6140beSAndroid Build Coastguard Worker 	};
342*0d6140beSAndroid Build Coastguard Worker 
343*0d6140beSAndroid Build Coastguard Worker 	const int result = spi_send_multicommand(flash, cmds);
344*0d6140beSAndroid Build Coastguard Worker 	if (result)
345*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed during command execution\n", __func__);
346*0d6140beSAndroid Build Coastguard Worker 
347*0d6140beSAndroid Build Coastguard Worker 	const int status = poll_delay ? spi_poll_wip(flash, poll_delay) : 0;
348*0d6140beSAndroid Build Coastguard Worker 
349*0d6140beSAndroid Build Coastguard Worker 	return result ? result : status;
350*0d6140beSAndroid Build Coastguard Worker }
351*0d6140beSAndroid Build Coastguard Worker 
spi_write_extended_address_register(struct flashctx * const flash,const uint8_t regdata)352*0d6140beSAndroid Build Coastguard Worker static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
353*0d6140beSAndroid Build Coastguard Worker {
354*0d6140beSAndroid Build Coastguard Worker 	uint8_t op;
355*0d6140beSAndroid Build Coastguard Worker 	if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
356*0d6140beSAndroid Build Coastguard Worker 		op = JEDEC_WRITE_EXT_ADDR_REG;
357*0d6140beSAndroid Build Coastguard Worker 	} else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
358*0d6140beSAndroid Build Coastguard Worker 		op = ALT_WRITE_EXT_ADDR_REG_17;
359*0d6140beSAndroid Build Coastguard Worker 	} else {
360*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("Flash misses feature flag for extended-address register.\n");
361*0d6140beSAndroid Build Coastguard Worker 		return -1;
362*0d6140beSAndroid Build Coastguard Worker 	}
363*0d6140beSAndroid Build Coastguard Worker 
364*0d6140beSAndroid Build Coastguard Worker 	struct spi_command cmds[] = {
365*0d6140beSAndroid Build Coastguard Worker 	{
366*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
367*0d6140beSAndroid Build Coastguard Worker 		.writecnt = 1,
368*0d6140beSAndroid Build Coastguard Worker 		.writearr = (const unsigned char[]){ JEDEC_WREN },
369*0d6140beSAndroid Build Coastguard Worker 	}, {
370*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
371*0d6140beSAndroid Build Coastguard Worker 		.writecnt = 2,
372*0d6140beSAndroid Build Coastguard Worker 		.writearr = (const unsigned char[]){ op, regdata },
373*0d6140beSAndroid Build Coastguard Worker 	},
374*0d6140beSAndroid Build Coastguard Worker 		NULL_SPI_CMD,
375*0d6140beSAndroid Build Coastguard Worker 	};
376*0d6140beSAndroid Build Coastguard Worker 
377*0d6140beSAndroid Build Coastguard Worker 	const int result = spi_send_multicommand(flash, cmds);
378*0d6140beSAndroid Build Coastguard Worker 	if (result)
379*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed during command execution\n", __func__);
380*0d6140beSAndroid Build Coastguard Worker 	return result;
381*0d6140beSAndroid Build Coastguard Worker }
382*0d6140beSAndroid Build Coastguard Worker 
spi_set_extended_address(struct flashctx * const flash,const uint8_t addr_high)383*0d6140beSAndroid Build Coastguard Worker int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
384*0d6140beSAndroid Build Coastguard Worker {
385*0d6140beSAndroid Build Coastguard Worker 	if (flash->address_high_byte != addr_high &&
386*0d6140beSAndroid Build Coastguard Worker 	    spi_write_extended_address_register(flash, addr_high))
387*0d6140beSAndroid Build Coastguard Worker 		return -1;
388*0d6140beSAndroid Build Coastguard Worker 	flash->address_high_byte = addr_high;
389*0d6140beSAndroid Build Coastguard Worker 	return 0;
390*0d6140beSAndroid Build Coastguard Worker }
391*0d6140beSAndroid Build Coastguard Worker 
spi_prepare_address(struct flashctx * const flash,uint8_t cmd_buf[],const bool native_4ba,const unsigned int addr)392*0d6140beSAndroid Build Coastguard Worker static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
393*0d6140beSAndroid Build Coastguard Worker 			       const bool native_4ba, const unsigned int addr)
394*0d6140beSAndroid Build Coastguard Worker {
395*0d6140beSAndroid Build Coastguard Worker 	if (native_4ba || flash->in_4ba_mode) {
396*0d6140beSAndroid Build Coastguard Worker 		if (!spi_master_4ba(flash)) {
397*0d6140beSAndroid Build Coastguard Worker 			msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n");
398*0d6140beSAndroid Build Coastguard Worker 			return -1;
399*0d6140beSAndroid Build Coastguard Worker 		}
400*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[1] = (addr >> 24) & 0xff;
401*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[2] = (addr >> 16) & 0xff;
402*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[3] = (addr >>  8) & 0xff;
403*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[4] = (addr >>  0) & 0xff;
404*0d6140beSAndroid Build Coastguard Worker 		return 4;
405*0d6140beSAndroid Build Coastguard Worker 	} else {
406*0d6140beSAndroid Build Coastguard Worker 		if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
407*0d6140beSAndroid Build Coastguard Worker 			if (spi_set_extended_address(flash, addr >> 24))
408*0d6140beSAndroid Build Coastguard Worker 				return -1;
409*0d6140beSAndroid Build Coastguard Worker 		} else if (addr >> 24) {
410*0d6140beSAndroid Build Coastguard Worker 			msg_cerr("Can't handle 4-byte address for opcode '0x%02x'\n"
411*0d6140beSAndroid Build Coastguard Worker 				 "with this chip/programmer combination.\n", cmd_buf[0]);
412*0d6140beSAndroid Build Coastguard Worker 			return -1;
413*0d6140beSAndroid Build Coastguard Worker 		}
414*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[1] = (addr >> 16) & 0xff;
415*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[2] = (addr >>  8) & 0xff;
416*0d6140beSAndroid Build Coastguard Worker 		cmd_buf[3] = (addr >>  0) & 0xff;
417*0d6140beSAndroid Build Coastguard Worker 		return 3;
418*0d6140beSAndroid Build Coastguard Worker 	}
419*0d6140beSAndroid Build Coastguard Worker }
420*0d6140beSAndroid Build Coastguard Worker 
421*0d6140beSAndroid Build Coastguard Worker /**
422*0d6140beSAndroid Build Coastguard Worker  * Execute WREN plus another `op` that takes an address and
423*0d6140beSAndroid Build Coastguard Worker  * optional data, poll WIP afterwards.
424*0d6140beSAndroid Build Coastguard Worker  *
425*0d6140beSAndroid Build Coastguard Worker  * @param flash       the flash chip's context
426*0d6140beSAndroid Build Coastguard Worker  * @param op          the operation to execute
427*0d6140beSAndroid Build Coastguard Worker  * @param native_4ba  whether `op` always takes a 4-byte address
428*0d6140beSAndroid Build Coastguard Worker  * @param addr        the address parameter to `op`
429*0d6140beSAndroid Build Coastguard Worker  * @param out_bytes   bytes to send after the address,
430*0d6140beSAndroid Build Coastguard Worker  *                    may be NULL if and only if `out_bytes` is 0
431*0d6140beSAndroid Build Coastguard Worker  * @param out_bytes   number of bytes to send, 256 at most, may be zero
432*0d6140beSAndroid Build Coastguard Worker  * @param poll_delay  interval in us for polling WIP
433*0d6140beSAndroid Build Coastguard Worker  * @return 0 on success, non-zero otherwise
434*0d6140beSAndroid Build Coastguard Worker  */
spi_write_cmd(struct flashctx * const flash,const uint8_t op,const bool native_4ba,const unsigned int addr,const uint8_t * const out_bytes,const size_t out_len,const unsigned int poll_delay)435*0d6140beSAndroid Build Coastguard Worker static int spi_write_cmd(struct flashctx *const flash, const uint8_t op,
436*0d6140beSAndroid Build Coastguard Worker 			 const bool native_4ba, const unsigned int addr,
437*0d6140beSAndroid Build Coastguard Worker 			 const uint8_t *const out_bytes, const size_t out_len,
438*0d6140beSAndroid Build Coastguard Worker 			 const unsigned int poll_delay)
439*0d6140beSAndroid Build Coastguard Worker {
440*0d6140beSAndroid Build Coastguard Worker 	uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN + 256];
441*0d6140beSAndroid Build Coastguard Worker 	struct spi_command cmds[] = {
442*0d6140beSAndroid Build Coastguard Worker 	{
443*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
444*0d6140beSAndroid Build Coastguard Worker 		.writecnt = 1,
445*0d6140beSAndroid Build Coastguard Worker 		.writearr = (const unsigned char[]){ JEDEC_WREN },
446*0d6140beSAndroid Build Coastguard Worker 	}, {
447*0d6140beSAndroid Build Coastguard Worker 		.readarr = 0,
448*0d6140beSAndroid Build Coastguard Worker 		.writearr = cmd,
449*0d6140beSAndroid Build Coastguard Worker 	},
450*0d6140beSAndroid Build Coastguard Worker 		NULL_SPI_CMD,
451*0d6140beSAndroid Build Coastguard Worker 	};
452*0d6140beSAndroid Build Coastguard Worker 
453*0d6140beSAndroid Build Coastguard Worker 	cmd[0] = op;
454*0d6140beSAndroid Build Coastguard Worker 	const int addr_len = spi_prepare_address(flash, cmd, native_4ba, addr);
455*0d6140beSAndroid Build Coastguard Worker 	if (addr_len < 0)
456*0d6140beSAndroid Build Coastguard Worker 		return 1;
457*0d6140beSAndroid Build Coastguard Worker 
458*0d6140beSAndroid Build Coastguard Worker 	if (1 + addr_len + out_len > sizeof(cmd)) {
459*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s called for too long a write\n", __func__);
460*0d6140beSAndroid Build Coastguard Worker 		return 1;
461*0d6140beSAndroid Build Coastguard Worker 	}
462*0d6140beSAndroid Build Coastguard Worker 	if (!out_bytes && out_len > 0)
463*0d6140beSAndroid Build Coastguard Worker 		return 1;
464*0d6140beSAndroid Build Coastguard Worker 
465*0d6140beSAndroid Build Coastguard Worker 	memcpy(cmd + 1 + addr_len, out_bytes, out_len);
466*0d6140beSAndroid Build Coastguard Worker 	cmds[1].writecnt = 1 + addr_len + out_len;
467*0d6140beSAndroid Build Coastguard Worker 
468*0d6140beSAndroid Build Coastguard Worker 	const int result = spi_send_multicommand(flash, cmds);
469*0d6140beSAndroid Build Coastguard Worker 	if (result)
470*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
471*0d6140beSAndroid Build Coastguard Worker 
472*0d6140beSAndroid Build Coastguard Worker 	const int status = spi_poll_wip(flash, poll_delay);
473*0d6140beSAndroid Build Coastguard Worker 
474*0d6140beSAndroid Build Coastguard Worker 	return result ? result : status;
475*0d6140beSAndroid Build Coastguard Worker }
476*0d6140beSAndroid Build Coastguard Worker 
spi_chip_erase_60(struct flashctx * flash)477*0d6140beSAndroid Build Coastguard Worker static int spi_chip_erase_60(struct flashctx *flash)
478*0d6140beSAndroid Build Coastguard Worker {
479*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 1-85s, so wait in 1s steps. */
480*0d6140beSAndroid Build Coastguard Worker 	return spi_simple_write_cmd(flash, JEDEC_CE_60, 1000 * 1000);
481*0d6140beSAndroid Build Coastguard Worker }
482*0d6140beSAndroid Build Coastguard Worker 
spi_chip_erase_62(struct flashctx * flash)483*0d6140beSAndroid Build Coastguard Worker static int spi_chip_erase_62(struct flashctx *flash)
484*0d6140beSAndroid Build Coastguard Worker {
485*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 2-5s, so wait in 100ms steps. */
486*0d6140beSAndroid Build Coastguard Worker 	return spi_simple_write_cmd(flash, JEDEC_CE_62, 100 * 1000);
487*0d6140beSAndroid Build Coastguard Worker }
488*0d6140beSAndroid Build Coastguard Worker 
spi_chip_erase_c7(struct flashctx * flash)489*0d6140beSAndroid Build Coastguard Worker static int spi_chip_erase_c7(struct flashctx *flash)
490*0d6140beSAndroid Build Coastguard Worker {
491*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 1-85s, so wait in 1s steps. */
492*0d6140beSAndroid Build Coastguard Worker 	return spi_simple_write_cmd(flash, JEDEC_CE_C7, 1000 * 1000);
493*0d6140beSAndroid Build Coastguard Worker }
494*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_52(struct flashctx * flash,unsigned int addr,unsigned int blocklen)495*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
496*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
497*0d6140beSAndroid Build Coastguard Worker {
498*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
499*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_52, false, addr, NULL, 0, 100 * 1000);
500*0d6140beSAndroid Build Coastguard Worker }
501*0d6140beSAndroid Build Coastguard Worker 
502*0d6140beSAndroid Build Coastguard Worker /* Block size is usually
503*0d6140beSAndroid Build Coastguard Worker  * 32M (one die) for Micron
504*0d6140beSAndroid Build Coastguard Worker  */
spi_block_erase_c4(struct flashctx * flash,unsigned int addr,unsigned int blocklen)505*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
506*0d6140beSAndroid Build Coastguard Worker {
507*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 240-480s, so wait in 500ms steps. */
508*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_C4, false, addr, NULL, 0, 500 * 1000);
509*0d6140beSAndroid Build Coastguard Worker }
510*0d6140beSAndroid Build Coastguard Worker 
511*0d6140beSAndroid Build Coastguard Worker /* Block size is usually
512*0d6140beSAndroid Build Coastguard Worker  * 64k for Macronix
513*0d6140beSAndroid Build Coastguard Worker  * 32k for SST
514*0d6140beSAndroid Build Coastguard Worker  * 4-32k non-uniform for EON
515*0d6140beSAndroid Build Coastguard Worker  */
spi_block_erase_d8(struct flashctx * flash,unsigned int addr,unsigned int blocklen)516*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
517*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
518*0d6140beSAndroid Build Coastguard Worker {
519*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
520*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_D8, false, addr, NULL, 0, 100 * 1000);
521*0d6140beSAndroid Build Coastguard Worker }
522*0d6140beSAndroid Build Coastguard Worker 
523*0d6140beSAndroid Build Coastguard Worker /* Block size is usually
524*0d6140beSAndroid Build Coastguard Worker  * 4k for PMC
525*0d6140beSAndroid Build Coastguard Worker  */
spi_block_erase_d7(struct flashctx * flash,unsigned int addr,unsigned int blocklen)526*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
527*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
528*0d6140beSAndroid Build Coastguard Worker {
529*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
530*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_D7, false, addr, NULL, 0, 100 * 1000);
531*0d6140beSAndroid Build Coastguard Worker }
532*0d6140beSAndroid Build Coastguard Worker 
533*0d6140beSAndroid Build Coastguard Worker /* Page erase (usually 256B blocks) */
spi_block_erase_db(struct flashctx * flash,unsigned int addr,unsigned int blocklen)534*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
535*0d6140beSAndroid Build Coastguard Worker {
536*0d6140beSAndroid Build Coastguard Worker 	/* This takes up to 20ms usually (on worn out devices
537*0d6140beSAndroid Build Coastguard Worker 	   up to the 0.5s range), so wait in 1ms steps. */
538*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
539*0d6140beSAndroid Build Coastguard Worker }
540*0d6140beSAndroid Build Coastguard Worker 
541*0d6140beSAndroid Build Coastguard Worker /* Sector size is usually 4k, though Macronix eliteflash has 64k */
spi_block_erase_20(struct flashctx * flash,unsigned int addr,unsigned int blocklen)542*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
543*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
544*0d6140beSAndroid Build Coastguard Worker {
545*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 15-800ms, so wait in 10ms steps. */
546*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_SE, false, addr, NULL, 0, 10 * 1000);
547*0d6140beSAndroid Build Coastguard Worker }
548*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_50(struct flashctx * flash,unsigned int addr,unsigned int blocklen)549*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
550*0d6140beSAndroid Build Coastguard Worker {
551*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 10ms, so wait in 1ms steps. */
552*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_50, false, addr, NULL, 0, 1 * 1000);
553*0d6140beSAndroid Build Coastguard Worker }
554*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_81(struct flashctx * flash,unsigned int addr,unsigned int blocklen)555*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
556*0d6140beSAndroid Build Coastguard Worker {
557*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 8ms, so wait in 1ms steps. */
558*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, JEDEC_BE_81, false, addr, NULL, 0, 1 * 1000);
559*0d6140beSAndroid Build Coastguard Worker }
560*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_60(struct flashctx * flash,unsigned int addr,unsigned int blocklen)561*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
562*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
563*0d6140beSAndroid Build Coastguard Worker {
564*0d6140beSAndroid Build Coastguard Worker 	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
565*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s called with incorrect arguments\n",
566*0d6140beSAndroid Build Coastguard Worker 			__func__);
567*0d6140beSAndroid Build Coastguard Worker 		return -1;
568*0d6140beSAndroid Build Coastguard Worker 	}
569*0d6140beSAndroid Build Coastguard Worker 	return spi_chip_erase_60(flash);
570*0d6140beSAndroid Build Coastguard Worker }
571*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_62(struct flashctx * flash,unsigned int addr,unsigned int blocklen)572*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
573*0d6140beSAndroid Build Coastguard Worker {
574*0d6140beSAndroid Build Coastguard Worker 	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
575*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s called with incorrect arguments\n",
576*0d6140beSAndroid Build Coastguard Worker 			__func__);
577*0d6140beSAndroid Build Coastguard Worker 		return -1;
578*0d6140beSAndroid Build Coastguard Worker 	}
579*0d6140beSAndroid Build Coastguard Worker 	return spi_chip_erase_62(flash);
580*0d6140beSAndroid Build Coastguard Worker }
581*0d6140beSAndroid Build Coastguard Worker 
spi_block_erase_c7(struct flashctx * flash,unsigned int addr,unsigned int blocklen)582*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
583*0d6140beSAndroid Build Coastguard Worker 		       unsigned int blocklen)
584*0d6140beSAndroid Build Coastguard Worker {
585*0d6140beSAndroid Build Coastguard Worker 	if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
586*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s called with incorrect arguments\n",
587*0d6140beSAndroid Build Coastguard Worker 			__func__);
588*0d6140beSAndroid Build Coastguard Worker 		return -1;
589*0d6140beSAndroid Build Coastguard Worker 	}
590*0d6140beSAndroid Build Coastguard Worker 	return spi_chip_erase_c7(flash);
591*0d6140beSAndroid Build Coastguard Worker }
592*0d6140beSAndroid Build Coastguard Worker 
593*0d6140beSAndroid Build Coastguard Worker /* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
spi_block_erase_21(struct flashctx * flash,unsigned int addr,unsigned int blocklen)594*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
595*0d6140beSAndroid Build Coastguard Worker {
596*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 15-800ms, so wait in 10ms steps. */
597*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
598*0d6140beSAndroid Build Coastguard Worker }
599*0d6140beSAndroid Build Coastguard Worker 
600*0d6140beSAndroid Build Coastguard Worker /* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
spi_block_erase_53(struct flashctx * flash,unsigned int addr,unsigned int blocklen)601*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
602*0d6140beSAndroid Build Coastguard Worker {
603*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
604*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
605*0d6140beSAndroid Build Coastguard Worker }
606*0d6140beSAndroid Build Coastguard Worker 
607*0d6140beSAndroid Build Coastguard Worker /* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
spi_block_erase_5c(struct flashctx * flash,unsigned int addr,unsigned int blocklen)608*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
609*0d6140beSAndroid Build Coastguard Worker {
610*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
611*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, 0x5c, true, addr, NULL, 0, 100 * 1000);
612*0d6140beSAndroid Build Coastguard Worker }
613*0d6140beSAndroid Build Coastguard Worker 
614*0d6140beSAndroid Build Coastguard Worker /* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
spi_block_erase_dc(struct flashctx * flash,unsigned int addr,unsigned int blocklen)615*0d6140beSAndroid Build Coastguard Worker int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
616*0d6140beSAndroid Build Coastguard Worker {
617*0d6140beSAndroid Build Coastguard Worker 	/* This usually takes 100-4000ms, so wait in 100ms steps. */
618*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000);
619*0d6140beSAndroid Build Coastguard Worker }
620*0d6140beSAndroid Build Coastguard Worker 
621*0d6140beSAndroid Build Coastguard Worker static const struct {
622*0d6140beSAndroid Build Coastguard Worker 	enum block_erase_func func;
623*0d6140beSAndroid Build Coastguard Worker 	uint8_t opcode;
624*0d6140beSAndroid Build Coastguard Worker } spi25_function_opcode_list[] = {
625*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_20, 0x20},
626*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_21, 0x21},
627*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_50, 0x50},
628*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_52, 0x52},
629*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_53, 0x53},
630*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_5C, 0x5c},
631*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_60, 0x60},
632*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_62, 0x62},
633*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_81, 0x81},
634*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_C4, 0xc4},
635*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_C7, 0xc7},
636*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_D7, 0xd7},
637*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_D8, 0xd8},
638*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_DB, 0xdb},
639*0d6140beSAndroid Build Coastguard Worker 	{SPI_BLOCK_ERASE_DC, 0xdc},
640*0d6140beSAndroid Build Coastguard Worker };
641*0d6140beSAndroid Build Coastguard Worker 
spi25_get_erasefn_from_opcode(uint8_t opcode)642*0d6140beSAndroid Build Coastguard Worker enum block_erase_func spi25_get_erasefn_from_opcode(uint8_t opcode)
643*0d6140beSAndroid Build Coastguard Worker {
644*0d6140beSAndroid Build Coastguard Worker 	size_t i;
645*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
646*0d6140beSAndroid Build Coastguard Worker 		if (spi25_function_opcode_list[i].opcode == opcode)
647*0d6140beSAndroid Build Coastguard Worker 			return spi25_function_opcode_list[i].func;
648*0d6140beSAndroid Build Coastguard Worker 	}
649*0d6140beSAndroid Build Coastguard Worker 	msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
650*0d6140beSAndroid Build Coastguard Worker 			  "this at [email protected]\n", __func__, opcode);
651*0d6140beSAndroid Build Coastguard Worker 	return NO_BLOCK_ERASE_FUNC;
652*0d6140beSAndroid Build Coastguard Worker }
653*0d6140beSAndroid Build Coastguard Worker 
spi_nbyte_program(struct flashctx * flash,unsigned int addr,const uint8_t * bytes,unsigned int len)654*0d6140beSAndroid Build Coastguard Worker static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
655*0d6140beSAndroid Build Coastguard Worker {
656*0d6140beSAndroid Build Coastguard Worker 	const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash);
657*0d6140beSAndroid Build Coastguard Worker 	const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM;
658*0d6140beSAndroid Build Coastguard Worker 	return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10);
659*0d6140beSAndroid Build Coastguard Worker }
660*0d6140beSAndroid Build Coastguard Worker 
spi_nbyte_read(struct flashctx * flash,unsigned int address,uint8_t * bytes,unsigned int len)661*0d6140beSAndroid Build Coastguard Worker int spi_nbyte_read(struct flashctx *flash, unsigned int address, uint8_t *bytes,
662*0d6140beSAndroid Build Coastguard Worker 		   unsigned int len)
663*0d6140beSAndroid Build Coastguard Worker {
664*0d6140beSAndroid Build Coastguard Worker 	const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash);
665*0d6140beSAndroid Build Coastguard Worker 	uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN] = { native_4ba ? JEDEC_READ_4BA : JEDEC_READ, };
666*0d6140beSAndroid Build Coastguard Worker 
667*0d6140beSAndroid Build Coastguard Worker 	const int addr_len = spi_prepare_address(flash, cmd, native_4ba, address);
668*0d6140beSAndroid Build Coastguard Worker 	if (addr_len < 0)
669*0d6140beSAndroid Build Coastguard Worker 		return 1;
670*0d6140beSAndroid Build Coastguard Worker 
671*0d6140beSAndroid Build Coastguard Worker 	/* Send Read */
672*0d6140beSAndroid Build Coastguard Worker 	return spi_send_command(flash, 1 + addr_len, len, cmd, bytes);
673*0d6140beSAndroid Build Coastguard Worker }
674*0d6140beSAndroid Build Coastguard Worker 
675*0d6140beSAndroid Build Coastguard Worker /*
676*0d6140beSAndroid Build Coastguard Worker  * Read a part of the flash chip.
677*0d6140beSAndroid Build Coastguard Worker  * Data is read in chunks with a maximum size of chunksize.
678*0d6140beSAndroid Build Coastguard Worker  */
spi_read_chunked(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len,unsigned int chunksize)679*0d6140beSAndroid Build Coastguard Worker int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
680*0d6140beSAndroid Build Coastguard Worker 		     unsigned int len, unsigned int chunksize)
681*0d6140beSAndroid Build Coastguard Worker {
682*0d6140beSAndroid Build Coastguard Worker 	int ret;
683*0d6140beSAndroid Build Coastguard Worker 	size_t to_read;
684*0d6140beSAndroid Build Coastguard Worker 	size_t start_address = start;
685*0d6140beSAndroid Build Coastguard Worker 	size_t end_address = len - start;
686*0d6140beSAndroid Build Coastguard Worker 	for (; len; len -= to_read, buf += to_read, start += to_read) {
687*0d6140beSAndroid Build Coastguard Worker 		to_read = min(chunksize, len);
688*0d6140beSAndroid Build Coastguard Worker 		ret = spi_nbyte_read(flash, start, buf, to_read);
689*0d6140beSAndroid Build Coastguard Worker 		if (ret)
690*0d6140beSAndroid Build Coastguard Worker 			return ret;
691*0d6140beSAndroid Build Coastguard Worker 		update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address);
692*0d6140beSAndroid Build Coastguard Worker 	}
693*0d6140beSAndroid Build Coastguard Worker 	return 0;
694*0d6140beSAndroid Build Coastguard Worker }
695*0d6140beSAndroid Build Coastguard Worker 
696*0d6140beSAndroid Build Coastguard Worker /*
697*0d6140beSAndroid Build Coastguard Worker  * Write a part of the flash chip.
698*0d6140beSAndroid Build Coastguard Worker  * FIXME: Use the chunk code from Michael Karcher instead.
699*0d6140beSAndroid Build Coastguard Worker  * Each page is written separately in chunks with a maximum size of chunksize.
700*0d6140beSAndroid Build Coastguard Worker  */
spi_write_chunked(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len,unsigned int chunksize)701*0d6140beSAndroid Build Coastguard Worker int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start,
702*0d6140beSAndroid Build Coastguard Worker 		      unsigned int len, unsigned int chunksize)
703*0d6140beSAndroid Build Coastguard Worker {
704*0d6140beSAndroid Build Coastguard Worker 	unsigned int i, j, starthere, lenhere, towrite;
705*0d6140beSAndroid Build Coastguard Worker 	/* FIXME: page_size is the wrong variable. We need max_writechunk_size
706*0d6140beSAndroid Build Coastguard Worker 	 * in struct flashctx to do this properly. All chips using
707*0d6140beSAndroid Build Coastguard Worker 	 * spi_chip_write_256 have page_size set to max_writechunk_size, so
708*0d6140beSAndroid Build Coastguard Worker 	 * we're OK for now.
709*0d6140beSAndroid Build Coastguard Worker 	 */
710*0d6140beSAndroid Build Coastguard Worker 	unsigned int page_size = flash->chip->page_size;
711*0d6140beSAndroid Build Coastguard Worker 	size_t start_address = start;
712*0d6140beSAndroid Build Coastguard Worker 	size_t end_address = len - start;
713*0d6140beSAndroid Build Coastguard Worker 
714*0d6140beSAndroid Build Coastguard Worker 	/* Warning: This loop has a very unusual condition and body.
715*0d6140beSAndroid Build Coastguard Worker 	 * The loop needs to go through each page with at least one affected
716*0d6140beSAndroid Build Coastguard Worker 	 * byte. The lowest page number is (start / page_size) since that
717*0d6140beSAndroid Build Coastguard Worker 	 * division rounds down. The highest page number we want is the page
718*0d6140beSAndroid Build Coastguard Worker 	 * where the last byte of the range lives. That last byte has the
719*0d6140beSAndroid Build Coastguard Worker 	 * address (start + len - 1), thus the highest page number is
720*0d6140beSAndroid Build Coastguard Worker 	 * (start + len - 1) / page_size. Since we want to include that last
721*0d6140beSAndroid Build Coastguard Worker 	 * page as well, the loop condition uses <=.
722*0d6140beSAndroid Build Coastguard Worker 	 */
723*0d6140beSAndroid Build Coastguard Worker 	for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
724*0d6140beSAndroid Build Coastguard Worker 		/* Byte position of the first byte in the range in this page. */
725*0d6140beSAndroid Build Coastguard Worker 		/* starthere is an offset to the base address of the chip. */
726*0d6140beSAndroid Build Coastguard Worker 		starthere = max(start, i * page_size);
727*0d6140beSAndroid Build Coastguard Worker 		/* Length of bytes in the range in this page. */
728*0d6140beSAndroid Build Coastguard Worker 		lenhere = min(start + len, (i + 1) * page_size) - starthere;
729*0d6140beSAndroid Build Coastguard Worker 		for (j = 0; j < lenhere; j += chunksize) {
730*0d6140beSAndroid Build Coastguard Worker 			int rc;
731*0d6140beSAndroid Build Coastguard Worker 
732*0d6140beSAndroid Build Coastguard Worker 			towrite = min(chunksize, lenhere - j);
733*0d6140beSAndroid Build Coastguard Worker 			rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
734*0d6140beSAndroid Build Coastguard Worker 			if (rc)
735*0d6140beSAndroid Build Coastguard Worker 				return rc;
736*0d6140beSAndroid Build Coastguard Worker 		}
737*0d6140beSAndroid Build Coastguard Worker 		update_progress(flash, FLASHROM_PROGRESS_WRITE, start - start_address + lenhere, end_address);
738*0d6140beSAndroid Build Coastguard Worker 	}
739*0d6140beSAndroid Build Coastguard Worker 
740*0d6140beSAndroid Build Coastguard Worker 	return 0;
741*0d6140beSAndroid Build Coastguard Worker }
742*0d6140beSAndroid Build Coastguard Worker 
743*0d6140beSAndroid Build Coastguard Worker /*
744*0d6140beSAndroid Build Coastguard Worker  * Program chip using byte programming. (SLOW!)
745*0d6140beSAndroid Build Coastguard Worker  * This is for chips which can only handle one byte writes
746*0d6140beSAndroid Build Coastguard Worker  * and for chips where memory mapped programming is impossible
747*0d6140beSAndroid Build Coastguard Worker  * (e.g. due to size constraints in IT87* for over 512 kB)
748*0d6140beSAndroid Build Coastguard Worker  */
749*0d6140beSAndroid Build Coastguard Worker /* real chunksize is 1, logical chunksize is 1 */
spi_chip_write_1(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)750*0d6140beSAndroid Build Coastguard Worker int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
751*0d6140beSAndroid Build Coastguard Worker {
752*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
753*0d6140beSAndroid Build Coastguard Worker 
754*0d6140beSAndroid Build Coastguard Worker 	for (i = start; i < start + len; i++) {
755*0d6140beSAndroid Build Coastguard Worker 		if (spi_nbyte_program(flash, i, buf + i - start, 1))
756*0d6140beSAndroid Build Coastguard Worker 			return 1;
757*0d6140beSAndroid Build Coastguard Worker 		update_progress(flash, FLASHROM_PROGRESS_WRITE, i - start, len - start);
758*0d6140beSAndroid Build Coastguard Worker 	}
759*0d6140beSAndroid Build Coastguard Worker 	return 0;
760*0d6140beSAndroid Build Coastguard Worker }
761*0d6140beSAndroid Build Coastguard Worker 
default_spi_write_aai(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)762*0d6140beSAndroid Build Coastguard Worker int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
763*0d6140beSAndroid Build Coastguard Worker {
764*0d6140beSAndroid Build Coastguard Worker 	uint32_t pos = start;
765*0d6140beSAndroid Build Coastguard Worker 	int result;
766*0d6140beSAndroid Build Coastguard Worker 	unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
767*0d6140beSAndroid Build Coastguard Worker 		JEDEC_AAI_WORD_PROGRAM,
768*0d6140beSAndroid Build Coastguard Worker 	};
769*0d6140beSAndroid Build Coastguard Worker 
770*0d6140beSAndroid Build Coastguard Worker 	/* The even start address and even length requirements can be either
771*0d6140beSAndroid Build Coastguard Worker 	 * honored outside this function, or we can call spi_byte_program
772*0d6140beSAndroid Build Coastguard Worker 	 * for the first and/or last byte and use AAI for the rest.
773*0d6140beSAndroid Build Coastguard Worker 	 * FIXME: Move this to generic code.
774*0d6140beSAndroid Build Coastguard Worker 	 */
775*0d6140beSAndroid Build Coastguard Worker 	/* The data sheet requires a start address with the low bit cleared. */
776*0d6140beSAndroid Build Coastguard Worker 	if (start % 2) {
777*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s: start address not even! Please report a bug at "
778*0d6140beSAndroid Build Coastguard Worker 			 "[email protected]\n", __func__);
779*0d6140beSAndroid Build Coastguard Worker 		if (spi_chip_write_1(flash, buf, start, start % 2))
780*0d6140beSAndroid Build Coastguard Worker 			return SPI_GENERIC_ERROR;
781*0d6140beSAndroid Build Coastguard Worker 		pos += start % 2;
782*0d6140beSAndroid Build Coastguard Worker 		/* Do not return an error for now. */
783*0d6140beSAndroid Build Coastguard Worker 		//return SPI_GENERIC_ERROR;
784*0d6140beSAndroid Build Coastguard Worker 	}
785*0d6140beSAndroid Build Coastguard Worker 	/* The data sheet requires total AAI write length to be even. */
786*0d6140beSAndroid Build Coastguard Worker 	if (len % 2) {
787*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s: total write length not even! Please report a "
788*0d6140beSAndroid Build Coastguard Worker 			 "bug at [email protected]\n", __func__);
789*0d6140beSAndroid Build Coastguard Worker 		/* Do not return an error for now. */
790*0d6140beSAndroid Build Coastguard Worker 		//return SPI_GENERIC_ERROR;
791*0d6140beSAndroid Build Coastguard Worker 	}
792*0d6140beSAndroid Build Coastguard Worker 
793*0d6140beSAndroid Build Coastguard Worker 	result = spi_write_cmd(flash, JEDEC_AAI_WORD_PROGRAM, false, start, buf + pos - start, 2, 10);
794*0d6140beSAndroid Build Coastguard Worker 	if (result)
795*0d6140beSAndroid Build Coastguard Worker 		goto bailout;
796*0d6140beSAndroid Build Coastguard Worker 
797*0d6140beSAndroid Build Coastguard Worker 	/* We already wrote 2 bytes in the multicommand step. */
798*0d6140beSAndroid Build Coastguard Worker 	pos += 2;
799*0d6140beSAndroid Build Coastguard Worker 
800*0d6140beSAndroid Build Coastguard Worker 	/* Are there at least two more bytes to write? */
801*0d6140beSAndroid Build Coastguard Worker 	while (pos < start + len - 1) {
802*0d6140beSAndroid Build Coastguard Worker 		cmd[1] = buf[pos++ - start];
803*0d6140beSAndroid Build Coastguard Worker 		cmd[2] = buf[pos++ - start];
804*0d6140beSAndroid Build Coastguard Worker 		result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
805*0d6140beSAndroid Build Coastguard Worker 		if (result != 0) {
806*0d6140beSAndroid Build Coastguard Worker 			msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
807*0d6140beSAndroid Build Coastguard Worker 			goto bailout;
808*0d6140beSAndroid Build Coastguard Worker 		}
809*0d6140beSAndroid Build Coastguard Worker 		if (spi_poll_wip(flash, 10))
810*0d6140beSAndroid Build Coastguard Worker 			goto bailout;
811*0d6140beSAndroid Build Coastguard Worker 	}
812*0d6140beSAndroid Build Coastguard Worker 
813*0d6140beSAndroid Build Coastguard Worker 	/* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
814*0d6140beSAndroid Build Coastguard Worker 	result = spi_write_disable(flash);
815*0d6140beSAndroid Build Coastguard Worker 	if (result != 0) {
816*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed to disable AAI mode.\n", __func__);
817*0d6140beSAndroid Build Coastguard Worker 		return SPI_GENERIC_ERROR;
818*0d6140beSAndroid Build Coastguard Worker 	}
819*0d6140beSAndroid Build Coastguard Worker 
820*0d6140beSAndroid Build Coastguard Worker 	/* Write remaining byte (if any). */
821*0d6140beSAndroid Build Coastguard Worker 	if (pos < start + len) {
822*0d6140beSAndroid Build Coastguard Worker 		if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
823*0d6140beSAndroid Build Coastguard Worker 			return SPI_GENERIC_ERROR;
824*0d6140beSAndroid Build Coastguard Worker 	}
825*0d6140beSAndroid Build Coastguard Worker 
826*0d6140beSAndroid Build Coastguard Worker 	return 0;
827*0d6140beSAndroid Build Coastguard Worker 
828*0d6140beSAndroid Build Coastguard Worker bailout:
829*0d6140beSAndroid Build Coastguard Worker 	result = spi_write_disable(flash);
830*0d6140beSAndroid Build Coastguard Worker 	if (result != 0)
831*0d6140beSAndroid Build Coastguard Worker 		msg_cerr("%s failed to disable AAI mode.\n", __func__);
832*0d6140beSAndroid Build Coastguard Worker 	return SPI_GENERIC_ERROR;
833*0d6140beSAndroid Build Coastguard Worker }
834*0d6140beSAndroid Build Coastguard Worker 
spi_enter_exit_4ba(struct flashctx * const flash,const bool enter)835*0d6140beSAndroid Build Coastguard Worker static int spi_enter_exit_4ba(struct flashctx *const flash, const bool enter)
836*0d6140beSAndroid Build Coastguard Worker {
837*0d6140beSAndroid Build Coastguard Worker 	const unsigned char cmd = enter ? JEDEC_ENTER_4_BYTE_ADDR_MODE : JEDEC_EXIT_4_BYTE_ADDR_MODE;
838*0d6140beSAndroid Build Coastguard Worker 	int ret = 1;
839*0d6140beSAndroid Build Coastguard Worker 
840*0d6140beSAndroid Build Coastguard Worker 	if (flash->chip->feature_bits & FEATURE_4BA_ENTER)
841*0d6140beSAndroid Build Coastguard Worker 		ret = spi_send_command(flash, sizeof(cmd), 0, &cmd, NULL);
842*0d6140beSAndroid Build Coastguard Worker 	else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_WREN)
843*0d6140beSAndroid Build Coastguard Worker 		ret = spi_simple_write_cmd(flash, cmd, 0);
844*0d6140beSAndroid Build Coastguard Worker 	else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_EAR7)
845*0d6140beSAndroid Build Coastguard Worker 		ret = spi_set_extended_address(flash, enter ? 0x80 : 0x00);
846*0d6140beSAndroid Build Coastguard Worker 
847*0d6140beSAndroid Build Coastguard Worker 	if (!ret)
848*0d6140beSAndroid Build Coastguard Worker 		flash->in_4ba_mode = enter;
849*0d6140beSAndroid Build Coastguard Worker 	return ret;
850*0d6140beSAndroid Build Coastguard Worker }
851*0d6140beSAndroid Build Coastguard Worker 
spi_enter_4ba(struct flashctx * const flash)852*0d6140beSAndroid Build Coastguard Worker int spi_enter_4ba(struct flashctx *const flash)
853*0d6140beSAndroid Build Coastguard Worker {
854*0d6140beSAndroid Build Coastguard Worker 	return spi_enter_exit_4ba(flash, true);
855*0d6140beSAndroid Build Coastguard Worker }
856*0d6140beSAndroid Build Coastguard Worker 
spi_exit_4ba(struct flashctx * flash)857*0d6140beSAndroid Build Coastguard Worker int spi_exit_4ba(struct flashctx *flash)
858*0d6140beSAndroid Build Coastguard Worker {
859*0d6140beSAndroid Build Coastguard Worker 	return spi_enter_exit_4ba(flash, false);
860*0d6140beSAndroid Build Coastguard Worker }
861