blob: c0378b5d878caa51dc755e76830e2c36be39b639 [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 *
34 * s25fs.c - Helper functions for Spansion S25FS SPI flash chips. This
35 * currently assumes that we are operating the chip in legacy 24-bit addressing
36 * mode and are working with uniform sectors.
37 * TODO: Implement fancy 32-bit addressing and hybrid sector architecture
38 * helpers.
39 */
40
41#include "chipdrivers.h"
42#include "spi.h"
43
44#define CMD_RDAR 0x65
45#define CMD_WRAR 0x71
46/* FIXME: These lengths assume we're operating in legacy mode */
47#define CMD_RDAR_LEN 4
48#define CMD_WRAR_LEN 5
49
50#define CMD_RSTEN 0x66
51#define CMD_RST 0x99
52
53#define CR3NV_ADDR 0x000004
54#define CR3NV_20H_NV (1 << 3)
55
56static int sf25s_read_cr(struct flashchip *flash, uint32_t addr)
57{
58 int result;
59 uint8_t cfg;
60 /* By default, 8 dummy cycles are necessary for variable-latency
61 commands such as RDAR (see CR2NV[3:0]). */
62 unsigned char read_cr_cmd[] = {
63 CMD_RDAR,
64 (addr >> 16) & 0xff,
65 (addr >> 8) & 0xff,
66 (addr & 0xff),
67 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00,
69 };
70
71 result = spi_send_command(sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
72 if (result) {
73 msg_cerr("%s failed during command execution at address 0x%x\n",
74 __func__, addr);
75 return result;
76 }
77
78 return cfg;
79}
80
81static int sf25s_write_cr(struct flashchip *flash, uint32_t addr, uint8_t data)
82{
83 int result;
84 struct spi_command cmds[] = {
85 {
86 .writecnt = JEDEC_WREN_OUTSIZE,
87 .writearr = (const unsigned char[]){ JEDEC_WREN },
88 .readcnt = 0,
89 .readarr = NULL,
90 }, {
91 .writecnt = CMD_WRAR_LEN,
92 .writearr = (const unsigned char[]){
93 CMD_WRAR,
94 (addr >> 16) & 0xff,
95 (addr >> 8) & 0xff,
96 (addr & 0xff),
97 data
98 },
99 .readcnt = 0,
100 .readarr = NULL,
101 }, {
102 .writecnt = 0,
103 .writearr = NULL,
104 .readcnt = 0,
105 .readarr = NULL,
106 }};
107
108 result = spi_send_multicommand(cmds);
109 if (result) {
110 msg_cerr("%s failed during command execution at address 0x%x\n",
111 __func__, addr);
112 return result;
113 }
114
115 /* Poll WIP bit while command is in progress. The datasheet specifies
116 Tw is typically 145ms, but can be up to 750ms. */
117 while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
118 programmer_delay(1000 * 10);
119
120 return 0;
121}
122
123static int s25fs_software_reset(struct flashchip *flash)
124{
125 int result;
126 struct spi_command cmds[] = {
127 {
128 .writecnt = 1,
129 .writearr = (const unsigned char[]){ CMD_RSTEN },
130 .readcnt = 0,
131 .readarr = NULL,
132 }, {
133 .writecnt = 1,
134 .writearr = (const unsigned char[]){ CMD_RST },
135 .readcnt = 0,
136 .readarr = NULL,
137 }, {
138 .writecnt = 0,
139 .writearr = NULL,
140 .readcnt = 0,
141 .readarr = NULL,
142 }};
143
144 result = spi_send_multicommand(cmds);
145 if (result) {
146 msg_cerr("%s failed during command execution\n", __func__);
147 return result;
148 }
149
150 /* Allow time for reset command to execute. The datasheet specifies
151 * Trph = 35us, double that to be safe. */
152 programmer_delay(35 * 2);
153
154 return 0;
155}
156
157static int s25fs_restore_cr3nv(struct flashchip *flash, uint8_t cfg)
158{
159 int ret = 0;
160
161 msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
162 ret |= sf25s_write_cr(flash, CR3NV_ADDR, cfg);
163 ret |= s25fs_software_reset(flash);
164 return ret;
165}
166
167int s25fs_block_erase_d8(struct flashchip *flash,
168 unsigned int addr, unsigned int blocklen)
169{
170 unsigned char cfg;
171 int result;
172 static int cr3nv_checked = 0;
173
174 struct spi_command erase_cmds[] = {
175 {
176 .writecnt = JEDEC_WREN_OUTSIZE,
177 .writearr = (const unsigned char[]){ JEDEC_WREN },
178 .readcnt = 0,
179 .readarr = NULL,
180 }, {
181 .writecnt = JEDEC_BE_D8_OUTSIZE,
182 .writearr = (const unsigned char[]){
183 JEDEC_BE_D8,
184 (addr >> 16) & 0xff,
185 (addr >> 8) & 0xff,
186 (addr & 0xff)
187 },
188 .readcnt = 0,
189 .readarr = NULL,
190 }, {
191 .writecnt = 0,
192 .writearr = NULL,
193 .readcnt = 0,
194 .readarr = NULL,
195 }};
196
197 /* Check if hybrid sector architecture is in use and, if so,
198 * switch to uniform sectors. */
199 if (!cr3nv_checked) {
200 cfg = sf25s_read_cr(flash, CR3NV_ADDR);
201 if (!(cfg & CR3NV_20H_NV)) {
202 sf25s_write_cr(flash, CR3NV_ADDR, cfg | CR3NV_20H_NV);
203 s25fs_software_reset(flash);
204
205 cfg = sf25s_read_cr(flash, CR3NV_ADDR);
206 if (!(cfg & CR3NV_20H_NV)) {
207 msg_cerr("%s: Unable to enable uniform "
208 "block sizes.\n", __func__);
209 return 1;
210 }
211
212 msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
213 __func__, cfg,
214 sf25s_read_cr(flash, CR3NV_ADDR));
215 /* Restore CR3V when flashrom exits */
216 register_chip_restore(s25fs_restore_cr3nv, flash, cfg);
217 }
218
219 cr3nv_checked = 1;
220 }
221
222 result = spi_send_multicommand(erase_cmds);
223 if (result) {
224 msg_cerr("%s failed during command execution at address 0x%x\n",
225 __func__, addr);
226 return result;
227 }
228
229 /* Wait until the Write-In-Progress bit is cleared. */
230 while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
231 programmer_delay(10 * 1000);
232 /* FIXME: Check the status register for errors. */
233 return 0;
234}