blob: bf0cf9745be9422b277e23ec6da8a88bc725cd4a [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
Boris Baykovb1f88362016-06-11 18:28:59 +020046 /* Switch to 4-bytes addressing mode */
Boris Baykov50a56602016-06-11 18:28:59 +020047 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
Boris Baykovb1f88362016-06-11 18:28:59 +020074 /* Switch to 4-bytes addressing mode */
Boris Baykov50a56602016-06-11 18:28:59 +020075 result = spi_send_multicommand(flash, cmds);
Boris Baykovb1f88362016-06-11 18:28:59 +020076 if (result)
Boris Baykov50a56602016-06-11 18:28:59 +020077 msg_cerr("%s failed during command execution\n", __func__);
Boris Baykov50a56602016-06-11 18:28:59 +020078 return result;
79}
80
81/* Program one flash byte from 4-bytes addressing mode */
Boris Baykovb1f88362016-06-11 18:28:59 +020082int spi_byte_program_4ba(struct flashctx *flash, unsigned int addr, uint8_t databyte)
Boris Baykov50a56602016-06-11 18:28:59 +020083{
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 = JEDEC_BYTE_PROGRAM_OUTSIZE + 1,
93 .writearr = (const unsigned char[]){
94 JEDEC_BYTE_PROGRAM,
95 (addr >> 24) & 0xff,
96 (addr >> 16) & 0xff,
97 (addr >> 8) & 0xff,
98 (addr & 0xff),
99 databyte
100 },
101 .readcnt = 0,
102 .readarr = NULL,
103 }, {
104 .writecnt = 0,
105 .writearr = NULL,
106 .readcnt = 0,
107 .readarr = NULL,
108 }};
109
110 msg_trace("-> %s (0x%08X)\n", __func__, addr);
111
112 result = spi_send_multicommand(flash, cmds);
Boris Baykovb1f88362016-06-11 18:28:59 +0200113 if (result)
114 msg_cerr("%s failed during command execution at address 0x%x\n", __func__, addr);
Boris Baykov50a56602016-06-11 18:28:59 +0200115 return result;
116}
117
118/* Program flash bytes from 4-bytes addressing mode */
Boris Baykovb1f88362016-06-11 18:28:59 +0200119int spi_nbyte_program_4ba(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
Boris Baykov50a56602016-06-11 18:28:59 +0200120{
121 int result;
122 unsigned char cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + 256] = {
123 JEDEC_BYTE_PROGRAM,
124 (addr >> 24) & 0xff,
125 (addr >> 16) & 0xff,
126 (addr >> 8) & 0xff,
127 (addr >> 0) & 0xff
128 };
129 struct spi_command cmds[] = {
130 {
131 .writecnt = JEDEC_WREN_OUTSIZE,
132 .writearr = (const unsigned char[]){ JEDEC_WREN },
133 .readcnt = 0,
134 .readarr = NULL,
135 }, {
136 .writecnt = (JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1 + len,
137 .writearr = cmd,
138 .readcnt = 0,
139 .readarr = NULL,
140 }, {
141 .writecnt = 0,
142 .writearr = NULL,
143 .readcnt = 0,
144 .readarr = NULL,
145 }};
146
147 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
148
149 if (!len) {
150 msg_cerr("%s called for zero-length write\n", __func__);
151 return 1;
152 }
153 if (len > 256) {
154 msg_cerr("%s called for too long a write\n", __func__);
155 return 1;
156 }
157
158 memcpy(&cmd[(JEDEC_BYTE_PROGRAM_OUTSIZE + 1) - 1], bytes, len);
159
160 result = spi_send_multicommand(flash, cmds);
161 if (result) {
162 msg_cerr("%s failed during command execution at address 0x%x\n",
163 __func__, addr);
164 }
165 return result;
166}
167
168/* Read flash bytes from 4-bytes addressing mode */
Boris Baykovb1f88362016-06-11 18:28:59 +0200169int spi_nbyte_read_4ba(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len)
Boris Baykov50a56602016-06-11 18:28:59 +0200170{
171 const unsigned char cmd[JEDEC_READ_OUTSIZE + 1] = {
172 JEDEC_READ,
173 (addr >> 24) & 0xff,
174 (addr >> 16) & 0xff,
175 (addr >> 8) & 0xff,
176 (addr >> 0) & 0xff
177 };
178
179 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
180
181 /* Send Read */
182 return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
183}
184
Boris Baykovb1f88362016-06-11 18:28:59 +0200185/* Erase one sector of flash from 4-bytes addressing mode */
186int spi_block_erase_20_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
Boris Baykov50a56602016-06-11 18:28:59 +0200187{
188 int result;
189 struct spi_command cmds[] = {
190 {
191 .writecnt = JEDEC_WREN_OUTSIZE,
192 .writearr = (const unsigned char[]){ JEDEC_WREN },
193 .readcnt = 0,
194 .readarr = NULL,
195 }, {
196 .writecnt = JEDEC_SE_OUTSIZE + 1,
197 .writearr = (const unsigned char[]){
198 JEDEC_SE,
199 (addr >> 24) & 0xff,
200 (addr >> 16) & 0xff,
201 (addr >> 8) & 0xff,
202 (addr & 0xff)
203 },
204 .readcnt = 0,
205 .readarr = NULL,
206 }, {
207 .writecnt = 0,
208 .writearr = NULL,
209 .readcnt = 0,
210 .readarr = NULL,
211 }};
212
213 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
214
215 result = spi_send_multicommand(flash, cmds);
216 if (result) {
217 msg_cerr("%s failed during command execution at address 0x%x\n",
218 __func__, addr);
219 return result;
220 }
221 /* Wait until the Write-In-Progress bit is cleared.
222 * This usually takes 15-800 ms, so wait in 10 ms steps.
223 */
224 while (spi_read_status_register(flash) & SPI_SR_WIP)
225 programmer_delay(10 * 1000);
226 /* FIXME: Check the status register for errors. */
227 return 0;
228}
229
Boris Baykovb1f88362016-06-11 18:28:59 +0200230/* Erase one sector of flash from 4-bytes addressing mode */
231int spi_block_erase_52_4ba(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
Boris Baykov50a56602016-06-11 18:28:59 +0200232{
233 int result;
234 struct spi_command cmds[] = {
235 {
236 .writecnt = JEDEC_WREN_OUTSIZE,
237 .writearr = (const unsigned char[]){ JEDEC_WREN },
238 .readcnt = 0,
239 .readarr = NULL,
240 }, {
241 .writecnt = JEDEC_BE_52_OUTSIZE + 1,
242 .writearr = (const unsigned char[]){
243 JEDEC_BE_52,
244 (addr >> 24) & 0xff,
245 (addr >> 16) & 0xff,
246 (addr >> 8) & 0xff,
247 (addr & 0xff)
248 },
249 .readcnt = 0,
250 .readarr = NULL,
251 }, {
252 .writecnt = 0,
253 .writearr = NULL,
254 .readcnt = 0,
255 .readarr = NULL,
256 }};
257
258 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
259
260 result = spi_send_multicommand(flash, cmds);
261 if (result) {
262 msg_cerr("%s failed during command execution at address 0x%x\n",
263 __func__, addr);
264 return result;
265 }
266 /* Wait until the Write-In-Progress bit is cleared.
267 * This usually takes 100-4000 ms, so wait in 100 ms steps.
268 */
269 while (spi_read_status_register(flash) & SPI_SR_WIP)
270 programmer_delay(100 * 1000);
271 /* FIXME: Check the status register for errors. */
272 return 0;
273}
274
Boris Baykovb1f88362016-06-11 18:28:59 +0200275/* Erase one sector of flash from 4-bytes addressing mode */
Boris Baykov50a56602016-06-11 18:28:59 +0200276int spi_block_erase_d8_4ba(struct flashctx *flash, unsigned int addr,
277 unsigned int blocklen)
278{
279 int result;
280 struct spi_command cmds[] = {
281 {
282 .writecnt = JEDEC_WREN_OUTSIZE,
283 .writearr = (const unsigned char[]){ JEDEC_WREN },
284 .readcnt = 0,
285 .readarr = NULL,
286 }, {
287 .writecnt = JEDEC_BE_D8_OUTSIZE + 1,
288 .writearr = (const unsigned char[]){
289 JEDEC_BE_D8,
290 (addr >> 24) & 0xff,
291 (addr >> 16) & 0xff,
292 (addr >> 8) & 0xff,
293 (addr & 0xff)
294 },
295 .readcnt = 0,
296 .readarr = NULL,
297 }, {
298 .writecnt = 0,
299 .writearr = NULL,
300 .readcnt = 0,
301 .readarr = NULL,
302 }};
303
304 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
305
306 result = spi_send_multicommand(flash, 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 /* Wait until the Write-In-Progress bit is cleared.
313 * This usually takes 100-4000 ms, so wait in 100 ms steps.
314 */
315 while (spi_read_status_register(flash) & SPI_SR_WIP)
316 programmer_delay(100 * 1000);
317 /* FIXME: Check the status register for errors. */
318 return 0;
319}