From 5824fbff010076cc0d2a4387c1b2f54644ae5785 Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Fri, 21 May 2010 23:09:42 +0000 Subject: Introduce a generic SPI read function: spi_write_chunked() 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 Corresponding to flashrom svn r1005. Signed-off-by: Carl-Daniel Hailfinger Acked-by: Michael Karcher Acked-by: David Hendricks --- bitbang_spi.c | 21 ++------------------- buspirate_spi.c | 25 ++----------------------- chipdrivers.h | 1 + ft2232_spi.c | 21 ++------------------- ichspi.c | 46 ++++++++++------------------------------------ sb600spi.c | 16 ++-------------- spi25.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 67 insertions(+), 113 deletions(-) diff --git a/bitbang_spi.c b/bitbang_spi.c index 8d6a9a1f..f60a7e15 100644 --- a/bitbang_spi.c +++ b/bitbang_spi.c @@ -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_read(struct flashchip *flash, uint8_t *buf, int start, int len) 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); } diff --git a/buspirate_spi.c b/buspirate_spi.c index dc491e20..524b608d 100644 --- a/buspirate_spi.c +++ b/buspirate_spi.c @@ -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_read(struct flashchip *flash, uint8_t *buf, int start, int len 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 @@ int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf) } 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); } diff --git a/chipdrivers.h b/chipdrivers.h index 6d5cef0f..9537775c 100644 --- a/chipdrivers.h +++ b/chipdrivers.h @@ -51,6 +51,7 @@ int spi_byte_program(int addr, uint8_t databyte); 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 */ diff --git a/ft2232_spi.c b/ft2232_spi.c index 97b4867f..111b46d5 100644 --- a/ft2232_spi.c +++ b/ft2232_spi.c @@ -2,7 +2,7 @@ * This file is part of the flashrom project. * * Copyright (C) 2009 Paul Fox - * 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_read(struct flashchip *flash, uint8_t *buf, int start, int len) 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 @@ int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) } 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 diff --git a/ichspi.c b/ichspi.c index fbe9092b..8add13e9 100644 --- a/ichspi.c +++ b/ichspi.c @@ -5,7 +5,7 @@ * Copyright (C) 2008 Claus Gindhart * Copyright (C) 2008 Dominik Geyer * Copyright (C) 2008 coresystems GmbH - * 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 @@ -149,8 +149,6 @@ static int generate_opcodes(OPCODES * op); 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 { @@ -636,28 +634,6 @@ static int run_opcode(OPCODE op, uint32_t offset, 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_pspew("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)) { - msg_perr("Error writing"); - return 1; - } - } - - return 0; -} - int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len) { int maxdata = 64; @@ -670,12 +646,14 @@ int ich_spi_read(struct flashchip *flash, uint8_t * buf, int start, int len) 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 */ msg_pinfo("Erasing flash before programming... "); @@ -687,19 +665,15 @@ int ich_spi_write_256(struct flashchip *flash, uint8_t * buf) msg_pinfo("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; } msg_pinfo("\n"); - return rc; + return ret; } int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, diff --git a/sb600spi.c b/sb600spi.c index 0cf797c3..5fcbd9ef 100644 --- a/sb600spi.c +++ b/sb600spi.c @@ -4,6 +4,7 @@ * Copyright (C) 2008 Wang Qingpei * Copyright (C) 2008 Joe Bao * 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 @@ int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) /* 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 @@ int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf) 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; } diff --git a/spi25.c b/spi25.c index c6d1b654..5a52f281 100644 --- a/spi25.c +++ b/spi25.c @@ -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 @@ int spi_nbyte_read(int address, uint8_t *bytes, int len) } /* - * 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) @@ -912,6 +912,52 @@ int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, return rc; } +/* + * 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 -- cgit v1.2.3