[flashrom] [PATCH] Partial writes for SPI
Carl-Daniel Hailfinger
c-d.hailfinger.devel.2006 at gmx.net
Thu Mar 25 03:10:08 CET 2010
Every SPI programmer driver had its own completely different chip write
implementation, and all of them were insufficiently commented.
Create spi_write_chunked as a copy of spi_read_chunked and convert all
SPI programmers to use it.
No functional changes except:
- Bus Pirate uses 12 Byte writes instead of 8 Byte writes
- SB600 uses 5 Byte writes instead of 1 Byte writes
Should work. Not for 0.9.1, but since I had that thing on my disk
anyway, I figured I'd post it to the list in case someone wants to
experiment with partial writes.
Tests appreciated.
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>
Index: flashrom-partial_write_spi/spi25.c
===================================================================
--- flashrom-partial_write_spi/spi25.c (Revision 982)
+++ flashrom-partial_write_spi/spi25.c (Arbeitskopie)
@@ -1,7 +1,7 @@
/*
* This file is part of the flashrom project.
*
- * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2007, 2008, 2009, 2010 Carl-Daniel Hailfinger
* Copyright (C) 2008 coresystems GmbH
*
* This program is free software; you can redistribute it and/or modify
@@ -874,7 +874,7 @@
}
/*
- * Read a complete flash chip.
+ * Read a part of the flash chip.
* Each page is read separately in chunks with a maximum size of chunksize.
*/
int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
@@ -913,6 +913,52 @@
}
/*
+ * Write a part of the flash chip.
+ * Each page is written separately in chunks with a maximum size of chunksize.
+ */
+int spi_write_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize)
+{
+ int rc = 0;
+ int i, j, starthere, lenhere;
+ /* FIXME: page_size is the wrong variable. We need max_writechunk_size
+ * in struct flashchip to do this properly. All chips using
+ * spi_chip_write_256 have page_size set to max_writechunk_size, so
+ * we're OK for now.
+ */
+ int page_size = flash->page_size;
+ int towrite;
+
+ /* Warning: This loop has a very unusual condition and body.
+ * The loop needs to go through each page with at least one affected
+ * byte. The lowest page number is (start / page_size) since that
+ * division rounds down. The highest page number we want is the page
+ * where the last byte of the range lives. That last byte has the
+ * address (start + len - 1), thus the highest page number is
+ * (start + len - 1) / page_size. Since we want to include that last
+ * page as well, the loop condition uses <=.
+ */
+ for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
+ /* Byte position of the first byte in the range in this page. */
+ /* starthere is an offset to the base address of the chip. */
+ starthere = max(start, i * page_size);
+ /* Length of bytes in the range in this page. */
+ lenhere = min(start + len, (i + 1) * page_size) - starthere;
+ for (j = 0; j < lenhere; j += chunksize) {
+ towrite = min(chunksize, lenhere - j);
+ rc = spi_nbyte_program(starthere + j, buf + starthere - start + j, towrite);
+ if (rc)
+ break;
+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
+ programmer_delay(10);
+ }
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/*
* Program chip using byte programming. (SLOW!)
* This is for chips which can only handle one byte writes
* and for chips where memory mapped programming is impossible
Index: flashrom-partial_write_spi/buspirate_spi.c
===================================================================
--- flashrom-partial_write_spi/buspirate_spi.c (Revision 982)
+++ flashrom-partial_write_spi/buspirate_spi.c (Arbeitskopie)
@@ -1,7 +1,7 @@
/*
* This file is part of the flashrom project.
*
- * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -319,7 +319,6 @@
int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf)
{
int total_size = 1024 * flash->total_size;
- int i;
spi_disable_blockprotect();
/* Erase first. */
@@ -330,25 +329,5 @@
}
msg_pinfo("done.\n");
- /* FIXME: We could do 12 byte writes, but then we'd have to make sure
- * not to cross a 256 byte page boundary. This problem only applies to
- * writes, reads can cross page boundaries just fine.
- */
- for (i = 0; i < total_size; i += 8) {
- int l, r;
- if (i + 8 <= total_size)
- l = 8;
- else
- l = total_size - i;
-
- if ((r = spi_nbyte_program(i, &buf[i], l))) {
- msg_perr("%s: write fail %d\n", __func__, r);
- return 1;
- }
-
- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
- /* loop */;
- }
-
- return 0;
+ return spi_write_chunked(flash, buf, 0, total_size, 12);
}
Index: flashrom-partial_write_spi/bitbang_spi.c
===================================================================
--- flashrom-partial_write_spi/bitbang_spi.c (Revision 982)
+++ flashrom-partial_write_spi/bitbang_spi.c (Arbeitskopie)
@@ -1,7 +1,7 @@
/*
* This file is part of the flashrom project.
*
- * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -142,24 +142,7 @@
int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf)
{
int total_size = 1024 * flash->total_size;
- int i;
msg_pdbg("total_size is %d\n", total_size);
- for (i = 0; i < total_size; i += 256) {
- int l, r;
- if (i + 256 <= total_size)
- l = 256;
- else
- l = total_size - i;
-
- if ((r = spi_nbyte_program(i, &buf[i], l))) {
- msg_perr("%s: write fail %d\n", __func__, r);
- return 1;
- }
-
- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
- /* loop */;
- }
-
- return 0;
+ return spi_write_chunked(flash, buf, 0, total_size, 256);
}
Index: flashrom-partial_write_spi/ft2232_spi.c
===================================================================
--- flashrom-partial_write_spi/ft2232_spi.c (Revision 982)
+++ flashrom-partial_write_spi/ft2232_spi.c (Arbeitskopie)
@@ -2,7 +2,7 @@
* This file is part of the flashrom project.
*
* Copyright (C) 2009 Paul Fox <pgf at laptop.org>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -288,7 +288,6 @@
int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf)
{
int total_size = 1024 * flash->total_size;
- int i;
spi_disable_blockprotect();
/* Erase first. */
@@ -299,23 +298,7 @@
}
msg_pinfo("done.\n");
msg_pdbg("total_size is %d\n", total_size);
- for (i = 0; i < total_size; i += 256) {
- int l, r;
- if (i + 256 <= total_size)
- l = 256;
- else
- l = total_size - i;
-
- if ((r = spi_nbyte_program(i, &buf[i], l))) {
- msg_perr("%s: write fail %d\n", __func__, r);
- return 1;
- }
-
- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
- /* loop */;
- }
-
- return 0;
+ return spi_write_chunked(flash, buf, 0, total_size, 256);
}
#endif
Index: flashrom-partial_write_spi/sb600spi.c
===================================================================
--- flashrom-partial_write_spi/sb600spi.c (Revision 982)
+++ flashrom-partial_write_spi/sb600spi.c (Arbeitskopie)
@@ -4,6 +4,7 @@
* Copyright (C) 2008 Wang Qingpei <Qingpei.Wang at amd.com>
* Copyright (C) 2008 Joe Bao <Zheng.Bao at amd.com>
* Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,7 +50,6 @@
/* FIXME: SB600 can write 5 bytes per transaction. */
int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf)
{
- int i;
int total_size = flash->total_size * 1024;
int result = 0;
@@ -63,19 +63,7 @@
msg_pinfo("done.\n");
msg_pinfo("Programming flash");
- for (i = 0; i < total_size; i++, buf++) {
- result = spi_nbyte_program(i, buf, 1);
- if (result) {
- msg_perr("Write error!\n");
- return result;
- }
-
- /* wait program complete. */
- if (i % 0x8000 == 0)
- msg_pspew(".");
- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
- ;
- }
+ result = spi_write_chunked(flash, buf, 0, total_size, 5);
msg_pinfo(" done.\n");
return result;
}
Index: flashrom-partial_write_spi/ichspi.c
===================================================================
--- flashrom-partial_write_spi/ichspi.c (Revision 982)
+++ flashrom-partial_write_spi/ichspi.c (Arbeitskopie)
@@ -5,7 +5,7 @@
* Copyright (C) 2008 Claus Gindhart <claus.gindhart at kontron.com>
* Copyright (C) 2008 Dominik Geyer <dominik.geyer at kontron.com>
* Copyright (C) 2008 coresystems GmbH <info at coresystems.de>
- * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -160,8 +160,6 @@
static int program_opcodes(OPCODES * op);
static int run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data);
-static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
- int offset, int maxdata);
/* for pairing opcodes with their required preop */
struct preop_opcode_pair {
@@ -645,28 +643,6 @@
return -1;
}
-static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes,
- int offset, int maxdata)
-{
- int page_size = flash->page_size;
- uint32_t remaining = page_size;
- int towrite;
-
- msg_comm_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n",
- offset, page_size, bytes);
-
- for (; remaining > 0; remaining -= towrite) {
- towrite = min(remaining, maxdata);
- if (spi_nbyte_program(offset + (page_size - remaining),
- &bytes[page_size - remaining], towrite)) {
- printf_debug("Error writing");
- return 1;
- }
- }
-
- return 0;
-}
-
int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len)
{
int maxdata = 64;
@@ -679,12 +655,14 @@
int ich_spi_write_256(struct flashchip *flash, uint8_t * buf)
{
- int i, j, rc = 0;
+ int i, ret = 0;
int total_size = flash->total_size * 1024;
- int page_size = flash->page_size;
int erase_size = 64 * 1024;
int maxdata = 64;
+ if (spi_controller == SPI_CONTROLLER_VIA)
+ maxdata = 16;
+
spi_disable_blockprotect();
/* Erase first */
printf("Erasing flash before programming... ");
@@ -696,19 +674,15 @@
printf("Programming page: \n");
for (i = 0; i < total_size / erase_size; i++) {
- if (spi_controller == SPI_CONTROLLER_VIA)
- maxdata = 16;
-
- for (j = 0; j < erase_size / page_size; j++) {
- ich_spi_write_page(flash,
- (void *)(buf + (i * erase_size) + (j * page_size)),
- (i * erase_size) + (j * page_size), maxdata);
- }
+ ret = spi_write_chunked(flash, buf + (i * erase_size),
+ i * erase_size, erase_size, maxdata);
+ if (ret)
+ break;
}
printf("\n");
- return rc;
+ return ret;
}
int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
Index: flashrom-partial_write_spi/chipdrivers.h
===================================================================
--- flashrom-partial_write_spi/chipdrivers.h (Revision 982)
+++ flashrom-partial_write_spi/chipdrivers.h (Arbeitskopie)
@@ -51,6 +51,7 @@
int spi_nbyte_program(int addr, uint8_t *bytes, int len);
int spi_nbyte_read(int addr, uint8_t *bytes, int len);
int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
+int spi_write_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize);
int spi_aai_write(struct flashchip *flash, uint8_t *buf);
/* 82802ab.c */
--
http://www.hailfinger.org/
More information about the flashrom
mailing list