blob: 6225116ce284f38eafd411646c9573d1f7aaa598 [file] [log] [blame]
David Hendricks398714f2014-07-03 17:49:41 -07001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2014 Google Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * Neither the name of Google or the names of contributors or
18 * licensors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * This software is provided "AS IS," without a warranty of any kind.
22 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
23 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
24 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
25 * GOOGLE INC AND ITS LICENSORS SHALL NOT BE LIABLE
26 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
27 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
28 * GOOGLE OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
29 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
30 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
31 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
32 * EVEN IF GOOGLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 *
Vadim Bendebury3a501162014-10-21 20:38:13 -070034 * s25fs.c - Helper functions for Spansion S25FL and S25FS SPI flash chips.
35 * Uses 24 bit addressing for the FS chips and 32 bit addressing for the FL
36 * chips (which is required by the overlayed sector size devices).
37 * TODO: Implement fancy hybrid sector architecture helpers.
David Hendricks398714f2014-07-03 17:49:41 -070038 */
39
Vadim Bendebury3a501162014-10-21 20:38:13 -070040#include <string.h>
41
David Hendricks398714f2014-07-03 17:49:41 -070042#include "chipdrivers.h"
43#include "spi.h"
44
45#define CMD_RDAR 0x65
46#define CMD_WRAR 0x71
47/* FIXME: These lengths assume we're operating in legacy mode */
48#define CMD_RDAR_LEN 4
49#define CMD_WRAR_LEN 5
50
51#define CMD_RSTEN 0x66
52#define CMD_RST 0x99
53
54#define CR3NV_ADDR 0x000004
55#define CR3NV_20H_NV (1 << 3)
56
57static int sf25s_read_cr(struct flashchip *flash, uint32_t addr)
58{
59 int result;
60 uint8_t cfg;
61 /* By default, 8 dummy cycles are necessary for variable-latency
62 commands such as RDAR (see CR2NV[3:0]). */
63 unsigned char read_cr_cmd[] = {
64 CMD_RDAR,
65 (addr >> 16) & 0xff,
66 (addr >> 8) & 0xff,
67 (addr & 0xff),
68 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00,
70 };
71
72 result = spi_send_command(sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
73 if (result) {
74 msg_cerr("%s failed during command execution at address 0x%x\n",
75 __func__, addr);
76 return result;
77 }
78
79 return cfg;
80}
81
82static int sf25s_write_cr(struct flashchip *flash, uint32_t addr, uint8_t data)
83{
84 int result;
85 struct spi_command cmds[] = {
86 {
87 .writecnt = JEDEC_WREN_OUTSIZE,
88 .writearr = (const unsigned char[]){ JEDEC_WREN },
89 .readcnt = 0,
90 .readarr = NULL,
91 }, {
92 .writecnt = CMD_WRAR_LEN,
93 .writearr = (const unsigned char[]){
94 CMD_WRAR,
95 (addr >> 16) & 0xff,
96 (addr >> 8) & 0xff,
97 (addr & 0xff),
98 data
99 },
100 .readcnt = 0,
101 .readarr = NULL,
102 }, {
103 .writecnt = 0,
104 .writearr = NULL,
105 .readcnt = 0,
106 .readarr = NULL,
107 }};
108
109 result = spi_send_multicommand(cmds);
110 if (result) {
111 msg_cerr("%s failed during command execution at address 0x%x\n",
112 __func__, addr);
113 return result;
114 }
115
116 /* Poll WIP bit while command is in progress. The datasheet specifies
117 Tw is typically 145ms, but can be up to 750ms. */
118 while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
119 programmer_delay(1000 * 10);
120
121 return 0;
122}
123
124static int s25fs_software_reset(struct flashchip *flash)
125{
126 int result;
127 struct spi_command cmds[] = {
128 {
129 .writecnt = 1,
130 .writearr = (const unsigned char[]){ CMD_RSTEN },
131 .readcnt = 0,
132 .readarr = NULL,
133 }, {
134 .writecnt = 1,
135 .writearr = (const unsigned char[]){ CMD_RST },
136 .readcnt = 0,
137 .readarr = NULL,
138 }, {
139 .writecnt = 0,
140 .writearr = NULL,
141 .readcnt = 0,
142 .readarr = NULL,
143 }};
144
145 result = spi_send_multicommand(cmds);
146 if (result) {
147 msg_cerr("%s failed during command execution\n", __func__);
148 return result;
149 }
150
151 /* Allow time for reset command to execute. The datasheet specifies
152 * Trph = 35us, double that to be safe. */
153 programmer_delay(35 * 2);
154
155 return 0;
156}
157
158static int s25fs_restore_cr3nv(struct flashchip *flash, uint8_t cfg)
159{
160 int ret = 0;
161
162 msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
163 ret |= sf25s_write_cr(flash, CR3NV_ADDR, cfg);
164 ret |= s25fs_software_reset(flash);
165 return ret;
166}
167
168int s25fs_block_erase_d8(struct flashchip *flash,
169 unsigned int addr, unsigned int blocklen)
170{
171 unsigned char cfg;
172 int result;
173 static int cr3nv_checked = 0;
174
175 struct spi_command erase_cmds[] = {
176 {
177 .writecnt = JEDEC_WREN_OUTSIZE,
178 .writearr = (const unsigned char[]){ JEDEC_WREN },
179 .readcnt = 0,
180 .readarr = NULL,
181 }, {
182 .writecnt = JEDEC_BE_D8_OUTSIZE,
183 .writearr = (const unsigned char[]){
184 JEDEC_BE_D8,
185 (addr >> 16) & 0xff,
186 (addr >> 8) & 0xff,
187 (addr & 0xff)
188 },
189 .readcnt = 0,
190 .readarr = NULL,
191 }, {
192 .writecnt = 0,
193 .writearr = NULL,
194 .readcnt = 0,
195 .readarr = NULL,
196 }};
197
198 /* Check if hybrid sector architecture is in use and, if so,
199 * switch to uniform sectors. */
200 if (!cr3nv_checked) {
201 cfg = sf25s_read_cr(flash, CR3NV_ADDR);
202 if (!(cfg & CR3NV_20H_NV)) {
203 sf25s_write_cr(flash, CR3NV_ADDR, cfg | CR3NV_20H_NV);
204 s25fs_software_reset(flash);
205
206 cfg = sf25s_read_cr(flash, CR3NV_ADDR);
207 if (!(cfg & CR3NV_20H_NV)) {
208 msg_cerr("%s: Unable to enable uniform "
209 "block sizes.\n", __func__);
210 return 1;
211 }
212
213 msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
214 __func__, cfg,
215 sf25s_read_cr(flash, CR3NV_ADDR));
216 /* Restore CR3V when flashrom exits */
217 register_chip_restore(s25fs_restore_cr3nv, flash, cfg);
218 }
219
220 cr3nv_checked = 1;
221 }
222
223 result = spi_send_multicommand(erase_cmds);
224 if (result) {
225 msg_cerr("%s failed during command execution at address 0x%x\n",
226 __func__, addr);
227 return result;
228 }
229
230 /* Wait until the Write-In-Progress bit is cleared. */
231 while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
232 programmer_delay(10 * 1000);
233 /* FIXME: Check the status register for errors. */
234 return 0;
235}
Vadim Bendebury3a501162014-10-21 20:38:13 -0700236
237int s25fl_block_erase(struct flashchip *flash,
238 unsigned int addr, unsigned int blocklen)
239{
240 unsigned char status;
241 int result;
242 static int cr3nv_checked = 0;
243
244 struct spi_command erase_cmds[] = {
245 {
246 .writecnt = JEDEC_WREN_OUTSIZE,
247 .writearr = (const unsigned char[]){
248 JEDEC_WREN
249 },
250 .readcnt = 0,
251 .readarr = NULL,
252 }, {
253 .writecnt = JEDEC_BE_DC_OUTSIZE,
254 .writearr = (const unsigned char[]){
255 JEDEC_BE_DC,
256 (addr >> 24) & 0xff,
257 (addr >> 16) & 0xff,
258 (addr >> 8) & 0xff,
259 (addr & 0xff)
260 },
261 .readcnt = 0,
262 .readarr = NULL,
263 }, {
264 .writecnt = 0,
265 .readcnt = 0,
266 }
267 };
268
269 result = spi_send_multicommand(erase_cmds);
270 if (result) {
271 msg_cerr("%s failed during command execution at address 0x%x\n",
272 __func__, addr);
273 return result;
274 }
275
276 /* Wait until the Write-In-Progress bit is cleared. */
277 status = spi_read_status_register();
278 while (status & JEDEC_RDSR_BIT_WIP) {
279 programmer_delay(1000);
280 status = spi_read_status_register();
281 }
282 return (status & JEDEC_RDSR_BIT_ERASE_ERR) != 0;
283}
284
285
286int probe_spi_big_spansion(struct flashchip *flash)
287{
288 static const unsigned char cmd = JEDEC_RDID;
289 int ret;
290 unsigned char dev_id[6]; /* We care only about 6 first bytes */
291
292 ret = spi_send_command(sizeof(cmd), sizeof(dev_id), &cmd, dev_id);
293
294 if (!ret) {
295 int i;
296
297 for (i = 0; i < sizeof(dev_id); i++)
298 msg_gdbg(" 0x%02x", dev_id[i]);
299 msg_gdbg(".\n");
300
301 if (dev_id[0] == flash->manufacture_id) {
302 union {
303 uint8_t array[4];
304 uint32_t whole;
305 } model_id;
306
307 /*
308 * The structure of the RDID output is as follows:
309 *
310 * offset value meaning
311 * 00h 01h Manufacturer ID for Spansion
312 * 01h 20h 128 Mb capacity
313 * 01h 02h 256 Mb capacity
314 * 02h 18h 128 Mb capacity
315 * 02h 19h 256 Mb capacity
316 * 03h 4Dh Full size of the RDID output (ignored)
317 * 04h 00h FS: 256-kB physical sectors
318 * 04h 01h FS: 64-kB physical sectors
319 * 04h 00h FL: 256-kB physical sectors
320 * 04h 01h FL: Mix of 64-kB and 4KB overlayed sectors
321 * 05h 80h FL family
322 * 05h 81h FS family
323 *
324 * Need to use bytes 1, 2, 4, and 5 to properly identify one of eight
325 * possible chips:
326 *
327 * 2 types * 2 possible sizes * 2 possible sector layouts
328 *
329 */
330 memcpy(model_id.array, dev_id + 1, 2);
331 memcpy(model_id.array + 2, dev_id + 4, 2);
332 if (be_to_cpu32(model_id.whole) == flash->model_id)
333 return 1;
334 }
335 }
336 return 0;
337}