xref: /aosp_15_r20/external/flashrom/s25f.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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