blob: 72df874275c935cf301b3464f41bccd457dccb00 [file] [log] [blame]
Boris Baykov50a56602016-06-11 18:28:59 +02001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2014 Boris Baykov
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; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * SPI chip driver functions for 4-bytes addressing
22 */
23
24#include <string.h>
25#include "flash.h"
26#include "chipdrivers.h"
27#include "spi.h"
28#include "programmer.h"
29#include "spi4ba.h"
30
31/* #define MSG_TRACE_4BA_FUNCS 1 */
32
33#ifdef MSG_TRACE_4BA_FUNCS
34#define msg_trace(...) print(MSG_DEBUG, __VA_ARGS__)
35#else
36#define msg_trace(...)
37#endif
38
39/* Enter 4-bytes addressing mode (without sending WREN before) */
40int spi_enter_4ba_b7(struct flashctx *flash)
41{
42 const unsigned char cmd[JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE] = { JEDEC_ENTER_4_BYTE_ADDR_MODE };
43
44 msg_trace("-> %s\n", __func__);
45
46 /* Switch to 4-bytes addressing mode */
47 return spi_send_command(flash, sizeof(cmd), 0, cmd, NULL);
48}
49
50/* Enter 4-bytes addressing mode with sending WREN before */
51int spi_enter_4ba_b7_we(struct flashctx *flash)
52{
53 int result;
54 struct spi_command cmds[] = {
55 {
56 .writecnt = JEDEC_WREN_OUTSIZE,
57 .writearr = (const unsigned char[]){ JEDEC_WREN },
58 .readcnt = 0,
59 .readarr = NULL,
60 }, {
61 .writecnt = JEDEC_ENTER_4_BYTE_ADDR_MODE_OUTSIZE,
62 .writearr = (const unsigned char[]){ JEDEC_ENTER_4_BYTE_ADDR_MODE },
63 .readcnt = 0,
64 .readarr = NULL,
65 }, {
66 .writecnt = 0,
67 .writearr = NULL,
68 .readcnt = 0,
69 .readarr = NULL,
70 }};
71
72 msg_trace("-> %s\n", __func__);
73
74 /* Switch to 4-bytes addressing mode */
75 result = spi_send_multicommand(flash, cmds);
76 if (result) {
77 msg_cerr("%s failed during command execution\n", __func__);
78 }
79 return result;
80}
81
82/* Program one flash byte from 4-bytes addressing mode */
83int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr,
84 uint8_t databyte)
85{
86 int result;
87 struct spi_command cmds[] = {
88 {
89 .writecnt = JEDEC_WREN_OUTSIZE,
90 .writearr = (const unsigned char[]){ JEDEC_WREN },
91 .readcnt = 0,
92 .readarr = NULL,
93 }, {
94 .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE + 1,
95 .writearr = (const unsigned char[]){
96 JEDEC_BYTE_PROGRAM,
97 (addr >> 24) & 0xff,
98 (addr >> 16) & 0xff,
99 (addr >> 8) & 0xff,
100 (addr & 0xff),
101 databyte
102 },
103 .readcnt = 0,
104 .readarr = NULL,
105 }, {
106 .writecnt = 0,
107 .writearr = NULL,
108 .readcnt = 0,
109 .readarr = NULL,
110 }};
111
112 msg_trace("-> %s (0x%08X)\n", __func__, addr);
113
114 result = spi_send_multicommand(flash, cmds);
115 if (result) {
116 msg_cerr("%s failed during command execution at address 0x%x\n",
117 __func__, addr);
118 }
119 return result;
120}
121
122/* Program flash bytes from 4-bytes addressing mode */
123int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr,
124 const uint8_t *bytes, unsigned int len)
125{
126 int result;
127 unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = {
128 JEDEC_BYTE_PROGRAM,
129 (addr >> 24) & 0xff,
130 (addr >> 16) & 0xff,
131 (addr >> 8) & 0xff,
132 (addr >> 0) & 0xff
133 };
134 struct spi_command cmds[] = {
135 {
136 .writecnt = JEDEC_WREN_OUTSIZE,
137 .writearr = (const unsigned char[]){ JEDEC_WREN },
138 .readcnt = 0,
139 .readarr = NULL,
140 }, {
141 .writecnt = (JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + len,
142 .writearr = cmd,
143 .readcnt = 0,
144 .readarr = NULL,
145 }, {
146 .writecnt = 0,
147 .writearr = NULL,
148 .readcnt = 0,
149 .readarr = NULL,
150 }};
151
152 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
153
154 if (!len) {
155 msg_cerr("%s called for zero-length write\n", __func__);
156 return 1;
157 }
158 if (len > 256) {
159 msg_cerr("%s called for too long a write\n", __func__);
160 return 1;
161 }
162
163 memcpy(&cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], bytes, len);
164
165 result = spi_send_multicommand(flash, cmds);
166 if (result) {
167 msg_cerr("%s failed during command execution at address 0x%x\n",
168 __func__, addr);
169 }
170 return result;
171}
172
173/* Read flash bytes from 4-bytes addressing mode */
174int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr,
175 uint8_t *bytes, unsigned int len)
176{
177 const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = {
178 JEDEC_READ,
179 (addr >> 24) & 0xff,
180 (addr >> 16) & 0xff,
181 (addr >> 8) & 0xff,
182 (addr >> 0) & 0xff
183 };
184
185 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
186
187 /* Send Read */
188 return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
189}
190
191/* Erases 4 KB of flash from 4-bytes addressing mode */
192int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr,
193 unsigned int blocklen)
194{
195 int result;
196 struct spi_command cmds[] = {
197 {
198 .writecnt = JEDEC_WREN_OUTSIZE,
199 .writearr = (const unsigned char[]){ JEDEC_WREN },
200 .readcnt = 0,
201 .readarr = NULL,
202 }, {
203 .writecnt = JEDEC_SE_OUTSIZE + 1,
204 .writearr = (const unsigned char[]){
205 JEDEC_SE,
206 (addr >> 24) & 0xff,
207 (addr >> 16) & 0xff,
208 (addr >> 8) & 0xff,
209 (addr & 0xff)
210 },
211 .readcnt = 0,
212 .readarr = NULL,
213 }, {
214 .writecnt = 0,
215 .writearr = NULL,
216 .readcnt = 0,
217 .readarr = NULL,
218 }};
219
220 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
221
222 result = spi_send_multicommand(flash, 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 /* Wait until the Write-In-Progress bit is cleared.
229 * This usually takes 15-800 ms, so wait in 10 ms steps.
230 */
231 while (spi_read_status_register(flash) & SPI_SR_WIP)
232 programmer_delay(10 * 1000);
233 /* FIXME: Check the status register for errors. */
234 return 0;
235}
236
237/* Erases 32 KB of flash from 4-bytes addressing mode */
238int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr,
239 unsigned int blocklen)
240{
241 int result;
242 struct spi_command cmds[] = {
243 {
244 .writecnt = JEDEC_WREN_OUTSIZE,
245 .writearr = (const unsigned char[]){ JEDEC_WREN },
246 .readcnt = 0,
247 .readarr = NULL,
248 }, {
249 .writecnt = JEDEC_BE_52_OUTSIZE + 1,
250 .writearr = (const unsigned char[]){
251 JEDEC_BE_52,
252 (addr >> 24) & 0xff,
253 (addr >> 16) & 0xff,
254 (addr >> 8) & 0xff,
255 (addr & 0xff)
256 },
257 .readcnt = 0,
258 .readarr = NULL,
259 }, {
260 .writecnt = 0,
261 .writearr = NULL,
262 .readcnt = 0,
263 .readarr = NULL,
264 }};
265
266 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
267
268 result = spi_send_multicommand(flash, cmds);
269 if (result) {
270 msg_cerr("%s failed during command execution at address 0x%x\n",
271 __func__, addr);
272 return result;
273 }
274 /* Wait until the Write-In-Progress bit is cleared.
275 * This usually takes 100-4000 ms, so wait in 100 ms steps.
276 */
277 while (spi_read_status_register(flash) & SPI_SR_WIP)
278 programmer_delay(100 * 1000);
279 /* FIXME: Check the status register for errors. */
280 return 0;
281}
282
283/* Erases 64 KB of flash from 4-bytes addressing mode */
284int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr,
285 unsigned int blocklen)
286{
287 int result;
288 struct spi_command cmds[] = {
289 {
290 .writecnt = JEDEC_WREN_OUTSIZE,
291 .writearr = (const unsigned char[]){ JEDEC_WREN },
292 .readcnt = 0,
293 .readarr = NULL,
294 }, {
295 .writecnt = JEDEC_BE_D8_OUTSIZE + 1,
296 .writearr = (const unsigned char[]){
297 JEDEC_BE_D8,
298 (addr >> 24) & 0xff,
299 (addr >> 16) & 0xff,
300 (addr >> 8) & 0xff,
301 (addr & 0xff)
302 },
303 .readcnt = 0,
304 .readarr = NULL,
305 }, {
306 .writecnt = 0,
307 .writearr = NULL,
308 .readcnt = 0,
309 .readarr = NULL,
310 }};
311
312 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
313
314 result = spi_send_multicommand(flash, cmds);
315 if (result) {
316 msg_cerr("%s failed during command execution at address 0x%x\n",
317 __func__, addr);
318 return result;
319 }
320 /* Wait until the Write-In-Progress bit is cleared.
321 * This usually takes 100-4000 ms, so wait in 100 ms steps.
322 */
323 while (spi_read_status_register(flash) & SPI_SR_WIP)
324 programmer_delay(100 * 1000);
325 /* FIXME: Check the status register for errors. */
326 return 0;
327}