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