Hello Carl-Daniel Hailfinger,
I'd like you to do a code review. Please visit
https://review.coreboot.org/25097
to review the following change.
Change subject: Add timeout check to SPI bitbang bus request
......................................................................
Add timeout check to SPI bitbang bus request
Am 05.10.2010 22:42 schrieb Iain Paton:
>>> root@p7fe-64:~/flashrom# ./flashrom -p nicintel_spi -V
>>> flashrom v0.9.2-r1186 on Linux 2.6.35-dt (x86_64), built with libpci
>>> 3.1.4, GCC 4.4.3, little endian
>>> Initializing nicintel_spi programmer
>>> Found "Intel 82540EM Gigabit Ethernet Controller" (8086:100e, BDF
>>> 06:02.0).
>
> I have a few of these cards, so maybe I'll try a different one just to
> be sure there's nothing odd going on with this one.
Here is an updated timeout patch (no functional changes for
nicintel_spi). A year has passed, and I'm still trying to find someone
who can test and ack it.
GatoLoko: This new patch also addresses the SB600 timeout issue you were
seeing.
Change-Id: I304546c98441fbd2e5daccb798557d016336a505
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006(a)gmx.net>
---
M bitbang_spi.c
M mcp6x_spi.c
M nicintel_spi.c
M ogp_spi.c
M programmer.h
M sb600spi.c
6 files changed, 61 insertions(+), 14 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/97/25097/1
diff --git a/bitbang_spi.c b/bitbang_spi.c
index 391fd32..a306e5f 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -51,10 +51,11 @@
return bitbang_spi_master->get_miso();
}
-static void bitbang_spi_request_bus(void)
+static int bitbang_spi_request_bus(void)
{
if (bitbang_spi_master->request_bus)
- bitbang_spi_master->request_bus();
+ return bitbang_spi_master->request_bus();
+ return 0;
}
static void bitbang_spi_release_bus(void)
@@ -99,7 +100,7 @@
register_spi_programmer(&spi_programmer_bitbang);
- /* FIXME: Run bitbang_spi_request_bus here or in programmer init? */
+ /* FIXME: Run bitbang_spi_request_bus here or per command? */
bitbang_spi_set_cs(1);
bitbang_spi_set_sck(0);
bitbang_spi_set_mosi(0);
@@ -144,13 +145,15 @@
static int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
- int i;
+ int i, ret;
/* FIXME: Run bitbang_spi_request_bus here or in programmer init?
* Requesting and releasing the SPI bus is handled in here to allow the
* programmer to use its own SPI engine for native accesses.
*/
- bitbang_spi_request_bus();
+ ret = bitbang_spi_request_bus();
+ if (ret)
+ return ret;
bitbang_spi_set_cs(0);
for (i = 0; i < writecnt; i++)
bitbang_spi_readwrite_byte(writearr[i]);
diff --git a/mcp6x_spi.c b/mcp6x_spi.c
index d2c31be..c30e36a 100644
--- a/mcp6x_spi.c
+++ b/mcp6x_spi.c
@@ -39,22 +39,38 @@
#define MCP6X_SPI_REQUEST 0
#define MCP6X_SPI_GRANT 8
+/* 1000000 loops are roughly 1 s. */
+#define MAX_REQUEST_LOOPS 1000000
+
void *mcp6x_spibar = NULL;
/* Cached value of last GPIO state. */
static uint8_t mcp_gpiostate;
-static void mcp6x_request_spibus(void)
+static void mcp6x_release_spibus(void);
+
+static int mcp6x_request_spibus(void)
{
+ int i = 0;
+
mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
mcp_gpiostate |= 1 << MCP6X_SPI_REQUEST;
mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
/* Wait until we are allowed to use the SPI bus. */
- while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
+ while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) {
+ if (i++ > MAX_REQUEST_LOOPS) {
+ /* Update the cache. */
+ mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+ mcp6x_release_spibus();
+ msg_perr("%s: Timeout! Aborting.\n", __func__);
+ return TIMEOUT_ERROR;
+ }
+ }
/* Update the cache. */
mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+ return 0;
}
static void mcp6x_release_spibus(void)
diff --git a/nicintel_spi.c b/nicintel_spi.c
index aacd68c..9f8631e 100644
--- a/nicintel_spi.c
+++ b/nicintel_spi.c
@@ -58,6 +58,9 @@
// #define FL_BUSY 30
// #define FL_ER 31
+/* 1000000 loops are roughly 1 s. */
+#define MAX_REQUEST_LOOPS 1000000
+
uint8_t *nicintel_spibar;
const struct pcidev_status nics_intel_spi[] = {
@@ -69,16 +72,27 @@
{},
};
-static void nicintel_request_spibus(void)
+static void nicintel_release_spibus(void);
+
+static int nicintel_request_spibus(void)
{
uint32_t tmp;
+ int i = 0;
tmp = pci_mmio_readl(nicintel_spibar + FLA);
tmp |= 1 << FL_REQ;
pci_mmio_writel(tmp, nicintel_spibar + FLA);
/* Wait until we are allowed to use the SPI bus. */
- while (!(pci_mmio_readl(nicintel_spibar + FLA) & (1 << FL_GNT))) ;
+ while (!(pci_mmio_readl(nicintel_spibar + FLA) & (1 << FL_GNT))) {
+ if (i++ > MAX_REQUEST_LOOPS) {
+ nicintel_release_spibus();
+ msg_perr("%s: Timeout! Aborting.\n", __func__);
+ return TIMEOUT_ERROR;
+ }
+ }
+
+ return 0;
}
static void nicintel_release_spibus(void)
diff --git a/ogp_spi.c b/ogp_spi.c
index dbaa57a..aa9d737 100644
--- a/ogp_spi.c
+++ b/ogp_spi.c
@@ -50,9 +50,13 @@
{},
};
-static void ogp_request_spibus(void)
+static int ogp_request_spibus(void)
{
+ /* FIXME: Do we have to check if any other SPI accesses are running
+ * right now? Can the request fail?
+ */
pci_mmio_writel(1, ogp_spibar + ogp_reg_sel);
+ return 0;
}
static void ogp_release_spibus(void)
diff --git a/programmer.h b/programmer.h
index b16e4f8..59c7d13 100644
--- a/programmer.h
+++ b/programmer.h
@@ -131,7 +131,7 @@
void (*set_sck) (int val);
void (*set_mosi) (int val);
int (*get_miso) (void);
- void (*request_bus) (void);
+ int (*request_bus) (void);
void (*release_bus) (void);
};
diff --git a/sb600spi.c b/sb600spi.c
index 9d82b47..7049924 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -80,12 +80,19 @@
return ret;
}
-static void execute_command(void)
+static int execute_command(void)
{
+ int timeout = 10000000;
+
mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
- while (mmio_readb(sb600_spibar + 2) & 1)
+ while ((mmio_readb(sb600_spibar + 2) & 1) && --timeout)
;
+ if (!timeout) {
+ msg_perr("SB600: execute_command timeout!\n");
+ return TIMEOUT_ERROR;
+ }
+ return 0;
}
static int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt,
@@ -96,6 +103,7 @@
unsigned char cmd = *writearr++;
unsigned int readoffby1;
unsigned char readwrite;
+ int ret;
writecnt--;
@@ -144,7 +152,9 @@
return SPI_PROGRAMMER_ERROR;
msg_pspew("Executing: \n");
- execute_command();
+ ret = execute_command();
+ if (ret)
+ return ret;
/*
* After the command executed, we should find out the index of the
--
To view, visit https://review.coreboot.org/25097
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I304546c98441fbd2e5daccb798557d016336a505
Gerrit-Change-Number: 25097
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006(a)gmx.net>
Nico Huber has posted comments on this change. ( https://review.coreboot.org/25096 )
Change subject: Add support for the Macronix MX28F2000P chip (256KB parallel)
......................................................................
Patch Set 1:
Has some comments on the ML:
https://mail.coreboot.org/pipermail/flashrom/2011-September/007908.html
--
To view, visit https://review.coreboot.org/25096
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: Id0c48d7cb3055a2c23bb9c601b73132390de1688
Gerrit-Change-Number: 25096
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Uwe Hermann <uwe(a)hermann-uwe.de>
Gerrit-Reviewer: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-Comment-Date: Sun, 11 Mar 2018 14:22:57 +0000
Gerrit-HasComments: No
Gerrit-HasLabels: No
Hello Uwe Hermann,
I'd like you to do a code review. Please visit
https://review.coreboot.org/25096
to review the following change.
Change subject: Add support for the Macronix MX28F2000P chip (256KB parallel)
......................................................................
Add support for the Macronix MX28F2000P chip (256KB parallel)
On Fri, Sep 02, 2011 at 10:51:43PM +0200, Uwe Hermann wrote:
> See patch for a first attempt to support the Macronix MX28F2000P.
Updated patch which now works.
Thanks to Carl-Daniel for pointing out that you need two 0x90 commands,
one per ID byte you want to read. Thanks Meteo0 on IRC for testing the
patch on his hardware, and verifying that the board always provides 12V
on the VPP pin (which is why write/erase work).
The patch now does the work without major hacks. Unneeded delays are
removed, incorrect comments too.
Uwe.
Add support for the Macronix MX28F2000P chip (256KB parallel).
This 256KB chip has a similar, but not identical, command set to the
SST SST28SF040A chip. It features a chip erase, block erase, byte write,
chip ID, and reset command.
In contrast to the SST28SF040A, the reset command is 0xff, 0xff (instead of
only one 0xff), and the write command is 0x40 (instead of 0x10).
No locking/unlocking (protect/unprotect) commands are documented, it seems.
Finally, unlike the SST28SF040A, the MX28F2000P requires 12V for write and
erase operations. Only read/ID is supported with the usual 5V. On the tested
board the 12V are always supplied on the VPP pin (confirmed via multimeter)
though, so that's not a problem there.
All operations were successfully tested, thus mark the chip as OK.
Write log:
http://paste.flashrom.org/view.php?id=804
Change-Id: Id0c48d7cb3055a2c23bb9c601b73132390de1688
Signed-off-by: Uwe Hermann <uwe(a)hermann-uwe.de>
Tested-by: Max Varentsov <admin(a)phpcode.us> (Meteo0 on IRC)
---
M chipdrivers.h
M flashchips.c
M flashchips.h
M sst28sf040.c
4 files changed, 101 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/96/25096/1
diff --git a/chipdrivers.h b/chipdrivers.h
index 2746e52..b8b1485 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -123,6 +123,10 @@
int write_28sf040(struct flashchip *flash, uint8_t *buf, int start, int len);
int unprotect_28sf040(struct flashchip *flash);
int protect_28sf040(struct flashchip *flash);
+int probe_mx28f2000p(struct flashchip *flash);
+int write_mx28f2000p(struct flashchip *flash, uint8_t *src, int start, int len);
+int erase_sector_mx28f2000p(struct flashchip *flash, unsigned int address,
+ unsigned int sector_size);
/* sst49lfxxxc.c */
int erase_sector_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size);
diff --git a/flashchips.c b/flashchips.c
index 7ce4b58..7da7fad 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -4482,6 +4482,38 @@
{
.vendor = "Macronix",
+ .name = "MX28F2000P",
+ .bustype = BUS_PARALLEL,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX28F2000P,
+ .total_size = 256,
+ .page_size = 0, /* unused */
+ .feature_bits = 0,
+ .tested = TEST_OK_PREW,
+ .probe = probe_mx28f2000p,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = {
+ {4 * 1024, 4},
+ {16 * 1024, 14},
+ {4 * 1024, 4},
+ },
+ .block_erase = erase_sector_mx28f2000p,
+ }, {
+ .eraseblocks = { {256 * 1024, 1} },
+ .block_erase = erase_chip_28sf040,
+ }
+ },
+ .unlock = NULL, /* No locking mechanism available. */
+ .write = write_mx28f2000p,
+ .read = read_memmapped,
+ .voltage = {4500, 5500}, /* Needs 12V for write/erase! */
+ },
+
+ {
+ .vendor = "Macronix",
.name = "MX29F001B",
.bustype = BUS_PARALLEL,
.manufacture_id = MACRONIX_ID,
diff --git a/flashchips.h b/flashchips.h
index 03efb86..f6624dc 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -369,6 +369,7 @@
#define MACRONIX_MX25L1635D 0x2415
#define MACRONIX_MX25L1635E 0x2515 /* MX25L1635{E} */
#define MACRONIX_MX25L3235D 0x5E16 /* MX25L3225D/MX25L3235D/MX25L3237D */
+#define MACRONIX_MX28F2000P 0x2a
#define MACRONIX_MX29F001B 0x19
#define MACRONIX_MX29F001T 0x18
#define MACRONIX_MX29F002B 0x34 /* Same as MX29F002NB; N has reset pin n/c. */
diff --git a/sst28sf040.c b/sst28sf040.c
index d621cc7..cf3ba84 100644
--- a/sst28sf040.c
+++ b/sst28sf040.c
@@ -26,6 +26,7 @@
#define AUTO_PG_ERASE1 0x20
#define AUTO_PG_ERASE2 0xD0
#define AUTO_PGRM 0x10
+#define AUTO_PGRM2 0x40 /* Used on MX28F2000P */
#define CHIP_ERASE 0x30
#define RESET 0xFF
#define READ_ID 0x90
@@ -60,7 +61,8 @@
return 0;
}
-int erase_sector_28sf040(struct flashchip *flash, unsigned int address, unsigned int sector_size)
+static int erase_sector_28sf040_generic(struct flashchip *flash,
+ unsigned int address, unsigned int sector_size, int toggle_delay)
{
chipaddr bios = flash->virtual_memory;
@@ -68,38 +70,65 @@
chip_writeb(AUTO_PG_ERASE1, bios);
chip_writeb(AUTO_PG_ERASE2, bios + address);
- /* wait for Toggle bit ready */
+ programmer_delay(toggle_delay);
+
+ /* Wait for toggle bit ready. */
toggle_ready_jedec(bios);
/* FIXME: Check the status register for errors. */
return 0;
}
+int erase_sector_28sf040(struct flashchip *flash, unsigned int address,
+ unsigned int sector_size)
+{
+ return erase_sector_28sf040_generic(flash, address, sector_size, 0);
+}
+
+int erase_sector_mx28f2000p(struct flashchip *flash, unsigned int address,
+ unsigned int sector_size)
+{
+ /* Needs 200us delay before the toggle bit checking begins. */
+ return erase_sector_28sf040_generic(flash, address, sector_size, 200);
+}
+
/* chunksize is 1 */
-int write_28sf040(struct flashchip *flash, uint8_t *src, int start, int len)
+static int write_28sf040_generic(struct flashchip *flash, uint8_t *src,
+ int start, int len, uint8_t auto_pgrm)
{
int i;
chipaddr bios = flash->virtual_memory;
chipaddr dst = flash->virtual_memory + start;
for (i = 0; i < len; i++) {
- /* transfer data from source to destination */
+ /* Transfer data from source to destination. */
if (*src == 0xFF) {
dst++, src++;
- /* If the data is 0xFF, don't program it */
+ /* If the data is 0xFF, don't program it. */
continue;
}
- /*issue AUTO PROGRAM command */
- chip_writeb(AUTO_PGRM, dst);
+
+ /* Issue auto program command. */
+ chip_writeb(auto_pgrm, dst);
chip_writeb(*src++, dst++);
- /* wait for Toggle bit ready */
+ /* Wait for Toggle bit ready. */
toggle_ready_jedec(bios);
}
return 0;
}
+int write_28sf040(struct flashchip *flash, uint8_t *src, int start, int len)
+{
+ return write_28sf040_generic(flash, src, start, len, AUTO_PGRM);
+}
+
+int write_mx28f2000p(struct flashchip *flash, uint8_t *src, int start, int len)
+{
+ return write_28sf040_generic(flash, src, start, len, AUTO_PGRM2);
+}
+
static int erase_28sf040(struct flashchip *flash)
{
chipaddr bios = flash->virtual_memory;
@@ -123,3 +152,30 @@
}
return erase_28sf040(flash);
}
+
+int probe_mx28f2000p(struct flashchip *flash)
+{
+ chipaddr bios = flash->virtual_memory;
+ uint8_t id1, id2;
+
+ /* Reset to get a clean state. */
+ chip_writeb(0xff, bios);
+ chip_writeb(0xff, bios);
+
+ /* Get the vendor and device ID. One 0x90 command per byte needed! */
+ chip_writeb(0x90, bios);
+ id1 = chip_readb(bios);
+ chip_writeb(0x90, bios);
+ id2 = chip_readb(bios + 0x01);
+
+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2);
+
+ if (!oddparity(id1))
+ msg_cdbg(", id1 parity violation");
+
+ msg_cdbg("\n");
+ if (id1 != flash->manufacture_id || id2 != flash->model_id)
+ return 0;
+
+ return 1;
+}
--
To view, visit https://review.coreboot.org/25096
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id0c48d7cb3055a2c23bb9c601b73132390de1688
Gerrit-Change-Number: 25096
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Uwe Hermann <uwe(a)hermann-uwe.de>