blob: 6ad1f7fcd98849e375441b14fbbe9bed00116777 [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 */
113 if (flash->chip->reg_bits.qe.reg != INVALID_REG) {
114 const struct reg_bit_info qe = flash->chip->reg_bits.qe;
115 uint8_t reg_val;
116
117 if (spi_read_register(flash, qe.reg, &reg_val)) {
118 msg_cwarn("Failed read chip register!\n");
119 reg_val = 0;
120 }
121 if (!(reg_val & 1 << qe.bit_index)) {
122 msg_cinfo("Quad-enable (QE) bit is unknown or unset, disabling quad i/o.\n");
123 flash->chip->feature_bits &= ~FEATURE_ANY_QUAD;
124 } else {
125 msg_cdbg("Quad-enable (QE) bit is set.\n");
126 }
127 }
128
Nico Huber1b1deda2024-04-18 00:35:48 +0200129 flash->in_qpi_mode = false;
130
131 if (!(flash->chip->feature_bits & (FEATURE_QPI_35_F5 | FEATURE_QPI_38_FF)) || !spi_master_qpi(flash))
132 return 0;
133
134 if (spi_enter_qpi(flash))
135 msg_cwarn("Failed to switch to QPI mode!\n");
136
Nico Huber0c9af0a2024-05-05 12:20:22 +0200137 return 0;
138}
139
Nico Huber1b1deda2024-04-18 00:35:48 +0200140static bool qpi_use_fast_read_qio(const struct flashctx *flash)
141{
142 return flash->chip->feature_bits & FEATURE_SET_READ_PARAMS ||
143 flash->chip->reg_bits.dc[0].reg != INVALID_REG ||
144 (flash->chip->dummy_cycles.qpi_fast_read_qio != 0 &&
145 (flash->chip->dummy_cycles.qpi_fast_read == 0 ||
146 flash->chip->dummy_cycles.qpi_fast_read_qio <=
147 flash->chip->dummy_cycles.qpi_fast_read));
148}
149
150static int qpi_dummy_cycles(const struct flashctx *flash)
151{
152 if (flash->chip->feature_bits & FEATURE_SET_READ_PARAMS ||
153 flash->chip->reg_bits.dc[0].reg != INVALID_REG)
154 /* TODO: Index 00 is assumed to be the default.
155 Could switch to potentially faster params. */
156 return flash->chip->dummy_cycles.qpi_read_params.clks00;
157 else if (qpi_use_fast_read_qio(flash))
158 return flash->chip->dummy_cycles.qpi_fast_read_qio;
159 else
160 return flash->chip->dummy_cycles.qpi_fast_read;
161}
162
163static const struct spi_read_op *select_qpi_fast_read(const struct flashctx *flash)
164{
165 static const struct spi_read_op fast_read = { QPI_4_4_4, false, JEDEC_FAST_READ, 0x00, 0 };
166 static const struct spi_read_op fast_read_qio = { QPI_4_4_4, false, JEDEC_FAST_READ_QIO, 0xff, 0 };
167 static const struct spi_read_op fast_read_qio_4ba = { QPI_4_4_4, true, JEDEC_FAST_READ_QIO_4BA, 0xff, 0 };
168
169 if (qpi_use_fast_read_qio(flash)) {
170 if (flash->chip->feature_bits & FEATURE_FAST_READ_QPI4B &&
171 spi_master_4ba(flash) && flash->mst.spi->probe_opcode(flash, fast_read_qio_4ba.opcode))
172 return &fast_read_qio_4ba;
173 else
174 return &fast_read_qio;
175 } else {
176 return &fast_read;
177 }
178}
179
180static const struct spi_read_op *select_multi_io_fast_read(const struct flashctx *flash)
Nico Huber4760b6e2024-01-06 23:45:28 +0100181{
182 static const struct {
183 unsigned int feature_check;
184 unsigned int master_check;
185 struct spi_read_op op;
186 #define MIO_CHECKS(flash_feature, master_feature) \
187 FEATURE_FAST_READ_##flash_feature, SPI_MASTER_##master_feature
188 } mio[] = { /* flash master 4BA mode dummies */
189 { MIO_CHECKS(QIO, QUAD_IO), { QUAD_IO_1_4_4, true, JEDEC_FAST_READ_QIO_4BA, 0xff, 3 } },
190 { MIO_CHECKS(QOUT, QUAD_IN), { QUAD_OUT_1_1_4, true, JEDEC_FAST_READ_QOUT_4BA, 0x00, 4 } },
191 { MIO_CHECKS(DIO, DUAL_IO), { DUAL_IO_1_2_2, true, JEDEC_FAST_READ_DIO_4BA, 0xff, 1 } },
192 { MIO_CHECKS(DOUT, DUAL_IN), { DUAL_OUT_1_1_2, true, JEDEC_FAST_READ_DOUT_4BA, 0x00, 2 } },
193 { MIO_CHECKS(QIO, QUAD_IO), { QUAD_IO_1_4_4, false, JEDEC_FAST_READ_QIO, 0xff, 3 } },
194 { MIO_CHECKS(QOUT, QUAD_IN), { QUAD_OUT_1_1_4, false, JEDEC_FAST_READ_QOUT, 0x00, 4 } },
195 { MIO_CHECKS(DIO, DUAL_IO), { DUAL_IO_1_2_2, false, JEDEC_FAST_READ_DIO, 0xff, 1 } },
196 { MIO_CHECKS(DOUT, DUAL_IN), { DUAL_OUT_1_1_2, false, JEDEC_FAST_READ_DOUT, 0x00, 2 } },
197 };
198
199 unsigned int i;
200 for (i = 0; i < ARRAY_SIZE(mio); ++i) {
201 if (mio[i].op.native_4ba && !(flash->chip->feature_bits & FEATURE_4BA_FAST_READ))
202 continue;
203 if ((flash->chip->feature_bits & mio[i].feature_check) != mio[i].feature_check)
204 continue;
205 if ((flash->mst.spi->features & mio[i].master_check) != mio[i].master_check)
206 continue;
207 if (mio[i].op.native_4ba && !spi_master_4ba(flash))
208 continue;
209 if (flash->mst.spi->probe_opcode(flash, mio[i].op.opcode))
210 return &mio[i].op;
211 }
212
213 return NULL;
214}
215
Nico Huber1b1deda2024-04-18 00:35:48 +0200216static struct spi_read_op *select_spi_fast_read(const struct flashctx *flash)
217{
218 const struct spi_read_op *const fast_read =
219 flash->in_qpi_mode
220 ? select_qpi_fast_read(flash)
221 : select_multi_io_fast_read(flash);
222 if (!fast_read)
223 return NULL;
224
225 struct spi_read_op *const fast_read_copy = malloc(sizeof(*flash->spi_fast_read));
226 if (!fast_read_copy)
227 return NULL;
228
229 *fast_read_copy = *fast_read;
230 if (flash->in_qpi_mode)
231 fast_read_copy->dummy_len = qpi_dummy_cycles(flash) / 2;
232
233 return fast_read_copy;
234}
235
Nico Huber930d4212024-05-04 18:59:15 +0200236int spi_prepare_io(struct flashctx *const flash, const enum preparation_steps prep)
237{
238 if (prep != PREPARE_FULL)
239 return 0;
240
241 int ret = spi_prepare_4ba(flash);
242 if (ret)
243 return ret;
244
Nico Huber0c9af0a2024-05-05 12:20:22 +0200245 ret = spi_prepare_quad_io(flash);
246 if (ret)
247 return ret;
248
Nico Huber4760b6e2024-01-06 23:45:28 +0100249 flash->spi_fast_read = select_spi_fast_read(flash);
250
Nico Huber1b1deda2024-04-18 00:35:48 +0200251 if (!flash->spi_fast_read && flash->in_qpi_mode) {
252 msg_cwarn("No compatible fast-read operation! Leaving QPI mode.\n");
253 if (spi_exit_qpi(flash)) {
254 msg_cerr("Failed to exit QPI mode!\n");
255 return 1;
256 }
257 /* Try again w/o QPI */
258 flash->spi_fast_read = select_spi_fast_read(flash);
259 }
260
Nico Huber930d4212024-05-04 18:59:15 +0200261 return 0;
262}
263
264void spi_finish_io(struct flashctx *const flash)
265{
Nico Huber1b1deda2024-04-18 00:35:48 +0200266 if (flash->in_qpi_mode) {
267 if (spi_exit_qpi(flash))
268 msg_cwarn("Failed to exit QPI mode!\n");
269 }
270 free(flash->spi_fast_read);
Nico Huber930d4212024-05-04 18:59:15 +0200271}