blob: 75730e0b8a433e2dc5bdc367f25182b5c4929194 [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}
Boris Baykov5de3b9b2016-06-11 18:29:02 +0200320
321/* Write Extended Address Register value */
322int spi_write_extended_address_register(struct flashctx *flash, uint8_t regdata)
323{
324 int result;
325 struct spi_command cmds[] = {
326 {
327 .writecnt = JEDEC_WREN_OUTSIZE,
328 .writearr = (const unsigned char[]){ JEDEC_WREN },
329 .readcnt = 0,
330 .readarr = NULL,
331 }, {
332 .writecnt = JEDEC_WRITE_EXT_ADDR_REG_OUTSIZE,
333 .writearr = (const unsigned char[]){
334 JEDEC_WRITE_EXT_ADDR_REG,
335 regdata
336 },
337 .readcnt = 0,
338 .readarr = NULL,
339 }, {
340 .writecnt = 0,
341 .writearr = NULL,
342 .readcnt = 0,
343 .readarr = NULL,
344 }};
345
346 msg_trace("-> %s (%02X)\n", __func__, regdata);
347
348 result = spi_send_multicommand(flash, cmds);
349 if (result) {
350 msg_cerr("%s failed during command execution\n", __func__);
351 return result;
352 }
353 return 0;
354}
355
356/* Assign required value of Extended Address Register. This function
357 keeps last value of the register and writes the register if the
358 value has to be changed only. */
359int set_extended_address_register(struct flashctx *flash, uint8_t data)
360{
361 static uint8_t ext_addr_reg_state; /* memory for last register state */
362 static int ext_addr_reg_state_valid = 0;
363 int result;
364
365 if (ext_addr_reg_state_valid == 0 || data != ext_addr_reg_state) {
366 result = spi_write_extended_address_register(flash, data);
367 if (result) {
368 ext_addr_reg_state_valid = 0;
369 return result;
370 }
371 ext_addr_reg_state = data;
372 ext_addr_reg_state_valid = 1;
373 }
374 return 0;
375}
376
377/* Program one flash byte using Extended Address Register
378 from 3-bytes addressing mode */
379int spi_byte_program_4ba_ereg(struct flashctx *flash, unsigned int addr,
380 uint8_t databyte)
381{
382 int result;
383 struct spi_command cmds[] = {
384 {
385 .writecnt = JEDEC_WREN_OUTSIZE,
386 .writearr = (const unsigned char[]){ JEDEC_WREN },
387 .readcnt = 0,
388 .readarr = NULL,
389 }, {
390 .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE,
391 .writearr = (const unsigned char[]){
392 JEDEC_BYTE_PROGRAM,
393 (addr >> 16) & 0xff,
394 (addr >> 8) & 0xff,
395 (addr & 0xff),
396 databyte
397 },
398 .readcnt = 0,
399 .readarr = NULL,
400 }, {
401 .writecnt = 0,
402 .writearr = NULL,
403 .readcnt = 0,
404 .readarr = NULL,
405 }};
406
407 msg_trace("-> %s (0x%08X)\n", __func__, addr);
408
409 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
410 if (result)
411 return result;
412
413 result = spi_send_multicommand(flash, cmds);
414 if (result) {
415 msg_cerr("%s failed during command execution at address 0x%x\n",
416 __func__, addr);
417 }
418 return result;
419}
420
421/* Program flash bytes using Extended Address Register
422 from 3-bytes addressing mode */
423int spi_nbyte_program_4ba_ereg(struct flashctx *flash, unsigned int addr,
424 const uint8_t *bytes, unsigned int len)
425{
426 int result;
427 unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = {
428 JEDEC_BYTE_PROGRAM,
429 (addr >> 16) & 0xff,
430 (addr >> 8) & 0xff,
431 (addr >> 0) & 0xff
432 };
433 struct spi_command cmds[] = {
434 {
435 .writecnt = JEDEC_WREN_OUTSIZE,
436 .writearr = (const unsigned char[]){ JEDEC_WREN },
437 .readcnt = 0,
438 .readarr = NULL,
439 }, {
440 .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len,
441 .writearr = cmd,
442 .readcnt = 0,
443 .readarr = NULL,
444 }, {
445 .writecnt = 0,
446 .writearr = NULL,
447 .readcnt = 0,
448 .readarr = NULL,
449 }};
450
451 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
452
453 if (!len) {
454 msg_cerr("%s called for zero-length write\n", __func__);
455 return 1;
456 }
457 if (len > 256) {
458 msg_cerr("%s called for too long a write\n", __func__);
459 return 1;
460 }
461
462 memcpy(&cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1], bytes, len);
463
464 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
465 if (result)
466 return result;
467
468 result = spi_send_multicommand(flash, cmds);
469 if (result) {
470 msg_cerr("%s failed during command execution at address 0x%x\n",
471 __func__, addr);
472 }
473 return result;
474}
475
476/* Read flash bytes using Extended Address Register
477 from 3-bytes addressing mode */
478int spi_nbyte_read_4ba_ereg(struct flashctx *flash, unsigned int addr,
479 uint8_t *bytes, unsigned int len)
480{
481 int result;
482 const unsigned char cmd[JEDEC_READ_OUTSIZE] = {
483 JEDEC_READ,
484 (addr >> 16) & 0xff,
485 (addr >> 8) & 0xff,
486 (addr >> 0) & 0xff
487 };
488
489 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + len - 1);
490
491 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
492 if (result)
493 return result;
494
495 /* Send Read */
496 return spi_send_command(flash, sizeof(cmd), len, cmd, bytes);
497}
498
499/* Erases 4 KB of flash using Extended Address Register
500 from 3-bytes addressing mode */
501int spi_block_erase_20_4ba_ereg(struct flashctx *flash, unsigned int addr,
502 unsigned int blocklen)
503{
504 int result;
505 struct spi_command cmds[] = {
506 {
507 .writecnt = JEDEC_WREN_OUTSIZE,
508 .writearr = (const unsigned char[]){ JEDEC_WREN },
509 .readcnt = 0,
510 .readarr = NULL,
511 }, {
512 .writecnt = JEDEC_SE_OUTSIZE,
513 .writearr = (const unsigned char[]){
514 JEDEC_SE,
515 (addr >> 16) & 0xff,
516 (addr >> 8) & 0xff,
517 (addr & 0xff)
518 },
519 .readcnt = 0,
520 .readarr = NULL,
521 }, {
522 .writecnt = 0,
523 .writearr = NULL,
524 .readcnt = 0,
525 .readarr = NULL,
526 }};
527
528 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
529
530 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
531 if (result)
532 return result;
533
534 result = spi_send_multicommand(flash, cmds);
535 if (result) {
536 msg_cerr("%s failed during command execution at address 0x%x\n",
537 __func__, addr);
538 return result;
539 }
540 /* Wait until the Write-In-Progress bit is cleared.
541 * This usually takes 15-800 ms, so wait in 10 ms steps.
542 */
543 while (spi_read_status_register(flash) & SPI_SR_WIP)
544 programmer_delay(10 * 1000);
545 /* FIXME: Check the status register for errors. */
546 return 0;
547}
548
549/* Erases 32 KB of flash using Extended Address Register
550 from 3-bytes addressing mode */
551int spi_block_erase_52_4ba_ereg(struct flashctx *flash, unsigned int addr,
552 unsigned int blocklen)
553{
554 int result;
555 struct spi_command cmds[] = {
556 {
557 .writecnt = JEDEC_WREN_OUTSIZE,
558 .writearr = (const unsigned char[]){ JEDEC_WREN },
559 .readcnt = 0,
560 .readarr = NULL,
561 }, {
562 .writecnt = JEDEC_BE_52_OUTSIZE,
563 .writearr = (const unsigned char[]){
564 JEDEC_BE_52,
565 (addr >> 16) & 0xff,
566 (addr >> 8) & 0xff,
567 (addr & 0xff)
568 },
569 .readcnt = 0,
570 .readarr = NULL,
571 }, {
572 .writecnt = 0,
573 .writearr = NULL,
574 .readcnt = 0,
575 .readarr = NULL,
576 }};
577
578 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
579
580 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
581 if (result)
582 return result;
583
584 result = spi_send_multicommand(flash, cmds);
585 if (result) {
586 msg_cerr("%s failed during command execution at address 0x%x\n",
587 __func__, addr);
588 return result;
589 }
590 /* Wait until the Write-In-Progress bit is cleared.
591 * This usually takes 100-4000 ms, so wait in 100 ms steps.
592 */
593 while (spi_read_status_register(flash) & SPI_SR_WIP)
594 programmer_delay(100 * 1000);
595 /* FIXME: Check the status register for errors. */
596 return 0;
597}
598
599/* Erases 64 KB of flash using Extended Address Register
600 from 3-bytes addressing mode */
601int spi_block_erase_d8_4ba_ereg(struct flashctx *flash, unsigned int addr,
602 unsigned int blocklen)
603{
604 int result;
605 struct spi_command cmds[] = {
606 {
607 .writecnt = JEDEC_WREN_OUTSIZE,
608 .writearr = (const unsigned char[]){ JEDEC_WREN },
609 .readcnt = 0,
610 .readarr = NULL,
611 }, {
612 .writecnt = JEDEC_BE_D8_OUTSIZE,
613 .writearr = (const unsigned char[]){
614 JEDEC_BE_D8,
615 (addr >> 16) & 0xff,
616 (addr >> 8) & 0xff,
617 (addr & 0xff)
618 },
619 .readcnt = 0,
620 .readarr = NULL,
621 }, {
622 .writecnt = 0,
623 .writearr = NULL,
624 .readcnt = 0,
625 .readarr = NULL,
626 }};
627
628 msg_trace("-> %s (0x%08X-0x%08X)\n", __func__, addr, addr + blocklen - 1);
629
630 result = set_extended_address_register(flash, (addr >> 24) & 0xff);
631 if (result)
632 return result;
633
634 result = spi_send_multicommand(flash, cmds);
635 if (result) {
636 msg_cerr("%s failed during command execution at address 0x%x\n",
637 __func__, addr);
638 return result;
639 }
640 /* Wait until the Write-In-Progress bit is cleared.
641 * This usually takes 100-4000 ms, so wait in 100 ms steps.
642 */
643 while (spi_read_status_register(flash) & SPI_SR_WIP)
644 programmer_delay(100 * 1000);
645 /* FIXME: Check the status register for errors. */
646 return 0;
647}