blob: 8cce3c618792e4aa6190e027a0566a036c492b4b [file] [log] [blame]
Boris Baykov50a56602016-06-11 18:28:59 +02001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2014 Boris Baykov
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * SPI chip driver functions for 4-bytes addressing
22 */
23
24#include <string.h>
25#include "flash.h"
26#include "chipdrivers.h"
27#include "spi.h"
28#include "programmer.h"
29#include "spi4ba.h"
30
31/* #define MSG_TRACE_4BA_FUNCS 1 */
32
33#ifdef MSG_TRACE_4BA_FUNCS
34#define msg_trace(...) print(MSG_DEBUG, __VA_ARGS__)
35#else
36#define msg_trace(...)
37#endif
38
39/* Enter 4-bytes addressing mode (without sending WREN before) */
40int spi_enter_4ba_b7(struct flashctx *flash)
41{
Nico Huberf43c6542017-10-14 17:47:28 +020042 int result;
Boris Baykov50a56602016-06-11 18:28:59 +020043 const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE };
44
45 msg_trace("-> %s\n", __func__);
46
Boris Baykovb1f88362016-06-11 18:28:59 +020047 /* Switch to 4-bytes addressing mode */
Nico Huberf43c6542017-10-14 17:47:28 +020048 result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
49 if (!result)
50 flash->in_4ba_mode = true;
51
52 return result;
Boris Baykov50a56602016-06-11 18:28:59 +020053}
54
55/* Enter 4-bytes addressing mode with sending WREN before */
56int spi_enter_4ba_b7_we(struct flashctx *flash)
57{
58 int result;
59 struct spi_command cmds[] = {
60 {
61 .writecnt = JEDEC_WREN_OUTSIZE,
62 .writearr = (const unsigned char[]){ JEDEC_WREN },
63 .readcnt = 0,
64 .readarr = NULL,
65 }, {
66 .writecnt = JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE,
67 .writearr = (const unsigned char[]){ JEDEC_ENTER_4_BYTE_ADDR_MODE },
68 .readcnt = 0,
69 .readarr = NULL,
70 }, {
71 .writecnt = 0,
72 .writearr = NULL,
73 .readcnt = 0,
74 .readarr = NULL,
75 }};
76
77 msg_trace("-> %s\n", __func__);
78
Boris Baykovb1f88362016-06-11 18:28:59 +020079 /* Switch to 4-bytes addressing mode */
Boris Baykov50a56602016-06-11 18:28:59 +020080 result = spi_send_multicommand(flash, cmds);
Boris Baykovb1f88362016-06-11 18:28:59 +020081 if (result)
Boris Baykov50a56602016-06-11 18:28:59 +020082 msg_cerr("%s failed during command execution\n", __func__);
Nico Huberf43c6542017-10-14 17:47:28 +020083 else
84 flash->in_4ba_mode = true;
Boris Baykov50a56602016-06-11 18:28:59 +020085 return result;
86}
87
Ed Swierkd94d2542017-07-03 13:02:18 -070088/* Exit 4-bytes addressing mode (without sending WREN before) */
89int spi_exit_4ba_e9(struct flashctx *flash)
90{
Nico Huberf43c6542017-10-14 17:47:28 +020091 int result;
Ed Swierkd94d2542017-07-03 13:02:18 -070092 const unsigned char cmd[JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_EXIT_4_BYTE_ADDR_MODE };
93
94 msg_trace("-> %s\n", __func__);
95
96 /* Switch to 3-bytes addressing mode */
Nico Huberf43c6542017-10-14 17:47:28 +020097 result = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
98 if (!result)
99 flash->in_4ba_mode = false;
100
101 return result;
Ed Swierkd94d2542017-07-03 13:02:18 -0700102}
103
104/* Exit 4-bytes addressing mode with sending WREN before */
105int spi_exit_4ba_e9_we(struct flashctx *flash)
106{
107 int result;
108 struct spi_command cmds[] = {
109 {
110 .writecnt = JEDEC_WREN_OUTSIZE,
111 .writearr = (const unsigned char[]){ JEDEC_WREN },
112 .readcnt = 0,
113 .readarr = NULL,
114 }, {
115 .writecnt = JEDEC_EXIT_4_BYTE_ADDR_MODE_OUTSIZE,
116 .writearr = (const unsigned char[]){ JEDEC_EXIT_4_BYTE_ADDR_MODE },
117 .readcnt = 0,
118 .readarr = NULL,
119 }, {
120 .writecnt = 0,
121 .writearr = NULL,
122 .readcnt = 0,
123 .readarr = NULL,
124 }};
125
126 msg_trace("-> %s\n", __func__);
127
128 /* Switch to 3-bytes addressing mode */
129 result = spi_send_multicommand(flash, cmds);
Nico Huberf43c6542017-10-14 17:47:28 +0200130 if (result)
Ed Swierkd94d2542017-07-03 13:02:18 -0700131 msg_cerr("%s failed during command execution\n", __func__);
Nico Huberf43c6542017-10-14 17:47:28 +0200132 else
133 flash->in_4ba_mode = false;
Ed Swierkd94d2542017-07-03 13:02:18 -0700134 return result;
135}
136
Boris Baykov5de3b9b2016-06-11 18:29:02 +0200137/* Write Extended Address Register value */
138int spi_write_extended_address_register(struct flashctx *flash, uint8_t regdata)
139{
140 int result;
141 struct spi_command cmds[] = {
142 {
143 .writecnt = JEDEC_WREN_OUTSIZE,
144 .writearr = (const unsigned char[]){ JEDEC_WREN },
145 .readcnt = 0,
146 .readarr = NULL,
147 }, {
148 .writecnt = JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE,
149 .writearr = (const unsigned char[]){
150 JEDEC_WRITE_EXT_ADDR_REG,
151 regdata
152 },
153 .readcnt = 0,
154 .readarr = NULL,
155 }, {
156 .writecnt = 0,
157 .writearr = NULL,
158 .readcnt = 0,
159 .readarr = NULL,
160 }};
161
162 msg_trace("-> %s (%02X)\n", __func__, regdata);
163
164 result = spi_send_multicommand(flash, cmds);
165 if (result) {
166 msg_cerr("%s failed during command execution\n", __func__);
167 return result;
168 }
169 return 0;
170}
171
Boris Baykov7fe85692016-06-11 18:29:03 +0200172/* Erase 4 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
173 JEDEC_SE_4BA (21h) instruction is new for 4-bytes addressing flash chips.
174 The presence of this instruction for an exact chip should be checked
175 by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
176int spi_block_erase_21_4ba_direct(struct flashctx *flash, unsigned int addr,
177 unsigned int blocklen)
178{
179 int result;
180 struct spi_command cmds[] = {
181 {
182 .writecnt = JEDEC_WREN_OUTSIZE,
183 .writearr = (const unsigned char[]){ JEDEC_WREN },
184 .readcnt = 0,
185 .readarr = NULL,
186 }, {
187 .writecnt = JEDEC_SE_4BA_OUTSIZE,
188 .writearr = (const unsigned char[]){
189 JEDEC_SE_4BA,
190 (addr >> 24) & 0xff,
191 (addr >> 16) & 0xff,
192 (addr >> 8) & 0xff,
193 (addr & 0xff)
194 },
195 .readcnt = 0,
196 .readarr = NULL,
197 }, {
198 .writecnt = 0,
199 .writearr = NULL,
200 .readcnt = 0,
201 .readarr = NULL,
202 }};
203
204 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
205
206 result = spi_send_multicommand(flash, cmds);
207 if (result) {
208 msg_cerr("%s failed during command execution at address 0x%x\n",
209 __func__, addr);
210 return result;
211 }
212 /* Wait until the Write-In-Progress bit is cleared.
213 * This usually takes 15-800 ms, so wait in 10 ms steps.
214 */
215 while (spi_read_status_register(flash) & SPI_SR_WIP)
216 programmer_delay(10 * 1000);
217 /* FIXME: Check the status register for errors. */
218 return 0;
219}
220
221/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
222 JEDEC_BE_5C_4BA (5Ch) instruction is new for 4-bytes addressing flash chips.
223 The presence of this instruction for an exact chip should be checked
224 by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
225int spi_block_erase_5c_4ba_direct(struct flashctx *flash, unsigned int addr,
226 unsigned int blocklen)
227{
228 int result;
229 struct spi_command cmds[] = {
230 {
231 .writecnt = JEDEC_WREN_OUTSIZE,
232 .writearr = (const unsigned char[]){ JEDEC_WREN },
233 .readcnt = 0,
234 .readarr = NULL,
235 }, {
236 .writecnt = JEDEC_BE_5C_4BA_OUTSIZE,
237 .writearr = (const unsigned char[]){
238 JEDEC_BE_5C_4BA,
239 (addr >> 24) & 0xff,
240 (addr >> 16) & 0xff,
241 (addr >> 8) & 0xff,
242 (addr & 0xff)
243 },
244 .readcnt = 0,
245 .readarr = NULL,
246 }, {
247 .writecnt = 0,
248 .writearr = NULL,
249 .readcnt = 0,
250 .readarr = NULL,
251 }};
252
253 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
254
255 result = spi_send_multicommand(flash, cmds);
256 if (result) {
257 msg_cerr("%s failed during command execution at address 0x%x\n",
258 __func__, addr);
259 return result;
260 }
261 /* Wait until the Write-In-Progress bit is cleared.
262 * This usually takes 100-4000 ms, so wait in 100 ms steps.
263 */
264 while (spi_read_status_register(flash) & SPI_SR_WIP)
265 programmer_delay(100 * 1000);
266 /* FIXME: Check the status register for errors. */
267 return 0;
268}
269
270/* Erase 64 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes)
271 JEDEC_BE_DC_4BA (DCh) instruction is new for 4-bytes addressing flash chips.
272 The presence of this instruction for an exact chip should be checked
273 by its datasheet or from SFDP 4-Bytes Address Instruction Table (JESD216B). */
274int spi_block_erase_dc_4ba_direct(struct flashctx *flash, unsigned int addr,
275 unsigned int blocklen)
276{
277 int result;
278 struct spi_command cmds[] = {
279 {
280 .writecnt = JEDEC_WREN_OUTSIZE,
281 .writearr = (const unsigned char[]){ JEDEC_WREN },
282 .readcnt = 0,
283 .readarr = NULL,
284 }, {
285 .writecnt = JEDEC_BE_DC_4BA_OUTSIZE,
286 .writearr = (const unsigned char[]){
287 JEDEC_BE_DC_4BA,
288 (addr >> 24) & 0xff,
289 (addr >> 16) & 0xff,
290 (addr >> 8) & 0xff,
291 (addr & 0xff)
292 },
293 .readcnt = 0,
294 .readarr = NULL,
295 }, {
296 .writecnt = 0,
297 .writearr = NULL,
298 .readcnt = 0,
299 .readarr = NULL,
300 }};
301
302 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
303
304 result = spi_send_multicommand(flash, cmds);
305 if (result) {
306 msg_cerr("%s failed during command execution at address 0x%x\n",
307 __func__, addr);
308 return result;
309 }
310 /* Wait until the Write-In-Progress bit is cleared.
311 * This usually takes 100-4000 ms, so wait in 100 ms steps.
312 */
313 while (spi_read_status_register(flash) & SPI_SR_WIP)
314 programmer_delay(100 * 1000);
315 /* FIXME: Check the status register for errors. */
316 return 0;
317}