blob: a6287709f1e75338af2fcfcf0ac7c1d3238841c9 [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"
Nico Huberfbc41d22026-02-22 23:04:01 +010027#include "chipdrivers/spi.h"
Nico Huber10337f72026-03-04 19:57:27 +010028#include "chipdrivers/memory_bus.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
Nico Huber64f53a12026-02-15 16:04:29 +010049static int spi_rems(const struct spi_master *spi, 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 Huber64f53a12026-02-15 16:04:29 +010054 ret = spi->command(spi, 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
Nico Huber64f53a12026-02-15 16:04:29 +010061static int spi_res(const struct spi_master *spi, 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
Nico Huber64f53a12026-02-15 16:04:29 +010067 ret = spi->command(spi, 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 Huberdae90222026-03-09 20:36:56 +010099struct found_id *probe_spi_rdid(const struct bus_probe *probe,
100 const struct master_common *mst,
101 const struct flashchip *chip)
Sean Nelson14ba6682010-02-26 05:48:29 +0000102{
Nico Huber43125762023-05-01 15:56:16 +0200103 const struct spi_master *const spi = (const struct spi_master *)mst;
Sean Nelson14ba6682010-02-26 05:48:29 +0000104 unsigned char readarr[4];
Nico Huber43125762023-05-01 15:56:16 +0200105 size_t bytes;
106 int ret;
Sean Nelson14ba6682010-02-26 05:48:29 +0000107
Nico Huber43125762023-05-01 15:56:16 +0200108 for (bytes = 4; bytes >= 3; --bytes) {
109 ret = spi_rdid(spi, readarr, bytes);
110 if (ret == SPI_INVALID_LENGTH)
111 msg_cinfo("%zu byte RDID not supported on this SPI controller\n", bytes);
112 if (!ret)
113 break;
114 }
115 if (ret || flashprog_no_data(readarr, bytes))
116 return NULL;
Sean Nelson14ba6682010-02-26 05:48:29 +0000117
118 if (!oddparity(readarr[0]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000119 msg_cdbg("RDID byte 0 parity violation. ");
Sean Nelson14ba6682010-02-26 05:48:29 +0000120
Nico Huber43125762023-05-01 15:56:16 +0200121 struct found_id *const found = calloc(1, sizeof(*found));
122 if (!found) {
123 msg_cerr("Out of memory!\n");
124 return NULL;
125 }
126
127 struct id_info *const id = &found->info.id;
128 id->type = ID_SPI_RDID;
129
Carl-Daniel Hailfinger8ae500e2010-06-20 10:39:33 +0000130 /* Check if this is a continuation vendor ID.
131 * FIXME: Handle continuation device IDs.
132 */
Sean Nelson14ba6682010-02-26 05:48:29 +0000133 if (readarr[0] == 0x7f) {
134 if (!oddparity(readarr[1]))
Sean Nelsoned479d22010-03-24 23:14:32 +0000135 msg_cdbg("RDID byte 1 parity violation. ");
Nico Huber43125762023-05-01 15:56:16 +0200136 id->manufacture = (readarr[0] << 8) | readarr[1];
137 id->model = readarr[2];
Sean Nelson14ba6682010-02-26 05:48:29 +0000138 if (bytes > 3) {
Nico Huber43125762023-05-01 15:56:16 +0200139 id->model <<= 8;
140 id->model |= readarr[3];
Sean Nelson14ba6682010-02-26 05:48:29 +0000141 }
142 } else {
Nico Huber43125762023-05-01 15:56:16 +0200143 id->manufacture = readarr[0];
144 id->model = (readarr[1] << 8) | readarr[2];
Sean Nelson14ba6682010-02-26 05:48:29 +0000145 }
146
Nico Huber43125762023-05-01 15:56:16 +0200147 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000148
Nico Huber43125762023-05-01 15:56:16 +0200149 return found;
Sean Nelson14ba6682010-02-26 05:48:29 +0000150}
151
Nico Huberdae90222026-03-09 20:36:56 +0100152struct found_id *probe_spi_rems(const struct bus_probe *probe,
153 const struct master_common *mst,
154 const struct flashchip *chip)
Sean Nelson14ba6682010-02-26 05:48:29 +0000155{
Nico Huber64f53a12026-02-15 16:04:29 +0100156 const struct spi_master *const spi = (const struct spi_master *)mst;
Sean Nelson14ba6682010-02-26 05:48:29 +0000157 unsigned char readarr[JEDEC_REMS_INSIZE];
Sean Nelson14ba6682010-02-26 05:48:29 +0000158
Nico Huber64f53a12026-02-15 16:04:29 +0100159 if (spi_rems(spi, readarr) || flashprog_no_data(readarr, sizeof(readarr))) {
160 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000161 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000162
Nico Huber64f53a12026-02-15 16:04:29 +0100163 struct found_id *const found = calloc(1, sizeof(*found));
164 if (!found) {
165 msg_cerr("Out of memory!\n");
166 return NULL;
167 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000168
Nico Huber64f53a12026-02-15 16:04:29 +0100169 struct id_info *const id = &found->info.id;
Sean Nelson14ba6682010-02-26 05:48:29 +0000170
Nico Huber64f53a12026-02-15 16:04:29 +0100171 id->manufacture = readarr[0];
172 id->model = readarr[1];
173 id->type = ID_SPI_REMS;
Sean Nelson14ba6682010-02-26 05:48:29 +0000174
Nico Huber64f53a12026-02-15 16:04:29 +0100175 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000176
Nico Huber64f53a12026-02-15 16:04:29 +0100177 return found;
Sean Nelson14ba6682010-02-26 05:48:29 +0000178}
179
Nico Huberdae90222026-03-09 20:36:56 +0100180struct found_id *probe_spi_res(const struct bus_probe *probe,
181 const struct master_common *mst,
182 const struct flashchip *chip)
Sean Nelson14ba6682010-02-26 05:48:29 +0000183{
Nico Huber64f53a12026-02-15 16:04:29 +0100184 const struct spi_master *const spi = (const struct spi_master *)mst;
185 const unsigned int res_len = probe->type == ID_SPI_RES3 ? 3 :
186 (probe->type == ID_SPI_RES2 ? 2 : 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000187 unsigned char readarr[3];
Sean Nelson14ba6682010-02-26 05:48:29 +0000188
Nico Huber64f53a12026-02-15 16:04:29 +0100189 if (res_len == 1) {
190 /* We only want one-byte RES if RDID and REMS are unusable. */
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000191
Nico Huber64f53a12026-02-15 16:04:29 +0100192 if (!spi_rdid(spi, readarr, 3) && !flashprog_no_data(readarr, 3)) {
193 msg_cdbg("Ignoring RES in favour of RDID.\n");
194 return NULL;
195 }
196
197 if (!spi_rems(spi, readarr) && !flashprog_no_data(readarr, JEDEC_REMS_INSIZE)) {
198 msg_cdbg("Ignoring RES in favour of REMS.\n");
199 return NULL;
200 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000201 }
202
Nico Huber64f53a12026-02-15 16:04:29 +0100203 if (spi_res(spi, readarr, res_len) || flashprog_no_data(readarr, res_len)) {
204 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000205 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000206
Nico Huber64f53a12026-02-15 16:04:29 +0100207 struct found_id *const found = calloc(1, sizeof(*found));
208 if (!found) {
209 msg_cerr("Out of memory!\n");
210 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000211 }
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000212
Nico Huber64f53a12026-02-15 16:04:29 +0100213 struct id_info *const id = &found->info.id;
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000214
Nico Huber64f53a12026-02-15 16:04:29 +0100215 switch (res_len) {
216 case 1:
217 id->manufacture = 0;
218 id->model = readarr[0];
219 msg_cdbg("%s: id 0x%02x\n", __func__, id->model);
220 break;
221 case 2:
222 id->manufacture = readarr[0];
223 id->model = readarr[1];
224 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
225 break;
226 case 3:
227 id->manufacture = (readarr[0] << 8) | readarr[1];
228 id->model = readarr[2];
229 msg_cdbg("%s: id1 0x%04x, id2 0x%02x\n", __func__, id->id1, id->id2);
230 break;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000231 }
Nico Huber64f53a12026-02-15 16:04:29 +0100232 id->type = probe->type;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000233
Nico Huber64f53a12026-02-15 16:04:29 +0100234 return found;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000235}
236
Stefan Tauner57794ac2012-12-29 15:04:20 +0000237/* Only used for some Atmel chips. */
Nico Huberdae90222026-03-09 20:36:56 +0100238struct found_id *probe_spi_at25f(const struct bus_probe *probe,
239 const struct master_common *mst,
240 const struct flashchip *chip)
Stefan Tauner57794ac2012-12-29 15:04:20 +0000241{
242 static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
Nico Huber64f53a12026-02-15 16:04:29 +0100243 const struct spi_master *const spi = (const struct spi_master *)mst;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000244 unsigned char readarr[AT25F_RDID_INSIZE];
Stefan Tauner57794ac2012-12-29 15:04:20 +0000245
Nico Huber64f53a12026-02-15 16:04:29 +0100246 if (spi->command(spi, sizeof(cmd), sizeof(readarr), cmd, readarr))
247 return NULL;
248 if (flashprog_no_data(readarr, sizeof(readarr)))
249 return NULL;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000250
Nico Huber64f53a12026-02-15 16:04:29 +0100251 struct found_id *const found = calloc(1, sizeof(*found));
252 if (!found) {
253 msg_cerr("Out of memory!\n");
254 return NULL;
255 }
Stefan Tauner57794ac2012-12-29 15:04:20 +0000256
Nico Huber64f53a12026-02-15 16:04:29 +0100257 struct id_info *const id = &found->info.id;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000258
Nico Huber64f53a12026-02-15 16:04:29 +0100259 id->manufacture = readarr[0];
260 id->model = readarr[1];
261 id->type = ID_SPI_AT25F;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000262
Nico Huber64f53a12026-02-15 16:04:29 +0100263 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
264
265 return found;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000266}
267
Nico Huber0ecbacb2017-10-14 16:50:43 +0200268static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
269{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200270 /* FIXME: We don't time out. */
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100271 while (true) {
272 uint8_t status;
273 int ret = spi_read_register(flash, STATUS1, &status);
274 if (ret)
275 return ret;
276 if (!(status & SPI_SR_WIP))
277 return 0;
278
Nico Huber0ecbacb2017-10-14 16:50:43 +0200279 programmer_delay(poll_delay);
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100280 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200281}
282
Nico Hubera3140d02017-10-15 11:20:58 +0200283/**
284 * Execute WREN plus another one byte `op`, optionally poll WIP afterwards.
285 *
286 * @param flash the flash chip's context
287 * @param op the operation to execute
288 * @param poll_delay interval in us for polling WIP, don't poll if zero
289 * @return 0 on success, non-zero otherwise
290 */
Nico Huber8d0f4652024-05-04 18:52:51 +0200291int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, const unsigned int poll_delay)
Sean Nelson14ba6682010-02-26 05:48:29 +0000292{
Sean Nelson14ba6682010-02-26 05:48:29 +0000293 struct spi_command cmds[] = {
294 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200295 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000296 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100297 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200298 .writearr = (const unsigned char[]){ JEDEC_WREN },
Sean Nelson14ba6682010-02-26 05:48:29 +0000299 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200300 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000301 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100302 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200303 .writearr = (const unsigned char[]){ op },
304 },
305 NULL_SPI_CMD,
306 };
307
308 const int result = spi_send_multicommand(flash, cmds);
309 if (result)
310 msg_cerr("%s failed during command execution\n", __func__);
311
Nico Huber0ecbacb2017-10-14 16:50:43 +0200312 const int status = poll_delay ? spi_poll_wip(flash, poll_delay) : 0;
Nico Hubera3140d02017-10-15 11:20:58 +0200313
Nico Huber0ecbacb2017-10-14 16:50:43 +0200314 return result ? result : status;
315}
316
Nico Huber7e3c81a2017-10-14 18:56:50 +0200317static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
318{
Nico Huber9bb8a322022-05-24 15:07:34 +0200319 uint8_t op;
320 if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
321 op = JEDEC_WRITE_EXT_ADDR_REG;
322 } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
323 op = ALT_WRITE_EXT_ADDR_REG_17;
324 } else {
325 msg_cerr("Flash misses feature flag for extended-address register.\n");
326 return -1;
327 }
328
Nico Huber7e3c81a2017-10-14 18:56:50 +0200329 struct spi_command cmds[] = {
330 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200331 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000332 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100333 .opcode_len = 1,
Nico Huber7e3c81a2017-10-14 18:56:50 +0200334 .writearr = (const unsigned char[]){ JEDEC_WREN },
335 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200336 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000337 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100338 .opcode_len = 1,
339 .write_len = 1,
Nico Huber57dbd642018-03-13 18:01:05 +0100340 .writearr = (const unsigned char[]){ op, regdata },
Nico Huber7e3c81a2017-10-14 18:56:50 +0200341 },
342 NULL_SPI_CMD,
343 };
344
345 const int result = spi_send_multicommand(flash, cmds);
346 if (result)
347 msg_cerr("%s failed during command execution\n", __func__);
348 return result;
349}
350
Nico Huber7eb38aa2019-03-21 15:42:54 +0100351int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
Nico Huberf43c6542017-10-14 17:47:28 +0200352{
353 if (flash->address_high_byte != addr_high &&
354 spi_write_extended_address_register(flash, addr_high))
355 return -1;
356 flash->address_high_byte = addr_high;
357 return 0;
358}
359
Nico Huber4e6155a2025-01-02 23:05:09 +0100360static size_t spi_address_length(struct flashctx *const flash, const bool native_4ba)
361{
362 if (flash->chip->spi_cmd_set == SPI25_EEPROM) {
363 if (flashprog_flash_getsize(flash) > 64*KiB)
364 return 3;
365 if (flashprog_flash_getsize(flash) > 256)
366 return 2;
367 return 1;
368 }
369
370 if (native_4ba || flash->in_4ba_mode)
371 return 4;
372
373 return 3;
374}
375
Nico Hubera1672f82017-10-14 18:00:20 +0200376static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
Nico Hubere3f648c2023-02-15 02:55:23 +0100377 const bool native_4ba, const unsigned int rel_addr)
Nico Huber0ecbacb2017-10-14 16:50:43 +0200378{
Nico Huber4e6155a2025-01-02 23:05:09 +0100379 const size_t len = spi_address_length(flash, native_4ba);
Nico Hubere3f648c2023-02-15 02:55:23 +0100380 unsigned int addr = rel_addr;
381
382 if (spi_master_top_aligned(flash))
383 addr = rel_addr - flashprog_flash_getsize(flash); /* intentional integer underflow */
Nico Huber4e6155a2025-01-02 23:05:09 +0100384
385 switch (len) {
386 case 4:
Nico Huber1cf407b2017-11-10 20:18:23 +0100387 if (!spi_master_4ba(flash)) {
388 msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n");
389 return -1;
390 }
Nico Huberf43c6542017-10-14 17:47:28 +0200391 cmd_buf[1] = (addr >> 24) & 0xff;
392 cmd_buf[2] = (addr >> 16) & 0xff;
393 cmd_buf[3] = (addr >> 8) & 0xff;
394 cmd_buf[4] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100395 return len;
396 case 3:
Nico Huber9bb8a322022-05-24 15:07:34 +0200397 if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
Nico Hubere3f648c2023-02-15 02:55:23 +0100398 if (spi_set_extended_address(flash, rel_addr >> 24))
Nico Huberf43c6542017-10-14 17:47:28 +0200399 return -1;
Nico Hubere3f648c2023-02-15 02:55:23 +0100400 } else if (rel_addr >> 24) {
Nico Huber1cf407b2017-11-10 20:18:23 +0100401 msg_cerr("Can't handle 4-byte address for opcode '0x%02x'\n"
402 "with this chip/programmer combination.\n", cmd_buf[0]);
403 return -1;
Nico Huberf43c6542017-10-14 17:47:28 +0200404 }
405 cmd_buf[1] = (addr >> 16) & 0xff;
406 cmd_buf[2] = (addr >> 8) & 0xff;
407 cmd_buf[3] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100408 return len;
409 case 2:
410 cmd_buf[1] = (addr >> 8) & 0xff;
411 cmd_buf[2] = (addr >> 0) & 0xff;
412 return len;
413 default:
414 cmd_buf[1] = addr & 0xff;
415 return len;
Nico Huberf43c6542017-10-14 17:47:28 +0200416 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200417}
418
419/**
420 * Execute WREN plus another `op` that takes an address and
421 * optional data, poll WIP afterwards.
422 *
423 * @param flash the flash chip's context
424 * @param op the operation to execute
Nico Hubera1672f82017-10-14 18:00:20 +0200425 * @param native_4ba whether `op` always takes a 4-byte address
Nico Huber0ecbacb2017-10-14 16:50:43 +0200426 * @param addr the address parameter to `op`
427 * @param out_bytes bytes to send after the address,
428 * may be NULL if and only if `out_bytes` is 0
429 * @param out_bytes number of bytes to send, 256 at most, may be zero
430 * @param poll_delay interval in us for polling WIP
431 * @return 0 on success, non-zero otherwise
432 */
Nico Hubera1672f82017-10-14 18:00:20 +0200433static int spi_write_cmd(struct flashctx *const flash, const uint8_t op,
434 const bool native_4ba, const unsigned int addr,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200435 const uint8_t *const out_bytes, const size_t out_len,
436 const unsigned int poll_delay)
437{
438 uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN + 256];
439 struct spi_command cmds[] = {
440 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200441 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000442 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100443 .opcode_len = 1,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200444 .writearr = (const unsigned char[]){ JEDEC_WREN },
445 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200446 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000447 .readarr = 0,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200448 .writearr = cmd,
449 },
450 NULL_SPI_CMD,
451 };
452
453 cmd[0] = op;
Nico Hubera1672f82017-10-14 18:00:20 +0200454 const int addr_len = spi_prepare_address(flash, cmd, native_4ba, addr);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200455 if (addr_len < 0)
456 return 1;
457
458 if (1 + addr_len + out_len > sizeof(cmd)) {
459 msg_cerr("%s called for too long a write\n", __func__);
460 return 1;
461 }
Angel Ponsc92f6872020-03-31 15:32:10 +0200462 if (!out_bytes && out_len > 0)
463 return 1;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200464
465 memcpy(cmd + 1 + addr_len, out_bytes, out_len);
Nico Huberd5185632024-01-05 18:44:41 +0100466 cmds[1].opcode_len = 1;
467 cmds[1].address_len = addr_len;
468 cmds[1].write_len = out_len;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200469
470 const int result = spi_send_multicommand(flash, cmds);
471 if (result)
472 msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
473
474 const int status = spi_poll_wip(flash, poll_delay);
475
476 return result ? result : status;
Nico Hubera3140d02017-10-15 11:20:58 +0200477}
478
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600479static int spi_chip_erase_60(struct flashctx *flash)
Nico Hubera3140d02017-10-15 11:20:58 +0200480{
481 /* This usually takes 1-85s, so wait in 1s steps. */
482 return spi_simple_write_cmd(flash, 0x60, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000483}
484
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600485static int spi_chip_erase_62(struct flashctx *flash)
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000486{
Nico Hubera3140d02017-10-15 11:20:58 +0200487 /* This usually takes 2-5s, so wait in 100ms steps. */
488 return spi_simple_write_cmd(flash, 0x62, 100 * 1000);
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000489}
490
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600491static int spi_chip_erase_c7(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000492{
Nico Hubera3140d02017-10-15 11:20:58 +0200493 /* This usually takes 1-85s, so wait in 1s steps. */
494 return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000495}
496
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000497int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
498 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000499{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200500 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200501 return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000502}
503
504/* Block size is usually
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000505 * 32M (one die) for Micron
506 */
507int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
508{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200509 /* This usually takes 240-480s, so wait in 500ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200510 return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000);
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000511}
512
513/* Block size is usually
Sean Nelson14ba6682010-02-26 05:48:29 +0000514 * 64k for Macronix
515 * 32k for SST
516 * 4-32k non-uniform for EON
517 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000518int spi_block_erase_d8(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, 0xd8, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000523}
524
525/* Block size is usually
526 * 4k for PMC
527 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000528int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
529 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000530{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200531 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200532 return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000533}
534
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000535/* Page erase (usually 256B blocks) */
536int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
537{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200538 /* This takes up to 20ms usually (on worn out devices
539 up to the 0.5s range), so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200540 return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000541}
542
Sean Nelson14ba6682010-02-26 05:48:29 +0000543/* Sector size is usually 4k, though Macronix eliteflash has 64k */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000544int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
545 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000546{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200547 /* This usually takes 15-800ms, so wait in 10ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200548 return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000549}
550
Stefan Tauner94b39b42012-10-27 00:06:02 +0000551int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
552{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200553 /* This usually takes 10ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200554 return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000555}
556
557int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
558{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200559 /* This usually takes 8ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200560 return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000561}
562
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000563int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
564 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000565{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000566 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000567 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000568 __func__);
569 return -1;
570 }
571 return spi_chip_erase_60(flash);
572}
573
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000574int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
575{
576 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
577 msg_cerr("%s called with incorrect arguments\n",
578 __func__);
579 return -1;
580 }
581 return spi_chip_erase_62(flash);
582}
583
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000584int spi_block_erase_c7(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_c7(flash);
593}
594
Nico Huber7e3c81a2017-10-14 18:56:50 +0200595/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
596int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
597{
598 /* This usually takes 15-800ms, so wait in 10ms steps. */
599 return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
600}
601
602/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huberfffc48d2022-05-28 14:26:06 +0200603int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
604{
605 /* This usually takes 100-4000ms, so wait in 100ms steps. */
606 return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
607}
608
609/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huber7e3c81a2017-10-14 18:56:50 +0200610int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
611{
612 /* This usually takes 100-4000ms, so wait in 100ms steps. */
613 return spi_write_cmd(flash, 0x5c, true, addr, NULL, 0, 100 * 1000);
614}
615
616/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
617int spi_block_erase_dc(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, 0xdc, true, addr, NULL, 0, 100 * 1000);
621}
622
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530623static const struct {
624 erasefunc_t *func;
625 uint8_t opcode;
Thomas Heijligen35614512022-09-19 23:46:58 +0200626} spi25_function_opcode_list[] = {
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530627 {&spi_block_erase_20, 0x20},
628 {&spi_block_erase_21, 0x21},
629 {&spi_block_erase_50, 0x50},
630 {&spi_block_erase_52, 0x52},
631 {&spi_block_erase_53, 0x53},
632 {&spi_block_erase_5c, 0x5c},
633 {&spi_block_erase_60, 0x60},
634 {&spi_block_erase_62, 0x62},
635 {&spi_block_erase_81, 0x81},
636 {&spi_block_erase_c4, 0xc4},
637 {&spi_block_erase_c7, 0xc7},
638 {&spi_block_erase_d7, 0xd7},
639 {&spi_block_erase_d8, 0xd8},
640 {&spi_block_erase_db, 0xdb},
641 {&spi_block_erase_dc, 0xdc},
642};
643
Thomas Heijligen35614512022-09-19 23:46:58 +0200644erasefunc_t *spi25_get_erasefn_from_opcode(uint8_t opcode)
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000645{
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530646 size_t i;
Thomas Heijligen35614512022-09-19 23:46:58 +0200647 for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
648 if (spi25_function_opcode_list[i].opcode == opcode)
649 return spi25_function_opcode_list[i].func;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000650 }
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530651 msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
Nico Huberc3b02dc2023-08-12 01:13:45 +0200652 "this at flashprog@flashprog.org\n", __func__, opcode);
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530653 return NULL;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000654}
655
Nico Huber0ecbacb2017-10-14 16:50:43 +0200656static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000657{
Nico Huber1cf407b2017-11-10 20:18:23 +0100658 const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash);
Nico Hubera1672f82017-10-14 18:00:20 +0200659 const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM;
660 return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10);
Sean Nelson14ba6682010-02-26 05:48:29 +0000661}
662
Nico Hubera1b7f352024-03-25 18:32:11 +0100663const struct spi_read_op *get_spi_read_op(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100664{
665 static const struct spi_read_op sio_read = { SINGLE_IO_1_1_1, false, JEDEC_READ, 0x00, 0 };
666 static const struct spi_read_op sio_read_4ba = { SINGLE_IO_1_1_1, true, JEDEC_READ_4BA, 0x00, 0 };
667
668 if (flash->spi_fast_read)
669 return flash->spi_fast_read;
670
671 if (flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash))
672 return &sio_read_4ba;
673
674 return &sio_read;
675}
676
Nico Huberca1c7fd2023-04-28 21:44:41 +0000677int spi_nbyte_read(struct flashctx *flash, uint8_t *dst, unsigned int address, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000678{
Nico Huber4760b6e2024-01-06 23:45:28 +0100679 const struct spi_read_op *const read_op = get_spi_read_op(flash);
680 const size_t mode_len = read_op->mode_byte ? 1 : 0;
Nico Huber648dfdc2024-12-06 23:00:30 +0100681 uint8_t cmd_buf[1 + JEDEC_MAX_ADDR_LEN + 1] = { read_op->opcode, };
Nico Huber0ecbacb2017-10-14 16:50:43 +0200682
Nico Huber4760b6e2024-01-06 23:45:28 +0100683 const int addr_len = spi_prepare_address(flash, cmd_buf, read_op->native_4ba, address);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200684 if (addr_len < 0)
685 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000686
Nico Huber4760b6e2024-01-06 23:45:28 +0100687 cmd_buf[addr_len + 1] = read_op->mode_byte;
688
689 struct spi_command cmd[] = {
690 {
691 .io_mode = read_op->io_mode,
692 .opcode_len = 1,
693 .address_len = addr_len,
694 .write_len = mode_len,
695 .high_z_len = read_op->dummy_len - mode_len,
696 .read_len = len,
697 .writearr = cmd_buf,
698 .readarr = dst,
699 },
700 NULL_SPI_CMD
701 };
702
703 return spi_send_multicommand(flash, cmd);
Sean Nelson14ba6682010-02-26 05:48:29 +0000704}
705
706/*
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000707 * Write a part of the flash chip.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000708 * FIXME: Use the chunk code from Michael Karcher instead.
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000709 * Each page is written separately in chunks with a maximum size of chunksize.
710 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000711int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000712 unsigned int len, unsigned int chunksize)
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000713{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000714 unsigned int i, j, starthere, lenhere, towrite;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000715 /* FIXME: page_size is the wrong variable. We need max_writechunk_size
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000716 * in struct flashctx to do this properly. All chips using
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000717 * spi_chip_write_256 have page_size set to max_writechunk_size, so
718 * we're OK for now.
719 */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000720 unsigned int page_size = flash->chip->page_size;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000721
722 /* Warning: This loop has a very unusual condition and body.
723 * The loop needs to go through each page with at least one affected
724 * byte. The lowest page number is (start / page_size) since that
725 * division rounds down. The highest page number we want is the page
726 * where the last byte of the range lives. That last byte has the
727 * address (start + len - 1), thus the highest page number is
728 * (start + len - 1) / page_size. Since we want to include that last
729 * page as well, the loop condition uses <=.
730 */
731 for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
732 /* Byte position of the first byte in the range in this page. */
733 /* starthere is an offset to the base address of the chip. */
734 starthere = max(start, i * page_size);
735 /* Length of bytes in the range in this page. */
736 lenhere = min(start + len, (i + 1) * page_size) - starthere;
737 for (j = 0; j < lenhere; j += chunksize) {
Nico Huber7a077222017-10-14 18:18:30 +0200738 int rc;
739
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000740 towrite = min(chunksize, lenhere - j);
Nico Huber7a077222017-10-14 18:18:30 +0200741 rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000742 if (rc)
Nico Huber7a077222017-10-14 18:18:30 +0200743 return rc;
Richard Hughes842d6782021-01-15 09:48:12 +0000744 flashprog_progress_add(flash, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000745 }
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000746 }
747
Nico Huber7a077222017-10-14 18:18:30 +0200748 return 0;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000749}
750
751/*
Sean Nelson14ba6682010-02-26 05:48:29 +0000752 * Program chip using byte programming. (SLOW!)
753 * This is for chips which can only handle one byte writes
754 * and for chips where memory mapped programming is impossible
755 * (e.g. due to size constraints in IT87* for over 512 kB)
756 */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000757/* real chunksize is 1, logical chunksize is 1 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000758int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000759{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000760 unsigned int i;
Sean Nelson14ba6682010-02-26 05:48:29 +0000761
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000762 for (i = start; i < start + len; i++) {
Nico Huber7a077222017-10-14 18:18:30 +0200763 if (spi_nbyte_program(flash, i, buf + i - start, 1))
Sean Nelson14ba6682010-02-26 05:48:29 +0000764 return 1;
Richard Hughes842d6782021-01-15 09:48:12 +0000765 flashprog_progress_add(flash, 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000766 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000767 return 0;
768}
769
Mark Marshallf20b7be2014-05-09 21:16:21 +0000770int 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 +0000771{
772 uint32_t pos = start;
Sean Nelson14ba6682010-02-26 05:48:29 +0000773 int result;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000774 unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
775 JEDEC_AAI_WORD_PROGRAM,
776 };
Sean Nelson14ba6682010-02-26 05:48:29 +0000777
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000778 /* The even start address and even length requirements can be either
779 * honored outside this function, or we can call spi_byte_program
780 * for the first and/or last byte and use AAI for the rest.
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000781 * FIXME: Move this to generic code.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000782 */
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000783 /* The data sheet requires a start address with the low bit cleared. */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000784 if (start % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000785 msg_cerr("%s: start address not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200786 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000787 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000788 if (spi_chip_write_1(flash, buf, start, start % 2))
789 return SPI_GENERIC_ERROR;
790 pos += start % 2;
791 /* Do not return an error for now. */
792 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000793 }
794 /* The data sheet requires total AAI write length to be even. */
795 if (len % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000796 msg_cerr("%s: total write length not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200797 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000798 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000799 /* Do not return an error for now. */
800 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000801 }
802
Nico Hubera1672f82017-10-14 18:00:20 +0200803 result = spi_write_cmd(flash, JEDEC_AAI_WORD_PROGRAM, false, start, buf + pos - start, 2, 10);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200804 if (result)
Stefan Reinauer87ace662014-04-26 16:12:55 +0000805 goto bailout;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000806
807 /* We already wrote 2 bytes in the multicommand step. */
Richard Hughes842d6782021-01-15 09:48:12 +0000808 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000809 pos += 2;
810
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000811 /* Are there at least two more bytes to write? */
812 while (pos < start + len - 1) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000813 cmd[1] = buf[pos++ - start];
814 cmd[2] = buf[pos++ - start];
Stefan Reinauer87ace662014-04-26 16:12:55 +0000815 result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
816 if (result != 0) {
817 msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
818 goto bailout;
819 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200820 if (spi_poll_wip(flash, 10))
821 goto bailout;
Richard Hughes842d6782021-01-15 09:48:12 +0000822 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000823 }
824
Stefan Tauner59c4d792014-04-26 16:13:09 +0000825 /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
826 result = spi_write_disable(flash);
827 if (result != 0) {
828 msg_cerr("%s failed to disable AAI mode.\n", __func__);
829 return SPI_GENERIC_ERROR;
830 }
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000831
832 /* Write remaining byte (if any). */
833 if (pos < start + len) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000834 if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000835 return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000836 }
837
Sean Nelson14ba6682010-02-26 05:48:29 +0000838 return 0;
Stefan Reinauer87ace662014-04-26 16:12:55 +0000839
840bailout:
Stefan Tauner59c4d792014-04-26 16:13:09 +0000841 result = spi_write_disable(flash);
842 if (result != 0)
843 msg_cerr("%s failed to disable AAI mode.\n", __func__);
Stefan Reinauer87ace662014-04-26 16:12:55 +0000844 return SPI_GENERIC_ERROR;
Sean Nelson14ba6682010-02-26 05:48:29 +0000845}