summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Huber <nico.h@gmx.de>2017-03-23 23:45:47 +0100
committerNico Huber <nico.h@gmx.de>2017-07-28 12:22:58 +0000
commitd54e4f467753a247552bfb629f007f8931b0caa7 (patch)
tree0a7bb8254865783ad1fa1dc958e74e1a57936953
parent93c306939b732fb05f6d8a692acc3fca78bc0f9f (diff)
downloadflashrom-d54e4f467753a247552bfb629f007f8931b0caa7.tar.gz
flashrom-d54e4f467753a247552bfb629f007f8931b0caa7.tar.bz2
flashrom-d54e4f467753a247552bfb629f007f8931b0caa7.zip
ichspi: Add support for Intel Skylake
The Sunrise Point PCH, paired with Skylake, has some minor changes in the HW sequencing interface: * Support for more flash regions moved PR* registers * Only 4KiB erase blocks are supported by the primary erase command * A second erase command for 64KiB pages was added * More commands were added for status register access etc. * A "Dedicated Lock Bits" register was added No support for the new commands was added. The SW sequencing interface seems to have moved register location and is not supported any more officially. It's also untested. Changes are loosely based on the Skylake support commit in Chromium OS by Ramya Vijaykumar: commit a9a64f9e4d52c39fcd3c5f7d7b88065baed189b1 Author: Ramya Vijaykumar <ramya.vijaykumar@intel.com> flashrom: Add Skylake platform support Change-Id: I0f4565a3c39f5fe3aec4fc8863605cebed1ad4ee Signed-off-by: Nico Huber <nico.huber@secunet.com> Reviewed-on: https://review.coreboot.org/18962 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: David Hendricks <david.hendricks@gmail.com> Reviewed-by: Youness Alaoui <snifikino@gmail.com>
-rw-r--r--ich_descriptors.c37
-rw-r--r--ich_descriptors.h4
-rw-r--r--ichspi.c279
3 files changed, 233 insertions, 87 deletions
diff --git a/ich_descriptors.c b/ich_descriptors.c
index a12022c6c..1fc8835ea 100644
--- a/ich_descriptors.c
+++ b/ich_descriptors.c
@@ -824,6 +824,7 @@ int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors
case CHIPSET_8_SERIES_WELLSBURG:
case CHIPSET_9_SERIES_WILDCAT_POINT:
case CHIPSET_9_SERIES_WILDCAT_POINT_LP:
+ case CHIPSET_100_SERIES_SUNRISE_POINT:
if (idx == 0) {
size_enc = desc->component.dens_new.comp1_density;
} else {
@@ -849,16 +850,22 @@ int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors
/* Only used by ichspi.c */
#if CONFIG_INTERNAL == 1 && (defined(__i386__) || defined(__x86_64__))
-static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar)
+static uint32_t read_descriptor_reg(enum ich_chipset cs, uint8_t section, uint16_t offset, void *spibar)
{
uint32_t control = 0;
control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS;
control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI;
- mmio_le_writel(control, spibar + ICH9_REG_FDOC);
- return mmio_le_readl(spibar + ICH9_REG_FDOD);
+ if (cs == CHIPSET_100_SERIES_SUNRISE_POINT) {
+ mmio_le_writel(control, spibar + PCH100_REG_FDOC);
+ return mmio_le_readl(spibar + PCH100_REG_FDOD);
+ } else {
+ mmio_le_writel(control, spibar + ICH9_REG_FDOC);
+ return mmio_le_readl(spibar + ICH9_REG_FDOD);
+ }
+
}
-int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc)
+int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc)
{
uint8_t i;
uint8_t nr;
@@ -888,15 +895,15 @@ int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc)
msg_pdbg2("Reading flash descriptors mapped by the chipset via FDOC/FDOD...");
/* content section */
- desc->content.FLVALSIG = read_descriptor_reg(0, 0, spibar);
- desc->content.FLMAP0 = read_descriptor_reg(0, 1, spibar);
- desc->content.FLMAP1 = read_descriptor_reg(0, 2, spibar);
- desc->content.FLMAP2 = read_descriptor_reg(0, 3, spibar);
+ desc->content.FLVALSIG = read_descriptor_reg(cs, 0, 0, spibar);
+ desc->content.FLMAP0 = read_descriptor_reg(cs, 0, 1, spibar);
+ desc->content.FLMAP1 = read_descriptor_reg(cs, 0, 2, spibar);
+ desc->content.FLMAP2 = read_descriptor_reg(cs, 0, 3, spibar);
/* component section */
- desc->component.FLCOMP = read_descriptor_reg(1, 0, spibar);
- desc->component.FLILL = read_descriptor_reg(1, 1, spibar);
- desc->component.FLPB = read_descriptor_reg(1, 2, spibar);
+ desc->component.FLCOMP = read_descriptor_reg(cs, 1, 0, spibar);
+ desc->component.FLILL = read_descriptor_reg(cs, 1, 1, spibar);
+ desc->component.FLPB = read_descriptor_reg(cs, 1, 2, spibar);
/* region section */
nr = desc->content.NR + 1;
@@ -906,12 +913,12 @@ int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc)
return ICH_RET_ERR;
}
for (i = 0; i < 5; i++)
- desc->region.FLREGs[i] = read_descriptor_reg(2, i, spibar);
+ desc->region.FLREGs[i] = read_descriptor_reg(cs, 2, i, spibar);
/* master section */
- desc->master.FLMSTR1 = read_descriptor_reg(3, 0, spibar);
- desc->master.FLMSTR2 = read_descriptor_reg(3, 1, spibar);
- desc->master.FLMSTR3 = read_descriptor_reg(3, 2, spibar);
+ desc->master.FLMSTR1 = read_descriptor_reg(cs, 3, 0, spibar);
+ desc->master.FLMSTR2 = read_descriptor_reg(cs, 3, 1, spibar);
+ desc->master.FLMSTR3 = read_descriptor_reg(cs, 3, 2, spibar);
/* Accessing the strap section via FDOC/D is only possible on ICH8 and
* reading the upper map is impossible on all chipsets, so don't bother.
diff --git a/ich_descriptors.h b/ich_descriptors.h
index ecf44bf8e..831341a64 100644
--- a/ich_descriptors.h
+++ b/ich_descriptors.h
@@ -33,6 +33,7 @@
#define ICH_RET_OOB -4
#define ICH9_REG_FDOC 0xB0 /* 32 Bits Flash Descriptor Observability Control */
+#define PCH100_REG_FDOC 0xB4 /* New offset from Sunrise Point on */
/* 0-1: reserved */
#define FDOC_FDSI_OFF 2 /* 2-11: Flash Descriptor Section Index */
#define FDOC_FDSI (0x3f << FDOC_FDSI_OFF)
@@ -41,6 +42,7 @@
/* 15-31: reserved */
#define ICH9_REG_FDOD 0xB4 /* 32 Bits Flash Descriptor Observability Data */
+#define PCH100_REG_FDOD 0xB8 /* New offset from Sunrise Point on */
/* Field locations and semantics for LVSCC, UVSCC and related words in the flash
* descriptor are equal therefore they all share the same macros below. */
@@ -581,7 +583,7 @@ void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap)
void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_descriptors *desc);
int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struct ich_descriptors *desc);
-int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc);
+int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc);
int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx);
int layout_from_ich_descriptors(struct ich_layout *, const void *dump, size_t len);
diff --git a/ichspi.c b/ichspi.c
index be13f915e..ecf0c4212 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -33,6 +33,60 @@
#include "spi.h"
#include "ich_descriptors.h"
+/* Sunrise Point */
+
+/* Added HSFS Status bits */
+#define HSFS_WRSDIS_OFF 11 /* 11: Flash Configuration Lock-Down */
+#define HSFS_WRSDIS (0x1 << HSFS_WRSDIS_OFF)
+#define HSFS_PRR34_LOCKDN_OFF 12 /* 12: PRR3 PRR4 Lock-Down */
+#define HSFS_PRR34_LOCKDN (0x1 << HSFS_PRR34_LOCKDN_OFF)
+/* HSFS_BERASE vanished */
+
+/*
+ * HSFC and HSFS 16-bit registers are combined into the 32-bit
+ * BIOS_HSFSTS_CTL register in the Sunrise Point datasheet,
+ * however we still treat them separately in order to reuse code.
+ */
+
+/* Changed HSFC Control bits */
+#define PCH100_HSFC_FCYCLE_OFF (17 - 16) /* 1-4: FLASH Cycle */
+#define PCH100_HSFC_FCYCLE (0xf << PCH100_HSFC_FCYCLE_OFF)
+/* New HSFC Control bit */
+#define HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
+#define HSFC_WET (0x1 << HSFC_WET_OFF)
+
+#define PCH100_FADDR_FLA 0x07ffffff
+
+#define PCH100_REG_DLOCK 0x0c /* 32 Bits Discrete Lock Bits */
+#define DLOCK_BMWAG_LOCKDN_OFF 0
+#define DLOCK_BMWAG_LOCKDN (0x1 << DLOCK_BMWAG_LOCKDN_OFF)
+#define DLOCK_BMRAG_LOCKDN_OFF 1
+#define DLOCK_BMRAG_LOCKDN (0x1 << DLOCK_BMRAG_LOCKDN_OFF)
+#define DLOCK_SBMWAG_LOCKDN_OFF 2
+#define DLOCK_SBMWAG_LOCKDN (0x1 << DLOCK_SBMWAG_LOCKDN_OFF)
+#define DLOCK_SBMRAG_LOCKDN_OFF 3
+#define DLOCK_SBMRAG_LOCKDN (0x1 << DLOCK_SBMRAG_LOCKDN_OFF)
+#define DLOCK_PR0_LOCKDN_OFF 8
+#define DLOCK_PR0_LOCKDN (0x1 << DLOCK_PR0_LOCKDN_OFF)
+#define DLOCK_PR1_LOCKDN_OFF 9
+#define DLOCK_PR1_LOCKDN (0x1 << DLOCK_PR1_LOCKDN_OFF)
+#define DLOCK_PR2_LOCKDN_OFF 10
+#define DLOCK_PR2_LOCKDN (0x1 << DLOCK_PR2_LOCKDN_OFF)
+#define DLOCK_PR3_LOCKDN_OFF 11
+#define DLOCK_PR3_LOCKDN (0x1 << DLOCK_PR3_LOCKDN_OFF)
+#define DLOCK_PR4_LOCKDN_OFF 12
+#define DLOCK_PR4_LOCKDN (0x1 << DLOCK_PR4_LOCKDN_OFF)
+#define DLOCK_SSEQ_LOCKDN_OFF 16
+#define DLOCK_SSEQ_LOCKDN (0x1 << DLOCK_SSEQ_LOCKDN_OFF)
+
+#define PCH100_REG_FPR0 0x84 /* 32 Bits Protected Range 0 */
+#define PCH100_REG_GPR0 0x98 /* 32 Bits Global Protected Range 0 */
+
+#define PCH100_REG_SSFSC 0xA0 /* 32 Bits Status (8) + Control (24) */
+#define PCH100_REG_PREOP 0xA4 /* 16 Bits */
+#define PCH100_REG_OPTYPE 0xA6 /* 16 Bits */
+#define PCH100_REG_OPMENU 0xA8 /* 64 Bits */
+
/* ICH9 controller register definition */
#define ICH9_REG_HSFS 0x04 /* 16 Bits Hardware Sequencing Flash Status */
#define HSFS_FDONE_OFF 0 /* 0: Flash Cycle Done */
@@ -66,6 +120,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 */
@@ -325,7 +380,8 @@ static void prettyprint_opcodes(OPCODES *ops)
ops->preop[1]);
}
-#define pprint_reg(reg, bit, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & reg##_##bit)>>reg##_##bit##_OFF)
+#define _pprint_reg(bit, mask, off, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & mask) >> off)
+#define pprint_reg(reg, bit, val, sep) _pprint_reg(bit, reg##_##bit, reg##_##bit##_OFF, val, sep)
static void prettyprint_ich9_reg_hsfs(uint16_t reg_val)
{
@@ -333,8 +389,14 @@ static void prettyprint_ich9_reg_hsfs(uint16_t reg_val)
pprint_reg(HSFS, FDONE, reg_val, ", ");
pprint_reg(HSFS, FCERR, reg_val, ", ");
pprint_reg(HSFS, AEL, reg_val, ", ");
- pprint_reg(HSFS, BERASE, reg_val, ", ");
+ if (ich_generation != CHIPSET_100_SERIES_SUNRISE_POINT) {
+ pprint_reg(HSFS, BERASE, reg_val, ", ");
+ }
pprint_reg(HSFS, SCIP, reg_val, ", ");
+ if (ich_generation == CHIPSET_100_SERIES_SUNRISE_POINT) {
+ pprint_reg(HSFS, PRR34_LOCKDN, reg_val, ", ");
+ pprint_reg(HSFS, WRSDIS, reg_val, ", ");
+ }
pprint_reg(HSFS, FDOPSS, reg_val, ", ");
pprint_reg(HSFS, FDV, reg_val, ", ");
pprint_reg(HSFS, FLOCKDN, reg_val, "\n");
@@ -344,7 +406,12 @@ static void prettyprint_ich9_reg_hsfc(uint16_t reg_val)
{
msg_pdbg("HSFC: ");
pprint_reg(HSFC, FGO, reg_val, ", ");
- pprint_reg(HSFC, FCYCLE, reg_val, ", ");
+ if (ich_generation != CHIPSET_100_SERIES_SUNRISE_POINT) {
+ pprint_reg(HSFC, FCYCLE, reg_val, ", ");
+ } else {
+ _pprint_reg(HSFC, PCH100_HSFC_FCYCLE, PCH100_HSFC_FCYCLE_OFF, reg_val, ", ");
+ pprint_reg(HSFC, WET, reg_val, ", ");
+ }
pprint_reg(HSFC, FDBC, reg_val, ", ");
pprint_reg(HSFC, SME, reg_val, "\n");
}
@@ -370,6 +437,28 @@ static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
pprint_reg(SSFC, SCF, reg_val, "\n");
}
+static void prettyprint_pch100_reg_dlock(const uint32_t reg_val)
+{
+ msg_pdbg("DLOCK: ");
+ pprint_reg(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n ");
+ pprint_reg(DLOCK, PR0_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, PR1_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, PR2_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, PR3_LOCKDN, reg_val, ", ");
+ pprint_reg(DLOCK, PR4_LOCKDN, reg_val, ",\n ");
+ pprint_reg(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
+}
+
+static struct {
+ size_t reg_ssfsc;
+ size_t reg_preop;
+ size_t reg_optype;
+ size_t reg_opmenu;
+} swseq_data;
+
static uint8_t lookup_spi_type(uint8_t opcode)
{
int a;
@@ -475,10 +564,10 @@ static int generate_opcodes(OPCODES * op)
break;
case CHIPSET_ICH8:
default: /* Future version might behave the same */
- preop = REGREAD16(ICH9_REG_PREOP);
- optype = REGREAD16(ICH9_REG_OPTYPE);
- opmenu[0] = REGREAD32(ICH9_REG_OPMENU);
- opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4);
+ preop = REGREAD16(swseq_data.reg_preop);
+ optype = REGREAD16(swseq_data.reg_optype);
+ opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
+ opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
break;
}
@@ -558,15 +647,15 @@ static int program_opcodes(OPCODES *op, int enable_undo)
default: /* Future version might behave the same */
/* Register undo only for enable_undo=1, i.e. first call. */
if (enable_undo) {
- rmmio_valw(ich_spibar + ICH9_REG_PREOP);
- rmmio_valw(ich_spibar + ICH9_REG_OPTYPE);
- rmmio_vall(ich_spibar + ICH9_REG_OPMENU);
- rmmio_vall(ich_spibar + ICH9_REG_OPMENU + 4);
+ rmmio_valw(ich_spibar + swseq_data.reg_preop);
+ rmmio_valw(ich_spibar + swseq_data.reg_optype);
+ rmmio_vall(ich_spibar + swseq_data.reg_opmenu);
+ rmmio_vall(ich_spibar + swseq_data.reg_opmenu + 4);
}
- mmio_writew(preop, ich_spibar + ICH9_REG_PREOP);
- mmio_writew(optype, ich_spibar + ICH9_REG_OPTYPE);
- mmio_writel(opmenu[0], ich_spibar + ICH9_REG_OPMENU);
- mmio_writel(opmenu[1], ich_spibar + ICH9_REG_OPMENU + 4);
+ mmio_writew(preop, ich_spibar + swseq_data.reg_preop);
+ mmio_writew(optype, ich_spibar + swseq_data.reg_optype);
+ mmio_writel(opmenu[0], ich_spibar + swseq_data.reg_opmenu);
+ mmio_writel(opmenu[1], ich_spibar + swseq_data.reg_opmenu + 4);
break;
}
@@ -853,7 +942,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
- while ((REGREAD8(ICH9_REG_SSFS) & SSFS_SCIP) && --timeout) {
+ while ((REGREAD8(swseq_data.reg_ssfsc) & SSFS_SCIP) && --timeout) {
programmer_delay(10);
}
if (!timeout) {
@@ -871,12 +960,12 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
ich_fill_data(data, datalength, ICH9_REG_FDATA0);
/* Assemble SSFS + SSFC */
- temp32 = REGREAD32(ICH9_REG_SSFS);
+ temp32 = REGREAD32(swseq_data.reg_ssfsc);
/* Keep reserved bits only */
temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
/* Clear cycle done and cycle error status registers */
temp32 |= (SSFS_FDONE | SSFS_FCERR);
- REGWRITE32(ICH9_REG_SSFS, temp32);
+ REGWRITE32(swseq_data.reg_ssfsc, temp32);
/* Use 20 MHz */
temp32 |= SSFC_SCF_20MHZ;
@@ -930,21 +1019,21 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
temp32 |= SSFC_SCGO;
/* write it */
- REGWRITE32(ICH9_REG_SSFS, temp32);
+ REGWRITE32(swseq_data.reg_ssfsc, temp32);
/* Wait for Cycle Done Status or Flash Cycle Error. */
- while (((REGREAD32(ICH9_REG_SSFS) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
+ while (((REGREAD32(swseq_data.reg_ssfsc) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
--timeout) {
programmer_delay(10);
}
if (!timeout) {
- msg_perr("timeout, ICH9_REG_SSFS=0x%08x\n",
- REGREAD32(ICH9_REG_SSFS));
+ msg_perr("timeout, REG_SSFS=0x%08x\n",
+ REGREAD32(swseq_data.reg_ssfsc));
return 1;
}
/* FIXME make sure we do not needlessly cause transaction errors. */
- temp32 = REGREAD32(ICH9_REG_SSFS);
+ temp32 = REGREAD32(swseq_data.reg_ssfsc);
if (temp32 & SSFS_FCERR) {
msg_perr("Transaction error!\n");
prettyprint_ich9_reg_ssfs(temp32);
@@ -952,7 +1041,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
/* keep reserved bits */
temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
/* Clear the transaction error. */
- REGWRITE32(ICH9_REG_SSFS, temp32 | SSFS_FCERR);
+ REGWRITE32(swseq_data.reg_ssfsc, temp32 | SSFS_FCERR);
return 1;
}
@@ -1117,13 +1206,16 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
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
@@ -1135,18 +1227,21 @@ static void ich_hwseq_set_addr(uint32_t addr)
*/
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
- };
+ if (hwseq_data.only_4k) {
+ return 4 * 1024;
+ } else {
+ uint8_t enc_berase;
+ static const uint32_t dec_berase[4] = {
+ 256,
+ 4 * 1024,
+ 8 * 1024,
+ 64 * 1024
+ };
- ich_hwseq_set_addr(addr);
- enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >>
- HSFS_BERASE_OFF;
- return dec_berase[enc_berase];
+ ich_hwseq_set_addr(addr);
+ enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF;
+ return dec_berase[enc_berase];
+ }
}
/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals.
@@ -1167,7 +1262,7 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
}
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);
@@ -1177,7 +1272,7 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
}
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);
@@ -1205,7 +1300,10 @@ static int ich_hwseq_probe(struct flashctx *flash)
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);
@@ -1279,7 +1377,7 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
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: ");
@@ -1316,7 +1414,7 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
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);
@@ -1357,7 +1455,7 @@ static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned
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 */
@@ -1449,6 +1547,8 @@ static int ich9_handle_frap(uint32_t frap, int i)
"Flash Descriptor", "BIOS", "Management Engine",
"Gigabit Ethernet", "Platform Data"
};
+ const char *const region_name = i < ARRAY_SIZE(region_names) ? region_names[i] : "unknown";
+
uint32_t base, limit;
int rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) |
(((ICH_BRRA(frap) >> i) & 1) << 0);
@@ -1460,19 +1560,19 @@ static int ich9_handle_frap(uint32_t frap, int i)
if (base > limit || (freg == 0 && i > 0)) {
/* this FREG is disabled */
msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n",
- offset, freg, i, region_names[i]);
+ offset, freg, i, region_name);
return 0;
}
msg_pdbg("0x%02X: 0x%08x ", offset, freg);
if (rwperms == 0x3) {
msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i,
- region_names[i], base, (limit | 0x0fff),
+ region_name, base, (limit | 0x0fff),
access_names[rwperms]);
return 0;
}
msg_pwarn("FREG%i: Warning: %s region (0x%08x-0x%08x) is %s.\n", i,
- region_names[i], base, (limit | 0x0fff),
+ region_name, base, (limit | 0x0fff),
access_names[rwperms]);
return 1;
}
@@ -1487,31 +1587,36 @@ static int ich9_handle_frap(uint32_t frap, int i)
((~((pr) >> PR_WP_OFF) & 1) << 1))
/* returns 0 if range is unused (i.e. r/w) */
-static int ich9_handle_pr(int i)
+static int ich9_handle_pr(const size_t reg_pr0, int i)
{
static const char *const access_names[3] = {
"locked", "read-only", "write-only"
};
- uint8_t off = ICH9_REG_PR0 + (i * 4);
+ uint8_t off = reg_pr0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off);
unsigned int rwperms = ICH_PR_PERMS(pr);
+ /* From 5 on we have GPR registers and start from 0 again. */
+ const char *const prefix = i >= 5 ? "G" : "";
+ if (i >= 5)
+ i -= 5;
+
if (rwperms == 0x3) {
- msg_pdbg2("0x%02X: 0x%08x (PR%u is unused)\n", off, pr, i);
+ msg_pdbg2("0x%02X: 0x%08x (%sPR%u is unused)\n", off, pr, prefix, i);
return 0;
}
msg_pdbg("0x%02X: 0x%08x ", off, pr);
- msg_pwarn("PR%u: Warning: 0x%08x-0x%08x is %s.\n", i, ICH_FREG_BASE(pr),
+ msg_pwarn("%sPR%u: Warning: 0x%08x-0x%08x is %s.\n", prefix, i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]);
return 1;
}
/* Set/Clear the read and write protection enable bits of PR register @i
* according to @read_prot and @write_prot. */
-static void ich9_set_pr(int i, int read_prot, int write_prot)
+static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_prot)
{
- void *addr = ich_spibar + ICH9_REG_PR0 + (i * 4);
+ void *addr = ich_spibar + reg_pr0 + (i * 4);
uint32_t old = mmio_readl(addr);
uint32_t new;
@@ -1576,10 +1681,36 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
ich_hwseq,
ich_swseq
} ich_spi_mode = ich_auto;
+ size_t num_freg, num_pr, reg_pr0;
ich_generation = ich_gen;
ich_spibar = spibar;
+ /* Moving registers / bits */
+ if (ich_generation == CHIPSET_100_SERIES_SUNRISE_POINT) {
+ num_freg = 10;
+ num_pr = 6;
+ reg_pr0 = PCH100_REG_FPR0;
+ swseq_data.reg_ssfsc = PCH100_REG_SSFSC;
+ swseq_data.reg_preop = PCH100_REG_PREOP;
+ swseq_data.reg_optype = PCH100_REG_OPTYPE;
+ swseq_data.reg_opmenu = PCH100_REG_OPMENU;
+ hwseq_data.addr_mask = PCH100_FADDR_FLA;
+ hwseq_data.only_4k = true;
+ hwseq_data.hsfc_fcycle = PCH100_HSFC_FCYCLE;
+ } else {
+ num_freg = 5;
+ num_pr = 5;
+ reg_pr0 = ICH9_REG_PR0;
+ swseq_data.reg_ssfsc = ICH9_REG_SSFS;
+ swseq_data.reg_preop = ICH9_REG_PREOP;
+ swseq_data.reg_optype = ICH9_REG_OPTYPE;
+ swseq_data.reg_opmenu = ICH9_REG_OPMENU;
+ hwseq_data.addr_mask = ICH9_FADDR_FLA;
+ hwseq_data.only_4k = false;
+ hwseq_data.hsfc_fcycle = HSFC_FCYCLE;
+ }
+
switch (ich_generation) {
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
@@ -1679,6 +1810,12 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
tmp = mmio_readl(ich_spibar + ICH9_REG_FADDR);
msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp);
+ if (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT) {
+ const uint32_t dlock = mmio_readl(ich_spibar + PCH100_REG_DLOCK);
+ msg_pdbg("0x0c: 0x%08x (DLOCK)\n", dlock);
+ prettyprint_pch100_reg_dlock(dlock);
+ }
+
if (desc_valid) {
tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP);
msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
@@ -1688,7 +1825,7 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
/* Handle FREGx and FRAP registers */
- for (i = 0; i < 5; i++)
+ for (i = 0; i < num_freg; i++)
ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
if (ich_spi_rw_restricted)
msg_pwarn("Not all flash regions are freely accessible by flashrom. This is "
@@ -1697,11 +1834,11 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
}
/* Handle PR registers */
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < num_pr; i++) {
/* if not locked down try to disable PR locks first */
if (!ichspi_lock)
- ich9_set_pr(i, 0, 0);
- ich_spi_rw_restricted |= ich9_handle_pr(i);
+ ich9_set_pr(reg_pr0, i, 0, 0);
+ ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
}
if (ich_spi_rw_restricted) {
@@ -1716,30 +1853,30 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
msg_pinfo("Continuing with write support because the user forced us to!\n");
}
- tmp = mmio_readl(ich_spibar + ICH9_REG_SSFS);
- msg_pdbg("0x90: 0x%02x (SSFS)\n", tmp & 0xff);
+ tmp = mmio_readl(ich_spibar + swseq_data.reg_ssfsc);
+ msg_pdbg("0x%zx: 0x%02x (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
prettyprint_ich9_reg_ssfs(tmp);
if (tmp & SSFS_FCERR) {
msg_pdbg("Clearing SSFS.FCERR\n");
- mmio_writeb(SSFS_FCERR, ich_spibar + ICH9_REG_SSFS);
+ mmio_writeb(SSFS_FCERR, ich_spibar + swseq_data.reg_ssfsc);
}
- msg_pdbg("0x91: 0x%06x (SSFC)\n", tmp >> 8);
+ msg_pdbg("0x%zx: 0x%06x (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
prettyprint_ich9_reg_ssfc(tmp);
- msg_pdbg("0x94: 0x%04x (PREOP)\n",
- mmio_readw(ich_spibar + ICH9_REG_PREOP));
- msg_pdbg("0x96: 0x%04x (OPTYPE)\n",
- mmio_readw(ich_spibar + ICH9_REG_OPTYPE));
- msg_pdbg("0x98: 0x%08x (OPMENU)\n",
- mmio_readl(ich_spibar + ICH9_REG_OPMENU));
- msg_pdbg("0x9C: 0x%08x (OPMENU+4)\n",
- mmio_readl(ich_spibar + ICH9_REG_OPMENU + 4));
+ msg_pdbg("0x%zx: 0x%04x (PREOP)\n",
+ swseq_data.reg_preop, mmio_readw(ich_spibar + swseq_data.reg_preop));
+ msg_pdbg("0x%zx: 0x%04x (OPTYPE)\n",
+ swseq_data.reg_optype, mmio_readw(ich_spibar + swseq_data.reg_optype));
+ msg_pdbg("0x%zx: 0x%08x (OPMENU)\n",
+ swseq_data.reg_opmenu, mmio_readl(ich_spibar + swseq_data.reg_opmenu));
+ msg_pdbg("0x%zx: 0x%08x (OPMENU+4)\n",
+ swseq_data.reg_opmenu + 4, mmio_readl(ich_spibar + swseq_data.reg_opmenu + 4));
if (ich_generation == CHIPSET_ICH8 && desc_valid) {
tmp = mmio_readl(ich_spibar + ICH8_REG_VSCC);
msg_pdbg("0xC1: 0x%08x (VSCC)\n", tmp);
msg_pdbg("VSCC: ");
prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
- } else {
+ } else if (ich_generation != CHIPSET_100_SERIES_SUNRISE_POINT) {
if (ich_generation != CHIPSET_BAYTRAIL && desc_valid) {
ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR);
msg_pdbg("0xA0: 0x%08x (BBAR)\n",
@@ -1764,7 +1901,7 @@ int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
}
if (desc_valid) {
- if (read_ich_descriptors_via_fdo(ich_spibar, &desc) == ICH_RET_OK)
+ if (read_ich_descriptors_via_fdo(ich_gen, ich_spibar, &desc) == ICH_RET_OK)
prettyprint_ich_descriptors(ich_gen, &desc);
/* If the descriptor is valid and indicates multiple