blob: e2bfe731a81e22f14677b270caec7b5b9ea5733e [file] [log] [blame]
rminnich8d3ff912003-10-25 17:01:29 +00001/*
uweb25f1ea2007-08-29 17:52:32 +00002 * This file is part of the flashrom project.
rminnich8d3ff912003-10-25 17:01:29 +00003 *
uwe555dd972007-09-09 20:21:05 +00004 * Copyright (C) 2000 Silicon Integrated System Corporation
5 * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
6 * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
Stuart Langley60395ef2020-03-25 20:32:45 +11007 * Copyright (C) 2007-2012 Carl-Daniel Hailfinger
snelson63133f92010-01-04 17:15:23 +00008 * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
Stuart Langley60395ef2020-03-25 20:32:45 +11009 * Copyright (C) 2014 Stefan Tauner
rminnich8d3ff912003-10-25 17:01:29 +000010 *
uweb25f1ea2007-08-29 17:52:32 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
rminnich8d3ff912003-10-25 17:01:29 +000015 *
uweb25f1ea2007-08-29 17:52:32 +000016 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
rminnich8d3ff912003-10-25 17:01:29 +000020 */
21
rminnich8d3ff912003-10-25 17:01:29 +000022#include "flash.h"
Kangheui Won4974cc12019-10-18 12:59:01 +110023#include <inttypes.h>
rminnich8d3ff912003-10-25 17:01:29 +000024
stepan7abc6322006-11-22 00:29:51 +000025#define MAX_REFLASH_TRIES 0x10
snelson63133f92010-01-04 17:15:23 +000026#define MASK_FULL 0xffff
27#define MASK_2AA 0x7ff
snelsonc6855342010-01-28 23:55:12 +000028#define MASK_AAA 0xfff
stepan7abc6322006-11-22 00:29:51 +000029
hailfinger79cf3672008-05-14 12:03:06 +000030/* Check one byte for odd parity */
31uint8_t oddparity(uint8_t val)
32{
33 val = (val ^ (val >> 4)) & 0xf;
34 val = (val ^ (val >> 2)) & 0x3;
35 return (val ^ (val >> 1)) & 0x1;
36}
37
Stuart Langley60395ef2020-03-25 20:32:45 +110038static void toggle_ready_jedec_common(const struct flashctx *flash, chipaddr dst, unsigned int delay)
uwedf467892007-08-23 10:20:40 +000039{
40 unsigned int i = 0;
41 uint8_t tmp1, tmp2;
42
Souvik Ghoshd75cd672016-06-17 14:21:39 -070043 tmp1 = chip_readb(flash, dst) & 0x40;
uwedf467892007-08-23 10:20:40 +000044
45 while (i++ < 0xFFFFFFF) {
hailfinger10023012009-12-17 16:20:26 +000046 if (delay)
47 programmer_delay(delay);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070048 tmp2 = chip_readb(flash, dst) & 0x40;
uwedf467892007-08-23 10:20:40 +000049 if (tmp1 == tmp2) {
50 break;
51 }
52 tmp1 = tmp2;
53 }
hailfinger10023012009-12-17 16:20:26 +000054 if (i > 0x100000)
snelsonfc007bb2010-03-24 23:14:32 +000055 msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
hailfinger10023012009-12-17 16:20:26 +000056}
57
Souvik Ghoshd75cd672016-06-17 14:21:39 -070058void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst)
hailfinger10023012009-12-17 16:20:26 +000059{
Souvik Ghoshd75cd672016-06-17 14:21:39 -070060 toggle_ready_jedec_common(flash, dst, 0);
hailfinger10023012009-12-17 16:20:26 +000061}
62
63/* Some chips require a minimum delay between toggle bit reads.
64 * The Winbond W39V040C wants 50 ms between reads on sector erase toggle,
65 * but experiments show that 2 ms are already enough. Pick a safety factor
66 * of 4 and use an 8 ms delay.
Stuart Langley60395ef2020-03-25 20:32:45 +110067 * Given that erase is slow on all chips, it is recommended to use
hailfinger10023012009-12-17 16:20:26 +000068 * toggle_ready_jedec_slow in erase functions.
69 */
Souvik Ghoshd75cd672016-06-17 14:21:39 -070070static void toggle_ready_jedec_slow(const struct flashctx *flash, chipaddr dst)
hailfinger10023012009-12-17 16:20:26 +000071{
Souvik Ghoshd75cd672016-06-17 14:21:39 -070072 toggle_ready_jedec_common(flash, dst, 8 * 1000);
uwedf467892007-08-23 10:20:40 +000073}
74
Stuart Langley60395ef2020-03-25 20:32:45 +110075void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
76 uint8_t data)
uwedf467892007-08-23 10:20:40 +000077{
78 unsigned int i = 0;
79 uint8_t tmp;
80
81 data &= 0x80;
82
83 while (i++ < 0xFFFFFFF) {
Souvik Ghoshd75cd672016-06-17 14:21:39 -070084 tmp = chip_readb(flash, dst) & 0x80;
uwedf467892007-08-23 10:20:40 +000085 if (tmp == data) {
86 break;
87 }
88 }
hailfinger10023012009-12-17 16:20:26 +000089 if (i > 0x100000)
snelsonfc007bb2010-03-24 23:14:32 +000090 msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i);
uwedf467892007-08-23 10:20:40 +000091}
92
Stuart Langley60395ef2020-03-25 20:32:45 +110093static unsigned int getaddrmask(const struct flashchip *chip)
hailfinger86bf3b52010-10-13 21:49:30 +000094{
Stuart Langley60395ef2020-03-25 20:32:45 +110095 switch (chip->feature_bits & FEATURE_ADDR_MASK) {
hailfinger86bf3b52010-10-13 21:49:30 +000096 case FEATURE_ADDR_FULL:
97 return MASK_FULL;
98 break;
99 case FEATURE_ADDR_2AA:
100 return MASK_2AA;
101 break;
102 case FEATURE_ADDR_AAA:
103 return MASK_AAA;
104 break;
105 default:
106 msg_cerr("%s called with unknown mask\n", __func__);
107 return 0;
108 break;
109 }
110}
111
Stuart Langley60395ef2020-03-25 20:32:45 +1100112static void start_program_jedec_common(const struct flashctx *flash, unsigned int mask)
uwedf467892007-08-23 10:20:40 +0000113{
snelson63133f92010-01-04 17:15:23 +0000114 chipaddr bios = flash->virtual_memory;
Stuart langleya7d761f2020-03-26 15:05:38 +1100115 bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
116
117 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
118 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
119 chip_writeb(flash, 0xA0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
uwedf467892007-08-23 10:20:40 +0000120}
121
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700122static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
rminnich8d3ff912003-10-25 17:01:29 +0000123{
hailfinger82719632009-05-16 21:22:56 +0000124 chipaddr bios = flash->virtual_memory;
Stuart langleya7d761f2020-03-26 15:05:38 +1100125 const struct flashchip *chip = flash->chip;
126 bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
ollie6a600992005-11-26 21:55:36 +0000127 uint8_t id1, id2;
hailfinger428f2012007-12-31 01:49:00 +0000128 uint32_t largeid1, largeid2;
hailfinger027d7d92009-05-11 14:40:31 +0000129 uint32_t flashcontent1, flashcontent2;
Stuart langleya7d761f2020-03-26 15:05:38 +1100130 unsigned int probe_timing_enter, probe_timing_exit;
hailfingerd5b35922009-06-03 14:46:22 +0000131
Stuart langleya7d761f2020-03-26 15:05:38 +1100132 if (chip->probe_timing > 0)
133 probe_timing_enter = probe_timing_exit = chip->probe_timing;
134 else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
hailfingerd5b35922009-06-03 14:46:22 +0000135 probe_timing_enter = probe_timing_exit = 0;
Stuart langleya7d761f2020-03-26 15:05:38 +1100136 } else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
137 msg_cdbg("Chip lacks correct probe timing information, using default 10ms/40us. ");
hailfingerd5b35922009-06-03 14:46:22 +0000138 probe_timing_enter = 10000;
139 probe_timing_exit = 40;
140 } else {
Stuart langleya7d761f2020-03-26 15:05:38 +1100141 msg_cerr("Chip has negative value in probe_timing, failing without chip access\n");
hailfingerd5b35922009-06-03 14:46:22 +0000142 return 0;
143 }
rminnich8d3ff912003-10-25 17:01:29 +0000144
hailfingerb07dc972010-10-20 21:13:19 +0000145 /* Earlier probes might have been too fast for the chip to enter ID
146 * mode completely. Allow the chip to finish this before seeing a
147 * reset command.
148 */
149 if (probe_timing_enter)
150 programmer_delay(probe_timing_enter);
151 /* Reset chip to a clean slate */
Stuart langleya7d761f2020-03-26 15:05:38 +1100152 if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
hailfingerb07dc972010-10-20 21:13:19 +0000153 {
Stuart langleya7d761f2020-03-26 15:05:38 +1100154 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
hailfingerb07dc972010-10-20 21:13:19 +0000155 if (probe_timing_exit)
156 programmer_delay(10);
Stuart langleya7d761f2020-03-26 15:05:38 +1100157 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
hailfingerb07dc972010-10-20 21:13:19 +0000158 if (probe_timing_exit)
159 programmer_delay(10);
160 }
Stuart langleya7d761f2020-03-26 15:05:38 +1100161 chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
hailfingerb07dc972010-10-20 21:13:19 +0000162 if (probe_timing_exit)
163 programmer_delay(probe_timing_exit);
164
ollie5b621572004-03-20 16:46:10 +0000165 /* Issue JEDEC Product ID Entry command */
Stuart langleya7d761f2020-03-26 15:05:38 +1100166 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
hailfingerc7568d52009-12-17 04:22:40 +0000167 if (probe_timing_enter)
168 programmer_delay(10);
Stuart langleya7d761f2020-03-26 15:05:38 +1100169 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
hailfingerc7568d52009-12-17 04:22:40 +0000170 if (probe_timing_enter)
171 programmer_delay(10);
Stuart langleya7d761f2020-03-26 15:05:38 +1100172 chip_writeb(flash, 0x90, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
hailfingerc7568d52009-12-17 04:22:40 +0000173 if (probe_timing_enter)
174 programmer_delay(probe_timing_enter);
rminnich8d3ff912003-10-25 17:01:29 +0000175
ollie5b621572004-03-20 16:46:10 +0000176 /* Read product ID */
Stuart langleya7d761f2020-03-26 15:05:38 +1100177 id1 = chip_readb(flash, bios + (0x00 << shifted));
178 id2 = chip_readb(flash, bios + (0x01 << shifted));
hailfinger428f2012007-12-31 01:49:00 +0000179 largeid1 = id1;
180 largeid2 = id2;
181
182 /* Check if it is a continuation ID, this should be a while loop. */
183 if (id1 == 0x7F) {
184 largeid1 <<= 8;
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700185 id1 = chip_readb(flash, bios + 0x100);
hailfinger428f2012007-12-31 01:49:00 +0000186 largeid1 |= id1;
187 }
188 if (id2 == 0x7F) {
189 largeid2 <<= 8;
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700190 id2 = chip_readb(flash, bios + 0x101);
hailfinger428f2012007-12-31 01:49:00 +0000191 largeid2 |= id2;
192 }
rminnich8d3ff912003-10-25 17:01:29 +0000193
ollie5b621572004-03-20 16:46:10 +0000194 /* Issue JEDEC Product ID Exit command */
Stuart langleya7d761f2020-03-26 15:05:38 +1100195 if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
snelson63133f92010-01-04 17:15:23 +0000196 {
Stuart langleya7d761f2020-03-26 15:05:38 +1100197 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
snelson63133f92010-01-04 17:15:23 +0000198 if (probe_timing_exit)
199 programmer_delay(10);
Stuart langleya7d761f2020-03-26 15:05:38 +1100200 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
snelson63133f92010-01-04 17:15:23 +0000201 if (probe_timing_exit)
202 programmer_delay(10);
203 }
Stuart langleya7d761f2020-03-26 15:05:38 +1100204 chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
hailfingerc7568d52009-12-17 04:22:40 +0000205 if (probe_timing_exit)
206 programmer_delay(probe_timing_exit);
rminnich8d3ff912003-10-25 17:01:29 +0000207
snelsonfc007bb2010-03-24 23:14:32 +0000208 msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
hailfinger79cf3672008-05-14 12:03:06 +0000209 if (!oddparity(id1))
snelsonfc007bb2010-03-24 23:14:32 +0000210 msg_cdbg(", id1 parity violation");
hailfinger027d7d92009-05-11 14:40:31 +0000211
212 /* Read the product ID location again. We should now see normal flash contents. */
Stuart langleya7d761f2020-03-26 15:05:38 +1100213 flashcontent1 = chip_readb(flash, bios + (0x00 << shifted));
214 flashcontent2 = chip_readb(flash, bios + (0x01 << shifted));
hailfinger027d7d92009-05-11 14:40:31 +0000215
216 /* Check if it is a continuation ID, this should be a while loop. */
217 if (flashcontent1 == 0x7F) {
218 flashcontent1 <<= 8;
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700219 flashcontent1 |= chip_readb(flash, bios + 0x100);
hailfinger027d7d92009-05-11 14:40:31 +0000220 }
221 if (flashcontent2 == 0x7F) {
222 flashcontent2 <<= 8;
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700223 flashcontent2 |= chip_readb(flash, bios + 0x101);
hailfinger027d7d92009-05-11 14:40:31 +0000224 }
225
226 if (largeid1 == flashcontent1)
snelsonfc007bb2010-03-24 23:14:32 +0000227 msg_cdbg(", id1 is normal flash content");
hailfinger027d7d92009-05-11 14:40:31 +0000228 if (largeid2 == flashcontent2)
snelsonfc007bb2010-03-24 23:14:32 +0000229 msg_cdbg(", id2 is normal flash content");
hailfinger027d7d92009-05-11 14:40:31 +0000230
snelsonfc007bb2010-03-24 23:14:32 +0000231 msg_cdbg("\n");
Stuart langleya7d761f2020-03-26 15:05:38 +1100232 if (largeid1 != chip->manufacture_id || largeid2 != chip->model_id)
hailfingerafac00e2010-01-09 02:24:17 +0000233 return 0;
rminnich8d3ff912003-10-25 17:01:29 +0000234
Patrick Georgif3fa2992017-02-02 16:24:44 +0100235 if (flash->chip->feature_bits & FEATURE_REGISTERMAP)
snelson63133f92010-01-04 17:15:23 +0000236 map_flash_registers(flash);
237
hailfingerafac00e2010-01-09 02:24:17 +0000238 return 1;
olliea3def632004-03-19 22:10:07 +0000239}
240
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700241static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
Stuart Langley60395ef2020-03-25 20:32:45 +1100242 unsigned int pagesize, unsigned int mask)
olliea3def632004-03-19 22:10:07 +0000243{
hailfinger7af83692009-06-15 17:23:36 +0000244 chipaddr bios = flash->virtual_memory;
Stuart langleya7d761f2020-03-26 15:05:38 +1100245 bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
246 unsigned int delay_us = 0;
247
Patrick Georgif3fa2992017-02-02 16:24:44 +0100248 if(flash->chip->probe_timing != TIMING_ZERO)
Stuart langleya7d761f2020-03-26 15:05:38 +1100249 delay_us = 10;
hailfinger7af83692009-06-15 17:23:36 +0000250
ollie5b621572004-03-20 16:46:10 +0000251 /* Issue the Sector Erase command */
Stuart langleya7d761f2020-03-26 15:05:38 +1100252 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000253 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100254 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000255 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100256 chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000257 programmer_delay(delay_us);
ollie0eb62d62004-12-08 20:10:01 +0000258
Stuart langleya7d761f2020-03-26 15:05:38 +1100259 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000260 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100261 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000262 programmer_delay(delay_us);
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700263 chip_writeb(flash, 0x30, bios + page);
mkarcherf7af1b42011-04-15 00:03:37 +0000264 programmer_delay(delay_us);
ollie5b621572004-03-20 16:46:10 +0000265
olliea3def632004-03-19 22:10:07 +0000266 /* wait for Toggle bit ready */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700267 toggle_ready_jedec_slow(flash, bios);
olliea3def632004-03-19 22:10:07 +0000268
hailfingerac8e3182011-06-26 17:04:16 +0000269 /* FIXME: Check the status register for errors. */
uwebe4477b2007-08-23 16:08:21 +0000270 return 0;
rminnich8d3ff912003-10-25 17:01:29 +0000271}
olliea4302802004-12-07 03:15:51 +0000272
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700273static int erase_block_jedec_common(struct flashctx *flash, unsigned int block,
Stuart Langley60395ef2020-03-25 20:32:45 +1100274 unsigned int blocksize, unsigned int mask)
rminnichdfcbaa72004-09-30 16:37:01 +0000275{
hailfinger7af83692009-06-15 17:23:36 +0000276 chipaddr bios = flash->virtual_memory;
Stuart langleya7d761f2020-03-26 15:05:38 +1100277 bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
278 unsigned int delay_us = 0;
279
Patrick Georgif3fa2992017-02-02 16:24:44 +0100280 if(flash->chip->probe_timing != TIMING_ZERO)
Stuart langleya7d761f2020-03-26 15:05:38 +1100281 delay_us = 10;
hailfinger7af83692009-06-15 17:23:36 +0000282
rminnichdfcbaa72004-09-30 16:37:01 +0000283 /* Issue the Sector Erase command */
Stuart langleya7d761f2020-03-26 15:05:38 +1100284 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000285 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100286 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000287 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100288 chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000289 programmer_delay(delay_us);
ollie0eb62d62004-12-08 20:10:01 +0000290
Stuart langleya7d761f2020-03-26 15:05:38 +1100291 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000292 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100293 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000294 programmer_delay(delay_us);
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700295 chip_writeb(flash, 0x50, bios + block);
mkarcherf7af1b42011-04-15 00:03:37 +0000296 programmer_delay(delay_us);
rminnichdfcbaa72004-09-30 16:37:01 +0000297
298 /* wait for Toggle bit ready */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700299 toggle_ready_jedec_slow(flash, bios);
rminnichdfcbaa72004-09-30 16:37:01 +0000300
hailfingerac8e3182011-06-26 17:04:16 +0000301 /* FIXME: Check the status register for errors. */
uwebe4477b2007-08-23 16:08:21 +0000302 return 0;
rminnichdfcbaa72004-09-30 16:37:01 +0000303}
rminnich8d3ff912003-10-25 17:01:29 +0000304
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700305static int erase_chip_jedec_common(struct flashctx *flash, unsigned int mask)
rminnich8d3ff912003-10-25 17:01:29 +0000306{
hailfinger82719632009-05-16 21:22:56 +0000307 chipaddr bios = flash->virtual_memory;
Stuart langleya7d761f2020-03-26 15:05:38 +1100308 bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
309 unsigned int delay_us = 0;
310
Patrick Georgif3fa2992017-02-02 16:24:44 +0100311 if(flash->chip->probe_timing != TIMING_ZERO)
Stuart langleya7d761f2020-03-26 15:05:38 +1100312 delay_us = 10;
rminnich8d3ff912003-10-25 17:01:29 +0000313
ollie5b621572004-03-20 16:46:10 +0000314 /* Issue the JEDEC Chip Erase command */
Stuart langleya7d761f2020-03-26 15:05:38 +1100315 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000316 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100317 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000318 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100319 chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000320 programmer_delay(delay_us);
ollie0eb62d62004-12-08 20:10:01 +0000321
Stuart langleya7d761f2020-03-26 15:05:38 +1100322 chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000323 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100324 chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000325 programmer_delay(delay_us);
Stuart langleya7d761f2020-03-26 15:05:38 +1100326 chip_writeb(flash, 0x10, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
mkarcherf7af1b42011-04-15 00:03:37 +0000327 programmer_delay(delay_us);
olliea3def632004-03-19 22:10:07 +0000328
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700329 toggle_ready_jedec_slow(flash, bios);
rminnich8d3ff912003-10-25 17:01:29 +0000330
hailfingerac8e3182011-06-26 17:04:16 +0000331 /* FIXME: Check the status register for errors. */
uwebe4477b2007-08-23 16:08:21 +0000332 return 0;
rminnich8d3ff912003-10-25 17:01:29 +0000333}
334
Stuart Langley60395ef2020-03-25 20:32:45 +1100335static int write_byte_program_jedec_common(const struct flashctx *flash, const uint8_t *src,
336 chipaddr dst, unsigned int mask)
snelson63133f92010-01-04 17:15:23 +0000337{
338 int tried = 0, failed = 0;
339 chipaddr bios = flash->virtual_memory;
340
341 /* If the data is 0xFF, don't program it and don't complain. */
342 if (*src == 0xFF) {
343 return 0;
344 }
345
346retry:
347 /* Issue JEDEC Byte Program command */
348 start_program_jedec_common(flash, mask);
349
350 /* transfer data from source to destination */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700351 chip_writeb(flash, *src, dst);
352 toggle_ready_jedec(flash, bios);
snelson63133f92010-01-04 17:15:23 +0000353
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700354 if (chip_readb(flash, dst) != *src && tried++ < MAX_REFLASH_TRIES) {
snelson63133f92010-01-04 17:15:23 +0000355 goto retry;
356 }
357
358 if (tried >= MAX_REFLASH_TRIES)
359 failed = 1;
360
361 return failed;
362}
363
hailfinger71e1bd42010-10-13 22:26:56 +0000364/* chunksize is 1 */
Stuart Langley60395ef2020-03-25 20:32:45 +1100365int write_jedec_1(struct flashctx *flash, const uint8_t *src, unsigned int start,
366 unsigned int len)
snelson63133f92010-01-04 17:15:23 +0000367{
Stuart Langley60395ef2020-03-25 20:32:45 +1100368 unsigned int i;
369 int failed = 0;
hailfingera10a6072010-10-10 14:02:27 +0000370 chipaddr dst = flash->virtual_memory + start;
snelson63133f92010-01-04 17:15:23 +0000371 chipaddr olddst;
stefanctc5eb8a92011-11-23 09:13:48 +0000372 unsigned int mask;
hailfinger86bf3b52010-10-13 21:49:30 +0000373
Stuart Langley60395ef2020-03-25 20:32:45 +1100374 mask = getaddrmask(flash->chip);
snelson63133f92010-01-04 17:15:23 +0000375
376 olddst = dst;
hailfingera10a6072010-10-10 14:02:27 +0000377 for (i = 0; i < len; i++) {
snelson63133f92010-01-04 17:15:23 +0000378 if (write_byte_program_jedec_common(flash, src, dst, mask))
379 failed = 1;
380 dst++, src++;
381 }
382 if (failed)
Kangheui Won4974cc12019-10-18 12:59:01 +1100383 msg_cerr(" writing sector at 0x%" PRIxPTR " failed!\n", olddst);
snelson63133f92010-01-04 17:15:23 +0000384
385 return failed;
386}
387
Stuart Langley60395ef2020-03-25 20:32:45 +1100388static int write_page_write_jedec_common(struct flashctx *flash, const uint8_t *src,
389 unsigned int start, unsigned int page_size)
rminnich8d3ff912003-10-25 17:01:29 +0000390{
Stuart Langley60395ef2020-03-25 20:32:45 +1100391 unsigned int i;
392 int tried = 0, failed;
393 const uint8_t *s = src;
hailfingerc2cfc592009-06-25 13:57:31 +0000394 chipaddr bios = flash->virtual_memory;
395 chipaddr dst = bios + start;
396 chipaddr d = dst;
stefanctc5eb8a92011-11-23 09:13:48 +0000397 unsigned int mask;
hailfinger86bf3b52010-10-13 21:49:30 +0000398
Stuart Langley60395ef2020-03-25 20:32:45 +1100399 mask = getaddrmask(flash->chip);
rminnich8d3ff912003-10-25 17:01:29 +0000400
stepan7abc6322006-11-22 00:29:51 +0000401retry:
uwe3a3ab2f2010-03-25 23:18:41 +0000402 /* Issue JEDEC Start Program command */
snelson63133f92010-01-04 17:15:23 +0000403 start_program_jedec_common(flash, mask);
ollie5b621572004-03-20 16:46:10 +0000404
olliea4302802004-12-07 03:15:51 +0000405 /* transfer data from source to destination */
hailfingerfe072472009-11-14 03:48:33 +0000406 for (i = 0; i < page_size; i++) {
olliea4302802004-12-07 03:15:51 +0000407 /* If the data is 0xFF, don't program it */
uwef6641642007-05-09 10:17:44 +0000408 if (*src != 0xFF)
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700409 chip_writeb(flash, *src, dst);
stepan7abc6322006-11-22 00:29:51 +0000410 dst++;
411 src++;
ollie5b621572004-03-20 16:46:10 +0000412 }
413
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700414 toggle_ready_jedec(flash, dst - 1);
olliea4302802004-12-07 03:15:51 +0000415
stepan7abc6322006-11-22 00:29:51 +0000416 dst = d;
417 src = s;
hailfingerf2ac27e2009-11-25 16:41:50 +0000418 failed = verify_range(flash, src, start, page_size, NULL);
uwef6641642007-05-09 10:17:44 +0000419
hailfingerf2ac27e2009-11-25 16:41:50 +0000420 if (failed && tried++ < MAX_REFLASH_TRIES) {
snelsonfc007bb2010-03-24 23:14:32 +0000421 msg_cerr("retrying.\n");
uwef6641642007-05-09 10:17:44 +0000422 goto retry;
423 }
hailfingerf2ac27e2009-11-25 16:41:50 +0000424 if (failed) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100425 msg_cerr(" page 0x%" PRIxPTR " failed!\n", (d - bios) / page_size);
stepan7abc6322006-11-22 00:29:51 +0000426 }
hailfingerf2ac27e2009-11-25 16:41:50 +0000427 return failed;
ollie5b621572004-03-20 16:46:10 +0000428}
429
hailfinger71e1bd42010-10-13 22:26:56 +0000430/* chunksize is page_size */
hailfinger86bf3b52010-10-13 21:49:30 +0000431/*
432 * Write a part of the flash chip.
433 * FIXME: Use the chunk code from Michael Karcher instead.
434 * This function is a slightly modified copy of spi_write_chunked.
435 * Each page is written separately in chunks with a maximum size of chunksize.
436 */
Stuart Langley60395ef2020-03-25 20:32:45 +1100437int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start,
438 int unsigned len)
hailfinger80dea312010-01-09 03:15:50 +0000439{
stefanctc5eb8a92011-11-23 09:13:48 +0000440 unsigned int i, starthere, lenhere;
hailfinger86bf3b52010-10-13 21:49:30 +0000441 /* FIXME: page_size is the wrong variable. We need max_writechunk_size
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700442 * in struct flashctx to do this properly. All chips using
hailfinger86bf3b52010-10-13 21:49:30 +0000443 * write_jedec have page_size set to max_writechunk_size, so
444 * we're OK for now.
445 */
Patrick Georgif3fa2992017-02-02 16:24:44 +0100446 unsigned int page_size = flash->chip->page_size;
ollie5b621572004-03-20 16:46:10 +0000447
hailfinger86bf3b52010-10-13 21:49:30 +0000448 /* Warning: This loop has a very unusual condition and body.
449 * The loop needs to go through each page with at least one affected
450 * byte. The lowest page number is (start / page_size) since that
451 * division rounds down. The highest page number we want is the page
452 * where the last byte of the range lives. That last byte has the
453 * address (start + len - 1), thus the highest page number is
454 * (start + len - 1) / page_size. Since we want to include that last
455 * page as well, the loop condition uses <=.
456 */
457 for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
458 /* Byte position of the first byte in the range in this page. */
459 /* starthere is an offset to the base address of the chip. */
460 starthere = max(start, i * page_size);
461 /* Length of bytes in the range in this page. */
462 lenhere = min(start + len, (i + 1) * page_size) - starthere;
snelsonc6855342010-01-28 23:55:12 +0000463
hailfinger86bf3b52010-10-13 21:49:30 +0000464 if (write_page_write_jedec_common(flash, buf + starthere - start, starthere, lenhere))
465 return 1;
rminnich8d3ff912003-10-25 17:01:29 +0000466 }
rminnich8d3ff912003-10-25 17:01:29 +0000467
hailfinger86bf3b52010-10-13 21:49:30 +0000468 return 0;
rminnich8d3ff912003-10-25 17:01:29 +0000469}
hailfingerfff99532009-11-27 17:49:42 +0000470
snelson63133f92010-01-04 17:15:23 +0000471/* erase chip with block_erase() prototype */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700472int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr,
snelson63133f92010-01-04 17:15:23 +0000473 unsigned int blocksize)
474{
stefanctc5eb8a92011-11-23 09:13:48 +0000475 unsigned int mask;
snelsonc6855342010-01-28 23:55:12 +0000476
Stuart Langley60395ef2020-03-25 20:32:45 +1100477 mask = getaddrmask(flash->chip);
Patrick Georgif3fa2992017-02-02 16:24:44 +0100478 if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
snelsonfc007bb2010-03-24 23:14:32 +0000479 msg_cerr("%s called with incorrect arguments\n",
snelson63133f92010-01-04 17:15:23 +0000480 __func__);
481 return -1;
482 }
snelsonc6855342010-01-28 23:55:12 +0000483 return erase_chip_jedec_common(flash, mask);
snelson63133f92010-01-04 17:15:23 +0000484}
485
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700486int probe_jedec(struct flashctx *flash)
snelson63133f92010-01-04 17:15:23 +0000487{
stefanctc5eb8a92011-11-23 09:13:48 +0000488 unsigned int mask;
hailfinger80dea312010-01-09 03:15:50 +0000489
Stuart Langley60395ef2020-03-25 20:32:45 +1100490 mask = getaddrmask(flash->chip);
snelsonc6855342010-01-28 23:55:12 +0000491 return probe_jedec_common(flash, mask);
snelson63133f92010-01-04 17:15:23 +0000492}
493
Stuart Langley60395ef2020-03-25 20:32:45 +1100494int erase_sector_jedec(struct flashctx *flash, unsigned int page,
495 unsigned int size)
snelson63133f92010-01-04 17:15:23 +0000496{
stefanctc5eb8a92011-11-23 09:13:48 +0000497 unsigned int mask;
snelsonc6855342010-01-28 23:55:12 +0000498
Stuart Langley60395ef2020-03-25 20:32:45 +1100499 mask = getaddrmask(flash->chip);
snelsonc6855342010-01-28 23:55:12 +0000500 return erase_sector_jedec_common(flash, page, size, mask);
snelson63133f92010-01-04 17:15:23 +0000501}
502
Stuart Langley60395ef2020-03-25 20:32:45 +1100503int erase_block_jedec(struct flashctx *flash, unsigned int page,
504 unsigned int size)
snelson63133f92010-01-04 17:15:23 +0000505{
stefanctc5eb8a92011-11-23 09:13:48 +0000506 unsigned int mask;
snelsonc6855342010-01-28 23:55:12 +0000507
Stuart Langley60395ef2020-03-25 20:32:45 +1100508 mask = getaddrmask(flash->chip);
snelsonc6855342010-01-28 23:55:12 +0000509 return erase_block_jedec_common(flash, page, size, mask);
snelson63133f92010-01-04 17:15:23 +0000510}
511
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700512int erase_chip_jedec(struct flashctx *flash)
snelson63133f92010-01-04 17:15:23 +0000513{
stefanctc5eb8a92011-11-23 09:13:48 +0000514 unsigned int mask;
snelsonc6855342010-01-28 23:55:12 +0000515
Stuart Langley60395ef2020-03-25 20:32:45 +1100516 mask = getaddrmask(flash->chip);
snelsonc6855342010-01-28 23:55:12 +0000517 return erase_chip_jedec_common(flash, mask);
snelson63133f92010-01-04 17:15:23 +0000518}
Alan Greend793f5b2019-09-02 17:03:51 +1000519
520struct unlockblock {
521 unsigned int size;
522 unsigned int count;
523};
524
525typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset);
526static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func)
527{
528 chipaddr off = flash->virtual_registers + 2;
529 while (block->count != 0) {
530 unsigned int j;
531 for (j = 0; j < block->count; j++) {
532 if (func(flash, off))
533 return -1;
534 off += block->size;
535 }
536 block++;
537 }
538 return 0;
539}
540
541#define REG2_RWLOCK ((1 << 2) | (1 << 0))
542#define REG2_LOCKDOWN (1 << 1)
543#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN)
544
545static int printlock_regspace2_block(const struct flashctx *flash, chipaddr lockreg)
546{
547 uint8_t state = chip_readb(flash, lockreg);
Stuart Langley60395ef2020-03-25 20:32:45 +1100548 msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, lockreg);
Alan Greend793f5b2019-09-02 17:03:51 +1000549 switch (state & REG2_MASK) {
550 case 0:
551 msg_cdbg("Full Access.\n");
552 break;
553 case 1:
554 msg_cdbg("Write Lock (Default State).\n");
555 break;
556 case 2:
557 msg_cdbg("Locked Open (Full Access, Locked Down).\n");
558 break;
559 case 3:
560 msg_cdbg("Write Lock, Locked Down.\n");
561 break;
562 case 4:
563 msg_cdbg("Read Lock.\n");
564 break;
565 case 5:
566 msg_cdbg("Read/Write Lock.\n");
567 break;
568 case 6:
569 msg_cdbg("Read Lock, Locked Down.\n");
570 break;
571 case 7:
572 msg_cdbg("Read/Write Lock, Locked Down.\n");
573 break;
574 }
575 return 0;
576}
577
578static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
579{
580 const unsigned int elems = flash->chip->total_size * 1024 / block_size;
581 struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
582 return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block);
583}
584
585int printlock_regspace2_uniform_64k(struct flashctx *flash)
586{
587 return printlock_regspace2_uniform(flash, 64 * 1024);
588}
589
590int printlock_regspace2_block_eraser_0(struct flashctx *flash)
591{
592 // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
593 const struct unlockblock *unlockblocks =
594 (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
595 return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
596}
597
598int printlock_regspace2_block_eraser_1(struct flashctx *flash)
599{
600 // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
601 const struct unlockblock *unlockblocks =
602 (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
603 return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
604}
605
606/* Try to change the lock register at address lockreg from cur to new.
607 *
608 * - Try to unlock the lock bit if requested and it is currently set (although this is probably futile).
609 * - Try to change the read/write bits if requested.
610 * - Try to set the lockdown bit if requested.
611 * Return an error immediately if any of this fails. */
612static int changelock_regspace2_block(const struct flashctx *flash, chipaddr lockreg, uint8_t cur, uint8_t new)
613{
614 /* Only allow changes to known read/write/lockdown bits */
615 if (((cur ^ new) & ~REG2_MASK) != 0) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100616 msg_cerr("Invalid lock change from 0x%02x to 0x%02x requested at 0x%0*" PRIxPTR "!\n"
Alan Greend793f5b2019-09-02 17:03:51 +1000617 "Please report a bug at flashrom@flashrom.org\n",
Stuart Langley60395ef2020-03-25 20:32:45 +1100618 cur, new, PRIxPTR_WIDTH, lockreg);
Alan Greend793f5b2019-09-02 17:03:51 +1000619 return -1;
620 }
621
622 /* Exit early if no change (of read/write/lockdown bits) was requested. */
623 if (((cur ^ new) & REG2_MASK) == 0) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100624 msg_cdbg2("Lock bits at 0x%0*" PRIxPTR " not changed.\n", PRIxPTR_WIDTH, lockreg);
Alan Greend793f5b2019-09-02 17:03:51 +1000625 return 0;
626 }
627
628 /* Normally the lockdown bit can not be cleared. Try nevertheless if requested. */
629 if ((cur & REG2_LOCKDOWN) && !(new & REG2_LOCKDOWN)) {
630 chip_writeb(flash, cur & ~REG2_LOCKDOWN, lockreg);
631 cur = chip_readb(flash, lockreg);
632 if ((cur & REG2_LOCKDOWN) == REG2_LOCKDOWN) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100633 msg_cwarn("Lockdown can't be removed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
634 PRIxPTR_WIDTH, lockreg, cur);
Alan Greend793f5b2019-09-02 17:03:51 +1000635 return -1;
636 }
637 }
638
639 /* Change read and/or write bit */
640 if ((cur ^ new) & REG2_RWLOCK) {
641 /* Do not lockdown yet. */
642 uint8_t wanted = (cur & ~REG2_RWLOCK) | (new & REG2_RWLOCK);
643 chip_writeb(flash, wanted, lockreg);
644 cur = chip_readb(flash, lockreg);
645 if (cur != wanted) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100646 msg_cerr("Changing lock bits failed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
647 PRIxPTR_WIDTH, lockreg, cur);
Alan Greend793f5b2019-09-02 17:03:51 +1000648 return -1;
649 }
Stuart Langley60395ef2020-03-25 20:32:45 +1100650 msg_cdbg("Changed lock bits at 0x%0*" PRIxPTR " to 0x%02x.\n",
651 PRIxPTR_WIDTH, lockreg, cur);
Alan Greend793f5b2019-09-02 17:03:51 +1000652 }
653
654 /* Eventually, enable lockdown if requested. */
655 if (!(cur & REG2_LOCKDOWN) && (new & REG2_LOCKDOWN)) {
656 chip_writeb(flash, new, lockreg);
657 cur = chip_readb(flash, lockreg);
658 if (cur != new) {
Stuart Langley60395ef2020-03-25 20:32:45 +1100659 msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
660 PRIxPTR_WIDTH, lockreg, cur);
Alan Greend793f5b2019-09-02 17:03:51 +1000661 return -1;
662 }
Stuart Langley60395ef2020-03-25 20:32:45 +1100663 msg_cdbg("Enabled lockdown at 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, lockreg);
Alan Greend793f5b2019-09-02 17:03:51 +1000664 }
665
666 return 0;
667}
668
669static int unlock_regspace2_block_generic(const struct flashctx *flash, chipaddr lockreg)
670{
671 uint8_t old = chip_readb(flash, lockreg);
672 /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */
673 return changelock_regspace2_block(flash, lockreg, old, old & ~REG2_RWLOCK);
674}
675
676static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
677{
678 const unsigned int elems = flash->chip->total_size * 1024 / block_size;
679 struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
680 return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block_generic);
681}
682
683int unlock_regspace2_uniform_64k(struct flashctx *flash)
684{
685 return unlock_regspace2_uniform(flash, 64 * 1024);
686}
687
688int unlock_regspace2_uniform_32k(struct flashctx *flash)
689{
690 return unlock_regspace2_uniform(flash, 32 * 1024);
691}
692
693int unlock_regspace2_block_eraser_0(struct flashctx *flash)
694{
695 // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
696 const struct unlockblock *unlockblocks =
697 (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
698 return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
699}
700
701int unlock_regspace2_block_eraser_1(struct flashctx *flash)
702{
703 // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
704 const struct unlockblock *unlockblocks =
705 (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
706 return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
707}