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