summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/flashrom/chipset_enable.c3
-rw-r--r--util/flashrom/flash.h8
-rw-r--r--util/flashrom/ichspi.c134
3 files changed, 145 insertions, 0 deletions
diff --git a/util/flashrom/chipset_enable.c b/util/flashrom/chipset_enable.c
index 01abf1090f..d2ae21279a 100644
--- a/util/flashrom/chipset_enable.c
+++ b/util/flashrom/chipset_enable.c
@@ -47,6 +47,8 @@ unsigned long flashbase = 0;
flashbus_t flashbus = BUS_TYPE_LPC;
void *spibar = NULL;
+extern int ichspi_lock;
+
static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
{
uint8_t tmp;
@@ -335,6 +337,7 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
printf_debug("\n");
if ((*(uint16_t *) spibar) & (1 << 15)) {
printf("WARNING: SPI Configuration Lockdown activated.\n");
+ ichspi_lock = 1;
}
break;
case BUS_TYPE_ICH9_SPI:
diff --git a/util/flashrom/flash.h b/util/flashrom/flash.h
index de9199ccb1..c74c96f3cb 100644
--- a/util/flashrom/flash.h
+++ b/util/flashrom/flash.h
@@ -51,6 +51,12 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+/* for pairing opcodes with their required preop */
+struct preop_opcode_pair {
+ uint8_t preop;
+ uint8_t opcode;
+};
+
struct flashchip {
const char *vendor;
const char *name;
@@ -76,6 +82,8 @@ struct flashchip {
int (*write) (struct flashchip *flash, uint8_t *buf);
int (*read) (struct flashchip *flash, uint8_t *buf);
+ struct preop_opcode_pair *preop_opcode_pairs;
+
/* Some flash devices have an additional register space. */
volatile uint8_t *virtual_memory;
volatile uint8_t *virtual_registers;
diff --git a/util/flashrom/ichspi.c b/util/flashrom/ichspi.c
index 5806ba68d9..cbc81b02f8 100644
--- a/util/flashrom/ichspi.c
+++ b/util/flashrom/ichspi.c
@@ -101,6 +101,9 @@
#define ICH7_REG_OPTYPE 0x56 /* 16 Bits */
#define ICH7_REG_OPMENU 0x58 /* 64 Bits */
+/* ICH SPI configuration lock-down. May be set during chipset enabling. */
+int ichspi_lock = 0;
+
typedef struct _OPCODE {
uint8_t opcode; //This commands spi opcode
uint8_t spi_type; //This commands spi type
@@ -147,7 +150,11 @@ static inline uint16_t REGREAD16(int X)
#define REGWRITE8(X,Y) (*(uint8_t *)((uint8_t *)spibar+X)=Y)
/* Common SPI functions */
+static inline int find_opcode(OPCODES *op, uint8_t opcode);
+static inline int find_preop(OPCODES *op, uint8_t preop);
+static int generate_opcodes(struct flashchip * flash, OPCODES * op);
static int program_opcodes(OPCODES * op);
+int ich_check_opcodes(struct flashchip * flash);
static int run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data);
static int ich_spi_read_page(struct flashchip *flash, uint8_t * buf,
@@ -171,6 +178,98 @@ OPCODES O_ST_M25P = {
}
};
+OPCODES O_EXISTING = {};
+
+static inline int find_opcode(OPCODES *op, uint8_t opcode)
+{
+ int a;
+
+ for (a = 0; a < 8; a++) {
+ if (op->opcode[a].opcode == opcode)
+ return a;
+ }
+
+ return -1;
+}
+
+static inline int find_preop(OPCODES *op, uint8_t preop)
+{
+ int a;
+
+ for (a = 0; a < 2; a++) {
+ if (op->preop[a] == preop)
+ return a;
+ }
+
+ return -1;
+}
+
+static int generate_opcodes(struct flashchip * flash, OPCODES * op)
+{
+ int a, b, i;
+ uint16_t preop, optype;
+ uint32_t opmenu[2];
+ struct preop_opcode_pair *pair;
+
+ if (op == NULL) {
+ printf_debug("\n%s: null OPCODES pointer!\n", __FUNCTION__);
+ return -1;
+ }
+
+ switch (flashbus) {
+ case BUS_TYPE_ICH7_SPI:
+ case BUS_TYPE_VIA_SPI:
+ preop = REGREAD16(ICH7_REG_PREOP);
+ optype = REGREAD16(ICH7_REG_OPTYPE);
+ opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
+ opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
+ break;
+ case BUS_TYPE_ICH9_SPI:
+ preop = REGREAD16(ICH9_REG_PREOP);
+ optype = REGREAD16(ICH9_REG_OPTYPE);
+ opmenu[0] = REGREAD32(ICH9_REG_OPMENU);
+ opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4);
+ break;
+ default:
+ printf_debug("%s: unsupported chipset\n", __FUNCTION__);
+ return -1;
+ }
+
+ op->preop[0] = (uint8_t) preop;
+ op->preop[1] = (uint8_t) (preop >> 8);
+
+ for (a = 0; a < 8; a++) {
+ op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
+ optype >>= 2;
+ }
+
+ for (a = 0; a < 4; a++) {
+ op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
+ opmenu[0] >>= 8;
+ }
+
+ for (a = 4; a < 8; a++) {
+ op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
+ opmenu[1] >>= 8;
+ }
+
+ /* atomic (link opcode with required pre-op) */
+ for (a = 4; a < 8; a++)
+ op->opcode[a].atomic = 0;
+
+ pair = flash->preop_opcode_pairs;
+ if (pair) {
+ for (i = 0; pair[i].opcode; i++) {
+ a = find_opcode(op, pair[i].opcode);
+ b = find_preop(op, pair[i].preop);
+ if ((a != -1) && (b != -1))
+ op->opcode[a].atomic = (uint8_t) ++b;
+ }
+ }
+
+ return 0;
+}
+
int program_opcodes(OPCODES * op)
{
uint8_t a;
@@ -224,6 +323,41 @@ int program_opcodes(OPCODES * op)
return 0;
}
+/* This function generates OPCODES from or programs OPCODES to the chipset
+ * according to its SPI configuration lock.
+ *
+ * It should be called in the ICH7/ICH9/VIA part of each operation driver(i.e.
+ * probe, read, erase, write, etc.) before any command is sent.
+ */
+int ich_check_opcodes(struct flashchip * flash)
+{
+ int rc = 0;
+ OPCODES *curopcodes_done;
+
+ if (curopcodes)
+ return 0;
+
+ if (ichspi_lock) {
+ printf_debug("Generating OPCODES... ");
+ curopcodes_done = &O_EXISTING;
+ rc = generate_opcodes(flash, curopcodes_done);
+ } else {
+ printf_debug("Programming OPCODES... ");
+ curopcodes_done = &O_ST_M25P;
+ rc = program_opcodes(curopcodes_done);
+ }
+
+ if (rc) {
+ curopcodes = NULL;
+ printf_debug("failed\n");
+ return 1;
+ } else {
+ curopcodes = curopcodes_done;
+ printf_debug("done\n");
+ return 0;
+ }
+}
+
static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data, int maxdata)
{