blob: 778a822f5f091c29be08bfff62235a63f83c8a4a [file] [log] [blame]
Sean Nelson14ba6682010-02-26 05:48:29 +00001/*
2 * This file is part of the flashrom project.
3 *
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +00004 * Copyright (C) 2007, 2008, 2009, 2010 Carl-Daniel Hailfinger
Sean Nelson14ba6682010-02-26 05:48:29 +00005 * Copyright (C) 2008 coresystems GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Sean Nelson14ba6682010-02-26 05:48:29 +000015 */
16
17/*
18 * Contains the common SPI chip driver functions
19 */
20
Nico Hubera3140d02017-10-15 11:20:58 +020021#include <stddef.h>
Sean Nelson14ba6682010-02-26 05:48:29 +000022#include <string.h>
Nico Hubera1672f82017-10-14 18:00:20 +020023#include <stdbool.h>
Sean Nelson14ba6682010-02-26 05:48:29 +000024#include "flash.h"
25#include "flashchips.h"
26#include "chipdrivers.h"
Nico Huberfbc41d22026-02-22 23:04:01 +010027#include "chipdrivers/spi.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000028#include "programmer.h"
Nico Huberd5185632024-01-05 18:44:41 +010029#include "spi_command.h"
Sean Nelson14ba6682010-02-26 05:48:29 +000030#include "spi.h"
31
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000032static int spi_rdid(struct flashctx *flash, unsigned char *readarr, int bytes)
Sean Nelson14ba6682010-02-26 05:48:29 +000033{
Mathias Krausea60faab2011-01-17 07:50:42 +000034 static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
Sean Nelson14ba6682010-02-26 05:48:29 +000035 int ret;
36 int i;
37
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000038 ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000039 if (ret)
40 return ret;
Sean Nelsoned479d22010-03-24 23:14:32 +000041 msg_cspew("RDID returned");
Sean Nelson14ba6682010-02-26 05:48:29 +000042 for (i = 0; i < bytes; i++)
Sean Nelsoned479d22010-03-24 23:14:32 +000043 msg_cspew(" 0x%02x", readarr[i]);
44 msg_cspew(". ");
Sean Nelson14ba6682010-02-26 05:48:29 +000045 return 0;
46}
47
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000048static int spi_rems(struct flashctx *flash, unsigned char *readarr)
Sean Nelson14ba6682010-02-26 05:48:29 +000049{
Nico Hubered098d62017-04-21 23:47:08 +020050 static const unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, };
Sean Nelson14ba6682010-02-26 05:48:29 +000051 int ret;
52
Nico Hubered098d62017-04-21 23:47:08 +020053 ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000054 if (ret)
55 return ret;
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +000056 msg_cspew("REMS returned 0x%02x 0x%02x. ", readarr[0], readarr[1]);
Sean Nelson14ba6682010-02-26 05:48:29 +000057 return 0;
58}
59
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000060static int spi_res(struct flashctx *flash, unsigned char *readarr, int bytes)
Sean Nelson14ba6682010-02-26 05:48:29 +000061{
Nico Hubered098d62017-04-21 23:47:08 +020062 static const unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, };
Sean Nelson14ba6682010-02-26 05:48:29 +000063 int ret;
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +000064 int i;
Sean Nelson14ba6682010-02-26 05:48:29 +000065
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000066 ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000067 if (ret)
68 return ret;
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +000069 msg_cspew("RES returned");
70 for (i = 0; i < bytes; i++)
71 msg_cspew(" 0x%02x", readarr[i]);
72 msg_cspew(". ");
Sean Nelson14ba6682010-02-26 05:48:29 +000073 return 0;
74}
75
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000076int spi_write_enable(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +000077{
Mathias Krausea60faab2011-01-17 07:50:42 +000078 static const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
Sean Nelson14ba6682010-02-26 05:48:29 +000079 int result;
80
81 /* Send WREN (Write Enable) */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000082 result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
Sean Nelson14ba6682010-02-26 05:48:29 +000083
84 if (result)
Sean Nelsoned479d22010-03-24 23:14:32 +000085 msg_cerr("%s failed\n", __func__);
Sean Nelson14ba6682010-02-26 05:48:29 +000086
87 return result;
88}
89
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000090int spi_write_disable(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +000091{
Mathias Krausea60faab2011-01-17 07:50:42 +000092 static const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
Sean Nelson14ba6682010-02-26 05:48:29 +000093
94 /* Send WRDI (Write Disable) */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000095 return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
Sean Nelson14ba6682010-02-26 05:48:29 +000096}
97
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +000098static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
Sean Nelson14ba6682010-02-26 05:48:29 +000099{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000100 const struct flashchip *chip = flash->chip;
Sean Nelson14ba6682010-02-26 05:48:29 +0000101 unsigned char readarr[4];
102 uint32_t id1;
103 uint32_t id2;
104
Nico Huber959aafa2017-04-22 00:13:15 +0200105 const int ret = spi_rdid(flash, readarr, bytes);
106 if (ret == SPI_INVALID_LENGTH)
107 msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes);
108 if (ret)
Sean Nelson14ba6682010-02-26 05:48:29 +0000109 return 0;
110
111 if (!oddparity(readarr[0]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000112 msg_cdbg("RDID byte 0 parity violation. ");
Sean Nelson14ba6682010-02-26 05:48:29 +0000113
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +0000114 /* Check if this is a continuation vendor ID.
115 * FIXME: Handle continuation device IDs.
116 */
Sean Nelson14ba6682010-02-26 05:48:29 +0000117 if (readarr[0] == 0x7f) {
118 if (!oddparity(readarr[1]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000119 msg_cdbg("RDID byte 1 parity violation. ");
Sean Nelson14ba6682010-02-26 05:48:29 +0000120 id1 = (readarr[0] << 8) | readarr[1];
121 id2 = readarr[2];
122 if (bytes > 3) {
123 id2 <<= 8;
124 id2 |= readarr[3];
125 }
126 } else {
127 id1 = readarr[0];
128 id2 = (readarr[1] << 8) | readarr[2];
129 }
130
Sean Nelsoned479d22010-03-24 23:14:32 +0000131 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000132
Nico Huber11136c22023-05-01 12:00:09 +0200133 if (id1 == chip->id.manufacture && id2 == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000134 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000135
136 /* Test if this is a pure vendor match. */
Nico Huber11136c22023-05-01 12:00:09 +0200137 if (id1 == chip->id.manufacture && GENERIC_DEVICE_ID == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000138 return 1;
139
140 /* Test if there is any vendor ID. */
Nico Huber11136c22023-05-01 12:00:09 +0200141 if (GENERIC_MANUF_ID == chip->id.manufacture && id1 != 0xff && id1 != 0x00)
Sean Nelson14ba6682010-02-26 05:48:29 +0000142 return 1;
143
144 return 0;
145}
146
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000147int probe_spi_rdid(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000148{
149 return probe_spi_rdid_generic(flash, 3);
150}
151
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000152int probe_spi_rdid4(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000153{
Nico Huber959aafa2017-04-22 00:13:15 +0200154 return probe_spi_rdid_generic(flash, 4);
Sean Nelson14ba6682010-02-26 05:48:29 +0000155}
156
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000157int probe_spi_rems(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000158{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000159 const struct flashchip *chip = flash->chip;
Sean Nelson14ba6682010-02-26 05:48:29 +0000160 unsigned char readarr[JEDEC_REMS_INSIZE];
161 uint32_t id1, id2;
162
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000163 if (spi_rems(flash, readarr)) {
Sean Nelson14ba6682010-02-26 05:48:29 +0000164 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000165 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000166
167 id1 = readarr[0];
168 id2 = readarr[1];
169
Sean Nelsoned479d22010-03-24 23:14:32 +0000170 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000171
Nico Huber11136c22023-05-01 12:00:09 +0200172 if (id1 == chip->id.manufacture && id2 == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000173 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000174
175 /* Test if this is a pure vendor match. */
Nico Huber11136c22023-05-01 12:00:09 +0200176 if (id1 == chip->id.manufacture && GENERIC_DEVICE_ID == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000177 return 1;
178
179 /* Test if there is any vendor ID. */
Nico Huber11136c22023-05-01 12:00:09 +0200180 if (GENERIC_MANUF_ID == chip->id.manufacture && id1 != 0xff && id1 != 0x00)
Sean Nelson14ba6682010-02-26 05:48:29 +0000181 return 1;
182
183 return 0;
184}
185
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000186int probe_spi_res1(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000187{
Mathias Krausea60faab2011-01-17 07:50:42 +0000188 static const unsigned char allff[] = {0xff, 0xff, 0xff};
189 static const unsigned char all00[] = {0x00, 0x00, 0x00};
Sean Nelson14ba6682010-02-26 05:48:29 +0000190 unsigned char readarr[3];
191 uint32_t id2;
Sean Nelson14ba6682010-02-26 05:48:29 +0000192
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000193 /* We only want one-byte RES if RDID and REMS are unusable. */
194
Sean Nelson14ba6682010-02-26 05:48:29 +0000195 /* Check if RDID is usable and does not return 0xff 0xff 0xff or
196 * 0x00 0x00 0x00. In that case, RES is pointless.
197 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000198 if (!spi_rdid(flash, readarr, 3) && memcmp(readarr, allff, 3) &&
Sean Nelson14ba6682010-02-26 05:48:29 +0000199 memcmp(readarr, all00, 3)) {
200 msg_cdbg("Ignoring RES in favour of RDID.\n");
201 return 0;
202 }
203 /* Check if REMS is usable and does not return 0xff 0xff or
204 * 0x00 0x00. In that case, RES is pointless.
205 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000206 if (!spi_rems(flash, readarr) &&
207 memcmp(readarr, allff, JEDEC_REMS_INSIZE) &&
Sean Nelson14ba6682010-02-26 05:48:29 +0000208 memcmp(readarr, all00, JEDEC_REMS_INSIZE)) {
209 msg_cdbg("Ignoring RES in favour of REMS.\n");
210 return 0;
211 }
212
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000213 if (spi_res(flash, readarr, 1)) {
Sean Nelson14ba6682010-02-26 05:48:29 +0000214 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000215 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000216
Sean Nelson14ba6682010-02-26 05:48:29 +0000217 id2 = readarr[0];
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000218
Sean Nelsoned479d22010-03-24 23:14:32 +0000219 msg_cdbg("%s: id 0x%x\n", __func__, id2);
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000220
Nico Huber11136c22023-05-01 12:00:09 +0200221 if (id2 != flash->chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000222 return 0;
223
Sean Nelson14ba6682010-02-26 05:48:29 +0000224 return 1;
225}
226
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000227int probe_spi_res2(struct flashctx *flash)
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000228{
229 unsigned char readarr[2];
230 uint32_t id1, id2;
231
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000232 if (spi_res(flash, readarr, 2)) {
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000233 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000234 }
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000235
236 id1 = readarr[0];
237 id2 = readarr[1];
238
239 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
240
Nico Huber11136c22023-05-01 12:00:09 +0200241 if (id1 != flash->chip->id.manufacture || id2 != flash->chip->id.model)
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000242 return 0;
243
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000244 return 1;
245}
246
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000247int probe_spi_res3(struct flashctx *flash)
248{
249 unsigned char readarr[3];
250 uint32_t id1, id2;
251
252 if (spi_res(flash, readarr, 3)) {
253 return 0;
254 }
255
256 id1 = (readarr[0] << 8) | readarr[1];
257 id2 = readarr[2];
258
259 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
260
Nico Huber11136c22023-05-01 12:00:09 +0200261 if (id1 != flash->chip->id.manufacture || id2 != flash->chip->id.model)
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000262 return 0;
263
264 return 1;
265}
266
Stefan Tauner57794ac2012-12-29 15:04:20 +0000267/* Only used for some Atmel chips. */
268int probe_spi_at25f(struct flashctx *flash)
269{
270 static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
271 unsigned char readarr[AT25F_RDID_INSIZE];
272 uint32_t id1;
273 uint32_t id2;
274
275 if (spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr))
276 return 0;
277
278 id1 = readarr[0];
279 id2 = readarr[1];
280
281 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
282
Nico Huber11136c22023-05-01 12:00:09 +0200283 if (id1 == flash->chip->id.manufacture && id2 == flash->chip->id.model)
Stefan Tauner57794ac2012-12-29 15:04:20 +0000284 return 1;
285
286 return 0;
287}
288
Nico Huber0ecbacb2017-10-14 16:50:43 +0200289static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
290{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200291 /* FIXME: We don't time out. */
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100292 while (true) {
293 uint8_t status;
294 int ret = spi_read_register(flash, STATUS1, &status);
295 if (ret)
296 return ret;
297 if (!(status & SPI_SR_WIP))
298 return 0;
299
Nico Huber0ecbacb2017-10-14 16:50:43 +0200300 programmer_delay(poll_delay);
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100301 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200302}
303
Nico Hubera3140d02017-10-15 11:20:58 +0200304/**
305 * Execute WREN plus another one byte `op`, optionally poll WIP afterwards.
306 *
307 * @param flash the flash chip's context
308 * @param op the operation to execute
309 * @param poll_delay interval in us for polling WIP, don't poll if zero
310 * @return 0 on success, non-zero otherwise
311 */
Nico Huber8d0f4652024-05-04 18:52:51 +0200312int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, const unsigned int poll_delay)
Sean Nelson14ba6682010-02-26 05:48:29 +0000313{
Sean Nelson14ba6682010-02-26 05:48:29 +0000314 struct spi_command cmds[] = {
315 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200316 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000317 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100318 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200319 .writearr = (const unsigned char[]){ JEDEC_WREN },
Sean Nelson14ba6682010-02-26 05:48:29 +0000320 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200321 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000322 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100323 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200324 .writearr = (const unsigned char[]){ op },
325 },
326 NULL_SPI_CMD,
327 };
328
329 const int result = spi_send_multicommand(flash, cmds);
330 if (result)
331 msg_cerr("%s failed during command execution\n", __func__);
332
Nico Huber0ecbacb2017-10-14 16:50:43 +0200333 const int status = poll_delay ? spi_poll_wip(flash, poll_delay) : 0;
Nico Hubera3140d02017-10-15 11:20:58 +0200334
Nico Huber0ecbacb2017-10-14 16:50:43 +0200335 return result ? result : status;
336}
337
Nico Huber7e3c81a2017-10-14 18:56:50 +0200338static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
339{
Nico Huber9bb8a322022-05-24 15:07:34 +0200340 uint8_t op;
341 if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
342 op = JEDEC_WRITE_EXT_ADDR_REG;
343 } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
344 op = ALT_WRITE_EXT_ADDR_REG_17;
345 } else {
346 msg_cerr("Flash misses feature flag for extended-address register.\n");
347 return -1;
348 }
349
Nico Huber7e3c81a2017-10-14 18:56:50 +0200350 struct spi_command cmds[] = {
351 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200352 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000353 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100354 .opcode_len = 1,
Nico Huber7e3c81a2017-10-14 18:56:50 +0200355 .writearr = (const unsigned char[]){ JEDEC_WREN },
356 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200357 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000358 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100359 .opcode_len = 1,
360 .write_len = 1,
Nico Huber57dbd642018-03-13 18:01:05 +0100361 .writearr = (const unsigned char[]){ op, regdata },
Nico Huber7e3c81a2017-10-14 18:56:50 +0200362 },
363 NULL_SPI_CMD,
364 };
365
366 const int result = spi_send_multicommand(flash, cmds);
367 if (result)
368 msg_cerr("%s failed during command execution\n", __func__);
369 return result;
370}
371
Nico Huber7eb38aa2019-03-21 15:42:54 +0100372int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
Nico Huberf43c6542017-10-14 17:47:28 +0200373{
374 if (flash->address_high_byte != addr_high &&
375 spi_write_extended_address_register(flash, addr_high))
376 return -1;
377 flash->address_high_byte = addr_high;
378 return 0;
379}
380
Nico Huber4e6155a2025-01-02 23:05:09 +0100381static size_t spi_address_length(struct flashctx *const flash, const bool native_4ba)
382{
383 if (flash->chip->spi_cmd_set == SPI25_EEPROM) {
384 if (flashprog_flash_getsize(flash) > 64*KiB)
385 return 3;
386 if (flashprog_flash_getsize(flash) > 256)
387 return 2;
388 return 1;
389 }
390
391 if (native_4ba || flash->in_4ba_mode)
392 return 4;
393
394 return 3;
395}
396
Nico Hubera1672f82017-10-14 18:00:20 +0200397static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
Nico Hubere3f648c2023-02-15 02:55:23 +0100398 const bool native_4ba, const unsigned int rel_addr)
Nico Huber0ecbacb2017-10-14 16:50:43 +0200399{
Nico Huber4e6155a2025-01-02 23:05:09 +0100400 const size_t len = spi_address_length(flash, native_4ba);
Nico Hubere3f648c2023-02-15 02:55:23 +0100401 unsigned int addr = rel_addr;
402
403 if (spi_master_top_aligned(flash))
404 addr = rel_addr - flashprog_flash_getsize(flash); /* intentional integer underflow */
Nico Huber4e6155a2025-01-02 23:05:09 +0100405
406 switch (len) {
407 case 4:
Nico Huber1cf407b2017-11-10 20:18:23 +0100408 if (!spi_master_4ba(flash)) {
409 msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n");
410 return -1;
411 }
Nico Huberf43c6542017-10-14 17:47:28 +0200412 cmd_buf[1] = (addr >> 24) & 0xff;
413 cmd_buf[2] = (addr >> 16) & 0xff;
414 cmd_buf[3] = (addr >> 8) & 0xff;
415 cmd_buf[4] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100416 return len;
417 case 3:
Nico Huber9bb8a322022-05-24 15:07:34 +0200418 if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
Nico Hubere3f648c2023-02-15 02:55:23 +0100419 if (spi_set_extended_address(flash, rel_addr >> 24))
Nico Huberf43c6542017-10-14 17:47:28 +0200420 return -1;
Nico Hubere3f648c2023-02-15 02:55:23 +0100421 } else if (rel_addr >> 24) {
Nico Huber1cf407b2017-11-10 20:18:23 +0100422 msg_cerr("Can't handle 4-byte address for opcode '0x%02x'\n"
423 "with this chip/programmer combination.\n", cmd_buf[0]);
424 return -1;
Nico Huberf43c6542017-10-14 17:47:28 +0200425 }
426 cmd_buf[1] = (addr >> 16) & 0xff;
427 cmd_buf[2] = (addr >> 8) & 0xff;
428 cmd_buf[3] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100429 return len;
430 case 2:
431 cmd_buf[1] = (addr >> 8) & 0xff;
432 cmd_buf[2] = (addr >> 0) & 0xff;
433 return len;
434 default:
435 cmd_buf[1] = addr & 0xff;
436 return len;
Nico Huberf43c6542017-10-14 17:47:28 +0200437 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200438}
439
440/**
441 * Execute WREN plus another `op` that takes an address and
442 * optional data, poll WIP afterwards.
443 *
444 * @param flash the flash chip's context
445 * @param op the operation to execute
Nico Hubera1672f82017-10-14 18:00:20 +0200446 * @param native_4ba whether `op` always takes a 4-byte address
Nico Huber0ecbacb2017-10-14 16:50:43 +0200447 * @param addr the address parameter to `op`
448 * @param out_bytes bytes to send after the address,
449 * may be NULL if and only if `out_bytes` is 0
450 * @param out_bytes number of bytes to send, 256 at most, may be zero
451 * @param poll_delay interval in us for polling WIP
452 * @return 0 on success, non-zero otherwise
453 */
Nico Hubera1672f82017-10-14 18:00:20 +0200454static int spi_write_cmd(struct flashctx *const flash, const uint8_t op,
455 const bool native_4ba, const unsigned int addr,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200456 const uint8_t *const out_bytes, const size_t out_len,
457 const unsigned int poll_delay)
458{
459 uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN + 256];
460 struct spi_command cmds[] = {
461 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200462 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000463 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100464 .opcode_len = 1,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200465 .writearr = (const unsigned char[]){ JEDEC_WREN },
466 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200467 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000468 .readarr = 0,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200469 .writearr = cmd,
470 },
471 NULL_SPI_CMD,
472 };
473
474 cmd[0] = op;
Nico Hubera1672f82017-10-14 18:00:20 +0200475 const int addr_len = spi_prepare_address(flash, cmd, native_4ba, addr);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200476 if (addr_len < 0)
477 return 1;
478
479 if (1 + addr_len + out_len > sizeof(cmd)) {
480 msg_cerr("%s called for too long a write\n", __func__);
481 return 1;
482 }
Angel Ponsc92f6872020-03-31 15:32:10 +0200483 if (!out_bytes && out_len > 0)
484 return 1;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200485
486 memcpy(cmd + 1 + addr_len, out_bytes, out_len);
Nico Huberd5185632024-01-05 18:44:41 +0100487 cmds[1].opcode_len = 1;
488 cmds[1].address_len = addr_len;
489 cmds[1].write_len = out_len;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200490
491 const int result = spi_send_multicommand(flash, cmds);
492 if (result)
493 msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
494
495 const int status = spi_poll_wip(flash, poll_delay);
496
497 return result ? result : status;
Nico Hubera3140d02017-10-15 11:20:58 +0200498}
499
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600500static int spi_chip_erase_60(struct flashctx *flash)
Nico Hubera3140d02017-10-15 11:20:58 +0200501{
502 /* This usually takes 1-85s, so wait in 1s steps. */
503 return spi_simple_write_cmd(flash, 0x60, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000504}
505
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600506static int spi_chip_erase_62(struct flashctx *flash)
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000507{
Nico Hubera3140d02017-10-15 11:20:58 +0200508 /* This usually takes 2-5s, so wait in 100ms steps. */
509 return spi_simple_write_cmd(flash, 0x62, 100 * 1000);
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000510}
511
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600512static int spi_chip_erase_c7(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000513{
Nico Hubera3140d02017-10-15 11:20:58 +0200514 /* This usually takes 1-85s, so wait in 1s steps. */
515 return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000516}
517
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000518int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
519 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000520{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200521 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200522 return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000523}
524
525/* Block size is usually
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000526 * 32M (one die) for Micron
527 */
528int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
529{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200530 /* This usually takes 240-480s, so wait in 500ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200531 return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000);
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000532}
533
534/* Block size is usually
Sean Nelson14ba6682010-02-26 05:48:29 +0000535 * 64k for Macronix
536 * 32k for SST
537 * 4-32k non-uniform for EON
538 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000539int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
540 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000541{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200542 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200543 return spi_write_cmd(flash, 0xd8, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000544}
545
546/* Block size is usually
547 * 4k for PMC
548 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000549int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
550 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000551{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200552 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200553 return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000554}
555
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000556/* Page erase (usually 256B blocks) */
557int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
558{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200559 /* This takes up to 20ms usually (on worn out devices
560 up to the 0.5s range), so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200561 return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000562}
563
Sean Nelson14ba6682010-02-26 05:48:29 +0000564/* Sector size is usually 4k, though Macronix eliteflash has 64k */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000565int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
566 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000567{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200568 /* This usually takes 15-800ms, so wait in 10ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200569 return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000570}
571
Stefan Tauner94b39b42012-10-27 00:06:02 +0000572int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
573{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200574 /* This usually takes 10ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200575 return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000576}
577
578int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
579{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200580 /* This usually takes 8ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200581 return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000582}
583
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000584int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
585 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000586{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000587 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000588 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000589 __func__);
590 return -1;
591 }
592 return spi_chip_erase_60(flash);
593}
594
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000595int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
596{
597 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
598 msg_cerr("%s called with incorrect arguments\n",
599 __func__);
600 return -1;
601 }
602 return spi_chip_erase_62(flash);
603}
604
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000605int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
606 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000607{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000608 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000609 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000610 __func__);
611 return -1;
612 }
613 return spi_chip_erase_c7(flash);
614}
615
Nico Huber7e3c81a2017-10-14 18:56:50 +0200616/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
617int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
618{
619 /* This usually takes 15-800ms, so wait in 10ms steps. */
620 return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
621}
622
623/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huberfffc48d2022-05-28 14:26:06 +0200624int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
625{
626 /* This usually takes 100-4000ms, so wait in 100ms steps. */
627 return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
628}
629
630/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huber7e3c81a2017-10-14 18:56:50 +0200631int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
632{
633 /* This usually takes 100-4000ms, so wait in 100ms steps. */
634 return spi_write_cmd(flash, 0x5c, true, addr, NULL, 0, 100 * 1000);
635}
636
637/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
638int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
639{
640 /* This usually takes 100-4000ms, so wait in 100ms steps. */
641 return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000);
642}
643
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530644static const struct {
645 erasefunc_t *func;
646 uint8_t opcode;
Thomas Heijligen35614512022-09-19 23:46:58 +0200647} spi25_function_opcode_list[] = {
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530648 {&spi_block_erase_20, 0x20},
649 {&spi_block_erase_21, 0x21},
650 {&spi_block_erase_50, 0x50},
651 {&spi_block_erase_52, 0x52},
652 {&spi_block_erase_53, 0x53},
653 {&spi_block_erase_5c, 0x5c},
654 {&spi_block_erase_60, 0x60},
655 {&spi_block_erase_62, 0x62},
656 {&spi_block_erase_81, 0x81},
657 {&spi_block_erase_c4, 0xc4},
658 {&spi_block_erase_c7, 0xc7},
659 {&spi_block_erase_d7, 0xd7},
660 {&spi_block_erase_d8, 0xd8},
661 {&spi_block_erase_db, 0xdb},
662 {&spi_block_erase_dc, 0xdc},
663};
664
Thomas Heijligen35614512022-09-19 23:46:58 +0200665erasefunc_t *spi25_get_erasefn_from_opcode(uint8_t opcode)
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000666{
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530667 size_t i;
Thomas Heijligen35614512022-09-19 23:46:58 +0200668 for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
669 if (spi25_function_opcode_list[i].opcode == opcode)
670 return spi25_function_opcode_list[i].func;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000671 }
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530672 msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
Nico Huberc3b02dc2023-08-12 01:13:45 +0200673 "this at flashprog@flashprog.org\n", __func__, opcode);
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530674 return NULL;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000675}
676
Nico Huber0ecbacb2017-10-14 16:50:43 +0200677static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000678{
Nico Huber1cf407b2017-11-10 20:18:23 +0100679 const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash);
Nico Hubera1672f82017-10-14 18:00:20 +0200680 const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM;
681 return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10);
Sean Nelson14ba6682010-02-26 05:48:29 +0000682}
683
Nico Hubera1b7f352024-03-25 18:32:11 +0100684const struct spi_read_op *get_spi_read_op(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100685{
686 static const struct spi_read_op sio_read = { SINGLE_IO_1_1_1, false, JEDEC_READ, 0x00, 0 };
687 static const struct spi_read_op sio_read_4ba = { SINGLE_IO_1_1_1, true, JEDEC_READ_4BA, 0x00, 0 };
688
689 if (flash->spi_fast_read)
690 return flash->spi_fast_read;
691
692 if (flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash))
693 return &sio_read_4ba;
694
695 return &sio_read;
696}
697
Nico Huberca1c7fd2023-04-28 21:44:41 +0000698int spi_nbyte_read(struct flashctx *flash, uint8_t *dst, unsigned int address, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000699{
Nico Huber4760b6e2024-01-06 23:45:28 +0100700 const struct spi_read_op *const read_op = get_spi_read_op(flash);
701 const size_t mode_len = read_op->mode_byte ? 1 : 0;
Nico Huber648dfdc2024-12-06 23:00:30 +0100702 uint8_t cmd_buf[1 + JEDEC_MAX_ADDR_LEN + 1] = { read_op->opcode, };
Nico Huber0ecbacb2017-10-14 16:50:43 +0200703
Nico Huber4760b6e2024-01-06 23:45:28 +0100704 const int addr_len = spi_prepare_address(flash, cmd_buf, read_op->native_4ba, address);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200705 if (addr_len < 0)
706 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000707
Nico Huber4760b6e2024-01-06 23:45:28 +0100708 cmd_buf[addr_len + 1] = read_op->mode_byte;
709
710 struct spi_command cmd[] = {
711 {
712 .io_mode = read_op->io_mode,
713 .opcode_len = 1,
714 .address_len = addr_len,
715 .write_len = mode_len,
716 .high_z_len = read_op->dummy_len - mode_len,
717 .read_len = len,
718 .writearr = cmd_buf,
719 .readarr = dst,
720 },
721 NULL_SPI_CMD
722 };
723
724 return spi_send_multicommand(flash, cmd);
Sean Nelson14ba6682010-02-26 05:48:29 +0000725}
726
727/*
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000728 * Write a part of the flash chip.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000729 * FIXME: Use the chunk code from Michael Karcher instead.
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000730 * Each page is written separately in chunks with a maximum size of chunksize.
731 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000732int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000733 unsigned int len, unsigned int chunksize)
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000734{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000735 unsigned int i, j, starthere, lenhere, towrite;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000736 /* FIXME: page_size is the wrong variable. We need max_writechunk_size
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000737 * in struct flashctx to do this properly. All chips using
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000738 * spi_chip_write_256 have page_size set to max_writechunk_size, so
739 * we're OK for now.
740 */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000741 unsigned int page_size = flash->chip->page_size;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000742
743 /* Warning: This loop has a very unusual condition and body.
744 * The loop needs to go through each page with at least one affected
745 * byte. The lowest page number is (start / page_size) since that
746 * division rounds down. The highest page number we want is the page
747 * where the last byte of the range lives. That last byte has the
748 * address (start + len - 1), thus the highest page number is
749 * (start + len - 1) / page_size. Since we want to include that last
750 * page as well, the loop condition uses <=.
751 */
752 for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
753 /* Byte position of the first byte in the range in this page. */
754 /* starthere is an offset to the base address of the chip. */
755 starthere = max(start, i * page_size);
756 /* Length of bytes in the range in this page. */
757 lenhere = min(start + len, (i + 1) * page_size) - starthere;
758 for (j = 0; j < lenhere; j += chunksize) {
Nico Huber7a077222017-10-14 18:18:30 +0200759 int rc;
760
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000761 towrite = min(chunksize, lenhere - j);
Nico Huber7a077222017-10-14 18:18:30 +0200762 rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000763 if (rc)
Nico Huber7a077222017-10-14 18:18:30 +0200764 return rc;
Richard Hughes842d6782021-01-15 09:48:12 +0000765 flashprog_progress_add(flash, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000766 }
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000767 }
768
Nico Huber7a077222017-10-14 18:18:30 +0200769 return 0;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000770}
771
772/*
Sean Nelson14ba6682010-02-26 05:48:29 +0000773 * Program chip using byte programming. (SLOW!)
774 * This is for chips which can only handle one byte writes
775 * and for chips where memory mapped programming is impossible
776 * (e.g. due to size constraints in IT87* for over 512 kB)
777 */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000778/* real chunksize is 1, logical chunksize is 1 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000779int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000780{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000781 unsigned int i;
Sean Nelson14ba6682010-02-26 05:48:29 +0000782
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000783 for (i = start; i < start + len; i++) {
Nico Huber7a077222017-10-14 18:18:30 +0200784 if (spi_nbyte_program(flash, i, buf + i - start, 1))
Sean Nelson14ba6682010-02-26 05:48:29 +0000785 return 1;
Richard Hughes842d6782021-01-15 09:48:12 +0000786 flashprog_progress_add(flash, 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000787 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000788 return 0;
789}
790
Mark Marshallf20b7be2014-05-09 21:16:21 +0000791int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000792{
793 uint32_t pos = start;
Sean Nelson14ba6682010-02-26 05:48:29 +0000794 int result;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000795 unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
796 JEDEC_AAI_WORD_PROGRAM,
797 };
Sean Nelson14ba6682010-02-26 05:48:29 +0000798
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000799 /* The even start address and even length requirements can be either
800 * honored outside this function, or we can call spi_byte_program
801 * for the first and/or last byte and use AAI for the rest.
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000802 * FIXME: Move this to generic code.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000803 */
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000804 /* The data sheet requires a start address with the low bit cleared. */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000805 if (start % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000806 msg_cerr("%s: start address not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200807 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000808 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000809 if (spi_chip_write_1(flash, buf, start, start % 2))
810 return SPI_GENERIC_ERROR;
811 pos += start % 2;
812 /* Do not return an error for now. */
813 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000814 }
815 /* The data sheet requires total AAI write length to be even. */
816 if (len % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000817 msg_cerr("%s: total write length not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200818 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000819 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000820 /* Do not return an error for now. */
821 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000822 }
823
Nico Hubera1672f82017-10-14 18:00:20 +0200824 result = spi_write_cmd(flash, JEDEC_AAI_WORD_PROGRAM, false, start, buf + pos - start, 2, 10);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200825 if (result)
Stefan Reinauer87ace662014-04-26 16:12:55 +0000826 goto bailout;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000827
828 /* We already wrote 2 bytes in the multicommand step. */
Richard Hughes842d6782021-01-15 09:48:12 +0000829 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000830 pos += 2;
831
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000832 /* Are there at least two more bytes to write? */
833 while (pos < start + len - 1) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000834 cmd[1] = buf[pos++ - start];
835 cmd[2] = buf[pos++ - start];
Stefan Reinauer87ace662014-04-26 16:12:55 +0000836 result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
837 if (result != 0) {
838 msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
839 goto bailout;
840 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200841 if (spi_poll_wip(flash, 10))
842 goto bailout;
Richard Hughes842d6782021-01-15 09:48:12 +0000843 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000844 }
845
Stefan Tauner59c4d792014-04-26 16:13:09 +0000846 /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
847 result = spi_write_disable(flash);
848 if (result != 0) {
849 msg_cerr("%s failed to disable AAI mode.\n", __func__);
850 return SPI_GENERIC_ERROR;
851 }
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000852
853 /* Write remaining byte (if any). */
854 if (pos < start + len) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000855 if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000856 return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000857 }
858
Sean Nelson14ba6682010-02-26 05:48:29 +0000859 return 0;
Stefan Reinauer87ace662014-04-26 16:12:55 +0000860
861bailout:
Stefan Tauner59c4d792014-04-26 16:13:09 +0000862 result = spi_write_disable(flash);
863 if (result != 0)
864 msg_cerr("%s failed to disable AAI mode.\n", __func__);
Stefan Reinauer87ace662014-04-26 16:12:55 +0000865 return SPI_GENERIC_ERROR;
Sean Nelson14ba6682010-02-26 05:48:29 +0000866}