summaryrefslogtreecommitdiffstats
path: root/ichspi.c
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 /ichspi.c
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>
Diffstat (limited to 'ichspi.c')
-rw-r--r--ichspi.c279
1 files changed, 208 insertions, 71 deletions
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