summaryrefslogtreecommitdiffstats
path: root/ichspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ichspi.c')
-rw-r--r--ichspi.c1365
1 files changed, 844 insertions, 521 deletions
diff --git a/ichspi.c b/ichspi.c
index e45b39a6e..2e38ff17c 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -19,13 +19,12 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
#include "spi.h"
#include "ich_descriptors.h"
@@ -47,12 +46,41 @@
* 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)
+/*
+ * HSFC Control bits
+ *
+ * FCYCLE is a 2 bit field (HSFC bits 1-2) on ICH9 and 4 bit field
+ * (HSFC bits 1-4) on PCH100.
+ *
+ * ICH9 and PCH100 use the same FCYCLE values for flash operations,
+ * however FCYCLE values above 3 are only supported by PCH100.
+ *
+ * 0: SPI Read
+ * 2: SPI Write
+ * 3: SPI Erase 4K
+ * 4: SPI Erase 64K
+ * 6: SPI RDID
+ * 7: SPI Write Status
+ * 8: SPI Read Status
+ */
+#define HSFC_FGO_OFF 0
+#define HSFC_FGO (0x1 << HSFC_FGO_OFF)
+#define HSFC_FCYCLE_MASK(n) ((n) << HSFC_FCYCLE_OFF)
+#define HSFC_FCYCLE_OFF 1
+#define HSFC_CYCLE_READ HSFC_FCYCLE_MASK(0x0)
+#define HSFC_CYCLE_WRITE HSFC_FCYCLE_MASK(0x2)
+#define HSFC_CYCLE_BLOCK_ERASE HSFC_FCYCLE_MASK(0x3)
+#define HSFC_CYCLE_RDID HSFC_FCYCLE_MASK(0x6)
+#define HSFC_CYCLE_WR_STATUS HSFC_FCYCLE_MASK(0x7)
+#define HSFC_CYCLE_RD_STATUS HSFC_FCYCLE_MASK(0x8)
+
+/* PCH100 controller register definition */
+#define PCH100_HSFC_FCYCLE_OFF 1
+#define PCH100_HSFC_FCYCLE_BIT_WIDTH 0xf
+#define PCH100_HSFC_FCYCLE HSFC_FCYCLE_MASK(PCH100_HSFC_FCYCLE_BIT_WIDTH)
/* New HSFC Control bit */
-#define HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
-#define HSFC_WET (0x1 << HSFC_WET_OFF)
+#define PCH100_HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
+#define PCH100_HSFC_WET (0x1 << PCH100_HSFC_WET_OFF)
#define PCH100_FADDR_FLA 0x07ffffff
@@ -107,13 +135,16 @@
#define HSFS_FLOCKDN (0x1 << HSFS_FLOCKDN_OFF)
#define ICH9_REG_HSFC 0x06 /* 16 Bits Hardware Sequencing Flash Control */
-#define HSFC_FGO_OFF 0 /* 0: Flash Cycle Go */
-#define HSFC_FGO (0x1 << HSFC_FGO_OFF)
-#define HSFC_FCYCLE_OFF 1 /* 1-2: FLASH Cycle */
-#define HSFC_FCYCLE (0x3 << HSFC_FCYCLE_OFF)
+
+ /* 0: Flash Cycle Go */
+ /* 1-2: FLASH Cycle */
+#define ICH9_HSFC_FCYCLE_OFF 1
+#define ICH9_HSFC_FCYCLE_BIT_WIDTH 3
+#define ICH9_HSFC_FCYCLE HSFC_FCYCLE_MASK(ICH9_HSFC_FCYCLE_BIT_WIDTH)
/* 3-7: reserved */
#define HSFC_FDBC_OFF 8 /* 8-13: Flash Data Byte Count */
#define HSFC_FDBC (0x3f << HSFC_FDBC_OFF)
+#define HSFC_FDBC_VAL(n) (((n) << HSFC_FDBC_OFF) & HSFC_FDBC)
/* 14: reserved */
#define HSFC_SME_OFF 15 /* 15: SPI SMI# Enable */
#define HSFC_SME (0x1 << HSFC_SME_OFF)
@@ -232,7 +263,7 @@ enum ich_access_protection {
};
/* ICH SPI configuration lock-down. May be set during chipset enabling. */
-static int ichspi_lock = 0;
+static bool ichspi_lock = false;
static enum ich_chipset ich_generation = CHIPSET_ICH_UNKNOWN;
static uint32_t ichspi_bbar;
@@ -414,99 +445,105 @@ static void prettyprint_opcodes(OPCODES *ops)
ops->preop[1]);
}
-#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)
+#define pprint_reg16(reg, bit, val, sep) msg_pdbg("%s=%"PRId16"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
+#define pprint_reg32(reg, bit, val, sep) msg_pdbg("%s=%"PRId32"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
static void prettyprint_ich9_reg_hsfs(uint16_t reg_val, enum ich_chipset ich_gen)
{
msg_pdbg("HSFS: ");
- pprint_reg(HSFS, FDONE, reg_val, ", ");
- pprint_reg(HSFS, FCERR, reg_val, ", ");
- pprint_reg(HSFS, AEL, reg_val, ", ");
+ pprint_reg16(HSFS, FDONE, reg_val, ", ");
+ pprint_reg16(HSFS, FCERR, reg_val, ", ");
+ pprint_reg16(HSFS, AEL, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
break;
default:
- pprint_reg(HSFS, BERASE, reg_val, ", ");
+ pprint_reg16(HSFS, BERASE, reg_val, ", ");
break;
}
- pprint_reg(HSFS, SCIP, reg_val, ", ");
+ pprint_reg16(HSFS, SCIP, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
- pprint_reg(HSFS, PRR34_LOCKDN, reg_val, ", ");
- pprint_reg(HSFS, WRSDIS, reg_val, ", ");
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
+ pprint_reg16(HSFS, PRR34_LOCKDN, reg_val, ", ");
+ pprint_reg16(HSFS, WRSDIS, reg_val, ", ");
break;
default:
break;
}
- pprint_reg(HSFS, FDOPSS, reg_val, ", ");
- pprint_reg(HSFS, FDV, reg_val, ", ");
- pprint_reg(HSFS, FLOCKDN, reg_val, "\n");
+ pprint_reg16(HSFS, FDOPSS, reg_val, ", ");
+ pprint_reg16(HSFS, FDV, reg_val, ", ");
+ pprint_reg16(HSFS, FLOCKDN, reg_val, "\n");
}
static void prettyprint_ich9_reg_hsfc(uint16_t reg_val, enum ich_chipset ich_gen)
{
msg_pdbg("HSFC: ");
- pprint_reg(HSFC, FGO, reg_val, ", ");
+ pprint_reg16(HSFC, FGO, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
- _pprint_reg(HSFC, PCH100_HSFC_FCYCLE, PCH100_HSFC_FCYCLE_OFF, reg_val, ", ");
- pprint_reg(HSFC, WET, reg_val, ", ");
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
+ pprint_reg16(PCH100_HSFC, FCYCLE, reg_val, ", ");
+ pprint_reg16(PCH100_HSFC, WET, reg_val, ", ");
break;
default:
- pprint_reg(HSFC, FCYCLE, reg_val, ", ");
+ pprint_reg16(ICH9_HSFC, FCYCLE, reg_val, ", ");
break;
}
- pprint_reg(HSFC, FDBC, reg_val, ", ");
- pprint_reg(HSFC, SME, reg_val, "\n");
+ pprint_reg16(HSFC, FDBC, reg_val, ", ");
+ pprint_reg16(HSFC, SME, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfs(uint32_t reg_val)
{
msg_pdbg("SSFS: ");
- pprint_reg(SSFS, SCIP, reg_val, ", ");
- pprint_reg(SSFS, FDONE, reg_val, ", ");
- pprint_reg(SSFS, FCERR, reg_val, ", ");
- pprint_reg(SSFS, AEL, reg_val, "\n");
+ pprint_reg32(SSFS, SCIP, reg_val, ", ");
+ pprint_reg32(SSFS, FDONE, reg_val, ", ");
+ pprint_reg32(SSFS, FCERR, reg_val, ", ");
+ pprint_reg32(SSFS, AEL, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
{
msg_pdbg("SSFC: ");
- pprint_reg(SSFC, SCGO, reg_val, ", ");
- pprint_reg(SSFC, ACS, reg_val, ", ");
- pprint_reg(SSFC, SPOP, reg_val, ", ");
- pprint_reg(SSFC, COP, reg_val, ", ");
- pprint_reg(SSFC, DBC, reg_val, ", ");
- pprint_reg(SSFC, SME, reg_val, ", ");
- pprint_reg(SSFC, SCF, reg_val, "\n");
+ pprint_reg32(SSFC, SCGO, reg_val, ", ");
+ pprint_reg32(SSFC, ACS, reg_val, ", ");
+ pprint_reg32(SSFC, SPOP, reg_val, ", ");
+ pprint_reg32(SSFC, COP, reg_val, ", ");
+ pprint_reg32(SSFC, DBC, reg_val, ", ");
+ pprint_reg32(SSFC, SME, reg_val, ", ");
+ pprint_reg32(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");
+ pprint_reg32(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n ");
+ pprint_reg32(DLOCK, PR0_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR1_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR2_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR3_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR4_LOCKDN, reg_val, ",\n ");
+ pprint_reg32(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
}
-static struct {
+static struct swseq_data {
size_t reg_ssfsc;
size_t reg_preop;
size_t reg_optype;
@@ -555,7 +592,7 @@ static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_ge
opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
}
- msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
+ msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08"PRIx32"%08"PRIx32"\n", __func__, preop, optype, opmenu[0], opmenu[1]);
switch (ich_gen) {
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
@@ -677,7 +714,7 @@ static void ich_set_bbar(uint32_t min_addr, enum ich_chipset ich_gen)
ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & ~BBAR_MASK;
if (ichspi_bbar) {
- msg_pdbg("Reserved bits in BBAR not zero: 0x%08x\n",
+ msg_pdbg("Reserved bits in BBAR not zero: 0x%08"PRIx32"\n",
ichspi_bbar);
}
min_addr &= BBAR_MASK;
@@ -689,7 +726,7 @@ static void ich_set_bbar(uint32_t min_addr, enum ich_chipset ich_gen)
* failed, the restore will fail as well, so no problem there.
*/
if (ichspi_bbar != min_addr)
- msg_perr("Setting BBAR to 0x%08x failed! New value: 0x%08x.\n",
+ msg_perr("Setting BBAR to 0x%08"PRIx32" failed! New value: 0x%08"PRIx32".\n",
min_addr, ichspi_bbar);
}
@@ -831,7 +868,7 @@ static void ich_read_data(uint8_t *data, int len, int reg0_off)
static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data, int maxdata)
{
- int write_cmd = 0;
+ bool write_cmd = false;
int timeout;
uint32_t temp32;
uint16_t temp16;
@@ -841,12 +878,12 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
- write_cmd = 1;
+ write_cmd = true;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD16(ICH7_REG_SPIS) & SPIS_SCIP) && --timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
@@ -922,11 +959,10 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
/* Wait for Cycle Done Status or Flash Cycle Error. */
while (((REGREAD16(ICH7_REG_SPIS) & (SPIS_CDS | SPIS_FCERR)) == 0) &&
--timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
- msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n",
- REGREAD16(ICH7_REG_SPIS));
+ msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n", REGREAD16(ICH7_REG_SPIS));
return 1;
}
@@ -949,7 +985,7 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
static int ich9_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data)
{
- int write_cmd = 0;
+ bool write_cmd = false;
int timeout;
uint32_t temp32;
uint64_t opmenu;
@@ -958,12 +994,12 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
- write_cmd = 1;
+ write_cmd = true;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD8(swseq_data.reg_ssfsc) & SSFS_SCIP) && --timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
@@ -971,7 +1007,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
}
/* Program offset in flash into FADDR while preserve the reserved bits
- * and clearing the 25. address bit which is only useable in hwseq. */
+ * and clearing the 25. address bit which is only usable in hwseq. */
temp32 = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF) | temp32);
@@ -994,8 +1030,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
if (datalength != 0) {
uint32_t datatemp;
temp32 |= SSFC_DS;
- datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) &
- SSFC_DBC);
+ datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) & SSFC_DBC);
temp32 |= datatemp;
}
@@ -1044,11 +1079,10 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
/* Wait for Cycle Done Status or Flash Cycle Error. */
while (((REGREAD32(swseq_data.reg_ssfsc) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
--timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
- msg_perr("timeout, REG_SSFS=0x%08x\n",
- REGREAD32(swseq_data.reg_ssfsc));
+ msg_perr("timeout, REG_SSFS=0x%08"PRIx32"\n", REGREAD32(swseq_data.reg_ssfsc));
return 1;
}
@@ -1122,8 +1156,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
return SPI_INVALID_LENGTH;
} else if (opcode_index == -1) {
- msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n",
- cmd);
+ msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n", cmd);
return SPI_INVALID_OPCODE;
}
}
@@ -1140,30 +1173,26 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) &&
(writecnt != 4)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =4\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want =4\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) &&
(writecnt != 1)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =1\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want =1\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) &&
(writecnt < 4)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
(opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) &&
(readcnt)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got readcnt=%i, want =0\n", __func__, cmd,
- readcnt);
+ "0x%02x, got readcnt=%i, want =0\n", __func__, cmd, readcnt);
return SPI_INVALID_LENGTH;
}
@@ -1202,7 +1231,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
if (addr < valid_base ||
addr_end < addr || /* integer overflow check */
addr_end > valid_end) {
- msg_perr("%s: Addressed region 0x%06x-0x%06x not in allowed range 0x%06x-0x%06x\n",
+ msg_perr("%s: Addressed region 0x%06"PRIx32"-0x%06"PRIx32" not in allowed range 0x%06"PRIx32"-0x%06"PRIx32"\n",
__func__, addr, addr_end - 1, valid_base, valid_end - 1);
return SPI_INVALID_ADDRESS;
}
@@ -1214,7 +1243,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
(opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) {
- msg_pdbg("at address 0x%06x ", addr);
+ msg_pdbg("at address 0x%06"PRIx32" ", addr);
}
msg_pdbg("(payload length was %d).\n", count);
@@ -1226,7 +1255,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
int i;
msg_pspew("The data was:\n");
for (i = 0; i < count; i++){
- msg_pspew("%3d: 0x%02x\n", i, data[i]);
+ msg_pspew("%3d: 0x%02"PRIx8"\n", i, data[i]);
}
}
}
@@ -1234,19 +1263,34 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
return result;
}
-static struct hwseq_data {
+#define MAX_FD_REGIONS 16
+struct fd_region {
+ const char* name;
+ enum ich_access_protection level;
+ uint32_t base;
+ uint32_t limit;
+};
+
+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 & hwseq_data.addr_mask) without touching other bits. */
-static void ich_hwseq_set_addr(uint32_t addr)
+ struct fd_region fd_regions[MAX_FD_REGIONS];
+};
+
+static struct hwseq_data *get_hwseq_data_from_context(const struct flashctx *flash)
{
- uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~hwseq_data.addr_mask;
- REGWRITE32(ICH9_REG_FADDR, (addr & hwseq_data.addr_mask) | addr_old);
+ return flash->mst->opaque.data;
+}
+
+/* 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 mask)
+{
+ uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~mask;
+ REGWRITE32(ICH9_REG_FADDR, (addr & mask) | addr_old);
}
/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes
@@ -1256,7 +1300,7 @@ static void ich_hwseq_set_addr(uint32_t addr)
* 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 ich_hwseq_get_erase_block_size(unsigned int addr)
+static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr, uint32_t addr_mask, bool only_4k)
{
uint8_t enc_berase;
static const uint32_t dec_berase[4] = {
@@ -1266,11 +1310,11 @@ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
64 * 1024
};
- if (hwseq_data.only_4k) {
+ if (only_4k) {
return 4 * 1024;
}
- ich_hwseq_set_addr(addr);
+ ich_hwseq_set_addr(addr, addr_mask);
enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF;
return dec_berase[enc_berase];
}
@@ -1279,24 +1323,27 @@ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
Resets all error flags in HSFS.
Returns 0 if the cycle completes successfully without errors within
timeout us, 1 on errors. */
-static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
- unsigned int len,
- enum ich_chipset ich_gen)
+static int ich_hwseq_wait_for_cycle_complete(unsigned int len, enum ich_chipset ich_gen, uint32_t addr_mask)
{
+ /*
+ * The SPI bus may be busy due to performing operations from other masters, hence
+ * introduce the long timeout of 30s to cover the worst case scenarios as well.
+ */
+ unsigned int timeout_us = 30 * 1000 * 1000;
uint16_t hsfs;
uint32_t addr;
- timeout /= 8; /* scale timeout duration to counter */
+ timeout_us /= 8; /* scale timeout duration to counter */
while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) &
(HSFS_FDONE | HSFS_FCERR)) == 0) &&
- --timeout) {
- programmer_delay(8);
+ --timeout_us) {
+ default_delay(8);
}
REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
- if (!timeout) {
- addr = REGREAD32(ICH9_REG_FADDR) & hwseq_data.addr_mask;
- msg_perr("Timeout error between offset 0x%08x and "
- "0x%08x (= 0x%08x + %d)!\n",
+ if (!timeout_us) {
+ addr = REGREAD32(ICH9_REG_FADDR) & addr_mask;
+ msg_perr("Timeout error between offset 0x%08"PRIx32" and "
+ "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
addr, addr + len - 1, addr, len - 1);
prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
@@ -1304,9 +1351,9 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
}
if (hsfs & HSFS_FCERR) {
- 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 = REGREAD32(ICH9_REG_FADDR) & addr_mask;
+ msg_perr("Transaction error between offset 0x%08"PRIx32" and "
+ "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
addr, addr + len - 1, addr, len - 1);
prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
@@ -1315,59 +1362,287 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
return 0;
}
+/* Fire up a transfer using the hardware sequencer. */
+static void ich_start_hwseq_xfer(const struct flashctx *flash,
+ uint32_t hsfc_cycle, uint32_t flash_addr, size_t len,
+ uint32_t addr_mask)
+{
+ /* make sure HSFC register is cleared before initiate any operation */
+ uint16_t hsfc = 0;
+
+ /* Sets flash_addr in FADDR */
+ ich_hwseq_set_addr(flash_addr, addr_mask);
+
+ /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
+ REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+ /* Set up transaction parameters. */
+ hsfc |= hsfc_cycle;
+ /*
+ * The number of bytes transferred is the value of `FDBC` plus 1, hence,
+ * subtracted 1 from the length field.
+ * As per Intel EDS, `0b` in the FDBC represents 1 byte while `0x3f`
+ * represents 64-bytes to be transferred.
+ */
+ hsfc |= HSFC_FDBC_VAL(len - 1);
+ hsfc |= HSFC_FGO; /* start */
+ prettyprint_ich9_reg_hsfc(hsfc, ich_generation);
+ REGWRITE16(ICH9_REG_HSFC, hsfc);
+}
+
+static int ich_wait_for_hwseq_spi_cycle_complete(void)
+{
+ if (REGREAD8(ICH9_REG_HSFS) & HSFS_SCIP) {
+ msg_perr("Error: SCIP bit is unexpectedly set.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* Execute SPI flash transfer */
+static int ich_exec_sync_hwseq_xfer(const struct flashctx *flash, uint32_t hsfc_cycle, uint32_t flash_addr,
+ size_t len, enum ich_chipset ich_gen, uint32_t addr_mask)
+{
+ if (ich_wait_for_hwseq_spi_cycle_complete()) {
+ msg_perr("SPI Transaction Timeout due to previous operation in process!\n");
+ return 1;
+ }
+
+ ich_start_hwseq_xfer(flash, hsfc_cycle, flash_addr, len, addr_mask);
+ return ich_hwseq_wait_for_cycle_complete(len, ich_gen, addr_mask);
+}
+
+static void ich_get_region(const struct flashctx *flash, unsigned int addr, struct flash_region *region)
+{
+ struct ich_descriptors desc = { 0 };
+ const ssize_t nr = ich_number_of_regions(ich_generation, &desc.content);
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+ const struct fd_region *fd_regions = hwseq_data->fd_regions;
+
+ /*
+ * Set default values for the region. If no flash descriptor containing
+ * addr is found, these values will be used instead.
+ *
+ * The region start and end are constrained so that they do not overlap
+ * any flash descriptor regions.
+ */
+ const char *name = "";
+ region->read_prot = false;
+ region->write_prot = false;
+ region->start = 0;
+ region->end = flashrom_flash_getsize(flash);
+
+ for (ssize_t i = 0; i < nr; i++) {
+ uint32_t base = fd_regions[i].base;
+ uint32_t limit = fd_regions[i].limit;
+ enum ich_access_protection level = fd_regions[i].level;
+
+ if (addr < base) {
+ /*
+ * fd_regions[i] starts after addr, constrain
+ * region->end so that it does not overlap.
+ */
+ region->end = min(region->end, base);
+ } else if (addr > limit) {
+ /*
+ * fd_regions[i] ends before addr, constrain
+ * region->start so that it does not overlap.
+ */
+ region->start = max(region->start, limit + 1);
+ } else {
+ /* fd_regions[i] contains addr, copy to *region. */
+ name = fd_regions[i].name;
+ region->start = base;
+ region->end = limit + 1;
+ region->read_prot = (level == LOCKED) || (level == READ_PROT);
+ region->write_prot = (level == LOCKED) || (level == WRITE_PROT);
+ break;
+ }
+ }
+
+ region->name = strdup(name);
+}
+
+/* Given RDID info, return pointer to entry in flashchips[] */
+static const struct flashchip *flash_id_to_entry(uint32_t mfg_id, uint32_t model_id)
+{
+ const struct flashchip *chip;
+
+ for (chip = &flashchips[0]; chip->vendor; chip++) {
+ if ((chip->manufacture_id == mfg_id) &&
+ (chip->model_id == model_id) &&
+ (chip->probe == PROBE_SPI_RDID) &&
+ ((chip->bustype & BUS_SPI) == BUS_SPI))
+ return chip;
+ }
+
+ return NULL;
+}
+
+static int ich_hwseq_read_status(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
+{
+ const int len = 1;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+
+ if (reg != STATUS1) {
+ msg_pdbg("%s: only supports STATUS1\n", __func__);
+ /*
+ * Return SPI_INVALID_OPCODE to be consistent with spi_read_register()
+ * and make error handling simpler even though this isn't a SPI master.
+ */
+ return SPI_INVALID_OPCODE;
+ }
+ msg_pdbg("Reading Status register\n");
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RD_STATUS, 1, len, ich_generation,
+ hwseq_data->addr_mask)) {
+ msg_perr("Reading Status register failed\n!!");
+ return -1;
+ }
+ ich_read_data(value, len, ICH9_REG_FDATA0);
+
+ return 0;
+}
+
+static int ich_hwseq_write_status(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
+{
+ const int len = 1;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+
+ if (reg != STATUS1) {
+ msg_pdbg("%s: only supports STATUS1\n", __func__);
+ /*
+ * Return SPI_INVALID_OPCODE to be consistent with spi_write_register()
+ * and make error handling simpler even though this isn't a SPI master.
+ */
+ return SPI_INVALID_OPCODE;
+ }
+ msg_pdbg("Writing status register\n");
+
+ ich_fill_data(&value, len, ICH9_REG_FDATA0);
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WR_STATUS, 1, len, ich_generation,
+ hwseq_data->addr_mask)) {
+ msg_perr("Writing Status register failed\n!!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ich_hwseq_get_flash_id(struct flashctx *flash, enum ich_chipset ich_gen)
+{
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+ if (hwseq_data->size_comp1 != 0) {
+ msg_pinfo("Multiple flash components detected, skipping flash identification.\n");
+ return;
+ }
+
+ /* PCH100 or above is required for RDID, ICH9 does not support it. */
+ if (hwseq_data->hsfc_fcycle != PCH100_HSFC_FCYCLE) {
+ msg_pinfo("RDID cycle not supported, skipping flash identification.\n");
+ return;
+ }
+
+ /*
+ * RDID gives 3 byte output:
+ * Byte 0: Manufacturer ID
+ * Byte 1: Model ID (MSB)
+ * Byte 2: Model ID (LSB)
+ */
+ const int len = 3;
+ uint8_t data[len];
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RDID, 1, len, ich_gen,
+ hwseq_data->addr_mask)) {
+ msg_perr("Timed out waiting for RDID to complete.\n");
+ }
+
+ ich_read_data(data, len, ICH9_REG_FDATA0);
+ uint32_t mfg_id = data[0];
+ uint32_t model_id = (data[1] << 8) | data[2];
+
+ const struct flashchip *entry = flash_id_to_entry(mfg_id, model_id);
+ if (!entry) {
+ msg_pwarn("Unable to identify chip, mfg_id: 0x%02"PRIx32", "
+ "model_id: 0x%02"PRIx32"\n", mfg_id, model_id);
+ return;
+ }
+
+ msg_pdbg("Chip identified: %s\n", entry->name);
+
+ /* Update informational flash chip entries only */
+ flash->chip->vendor = entry->vendor;
+ flash->chip->name = entry->name;
+ flash->chip->manufacture_id = entry->manufacture_id;
+ flash->chip->model_id = entry->model_id;
+ /* total_size read from flash descriptor */
+ flash->chip->page_size = entry->page_size;
+ flash->chip->feature_bits = entry->feature_bits;
+ flash->chip->tested = entry->tested;
+ /* Support writeprotect */
+ flash->chip->reg_bits = entry->reg_bits;
+ flash->chip->decode_range = entry->decode_range;
+}
+
static int ich_hwseq_probe(struct flashctx *flash)
{
uint32_t total_size, boundary;
uint32_t erase_size_low, size_low, erase_size_high, size_high;
struct block_eraser *eraser;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
- total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1;
+ total_size = hwseq_data->size_comp0 + hwseq_data->size_comp1;
msg_cdbg("Hardware sequencing reports %d attached SPI flash chip",
- (hwseq_data.size_comp1 != 0) ? 2 : 1);
- if (hwseq_data.size_comp1 != 0)
+ (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);
+ msg_cdbg(" density of %"PRId32" kB.\n", total_size / 1024);
flash->chip->total_size = total_size / 1024;
eraser = &(flash->chip->block_erasers[0]);
- if (!hwseq_data.only_4k)
+ 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);
+ erase_size_high = ich_hwseq_get_erase_block_size(boundary, hwseq_data->addr_mask, hwseq_data->only_4k);
if (boundary == 0) {
msg_cdbg2("There is only one partition containing the whole "
- "address space (0x%06x - 0x%06x).\n", 0, size_high-1);
+ "address space (0x%06x - 0x%06"PRIx32").\n", 0, size_high-1);
eraser->eraseblocks[0].size = erase_size_high;
eraser->eraseblocks[0].count = size_high / erase_size_high;
- msg_cdbg2("There are %d erase blocks with %d B each.\n",
+ msg_cdbg2("There are %"PRId32" erase blocks with %"PRId32" B each.\n",
size_high / erase_size_high, erase_size_high);
} else {
- msg_cdbg2("The flash address space (0x%06x - 0x%06x) is divided "
- "at address 0x%06x in two partitions.\n",
+ msg_cdbg2("The flash address space (0x%06x - 0x%06"PRIx32") is divided "
+ "at address 0x%06"PRIx32" in two partitions.\n",
0, total_size-1, boundary);
size_low = total_size - size_high;
- erase_size_low = ich_hwseq_get_erase_block_size(0);
+ erase_size_low = ich_hwseq_get_erase_block_size(0, hwseq_data->addr_mask, hwseq_data->only_4k);
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",
+ msg_cdbg("The first partition ranges from 0x%06x to 0x%06"PRIx32".\n", 0, size_low-1);
+ msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" 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",
+ msg_cdbg("The second partition ranges from 0x%06"PRIx32" to 0x%06"PRIx32".\n",
boundary, total_size-1);
- msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+ msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" B each.\n",
size_high / erase_size_high, erase_size_high);
}
- flash->chip->tested = TEST_OK_PREW;
+
+ /* May be overwritten by ich_hwseq_get_flash_id(). */
+ flash->chip->tested = TEST_OK_PREWB;
+
+ ich_hwseq_get_flash_id(flash, ich_generation);
+
return 1;
}
@@ -1375,12 +1650,11 @@ static int ich_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 */
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
- erase_block = ich_hwseq_get_erase_block_size(addr);
+ erase_block = ich_hwseq_get_erase_block_size(addr, hwseq_data->addr_mask, hwseq_data->only_4k);
if (len != erase_block) {
- msg_cerr("Erase block size for address 0x%06x is %d B, "
+ msg_cerr("Erase block size for address 0x%06x is %"PRId32" B, "
"but requested erase block size is %d B. "
"Not erasing anything.\n", addr, erase_block, len);
return -1;
@@ -1390,33 +1664,21 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
* 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). "
+ "block boundary (any multiple of %"PRId32"). "
"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);
+ " (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);
- ich_hwseq_set_addr(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 &= ~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: ");
- prettyprint_ich9_reg_hsfc(hsfc, ich_generation);
- REGWRITE16(ICH9_REG_HSFC, hsfc);
- if (ich_hwseq_wait_for_cycle_complete(timeout, len, ich_generation))
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_BLOCK_ERASE, addr, 1, ich_generation,
+ hwseq_data->addr_mask))
return -1;
return 0;
}
@@ -1424,9 +1686,8 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
static int ich_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;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
if (addr + len > flash->chip->total_size * 1024) {
msg_perr("Request to read from an inaccessible memory address "
@@ -1444,16 +1705,8 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
/* as well as flash chip page borders as demanded in the Intel datasheets. */
block_len = min(block_len, 256 - (addr & 0xFF));
- ich_hwseq_set_addr(addr);
- hsfc = REGREAD16(ICH9_REG_HSFC);
- 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);
- hsfc |= HSFC_FGO; /* start */
- REGWRITE16(ICH9_REG_HSFC, hsfc);
-
- if (ich_hwseq_wait_for_cycle_complete(timeout, block_len, ich_generation))
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_READ, addr, block_len, ich_generation,
+ hwseq_data->addr_mask))
return 1;
ich_read_data(buf, block_len, ICH9_REG_FDATA0);
addr += block_len;
@@ -1465,9 +1718,8 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
static int ich_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;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
if (addr + len > flash->chip->total_size * 1024) {
msg_perr("Request to write to an inaccessible memory address "
@@ -1480,22 +1732,14 @@ static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned
REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
while (len > 0) {
- ich_hwseq_set_addr(addr);
/* Obey programmer limit... */
block_len = min(len, flash->mst->opaque.max_data_write);
/* as well as flash chip page borders as demanded in the Intel datasheets. */
block_len = min(block_len, 256 - (addr & 0xFF));
ich_fill_data(buf, block_len, ICH9_REG_FDATA0);
- hsfc = REGREAD16(ICH9_REG_HSFC);
- hsfc &= ~hwseq_data.hsfc_fcycle; /* clear operation */
- hsfc |= (0x2 << 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 (ich_hwseq_wait_for_cycle_complete(timeout, block_len, ich_generation))
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WRITE, addr, block_len, ich_generation,
+ hwseq_data->addr_mask))
return -1;
addr += block_len;
buf += block_len;
@@ -1504,6 +1748,12 @@ static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned
return 0;
}
+static int ich_hwseq_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
static int ich_spi_send_multicommand(const struct flashctx *flash,
struct spi_command *cmds)
{
@@ -1564,6 +1814,11 @@ static int ich_spi_send_multicommand(const struct flashctx *flash,
return ret;
}
+static bool ich_spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
+{
+ return find_opcode(curopcodes, opcode) >= 0;
+}
+
#define ICH_BMWAG(x) ((x >> 24) & 0xff)
#define ICH_BMRAG(x) ((x >> 16) & 0xff)
#define ICH_BRWA(x) ((x >> 8) & 0xff)
@@ -1573,12 +1828,12 @@ static const enum ich_access_protection access_perms_to_protection[] = {
LOCKED, WRITE_PROT, READ_PROT, NO_PROT
};
static const char *const access_names[] = {
- "locked", "read-only", "write-only", "read-write"
+ "read-write", "write-only", "read-only", "locked"
};
-static enum ich_access_protection ich9_handle_frap(uint32_t frap, unsigned int i)
+static enum ich_access_protection ich9_handle_frap(struct fd_region *fd_regions,
+ uint32_t frap, unsigned int i)
{
- const int rwperms_unknown = ARRAY_SIZE(access_names);
static const char *const region_names[] = {
"Flash Descriptor", "BIOS", "Management Engine",
"Gigabit Ethernet", "Platform Data", "Device Expansion",
@@ -1587,46 +1842,46 @@ static enum ich_access_protection ich9_handle_frap(uint32_t frap, unsigned int i
const char *const region_name = i < ARRAY_SIZE(region_names) ? region_names[i] : "unknown";
uint32_t base, limit;
- int rwperms;
+ unsigned int rwperms_idx;
+ enum ich_access_protection rwperms;
const int offset = i < 12
? ICH9_REG_FREG0 + i * 4
: APL_REG_FREG12 + (i - 12) * 4;
uint32_t freg = mmio_readl(ich_spibar + offset);
- if (i < 8) {
- rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) |
- (((ICH_BRRA(frap) >> i) & 1) << 0);
- } else {
- /* Datasheets don't define any access bits for regions > 7. We
- can't rely on the actual descriptor settings either as there
- are several overrides for them (those by other masters are
- not even readable by us, *shrug*). */
- rwperms = rwperms_unknown;
- }
-
base = ICH_FREG_BASE(freg);
limit = ICH_FREG_LIMIT(freg);
if (base > limit || (freg == 0 && i > 0)) {
/* this FREG is disabled */
- msg_pdbg2("0x%02X: 0x%08x FREG%u: %s region is unused.\n",
+ msg_pdbg2("0x%02X: 0x%08"PRIx32" FREG%u: %s region is unused.\n",
offset, freg, i, region_name);
return NO_PROT;
}
- msg_pdbg("0x%02X: 0x%08x ", offset, freg);
- if (rwperms == 0x3) {
- msg_pdbg("FREG%u: %s region (0x%08x-0x%08x) is %s.\n", i,
- region_name, base, limit, access_names[rwperms]);
- return NO_PROT;
- }
- if (rwperms == rwperms_unknown) {
- msg_pdbg("FREG%u: %s region (0x%08x-0x%08x) has unknown permissions.\n",
- i, region_name, base, limit);
+ msg_pdbg("0x%02X: 0x%08"PRIx32" ", offset, freg);
+
+ if (i < 8) {
+ rwperms_idx = (((ICH_BRWA(frap) >> i) & 1) << 1) |
+ (((ICH_BRRA(frap) >> i) & 1) << 0);
+ rwperms = access_perms_to_protection[rwperms_idx];
+ } else {
+ /* Datasheets don't define any access bits for regions > 7. We
+ can't rely on the actual descriptor settings either as there
+ are several overrides for them (those by other masters are
+ not even readable by us, *shrug*). */
+ msg_pdbg("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") has unknown permissions.\n",
+ i, region_name, base, limit);
return NO_PROT;
}
-
- msg_pinfo("FREG%u: %s region (0x%08x-0x%08x) is %s.\n", i,
+ msg_pinfo("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") is %s.\n", i,
region_name, base, limit, access_names[rwperms]);
- return access_perms_to_protection[rwperms];
+
+ /* Save region attributes for use by ich_get_region(). */
+ fd_regions[i].base = base;
+ fd_regions[i].limit = limit;
+ fd_regions[i].level = rwperms;
+ fd_regions[i].name = region_name;
+
+ return rwperms;
}
/* In contrast to FRAP and the master section of the descriptor the bits
@@ -1642,22 +1897,24 @@ static enum ich_access_protection ich9_handle_pr(const size_t reg_pr0, unsigned
{
uint8_t off = reg_pr0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off);
- unsigned int rwperms = ICH_PR_PERMS(pr);
+ unsigned int rwperms_idx = ICH_PR_PERMS(pr);
+ enum ich_access_protection rwperms = access_perms_to_protection[rwperms_idx];
/* 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 (%sPR%u is unused)\n", off, pr, prefix, i);
+ if (rwperms == NO_PROT) {
+ msg_pdbg2("0x%02"PRIX8": 0x%08"PRIx32" (%sPR%u is unused)\n", off, pr, prefix, i);
return NO_PROT;
}
- msg_pdbg("0x%02X: 0x%08x ", off, pr);
- msg_pwarn("%sPR%u: Warning: 0x%08x-0x%08x is %s.\n", prefix, i, ICH_FREG_BASE(pr),
+ msg_pdbg("0x%02"PRIX8": 0x%08"PRIx32" ", off, pr);
+ msg_pwarn("%sPR%u: Warning: 0x%08"PRIx32"-0x%08"PRIx32" is %s.\n", prefix, i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr), access_names[rwperms]);
- return access_perms_to_protection[rwperms];
+
+ return rwperms;
}
/* Set/Clear the read and write protection enable bits of PR register @i
@@ -1668,7 +1925,7 @@ static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_pr
uint32_t old = mmio_readl(addr);
uint32_t new;
- msg_gspew("PR%u is 0x%08x", i, old);
+ msg_gspew("PR%u is 0x%08"PRIx32"", i, old);
new = old & ~((1 << PR_RP_OFF) | (1 << PR_WP_OFF));
if (read_prot)
new |= (1 << PR_RP_OFF);
@@ -1678,385 +1935,455 @@ static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_pr
msg_gspew(" already.\n");
return;
}
- msg_gspew(", trying to set it to 0x%08x ", new);
+ msg_gspew(", trying to set it to 0x%08"PRIx32" ", new);
rmmio_writel(new, addr);
- msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr));
+ msg_gspew("resulted in 0x%08"PRIx32".\n", mmio_readl(addr));
}
static const struct spi_master spi_master_ich7 = {
- .max_data_read = 64,
- .max_data_write = 64,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
};
static const struct spi_master spi_master_ich9 = {
- .max_data_read = 64,
- .max_data_write = 64,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .probe_opcode = ich_spi_probe_opcode,
};
static const struct opaque_master opaque_master_ich_hwseq = {
- .max_data_read = 64,
- .max_data_write = 64,
- .probe = ich_hwseq_probe,
- .read = ich_hwseq_read,
- .write = ich_hwseq_write,
- .erase = ich_hwseq_block_erase,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .probe = ich_hwseq_probe,
+ .read = ich_hwseq_read,
+ .write = ich_hwseq_write,
+ .erase = ich_hwseq_block_erase,
+ .read_register = ich_hwseq_read_status,
+ .write_register = ich_hwseq_write_status,
+ .get_region = ich_get_region,
+ .shutdown = ich_hwseq_shutdown,
};
-int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
+static int init_ich7_spi(void *spibar, enum ich_chipset ich_gen)
{
unsigned int i;
- uint16_t tmp2;
- uint32_t tmp;
- char *arg;
- int ich_spi_rw_restricted = 0;
- int desc_valid = 0;
- struct ich_descriptors desc;
- enum ich_spi_mode {
- ich_auto,
- ich_hwseq,
- ich_swseq
- } ich_spi_mode = ich_auto;
- size_t num_freg, num_pr, reg_pr0;
- ich_generation = ich_gen;
- ich_spibar = spibar;
+ msg_pdbg("0x00: 0x%04"PRIx16" (SPIS)\n", mmio_readw(spibar + 0));
+ msg_pdbg("0x02: 0x%04"PRIx16" (SPIC)\n", mmio_readw(spibar + 2));
+ msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n", mmio_readl(spibar + 4));
+
+ ichspi_bbar = mmio_readl(spibar + 0x50);
+
+ msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n", ichspi_bbar);
+ msg_pdbg("0x54: 0x%04"PRIx16" (PREOP)\n", mmio_readw(spibar + 0x54));
+ msg_pdbg("0x56: 0x%04"PRIx16" (OPTYPE)\n", mmio_readw(spibar + 0x56));
+ msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n", mmio_readl(spibar + 0x58));
+ msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n", mmio_readl(spibar + 0x5c));
+
+ for (i = 0; i < 3; i++) {
+ int offs;
+ offs = 0x60 + (i * 4);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%u)\n", offs, mmio_readl(spibar + offs), i);
+ }
+ if (mmio_readw(spibar) & (1 << 15)) {
+ msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
+ ichspi_lock = true;
+ }
+ ich_init_opcodes(ich_gen);
+ ich_set_bbar(0, ich_gen);
+ register_spi_master(&spi_master_ich7, NULL);
+
+ return 0;
+}
+
+enum ich_spi_mode {
+ ich_auto,
+ ich_hwseq,
+ ich_swseq
+};
+
+static int get_ich_spi_mode_param(const struct programmer_cfg *cfg, enum ich_spi_mode *ich_spi_mode)
+{
+ char *const arg = extract_programmer_param_str(cfg, "ich_spi_mode");
+ if (!arg) {
+ return 0;
+ } else if (!strcmp(arg, "hwseq")) {
+ *ich_spi_mode = ich_hwseq;
+ msg_pspew("user selected hwseq\n");
+ } else if (!strcmp(arg, "swseq")) {
+ *ich_spi_mode = ich_swseq;
+ msg_pspew("user selected swseq\n");
+ } else if (!strcmp(arg, "auto")) {
+ msg_pspew("user selected auto\n");
+ *ich_spi_mode = ich_auto;
+ } else if (!strlen(arg)) {
+ msg_perr("Missing argument for ich_spi_mode.\n");
+ free(arg);
+ return ERROR_FLASHROM_FATAL;
+ } else {
+ msg_perr("Unknown argument for ich_spi_mode: %s\n", arg);
+ free(arg);
+ return ERROR_FLASHROM_FATAL;
+ }
+ free(arg);
- memset(&desc, 0x00, sizeof(struct ich_descriptors));
+ return 0;
+}
+static void init_chipset_properties(struct swseq_data *swseq, struct hwseq_data *hwseq,
+ size_t *num_freg, size_t *num_pr, size_t *reg_pr0,
+ enum ich_chipset ich_gen)
+{
/* Moving registers / bits */
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- num_pr = 6; /* Includes GPR0 */
- 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;
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ *num_pr = 6; /* Includes GPR0 */
+ *reg_pr0 = PCH100_REG_FPR0;
+ swseq->reg_ssfsc = PCH100_REG_SSFSC;
+ swseq->reg_preop = PCH100_REG_PREOP;
+ swseq->reg_optype = PCH100_REG_OPTYPE;
+ swseq->reg_opmenu = PCH100_REG_OPMENU;
+ hwseq->addr_mask = PCH100_FADDR_FLA;
+ hwseq->only_4k = true;
+ hwseq->hsfc_fcycle = PCH100_HSFC_FCYCLE;
break;
default:
- 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;
+ *num_pr = 5;
+ *reg_pr0 = ICH9_REG_PR0;
+ swseq->reg_ssfsc = ICH9_REG_SSFS;
+ swseq->reg_preop = ICH9_REG_PREOP;
+ swseq->reg_optype = ICH9_REG_OPTYPE;
+ swseq->reg_opmenu = ICH9_REG_OPMENU;
+ hwseq->addr_mask = ICH9_FADDR_FLA;
+ hwseq->only_4k = false;
+ hwseq->hsfc_fcycle = ICH9_HSFC_FCYCLE;
break;
}
+
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
- num_freg = 10;
+ *num_freg = 10;
break;
case CHIPSET_C620_SERIES_LEWISBURG:
- num_freg = 12; /* 12 MMIO regs, but 16 regions in FD spec */
+ *num_freg = 12; /* 12 MMIO regs, but 16 regions in FD spec */
break;
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- num_freg = 16;
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ *num_freg = 16;
break;
default:
- num_freg = 5;
+ *num_freg = 5;
break;
}
+}
+
+static int init_ich_default(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
+{
+ unsigned int i;
+ uint16_t tmp2;
+ uint32_t tmp;
+ int ich_spi_rw_restricted = 0;
+ bool desc_valid = false;
+ struct ich_descriptors desc = { 0 };
+ enum ich_spi_mode ich_spi_mode = ich_auto;
+ size_t num_freg, num_pr, reg_pr0;
+ struct hwseq_data hwseq_data = { 0 };
+ init_chipset_properties(&swseq_data, &hwseq_data, &num_freg, &num_pr, &reg_pr0, ich_gen);
+
+ int ret = get_ich_spi_mode_param(cfg, &ich_spi_mode);
+ if (ret)
+ return ret;
+
+ tmp2 = mmio_readw(spibar + ICH9_REG_HSFS);
+ msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
+ prettyprint_ich9_reg_hsfs(tmp2, ich_gen);
+ if (tmp2 & HSFS_FLOCKDN) {
+ msg_pinfo("SPI Configuration is locked down.\n");
+ ichspi_lock = true;
+ }
+ if (tmp2 & HSFS_FDV)
+ desc_valid = true;
+ if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
+ msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
+ "the Master Section of the flash descriptor are NOT in effect. Please note\n"
+ "that Protected Range (PR) restrictions still apply.\n");
+ ich_init_opcodes(ich_gen);
+
+ if (desc_valid) {
+ tmp2 = mmio_readw(spibar + ICH9_REG_HSFC);
+ msg_pdbg("0x06: 0x%04"PRIx16" (HSFC)\n", tmp2);
+ prettyprint_ich9_reg_hsfc(tmp2, ich_gen);
+ }
+
+ tmp = mmio_readl(spibar + ICH9_REG_FADDR);
+ msg_pdbg2("0x08: 0x%08"PRIx32" (FADDR)\n", tmp);
switch (ich_gen) {
- case CHIPSET_ICH7:
- case CHIPSET_TUNNEL_CREEK:
- case CHIPSET_CENTERTON:
- msg_pdbg("0x00: 0x%04x (SPIS)\n",
- mmio_readw(spibar + 0));
- msg_pdbg("0x02: 0x%04x (SPIC)\n",
- mmio_readw(spibar + 2));
- msg_pdbg("0x04: 0x%08x (SPIA)\n",
- mmio_readl(spibar + 4));
- ichspi_bbar = mmio_readl(spibar + 0x50);
- msg_pdbg("0x50: 0x%08x (BBAR)\n",
- ichspi_bbar);
- msg_pdbg("0x54: 0x%04x (PREOP)\n",
- mmio_readw(spibar + 0x54));
- msg_pdbg("0x56: 0x%04x (OPTYPE)\n",
- mmio_readw(spibar + 0x56));
- msg_pdbg("0x58: 0x%08x (OPMENU)\n",
- mmio_readl(spibar + 0x58));
- msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n",
- mmio_readl(spibar + 0x5c));
- for (i = 0; i < 3; i++) {
- int offs;
- offs = 0x60 + (i * 4);
- msg_pdbg("0x%02x: 0x%08x (PBR%u)\n", offs,
- mmio_readl(spibar + offs), i);
- }
- if (mmio_readw(spibar) & (1 << 15)) {
- msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
- ichspi_lock = 1;
- }
- ich_init_opcodes(ich_gen);
- ich_set_bbar(0, ich_gen);
- register_spi_master(&spi_master_ich7);
+ case CHIPSET_100_SERIES_SUNRISE_POINT:
+ case CHIPSET_C620_SERIES_LEWISBURG:
+ case CHIPSET_300_SERIES_CANNON_POINT:
+ case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ tmp = mmio_readl(spibar + PCH100_REG_DLOCK);
+ msg_pdbg("0x0c: 0x%08"PRIx32" (DLOCK)\n", tmp);
+ prettyprint_pch100_reg_dlock(tmp);
break;
- case CHIPSET_ICH8:
- default: /* Future version might behave the same */
- arg = extract_programmer_param("ich_spi_mode");
- if (arg && !strcmp(arg, "hwseq")) {
- ich_spi_mode = ich_hwseq;
- msg_pspew("user selected hwseq\n");
- } else if (arg && !strcmp(arg, "swseq")) {
- ich_spi_mode = ich_swseq;
- msg_pspew("user selected swseq\n");
- } else if (arg && !strcmp(arg, "auto")) {
- msg_pspew("user selected auto\n");
- ich_spi_mode = ich_auto;
- } else if (arg && !strlen(arg)) {
- msg_perr("Missing argument for ich_spi_mode.\n");
- free(arg);
- return ERROR_FATAL;
- } else if (arg) {
- msg_perr("Unknown argument for ich_spi_mode: %s\n",
- arg);
- free(arg);
- return ERROR_FATAL;
- }
- free(arg);
+ default:
+ break;
+ }
- tmp2 = mmio_readw(spibar + ICH9_REG_HSFS);
- msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
- prettyprint_ich9_reg_hsfs(tmp2, ich_gen);
- if (tmp2 & HSFS_FLOCKDN) {
- msg_pinfo("SPI Configuration is locked down.\n");
- ichspi_lock = 1;
- }
- if (tmp2 & HSFS_FDV)
- desc_valid = 1;
- if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
- msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
- "the Master Section of the flash descriptor are NOT in effect. Please note\n"
- "that Protected Range (PR) restrictions still apply.\n");
- ich_init_opcodes(ich_gen);
-
- if (desc_valid) {
- tmp2 = mmio_readw(spibar + ICH9_REG_HSFC);
- msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
- prettyprint_ich9_reg_hsfc(tmp2, ich_gen);
- }
+ if (desc_valid) {
+ tmp = mmio_readl(spibar + ICH9_REG_FRAP);
+ msg_pdbg("0x50: 0x%08"PRIx32" (FRAP)\n", tmp);
+ msg_pdbg("BMWAG 0x%02"PRIx32", ", ICH_BMWAG(tmp));
+ msg_pdbg("BMRAG 0x%02"PRIx32", ", ICH_BMRAG(tmp));
+ msg_pdbg("BRWA 0x%02"PRIx32", ", ICH_BRWA(tmp));
+ msg_pdbg("BRRA 0x%02"PRIx32"\n", ICH_BRRA(tmp));
- tmp = mmio_readl(spibar + ICH9_REG_FADDR);
- msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp);
+ /* Handle FREGx and FRAP registers */
+ for (i = 0; i < num_freg; i++)
+ ich_spi_rw_restricted |= ich9_handle_frap(hwseq_data.fd_regions, tmp, i);
+ if (ich_spi_rw_restricted)
+ msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
+ "most likely\ndue to an active ME. Please see "
+ "https://flashrom.org/ME for details.\n");
+ }
+
+ /* Handle PR registers */
+ for (i = 0; i < num_pr; i++) {
+ /* if not locked down try to disable PR locks first */
+ if (!ichspi_lock)
+ ich9_set_pr(reg_pr0, i, 0, 0);
+ ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
+ }
+ switch (ich_spi_rw_restricted) {
+ case WRITE_PROT:
+ msg_pwarn("At least some flash regions are write protected. For write operations,\n"
+ "you should use a flash layout and include only writable regions. See\n"
+ "manpage for more details.\n");
+ break;
+ case READ_PROT:
+ case LOCKED:
+ msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
+ "layout and include only accessible regions. For write operations, you'll\n"
+ "additionally need the --noverify-all switch. See manpage for more details.\n");
+ break;
+ }
+
+ tmp = mmio_readl(spibar + swseq_data.reg_ssfsc);
+ msg_pdbg("0x%zx: 0x%02"PRIx32" (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, spibar + swseq_data.reg_ssfsc);
+ }
+ msg_pdbg("0x%zx: 0x%06"PRIx32" (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
+ prettyprint_ich9_reg_ssfc(tmp);
+
+ msg_pdbg("0x%zx: 0x%04"PRIx16" (PREOP)\n",
+ swseq_data.reg_preop, mmio_readw(spibar + swseq_data.reg_preop));
+ msg_pdbg("0x%zx: 0x%04"PRIx16" (OPTYPE)\n",
+ swseq_data.reg_optype, mmio_readw(spibar + swseq_data.reg_optype));
+ msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU)\n",
+ swseq_data.reg_opmenu, mmio_readl(spibar + swseq_data.reg_opmenu));
+ msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU+4)\n",
+ swseq_data.reg_opmenu + 4, mmio_readl(spibar + swseq_data.reg_opmenu + 4));
+
+ if (desc_valid) {
switch (ich_gen) {
+ case CHIPSET_ICH8:
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- tmp = mmio_readl(spibar + PCH100_REG_DLOCK);
- msg_pdbg("0x0c: 0x%08x (DLOCK)\n", tmp);
- prettyprint_pch100_reg_dlock(tmp);
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_BAYTRAIL:
+ case CHIPSET_ELKHART_LAKE:
break;
default:
+ ichspi_bbar = mmio_readl(spibar + ICH9_REG_BBAR);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
+ ich_set_bbar(0, ich_gen);
break;
}
- if (desc_valid) {
- tmp = mmio_readl(spibar + ICH9_REG_FRAP);
- msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
- msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp));
- msg_pdbg("BMRAG 0x%02x, ", ICH_BMRAG(tmp));
- msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
- msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
-
- /* Handle FREGx and FRAP registers */
- for (i = 0; i < num_freg; i++)
- ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
- if (ich_spi_rw_restricted)
- msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
- "most likely\ndue to an active ME. Please see "
- "https://flashrom.org/ME for details.\n");
- }
-
- /* Handle PR registers */
- for (i = 0; i < num_pr; i++) {
- /* if not locked down try to disable PR locks first */
- if (!ichspi_lock)
- ich9_set_pr(reg_pr0, i, 0, 0);
- ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
+ if (ich_gen == CHIPSET_ICH8) {
+ tmp = mmio_readl(spibar + ICH8_REG_VSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (VSCC)\n", ICH8_REG_VSCC, tmp);
+ msg_pdbg("VSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
+ } else {
+ tmp = mmio_readl(spibar + ICH9_REG_LVSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (LVSCC)\n", ICH9_REG_LVSCC, tmp);
+ msg_pdbg("LVSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
+
+ tmp = mmio_readl(spibar + ICH9_REG_UVSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (UVSCC)\n", ICH9_REG_UVSCC, tmp);
+ msg_pdbg("UVSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, false);
}
- switch (ich_spi_rw_restricted) {
- case WRITE_PROT:
- msg_pwarn("At least some flash regions are write protected. For write operations,\n"
- "you should use a flash layout and include only writable regions. See\n"
- "manpage for more details.\n");
+ switch (ich_gen) {
+ case CHIPSET_ICH8:
+ case CHIPSET_100_SERIES_SUNRISE_POINT:
+ case CHIPSET_C620_SERIES_LEWISBURG:
+ case CHIPSET_300_SERIES_CANNON_POINT:
+ case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
break;
- case READ_PROT:
- case LOCKED:
- msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
- "layout and include only accessible regions. For write operations, you'll\n"
- "additionally need the --noverify-all switch. See manpage for more details.\n"
- );
+ default:
+ tmp = mmio_readl(spibar + ICH9_REG_FPB);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (FPB)\n", ICH9_REG_FPB, tmp);
break;
}
- tmp = mmio_readl(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, spibar + swseq_data.reg_ssfsc);
- }
- msg_pdbg("0x%zx: 0x%06x (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
- prettyprint_ich9_reg_ssfc(tmp);
-
- msg_pdbg("0x%zx: 0x%04x (PREOP)\n",
- swseq_data.reg_preop, mmio_readw(spibar + swseq_data.reg_preop));
- msg_pdbg("0x%zx: 0x%04x (OPTYPE)\n",
- swseq_data.reg_optype, mmio_readw(spibar + swseq_data.reg_optype));
- msg_pdbg("0x%zx: 0x%08x (OPMENU)\n",
- swseq_data.reg_opmenu, mmio_readl(spibar + swseq_data.reg_opmenu));
- msg_pdbg("0x%zx: 0x%08x (OPMENU+4)\n",
- swseq_data.reg_opmenu + 4, mmio_readl(spibar + swseq_data.reg_opmenu + 4));
-
- if (desc_valid) {
- switch (ich_gen) {
- case CHIPSET_ICH8:
- case CHIPSET_100_SERIES_SUNRISE_POINT:
- case CHIPSET_C620_SERIES_LEWISBURG:
- case CHIPSET_300_SERIES_CANNON_POINT:
- case CHIPSET_400_SERIES_COMET_POINT:
- case CHIPSET_APOLLO_LAKE:
- case CHIPSET_BAYTRAIL:
- break;
- default:
- ichspi_bbar = mmio_readl(spibar + ICH9_REG_BBAR);
- msg_pdbg("0x%x: 0x%08x (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
- ich_set_bbar(0, ich_gen);
- break;
- }
+ if (read_ich_descriptors_via_fdo(ich_gen, spibar, &desc) == ICH_RET_OK)
+ prettyprint_ich_descriptors(ich_gen, &desc);
- if (ich_gen == CHIPSET_ICH8) {
- tmp = mmio_readl(spibar + ICH8_REG_VSCC);
- msg_pdbg("0x%x: 0x%08x (VSCC)\n", ICH8_REG_VSCC, tmp);
- msg_pdbg("VSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
- } else {
- tmp = mmio_readl(spibar + ICH9_REG_LVSCC);
- msg_pdbg("0x%x: 0x%08x (LVSCC)\n", ICH9_REG_LVSCC, tmp);
- msg_pdbg("LVSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
-
- tmp = mmio_readl(spibar + ICH9_REG_UVSCC);
- msg_pdbg("0x%x: 0x%08x (UVSCC)\n", ICH9_REG_UVSCC, tmp);
- msg_pdbg("UVSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, false);
- }
+ /* If the descriptor is valid and indicates multiple
+ * flash devices we need to use hwseq to be able to
+ * access the second flash device.
+ */
+ if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
+ msg_pinfo("Enabling hardware sequencing due to multiple flash chips detected.\n");
+ ich_spi_mode = ich_hwseq;
+ }
+ }
- switch (ich_gen) {
- case CHIPSET_ICH8:
- case CHIPSET_100_SERIES_SUNRISE_POINT:
- case CHIPSET_C620_SERIES_LEWISBURG:
- case CHIPSET_300_SERIES_CANNON_POINT:
- case CHIPSET_400_SERIES_COMET_POINT:
- case CHIPSET_APOLLO_LAKE:
- break;
- default:
- tmp = mmio_readl(spibar + ICH9_REG_FPB);
- msg_pdbg("0x%x: 0x%08x (FPB)\n", ICH9_REG_FPB, tmp);
- break;
- }
+ if (ich_spi_mode == ich_auto && ichspi_lock &&
+ ich_missing_opcodes()) {
+ msg_pinfo("Enabling hardware sequencing because "
+ "some important opcode is locked.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- if (read_ich_descriptors_via_fdo(ich_gen, spibar, &desc) == ICH_RET_OK)
- prettyprint_ich_descriptors(ich_gen, &desc);
+ if (ich_spi_mode == ich_auto &&
+ (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
+ ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
+ ich_gen == CHIPSET_400_SERIES_COMET_POINT ||
+ ich_gen == CHIPSET_500_SERIES_TIGER_POINT ||
+ ich_gen == CHIPSET_600_SERIES_ALDER_POINT)) {
+ msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- /* If the descriptor is valid and indicates multiple
- * flash devices we need to use hwseq to be able to
- * access the second flash device.
- */
- if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
- msg_pinfo("Enabling hardware sequencing due to "
- "multiple flash chips detected.\n");
- ich_spi_mode = ich_hwseq;
- }
- }
+ if (ich_spi_mode == ich_auto &&
+ (ich_gen == CHIPSET_APOLLO_LAKE ||
+ ich_gen == CHIPSET_GEMINI_LAKE ||
+ ich_gen == CHIPSET_JASPER_LAKE ||
+ ich_gen == CHIPSET_ELKHART_LAKE ||
+ ich_gen == CHIPSET_METEOR_LAKE)) {
+ msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini/Jasper/Elkhart/Meteor Lake.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- if (ich_spi_mode == ich_auto && ichspi_lock &&
- ich_missing_opcodes()) {
- msg_pinfo("Enabling hardware sequencing because "
- "some important opcode is locked.\n");
- ich_spi_mode = ich_hwseq;
+ if (ich_spi_mode == ich_hwseq) {
+ if (!desc_valid) {
+ msg_perr("Hardware sequencing was requested "
+ "but the flash descriptor is not valid. Aborting.\n");
+ return ERROR_FLASHROM_FATAL;
}
- if (ich_spi_mode == ich_auto &&
- (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
- ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
- ich_gen == CHIPSET_400_SERIES_COMET_POINT)) {
- msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
- ich_spi_mode = ich_hwseq;
+ int tmpi = getFCBA_component_density(ich_gen, &desc, 0);
+ if (tmpi < 0) {
+ msg_perr("Could not determine density of flash component %d.\n", 0);
+ return ERROR_FLASHROM_FATAL;
}
+ hwseq_data.size_comp0 = tmpi;
- if (ich_spi_mode == ich_auto && ich_gen == CHIPSET_APOLLO_LAKE) {
- msg_pdbg("Enabling hardware sequencing by default for Apollo Lake.\n");
- ich_spi_mode = ich_hwseq;
+ tmpi = getFCBA_component_density(ich_gen, &desc, 1);
+ if (tmpi < 0) {
+ msg_perr("Could not determine density of flash component %d.\n", 1);
+ return ERROR_FLASHROM_FATAL;
}
+ hwseq_data.size_comp1 = tmpi;
- if (ich_spi_mode == ich_hwseq) {
- if (!desc_valid) {
- msg_perr("Hardware sequencing was requested "
- "but the flash descriptor is not "
- "valid. Aborting.\n");
- return ERROR_FATAL;
- }
+ struct hwseq_data *opaque_hwseq_data = calloc(1, sizeof(struct hwseq_data));
+ if (!opaque_hwseq_data)
+ return ERROR_FLASHROM_FATAL;
+ memcpy(opaque_hwseq_data, &hwseq_data, sizeof(*opaque_hwseq_data));
+ register_opaque_master(&opaque_master_ich_hwseq, opaque_hwseq_data);
+ } else {
+ register_spi_master(&spi_master_ich9, NULL);
+ }
- int tmpi = getFCBA_component_density(ich_gen, &desc, 0);
- if (tmpi < 0) {
- msg_perr("Could not determine density of flash component %d.\n", 0);
- return ERROR_FATAL;
- }
- hwseq_data.size_comp0 = tmpi;
+ return 0;
+}
- tmpi = getFCBA_component_density(ich_gen, &desc, 1);
- if (tmpi < 0) {
- msg_perr("Could not determine density of flash component %d.\n", 1);
- return ERROR_FATAL;
- }
- hwseq_data.size_comp1 = tmpi;
+int ich_init_spi(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
+{
+ ich_generation = ich_gen;
+ ich_spibar = spibar;
- register_opaque_master(&opaque_master_ich_hwseq);
- } else {
- register_spi_master(&spi_master_ich9);
- }
- break;
+ switch (ich_gen) {
+ case CHIPSET_ICH7:
+ case CHIPSET_TUNNEL_CREEK:
+ case CHIPSET_CENTERTON:
+ return init_ich7_spi(spibar, ich_gen);
+ case CHIPSET_ICH8:
+ default: /* Future version might behave the same */
+ return init_ich_default(cfg, spibar, ich_gen);
}
-
- return 0;
}
static const struct spi_master spi_master_via = {
- .max_data_read = 16,
- .max_data_write = 16,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 16,
+ .max_data_write = 16,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .probe_opcode = ich_spi_probe_opcode,
};
int via_init_spi(uint32_t mmio_base)
@@ -2065,42 +2392,40 @@ int via_init_spi(uint32_t mmio_base)
ich_spibar = rphysmap("VIA SPI MMIO registers", mmio_base, 0x70);
if (ich_spibar == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* Do we really need no write enable? Like the LPC one at D17F0 0x40 */
/* Not sure if it speaks all these bus protocols. */
internal_buses_supported &= BUS_LPC | BUS_FWH;
ich_generation = CHIPSET_ICH7;
- register_spi_master(&spi_master_via);
+ register_spi_master(&spi_master_via, NULL);
- msg_pdbg("0x00: 0x%04x (SPIS)\n", mmio_readw(ich_spibar + 0));
- msg_pdbg("0x02: 0x%04x (SPIC)\n", mmio_readw(ich_spibar + 2));
- msg_pdbg("0x04: 0x%08x (SPIA)\n", mmio_readl(ich_spibar + 4));
+ msg_pdbg("0x00: 0x%04"PRIx16" (SPIS)\n", mmio_readw(ich_spibar + 0));
+ msg_pdbg("0x02: 0x%04"PRIx16" (SPIC)\n", mmio_readw(ich_spibar + 2));
+ msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n", mmio_readl(ich_spibar + 4));
for (i = 0; i < 2; i++) {
int offs;
offs = 8 + (i * 8);
- msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
- mmio_readl(ich_spibar + offs), i);
- msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d)\n", offs, mmio_readl(ich_spibar + offs), i);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d+4)\n", offs + 4,
mmio_readl(ich_spibar + offs + 4), i);
}
ichspi_bbar = mmio_readl(ich_spibar + 0x50);
- msg_pdbg("0x50: 0x%08x (BBAR)\n", ichspi_bbar);
- msg_pdbg("0x54: 0x%04x (PREOP)\n", mmio_readw(ich_spibar + 0x54));
- msg_pdbg("0x56: 0x%04x (OPTYPE)\n", mmio_readw(ich_spibar + 0x56));
- msg_pdbg("0x58: 0x%08x (OPMENU)\n", mmio_readl(ich_spibar + 0x58));
- msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n", mmio_readl(ich_spibar + 0x5c));
+
+ msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n", ichspi_bbar);
+ msg_pdbg("0x54: 0x%04"PRIx16" (PREOP)\n", mmio_readw(ich_spibar + 0x54));
+ msg_pdbg("0x56: 0x%04"PRIx16" (OPTYPE)\n", mmio_readw(ich_spibar + 0x56));
+ msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n", mmio_readl(ich_spibar + 0x58));
+ msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n", mmio_readl(ich_spibar + 0x5c));
for (i = 0; i < 3; i++) {
int offs;
offs = 0x60 + (i * 4);
- msg_pdbg("0x%02x: 0x%08x (PBR%d)\n", offs,
- mmio_readl(ich_spibar + offs), i);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%d)\n", offs, mmio_readl(ich_spibar + offs), i);
}
- msg_pdbg("0x6c: 0x%04x (CLOCK/DEBUG)\n",
- mmio_readw(ich_spibar + 0x6c));
+ msg_pdbg("0x6c: 0x%04x (CLOCK/DEBUG)\n", mmio_readw(ich_spibar + 0x6c));
if (mmio_readw(ich_spibar) & (1 << 15)) {
msg_pwarn("Warning: SPI Configuration Lockdown activated.\n");
- ichspi_lock = 1;
+ ichspi_lock = true;
}
ich_set_bbar(0, ich_generation);
@@ -2108,5 +2433,3 @@ int via_init_spi(uint32_t mmio_base)
return 0;
}
-
-#endif