Nico Huber has uploaded a new change for review. ( https://review.coreboot.org/18937 )
Change subject: fixup! flashrom: Add Skylake platform support ......................................................................
fixup! flashrom: Add Skylake platform support
ichspi: Consolidate copy-pasta hwseq code
Change-Id: I79d0c6284397ca382ce8e531c6f9490c74d31cc1 Signed-off-by: Nico Huber nico.huber@secunet.com --- M ichspi.c 1 file changed, 31 insertions(+), 234 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/37/18937/1
diff --git a/ichspi.c b/ichspi.c index 81da495..3b7e5d8 100644 --- a/ichspi.c +++ b/ichspi.c @@ -46,6 +46,8 @@ #define PCH100_HSFC_FCYCLE_OFF 1 /* 1-3: FLASH Cycle */ #define PCH100_HSFC_FCYCLE (0x7 << PCH100_HSFC_FCYCLE_OFF)
+#define PCH100_FADDR_FLA 0x07ffffff + #define PCH100_REG_FPR0 0x84 /* 32 Bytes Protected Range 0 */
#define PCH100_REG_PREOP_OPTYPE 0xA4 /* 32 Bits */ @@ -85,6 +87,7 @@ #define HSFC_SME (0x1 << HSFC_SME_OFF)
#define ICH9_REG_FADDR 0x08 /* 32 Bits */ +#define ICH9_FADDR_FLA 0x01ffffff #define ICH9_REG_FDATA0 0x10 /* 64 Bytes */
#define ICH9_REG_FRAP 0x50 /* 32 Bytes Flash Region Access Permissions */ @@ -1155,13 +1158,16 @@ static struct hwseq_data { uint32_t size_comp0; uint32_t size_comp1; + uint32_t addr_mask; + bool only_4k; + uint32_t hsfc_fcycle; } hwseq_data;
-/* Sets FLA in FADDR to (addr & 0x01FFFFFF) without touching other bits. */ +/* Sets FLA in FADDR to (addr & hwseq_data.addr_mask) without touching other bits. */ static void ich_hwseq_set_addr(uint32_t addr) { - uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF; - REGWRITE32(ICH9_REG_FADDR, (addr & 0x01FFFFFF) | addr_old); + uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~hwseq_data.addr_mask; + REGWRITE32(ICH9_REG_FADDR, (addr & hwseq_data.addr_mask) | addr_old); }
/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes @@ -1173,17 +1179,18 @@ */ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr) { - uint8_t enc_berase; static const uint32_t dec_berase[4] = { 256, 4 * 1024, 8 * 1024, 64 * 1024 }; + const uint8_t enc_berase = + hwseq_data.only_4k ? 1 : + (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF;
ich_hwseq_set_addr(addr); - enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> - HSFS_BERASE_OFF; + return dec_berase[enc_berase]; }
@@ -1205,7 +1212,7 @@ } REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); if (!timeout) { - addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF; + addr = REGREAD32(ICH9_REG_FADDR) & hwseq_data.addr_mask; msg_perr("Timeout error between offset 0x%08x and " "0x%08x (= 0x%08x + %d)!\n", addr, addr + len - 1, addr, len - 1); @@ -1215,7 +1222,7 @@ }
if (hsfs & HSFS_FCERR) { - addr = REGREAD32(ICH9_REG_FADDR) & 0x01FFFFFF; + addr = REGREAD32(ICH9_REG_FADDR) & hwseq_data.addr_mask; msg_perr("Transaction error between offset 0x%08x and " "0x%08x (= 0x%08x + %d)!\n", addr, addr + len - 1, addr, len - 1); @@ -1243,7 +1250,10 @@ flash->chip->total_size = total_size / 1024;
eraser = &(flash->chip->block_erasers[0]); - boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12; + if (!hwseq_data.only_4k) + boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12; + else + boundary = 0; size_high = total_size - boundary; erase_size_high = ich_hwseq_get_erase_block_size(boundary);
@@ -1317,7 +1327,7 @@ REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~HSFC_FCYCLE; /* clear operation */ + hsfc &= ~hwseq_data.hsfc_fcycle; /* clear operation */ hsfc |= (0x3 << HSFC_FCYCLE_OFF); /* set erase operation */ hsfc |= HSFC_FGO; /* start */ msg_pdbg("HSFC used for block erasing: "); @@ -1354,7 +1364,7 @@
ich_hwseq_set_addr(addr); hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~HSFC_FCYCLE; /* set read operation */ + hsfc &= ~hwseq_data.hsfc_fcycle; /* set read operation */ hsfc &= ~HSFC_FDBC; /* clear byte count */ /* set byte count */ hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC); @@ -1395,7 +1405,7 @@ block_len = min(block_len, 256 - (addr & 0xFF)); ich_fill_data(buf, block_len, ICH9_REG_FDATA0); hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~HSFC_FCYCLE; /* clear operation */ + hsfc &= ~hwseq_data.hsfc_fcycle; /* clear operation */ hsfc |= (0x2 << HSFC_FCYCLE_OFF); /* set write operation */ hsfc &= ~HSFC_FDBC; /* clear byte count */ /* set byte count */ @@ -1404,218 +1414,6 @@ REGWRITE16(ICH9_REG_HSFC, hsfc);
if (ich_hwseq_wait_for_cycle_complete(timeout, block_len)) - return -1; - addr += block_len; - buf += block_len; - len -= block_len; - } - return 0; -} - -/* Routines for PCH */ - -/* Sets FLA in FADDR to (addr & 0x07FFFFFF) without touching other bits. */ -static void pch_hwseq_set_addr(uint32_t addr) -{ - uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~0x07FFFFFF; - REGWRITE32(ICH9_REG_FADDR, (addr & 0x07FFFFFF) | addr_old); -} - -/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes - * of the block containing this address. May return nonsense if the address is - * not valid. The erase block size for a specific address depends on the flash - * partition layout as specified by FPB and the partition properties as defined - * by UVSCC and LVSCC respectively. An alternative to implement this method - * would be by querying FPB and the respective VSCC register directly. - */ -static uint32_t pch_hwseq_get_erase_block_size(unsigned int addr) -{ - pch_hwseq_set_addr(addr); - return 4 * 1024; -} - -/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals. - Resets all error flags in HSFS. - Returns 0 if the cycle completes successfully without errors within - timeout us, 1 on errors. */ -static int pch_hwseq_wait_for_cycle_complete(unsigned int timeout, - unsigned int len) -{ - uint16_t hsfs; - uint32_t addr; - - timeout /= 8; /* scale timeout duration to counter */ - while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) & - (HSFS_FDONE | HSFS_FCERR)) == 0) && - --timeout) { - programmer_delay(8); - } - REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); - if (!timeout) { - addr = REGREAD32(ICH9_REG_FADDR) & 0x07FFFFFF; - msg_perr("Timeout error between offset 0x%08x and " - "0x%08x (= 0x%08x + %d)!\n", - addr, addr + len - 1, addr, len - 1); - return 1; - } - - if (hsfs & HSFS_FCERR) { - addr = REGREAD32(ICH9_REG_FADDR) & 0x07FFFFFF; - msg_perr("Transaction error between offset 0x%08x and " - "0x%08x (= 0x%08x + %d)!\n", - addr, addr + len - 1, addr, len - 1); - return 1; - } - return 0; -} - - -int pch_hwseq_probe(struct flashctx *flash) -{ - uint32_t total_size, boundary = 0; /*There are no partitions in flash*/ - uint32_t erase_size_high, size_high; - struct block_eraser *eraser; - - total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1; - msg_cdbg("Found %d attached SPI flash chip", - (hwseq_data.size_comp1 != 0) ? 2 : 1); - if (hwseq_data.size_comp1 != 0) - msg_cdbg("s with a combined"); - else - msg_cdbg(" with a"); - msg_cdbg(" density of %d kB.\n", total_size / 1024); - flash->chip->total_size = total_size / 1024; - eraser = &(flash->chip->block_erasers[0]); - size_high = total_size - boundary; - erase_size_high = pch_hwseq_get_erase_block_size(boundary); - 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); - flash->chip->tested = TEST_OK_PREW; - return 1; -} - -int pch_hwseq_block_erase(struct flashctx *flash, - unsigned int addr, - unsigned int len) -{ - uint32_t erase_block; - uint16_t hsfc; - uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */ - - erase_block = pch_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. " - "Not erasing anything.\n", addr, erase_block, len); - 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). " - "Not erasing anything.\n", addr, erase_block); - return -1; - } - - if (addr + len > flash->chip->total_size * 1024) { - msg_perr("Request to erase some inaccessible memory address(es)" - " (addr=0x%x, len=%d). " - "Not erasing anything.\n", addr, len); - return -1; - } - - msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr); - - /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */ - REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); - - hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~PCH100_HSFC_FCYCLE; /* clear operation */ - hsfc |= (0x3 << HSFC_FCYCLE_OFF); /* set erase operation */ - hsfc |= HSFC_FGO; /* start */ - msg_pdbg("HSFC used for block erasing: "); - REGWRITE16(ICH9_REG_HSFC, hsfc); - - if (pch_hwseq_wait_for_cycle_complete(timeout, len)) - return -1; - return 0; -} - -int pch_hwseq_read(struct flashctx *flash, uint8_t *buf, unsigned int addr, - unsigned int len) -{ - uint16_t hsfc; - uint16_t timeout = 100 * 60; - uint8_t block_len; - - - if ((addr + len) > (flash->chip->total_size * 1024)) { - msg_perr("Request to read from an inaccessible memory address " - "(addr=0x%x, len=%d).\n", addr, len); - return -1; - } - - msg_pdbg("Reading %d bytes starting at 0x%06x.\n", len, addr); - /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ - - REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); - - while (len > 0) { - block_len = min(len, flash->mst->opaque.max_data_read); - pch_hwseq_set_addr(addr); - hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~PCH100_HSFC_FCYCLE; /* set read operation */ - hsfc &= ~HSFC_FDBC; /* clear byte count */ - /* set byte count */ - hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC); - hsfc |= HSFC_FGO; /* start */ - REGWRITE16(ICH9_REG_HSFC, hsfc); - - if (pch_hwseq_wait_for_cycle_complete(timeout, block_len)) - return 1; - ich_read_data(buf, block_len, ICH9_REG_FDATA0); - addr += block_len; - buf += block_len; - len -= block_len; - } - return 0; -} - -int pch_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned int addr, - unsigned int len) -{ - uint16_t hsfc; - uint16_t timeout = 100 * 60; - uint8_t block_len; - - if ((addr + len) > (flash->chip->total_size * 1024)) { - msg_perr("Request to write to an inaccessible memory address " - "(addr=0x%x, len=%d).\n", addr, len); - return -1; - } - - msg_pdbg("Writing %d bytes starting at 0x%06x.\n", len, addr); - /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ - REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS)); - - while (len > 0) { - pch_hwseq_set_addr(addr); - block_len = min(len, flash->mst->opaque.max_data_write); - ich_fill_data(buf, block_len, ICH9_REG_FDATA0); - hsfc = REGREAD16(ICH9_REG_HSFC); - hsfc &= ~PCH100_HSFC_FCYCLE; /* clear operation */ - hsfc |= (0x2 << PCH100_HSFC_FCYCLE_OFF); /* set write operation */ - hsfc &= ~HSFC_FDBC; /* clear byte count */ - /* set byte count */ - hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC); - hsfc |= HSFC_FGO; /* start */ - REGWRITE16(ICH9_REG_HSFC, hsfc); - - if (pch_hwseq_wait_for_cycle_complete(timeout, block_len)) return -1; addr += block_len; buf += block_len; @@ -1818,15 +1616,6 @@ .write_aai = default_spi_write_aai, };
-static struct opaque_master opaque_master_pch_hwseq = { - .max_data_read = 64, - .max_data_write = 64, - .probe = pch_hwseq_probe, - .read = pch_hwseq_read, - .write = pch_hwseq_write, - .erase = pch_hwseq_block_erase, -}; - static const struct opaque_master opaque_master_ich_hwseq = { .max_data_read = 64, .max_data_write = 64, @@ -1891,6 +1680,10 @@ register_spi_master(&spi_master_ich7); break; case CHIPSET_100_SERIES_SUNRISE_POINT: + hwseq_data.addr_mask = PCH100_FADDR_FLA; + hwseq_data.only_4k = true; + hwseq_data.hsfc_fcycle = PCH100_HSFC_FCYCLE; + arg = extract_programmer_param("ich_spi_mode"); if (arg && !strcmp(arg, "hwseq")) { ich_spi_mode = ich_hwseq; @@ -1981,13 +1774,17 @@ } hwseq_data.size_comp0 = getFCBA_component_density(ich_gen, &desc, 0); hwseq_data.size_comp1 = getFCBA_component_density(ich_gen, &desc, 1); - register_opaque_master(&opaque_master_pch_hwseq); + register_opaque_master(&opaque_master_ich_hwseq); } else { register_spi_master(&spi_master_ich9); } break; case CHIPSET_ICH8: default: /* Future version might behave the same */ + hwseq_data.addr_mask = ICH9_FADDR_FLA; + hwseq_data.only_4k = false; + hwseq_data.hsfc_fcycle = HSFC_FCYCLE; + arg = extract_programmer_param("ich_spi_mode"); if (arg && !strcmp(arg, "hwseq")) { ich_spi_mode = ich_hwseq;