blob: 619a8d0e3cec6aa6e392a8c41f47953fb0b6072b [file] [log] [blame]
Nico Huber8d0f4652024-05-04 18:52:51 +02001/*
2 * This file is part of the flashprog project.
3 *
Nico Huber9512c9c2025-01-30 22:38:18 +01004 * Copyright (C) 2017, 2018 secunet Security Networks AG
5 * Copyright (C) 2024 Nico Huber <nico.h@gmx.de>
6 *
Nico Huber8d0f4652024-05-04 18:52:51 +02007 * 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; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <stdbool.h>
19#include "flash.h"
20#include "chipdrivers.h"
21#include "programmer.h"
22#include "spi_command.h"
23#include "spi.h"
24
25static int spi_enter_exit_4ba(struct flashctx *const flash, const bool enter)
26{
27 const unsigned char cmd = enter ? JEDEC_ENTER_4_BYTE_ADDR_MODE : JEDEC_EXIT_4_BYTE_ADDR_MODE;
28 int ret = 1;
29
30 if (flash->chip->feature_bits & FEATURE_4BA_ENTER)
31 ret = spi_send_command(flash, sizeof(cmd), 0, &cmd, NULL);
32 else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_WREN)
33 ret = spi_simple_write_cmd(flash, cmd, 0);
34 else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_EAR7)
35 ret = spi_set_extended_address(flash, enter ? 0x80 : 0x00);
36
37 if (!ret)
38 flash->in_4ba_mode = enter;
39 return ret;
40}
41
42static int spi_enter_4ba(struct flashctx *const flash)
43{
44 return spi_enter_exit_4ba(flash, true);
45}
46
47static int spi_exit_4ba(struct flashctx *flash)
48{
49 return spi_enter_exit_4ba(flash, false);
50}
51
Nico Huber930d4212024-05-04 18:59:15 +020052static int spi_prepare_4ba(struct flashctx *const flash)
Nico Huber8d0f4652024-05-04 18:52:51 +020053{
Nico Huber8d0f4652024-05-04 18:52:51 +020054 flash->address_high_byte = -1;
55 flash->in_4ba_mode = false;
56
57 /* Be careful about 4BA chips and broken masters */
58 if (flash->chip->total_size > 16 * 1024 && spi_master_no_4ba_modes(flash)) {
59 /* If we can't use native instructions, bail out */
60 if ((flash->chip->feature_bits & FEATURE_4BA_NATIVE) != FEATURE_4BA_NATIVE
61 || !spi_master_4ba(flash)) {
62 msg_cerr("Programmer doesn't support this chip. Aborting.\n");
63 return 1;
64 }
65 }
66
67 /* Enable/disable 4-byte addressing mode if flash chip supports it */
68 if (flash->chip->feature_bits & (FEATURE_4BA_ENTER | FEATURE_4BA_ENTER_WREN | FEATURE_4BA_ENTER_EAR7)) {
69 int ret;
70 if (spi_master_4ba(flash))
71 ret = spi_enter_4ba(flash);
72 else
73 ret = spi_exit_4ba(flash);
74 if (ret) {
75 msg_cerr("Failed to set correct 4BA mode! Aborting.\n");
76 return 1;
77 }
78 }
79
80 return 0;
81}
Nico Huber930d4212024-05-04 18:59:15 +020082
Nico Huber1b1deda2024-04-18 00:35:48 +020083static int spi_enter_qpi(struct flashctx *const flash)
84{
85 const unsigned char cmd = flash->chip->feature_bits & FEATURE_QPI_35_F5 ? 0x35 : 0x38;
86 const int ret = spi_send_command(flash, sizeof(cmd), 0, &cmd, NULL);
87 if (!ret) {
88 msg_cdbg("Entered QPI mode.\n");
89 flash->in_qpi_mode = true;
90 }
91 return ret;
92}
93
94static int spi_exit_qpi(struct flashctx *const flash)
95{
96 const unsigned char cmd = flash->chip->feature_bits & FEATURE_QPI_35_F5 ? 0xf5 : 0xff;
97 const int ret = spi_send_command(flash, sizeof(cmd), 0, &cmd, NULL);
98 if (!ret) {
99 msg_cdbg("Left QPI mode.\n");
100 flash->in_qpi_mode = false;
101 }
102 return ret;
103}
104
105enum io_mode spi_current_io_mode(const struct flashctx *const flash)
106{
107 return flash->in_qpi_mode ? QPI_4_4_4 : SINGLE_IO_1_1_1;
108}
109
Nico Huber0c9af0a2024-05-05 12:20:22 +0200110static int spi_prepare_quad_io(struct flashctx *const flash)
111{
Nico Huber1b1deda2024-04-18 00:35:48 +0200112 if (!spi_master_quad(flash) && !spi_master_qpi(flash))
Nico Huber0c9af0a2024-05-05 12:20:22 +0200113 return 0;
114
115 /* Check QE bit if present */
Nico Huber28620112024-07-21 15:43:59 +0200116 flash->volatile_qe_enabled = false;
Nico Huber0c9af0a2024-05-05 12:20:22 +0200117 if (flash->chip->reg_bits.qe.reg != INVALID_REG) {
118 const struct reg_bit_info qe = flash->chip->reg_bits.qe;
Nico Huber28620112024-07-21 15:43:59 +0200119 const uint8_t mask = 1 << qe.bit_index;
Nico Huber0c9af0a2024-05-05 12:20:22 +0200120 uint8_t reg_val;
121
122 if (spi_read_register(flash, qe.reg, &reg_val)) {
Nico Huber0c9af0a2024-05-05 12:20:22 +0200123 reg_val = 0;
Nico Huber28620112024-07-21 15:43:59 +0200124 } else if (!(reg_val & mask) &&
125 (flash->chip->feature_bits & FEATURE_WRSR_EWSR)) {
126 msg_pdbg("Trying to set volatile quad-enable (QE).\n");
127 reg_val |= mask;
128 if (spi_write_register(flash, qe.reg, reg_val, WRSR_VOLATILE_BITS) ||
129 spi_read_register(flash, qe.reg, &reg_val)) {
130 reg_val = 0;
131 } else if (reg_val & mask) {
132 flash->volatile_qe_enabled = true;
133 }
Nico Huber0c9af0a2024-05-05 12:20:22 +0200134 }
Nico Huber28620112024-07-21 15:43:59 +0200135
136 if (!(reg_val & mask)) {
Nico Huber0c9af0a2024-05-05 12:20:22 +0200137 msg_cinfo("Quad-enable (QE) bit is unknown or unset, disabling quad i/o.\n");
138 flash->chip->feature_bits &= ~FEATURE_ANY_QUAD;
139 } else {
140 msg_cdbg("Quad-enable (QE) bit is set.\n");
141 }
142 }
143
Nico Huber1b1deda2024-04-18 00:35:48 +0200144 flash->in_qpi_mode = false;
145
146 if (!(flash->chip->feature_bits & (FEATURE_QPI_35_F5 | FEATURE_QPI_38_FF)) || !spi_master_qpi(flash))
147 return 0;
148
149 if (spi_enter_qpi(flash))
150 msg_cwarn("Failed to switch to QPI mode!\n");
151
Nico Huber0c9af0a2024-05-05 12:20:22 +0200152 return 0;
153}
154
Nico Huber1b1deda2024-04-18 00:35:48 +0200155static bool qpi_use_fast_read_qio(const struct flashctx *flash)
156{
157 return flash->chip->feature_bits & FEATURE_SET_READ_PARAMS ||
158 flash->chip->reg_bits.dc[0].reg != INVALID_REG ||
159 (flash->chip->dummy_cycles.qpi_fast_read_qio != 0 &&
160 (flash->chip->dummy_cycles.qpi_fast_read == 0 ||
161 flash->chip->dummy_cycles.qpi_fast_read_qio <=
162 flash->chip->dummy_cycles.qpi_fast_read));
163}
164
165static int qpi_dummy_cycles(const struct flashctx *flash)
166{
167 if (flash->chip->feature_bits & FEATURE_SET_READ_PARAMS ||
168 flash->chip->reg_bits.dc[0].reg != INVALID_REG)
169 /* TODO: Index 00 is assumed to be the default.
170 Could switch to potentially faster params. */
171 return flash->chip->dummy_cycles.qpi_read_params.clks00;
172 else if (qpi_use_fast_read_qio(flash))
173 return flash->chip->dummy_cycles.qpi_fast_read_qio;
174 else
175 return flash->chip->dummy_cycles.qpi_fast_read;
176}
177
178static const struct spi_read_op *select_qpi_fast_read(const struct flashctx *flash)
179{
180 static const struct spi_read_op fast_read = { QPI_4_4_4, false, JEDEC_FAST_READ, 0x00, 0 };
181 static const struct spi_read_op fast_read_qio = { QPI_4_4_4, false, JEDEC_FAST_READ_QIO, 0xff, 0 };
182 static const struct spi_read_op fast_read_qio_4ba = { QPI_4_4_4, true, JEDEC_FAST_READ_QIO_4BA, 0xff, 0 };
183
184 if (qpi_use_fast_read_qio(flash)) {
185 if (flash->chip->feature_bits & FEATURE_FAST_READ_QPI4B &&
186 spi_master_4ba(flash) && flash->mst.spi->probe_opcode(flash, fast_read_qio_4ba.opcode))
187 return &fast_read_qio_4ba;
188 else
189 return &fast_read_qio;
190 } else {
191 return &fast_read;
192 }
193}
194
195static const struct spi_read_op *select_multi_io_fast_read(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100196{
197 static const struct {
198 unsigned int feature_check;
199 unsigned int master_check;
200 struct spi_read_op op;
201 #define MIO_CHECKS(flash_feature, master_feature) \
202 FEATURE_FAST_READ_##flash_feature, SPI_MASTER_##master_feature
203 } mio[] = { /* flash master 4BA mode dummies */
204 { MIO_CHECKS(QIO, QUAD_IO), { QUAD_IO_1_4_4, true, JEDEC_FAST_READ_QIO_4BA, 0xff, 3 } },
205 { MIO_CHECKS(QOUT, QUAD_IN), { QUAD_OUT_1_1_4, true, JEDEC_FAST_READ_QOUT_4BA, 0x00, 4 } },
206 { MIO_CHECKS(DIO, DUAL_IO), { DUAL_IO_1_2_2, true, JEDEC_FAST_READ_DIO_4BA, 0xff, 1 } },
207 { MIO_CHECKS(DOUT, DUAL_IN), { DUAL_OUT_1_1_2, true, JEDEC_FAST_READ_DOUT_4BA, 0x00, 2 } },
208 { MIO_CHECKS(QIO, QUAD_IO), { QUAD_IO_1_4_4, false, JEDEC_FAST_READ_QIO, 0xff, 3 } },
209 { MIO_CHECKS(QOUT, QUAD_IN), { QUAD_OUT_1_1_4, false, JEDEC_FAST_READ_QOUT, 0x00, 4 } },
210 { MIO_CHECKS(DIO, DUAL_IO), { DUAL_IO_1_2_2, false, JEDEC_FAST_READ_DIO, 0xff, 1 } },
211 { MIO_CHECKS(DOUT, DUAL_IN), { DUAL_OUT_1_1_2, false, JEDEC_FAST_READ_DOUT, 0x00, 2 } },
212 };
213
214 unsigned int i;
215 for (i = 0; i < ARRAY_SIZE(mio); ++i) {
216 if (mio[i].op.native_4ba && !(flash->chip->feature_bits & FEATURE_4BA_FAST_READ))
217 continue;
218 if ((flash->chip->feature_bits & mio[i].feature_check) != mio[i].feature_check)
219 continue;
220 if ((flash->mst.spi->features & mio[i].master_check) != mio[i].master_check)
221 continue;
222 if (mio[i].op.native_4ba && !spi_master_4ba(flash))
223 continue;
224 if (flash->mst.spi->probe_opcode(flash, mio[i].op.opcode))
225 return &mio[i].op;
226 }
227
228 return NULL;
229}
230
Nico Huber1b1deda2024-04-18 00:35:48 +0200231static struct spi_read_op *select_spi_fast_read(const struct flashctx *flash)
232{
233 const struct spi_read_op *const fast_read =
234 flash->in_qpi_mode
235 ? select_qpi_fast_read(flash)
236 : select_multi_io_fast_read(flash);
237 if (!fast_read)
238 return NULL;
239
240 struct spi_read_op *const fast_read_copy = malloc(sizeof(*flash->spi_fast_read));
241 if (!fast_read_copy)
242 return NULL;
243
244 *fast_read_copy = *fast_read;
245 if (flash->in_qpi_mode)
246 fast_read_copy->dummy_len = qpi_dummy_cycles(flash) / 2;
247
248 return fast_read_copy;
249}
250
Nico Huber930d4212024-05-04 18:59:15 +0200251int spi_prepare_io(struct flashctx *const flash, const enum preparation_steps prep)
252{
253 if (prep != PREPARE_FULL)
254 return 0;
255
256 int ret = spi_prepare_4ba(flash);
257 if (ret)
258 return ret;
259
Nico Huber0c9af0a2024-05-05 12:20:22 +0200260 ret = spi_prepare_quad_io(flash);
261 if (ret)
262 return ret;
263
Nico Huber4760b6e2024-01-06 23:45:28 +0100264 flash->spi_fast_read = select_spi_fast_read(flash);
265
Nico Huber1b1deda2024-04-18 00:35:48 +0200266 if (!flash->spi_fast_read && flash->in_qpi_mode) {
267 msg_cwarn("No compatible fast-read operation! Leaving QPI mode.\n");
268 if (spi_exit_qpi(flash)) {
269 msg_cerr("Failed to exit QPI mode!\n");
270 return 1;
271 }
272 /* Try again w/o QPI */
273 flash->spi_fast_read = select_spi_fast_read(flash);
274 }
275
Nico Huber930d4212024-05-04 18:59:15 +0200276 return 0;
277}
278
279void spi_finish_io(struct flashctx *const flash)
280{
Nico Huber1b1deda2024-04-18 00:35:48 +0200281 if (flash->in_qpi_mode) {
282 if (spi_exit_qpi(flash))
283 msg_cwarn("Failed to exit QPI mode!\n");
284 }
Nico Huber28620112024-07-21 15:43:59 +0200285 if (flash->volatile_qe_enabled) {
286 msg_pdbg("Trying to restore volatile quad-enable (QE) state.\n");
287 const struct reg_bit_info qe = flash->chip->reg_bits.qe;
288 uint8_t reg_val;
289
290 if (!spi_read_register(flash, qe.reg, &reg_val)) {
291 reg_val &= ~(1 << qe.bit_index);
292 spi_write_register(flash, qe.reg, reg_val, WRSR_VOLATILE_BITS);
293 }
294 }
Nico Huber1b1deda2024-04-18 00:35:48 +0200295 free(flash->spi_fast_read);
Nico Huber930d4212024-05-04 18:59:15 +0200296}