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