yay, i have found a way around the const flashchips array. the common/general probing function that loops around the chips array actually does not use the chips form that array directly but copies each to a local non-const(!) buffer and calls the probing function with it as a non-const parameter. so we are free to modify the flashchip struct in the probing function. and this is exactly what i do. i set the total_size and the first eraser in ich_hwseq_probe accordingly to the values found in the registers (derived from the descriptors). this way we can even support dual-chip configurations easily (which i have also added). i think this is almost mergeable. it's probably easier to review this one squashed/combined with the original 11 version, especially if you did not look at that one before.
we still need someone test this on real (recoverable) hardware though. :( -- Kind regards/Mit freundlichen Grüßen, Stefan Tauner
>From 1f0d8d7b516102d79760ddfdbfeea427afed4d4d Mon Sep 17 00:00:00 2001 From: Stefan Tauner <[email protected]> Date: Sun, 5 Jun 2011 03:34:37 +0200 Subject: [PATCH] squash! add support for Intel Hardware Sequencing Signed-off-by: Stefan Tauner <[email protected]> --- flashchips.c | 27 ++--------- flashchips.h | 2 + flashrom.c | 6 +- ichspi.c | 144 ++++++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 111 insertions(+), 68 deletions(-) diff --git a/flashchips.c b/flashchips.c index f912c23..2f0161f 100644 --- a/flashchips.c +++ b/flashchips.c @@ -8507,44 +8507,27 @@ const struct flashchip flashchips[] = { .write = write_jedec_1, .read = read_memmapped, }, -#if defined(__i386__) || defined(__x86_64__) +#if defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__)) { .vendor = "Intel", .name = "Hardware Sequencing", .bustype = CHIP_BUSTYPE_SPI, .manufacture_id = INTEL_ID, - .model_id = GENERIC_DEVICE_ID, - .total_size = 4, + .model_id = INTEL_HWSEQ, + .total_size = 0, .page_size = 256, .tested = TEST_OK_PR, .probe = ich_hwseq_probe, .block_erasers = { - { - .eraseblocks = { {256, 4 * 4} }, + { /* erase blocks will be set by the probing function */ .block_erase = ich_hwseq_block_erase, - //}, { - //{ - //.eraseblocks = { {256, CHIPSIZE * 4} }, - //.block_erase = ich_hwseq_block_erase, - //}, { - //{ - //.eraseblocks = { {4 * 1024, CHIPSIZE / 4} }, - //.block_erase = ich_hwseq_block_erase, - //}, { - //{ - //.eraseblocks = { {8 * 1024, CHIPSIZE / 8} }, - //.block_erase = ich_hwseq_block_erase, - //}, { - //{ - //.eraseblocks = { {64 * 1024, CHIPSIZE / 64} }, - //.block_erase = ich_hwseq_block_erase, } }, .write = ich_hwseq_write_256, .read = ich_hwseq_read, }, -#endif // defined(__i386__) || defined(__x86_64__) +#endif // defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__)) { .vendor = "AMIC", .name = "unknown AMIC SPI chip", diff --git a/flashchips.h b/flashchips.h index 3b2b94f..6b8d574 100644 --- a/flashchips.h +++ b/flashchips.h @@ -340,6 +340,8 @@ #define SHARP_LH28F008SA 0xA2 /* Sharp chip, Intel Vendor ID */ #define SHARP_LH28F008SC 0xA6 /* Sharp chip, Intel Vendor ID */ +#define INTEL_HWSEQ 0xFFFE /* dummy ID for hardware sequencing */ + #define ISSI_ID 0xD5 /* ISSI Integrated Silicon Solutions */ /* diff --git a/flashrom.c b/flashrom.c index e9e6a77..41f4c26 100644 --- a/flashrom.c +++ b/flashrom.c @@ -1191,7 +1191,7 @@ notfound: programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size); } - if (!flash || !flash->name) + if (!fill_flash || !fill_flash->name) return -1; #if CONFIG_INTERNAL == 1 @@ -1203,8 +1203,8 @@ notfound: msg_cinfo("%s chip \"%s %s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found", - flash->vendor, flash->name, flash->total_size, - flashbuses_to_text(flash->bustype), location); + fill_flash->vendor, fill_flash->name, fill_flash->total_size, + flashbuses_to_text(fill_flash->bustype), location); /* Flash registers will not be mapped if the chip was forced. Lock info * may be stored in registers, so avoid lock info printing. diff --git a/ichspi.c b/ichspi.c index 8cdcb5c..238c43c 100644 --- a/ichspi.c +++ b/ichspi.c @@ -35,10 +35,11 @@ * */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__)) #include <string.h> #include "flash.h" +#include "flashchips.h" #include "chipdrivers.h" #include "programmer.h" #include "spi.h" @@ -1099,8 +1100,16 @@ static int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, return result; } -uint32_t ich_hwseq_get_erase_block_size(void) +static uint32_t ich_hwseq_get_flash_boundary(void) { + return (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12; +} + +/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes + * of the block containing this address. */ +static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr) +{ + REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF)); uint8_t enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF; const uint32_t dec_berase[4] = { @@ -1114,19 +1123,71 @@ uint32_t ich_hwseq_get_erase_block_size(void) int ich_hwseq_probe(struct flashchip *flash) { + uint32_t total_size, boundary; + uint32_t erase_size_low, size_low, erase_size_high, size_high; + struct block_eraser eraser; extern struct flash_descriptor fdbar; + + if (flash->manufacture_id != INTEL_ID || + flash->model_id != INTEL_HWSEQ) { + msg_cerr("This chip (%s) is not supported in hardware" + "sequencing mode and should never have been probed.\n", + flash->name); + msg_cerr("%s: Please report a bug at [email protected]\n", + __func__); + return 0; + } + msg_cdbg("Prerequisites for Intel Hardware Sequencing are "); - if (spi_programmer->type == SPI_CONTROLLER_ICH_HWSEQ) { - msg_cdbg("met.\n"); - msg_cdbg("Found %d attached SPI flash chips with a " - "combined density of %d kB.\n", fdbar.NC + 1, - (getFCBA_component_density(0) + - getFCBA_component_density(1)) / 1024); - return 1; - } else { + if (spi_programmer->type != SPI_CONTROLLER_ICH_HWSEQ) { msg_cdbg("not met.\n"); return 0; } + + msg_cdbg("met.\n"); + total_size = (getFCBA_component_density(0) + + getFCBA_component_density(1)); + msg_cdbg("Found %d attached SPI flash chip", fdbar.NC + 1); + if (fdbar.NC) + msg_cdbg("s with a combined"); + else + msg_cdbg(" with a"); + msg_cdbg(" density of %d kB.\n", total_size / 1024); + flash->total_size = total_size / 1024; + + eraser = flash->block_erasers[0]; + boundary = ich_hwseq_get_flash_boundary(); + size_high = total_size - boundary; + erase_size_high = ich_hwseq_get_erase_block_size(boundary); + + if (boundary == 0) { + msg_cdbg("There is only one partition containting the whole " + "address space (0x%06x - 0x%06x)\n", 0, size_high-1); + eraser.eraseblocks[0].size = erase_size_high; + eraser.eraseblocks[0].count = size_high / erase_size_high; + msg_cdbg("There are %d erase blocks with %d B each.\n", + size_high / erase_size_high, erase_size_high); + } else { + msg_cdbg("The flash is divided at address 0x%06x in two " + "partitions.\n", boundary); + size_low = total_size - size_high; + erase_size_low = ich_hwseq_get_erase_block_size(0); + + eraser.eraseblocks[0].size = erase_size_low; + eraser.eraseblocks[0].count = size_low / erase_size_low; + msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n", + 0, size_low-1); + msg_cdbg("In that range are %d erase blocks with %d B each.\n", + size_low / erase_size_low, erase_size_low); + + eraser.eraseblocks[1].size = erase_size_high; + eraser.eraseblocks[1].count = size_high / erase_size_high; + msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n", + boundary, size_high-1); + msg_cdbg("In that range are %d erase blocks with %d B each.\n", + size_high / erase_size_high, erase_size_high); + } + return 1; } static int ich_hwseq_send_command(unsigned int writecnt, @@ -1148,14 +1209,14 @@ int ich_hwseq_block_erase(struct flashchip *flash, uint32_t hsfs; uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */ - REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF)); - erase_block = ich_hwseq_get_erase_block_size(); - if (strcmp(flash->name, "Hardware Sequencing") != 0) { + if (flash->manufacture_id != INTEL_ID || + flash->model_id != INTEL_HWSEQ) { msg_perr("This chip (%s) is not supported in hardware" "sequencing mode\n", flash->name); return -1; } + erase_block = ich_hwseq_get_erase_block_size(addr); if (len != erase_block) { msg_cerr("Erase block size for address 0x%06x is %d B, " "but requested erase block size is %d B. " @@ -1166,6 +1227,8 @@ int ich_hwseq_block_erase(struct flashchip *flash, return -1; } + /* Although the hardware supports this (it would erase the whole block + * containing the address) we play safe here. */ if (addr % erase_block != 0) { msg_cerr("Erase address 0x%06x is not aligned to the erase " "block boundary (any multiple of %d). " @@ -1175,10 +1238,10 @@ int ich_hwseq_block_erase(struct flashchip *flash, return -1; } - msg_pdbg("erasing %d bytes starting at 0x%06x\n", len, addr); + msg_pdbg("Erasing %d bytes starting at 0x%06x\n", len, addr); hsfc = REGREAD16(ICH9_REG_HSFC); - /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ + /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */ REGWRITE16(ICH9_REG_HSFC, hsfc); hsfc &= ~HSFC_FCYCLE; /* clear operation */ hsfc = (0x11 << HSFC_FCYCLE_OFF); /* set erase operation */ @@ -1191,17 +1254,18 @@ int ich_hwseq_block_erase(struct flashchip *flash, --timeout) { programmer_delay(10); } + hsfs = REGREAD16(ICH9_REG_HSFS); if (!timeout) { - msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n", - REGREAD16(ICH9_REG_HSFS)); + msg_perr("timeout!\n"); + prettyprint_ich9_reg_hsfs(hsfs); + prettyprint_ich9_reg_hsfc(hsfs); return 1; } - hsfs = REGREAD16(ICH9_REG_HSFS); REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */ if (hsfs & HSFS_FCERR) { msg_perr("Transaction error between offset 0x%06x and 0x%06x + " - "%d (= 0x%06x)!\n", + "%d (=0x%06x)!\n", addr, addr, len, addr+len); prettyprint_ich9_reg_hsfs(hsfs); prettyprint_ich9_reg_hsfc(hsfs); @@ -1218,15 +1282,16 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len) uint16_t timeout = 100 * 60; int i; - if (strcmp(flash->name, "Hardware Sequencing") != 0) { + if (flash->manufacture_id != INTEL_ID || + flash->model_id != INTEL_HWSEQ) { msg_perr("This chip (%s) is not supported in hardware" - "sequencing mode\n", flash->name); + "sequencing mode.\n", flash->name); return -1; } if (len % 4 != 0) { - msg_perr("Read size has to be a multiple of 4 in hardware" - "sequencing mode\n"); + msg_perr("Read size has to be a multiple of 4 for this " + "implementation of hardware sequencing mode.\n"); return -1; } @@ -1249,13 +1314,14 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len) --timeout) { programmer_delay(10); } + hsfs = REGREAD16(ICH9_REG_HSFS); if (!timeout) { - msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n", - REGREAD16(ICH9_REG_HSFS)); + msg_perr("timeout!\n"); + prettyprint_ich9_reg_hsfs(hsfs); + prettyprint_ich9_reg_hsfc(hsfs); return 1; } - hsfs = REGREAD16(ICH9_REG_HSFS); REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */ if (hsfs & HSFS_FCERR) { msg_perr("Transaction error between offset 0x%06x and " @@ -1279,15 +1345,16 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len uint16_t hsfs; uint16_t timeout = 100 * 60; int i; - if (strcmp(flash->name, "Hardware Sequencing") != 0) { + if (flash->manufacture_id != INTEL_ID || + flash->model_id != INTEL_HWSEQ) { msg_perr("This chip (%s) is not supported in hardware" "sequencing mode\n", flash->name); return -1; } if ((len % 4 != 0)) { - msg_perr("Write size has to be a multiple of 4 in hardware " - "sequencing mode\n"); + msg_perr("Write size has to be a multiple of 4 for this " + "implementation of hardware sequencing mode\n"); return -1; } @@ -1312,13 +1379,14 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len --timeout) { programmer_delay(10); } + hsfs = REGREAD16(ICH9_REG_HSFS); if (!timeout) { - msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n", - REGREAD16(ICH9_REG_HSFS)); + msg_perr("timeout!\n"); + prettyprint_ich9_reg_hsfs(hsfs); + prettyprint_ich9_reg_hsfc(hsfs); return 1; } - hsfs = REGREAD16(ICH9_REG_HSFS); REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */ if (hsfs & HSFS_FCERR) { msg_perr("Transaction error between offset 0x%06x and " @@ -1471,8 +1539,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, int ichspi_desc = 0; /* used for hw sequencing detection */ extern struct flash_descriptor fdbar; - uint32_t size_low; - uint32_t size_high; switch (ich_generation) { case 7: @@ -1615,15 +1681,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, pretty_print_ich_descriptors(); } - /* Fetch erase block sizes for addresses below and above FPBA - * and check if erase blocks are equal for all addresses. */ - REGWRITE32(ICH9_REG_FADDR, (0 & 0x00FFFFFF)); - size_low = ich_hwseq_get_erase_block_size(); - REGWRITE32(ICH9_REG_FADDR, - (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) & 0x00FFFFFF); - size_high = ich_hwseq_get_erase_block_size(); - - if ((ichspi_lock || fdbar.NC != 0) && (size_low == size_high)) + if (ichspi_lock || fdbar.NC != 0) register_spi_programmer(&spi_programmer_ich_hwseq); else { register_spi_programmer(&spi_programmer_ich9); -- 1.7.1
_______________________________________________ flashrom mailing list [email protected] http://www.flashrom.org/mailman/listinfo/flashrom
