blob: b22c8a82fe872bd7a9917171b7ec5a40bcddfa21 [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>
Nico Huber43125762023-05-01 15:56:16 +020022#include <stdlib.h>
Sean Nelson14ba6682010-02-26 05:48:29 +000023#include <string.h>
Nico Hubera1672f82017-10-14 18:00:20 +020024#include <stdbool.h>
Sean Nelson14ba6682010-02-26 05:48:29 +000025#include "flash.h"
26#include "flashchips.h"
27#include "chipdrivers.h"
Nico Huberfbc41d22026-02-22 23:04:01 +010028#include "chipdrivers/spi.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000029#include "programmer.h"
Nico Huberd5185632024-01-05 18:44:41 +010030#include "spi_command.h"
Sean Nelson14ba6682010-02-26 05:48:29 +000031#include "spi.h"
32
Nico Huber43125762023-05-01 15:56:16 +020033static int spi_rdid(const struct spi_master *spi, unsigned char *readarr, int bytes)
Sean Nelson14ba6682010-02-26 05:48:29 +000034{
Mathias Krausea60faab2011-01-17 07:50:42 +000035 static const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID };
Sean Nelson14ba6682010-02-26 05:48:29 +000036 int ret;
37 int i;
38
Nico Huber43125762023-05-01 15:56:16 +020039 ret = spi->command(spi, sizeof(cmd), bytes, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000040 if (ret)
41 return ret;
Sean Nelsoned479d22010-03-24 23:14:32 +000042 msg_cspew("RDID returned");
Sean Nelson14ba6682010-02-26 05:48:29 +000043 for (i = 0; i < bytes; i++)
Sean Nelsoned479d22010-03-24 23:14:32 +000044 msg_cspew(" 0x%02x", readarr[i]);
45 msg_cspew(". ");
Sean Nelson14ba6682010-02-26 05:48:29 +000046 return 0;
47}
48
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000049static int spi_rems(struct flashctx *flash, unsigned char *readarr)
Sean Nelson14ba6682010-02-26 05:48:29 +000050{
Nico Hubered098d62017-04-21 23:47:08 +020051 static const unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, };
Sean Nelson14ba6682010-02-26 05:48:29 +000052 int ret;
53
Nico Hubered098d62017-04-21 23:47:08 +020054 ret = spi_send_command(flash, sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000055 if (ret)
56 return ret;
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +000057 msg_cspew("REMS returned 0x%02x 0x%02x. ", readarr[0], readarr[1]);
Sean Nelson14ba6682010-02-26 05:48:29 +000058 return 0;
59}
60
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000061static int spi_res(struct flashctx *flash, unsigned char *readarr, int bytes)
Sean Nelson14ba6682010-02-26 05:48:29 +000062{
Nico Hubered098d62017-04-21 23:47:08 +020063 static const unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, };
Sean Nelson14ba6682010-02-26 05:48:29 +000064 int ret;
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +000065 int i;
Sean Nelson14ba6682010-02-26 05:48:29 +000066
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000067 ret = spi_send_command(flash, sizeof(cmd), bytes, cmd, readarr);
Sean Nelson14ba6682010-02-26 05:48:29 +000068 if (ret)
69 return ret;
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +000070 msg_cspew("RES returned");
71 for (i = 0; i < bytes; i++)
72 msg_cspew(" 0x%02x", readarr[i]);
73 msg_cspew(". ");
Sean Nelson14ba6682010-02-26 05:48:29 +000074 return 0;
75}
76
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000077int spi_write_enable(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +000078{
Mathias Krausea60faab2011-01-17 07:50:42 +000079 static const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN };
Sean Nelson14ba6682010-02-26 05:48:29 +000080 int result;
81
82 /* Send WREN (Write Enable) */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000083 result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
Sean Nelson14ba6682010-02-26 05:48:29 +000084
85 if (result)
Sean Nelsoned479d22010-03-24 23:14:32 +000086 msg_cerr("%s failed\n", __func__);
Sean Nelson14ba6682010-02-26 05:48:29 +000087
88 return result;
89}
90
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000091int spi_write_disable(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +000092{
Mathias Krausea60faab2011-01-17 07:50:42 +000093 static const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI };
Sean Nelson14ba6682010-02-26 05:48:29 +000094
95 /* Send WRDI (Write Disable) */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +000096 return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
Sean Nelson14ba6682010-02-26 05:48:29 +000097}
98
Nico Huber43125762023-05-01 15:56:16 +020099struct found_id *probe_spi_rdid(const struct bus_probe *probe, const struct master_common *mst)
Sean Nelson14ba6682010-02-26 05:48:29 +0000100{
Nico Huber43125762023-05-01 15:56:16 +0200101 const struct spi_master *const spi = (const struct spi_master *)mst;
Sean Nelson14ba6682010-02-26 05:48:29 +0000102 unsigned char readarr[4];
Nico Huber43125762023-05-01 15:56:16 +0200103 size_t bytes;
104 int ret;
Sean Nelson14ba6682010-02-26 05:48:29 +0000105
Nico Huber43125762023-05-01 15:56:16 +0200106 for (bytes = 4; bytes >= 3; --bytes) {
107 ret = spi_rdid(spi, readarr, bytes);
108 if (ret == SPI_INVALID_LENGTH)
109 msg_cinfo("%zu byte RDID not supported on this SPI controller\n", bytes);
110 if (!ret)
111 break;
112 }
113 if (ret || flashprog_no_data(readarr, bytes))
114 return NULL;
Sean Nelson14ba6682010-02-26 05:48:29 +0000115
116 if (!oddparity(readarr[0]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000117 msg_cdbg("RDID byte 0 parity violation. ");
Sean Nelson14ba6682010-02-26 05:48:29 +0000118
Nico Huber43125762023-05-01 15:56:16 +0200119 struct found_id *const found = calloc(1, sizeof(*found));
120 if (!found) {
121 msg_cerr("Out of memory!\n");
122 return NULL;
123 }
124
125 struct id_info *const id = &found->info.id;
126 id->type = ID_SPI_RDID;
127
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +0000128 /* Check if this is a continuation vendor ID.
129 * FIXME: Handle continuation device IDs.
130 */
Sean Nelson14ba6682010-02-26 05:48:29 +0000131 if (readarr[0] == 0x7f) {
132 if (!oddparity(readarr[1]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000133 msg_cdbg("RDID byte 1 parity violation. ");
Nico Huber43125762023-05-01 15:56:16 +0200134 id->manufacture = (readarr[0] << 8) | readarr[1];
135 id->model = readarr[2];
Sean Nelson14ba6682010-02-26 05:48:29 +0000136 if (bytes > 3) {
Nico Huber43125762023-05-01 15:56:16 +0200137 id->model <<= 8;
138 id->model |= readarr[3];
Sean Nelson14ba6682010-02-26 05:48:29 +0000139 }
140 } else {
Nico Huber43125762023-05-01 15:56:16 +0200141 id->manufacture = readarr[0];
142 id->model = (readarr[1] << 8) | readarr[2];
Sean Nelson14ba6682010-02-26 05:48:29 +0000143 }
144
Nico Huber43125762023-05-01 15:56:16 +0200145 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000146
Nico Huber43125762023-05-01 15:56:16 +0200147 return found;
Sean Nelson14ba6682010-02-26 05:48:29 +0000148}
149
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000150int probe_spi_rems(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000151{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000152 const struct flashchip *chip = flash->chip;
Sean Nelson14ba6682010-02-26 05:48:29 +0000153 unsigned char readarr[JEDEC_REMS_INSIZE];
154 uint32_t id1, id2;
155
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000156 if (spi_rems(flash, readarr)) {
Sean Nelson14ba6682010-02-26 05:48:29 +0000157 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000158 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000159
160 id1 = readarr[0];
161 id2 = readarr[1];
162
Sean Nelsoned479d22010-03-24 23:14:32 +0000163 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000164
Nico Huber11136c22023-05-01 12:00:09 +0200165 if (id1 == chip->id.manufacture && id2 == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000166 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000167
168 /* Test if this is a pure vendor match. */
Nico Huber11136c22023-05-01 12:00:09 +0200169 if (id1 == chip->id.manufacture && GENERIC_DEVICE_ID == chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000170 return 1;
171
172 /* Test if there is any vendor ID. */
Nico Huber11136c22023-05-01 12:00:09 +0200173 if (GENERIC_MANUF_ID == chip->id.manufacture && id1 != 0xff && id1 != 0x00)
Sean Nelson14ba6682010-02-26 05:48:29 +0000174 return 1;
175
176 return 0;
177}
178
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000179int probe_spi_res1(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000180{
Mathias Krausea60faab2011-01-17 07:50:42 +0000181 static const unsigned char allff[] = {0xff, 0xff, 0xff};
182 static const unsigned char all00[] = {0x00, 0x00, 0x00};
Sean Nelson14ba6682010-02-26 05:48:29 +0000183 unsigned char readarr[3];
184 uint32_t id2;
Sean Nelson14ba6682010-02-26 05:48:29 +0000185
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000186 /* We only want one-byte RES if RDID and REMS are unusable. */
187
Sean Nelson14ba6682010-02-26 05:48:29 +0000188 /* Check if RDID is usable and does not return 0xff 0xff 0xff or
189 * 0x00 0x00 0x00. In that case, RES is pointless.
190 */
Nico Huber43125762023-05-01 15:56:16 +0200191 if (!spi_rdid(flash->mst.spi, readarr, 3) && memcmp(readarr, allff, 3) &&
Sean Nelson14ba6682010-02-26 05:48:29 +0000192 memcmp(readarr, all00, 3)) {
193 msg_cdbg("Ignoring RES in favour of RDID.\n");
194 return 0;
195 }
196 /* Check if REMS is usable and does not return 0xff 0xff or
197 * 0x00 0x00. In that case, RES is pointless.
198 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000199 if (!spi_rems(flash, readarr) &&
200 memcmp(readarr, allff, JEDEC_REMS_INSIZE) &&
Sean Nelson14ba6682010-02-26 05:48:29 +0000201 memcmp(readarr, all00, JEDEC_REMS_INSIZE)) {
202 msg_cdbg("Ignoring RES in favour of REMS.\n");
203 return 0;
204 }
205
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000206 if (spi_res(flash, readarr, 1)) {
Sean Nelson14ba6682010-02-26 05:48:29 +0000207 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000208 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000209
Sean Nelson14ba6682010-02-26 05:48:29 +0000210 id2 = readarr[0];
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000211
Sean Nelsoned479d22010-03-24 23:14:32 +0000212 msg_cdbg("%s: id 0x%x\n", __func__, id2);
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000213
Nico Huber11136c22023-05-01 12:00:09 +0200214 if (id2 != flash->chip->id.model)
Sean Nelson14ba6682010-02-26 05:48:29 +0000215 return 0;
216
Sean Nelson14ba6682010-02-26 05:48:29 +0000217 return 1;
218}
219
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000220int probe_spi_res2(struct flashctx *flash)
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000221{
222 unsigned char readarr[2];
223 uint32_t id1, id2;
224
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000225 if (spi_res(flash, readarr, 2)) {
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000226 return 0;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000227 }
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000228
229 id1 = readarr[0];
230 id2 = readarr[1];
231
232 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
233
Nico Huber11136c22023-05-01 12:00:09 +0200234 if (id1 != flash->chip->id.manufacture || id2 != flash->chip->id.model)
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000235 return 0;
236
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000237 return 1;
238}
239
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000240int probe_spi_res3(struct flashctx *flash)
241{
242 unsigned char readarr[3];
243 uint32_t id1, id2;
244
245 if (spi_res(flash, readarr, 3)) {
246 return 0;
247 }
248
249 id1 = (readarr[0] << 8) | readarr[1];
250 id2 = readarr[2];
251
252 msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
253
Nico Huber11136c22023-05-01 12:00:09 +0200254 if (id1 != flash->chip->id.manufacture || id2 != flash->chip->id.model)
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000255 return 0;
256
257 return 1;
258}
259
Stefan Tauner57794ac2012-12-29 15:04:20 +0000260/* Only used for some Atmel chips. */
261int probe_spi_at25f(struct flashctx *flash)
262{
263 static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
264 unsigned char readarr[AT25F_RDID_INSIZE];
265 uint32_t id1;
266 uint32_t id2;
267
268 if (spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr))
269 return 0;
270
271 id1 = readarr[0];
272 id2 = readarr[1];
273
274 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
275
Nico Huber11136c22023-05-01 12:00:09 +0200276 if (id1 == flash->chip->id.manufacture && id2 == flash->chip->id.model)
Stefan Tauner57794ac2012-12-29 15:04:20 +0000277 return 1;
278
279 return 0;
280}
281
Nico Huber0ecbacb2017-10-14 16:50:43 +0200282static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
283{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200284 /* FIXME: We don't time out. */
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100285 while (true) {
286 uint8_t status;
287 int ret = spi_read_register(flash, STATUS1, &status);
288 if (ret)
289 return ret;
290 if (!(status & SPI_SR_WIP))
291 return 0;
292
Nico Huber0ecbacb2017-10-14 16:50:43 +0200293 programmer_delay(poll_delay);
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100294 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200295}
296
Nico Hubera3140d02017-10-15 11:20:58 +0200297/**
298 * Execute WREN plus another one byte `op`, optionally poll WIP afterwards.
299 *
300 * @param flash the flash chip's context
301 * @param op the operation to execute
302 * @param poll_delay interval in us for polling WIP, don't poll if zero
303 * @return 0 on success, non-zero otherwise
304 */
Nico Huber8d0f4652024-05-04 18:52:51 +0200305int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, const unsigned int poll_delay)
Sean Nelson14ba6682010-02-26 05:48:29 +0000306{
Sean Nelson14ba6682010-02-26 05:48:29 +0000307 struct spi_command cmds[] = {
308 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200309 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000310 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100311 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200312 .writearr = (const unsigned char[]){ JEDEC_WREN },
Sean Nelson14ba6682010-02-26 05:48:29 +0000313 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200314 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000315 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100316 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200317 .writearr = (const unsigned char[]){ op },
318 },
319 NULL_SPI_CMD,
320 };
321
322 const int result = spi_send_multicommand(flash, cmds);
323 if (result)
324 msg_cerr("%s failed during command execution\n", __func__);
325
Nico Huber0ecbacb2017-10-14 16:50:43 +0200326 const int status = poll_delay ? spi_poll_wip(flash, poll_delay) : 0;
Nico Hubera3140d02017-10-15 11:20:58 +0200327
Nico Huber0ecbacb2017-10-14 16:50:43 +0200328 return result ? result : status;
329}
330
Nico Huber7e3c81a2017-10-14 18:56:50 +0200331static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
332{
Nico Huber9bb8a322022-05-24 15:07:34 +0200333 uint8_t op;
334 if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
335 op = JEDEC_WRITE_EXT_ADDR_REG;
336 } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
337 op = ALT_WRITE_EXT_ADDR_REG_17;
338 } else {
339 msg_cerr("Flash misses feature flag for extended-address register.\n");
340 return -1;
341 }
342
Nico Huber7e3c81a2017-10-14 18:56:50 +0200343 struct spi_command cmds[] = {
344 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200345 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000346 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100347 .opcode_len = 1,
Nico Huber7e3c81a2017-10-14 18:56:50 +0200348 .writearr = (const unsigned char[]){ JEDEC_WREN },
349 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200350 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000351 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100352 .opcode_len = 1,
353 .write_len = 1,
Nico Huber57dbd642018-03-13 18:01:05 +0100354 .writearr = (const unsigned char[]){ op, regdata },
Nico Huber7e3c81a2017-10-14 18:56:50 +0200355 },
356 NULL_SPI_CMD,
357 };
358
359 const int result = spi_send_multicommand(flash, cmds);
360 if (result)
361 msg_cerr("%s failed during command execution\n", __func__);
362 return result;
363}
364
Nico Huber7eb38aa2019-03-21 15:42:54 +0100365int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
Nico Huberf43c6542017-10-14 17:47:28 +0200366{
367 if (flash->address_high_byte != addr_high &&
368 spi_write_extended_address_register(flash, addr_high))
369 return -1;
370 flash->address_high_byte = addr_high;
371 return 0;
372}
373
Nico Huber4e6155a2025-01-02 23:05:09 +0100374static size_t spi_address_length(struct flashctx *const flash, const bool native_4ba)
375{
376 if (flash->chip->spi_cmd_set == SPI25_EEPROM) {
377 if (flashprog_flash_getsize(flash) > 64*KiB)
378 return 3;
379 if (flashprog_flash_getsize(flash) > 256)
380 return 2;
381 return 1;
382 }
383
384 if (native_4ba || flash->in_4ba_mode)
385 return 4;
386
387 return 3;
388}
389
Nico Hubera1672f82017-10-14 18:00:20 +0200390static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
Nico Hubere3f648c2023-02-15 02:55:23 +0100391 const bool native_4ba, const unsigned int rel_addr)
Nico Huber0ecbacb2017-10-14 16:50:43 +0200392{
Nico Huber4e6155a2025-01-02 23:05:09 +0100393 const size_t len = spi_address_length(flash, native_4ba);
Nico Hubere3f648c2023-02-15 02:55:23 +0100394 unsigned int addr = rel_addr;
395
396 if (spi_master_top_aligned(flash))
397 addr = rel_addr - flashprog_flash_getsize(flash); /* intentional integer underflow */
Nico Huber4e6155a2025-01-02 23:05:09 +0100398
399 switch (len) {
400 case 4:
Nico Huber1cf407b2017-11-10 20:18:23 +0100401 if (!spi_master_4ba(flash)) {
402 msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n");
403 return -1;
404 }
Nico Huberf43c6542017-10-14 17:47:28 +0200405 cmd_buf[1] = (addr >> 24) & 0xff;
406 cmd_buf[2] = (addr >> 16) & 0xff;
407 cmd_buf[3] = (addr >> 8) & 0xff;
408 cmd_buf[4] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100409 return len;
410 case 3:
Nico Huber9bb8a322022-05-24 15:07:34 +0200411 if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
Nico Hubere3f648c2023-02-15 02:55:23 +0100412 if (spi_set_extended_address(flash, rel_addr >> 24))
Nico Huberf43c6542017-10-14 17:47:28 +0200413 return -1;
Nico Hubere3f648c2023-02-15 02:55:23 +0100414 } else if (rel_addr >> 24) {
Nico Huber1cf407b2017-11-10 20:18:23 +0100415 msg_cerr("Can't handle 4-byte address for opcode '0x%02x'\n"
416 "with this chip/programmer combination.\n", cmd_buf[0]);
417 return -1;
Nico Huberf43c6542017-10-14 17:47:28 +0200418 }
419 cmd_buf[1] = (addr >> 16) & 0xff;
420 cmd_buf[2] = (addr >> 8) & 0xff;
421 cmd_buf[3] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100422 return len;
423 case 2:
424 cmd_buf[1] = (addr >> 8) & 0xff;
425 cmd_buf[2] = (addr >> 0) & 0xff;
426 return len;
427 default:
428 cmd_buf[1] = addr & 0xff;
429 return len;
Nico Huberf43c6542017-10-14 17:47:28 +0200430 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200431}
432
433/**
434 * Execute WREN plus another `op` that takes an address and
435 * optional data, poll WIP afterwards.
436 *
437 * @param flash the flash chip's context
438 * @param op the operation to execute
Nico Hubera1672f82017-10-14 18:00:20 +0200439 * @param native_4ba whether `op` always takes a 4-byte address
Nico Huber0ecbacb2017-10-14 16:50:43 +0200440 * @param addr the address parameter to `op`
441 * @param out_bytes bytes to send after the address,
442 * may be NULL if and only if `out_bytes` is 0
443 * @param out_bytes number of bytes to send, 256 at most, may be zero
444 * @param poll_delay interval in us for polling WIP
445 * @return 0 on success, non-zero otherwise
446 */
Nico Hubera1672f82017-10-14 18:00:20 +0200447static int spi_write_cmd(struct flashctx *const flash, const uint8_t op,
448 const bool native_4ba, const unsigned int addr,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200449 const uint8_t *const out_bytes, const size_t out_len,
450 const unsigned int poll_delay)
451{
452 uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN + 256];
453 struct spi_command cmds[] = {
454 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200455 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000456 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100457 .opcode_len = 1,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200458 .writearr = (const unsigned char[]){ JEDEC_WREN },
459 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200460 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000461 .readarr = 0,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200462 .writearr = cmd,
463 },
464 NULL_SPI_CMD,
465 };
466
467 cmd[0] = op;
Nico Hubera1672f82017-10-14 18:00:20 +0200468 const int addr_len = spi_prepare_address(flash, cmd, native_4ba, addr);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200469 if (addr_len < 0)
470 return 1;
471
472 if (1 + addr_len + out_len > sizeof(cmd)) {
473 msg_cerr("%s called for too long a write\n", __func__);
474 return 1;
475 }
Angel Ponsc92f6872020-03-31 15:32:10 +0200476 if (!out_bytes && out_len > 0)
477 return 1;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200478
479 memcpy(cmd + 1 + addr_len, out_bytes, out_len);
Nico Huberd5185632024-01-05 18:44:41 +0100480 cmds[1].opcode_len = 1;
481 cmds[1].address_len = addr_len;
482 cmds[1].write_len = out_len;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200483
484 const int result = spi_send_multicommand(flash, cmds);
485 if (result)
486 msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
487
488 const int status = spi_poll_wip(flash, poll_delay);
489
490 return result ? result : status;
Nico Hubera3140d02017-10-15 11:20:58 +0200491}
492
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600493static int spi_chip_erase_60(struct flashctx *flash)
Nico Hubera3140d02017-10-15 11:20:58 +0200494{
495 /* This usually takes 1-85s, so wait in 1s steps. */
496 return spi_simple_write_cmd(flash, 0x60, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000497}
498
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600499static int spi_chip_erase_62(struct flashctx *flash)
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000500{
Nico Hubera3140d02017-10-15 11:20:58 +0200501 /* This usually takes 2-5s, so wait in 100ms steps. */
502 return spi_simple_write_cmd(flash, 0x62, 100 * 1000);
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000503}
504
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600505static int spi_chip_erase_c7(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000506{
Nico Hubera3140d02017-10-15 11:20:58 +0200507 /* This usually takes 1-85s, so wait in 1s steps. */
508 return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000509}
510
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000511int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
512 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000513{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200514 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200515 return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000516}
517
518/* Block size is usually
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000519 * 32M (one die) for Micron
520 */
521int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
522{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200523 /* This usually takes 240-480s, so wait in 500ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200524 return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000);
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000525}
526
527/* Block size is usually
Sean Nelson14ba6682010-02-26 05:48:29 +0000528 * 64k for Macronix
529 * 32k for SST
530 * 4-32k non-uniform for EON
531 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000532int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
533 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000534{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200535 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200536 return spi_write_cmd(flash, 0xd8, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000537}
538
539/* Block size is usually
540 * 4k for PMC
541 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000542int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
543 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000544{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200545 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200546 return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000547}
548
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000549/* Page erase (usually 256B blocks) */
550int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
551{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200552 /* This takes up to 20ms usually (on worn out devices
553 up to the 0.5s range), so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200554 return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000555}
556
Sean Nelson14ba6682010-02-26 05:48:29 +0000557/* Sector size is usually 4k, though Macronix eliteflash has 64k */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000558int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
559 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000560{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200561 /* This usually takes 15-800ms, so wait in 10ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200562 return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000563}
564
Stefan Tauner94b39b42012-10-27 00:06:02 +0000565int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
566{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200567 /* This usually takes 10ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200568 return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000569}
570
571int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
572{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200573 /* This usually takes 8ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200574 return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000575}
576
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000577int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
578 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000579{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000580 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000581 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000582 __func__);
583 return -1;
584 }
585 return spi_chip_erase_60(flash);
586}
587
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000588int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
589{
590 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
591 msg_cerr("%s called with incorrect arguments\n",
592 __func__);
593 return -1;
594 }
595 return spi_chip_erase_62(flash);
596}
597
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000598int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
599 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000600{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000601 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000602 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000603 __func__);
604 return -1;
605 }
606 return spi_chip_erase_c7(flash);
607}
608
Nico Huber7e3c81a2017-10-14 18:56:50 +0200609/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
610int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
611{
612 /* This usually takes 15-800ms, so wait in 10ms steps. */
613 return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
614}
615
616/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huberfffc48d2022-05-28 14:26:06 +0200617int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
618{
619 /* This usually takes 100-4000ms, so wait in 100ms steps. */
620 return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
621}
622
623/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huber7e3c81a2017-10-14 18:56:50 +0200624int spi_block_erase_5c(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, 0x5c, true, addr, NULL, 0, 100 * 1000);
628}
629
630/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
631int spi_block_erase_dc(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, 0xdc, true, addr, NULL, 0, 100 * 1000);
635}
636
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530637static const struct {
638 erasefunc_t *func;
639 uint8_t opcode;
Thomas Heijligen35614512022-09-19 23:46:58 +0200640} spi25_function_opcode_list[] = {
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530641 {&spi_block_erase_20, 0x20},
642 {&spi_block_erase_21, 0x21},
643 {&spi_block_erase_50, 0x50},
644 {&spi_block_erase_52, 0x52},
645 {&spi_block_erase_53, 0x53},
646 {&spi_block_erase_5c, 0x5c},
647 {&spi_block_erase_60, 0x60},
648 {&spi_block_erase_62, 0x62},
649 {&spi_block_erase_81, 0x81},
650 {&spi_block_erase_c4, 0xc4},
651 {&spi_block_erase_c7, 0xc7},
652 {&spi_block_erase_d7, 0xd7},
653 {&spi_block_erase_d8, 0xd8},
654 {&spi_block_erase_db, 0xdb},
655 {&spi_block_erase_dc, 0xdc},
656};
657
Thomas Heijligen35614512022-09-19 23:46:58 +0200658erasefunc_t *spi25_get_erasefn_from_opcode(uint8_t opcode)
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000659{
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530660 size_t i;
Thomas Heijligen35614512022-09-19 23:46:58 +0200661 for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
662 if (spi25_function_opcode_list[i].opcode == opcode)
663 return spi25_function_opcode_list[i].func;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000664 }
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530665 msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
Nico Huberc3b02dc2023-08-12 01:13:45 +0200666 "this at flashprog@flashprog.org\n", __func__, opcode);
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530667 return NULL;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000668}
669
Nico Huber0ecbacb2017-10-14 16:50:43 +0200670static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000671{
Nico Huber1cf407b2017-11-10 20:18:23 +0100672 const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash);
Nico Hubera1672f82017-10-14 18:00:20 +0200673 const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM;
674 return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10);
Sean Nelson14ba6682010-02-26 05:48:29 +0000675}
676
Nico Hubera1b7f352024-03-25 18:32:11 +0100677const struct spi_read_op *get_spi_read_op(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100678{
679 static const struct spi_read_op sio_read = { SINGLE_IO_1_1_1, false, JEDEC_READ, 0x00, 0 };
680 static const struct spi_read_op sio_read_4ba = { SINGLE_IO_1_1_1, true, JEDEC_READ_4BA, 0x00, 0 };
681
682 if (flash->spi_fast_read)
683 return flash->spi_fast_read;
684
685 if (flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash))
686 return &sio_read_4ba;
687
688 return &sio_read;
689}
690
Nico Huberca1c7fd2023-04-28 21:44:41 +0000691int spi_nbyte_read(struct flashctx *flash, uint8_t *dst, unsigned int address, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000692{
Nico Huber4760b6e2024-01-06 23:45:28 +0100693 const struct spi_read_op *const read_op = get_spi_read_op(flash);
694 const size_t mode_len = read_op->mode_byte ? 1 : 0;
Nico Huber648dfdc2024-12-06 23:00:30 +0100695 uint8_t cmd_buf[1 + JEDEC_MAX_ADDR_LEN + 1] = { read_op->opcode, };
Nico Huber0ecbacb2017-10-14 16:50:43 +0200696
Nico Huber4760b6e2024-01-06 23:45:28 +0100697 const int addr_len = spi_prepare_address(flash, cmd_buf, read_op->native_4ba, address);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200698 if (addr_len < 0)
699 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000700
Nico Huber4760b6e2024-01-06 23:45:28 +0100701 cmd_buf[addr_len + 1] = read_op->mode_byte;
702
703 struct spi_command cmd[] = {
704 {
705 .io_mode = read_op->io_mode,
706 .opcode_len = 1,
707 .address_len = addr_len,
708 .write_len = mode_len,
709 .high_z_len = read_op->dummy_len - mode_len,
710 .read_len = len,
711 .writearr = cmd_buf,
712 .readarr = dst,
713 },
714 NULL_SPI_CMD
715 };
716
717 return spi_send_multicommand(flash, cmd);
Sean Nelson14ba6682010-02-26 05:48:29 +0000718}
719
720/*
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000721 * Write a part of the flash chip.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000722 * FIXME: Use the chunk code from Michael Karcher instead.
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000723 * Each page is written separately in chunks with a maximum size of chunksize.
724 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000725int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000726 unsigned int len, unsigned int chunksize)
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000727{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000728 unsigned int i, j, starthere, lenhere, towrite;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000729 /* FIXME: page_size is the wrong variable. We need max_writechunk_size
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000730 * in struct flashctx to do this properly. All chips using
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000731 * spi_chip_write_256 have page_size set to max_writechunk_size, so
732 * we're OK for now.
733 */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000734 unsigned int page_size = flash->chip->page_size;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000735
736 /* Warning: This loop has a very unusual condition and body.
737 * The loop needs to go through each page with at least one affected
738 * byte. The lowest page number is (start / page_size) since that
739 * division rounds down. The highest page number we want is the page
740 * where the last byte of the range lives. That last byte has the
741 * address (start + len - 1), thus the highest page number is
742 * (start + len - 1) / page_size. Since we want to include that last
743 * page as well, the loop condition uses <=.
744 */
745 for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
746 /* Byte position of the first byte in the range in this page. */
747 /* starthere is an offset to the base address of the chip. */
748 starthere = max(start, i * page_size);
749 /* Length of bytes in the range in this page. */
750 lenhere = min(start + len, (i + 1) * page_size) - starthere;
751 for (j = 0; j < lenhere; j += chunksize) {
Nico Huber7a077222017-10-14 18:18:30 +0200752 int rc;
753
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000754 towrite = min(chunksize, lenhere - j);
Nico Huber7a077222017-10-14 18:18:30 +0200755 rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000756 if (rc)
Nico Huber7a077222017-10-14 18:18:30 +0200757 return rc;
Richard Hughes842d6782021-01-15 09:48:12 +0000758 flashprog_progress_add(flash, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000759 }
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000760 }
761
Nico Huber7a077222017-10-14 18:18:30 +0200762 return 0;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000763}
764
765/*
Sean Nelson14ba6682010-02-26 05:48:29 +0000766 * Program chip using byte programming. (SLOW!)
767 * This is for chips which can only handle one byte writes
768 * and for chips where memory mapped programming is impossible
769 * (e.g. due to size constraints in IT87* for over 512 kB)
770 */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000771/* real chunksize is 1, logical chunksize is 1 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000772int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000773{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000774 unsigned int i;
Sean Nelson14ba6682010-02-26 05:48:29 +0000775
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000776 for (i = start; i < start + len; i++) {
Nico Huber7a077222017-10-14 18:18:30 +0200777 if (spi_nbyte_program(flash, i, buf + i - start, 1))
Sean Nelson14ba6682010-02-26 05:48:29 +0000778 return 1;
Richard Hughes842d6782021-01-15 09:48:12 +0000779 flashprog_progress_add(flash, 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000780 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000781 return 0;
782}
783
Mark Marshallf20b7be2014-05-09 21:16:21 +0000784int 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 +0000785{
786 uint32_t pos = start;
Sean Nelson14ba6682010-02-26 05:48:29 +0000787 int result;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000788 unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
789 JEDEC_AAI_WORD_PROGRAM,
790 };
Sean Nelson14ba6682010-02-26 05:48:29 +0000791
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000792 /* The even start address and even length requirements can be either
793 * honored outside this function, or we can call spi_byte_program
794 * for the first and/or last byte and use AAI for the rest.
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000795 * FIXME: Move this to generic code.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000796 */
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000797 /* The data sheet requires a start address with the low bit cleared. */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000798 if (start % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000799 msg_cerr("%s: start address not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200800 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000801 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000802 if (spi_chip_write_1(flash, buf, start, start % 2))
803 return SPI_GENERIC_ERROR;
804 pos += start % 2;
805 /* Do not return an error for now. */
806 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000807 }
808 /* The data sheet requires total AAI write length to be even. */
809 if (len % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000810 msg_cerr("%s: total write length not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200811 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000812 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000813 /* Do not return an error for now. */
814 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000815 }
816
Nico Hubera1672f82017-10-14 18:00:20 +0200817 result = spi_write_cmd(flash, JEDEC_AAI_WORD_PROGRAM, false, start, buf + pos - start, 2, 10);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200818 if (result)
Stefan Reinauer87ace662014-04-26 16:12:55 +0000819 goto bailout;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000820
821 /* We already wrote 2 bytes in the multicommand step. */
Richard Hughes842d6782021-01-15 09:48:12 +0000822 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000823 pos += 2;
824
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000825 /* Are there at least two more bytes to write? */
826 while (pos < start + len - 1) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000827 cmd[1] = buf[pos++ - start];
828 cmd[2] = buf[pos++ - start];
Stefan Reinauer87ace662014-04-26 16:12:55 +0000829 result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
830 if (result != 0) {
831 msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
832 goto bailout;
833 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200834 if (spi_poll_wip(flash, 10))
835 goto bailout;
Richard Hughes842d6782021-01-15 09:48:12 +0000836 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000837 }
838
Stefan Tauner59c4d792014-04-26 16:13:09 +0000839 /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
840 result = spi_write_disable(flash);
841 if (result != 0) {
842 msg_cerr("%s failed to disable AAI mode.\n", __func__);
843 return SPI_GENERIC_ERROR;
844 }
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000845
846 /* Write remaining byte (if any). */
847 if (pos < start + len) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000848 if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000849 return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000850 }
851
Sean Nelson14ba6682010-02-26 05:48:29 +0000852 return 0;
Stefan Reinauer87ace662014-04-26 16:12:55 +0000853
854bailout:
Stefan Tauner59c4d792014-04-26 16:13:09 +0000855 result = spi_write_disable(flash);
856 if (result != 0)
857 msg_cerr("%s failed to disable AAI mode.\n", __func__);
Stefan Reinauer87ace662014-04-26 16:12:55 +0000858 return SPI_GENERIC_ERROR;
Sean Nelson14ba6682010-02-26 05:48:29 +0000859}