blob: d1ce38ec2b0d72b3c675673e8446beff9aa655b9 [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
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 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
Nico Huber64f53a12026-02-15 16:04:29 +0100150struct found_id *probe_spi_rems(const struct bus_probe *probe, const struct master_common *mst)
Sean Nelson14ba6682010-02-26 05:48:29 +0000151{
Nico Huber64f53a12026-02-15 16:04:29 +0100152 const struct spi_master *const spi = (const struct spi_master *)mst;
Sean Nelson14ba6682010-02-26 05:48:29 +0000153 unsigned char readarr[JEDEC_REMS_INSIZE];
Sean Nelson14ba6682010-02-26 05:48:29 +0000154
Nico Huber64f53a12026-02-15 16:04:29 +0100155 if (spi_rems(spi, readarr) || flashprog_no_data(readarr, sizeof(readarr))) {
156 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000157 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000158
Nico Huber64f53a12026-02-15 16:04:29 +0100159 struct found_id *const found = calloc(1, sizeof(*found));
160 if (!found) {
161 msg_cerr("Out of memory!\n");
162 return NULL;
163 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000164
Nico Huber64f53a12026-02-15 16:04:29 +0100165 struct id_info *const id = &found->info.id;
Sean Nelson14ba6682010-02-26 05:48:29 +0000166
Nico Huber64f53a12026-02-15 16:04:29 +0100167 id->manufacture = readarr[0];
168 id->model = readarr[1];
169 id->type = ID_SPI_REMS;
Sean Nelson14ba6682010-02-26 05:48:29 +0000170
Nico Huber64f53a12026-02-15 16:04:29 +0100171 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
Sean Nelson14ba6682010-02-26 05:48:29 +0000172
Nico Huber64f53a12026-02-15 16:04:29 +0100173 return found;
Sean Nelson14ba6682010-02-26 05:48:29 +0000174}
175
Nico Huber64f53a12026-02-15 16:04:29 +0100176struct found_id *probe_spi_res(const struct bus_probe *probe, const struct master_common *mst)
Sean Nelson14ba6682010-02-26 05:48:29 +0000177{
Nico Huber64f53a12026-02-15 16:04:29 +0100178 const struct spi_master *const spi = (const struct spi_master *)mst;
179 const unsigned int res_len = probe->type == ID_SPI_RES3 ? 3 :
180 (probe->type == ID_SPI_RES2 ? 2 : 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000181 unsigned char readarr[3];
Sean Nelson14ba6682010-02-26 05:48:29 +0000182
Nico Huber64f53a12026-02-15 16:04:29 +0100183 if (res_len == 1) {
184 /* We only want one-byte RES if RDID and REMS are unusable. */
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000185
Nico Huber64f53a12026-02-15 16:04:29 +0100186 if (!spi_rdid(spi, readarr, 3) && !flashprog_no_data(readarr, 3)) {
187 msg_cdbg("Ignoring RES in favour of RDID.\n");
188 return NULL;
189 }
190
191 if (!spi_rems(spi, readarr) && !flashprog_no_data(readarr, JEDEC_REMS_INSIZE)) {
192 msg_cdbg("Ignoring RES in favour of REMS.\n");
193 return NULL;
194 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000195 }
196
Nico Huber64f53a12026-02-15 16:04:29 +0100197 if (spi_res(spi, readarr, res_len) || flashprog_no_data(readarr, res_len)) {
198 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000199 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000200
Nico Huber64f53a12026-02-15 16:04:29 +0100201 struct found_id *const found = calloc(1, sizeof(*found));
202 if (!found) {
203 msg_cerr("Out of memory!\n");
204 return NULL;
Stefan Tauner355cbfd2011-05-28 02:37:14 +0000205 }
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000206
Nico Huber64f53a12026-02-15 16:04:29 +0100207 struct id_info *const id = &found->info.id;
Carl-Daniel Hailfingerdc1cda12010-05-28 17:07:57 +0000208
Nico Huber64f53a12026-02-15 16:04:29 +0100209 switch (res_len) {
210 case 1:
211 id->manufacture = 0;
212 id->model = readarr[0];
213 msg_cdbg("%s: id 0x%02x\n", __func__, id->model);
214 break;
215 case 2:
216 id->manufacture = readarr[0];
217 id->model = readarr[1];
218 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
219 break;
220 case 3:
221 id->manufacture = (readarr[0] << 8) | readarr[1];
222 id->model = readarr[2];
223 msg_cdbg("%s: id1 0x%04x, id2 0x%02x\n", __func__, id->id1, id->id2);
224 break;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000225 }
Nico Huber64f53a12026-02-15 16:04:29 +0100226 id->type = probe->type;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000227
Nico Huber64f53a12026-02-15 16:04:29 +0100228 return found;
Stefan Tauner3f5e35d2013-04-19 01:58:33 +0000229}
230
Stefan Tauner57794ac2012-12-29 15:04:20 +0000231/* Only used for some Atmel chips. */
Nico Huber64f53a12026-02-15 16:04:29 +0100232struct found_id *probe_spi_at25f(const struct bus_probe *probe, const struct master_common *mst)
Stefan Tauner57794ac2012-12-29 15:04:20 +0000233{
234 static const unsigned char cmd[AT25F_RDID_OUTSIZE] = { AT25F_RDID };
Nico Huber64f53a12026-02-15 16:04:29 +0100235 const struct spi_master *const spi = (const struct spi_master *)mst;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000236 unsigned char readarr[AT25F_RDID_INSIZE];
Stefan Tauner57794ac2012-12-29 15:04:20 +0000237
Nico Huber64f53a12026-02-15 16:04:29 +0100238 if (spi->command(spi, sizeof(cmd), sizeof(readarr), cmd, readarr))
239 return NULL;
240 if (flashprog_no_data(readarr, sizeof(readarr)))
241 return NULL;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000242
Nico Huber64f53a12026-02-15 16:04:29 +0100243 struct found_id *const found = calloc(1, sizeof(*found));
244 if (!found) {
245 msg_cerr("Out of memory!\n");
246 return NULL;
247 }
Stefan Tauner57794ac2012-12-29 15:04:20 +0000248
Nico Huber64f53a12026-02-15 16:04:29 +0100249 struct id_info *const id = &found->info.id;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000250
Nico Huber64f53a12026-02-15 16:04:29 +0100251 id->manufacture = readarr[0];
252 id->model = readarr[1];
253 id->type = ID_SPI_AT25F;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000254
Nico Huber64f53a12026-02-15 16:04:29 +0100255 msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id->id1, id->id2);
256
257 return found;
Stefan Tauner57794ac2012-12-29 15:04:20 +0000258}
259
Nico Huber0ecbacb2017-10-14 16:50:43 +0200260static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
261{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200262 /* FIXME: We don't time out. */
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100263 while (true) {
264 uint8_t status;
265 int ret = spi_read_register(flash, STATUS1, &status);
266 if (ret)
267 return ret;
268 if (!(status & SPI_SR_WIP))
269 return 0;
270
Nico Huber0ecbacb2017-10-14 16:50:43 +0200271 programmer_delay(poll_delay);
Nikolai Artemievb8a90d02021-10-28 16:18:28 +1100272 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200273}
274
Nico Hubera3140d02017-10-15 11:20:58 +0200275/**
276 * Execute WREN plus another one byte `op`, optionally poll WIP afterwards.
277 *
278 * @param flash the flash chip's context
279 * @param op the operation to execute
280 * @param poll_delay interval in us for polling WIP, don't poll if zero
281 * @return 0 on success, non-zero otherwise
282 */
Nico Huber8d0f4652024-05-04 18:52:51 +0200283int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op, const unsigned int poll_delay)
Sean Nelson14ba6682010-02-26 05:48:29 +0000284{
Sean Nelson14ba6682010-02-26 05:48:29 +0000285 struct spi_command cmds[] = {
286 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200287 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000288 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100289 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200290 .writearr = (const unsigned char[]){ JEDEC_WREN },
Sean Nelson14ba6682010-02-26 05:48:29 +0000291 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200292 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000293 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100294 .opcode_len = 1,
Nico Hubera3140d02017-10-15 11:20:58 +0200295 .writearr = (const unsigned char[]){ op },
296 },
297 NULL_SPI_CMD,
298 };
299
300 const int result = spi_send_multicommand(flash, cmds);
301 if (result)
302 msg_cerr("%s failed during command execution\n", __func__);
303
Nico Huber0ecbacb2017-10-14 16:50:43 +0200304 const int status = poll_delay ? spi_poll_wip(flash, poll_delay) : 0;
Nico Hubera3140d02017-10-15 11:20:58 +0200305
Nico Huber0ecbacb2017-10-14 16:50:43 +0200306 return result ? result : status;
307}
308
Nico Huber7e3c81a2017-10-14 18:56:50 +0200309static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
310{
Nico Huber9bb8a322022-05-24 15:07:34 +0200311 uint8_t op;
312 if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
313 op = JEDEC_WRITE_EXT_ADDR_REG;
314 } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
315 op = ALT_WRITE_EXT_ADDR_REG_17;
316 } else {
317 msg_cerr("Flash misses feature flag for extended-address register.\n");
318 return -1;
319 }
320
Nico Huber7e3c81a2017-10-14 18:56:50 +0200321 struct spi_command cmds[] = {
322 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200323 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000324 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100325 .opcode_len = 1,
Nico Huber7e3c81a2017-10-14 18:56:50 +0200326 .writearr = (const unsigned char[]){ JEDEC_WREN },
327 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200328 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000329 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100330 .opcode_len = 1,
331 .write_len = 1,
Nico Huber57dbd642018-03-13 18:01:05 +0100332 .writearr = (const unsigned char[]){ op, regdata },
Nico Huber7e3c81a2017-10-14 18:56:50 +0200333 },
334 NULL_SPI_CMD,
335 };
336
337 const int result = spi_send_multicommand(flash, cmds);
338 if (result)
339 msg_cerr("%s failed during command execution\n", __func__);
340 return result;
341}
342
Nico Huber7eb38aa2019-03-21 15:42:54 +0100343int spi_set_extended_address(struct flashctx *const flash, const uint8_t addr_high)
Nico Huberf43c6542017-10-14 17:47:28 +0200344{
345 if (flash->address_high_byte != addr_high &&
346 spi_write_extended_address_register(flash, addr_high))
347 return -1;
348 flash->address_high_byte = addr_high;
349 return 0;
350}
351
Nico Huber4e6155a2025-01-02 23:05:09 +0100352static size_t spi_address_length(struct flashctx *const flash, const bool native_4ba)
353{
354 if (flash->chip->spi_cmd_set == SPI25_EEPROM) {
355 if (flashprog_flash_getsize(flash) > 64*KiB)
356 return 3;
357 if (flashprog_flash_getsize(flash) > 256)
358 return 2;
359 return 1;
360 }
361
362 if (native_4ba || flash->in_4ba_mode)
363 return 4;
364
365 return 3;
366}
367
Nico Hubera1672f82017-10-14 18:00:20 +0200368static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
Nico Hubere3f648c2023-02-15 02:55:23 +0100369 const bool native_4ba, const unsigned int rel_addr)
Nico Huber0ecbacb2017-10-14 16:50:43 +0200370{
Nico Huber4e6155a2025-01-02 23:05:09 +0100371 const size_t len = spi_address_length(flash, native_4ba);
Nico Hubere3f648c2023-02-15 02:55:23 +0100372 unsigned int addr = rel_addr;
373
374 if (spi_master_top_aligned(flash))
375 addr = rel_addr - flashprog_flash_getsize(flash); /* intentional integer underflow */
Nico Huber4e6155a2025-01-02 23:05:09 +0100376
377 switch (len) {
378 case 4:
Nico Huber1cf407b2017-11-10 20:18:23 +0100379 if (!spi_master_4ba(flash)) {
380 msg_cwarn("4-byte address requested but master can't handle 4-byte addresses.\n");
381 return -1;
382 }
Nico Huberf43c6542017-10-14 17:47:28 +0200383 cmd_buf[1] = (addr >> 24) & 0xff;
384 cmd_buf[2] = (addr >> 16) & 0xff;
385 cmd_buf[3] = (addr >> 8) & 0xff;
386 cmd_buf[4] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100387 return len;
388 case 3:
Nico Huber9bb8a322022-05-24 15:07:34 +0200389 if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
Nico Hubere3f648c2023-02-15 02:55:23 +0100390 if (spi_set_extended_address(flash, rel_addr >> 24))
Nico Huberf43c6542017-10-14 17:47:28 +0200391 return -1;
Nico Hubere3f648c2023-02-15 02:55:23 +0100392 } else if (rel_addr >> 24) {
Nico Huber1cf407b2017-11-10 20:18:23 +0100393 msg_cerr("Can't handle 4-byte address for opcode '0x%02x'\n"
394 "with this chip/programmer combination.\n", cmd_buf[0]);
395 return -1;
Nico Huberf43c6542017-10-14 17:47:28 +0200396 }
397 cmd_buf[1] = (addr >> 16) & 0xff;
398 cmd_buf[2] = (addr >> 8) & 0xff;
399 cmd_buf[3] = (addr >> 0) & 0xff;
Nico Huber4e6155a2025-01-02 23:05:09 +0100400 return len;
401 case 2:
402 cmd_buf[1] = (addr >> 8) & 0xff;
403 cmd_buf[2] = (addr >> 0) & 0xff;
404 return len;
405 default:
406 cmd_buf[1] = addr & 0xff;
407 return len;
Nico Huberf43c6542017-10-14 17:47:28 +0200408 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200409}
410
411/**
412 * Execute WREN plus another `op` that takes an address and
413 * optional data, poll WIP afterwards.
414 *
415 * @param flash the flash chip's context
416 * @param op the operation to execute
Nico Hubera1672f82017-10-14 18:00:20 +0200417 * @param native_4ba whether `op` always takes a 4-byte address
Nico Huber0ecbacb2017-10-14 16:50:43 +0200418 * @param addr the address parameter to `op`
419 * @param out_bytes bytes to send after the address,
420 * may be NULL if and only if `out_bytes` is 0
421 * @param out_bytes number of bytes to send, 256 at most, may be zero
422 * @param poll_delay interval in us for polling WIP
423 * @return 0 on success, non-zero otherwise
424 */
Nico Hubera1672f82017-10-14 18:00:20 +0200425static int spi_write_cmd(struct flashctx *const flash, const uint8_t op,
426 const bool native_4ba, const unsigned int addr,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200427 const uint8_t *const out_bytes, const size_t out_len,
428 const unsigned int poll_delay)
429{
430 uint8_t cmd[1 + JEDEC_MAX_ADDR_LEN + 256];
431 struct spi_command cmds[] = {
432 {
Nico Huber1b1deda2024-04-18 00:35:48 +0200433 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000434 .readarr = 0,
Nico Huberd5185632024-01-05 18:44:41 +0100435 .opcode_len = 1,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200436 .writearr = (const unsigned char[]){ JEDEC_WREN },
437 }, {
Nico Huber1b1deda2024-04-18 00:35:48 +0200438 .io_mode = spi_current_io_mode(flash),
Richard Hughesdf490582018-12-19 11:57:15 +0000439 .readarr = 0,
Nico Huber0ecbacb2017-10-14 16:50:43 +0200440 .writearr = cmd,
441 },
442 NULL_SPI_CMD,
443 };
444
445 cmd[0] = op;
Nico Hubera1672f82017-10-14 18:00:20 +0200446 const int addr_len = spi_prepare_address(flash, cmd, native_4ba, addr);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200447 if (addr_len < 0)
448 return 1;
449
450 if (1 + addr_len + out_len > sizeof(cmd)) {
451 msg_cerr("%s called for too long a write\n", __func__);
452 return 1;
453 }
Angel Ponsc92f6872020-03-31 15:32:10 +0200454 if (!out_bytes && out_len > 0)
455 return 1;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200456
457 memcpy(cmd + 1 + addr_len, out_bytes, out_len);
Nico Huberd5185632024-01-05 18:44:41 +0100458 cmds[1].opcode_len = 1;
459 cmds[1].address_len = addr_len;
460 cmds[1].write_len = out_len;
Nico Huber0ecbacb2017-10-14 16:50:43 +0200461
462 const int result = spi_send_multicommand(flash, cmds);
463 if (result)
464 msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
465
466 const int status = spi_poll_wip(flash, poll_delay);
467
468 return result ? result : status;
Nico Hubera3140d02017-10-15 11:20:58 +0200469}
470
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600471static int spi_chip_erase_60(struct flashctx *flash)
Nico Hubera3140d02017-10-15 11:20:58 +0200472{
473 /* This usually takes 1-85s, so wait in 1s steps. */
474 return spi_simple_write_cmd(flash, 0x60, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000475}
476
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600477static int spi_chip_erase_62(struct flashctx *flash)
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000478{
Nico Hubera3140d02017-10-15 11:20:58 +0200479 /* This usually takes 2-5s, so wait in 100ms steps. */
480 return spi_simple_write_cmd(flash, 0x62, 100 * 1000);
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000481}
482
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600483static int spi_chip_erase_c7(struct flashctx *flash)
Sean Nelson14ba6682010-02-26 05:48:29 +0000484{
Nico Hubera3140d02017-10-15 11:20:58 +0200485 /* This usually takes 1-85s, so wait in 1s steps. */
486 return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000487}
488
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000489int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
490 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000491{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200492 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200493 return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000494}
495
496/* Block size is usually
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000497 * 32M (one die) for Micron
498 */
499int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
500{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200501 /* This usually takes 240-480s, so wait in 500ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200502 return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000);
Nikolay Nikolaev6f59b0b2013-06-28 21:29:51 +0000503}
504
505/* Block size is usually
Sean Nelson14ba6682010-02-26 05:48:29 +0000506 * 64k for Macronix
507 * 32k for SST
508 * 4-32k non-uniform for EON
509 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000510int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
511 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000512{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200513 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200514 return spi_write_cmd(flash, 0xd8, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000515}
516
517/* Block size is usually
518 * 4k for PMC
519 */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000520int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
521 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000522{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200523 /* This usually takes 100-4000ms, so wait in 100ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200524 return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000525}
526
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000527/* Page erase (usually 256B blocks) */
528int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
529{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200530 /* This takes up to 20ms usually (on worn out devices
531 up to the 0.5s range), so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200532 return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
Nikolay Nikolaev579f1e02013-06-28 21:28:37 +0000533}
534
Sean Nelson14ba6682010-02-26 05:48:29 +0000535/* Sector size is usually 4k, though Macronix eliteflash has 64k */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000536int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
537 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000538{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200539 /* This usually takes 15-800ms, so wait in 10ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200540 return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000);
Sean Nelson14ba6682010-02-26 05:48:29 +0000541}
542
Stefan Tauner94b39b42012-10-27 00:06:02 +0000543int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
544{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200545 /* This usually takes 10ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200546 return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000547}
548
549int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
550{
Nico Huber0ecbacb2017-10-14 16:50:43 +0200551 /* This usually takes 8ms, so wait in 1ms steps. */
Nico Hubera1672f82017-10-14 18:00:20 +0200552 return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000);
Stefan Tauner94b39b42012-10-27 00:06:02 +0000553}
554
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000555int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
556 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000557{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000558 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000559 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000560 __func__);
561 return -1;
562 }
563 return spi_chip_erase_60(flash);
564}
565
Stefan Tauner3c0fcd02012-09-21 12:46:56 +0000566int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
567{
568 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
569 msg_cerr("%s called with incorrect arguments\n",
570 __func__);
571 return -1;
572 }
573 return spi_chip_erase_62(flash);
574}
575
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000576int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
577 unsigned int blocklen)
Sean Nelson14ba6682010-02-26 05:48:29 +0000578{
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000579 if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000580 msg_cerr("%s called with incorrect arguments\n",
Sean Nelson14ba6682010-02-26 05:48:29 +0000581 __func__);
582 return -1;
583 }
584 return spi_chip_erase_c7(flash);
585}
586
Nico Huber7e3c81a2017-10-14 18:56:50 +0200587/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
588int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
589{
590 /* This usually takes 15-800ms, so wait in 10ms steps. */
591 return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
592}
593
594/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huberfffc48d2022-05-28 14:26:06 +0200595int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
596{
597 /* This usually takes 100-4000ms, so wait in 100ms steps. */
598 return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
599}
600
601/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
Nico Huber7e3c81a2017-10-14 18:56:50 +0200602int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
603{
604 /* This usually takes 100-4000ms, so wait in 100ms steps. */
605 return spi_write_cmd(flash, 0x5c, true, addr, NULL, 0, 100 * 1000);
606}
607
608/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
609int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
610{
611 /* This usually takes 100-4000ms, so wait in 100ms steps. */
612 return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000);
613}
614
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530615static const struct {
616 erasefunc_t *func;
617 uint8_t opcode;
Thomas Heijligen35614512022-09-19 23:46:58 +0200618} spi25_function_opcode_list[] = {
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530619 {&spi_block_erase_20, 0x20},
620 {&spi_block_erase_21, 0x21},
621 {&spi_block_erase_50, 0x50},
622 {&spi_block_erase_52, 0x52},
623 {&spi_block_erase_53, 0x53},
624 {&spi_block_erase_5c, 0x5c},
625 {&spi_block_erase_60, 0x60},
626 {&spi_block_erase_62, 0x62},
627 {&spi_block_erase_81, 0x81},
628 {&spi_block_erase_c4, 0xc4},
629 {&spi_block_erase_c7, 0xc7},
630 {&spi_block_erase_d7, 0xd7},
631 {&spi_block_erase_d8, 0xd8},
632 {&spi_block_erase_db, 0xdb},
633 {&spi_block_erase_dc, 0xdc},
634};
635
Thomas Heijligen35614512022-09-19 23:46:58 +0200636erasefunc_t *spi25_get_erasefn_from_opcode(uint8_t opcode)
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000637{
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530638 size_t i;
Thomas Heijligen35614512022-09-19 23:46:58 +0200639 for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
640 if (spi25_function_opcode_list[i].opcode == opcode)
641 return spi25_function_opcode_list[i].func;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000642 }
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530643 msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
Nico Huberc3b02dc2023-08-12 01:13:45 +0200644 "this at flashprog@flashprog.org\n", __func__, opcode);
Aarya Chaumalb725c0c2022-06-23 16:12:12 +0530645 return NULL;
Stefan Taunerac1b4c82012-02-17 14:51:04 +0000646}
647
Nico Huber0ecbacb2017-10-14 16:50:43 +0200648static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000649{
Nico Huber1cf407b2017-11-10 20:18:23 +0100650 const bool native_4ba = flash->chip->feature_bits & FEATURE_4BA_WRITE && spi_master_4ba(flash);
Nico Hubera1672f82017-10-14 18:00:20 +0200651 const uint8_t op = native_4ba ? JEDEC_BYTE_PROGRAM_4BA : JEDEC_BYTE_PROGRAM;
652 return spi_write_cmd(flash, op, native_4ba, addr, bytes, len, 10);
Sean Nelson14ba6682010-02-26 05:48:29 +0000653}
654
Nico Hubera1b7f352024-03-25 18:32:11 +0100655const struct spi_read_op *get_spi_read_op(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100656{
657 static const struct spi_read_op sio_read = { SINGLE_IO_1_1_1, false, JEDEC_READ, 0x00, 0 };
658 static const struct spi_read_op sio_read_4ba = { SINGLE_IO_1_1_1, true, JEDEC_READ_4BA, 0x00, 0 };
659
660 if (flash->spi_fast_read)
661 return flash->spi_fast_read;
662
663 if (flash->chip->feature_bits & FEATURE_4BA_READ && spi_master_4ba(flash))
664 return &sio_read_4ba;
665
666 return &sio_read;
667}
668
Nico Huberca1c7fd2023-04-28 21:44:41 +0000669int spi_nbyte_read(struct flashctx *flash, uint8_t *dst, unsigned int address, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000670{
Nico Huber4760b6e2024-01-06 23:45:28 +0100671 const struct spi_read_op *const read_op = get_spi_read_op(flash);
672 const size_t mode_len = read_op->mode_byte ? 1 : 0;
Nico Huber648dfdc2024-12-06 23:00:30 +0100673 uint8_t cmd_buf[1 + JEDEC_MAX_ADDR_LEN + 1] = { read_op->opcode, };
Nico Huber0ecbacb2017-10-14 16:50:43 +0200674
Nico Huber4760b6e2024-01-06 23:45:28 +0100675 const int addr_len = spi_prepare_address(flash, cmd_buf, read_op->native_4ba, address);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200676 if (addr_len < 0)
677 return 1;
Sean Nelson14ba6682010-02-26 05:48:29 +0000678
Nico Huber4760b6e2024-01-06 23:45:28 +0100679 cmd_buf[addr_len + 1] = read_op->mode_byte;
680
681 struct spi_command cmd[] = {
682 {
683 .io_mode = read_op->io_mode,
684 .opcode_len = 1,
685 .address_len = addr_len,
686 .write_len = mode_len,
687 .high_z_len = read_op->dummy_len - mode_len,
688 .read_len = len,
689 .writearr = cmd_buf,
690 .readarr = dst,
691 },
692 NULL_SPI_CMD
693 };
694
695 return spi_send_multicommand(flash, cmd);
Sean Nelson14ba6682010-02-26 05:48:29 +0000696}
697
698/*
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000699 * Write a part of the flash chip.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000700 * FIXME: Use the chunk code from Michael Karcher instead.
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000701 * Each page is written separately in chunks with a maximum size of chunksize.
702 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000703int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int start,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000704 unsigned int len, unsigned int chunksize)
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000705{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000706 unsigned int i, j, starthere, lenhere, towrite;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000707 /* FIXME: page_size is the wrong variable. We need max_writechunk_size
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000708 * in struct flashctx to do this properly. All chips using
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000709 * spi_chip_write_256 have page_size set to max_writechunk_size, so
710 * we're OK for now.
711 */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000712 unsigned int page_size = flash->chip->page_size;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000713
714 /* Warning: This loop has a very unusual condition and body.
715 * The loop needs to go through each page with at least one affected
716 * byte. The lowest page number is (start / page_size) since that
717 * division rounds down. The highest page number we want is the page
718 * where the last byte of the range lives. That last byte has the
719 * address (start + len - 1), thus the highest page number is
720 * (start + len - 1) / page_size. Since we want to include that last
721 * page as well, the loop condition uses <=.
722 */
723 for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
724 /* Byte position of the first byte in the range in this page. */
725 /* starthere is an offset to the base address of the chip. */
726 starthere = max(start, i * page_size);
727 /* Length of bytes in the range in this page. */
728 lenhere = min(start + len, (i + 1) * page_size) - starthere;
729 for (j = 0; j < lenhere; j += chunksize) {
Nico Huber7a077222017-10-14 18:18:30 +0200730 int rc;
731
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000732 towrite = min(chunksize, lenhere - j);
Nico Huber7a077222017-10-14 18:18:30 +0200733 rc = spi_nbyte_program(flash, starthere + j, buf + starthere - start + j, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000734 if (rc)
Nico Huber7a077222017-10-14 18:18:30 +0200735 return rc;
Richard Hughes842d6782021-01-15 09:48:12 +0000736 flashprog_progress_add(flash, towrite);
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000737 }
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000738 }
739
Nico Huber7a077222017-10-14 18:18:30 +0200740 return 0;
Carl-Daniel Hailfinger5824fbf2010-05-21 23:09:42 +0000741}
742
743/*
Sean Nelson14ba6682010-02-26 05:48:29 +0000744 * Program chip using byte programming. (SLOW!)
745 * This is for chips which can only handle one byte writes
746 * and for chips where memory mapped programming is impossible
747 * (e.g. due to size constraints in IT87* for over 512 kB)
748 */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000749/* real chunksize is 1, logical chunksize is 1 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000750int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
Sean Nelson14ba6682010-02-26 05:48:29 +0000751{
Stefan Taunerc69c9c82011-11-23 09:13:48 +0000752 unsigned int i;
Sean Nelson14ba6682010-02-26 05:48:29 +0000753
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000754 for (i = start; i < start + len; i++) {
Nico Huber7a077222017-10-14 18:18:30 +0200755 if (spi_nbyte_program(flash, i, buf + i - start, 1))
Sean Nelson14ba6682010-02-26 05:48:29 +0000756 return 1;
Richard Hughes842d6782021-01-15 09:48:12 +0000757 flashprog_progress_add(flash, 1);
Sean Nelson14ba6682010-02-26 05:48:29 +0000758 }
Sean Nelson14ba6682010-02-26 05:48:29 +0000759 return 0;
760}
761
Mark Marshallf20b7be2014-05-09 21:16:21 +0000762int 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 +0000763{
764 uint32_t pos = start;
Sean Nelson14ba6682010-02-26 05:48:29 +0000765 int result;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000766 unsigned char cmd[JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE] = {
767 JEDEC_AAI_WORD_PROGRAM,
768 };
Sean Nelson14ba6682010-02-26 05:48:29 +0000769
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000770 /* The even start address and even length requirements can be either
771 * honored outside this function, or we can call spi_byte_program
772 * for the first and/or last byte and use AAI for the rest.
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000773 * FIXME: Move this to generic code.
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000774 */
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000775 /* The data sheet requires a start address with the low bit cleared. */
Carl-Daniel Hailfinger9a795d82010-07-14 16:19:05 +0000776 if (start % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000777 msg_cerr("%s: start address not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200778 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000779 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000780 if (spi_chip_write_1(flash, buf, start, start % 2))
781 return SPI_GENERIC_ERROR;
782 pos += start % 2;
783 /* Do not return an error for now. */
784 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000785 }
786 /* The data sheet requires total AAI write length to be even. */
787 if (len % 2) {
Nico Huberac90af62022-12-18 00:22:47 +0000788 msg_cerr("%s: total write length not even!\n"
Nico Huberc3b02dc2023-08-12 01:13:45 +0200789 "Please report a bug at flashprog@flashprog.org\n",
Nico Huberac90af62022-12-18 00:22:47 +0000790 __func__);
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000791 /* Do not return an error for now. */
792 //return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000793 }
794
Nico Hubera1672f82017-10-14 18:00:20 +0200795 result = spi_write_cmd(flash, JEDEC_AAI_WORD_PROGRAM, false, start, buf + pos - start, 2, 10);
Nico Huber0ecbacb2017-10-14 16:50:43 +0200796 if (result)
Stefan Reinauer87ace662014-04-26 16:12:55 +0000797 goto bailout;
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000798
799 /* We already wrote 2 bytes in the multicommand step. */
Richard Hughes842d6782021-01-15 09:48:12 +0000800 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000801 pos += 2;
802
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000803 /* Are there at least two more bytes to write? */
804 while (pos < start + len - 1) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000805 cmd[1] = buf[pos++ - start];
806 cmd[2] = buf[pos++ - start];
Stefan Reinauer87ace662014-04-26 16:12:55 +0000807 result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL);
808 if (result != 0) {
809 msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result);
810 goto bailout;
811 }
Nico Huber0ecbacb2017-10-14 16:50:43 +0200812 if (spi_poll_wip(flash, 10))
813 goto bailout;
Richard Hughes842d6782021-01-15 09:48:12 +0000814 flashprog_progress_add(flash, 2);
Carl-Daniel Hailfinger9c62d112010-06-20 10:41:35 +0000815 }
816
Stefan Tauner59c4d792014-04-26 16:13:09 +0000817 /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */
818 result = spi_write_disable(flash);
819 if (result != 0) {
820 msg_cerr("%s failed to disable AAI mode.\n", __func__);
821 return SPI_GENERIC_ERROR;
822 }
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000823
824 /* Write remaining byte (if any). */
825 if (pos < start + len) {
Carl-Daniel Hailfingerccfe0ac2010-10-27 22:07:11 +0000826 if (spi_chip_write_1(flash, buf + pos - start, pos, pos % 2))
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000827 return SPI_GENERIC_ERROR;
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000828 }
829
Sean Nelson14ba6682010-02-26 05:48:29 +0000830 return 0;
Stefan Reinauer87ace662014-04-26 16:12:55 +0000831
832bailout:
Stefan Tauner59c4d792014-04-26 16:13:09 +0000833 result = spi_write_disable(flash);
834 if (result != 0)
835 msg_cerr("%s failed to disable AAI mode.\n", __func__);
Stefan Reinauer87ace662014-04-26 16:12:55 +0000836 return SPI_GENERIC_ERROR;
Sean Nelson14ba6682010-02-26 05:48:29 +0000837}