1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2014 Google LLC.
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; either version 2 of the License, or
9 * (at your option) any later version.
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.
15 */
16
17 /*
18 * s25f.c - Helper functions for Spansion S25FL and S25FS SPI flash chips.
19 * Uses 24 bit addressing for the FS chips and 32 bit addressing for the FL
20 * chips (which is required by the overlaid sector size devices).
21 * TODO: Implement fancy hybrid sector architecture helpers.
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "chipdrivers.h"
28 #include "spi.h"
29
30 /*
31 * RDAR and WRAR are supported on chips which have more than one set of status
32 * and control registers and take an address of the register to read/write.
33 * WRR, RDSR2, and RDCR are used on chips with a more limited set of control/
34 * status registers.
35 *
36 * WRR is somewhat peculiar. It shares the same opcode as JEDEC_WRSR, and if
37 * given one data byte (following the opcode) it acts the same way. If it's
38 * given two data bytes, the first data byte overwrites status register 1
39 * and the second data byte overwrites config register 1.
40 */
41 #define CMD_WRR 0x01
42 #define CMD_WRDI 0x04
43 #define CMD_RDSR2 0x07 /* note: read SR1 with JEDEC RDSR opcode */
44 #define CMD_RDCR 0x35
45 #define CMD_RDAR 0x65
46 #define CMD_WRAR 0x71
47
48 /* TODO: For now, commands which use an address assume 24-bit addressing */
49 #define CMD_WRR_LEN 3
50 #define CMD_WRDI_LEN 1
51 #define CMD_RDAR_LEN 4
52 #define CMD_WRAR_LEN 5
53
54 #define CMD_RSTEN 0x66
55 #define CMD_RST 0x99
56
57 #define CR1NV_ADDR 0x000002
58 #define CR1_BPNV_O (1 << 3)
59 #define CR1_TBPROT_O (1 << 5)
60 #define CR3NV_ADDR 0x000004
61 #define CR3NV_20H_NV (1 << 3)
62
63 /* See "Embedded Algorithm Performance Tables for additional timing specs. */
64 #define T_W 145 * 1000 /* NV register write time (145ms) */
65 #define T_RPH 35 /* Reset pulse hold time (35us) */
66 #define S25FS_T_SE 145 * 1000 /* Sector Erase Time (145ms) */
67 #define S25FL_T_SE 130 * 1000 /* Sector Erase Time (130ms) */
68
s25f_legacy_software_reset(const struct flashctx * flash)69 static int s25f_legacy_software_reset(const struct flashctx *flash)
70 {
71 struct spi_command cmds[] = {
72 {
73 .writecnt = 1,
74 .writearr = (const uint8_t[]){ CMD_RSTEN },
75 .readcnt = 0,
76 .readarr = NULL,
77 }, {
78 .writecnt = 1,
79 .writearr = (const uint8_t[]){ 0xf0 },
80 .readcnt = 0,
81 .readarr = NULL,
82 }, {
83 .writecnt = 0,
84 .writearr = NULL,
85 .readcnt = 0,
86 .readarr = NULL,
87 }};
88
89 int result = spi_send_multicommand(flash, cmds);
90 if (result) {
91 msg_cerr("%s failed during command execution\n", __func__);
92 return result;
93 }
94
95 /* Allow time for reset command to execute. The datasheet specifies
96 * Trph = 35us, double that to be safe. */
97 programmer_delay(flash, T_RPH * 2);
98
99 return 0;
100 }
101
102 /* "Legacy software reset" is disabled by default on S25FS, use this instead. */
s25fs_software_reset(struct flashctx * flash)103 static int s25fs_software_reset(struct flashctx *flash)
104 {
105 struct spi_command cmds[] = {
106 {
107 .writecnt = 1,
108 .writearr = (const uint8_t[]){ CMD_RSTEN },
109 .readcnt = 0,
110 .readarr = NULL,
111 }, {
112 .writecnt = 1,
113 .writearr = (const uint8_t[]){ CMD_RST },
114 .readcnt = 0,
115 .readarr = NULL,
116 }, {
117 .writecnt = 0,
118 .writearr = NULL,
119 .readcnt = 0,
120 .readarr = NULL,
121 }};
122
123 int result = spi_send_multicommand(flash, cmds);
124 if (result) {
125 msg_cerr("%s failed during command execution\n", __func__);
126 return result;
127 }
128
129 /* Allow time for reset command to execute. Double tRPH to be safe. */
130 programmer_delay(flash, T_RPH * 2);
131
132 return 0;
133 }
134
s25f_poll_status(const struct flashctx * flash)135 static int s25f_poll_status(const struct flashctx *flash)
136 {
137 while (true) {
138 uint8_t tmp;
139 if (spi_read_register(flash, STATUS1, &tmp))
140 return -1;
141
142 if ((tmp & SPI_SR_WIP) == 0)
143 break;
144
145 /*
146 * The WIP bit on S25F chips remains set to 1 if erase or
147 * programming errors occur, so we must check for those
148 * errors here. If an error is encountered, do a software
149 * reset to clear WIP and other volatile bits, otherwise
150 * the chip will be unresponsive to further commands.
151 */
152 if (tmp & SPI_SR_ERA_ERR) {
153 msg_cerr("Erase error occurred\n");
154 s25f_legacy_software_reset(flash);
155 return -1;
156 }
157
158 if (tmp & (1 << 6)) {
159 msg_cerr("Programming error occurred\n");
160 s25f_legacy_software_reset(flash);
161 return -1;
162 }
163
164 programmer_delay(flash, 1000 * 10);
165 }
166
167 return 0;
168 }
169
170 /* "Read Any Register" instruction only supported on S25FS */
s25fs_read_cr(const struct flashctx * flash,uint32_t addr)171 static int s25fs_read_cr(const struct flashctx *flash, uint32_t addr)
172 {
173 uint8_t cfg;
174 /* By default, 8 dummy cycles are necessary for variable-latency
175 commands such as RDAR (see CR2NV[3:0]). */
176 uint8_t read_cr_cmd[] = {
177 CMD_RDAR,
178 (addr >> 16) & 0xff,
179 (addr >> 8) & 0xff,
180 (addr & 0xff),
181 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00,
183 };
184
185 int result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
186 if (result) {
187 msg_cerr("%s failed during command execution at address 0x%"PRIx32"\n",
188 __func__, addr);
189 return -1;
190 }
191
192 return cfg;
193 }
194
195 /* "Write Any Register" instruction only supported on S25FS */
s25fs_write_cr(const struct flashctx * flash,uint32_t addr,uint8_t data)196 static int s25fs_write_cr(const struct flashctx *flash,
197 uint32_t addr, uint8_t data)
198 {
199 struct spi_command cmds[] = {
200 {
201 .writecnt = JEDEC_WREN_OUTSIZE,
202 .writearr = (const uint8_t[]){ JEDEC_WREN },
203 .readcnt = 0,
204 .readarr = NULL,
205 }, {
206 .writecnt = CMD_WRAR_LEN,
207 .writearr = (const uint8_t[]){
208 CMD_WRAR,
209 (addr >> 16) & 0xff,
210 (addr >> 8) & 0xff,
211 (addr & 0xff),
212 data
213 },
214 .readcnt = 0,
215 .readarr = NULL,
216 }, {
217 .writecnt = 0,
218 .writearr = NULL,
219 .readcnt = 0,
220 .readarr = NULL,
221 }};
222
223 int result = spi_send_multicommand(flash, cmds);
224 if (result) {
225 msg_cerr("%s failed during command execution at address 0x%"PRIx32"\n",
226 __func__, addr);
227 return -1;
228 }
229
230 programmer_delay(flash, T_W);
231 return s25f_poll_status(flash);
232 }
233
s25fs_restore_cr3nv(struct flashctx * flash,void * data)234 static int s25fs_restore_cr3nv(struct flashctx *flash, void *data)
235 {
236 int ret = 0;
237
238 uint8_t cfg = *(uint8_t *)data;
239 free(data);
240
241 msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
242 ret |= s25fs_write_cr(flash, CR3NV_ADDR, cfg);
243 ret |= s25fs_software_reset(flash);
244 return ret;
245 }
246
s25fs_block_erase_d8(struct flashctx * flash,unsigned int addr,unsigned int blocklen)247 int s25fs_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
248 {
249 static int cr3nv_checked = 0;
250
251 struct spi_command erase_cmds[] = {
252 {
253 .writecnt = JEDEC_WREN_OUTSIZE,
254 .writearr = (const uint8_t[]){ JEDEC_WREN },
255 .readcnt = 0,
256 .readarr = NULL,
257 }, {
258 .writecnt = JEDEC_BE_D8_OUTSIZE,
259 .writearr = (const uint8_t[]){
260 JEDEC_BE_D8,
261 (addr >> 16) & 0xff,
262 (addr >> 8) & 0xff,
263 (addr & 0xff)
264 },
265 .readcnt = 0,
266 .readarr = NULL,
267 }, {
268 .writecnt = 0,
269 .writearr = NULL,
270 .readcnt = 0,
271 .readarr = NULL,
272 }};
273
274 /* Check if hybrid sector architecture is in use and, if so,
275 * switch to uniform sectors. */
276 if (!cr3nv_checked) {
277 uint8_t cfg = s25fs_read_cr(flash, CR3NV_ADDR);
278 if (!(cfg & CR3NV_20H_NV)) {
279 s25fs_write_cr(flash, CR3NV_ADDR, cfg | CR3NV_20H_NV);
280 s25fs_software_reset(flash);
281
282 cfg = s25fs_read_cr(flash, CR3NV_ADDR);
283 if (!(cfg & CR3NV_20H_NV)) {
284 msg_cerr("%s: Unable to enable uniform "
285 "block sizes.\n", __func__);
286 return 1;
287 }
288
289 msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
290 __func__, cfg,
291 s25fs_read_cr(flash, CR3NV_ADDR));
292
293 /* Restore CR3V when flashrom exits */
294 uint8_t *data = calloc(1, sizeof(uint8_t));
295 if (!data) {
296 msg_cerr("Out of memory!\n");
297 return 1;
298 }
299 *data = cfg;
300 register_chip_restore(s25fs_restore_cr3nv, flash, data);
301 }
302
303 cr3nv_checked = 1;
304 }
305
306 int result = spi_send_multicommand(flash, erase_cmds);
307 if (result) {
308 msg_cerr("%s failed during command execution at address 0x%x\n",
309 __func__, addr);
310 return result;
311 }
312
313 programmer_delay(flash, S25FS_T_SE);
314 return s25f_poll_status(flash);
315 }
316
s25fl_block_erase(struct flashctx * flash,unsigned int addr,unsigned int blocklen)317 int s25fl_block_erase(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
318 {
319 struct spi_command erase_cmds[] = {
320 {
321 .writecnt = JEDEC_WREN_OUTSIZE,
322 .writearr = (const uint8_t[]){
323 JEDEC_WREN
324 },
325 .readcnt = 0,
326 .readarr = NULL,
327 }, {
328 .writecnt = JEDEC_BE_DC_OUTSIZE,
329 .writearr = (const uint8_t[]){
330 JEDEC_BE_DC,
331 (addr >> 24) & 0xff,
332 (addr >> 16) & 0xff,
333 (addr >> 8) & 0xff,
334 (addr & 0xff)
335 },
336 .readcnt = 0,
337 .readarr = NULL,
338 }, {
339 .writecnt = 0,
340 .readcnt = 0,
341 }
342 };
343
344 int result = spi_send_multicommand(flash, erase_cmds);
345 if (result) {
346 msg_cerr("%s failed during command execution at address 0x%x\n",
347 __func__, addr);
348 return result;
349 }
350
351 programmer_delay(flash, S25FL_T_SE);
352 return s25f_poll_status(flash);
353 }
354
355
probe_spi_big_spansion(struct flashctx * flash)356 int probe_spi_big_spansion(struct flashctx *flash)
357 {
358 uint8_t cmd = JEDEC_RDID;
359 uint8_t dev_id[6]; /* We care only about 6 first bytes */
360
361 if (spi_send_command(flash, sizeof(cmd), sizeof(dev_id), &cmd, dev_id))
362 return 0;
363
364 msg_gdbg("Read id bytes: ");
365 for (size_t i = 0; i < sizeof(dev_id); i++)
366 msg_gdbg(" 0x%02x", dev_id[i]);
367 msg_gdbg(".\n");
368
369 /*
370 * The structure of the RDID output is as follows:
371 *
372 * offset value meaning
373 * 00h 01h Manufacturer ID for Spansion
374 * 01h 20h 128 Mb capacity
375 * 01h 02h 256 Mb capacity
376 * 02h 18h 128 Mb capacity
377 * 02h 19h 256 Mb capacity
378 * 03h 4Dh Full size of the RDID output (ignored)
379 * 04h 00h FS: 256-kB physical sectors
380 * 04h 01h FS: 64-kB physical sectors
381 * 04h 00h FL: 256-kB physical sectors
382 * 04h 01h FL: Mix of 64-kB and 4KB overlaid sectors
383 * 05h 80h FL family
384 * 05h 81h FS family
385 *
386 * Need to use bytes 1, 2, 4, and 5 to properly identify one of eight
387 * possible chips:
388 *
389 * 2 types * 2 possible sizes * 2 possible sector layouts
390 *
391 */
392
393 uint32_t model_id =
394 (uint32_t)dev_id[1] << 24 |
395 (uint32_t)dev_id[2] << 16 |
396 (uint32_t)dev_id[4] << 8 |
397 (uint32_t)dev_id[5] << 0;
398
399 if (dev_id[0] == flash->chip->manufacture_id && model_id == flash->chip->model_id)
400 return 1;
401
402 return 0;
403 }
404