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) 2000 Silicon Integrated System Corporation
5*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2006 Giampiero Giancipoli <[email protected]>
6*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2006 coresystems GmbH <[email protected]>
7*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2007-2012 Carl-Daniel Hailfinger
8*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2009 Sean Nelson <[email protected]>
9*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2014 Stefan Tauner
10*0d6140beSAndroid Build Coastguard Worker *
11*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
12*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
13*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
14*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
15*0d6140beSAndroid Build Coastguard Worker *
16*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
17*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
20*0d6140beSAndroid Build Coastguard Worker */
21*0d6140beSAndroid Build Coastguard Worker
22*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
23*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
24*0d6140beSAndroid Build Coastguard Worker
25*0d6140beSAndroid Build Coastguard Worker #define MAX_REFLASH_TRIES 0x10
26*0d6140beSAndroid Build Coastguard Worker #define MASK_FULL 0xffff
27*0d6140beSAndroid Build Coastguard Worker #define MASK_2AA 0x7ff
28*0d6140beSAndroid Build Coastguard Worker #define MASK_AAA 0xfff
29*0d6140beSAndroid Build Coastguard Worker
30*0d6140beSAndroid Build Coastguard Worker /* Check one byte for odd parity */
oddparity(uint8_t val)31*0d6140beSAndroid Build Coastguard Worker uint8_t oddparity(uint8_t val)
32*0d6140beSAndroid Build Coastguard Worker {
33*0d6140beSAndroid Build Coastguard Worker val = (val ^ (val >> 4)) & 0xf;
34*0d6140beSAndroid Build Coastguard Worker val = (val ^ (val >> 2)) & 0x3;
35*0d6140beSAndroid Build Coastguard Worker return (val ^ (val >> 1)) & 0x1;
36*0d6140beSAndroid Build Coastguard Worker }
37*0d6140beSAndroid Build Coastguard Worker
toggle_ready_jedec_common(const struct flashctx * flash,chipaddr dst,unsigned int delay)38*0d6140beSAndroid Build Coastguard Worker static void toggle_ready_jedec_common(const struct flashctx *flash, chipaddr dst, unsigned int delay)
39*0d6140beSAndroid Build Coastguard Worker {
40*0d6140beSAndroid Build Coastguard Worker unsigned int i = 0;
41*0d6140beSAndroid Build Coastguard Worker uint8_t tmp1 = chip_readb(flash, dst) & 0x40;
42*0d6140beSAndroid Build Coastguard Worker
43*0d6140beSAndroid Build Coastguard Worker while (i++ < 0xFFFFFFF) {
44*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, delay);
45*0d6140beSAndroid Build Coastguard Worker uint8_t tmp2 = chip_readb(flash, dst) & 0x40;
46*0d6140beSAndroid Build Coastguard Worker if (tmp1 == tmp2) {
47*0d6140beSAndroid Build Coastguard Worker break;
48*0d6140beSAndroid Build Coastguard Worker }
49*0d6140beSAndroid Build Coastguard Worker tmp1 = tmp2;
50*0d6140beSAndroid Build Coastguard Worker }
51*0d6140beSAndroid Build Coastguard Worker if (i > 0x100000)
52*0d6140beSAndroid Build Coastguard Worker msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
53*0d6140beSAndroid Build Coastguard Worker }
54*0d6140beSAndroid Build Coastguard Worker
toggle_ready_jedec(const struct flashctx * flash,chipaddr dst)55*0d6140beSAndroid Build Coastguard Worker void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst)
56*0d6140beSAndroid Build Coastguard Worker {
57*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec_common(flash, dst, 0);
58*0d6140beSAndroid Build Coastguard Worker }
59*0d6140beSAndroid Build Coastguard Worker
60*0d6140beSAndroid Build Coastguard Worker /* Some chips require a minimum delay between toggle bit reads.
61*0d6140beSAndroid Build Coastguard Worker * The Winbond W39V040C wants 50 ms between reads on sector erase toggle,
62*0d6140beSAndroid Build Coastguard Worker * but experiments show that 2 ms are already enough. Pick a safety factor
63*0d6140beSAndroid Build Coastguard Worker * of 4 and use an 8 ms delay.
64*0d6140beSAndroid Build Coastguard Worker * Given that erase is slow on all chips, it is recommended to use
65*0d6140beSAndroid Build Coastguard Worker * toggle_ready_jedec_slow in erase functions.
66*0d6140beSAndroid Build Coastguard Worker */
toggle_ready_jedec_slow(const struct flashctx * flash)67*0d6140beSAndroid Build Coastguard Worker static void toggle_ready_jedec_slow(const struct flashctx *flash)
68*0d6140beSAndroid Build Coastguard Worker {
69*0d6140beSAndroid Build Coastguard Worker const chipaddr dst = flash->virtual_memory;
70*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec_common(flash, dst, 8 * 1000);
71*0d6140beSAndroid Build Coastguard Worker }
72*0d6140beSAndroid Build Coastguard Worker
data_polling_jedec(const struct flashctx * flash,chipaddr dst,uint8_t data)73*0d6140beSAndroid Build Coastguard Worker void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
74*0d6140beSAndroid Build Coastguard Worker uint8_t data)
75*0d6140beSAndroid Build Coastguard Worker {
76*0d6140beSAndroid Build Coastguard Worker unsigned int i = 0;
77*0d6140beSAndroid Build Coastguard Worker
78*0d6140beSAndroid Build Coastguard Worker data &= 0x80;
79*0d6140beSAndroid Build Coastguard Worker
80*0d6140beSAndroid Build Coastguard Worker while (i++ < 0xFFFFFFF) {
81*0d6140beSAndroid Build Coastguard Worker uint8_t tmp = chip_readb(flash, dst) & 0x80;
82*0d6140beSAndroid Build Coastguard Worker if (tmp == data) {
83*0d6140beSAndroid Build Coastguard Worker break;
84*0d6140beSAndroid Build Coastguard Worker }
85*0d6140beSAndroid Build Coastguard Worker }
86*0d6140beSAndroid Build Coastguard Worker if (i > 0x100000)
87*0d6140beSAndroid Build Coastguard Worker msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
88*0d6140beSAndroid Build Coastguard Worker }
89*0d6140beSAndroid Build Coastguard Worker
getaddrmask(const struct flashchip * chip)90*0d6140beSAndroid Build Coastguard Worker static unsigned int getaddrmask(const struct flashchip *chip)
91*0d6140beSAndroid Build Coastguard Worker {
92*0d6140beSAndroid Build Coastguard Worker switch (chip->feature_bits & FEATURE_ADDR_MASK) {
93*0d6140beSAndroid Build Coastguard Worker case FEATURE_ADDR_FULL:
94*0d6140beSAndroid Build Coastguard Worker return MASK_FULL;
95*0d6140beSAndroid Build Coastguard Worker break;
96*0d6140beSAndroid Build Coastguard Worker case FEATURE_ADDR_2AA:
97*0d6140beSAndroid Build Coastguard Worker return MASK_2AA;
98*0d6140beSAndroid Build Coastguard Worker break;
99*0d6140beSAndroid Build Coastguard Worker case FEATURE_ADDR_AAA:
100*0d6140beSAndroid Build Coastguard Worker return MASK_AAA;
101*0d6140beSAndroid Build Coastguard Worker break;
102*0d6140beSAndroid Build Coastguard Worker default:
103*0d6140beSAndroid Build Coastguard Worker msg_cerr("%s called with unknown mask\n", __func__);
104*0d6140beSAndroid Build Coastguard Worker return 0;
105*0d6140beSAndroid Build Coastguard Worker break;
106*0d6140beSAndroid Build Coastguard Worker }
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker
start_program_jedec_common(const struct flashctx * flash)109*0d6140beSAndroid Build Coastguard Worker static void start_program_jedec_common(const struct flashctx *flash)
110*0d6140beSAndroid Build Coastguard Worker {
111*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
112*0d6140beSAndroid Build Coastguard Worker const bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
113*0d6140beSAndroid Build Coastguard Worker const unsigned int mask = getaddrmask(flash->chip);
114*0d6140beSAndroid Build Coastguard Worker
115*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
116*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
117*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xA0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
118*0d6140beSAndroid Build Coastguard Worker }
119*0d6140beSAndroid Build Coastguard Worker
probe_jedec_29gl(struct flashctx * flash)120*0d6140beSAndroid Build Coastguard Worker int probe_jedec_29gl(struct flashctx *flash)
121*0d6140beSAndroid Build Coastguard Worker {
122*0d6140beSAndroid Build Coastguard Worker const unsigned int mask = getaddrmask(flash->chip);
123*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
124*0d6140beSAndroid Build Coastguard Worker const struct flashchip *chip = flash->chip;
125*0d6140beSAndroid Build Coastguard Worker
126*0d6140beSAndroid Build Coastguard Worker /* Reset chip to a clean slate */
127*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
128*0d6140beSAndroid Build Coastguard Worker
129*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Product ID Entry command */
130*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + (0x5555 & mask));
131*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + (0x2AAA & mask));
132*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x90, bios + (0x5555 & mask));
133*0d6140beSAndroid Build Coastguard Worker
134*0d6140beSAndroid Build Coastguard Worker /* Read product ID */
135*0d6140beSAndroid Build Coastguard Worker // FIXME: Continuation loop, second byte is at word 0x100/byte 0x200
136*0d6140beSAndroid Build Coastguard Worker uint32_t man_id = chip_readb(flash, bios + 0x00);
137*0d6140beSAndroid Build Coastguard Worker uint32_t dev_id = (chip_readb(flash, bios + 0x01) << 16) |
138*0d6140beSAndroid Build Coastguard Worker (chip_readb(flash, bios + 0x0E) << 8) |
139*0d6140beSAndroid Build Coastguard Worker (chip_readb(flash, bios + 0x0F) << 0);
140*0d6140beSAndroid Build Coastguard Worker
141*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Product ID Exit command */
142*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
143*0d6140beSAndroid Build Coastguard Worker
144*0d6140beSAndroid Build Coastguard Worker msg_cdbg("%s: man_id 0x%02"PRIx32", dev_id 0x%06"PRIx32"", __func__, man_id, dev_id);
145*0d6140beSAndroid Build Coastguard Worker if (!oddparity(man_id))
146*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", man_id parity violation");
147*0d6140beSAndroid Build Coastguard Worker
148*0d6140beSAndroid Build Coastguard Worker /* Read the product ID location again. We should now see normal flash contents. */
149*0d6140beSAndroid Build Coastguard Worker uint32_t flashcontent1 = chip_readb(flash, bios + 0x00); // FIXME: Continuation loop
150*0d6140beSAndroid Build Coastguard Worker uint32_t flashcontent2 = (chip_readb(flash, bios + 0x01) << 16) |
151*0d6140beSAndroid Build Coastguard Worker (chip_readb(flash, bios + 0x0E) << 8) |
152*0d6140beSAndroid Build Coastguard Worker (chip_readb(flash, bios + 0x0F) << 0);
153*0d6140beSAndroid Build Coastguard Worker
154*0d6140beSAndroid Build Coastguard Worker if (man_id == flashcontent1)
155*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", man_id seems to be normal flash content");
156*0d6140beSAndroid Build Coastguard Worker if (dev_id == flashcontent2)
157*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", dev_id seems to be normal flash content");
158*0d6140beSAndroid Build Coastguard Worker
159*0d6140beSAndroid Build Coastguard Worker msg_cdbg("\n");
160*0d6140beSAndroid Build Coastguard Worker if (man_id != chip->manufacture_id || dev_id != chip->model_id)
161*0d6140beSAndroid Build Coastguard Worker return 0;
162*0d6140beSAndroid Build Coastguard Worker
163*0d6140beSAndroid Build Coastguard Worker return 1;
164*0d6140beSAndroid Build Coastguard Worker }
165*0d6140beSAndroid Build Coastguard Worker
probe_timings(const struct flashchip * chip,unsigned int * tenter,unsigned int * texit)166*0d6140beSAndroid Build Coastguard Worker static int probe_timings(const struct flashchip *chip, unsigned int *tenter, unsigned int *texit)
167*0d6140beSAndroid Build Coastguard Worker {
168*0d6140beSAndroid Build Coastguard Worker if (chip->probe_timing > 0) {
169*0d6140beSAndroid Build Coastguard Worker *tenter = *texit = chip->probe_timing;
170*0d6140beSAndroid Build Coastguard Worker } else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
171*0d6140beSAndroid Build Coastguard Worker *tenter = *texit = 0;
172*0d6140beSAndroid Build Coastguard Worker } else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
173*0d6140beSAndroid Build Coastguard Worker msg_cdbg("Chip lacks correct probe timing information, using default 10ms/40us. ");
174*0d6140beSAndroid Build Coastguard Worker *tenter = 10000;
175*0d6140beSAndroid Build Coastguard Worker *texit = 40;
176*0d6140beSAndroid Build Coastguard Worker } else {
177*0d6140beSAndroid Build Coastguard Worker msg_cerr("Chip has negative value in probe_timing, failing without chip access\n");
178*0d6140beSAndroid Build Coastguard Worker return -1;
179*0d6140beSAndroid Build Coastguard Worker }
180*0d6140beSAndroid Build Coastguard Worker
181*0d6140beSAndroid Build Coastguard Worker return 0;
182*0d6140beSAndroid Build Coastguard Worker }
183*0d6140beSAndroid Build Coastguard Worker
probe_jedec(struct flashctx * flash)184*0d6140beSAndroid Build Coastguard Worker int probe_jedec(struct flashctx *flash)
185*0d6140beSAndroid Build Coastguard Worker {
186*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
187*0d6140beSAndroid Build Coastguard Worker const struct flashchip *chip = flash->chip;
188*0d6140beSAndroid Build Coastguard Worker const bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
189*0d6140beSAndroid Build Coastguard Worker const unsigned int mask = getaddrmask(flash->chip);
190*0d6140beSAndroid Build Coastguard Worker uint8_t id1, id2;
191*0d6140beSAndroid Build Coastguard Worker uint32_t largeid1, largeid2;
192*0d6140beSAndroid Build Coastguard Worker uint32_t flashcontent1, flashcontent2;
193*0d6140beSAndroid Build Coastguard Worker unsigned int probe_timing_enter, probe_timing_exit;
194*0d6140beSAndroid Build Coastguard Worker
195*0d6140beSAndroid Build Coastguard Worker if (probe_timings(chip, &probe_timing_enter, &probe_timing_exit) < 0)
196*0d6140beSAndroid Build Coastguard Worker return 0;
197*0d6140beSAndroid Build Coastguard Worker
198*0d6140beSAndroid Build Coastguard Worker /* Earlier probes might have been too fast for the chip to enter ID
199*0d6140beSAndroid Build Coastguard Worker * mode completely. Allow the chip to finish this before seeing a
200*0d6140beSAndroid Build Coastguard Worker * reset command.
201*0d6140beSAndroid Build Coastguard Worker */
202*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, probe_timing_enter);
203*0d6140beSAndroid Build Coastguard Worker /* Reset chip to a clean slate */
204*0d6140beSAndroid Build Coastguard Worker if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET) {
205*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
206*0d6140beSAndroid Build Coastguard Worker if (probe_timing_exit)
207*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
208*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
209*0d6140beSAndroid Build Coastguard Worker if (probe_timing_exit)
210*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
211*0d6140beSAndroid Build Coastguard Worker }
212*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
213*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, probe_timing_exit);
214*0d6140beSAndroid Build Coastguard Worker
215*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Product ID Entry command */
216*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
217*0d6140beSAndroid Build Coastguard Worker if (probe_timing_enter)
218*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
219*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
220*0d6140beSAndroid Build Coastguard Worker if (probe_timing_enter)
221*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
222*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x90, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
223*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, probe_timing_enter);
224*0d6140beSAndroid Build Coastguard Worker
225*0d6140beSAndroid Build Coastguard Worker /* Read product ID */
226*0d6140beSAndroid Build Coastguard Worker id1 = chip_readb(flash, bios + (0x00 << shifted));
227*0d6140beSAndroid Build Coastguard Worker id2 = chip_readb(flash, bios + (0x01 << shifted));
228*0d6140beSAndroid Build Coastguard Worker largeid1 = id1;
229*0d6140beSAndroid Build Coastguard Worker largeid2 = id2;
230*0d6140beSAndroid Build Coastguard Worker
231*0d6140beSAndroid Build Coastguard Worker /* Check if it is a continuation ID, this should be a while loop. */
232*0d6140beSAndroid Build Coastguard Worker if (id1 == 0x7F) {
233*0d6140beSAndroid Build Coastguard Worker largeid1 <<= 8;
234*0d6140beSAndroid Build Coastguard Worker id1 = chip_readb(flash, bios + 0x100);
235*0d6140beSAndroid Build Coastguard Worker largeid1 |= id1;
236*0d6140beSAndroid Build Coastguard Worker }
237*0d6140beSAndroid Build Coastguard Worker if (id2 == 0x7F) {
238*0d6140beSAndroid Build Coastguard Worker largeid2 <<= 8;
239*0d6140beSAndroid Build Coastguard Worker id2 = chip_readb(flash, bios + 0x101);
240*0d6140beSAndroid Build Coastguard Worker largeid2 |= id2;
241*0d6140beSAndroid Build Coastguard Worker }
242*0d6140beSAndroid Build Coastguard Worker
243*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Product ID Exit command */
244*0d6140beSAndroid Build Coastguard Worker if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET) {
245*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
246*0d6140beSAndroid Build Coastguard Worker if (probe_timing_exit)
247*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
248*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
249*0d6140beSAndroid Build Coastguard Worker if (probe_timing_exit)
250*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, 10);
251*0d6140beSAndroid Build Coastguard Worker }
252*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
253*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, probe_timing_exit);
254*0d6140beSAndroid Build Coastguard Worker
255*0d6140beSAndroid Build Coastguard Worker msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"", __func__, largeid1, largeid2);
256*0d6140beSAndroid Build Coastguard Worker if (!oddparity(id1))
257*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", id1 parity violation");
258*0d6140beSAndroid Build Coastguard Worker
259*0d6140beSAndroid Build Coastguard Worker /* Read the product ID location again. We should now see normal flash contents. */
260*0d6140beSAndroid Build Coastguard Worker flashcontent1 = chip_readb(flash, bios + (0x00 << shifted));
261*0d6140beSAndroid Build Coastguard Worker flashcontent2 = chip_readb(flash, bios + (0x01 << shifted));
262*0d6140beSAndroid Build Coastguard Worker
263*0d6140beSAndroid Build Coastguard Worker /* Check if it is a continuation ID, this should be a while loop. */
264*0d6140beSAndroid Build Coastguard Worker if (flashcontent1 == 0x7F) {
265*0d6140beSAndroid Build Coastguard Worker flashcontent1 <<= 8;
266*0d6140beSAndroid Build Coastguard Worker flashcontent1 |= chip_readb(flash, bios + 0x100);
267*0d6140beSAndroid Build Coastguard Worker }
268*0d6140beSAndroid Build Coastguard Worker if (flashcontent2 == 0x7F) {
269*0d6140beSAndroid Build Coastguard Worker flashcontent2 <<= 8;
270*0d6140beSAndroid Build Coastguard Worker flashcontent2 |= chip_readb(flash, bios + 0x101);
271*0d6140beSAndroid Build Coastguard Worker }
272*0d6140beSAndroid Build Coastguard Worker
273*0d6140beSAndroid Build Coastguard Worker if (largeid1 == flashcontent1)
274*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", id1 is normal flash content");
275*0d6140beSAndroid Build Coastguard Worker if (largeid2 == flashcontent2)
276*0d6140beSAndroid Build Coastguard Worker msg_cdbg(", id2 is normal flash content");
277*0d6140beSAndroid Build Coastguard Worker
278*0d6140beSAndroid Build Coastguard Worker msg_cdbg("\n");
279*0d6140beSAndroid Build Coastguard Worker if (largeid1 != chip->manufacture_id || largeid2 != chip->model_id)
280*0d6140beSAndroid Build Coastguard Worker return 0;
281*0d6140beSAndroid Build Coastguard Worker
282*0d6140beSAndroid Build Coastguard Worker return 1;
283*0d6140beSAndroid Build Coastguard Worker }
284*0d6140beSAndroid Build Coastguard Worker
issuecmd(const struct flashctx * flash,uint8_t op,unsigned int operand)285*0d6140beSAndroid Build Coastguard Worker static void issuecmd(const struct flashctx *flash, uint8_t op, unsigned int operand)
286*0d6140beSAndroid Build Coastguard Worker {
287*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
288*0d6140beSAndroid Build Coastguard Worker bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
289*0d6140beSAndroid Build Coastguard Worker const unsigned int mask = getaddrmask(flash->chip);
290*0d6140beSAndroid Build Coastguard Worker unsigned int delay_us = (flash->chip->probe_timing == TIMING_ZERO) ? 0 : 10;
291*0d6140beSAndroid Build Coastguard Worker
292*0d6140beSAndroid Build Coastguard Worker if (!operand)
293*0d6140beSAndroid Build Coastguard Worker operand = (shifted ? 0x2AAA : 0x5555) & mask;
294*0d6140beSAndroid Build Coastguard Worker
295*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
296*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, delay_us);
297*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
298*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, delay_us);
299*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, op, bios + operand);
300*0d6140beSAndroid Build Coastguard Worker programmer_delay(flash, delay_us);
301*0d6140beSAndroid Build Coastguard Worker }
302*0d6140beSAndroid Build Coastguard Worker
erase_sector_jedec(struct flashctx * flash,unsigned int page,unsigned int size)303*0d6140beSAndroid Build Coastguard Worker int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int size)
304*0d6140beSAndroid Build Coastguard Worker {
305*0d6140beSAndroid Build Coastguard Worker /* Issue the Sector Erase command */
306*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x80, 0);
307*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x30, page);
308*0d6140beSAndroid Build Coastguard Worker
309*0d6140beSAndroid Build Coastguard Worker /* Wait for Toggle bit ready */
310*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec_slow(flash);
311*0d6140beSAndroid Build Coastguard Worker
312*0d6140beSAndroid Build Coastguard Worker /* FIXME: Check the status register for errors. */
313*0d6140beSAndroid Build Coastguard Worker return 0;
314*0d6140beSAndroid Build Coastguard Worker }
315*0d6140beSAndroid Build Coastguard Worker
erase_block_jedec(struct flashctx * flash,unsigned int block,unsigned int size)316*0d6140beSAndroid Build Coastguard Worker int erase_block_jedec(struct flashctx *flash, unsigned int block, unsigned int size)
317*0d6140beSAndroid Build Coastguard Worker {
318*0d6140beSAndroid Build Coastguard Worker /* Issue the Block Erase command */
319*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x80, 0);
320*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x50, block);
321*0d6140beSAndroid Build Coastguard Worker
322*0d6140beSAndroid Build Coastguard Worker /* Wait for Toggle bit ready */
323*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec_slow(flash);
324*0d6140beSAndroid Build Coastguard Worker
325*0d6140beSAndroid Build Coastguard Worker /* FIXME: Check the status register for errors. */
326*0d6140beSAndroid Build Coastguard Worker return 0;
327*0d6140beSAndroid Build Coastguard Worker }
328*0d6140beSAndroid Build Coastguard Worker
329*0d6140beSAndroid Build Coastguard Worker /* erase chip with block_erase() prototype */
erase_chip_block_jedec(struct flashctx * flash,unsigned int addr,unsigned int blocksize)330*0d6140beSAndroid Build Coastguard Worker int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr, unsigned int blocksize)
331*0d6140beSAndroid Build Coastguard Worker {
332*0d6140beSAndroid Build Coastguard Worker if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
333*0d6140beSAndroid Build Coastguard Worker msg_cerr("%s called with incorrect arguments\n", __func__);
334*0d6140beSAndroid Build Coastguard Worker return -1;
335*0d6140beSAndroid Build Coastguard Worker }
336*0d6140beSAndroid Build Coastguard Worker
337*0d6140beSAndroid Build Coastguard Worker /* Issue the JEDEC Chip Erase command */
338*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x80, 0);
339*0d6140beSAndroid Build Coastguard Worker issuecmd(flash, 0x10, 0);
340*0d6140beSAndroid Build Coastguard Worker
341*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec_slow(flash);
342*0d6140beSAndroid Build Coastguard Worker
343*0d6140beSAndroid Build Coastguard Worker /* FIXME: Check the status register for errors. */
344*0d6140beSAndroid Build Coastguard Worker return 0;
345*0d6140beSAndroid Build Coastguard Worker }
346*0d6140beSAndroid Build Coastguard Worker
write_byte_program_jedec_common(const struct flashctx * flash,const uint8_t * src,chipaddr dst)347*0d6140beSAndroid Build Coastguard Worker static int write_byte_program_jedec_common(const struct flashctx *flash, const uint8_t *src,
348*0d6140beSAndroid Build Coastguard Worker chipaddr dst)
349*0d6140beSAndroid Build Coastguard Worker {
350*0d6140beSAndroid Build Coastguard Worker int tries = 0;
351*0d6140beSAndroid Build Coastguard Worker
352*0d6140beSAndroid Build Coastguard Worker /* If the data is 0xFF, don't program it and don't complain. */
353*0d6140beSAndroid Build Coastguard Worker if (*src == 0xFF) {
354*0d6140beSAndroid Build Coastguard Worker return 0;
355*0d6140beSAndroid Build Coastguard Worker }
356*0d6140beSAndroid Build Coastguard Worker
357*0d6140beSAndroid Build Coastguard Worker for (; tries < MAX_REFLASH_TRIES; tries++) {
358*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
359*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Byte Program command */
360*0d6140beSAndroid Build Coastguard Worker start_program_jedec_common(flash);
361*0d6140beSAndroid Build Coastguard Worker
362*0d6140beSAndroid Build Coastguard Worker /* transfer data from source to destination */
363*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, *src, dst);
364*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec(flash, bios);
365*0d6140beSAndroid Build Coastguard Worker
366*0d6140beSAndroid Build Coastguard Worker if (chip_readb(flash, dst) == *src)
367*0d6140beSAndroid Build Coastguard Worker break;
368*0d6140beSAndroid Build Coastguard Worker }
369*0d6140beSAndroid Build Coastguard Worker
370*0d6140beSAndroid Build Coastguard Worker return (tries >= MAX_REFLASH_TRIES) ? 1 : 0;
371*0d6140beSAndroid Build Coastguard Worker }
372*0d6140beSAndroid Build Coastguard Worker
373*0d6140beSAndroid Build Coastguard Worker /* chunksize is 1 */
write_jedec_1(struct flashctx * flash,const uint8_t * src,unsigned int start,unsigned int len)374*0d6140beSAndroid Build Coastguard Worker int write_jedec_1(struct flashctx *flash, const uint8_t *src, unsigned int start,
375*0d6140beSAndroid Build Coastguard Worker unsigned int len)
376*0d6140beSAndroid Build Coastguard Worker {
377*0d6140beSAndroid Build Coastguard Worker int failed = 0;
378*0d6140beSAndroid Build Coastguard Worker chipaddr dst = flash->virtual_memory + start;
379*0d6140beSAndroid Build Coastguard Worker const chipaddr olddst = dst;
380*0d6140beSAndroid Build Coastguard Worker
381*0d6140beSAndroid Build Coastguard Worker for (unsigned int i = 0; i < len; i++) {
382*0d6140beSAndroid Build Coastguard Worker if (write_byte_program_jedec_common(flash, src, dst))
383*0d6140beSAndroid Build Coastguard Worker failed = 1;
384*0d6140beSAndroid Build Coastguard Worker dst++, src++;
385*0d6140beSAndroid Build Coastguard Worker update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len);
386*0d6140beSAndroid Build Coastguard Worker }
387*0d6140beSAndroid Build Coastguard Worker if (failed)
388*0d6140beSAndroid Build Coastguard Worker msg_cerr(" writing sector at 0x%" PRIxPTR " failed!\n", olddst);
389*0d6140beSAndroid Build Coastguard Worker
390*0d6140beSAndroid Build Coastguard Worker return failed;
391*0d6140beSAndroid Build Coastguard Worker }
392*0d6140beSAndroid Build Coastguard Worker
jedec_write_page(struct flashctx * flash,const uint8_t * src,unsigned int start,unsigned int page_size)393*0d6140beSAndroid Build Coastguard Worker static int jedec_write_page(struct flashctx *flash, const uint8_t *src,
394*0d6140beSAndroid Build Coastguard Worker unsigned int start, unsigned int page_size)
395*0d6140beSAndroid Build Coastguard Worker {
396*0d6140beSAndroid Build Coastguard Worker int tries = 0, failed;
397*0d6140beSAndroid Build Coastguard Worker const uint8_t *s = src;
398*0d6140beSAndroid Build Coastguard Worker const chipaddr bios = flash->virtual_memory;
399*0d6140beSAndroid Build Coastguard Worker chipaddr dst = bios + start;
400*0d6140beSAndroid Build Coastguard Worker chipaddr d = dst;
401*0d6140beSAndroid Build Coastguard Worker
402*0d6140beSAndroid Build Coastguard Worker for (; tries < MAX_REFLASH_TRIES; tries++) {
403*0d6140beSAndroid Build Coastguard Worker /* Issue JEDEC Start Program command */
404*0d6140beSAndroid Build Coastguard Worker start_program_jedec_common(flash);
405*0d6140beSAndroid Build Coastguard Worker
406*0d6140beSAndroid Build Coastguard Worker /* transfer data from source to destination */
407*0d6140beSAndroid Build Coastguard Worker for (unsigned int i = 0; i < page_size; i++) {
408*0d6140beSAndroid Build Coastguard Worker /* If the data is 0xFF, don't program it */
409*0d6140beSAndroid Build Coastguard Worker if (*src != 0xFF)
410*0d6140beSAndroid Build Coastguard Worker chip_writeb(flash, *src, dst);
411*0d6140beSAndroid Build Coastguard Worker dst++;
412*0d6140beSAndroid Build Coastguard Worker src++;
413*0d6140beSAndroid Build Coastguard Worker }
414*0d6140beSAndroid Build Coastguard Worker
415*0d6140beSAndroid Build Coastguard Worker toggle_ready_jedec(flash, dst - 1);
416*0d6140beSAndroid Build Coastguard Worker
417*0d6140beSAndroid Build Coastguard Worker dst = d;
418*0d6140beSAndroid Build Coastguard Worker src = s;
419*0d6140beSAndroid Build Coastguard Worker failed = verify_range(flash, src, start, page_size);
420*0d6140beSAndroid Build Coastguard Worker if (!failed)
421*0d6140beSAndroid Build Coastguard Worker break;
422*0d6140beSAndroid Build Coastguard Worker
423*0d6140beSAndroid Build Coastguard Worker msg_cerr("retrying.\n");
424*0d6140beSAndroid Build Coastguard Worker }
425*0d6140beSAndroid Build Coastguard Worker
426*0d6140beSAndroid Build Coastguard Worker if (failed) {
427*0d6140beSAndroid Build Coastguard Worker msg_cerr(" page 0x%" PRIxPTR " failed!\n", (d - bios) / page_size);
428*0d6140beSAndroid Build Coastguard Worker }
429*0d6140beSAndroid Build Coastguard Worker
430*0d6140beSAndroid Build Coastguard Worker return failed;
431*0d6140beSAndroid Build Coastguard Worker }
432*0d6140beSAndroid Build Coastguard Worker
433*0d6140beSAndroid Build Coastguard Worker /* chunksize is page_size */
434*0d6140beSAndroid Build Coastguard Worker /*
435*0d6140beSAndroid Build Coastguard Worker * Write a part of the flash chip.
436*0d6140beSAndroid Build Coastguard Worker * FIXME: Use the chunk code from Michael Karcher instead.
437*0d6140beSAndroid Build Coastguard Worker * This function is a slightly modified copy of spi_write_chunked.
438*0d6140beSAndroid Build Coastguard Worker * Each page is written separately in chunks with a maximum size of chunksize.
439*0d6140beSAndroid Build Coastguard Worker */
write_jedec(struct flashctx * flash,const uint8_t * buf,unsigned int start,int unsigned len)440*0d6140beSAndroid Build Coastguard Worker int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start,
441*0d6140beSAndroid Build Coastguard Worker int unsigned len)
442*0d6140beSAndroid Build Coastguard Worker {
443*0d6140beSAndroid Build Coastguard Worker unsigned int starthere, lenhere;
444*0d6140beSAndroid Build Coastguard Worker /* FIXME: page_size is the wrong variable. We need max_writechunk_size
445*0d6140beSAndroid Build Coastguard Worker * in struct flashctx to do this properly. All chips using
446*0d6140beSAndroid Build Coastguard Worker * write_jedec have page_size set to max_writechunk_size, so
447*0d6140beSAndroid Build Coastguard Worker * we're OK for now.
448*0d6140beSAndroid Build Coastguard Worker */
449*0d6140beSAndroid Build Coastguard Worker const unsigned int page_size = flash->chip->page_size;
450*0d6140beSAndroid Build Coastguard Worker const unsigned int nwrites = (start + len - 1) / page_size;
451*0d6140beSAndroid Build Coastguard Worker
452*0d6140beSAndroid Build Coastguard Worker /* Warning: This loop has a very unusual condition and body.
453*0d6140beSAndroid Build Coastguard Worker * The loop needs to go through each page with at least one affected
454*0d6140beSAndroid Build Coastguard Worker * byte. The lowest page number is (start / page_size) since that
455*0d6140beSAndroid Build Coastguard Worker * division rounds down. The highest page number we want is the page
456*0d6140beSAndroid Build Coastguard Worker * where the last byte of the range lives. That last byte has the
457*0d6140beSAndroid Build Coastguard Worker * address (start + len - 1), thus the highest page number is
458*0d6140beSAndroid Build Coastguard Worker * (start + len - 1) / page_size. Since we want to include that last
459*0d6140beSAndroid Build Coastguard Worker * page as well, the loop condition uses <=.
460*0d6140beSAndroid Build Coastguard Worker */
461*0d6140beSAndroid Build Coastguard Worker for (unsigned int i = start / page_size; i <= nwrites; i++) {
462*0d6140beSAndroid Build Coastguard Worker /* Byte position of the first byte in the range in this page. */
463*0d6140beSAndroid Build Coastguard Worker /* starthere is an offset to the base address of the chip. */
464*0d6140beSAndroid Build Coastguard Worker starthere = max(start, i * page_size);
465*0d6140beSAndroid Build Coastguard Worker /* Length of bytes in the range in this page. */
466*0d6140beSAndroid Build Coastguard Worker lenhere = min(start + len, (i + 1) * page_size) - starthere;
467*0d6140beSAndroid Build Coastguard Worker
468*0d6140beSAndroid Build Coastguard Worker if (jedec_write_page(flash, buf + starthere - start, starthere, lenhere))
469*0d6140beSAndroid Build Coastguard Worker return 1;
470*0d6140beSAndroid Build Coastguard Worker update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, nwrites + 1);
471*0d6140beSAndroid Build Coastguard Worker }
472*0d6140beSAndroid Build Coastguard Worker
473*0d6140beSAndroid Build Coastguard Worker return 0;
474*0d6140beSAndroid Build Coastguard Worker }
475