From 657437e1ceeea45f91e8c51d98a8f3ffae9cf89a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Feb 2020 09:04:40 -0700 Subject: [PATCH] Faster flashing with SMFI (#32) * WIP: support for new flashing API * Add SPI flashing support to tool * Add timeouts when flashing with ectool * Test SPI reading * Use chunks for SPI commands * Sanity test of flash size * Read rom in sectors * Relocate memmap region, remove PMC3 * Use ectool to flash * Remove debugging of spi command * Fix flashing over smfi --- ecflash | 2 +- src/board/system76/darp5/board.mk | 12 +- src/board/system76/darp5/pmc.c | 7 - src/board/system76/darp5/pnp.c | 4 - .../darp5/scratch/include/scratch/pmc.h | 53 ------ src/board/system76/darp5/scratch/main.c | 126 +------------ src/board/system76/darp5/scratch/pmc.c | 23 --- src/board/system76/darp5/scratch/scratch.mk | 4 + src/board/system76/darp5/scratch/stdio.c | 9 + src/board/system76/darp5/smfi.c | 141 +++++++++++---- src/board/system76/galp3-c/board.mk | 12 +- src/board/system76/galp3-c/pmc.c | 7 - src/board/system76/galp3-c/pnp.c | 4 - .../galp3-c/scratch/include/scratch/pmc.h | 53 ------ src/board/system76/galp3-c/scratch/main.c | 126 +------------ src/board/system76/galp3-c/scratch/pmc.c | 23 --- src/board/system76/galp3-c/scratch/scratch.mk | 4 + src/board/system76/galp3-c/scratch/stdio.c | 9 + src/board/system76/galp3-c/smfi.c | 141 +++++++++++---- src/board/system76/lemp9/board.mk | 12 +- src/board/system76/lemp9/pmc.c | 7 - src/board/system76/lemp9/pnp.c | 4 - .../lemp9/scratch/include/scratch/pmc.h | 53 ------ src/board/system76/lemp9/scratch/main.c | 126 +------------ src/board/system76/lemp9/scratch/pmc.c | 23 --- src/board/system76/lemp9/scratch/scratch.mk | 4 + src/board/system76/lemp9/scratch/stdio.c | 9 + src/board/system76/lemp9/smfi.c | 141 +++++++++++---- src/common/include/common/command.h | 39 +++++ tool/src/ec.rs | 150 ++++++++++++---- tool/src/error.rs | 2 + tool/src/lib.rs | 3 + tool/src/main.rs | 119 ++++++++++++- tool/src/spi.rs | 165 ++++++++++++++++++ 34 files changed, 826 insertions(+), 791 deletions(-) delete mode 100644 src/board/system76/darp5/scratch/include/scratch/pmc.h delete mode 100644 src/board/system76/darp5/scratch/pmc.c create mode 100644 src/board/system76/darp5/scratch/stdio.c delete mode 100644 src/board/system76/galp3-c/scratch/include/scratch/pmc.h delete mode 100644 src/board/system76/galp3-c/scratch/pmc.c create mode 100644 src/board/system76/galp3-c/scratch/stdio.c delete mode 100644 src/board/system76/lemp9/scratch/include/scratch/pmc.h delete mode 100644 src/board/system76/lemp9/scratch/pmc.c create mode 100644 src/board/system76/lemp9/scratch/stdio.c create mode 100644 src/common/include/common/command.h create mode 100644 tool/src/spi.rs diff --git a/ecflash b/ecflash index 945ec8d..fc3f098 160000 --- a/ecflash +++ b/ecflash @@ -1 +1 @@ -Subproject commit 945ec8d276edd78f26cd744624344e67549824ad +Subproject commit fc3f098fda1c1f0707ac2f339f1cb760ff7376bb diff --git a/src/board/system76/darp5/board.mk b/src/board/system76/darp5/board.mk index 3416bae..9d4c452 100644 --- a/src/board/system76/darp5/board.mk +++ b/src/board/system76/darp5/board.mk @@ -27,11 +27,15 @@ SCRATCH_OFFSET=1024 SCRATCH_SIZE=1024 CFLAGS+=-DSCRATCH_OFFSET=$(SCRATCH_OFFSET) -DSCRATCH_SIZE=$(SCRATCH_SIZE) +# Copy parameters to use when compiling scratch ROM +SCRATCH_INCLUDE=$(INCLUDE) +SCRATCH_CFLAGS=$(CFLAGS) + # Add scratch ROM source SCRATCH_DIR=$(BOARD_DIR)/scratch SCRATCH_SRC=$(wildcard $(SCRATCH_DIR)/*.c) -SCRATCH_INCLUDE=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk -SCRATCH_CFLAGS=-I$(SCRATCH_DIR)/include +SCRATCH_INCLUDE+=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk +SCRATCH_CFLAGS+=-I$(SCRATCH_DIR)/include -D__SCRATCH__ include $(SCRATCH_DIR)/scratch.mk # Include scratch header in main firmware @@ -43,8 +47,8 @@ console: sudo tool/target/release/system76_ectool console flash: $(BUILD)/ec.rom - cargo build --manifest-path ecflash/Cargo.toml --example isp --release - sudo ecflash/target/release/examples/isp --internal $< + cargo build --manifest-path tool/Cargo.toml --release + sudo tool/target/release/system76_ectool flash $< isp: $(BUILD)/ec.rom cargo build --manifest-path ecflash/Cargo.toml --example isp --release diff --git a/src/board/system76/darp5/pmc.c b/src/board/system76/darp5/pmc.c index 8387b6d..d60cd98 100644 --- a/src/board/system76/darp5/pmc.c +++ b/src/board/system76/darp5/pmc.c @@ -2,7 +2,6 @@ #include #include #include -#include #include void pmc_init(void) { @@ -102,12 +101,6 @@ void pmc_event(struct Pmc * pmc) { // Clear SCI queue pmc_sci_queue = 0; break; - - case 0xEC: - TRACE(" scratch rom\n"); - pmc_write(pmc, 0x76); - scratch_trampoline(); - break; } } else { TRACE("pmc data: %02X\n", data); diff --git a/src/board/system76/darp5/pnp.c b/src/board/system76/darp5/pnp.c index 6f9ab5b..8ab6cdb 100644 --- a/src/board/system76/darp5/pnp.c +++ b/src/board/system76/darp5/pnp.c @@ -28,10 +28,6 @@ void pnp_enable() { // Enable PMC1 pnp_write(0x07, 0x11); pnp_write(0x30, 0x01); - // - // Enable PMC3 - pnp_write(0x07, 0x17); - pnp_write(0x30, 0x01); // Enable KBC keyboard pnp_write(0x07, 0x06); diff --git a/src/board/system76/darp5/scratch/include/scratch/pmc.h b/src/board/system76/darp5/scratch/include/scratch/pmc.h deleted file mode 100644 index 4a23403..0000000 --- a/src/board/system76/darp5/scratch/include/scratch/pmc.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _EC_PMC_H -#define _EC_PMC_H - -#include -#include - -struct Pmc { - // Status register - volatile uint8_t * status; - // Data out register - volatile uint8_t * data_out; - // Data in register - volatile uint8_t * data_in; - // Control register - volatile uint8_t * control; -}; - -extern struct Pmc __code PMC_3; - -#define PMC_STS_OBF (1 << 0) -#define PMC_STS_IBF (1 << 1) -#define PMC_STS_CMD (1 << 3) - -uint8_t pmc_status(struct Pmc * pmc); -uint8_t pmc_read(struct Pmc * pmc); -bool pmc_write(struct Pmc * pmc, uint8_t data); - -volatile uint8_t __xdata __at(0x1500) PM1STS; -volatile uint8_t __xdata __at(0x1501) PM1DO; -volatile uint8_t __xdata __at(0x1504) PM1DI; -volatile uint8_t __xdata __at(0x1506) PM1CTL; - -volatile uint8_t __xdata __at(0x1510) PM2STS; -volatile uint8_t __xdata __at(0x1511) PM2DO; -volatile uint8_t __xdata __at(0x1514) PM2DI; -volatile uint8_t __xdata __at(0x1516) PM2CTL; - -volatile uint8_t __xdata __at(0x1520) PM3STS; -volatile uint8_t __xdata __at(0x1521) PM3DO; -volatile uint8_t __xdata __at(0x1522) PM3DI; -volatile uint8_t __xdata __at(0x1523) PM3CTL; - -volatile uint8_t __xdata __at(0x1530) PM4STS; -volatile uint8_t __xdata __at(0x1531) PM4DO; -volatile uint8_t __xdata __at(0x1532) PM4DI; -volatile uint8_t __xdata __at(0x1533) PM4CTL; - -volatile uint8_t __xdata __at(0x1540) PM5STS; -volatile uint8_t __xdata __at(0x1541) PM5DO; -volatile uint8_t __xdata __at(0x1542) PM5DI; -volatile uint8_t __xdata __at(0x1543) PM5CTL; - -#endif // _EC_PMC_H diff --git a/src/board/system76/darp5/scratch/main.c b/src/board/system76/darp5/scratch/main.c index 83db410..dffe493 100644 --- a/src/board/system76/darp5/scratch/main.c +++ b/src/board/system76/darp5/scratch/main.c @@ -1,130 +1,8 @@ -#include -#include - -#include - -volatile uint8_t __xdata __at(0x103B) ECINDAR0; -volatile uint8_t __xdata __at(0x103C) ECINDAR1; -volatile uint8_t __xdata __at(0x103D) ECINDAR2; -volatile uint8_t __xdata __at(0x103E) ECINDAR3; -volatile uint8_t __xdata __at(0x103F) ECINDDR; - -volatile uint8_t __xdata __at(0x1F01) ETWCFG; -volatile uint8_t __xdata __at(0x1F07) EWDKEYR; - -uint8_t acpi_read(uint8_t addr) { - uint8_t data = 0; - - switch (addr) { - case 4: - data = ECINDAR0; - break; - case 5: - data = ECINDAR1; - break; - case 6: - data = ECINDAR2; - break; - case 7: - data = ECINDAR3; - break; - case 8: - data = ECINDDR; - break; - } - - return data; -} - -void acpi_write(uint8_t addr, uint8_t data) { - switch (addr) { - case 4: - ECINDAR0 = data; - break; - case 5: - ECINDAR1 = data; - break; - case 6: - ECINDAR2 = data; - break; - case 7: - ECINDAR3 = data; - break; - case 8: - ECINDDR = data; - break; - } -} - -enum PmcState { - PMC_STATE_DEFAULT, - PMC_STATE_WRITE, - PMC_STATE_ACPI_READ, - PMC_STATE_ACPI_WRITE, - PMC_STATE_ACPI_WRITE_ADDR, -}; - -void pmc_event(struct Pmc * pmc) { - static enum PmcState state = PMC_STATE_DEFAULT; - static uint8_t state_data = 0; - - uint8_t sts = pmc_status(pmc); - - // Read command/data if available - if (sts & PMC_STS_IBF) { - uint8_t data = pmc_read(pmc); - if (sts & PMC_STS_CMD) { - state = PMC_STATE_DEFAULT; - switch (data) { - case 0x80: - state = PMC_STATE_ACPI_READ; - break; - case 0x81: - state = PMC_STATE_ACPI_WRITE; - break; - case 0xEC: - for (;;) { - // Attempt to trigger watchdog reset - ETWCFG |= (1 << 5); - EWDKEYR = 0; - } - break; - } - } else { - switch (state) { - case PMC_STATE_ACPI_READ: - state = PMC_STATE_WRITE; - state_data = acpi_read(data); - break; - case PMC_STATE_ACPI_WRITE: - state = PMC_STATE_ACPI_WRITE_ADDR; - state_data = data; - break; - case PMC_STATE_ACPI_WRITE_ADDR: - state = PMC_STATE_DEFAULT; - acpi_write(state_data, data); - break; - default: - state = PMC_STATE_DEFAULT; - break; - } - } - } - - // Write data if possible - if (!(sts & PMC_STS_OBF)) { - switch (state) { - case PMC_STATE_WRITE: - state = PMC_STATE_DEFAULT; - pmc_write(pmc, state_data); - break; - } - } -} +#include // Main program while running in scratch ROM void main(void) { for (;;) { - pmc_event(&PMC_3); + smfi_event(); } } diff --git a/src/board/system76/darp5/scratch/pmc.c b/src/board/system76/darp5/scratch/pmc.c deleted file mode 100644 index 2cd653a..0000000 --- a/src/board/system76/darp5/scratch/pmc.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#define PMC(NUM) { \ - .status = &PM ## NUM ## STS, \ - .data_out = &PM ## NUM ## DO, \ - .data_in = &PM ## NUM ## DI, \ - .control = &PM ## NUM ## CTL, \ -} - -struct Pmc __code PMC_3 = PMC(3); - -uint8_t pmc_status(struct Pmc * pmc) { - return *(pmc->status); -} - -uint8_t pmc_read(struct Pmc * pmc) { - return *(pmc->data_in); -} - -bool pmc_write(struct Pmc * pmc, uint8_t data) { - *(pmc->data_out) = data; - return true; -} diff --git a/src/board/system76/darp5/scratch/scratch.mk b/src/board/system76/darp5/scratch/scratch.mk index 8f61c65..08610d3 100644 --- a/src/board/system76/darp5/scratch/scratch.mk +++ b/src/board/system76/darp5/scratch/scratch.mk @@ -1,3 +1,7 @@ +SCRATCH_SRC+=\ + $(COMMON_DIR)/version.c \ + $(BOARD_DIR)/smfi.c + SCRATCH_BUILD=$(BUILD)/scratch SCRATCH_OBJ=$(patsubst src/%.c,$(SCRATCH_BUILD)/%.rel,$(SCRATCH_SRC)) SCRATCH_CC=\ diff --git a/src/board/system76/darp5/scratch/stdio.c b/src/board/system76/darp5/scratch/stdio.c new file mode 100644 index 0000000..62541dd --- /dev/null +++ b/src/board/system76/darp5/scratch/stdio.c @@ -0,0 +1,9 @@ +#include + +#include + +int putchar(int c) { + unsigned char byte = (unsigned char)c; + smfi_debug(byte); + return (int)byte; +} diff --git a/src/board/system76/darp5/smfi.c b/src/board/system76/darp5/smfi.c index ff95768..04387a0 100644 --- a/src/board/system76/darp5/smfi.c +++ b/src/board/system76/darp5/smfi.c @@ -2,7 +2,11 @@ #include #include +#ifndef __SCRATCH__ + #include +#endif #include +#include #include #include @@ -19,84 +23,149 @@ volatile uint8_t __xdata __at(0x105D) HRAMW0AAS; // Host RAM window 1 access allow size volatile uint8_t __xdata __at(0x105E) HRAMW1AAS; -static volatile uint8_t __xdata __at(0xC00) smfi_cmd[256]; -static volatile uint8_t __xdata __at(0xD00) smfi_dbg[256]; +volatile uint8_t __xdata __at(0x103B) ECINDAR0; +volatile uint8_t __xdata __at(0x103C) ECINDAR1; +volatile uint8_t __xdata __at(0x103D) ECINDAR2; +volatile uint8_t __xdata __at(0x103E) ECINDAR3; +volatile uint8_t __xdata __at(0x103F) ECINDDR; -enum SmfiCmd { - SMFI_CMD_NONE = 0, - SMFI_CMD_PROBE = 1, - SMFI_CMD_BOARD = 2, - SMFI_CMD_VERSION = 3, - SMFI_CMD_DEBUG = 4, - //TODO -}; +volatile uint8_t __xdata __at(0x1F01) ETWCFG; +volatile uint8_t __xdata __at(0x1F07) EWDKEYR; -enum SmfiRes { - SMFI_RES_OK = 0, - SMFI_RES_ERR = 1, - //TODO -}; +static volatile uint8_t __xdata __at(0xE00) smfi_cmd[256]; +static volatile uint8_t __xdata __at(0xF00) smfi_dbg[256]; void smfi_init(void) { int i; // Clear command region - for (i = 0; i < ARRAY_SIZE(smfi_cmd); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_cmd); i++) { smfi_cmd[i] = 0x00; } + // Clear host command last + smfi_cmd[0] = 0x00; // Clear debug region - for (i = 0; i < ARRAY_SIZE(smfi_dbg); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_dbg); i++) { smfi_dbg[i] = 0x00; } + // Clear tail last + smfi_dbg[0] = 0x00; - // H2RAM window 0 address 0xC00 - 0xCFF, read/write - HRAMW0BA = 0xC0; + // H2RAM window 0 address 0xE00 - 0xEFF, read/write + HRAMW0BA = 0xE0; HRAMW0AAS = 0x04; - // H2RAM window 1 address 0xD00 - 0xDFF, read/write - HRAMW1BA = 0xD0; + // H2RAM window 1 address 0xF00 - 0xFFF, read/write + HRAMW1BA = 0xF0; HRAMW1AAS = 0x04; // Enable H2RAM window 0 and 1 using LPC I/O HRAMWC |= 0x13; } -void smfi_event(void) { +static enum Result cmd_debug(void) { int i; - if (smfi_cmd[0]) { - // Default to success - smfi_cmd[1] = SMFI_RES_OK; + for (i = 2; i < ARRAY_SIZE(smfi_cmd); i++) { + uint8_t b = smfi_cmd[i]; + if (b == 0) break; + putchar(b); + } + return RES_OK; +} + +static enum Result cmd_spi(void) { + uint8_t flags = smfi_cmd[2]; + +#ifdef __SCRATCH__ + int len = (int)smfi_cmd[3]; + + // Enable chip (internal) + ECINDAR3 = 0x7F; + ECINDAR2 = 0xFF; + ECINDAR1 = 0xFD; + ECINDAR0 = 0x00; + + // Read or write len bytes + int i; + for (i = 0; (i < len) && ((i + 4) < ARRAY_SIZE(smfi_cmd)); i++) { + if (flags & CMD_SPI_FLAG_READ) { + smfi_cmd[i + 4] = ECINDDR; + } else { + ECINDDR = smfi_cmd[i + 4]; + } + } + + // Set actually read/written count + smfi_cmd[3] = (uint8_t)i; + + if (flags & CMD_SPI_FLAG_DISABLE) { + // Disable chip + ECINDAR1 = 0xFE; + ECINDDR = 0; + } + + return RES_OK; +#else + if (flags & CMD_SPI_FLAG_SCRATCH) { + scratch_trampoline(); + } + + // Cannot use SPI bus while running EC from SPI, or trampoline failed + return RES_ERR; +#endif +} + +static enum Result cmd_reset(void) { + // Attempt to trigger watchdog reset + ETWCFG |= (1 << 5); + EWDKEYR = 0; + + // Failed if it got this far + return RES_ERR; +} + +void smfi_event(void) { + if (smfi_cmd[0]) { switch (smfi_cmd[0]) { - case SMFI_CMD_PROBE: + case CMD_PROBE: // Signature smfi_cmd[2] = 0x76; smfi_cmd[3] = 0xEC; // Version smfi_cmd[4] = 0x01; + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_BOARD: + case CMD_BOARD: strncpy(&smfi_cmd[2], board(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_VERSION: + case CMD_VERSION: strncpy(&smfi_cmd[2], version(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; + break; + case CMD_DEBUG: + smfi_cmd[1] = cmd_debug(); + break; + case CMD_SPI: + smfi_cmd[1] = cmd_spi(); + break; + case CMD_RESET: + smfi_cmd[1] = cmd_reset(); break; - case SMFI_CMD_DEBUG: - for (i = 2; i < ARRAY_SIZE(smfi_cmd) - 2; i++) { - uint8_t b = smfi_cmd[i]; - if (b == 0) break; - putchar(b); - } default: // Command not found - smfi_cmd[1] = SMFI_RES_ERR; + smfi_cmd[1] = RES_ERR; break; } // Mark command as finished - smfi_cmd[0] = SMFI_CMD_NONE; + smfi_cmd[0] = CMD_NONE; } } diff --git a/src/board/system76/galp3-c/board.mk b/src/board/system76/galp3-c/board.mk index 70b9467..c215c93 100644 --- a/src/board/system76/galp3-c/board.mk +++ b/src/board/system76/galp3-c/board.mk @@ -24,11 +24,15 @@ SCRATCH_OFFSET=1024 SCRATCH_SIZE=1024 CFLAGS+=-DSCRATCH_OFFSET=$(SCRATCH_OFFSET) -DSCRATCH_SIZE=$(SCRATCH_SIZE) +# Copy parameters to use when compiling scratch ROM +SCRATCH_INCLUDE=$(INCLUDE) +SCRATCH_CFLAGS=$(CFLAGS) + # Add scratch ROM source SCRATCH_DIR=$(BOARD_DIR)/scratch SCRATCH_SRC=$(wildcard $(SCRATCH_DIR)/*.c) -SCRATCH_INCLUDE=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk -SCRATCH_CFLAGS=-I$(SCRATCH_DIR)/include +SCRATCH_INCLUDE+=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk +SCRATCH_CFLAGS+=-I$(SCRATCH_DIR)/include -D__SCRATCH__ include $(SCRATCH_DIR)/scratch.mk # Include scratch header in main firmware @@ -40,8 +44,8 @@ console: sudo tool/target/release/system76_ectool console flash: $(BUILD)/ec.rom - cargo build --manifest-path ecflash/Cargo.toml --example isp --release - sudo ecflash/target/release/examples/isp --internal $< + cargo build --manifest-path tool/Cargo.toml --release + sudo tool/target/release/system76_ectool flash $< isp: $(BUILD)/ec.rom cargo build --manifest-path ecflash/Cargo.toml --example isp --release diff --git a/src/board/system76/galp3-c/pmc.c b/src/board/system76/galp3-c/pmc.c index 8387b6d..d60cd98 100644 --- a/src/board/system76/galp3-c/pmc.c +++ b/src/board/system76/galp3-c/pmc.c @@ -2,7 +2,6 @@ #include #include #include -#include #include void pmc_init(void) { @@ -102,12 +101,6 @@ void pmc_event(struct Pmc * pmc) { // Clear SCI queue pmc_sci_queue = 0; break; - - case 0xEC: - TRACE(" scratch rom\n"); - pmc_write(pmc, 0x76); - scratch_trampoline(); - break; } } else { TRACE("pmc data: %02X\n", data); diff --git a/src/board/system76/galp3-c/pnp.c b/src/board/system76/galp3-c/pnp.c index 6f9ab5b..8ab6cdb 100644 --- a/src/board/system76/galp3-c/pnp.c +++ b/src/board/system76/galp3-c/pnp.c @@ -28,10 +28,6 @@ void pnp_enable() { // Enable PMC1 pnp_write(0x07, 0x11); pnp_write(0x30, 0x01); - // - // Enable PMC3 - pnp_write(0x07, 0x17); - pnp_write(0x30, 0x01); // Enable KBC keyboard pnp_write(0x07, 0x06); diff --git a/src/board/system76/galp3-c/scratch/include/scratch/pmc.h b/src/board/system76/galp3-c/scratch/include/scratch/pmc.h deleted file mode 100644 index 4a23403..0000000 --- a/src/board/system76/galp3-c/scratch/include/scratch/pmc.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _EC_PMC_H -#define _EC_PMC_H - -#include -#include - -struct Pmc { - // Status register - volatile uint8_t * status; - // Data out register - volatile uint8_t * data_out; - // Data in register - volatile uint8_t * data_in; - // Control register - volatile uint8_t * control; -}; - -extern struct Pmc __code PMC_3; - -#define PMC_STS_OBF (1 << 0) -#define PMC_STS_IBF (1 << 1) -#define PMC_STS_CMD (1 << 3) - -uint8_t pmc_status(struct Pmc * pmc); -uint8_t pmc_read(struct Pmc * pmc); -bool pmc_write(struct Pmc * pmc, uint8_t data); - -volatile uint8_t __xdata __at(0x1500) PM1STS; -volatile uint8_t __xdata __at(0x1501) PM1DO; -volatile uint8_t __xdata __at(0x1504) PM1DI; -volatile uint8_t __xdata __at(0x1506) PM1CTL; - -volatile uint8_t __xdata __at(0x1510) PM2STS; -volatile uint8_t __xdata __at(0x1511) PM2DO; -volatile uint8_t __xdata __at(0x1514) PM2DI; -volatile uint8_t __xdata __at(0x1516) PM2CTL; - -volatile uint8_t __xdata __at(0x1520) PM3STS; -volatile uint8_t __xdata __at(0x1521) PM3DO; -volatile uint8_t __xdata __at(0x1522) PM3DI; -volatile uint8_t __xdata __at(0x1523) PM3CTL; - -volatile uint8_t __xdata __at(0x1530) PM4STS; -volatile uint8_t __xdata __at(0x1531) PM4DO; -volatile uint8_t __xdata __at(0x1532) PM4DI; -volatile uint8_t __xdata __at(0x1533) PM4CTL; - -volatile uint8_t __xdata __at(0x1540) PM5STS; -volatile uint8_t __xdata __at(0x1541) PM5DO; -volatile uint8_t __xdata __at(0x1542) PM5DI; -volatile uint8_t __xdata __at(0x1543) PM5CTL; - -#endif // _EC_PMC_H diff --git a/src/board/system76/galp3-c/scratch/main.c b/src/board/system76/galp3-c/scratch/main.c index 83db410..dffe493 100644 --- a/src/board/system76/galp3-c/scratch/main.c +++ b/src/board/system76/galp3-c/scratch/main.c @@ -1,130 +1,8 @@ -#include -#include - -#include - -volatile uint8_t __xdata __at(0x103B) ECINDAR0; -volatile uint8_t __xdata __at(0x103C) ECINDAR1; -volatile uint8_t __xdata __at(0x103D) ECINDAR2; -volatile uint8_t __xdata __at(0x103E) ECINDAR3; -volatile uint8_t __xdata __at(0x103F) ECINDDR; - -volatile uint8_t __xdata __at(0x1F01) ETWCFG; -volatile uint8_t __xdata __at(0x1F07) EWDKEYR; - -uint8_t acpi_read(uint8_t addr) { - uint8_t data = 0; - - switch (addr) { - case 4: - data = ECINDAR0; - break; - case 5: - data = ECINDAR1; - break; - case 6: - data = ECINDAR2; - break; - case 7: - data = ECINDAR3; - break; - case 8: - data = ECINDDR; - break; - } - - return data; -} - -void acpi_write(uint8_t addr, uint8_t data) { - switch (addr) { - case 4: - ECINDAR0 = data; - break; - case 5: - ECINDAR1 = data; - break; - case 6: - ECINDAR2 = data; - break; - case 7: - ECINDAR3 = data; - break; - case 8: - ECINDDR = data; - break; - } -} - -enum PmcState { - PMC_STATE_DEFAULT, - PMC_STATE_WRITE, - PMC_STATE_ACPI_READ, - PMC_STATE_ACPI_WRITE, - PMC_STATE_ACPI_WRITE_ADDR, -}; - -void pmc_event(struct Pmc * pmc) { - static enum PmcState state = PMC_STATE_DEFAULT; - static uint8_t state_data = 0; - - uint8_t sts = pmc_status(pmc); - - // Read command/data if available - if (sts & PMC_STS_IBF) { - uint8_t data = pmc_read(pmc); - if (sts & PMC_STS_CMD) { - state = PMC_STATE_DEFAULT; - switch (data) { - case 0x80: - state = PMC_STATE_ACPI_READ; - break; - case 0x81: - state = PMC_STATE_ACPI_WRITE; - break; - case 0xEC: - for (;;) { - // Attempt to trigger watchdog reset - ETWCFG |= (1 << 5); - EWDKEYR = 0; - } - break; - } - } else { - switch (state) { - case PMC_STATE_ACPI_READ: - state = PMC_STATE_WRITE; - state_data = acpi_read(data); - break; - case PMC_STATE_ACPI_WRITE: - state = PMC_STATE_ACPI_WRITE_ADDR; - state_data = data; - break; - case PMC_STATE_ACPI_WRITE_ADDR: - state = PMC_STATE_DEFAULT; - acpi_write(state_data, data); - break; - default: - state = PMC_STATE_DEFAULT; - break; - } - } - } - - // Write data if possible - if (!(sts & PMC_STS_OBF)) { - switch (state) { - case PMC_STATE_WRITE: - state = PMC_STATE_DEFAULT; - pmc_write(pmc, state_data); - break; - } - } -} +#include // Main program while running in scratch ROM void main(void) { for (;;) { - pmc_event(&PMC_3); + smfi_event(); } } diff --git a/src/board/system76/galp3-c/scratch/pmc.c b/src/board/system76/galp3-c/scratch/pmc.c deleted file mode 100644 index 2cd653a..0000000 --- a/src/board/system76/galp3-c/scratch/pmc.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#define PMC(NUM) { \ - .status = &PM ## NUM ## STS, \ - .data_out = &PM ## NUM ## DO, \ - .data_in = &PM ## NUM ## DI, \ - .control = &PM ## NUM ## CTL, \ -} - -struct Pmc __code PMC_3 = PMC(3); - -uint8_t pmc_status(struct Pmc * pmc) { - return *(pmc->status); -} - -uint8_t pmc_read(struct Pmc * pmc) { - return *(pmc->data_in); -} - -bool pmc_write(struct Pmc * pmc, uint8_t data) { - *(pmc->data_out) = data; - return true; -} diff --git a/src/board/system76/galp3-c/scratch/scratch.mk b/src/board/system76/galp3-c/scratch/scratch.mk index 8f61c65..08610d3 100644 --- a/src/board/system76/galp3-c/scratch/scratch.mk +++ b/src/board/system76/galp3-c/scratch/scratch.mk @@ -1,3 +1,7 @@ +SCRATCH_SRC+=\ + $(COMMON_DIR)/version.c \ + $(BOARD_DIR)/smfi.c + SCRATCH_BUILD=$(BUILD)/scratch SCRATCH_OBJ=$(patsubst src/%.c,$(SCRATCH_BUILD)/%.rel,$(SCRATCH_SRC)) SCRATCH_CC=\ diff --git a/src/board/system76/galp3-c/scratch/stdio.c b/src/board/system76/galp3-c/scratch/stdio.c new file mode 100644 index 0000000..62541dd --- /dev/null +++ b/src/board/system76/galp3-c/scratch/stdio.c @@ -0,0 +1,9 @@ +#include + +#include + +int putchar(int c) { + unsigned char byte = (unsigned char)c; + smfi_debug(byte); + return (int)byte; +} diff --git a/src/board/system76/galp3-c/smfi.c b/src/board/system76/galp3-c/smfi.c index ff95768..38a67e3 100644 --- a/src/board/system76/galp3-c/smfi.c +++ b/src/board/system76/galp3-c/smfi.c @@ -2,7 +2,11 @@ #include #include +#ifndef __SCRATCH__ + #include +#endif #include +#include #include #include @@ -19,84 +23,149 @@ volatile uint8_t __xdata __at(0x105D) HRAMW0AAS; // Host RAM window 1 access allow size volatile uint8_t __xdata __at(0x105E) HRAMW1AAS; -static volatile uint8_t __xdata __at(0xC00) smfi_cmd[256]; -static volatile uint8_t __xdata __at(0xD00) smfi_dbg[256]; +volatile uint8_t __xdata __at(0x103B) ECINDAR0; +volatile uint8_t __xdata __at(0x103C) ECINDAR1; +volatile uint8_t __xdata __at(0x103D) ECINDAR2; +volatile uint8_t __xdata __at(0x103E) ECINDAR3; +volatile uint8_t __xdata __at(0x103F) ECINDDR; -enum SmfiCmd { - SMFI_CMD_NONE = 0, - SMFI_CMD_PROBE = 1, - SMFI_CMD_BOARD = 2, - SMFI_CMD_VERSION = 3, - SMFI_CMD_DEBUG = 4, - //TODO -}; +volatile uint8_t __xdata __at(0x1F01) ETWCFG; +volatile uint8_t __xdata __at(0x1F07) EWDKEYR; -enum SmfiRes { - SMFI_RES_OK = 0, - SMFI_RES_ERR = 1, - //TODO -}; +static volatile uint8_t __xdata __at(0xE00) smfi_cmd[256]; +static volatile uint8_t __xdata __at(0xF00) smfi_dbg[256]; void smfi_init(void) { int i; // Clear command region - for (i = 0; i < ARRAY_SIZE(smfi_cmd); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_cmd); i++) { smfi_cmd[i] = 0x00; } + // Clear host command last + smfi_cmd[0] = 0x00; // Clear debug region - for (i = 0; i < ARRAY_SIZE(smfi_dbg); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_dbg); i++) { smfi_dbg[i] = 0x00; } + // Clear tail last + smfi_dbg[0] = 0x00; - // H2RAM window 0 address 0xC00 - 0xCFF, read/write - HRAMW0BA = 0xC0; + // H2RAM window 0 address 0xE00 - 0xEFF, read/write + HRAMW0BA = 0xE0; HRAMW0AAS = 0x04; - // H2RAM window 1 address 0xD00 - 0xDFF, read/write - HRAMW1BA = 0xD0; + // H2RAM window 1 address 0xF00 - 0xFFF, read/write + HRAMW1BA = 0xF0; HRAMW1AAS = 0x04; // Enable H2RAM window 0 and 1 using LPC I/O HRAMWC |= 0x13; } -void smfi_event(void) { +static enum Result cmd_debug(void) { int i; - if (smfi_cmd[0]) { - // Default to success - smfi_cmd[1] = SMFI_RES_OK; + for (i = 2; i < ARRAY_SIZE(smfi_cmd); i++) { + uint8_t b = smfi_cmd[i]; + if (b == 0) break; + putchar(b); + } + return RES_OK; +} + +static enum Result cmd_spi(void) { + uint8_t flags = smfi_cmd[2]; + +#ifdef __SCRATCH__ + uint8_t len = smfi_cmd[3]; + + // Enable chip (internal) + ECINDAR3 = 0x7F; + ECINDAR2 = 0xFF; + ECINDAR1 = 0xFD; + ECINDAR0 = 0x00; + + // Read or write len bytes + uint8_t i; + for (i = 0; (i < len) && ((i + 4) < ARRAY_SIZE(smfi_cmd)); i++) { + if (flags & CMD_SPI_FLAG_READ) { + smfi_cmd[i + 4] = ECINDDR; + } else { + ECINDDR = smfi_cmd[i + 4]; + } + } + + // Set actually read/written count + smfi_cmd[3] = i; + + if (flags & CMD_SPI_FLAG_DISABLE) { + // Disable chip + ECINDAR1 = 0xFE; + ECINDDR = 0; + } + + return RES_OK; +#else + if (flags & CMD_SPI_FLAG_SCRATCH) { + scratch_trampoline(); + } + + // Cannot use SPI bus while running EC from SPI, or trampoline failed + return RES_ERR; +#endif +} + +static enum Result cmd_reset(void) { + // Attempt to trigger watchdog reset + ETWCFG |= (1 << 5); + EWDKEYR = 0; + + // Failed if it got this far + return RES_ERR; +} + +void smfi_event(void) { + if (smfi_cmd[0]) { switch (smfi_cmd[0]) { - case SMFI_CMD_PROBE: + case CMD_PROBE: // Signature smfi_cmd[2] = 0x76; smfi_cmd[3] = 0xEC; // Version smfi_cmd[4] = 0x01; + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_BOARD: + case CMD_BOARD: strncpy(&smfi_cmd[2], board(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_VERSION: + case CMD_VERSION: strncpy(&smfi_cmd[2], version(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; + break; + case CMD_DEBUG: + smfi_cmd[1] = cmd_debug(); + break; + case CMD_SPI: + smfi_cmd[1] = cmd_spi(); + break; + case CMD_RESET: + smfi_cmd[1] = cmd_reset(); break; - case SMFI_CMD_DEBUG: - for (i = 2; i < ARRAY_SIZE(smfi_cmd) - 2; i++) { - uint8_t b = smfi_cmd[i]; - if (b == 0) break; - putchar(b); - } default: // Command not found - smfi_cmd[1] = SMFI_RES_ERR; + smfi_cmd[1] = RES_ERR; break; } // Mark command as finished - smfi_cmd[0] = SMFI_CMD_NONE; + smfi_cmd[0] = CMD_NONE; } } diff --git a/src/board/system76/lemp9/board.mk b/src/board/system76/lemp9/board.mk index 7a8f649..5ed6fcf 100644 --- a/src/board/system76/lemp9/board.mk +++ b/src/board/system76/lemp9/board.mk @@ -27,11 +27,15 @@ SCRATCH_OFFSET=1024 SCRATCH_SIZE=1024 CFLAGS+=-DSCRATCH_OFFSET=$(SCRATCH_OFFSET) -DSCRATCH_SIZE=$(SCRATCH_SIZE) +# Copy parameters to use when compiling scratch ROM +SCRATCH_INCLUDE=$(INCLUDE) +SCRATCH_CFLAGS=$(CFLAGS) + # Add scratch ROM source SCRATCH_DIR=$(BOARD_DIR)/scratch SCRATCH_SRC=$(wildcard $(SCRATCH_DIR)/*.c) -SCRATCH_INCLUDE=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk -SCRATCH_CFLAGS=-I$(SCRATCH_DIR)/include +SCRATCH_INCLUDE+=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk +SCRATCH_CFLAGS+=-I$(SCRATCH_DIR)/include -D__SCRATCH__ include $(SCRATCH_DIR)/scratch.mk # Include scratch header in main firmware @@ -43,8 +47,8 @@ console: sudo tool/target/release/system76_ectool console flash: $(BUILD)/ec.rom - cargo build --manifest-path ecflash/Cargo.toml --example isp --release - sudo ecflash/target/release/examples/isp --internal $< + cargo build --manifest-path tool/Cargo.toml --release + sudo tool/target/release/system76_ectool flash $< isp: $(BUILD)/ec.rom cargo build --manifest-path ecflash/Cargo.toml --example isp --release diff --git a/src/board/system76/lemp9/pmc.c b/src/board/system76/lemp9/pmc.c index 8387b6d..d60cd98 100644 --- a/src/board/system76/lemp9/pmc.c +++ b/src/board/system76/lemp9/pmc.c @@ -2,7 +2,6 @@ #include #include #include -#include #include void pmc_init(void) { @@ -102,12 +101,6 @@ void pmc_event(struct Pmc * pmc) { // Clear SCI queue pmc_sci_queue = 0; break; - - case 0xEC: - TRACE(" scratch rom\n"); - pmc_write(pmc, 0x76); - scratch_trampoline(); - break; } } else { TRACE("pmc data: %02X\n", data); diff --git a/src/board/system76/lemp9/pnp.c b/src/board/system76/lemp9/pnp.c index 6f9ab5b..8ab6cdb 100644 --- a/src/board/system76/lemp9/pnp.c +++ b/src/board/system76/lemp9/pnp.c @@ -28,10 +28,6 @@ void pnp_enable() { // Enable PMC1 pnp_write(0x07, 0x11); pnp_write(0x30, 0x01); - // - // Enable PMC3 - pnp_write(0x07, 0x17); - pnp_write(0x30, 0x01); // Enable KBC keyboard pnp_write(0x07, 0x06); diff --git a/src/board/system76/lemp9/scratch/include/scratch/pmc.h b/src/board/system76/lemp9/scratch/include/scratch/pmc.h deleted file mode 100644 index 4a23403..0000000 --- a/src/board/system76/lemp9/scratch/include/scratch/pmc.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _EC_PMC_H -#define _EC_PMC_H - -#include -#include - -struct Pmc { - // Status register - volatile uint8_t * status; - // Data out register - volatile uint8_t * data_out; - // Data in register - volatile uint8_t * data_in; - // Control register - volatile uint8_t * control; -}; - -extern struct Pmc __code PMC_3; - -#define PMC_STS_OBF (1 << 0) -#define PMC_STS_IBF (1 << 1) -#define PMC_STS_CMD (1 << 3) - -uint8_t pmc_status(struct Pmc * pmc); -uint8_t pmc_read(struct Pmc * pmc); -bool pmc_write(struct Pmc * pmc, uint8_t data); - -volatile uint8_t __xdata __at(0x1500) PM1STS; -volatile uint8_t __xdata __at(0x1501) PM1DO; -volatile uint8_t __xdata __at(0x1504) PM1DI; -volatile uint8_t __xdata __at(0x1506) PM1CTL; - -volatile uint8_t __xdata __at(0x1510) PM2STS; -volatile uint8_t __xdata __at(0x1511) PM2DO; -volatile uint8_t __xdata __at(0x1514) PM2DI; -volatile uint8_t __xdata __at(0x1516) PM2CTL; - -volatile uint8_t __xdata __at(0x1520) PM3STS; -volatile uint8_t __xdata __at(0x1521) PM3DO; -volatile uint8_t __xdata __at(0x1522) PM3DI; -volatile uint8_t __xdata __at(0x1523) PM3CTL; - -volatile uint8_t __xdata __at(0x1530) PM4STS; -volatile uint8_t __xdata __at(0x1531) PM4DO; -volatile uint8_t __xdata __at(0x1532) PM4DI; -volatile uint8_t __xdata __at(0x1533) PM4CTL; - -volatile uint8_t __xdata __at(0x1540) PM5STS; -volatile uint8_t __xdata __at(0x1541) PM5DO; -volatile uint8_t __xdata __at(0x1542) PM5DI; -volatile uint8_t __xdata __at(0x1543) PM5CTL; - -#endif // _EC_PMC_H diff --git a/src/board/system76/lemp9/scratch/main.c b/src/board/system76/lemp9/scratch/main.c index 83db410..dffe493 100644 --- a/src/board/system76/lemp9/scratch/main.c +++ b/src/board/system76/lemp9/scratch/main.c @@ -1,130 +1,8 @@ -#include -#include - -#include - -volatile uint8_t __xdata __at(0x103B) ECINDAR0; -volatile uint8_t __xdata __at(0x103C) ECINDAR1; -volatile uint8_t __xdata __at(0x103D) ECINDAR2; -volatile uint8_t __xdata __at(0x103E) ECINDAR3; -volatile uint8_t __xdata __at(0x103F) ECINDDR; - -volatile uint8_t __xdata __at(0x1F01) ETWCFG; -volatile uint8_t __xdata __at(0x1F07) EWDKEYR; - -uint8_t acpi_read(uint8_t addr) { - uint8_t data = 0; - - switch (addr) { - case 4: - data = ECINDAR0; - break; - case 5: - data = ECINDAR1; - break; - case 6: - data = ECINDAR2; - break; - case 7: - data = ECINDAR3; - break; - case 8: - data = ECINDDR; - break; - } - - return data; -} - -void acpi_write(uint8_t addr, uint8_t data) { - switch (addr) { - case 4: - ECINDAR0 = data; - break; - case 5: - ECINDAR1 = data; - break; - case 6: - ECINDAR2 = data; - break; - case 7: - ECINDAR3 = data; - break; - case 8: - ECINDDR = data; - break; - } -} - -enum PmcState { - PMC_STATE_DEFAULT, - PMC_STATE_WRITE, - PMC_STATE_ACPI_READ, - PMC_STATE_ACPI_WRITE, - PMC_STATE_ACPI_WRITE_ADDR, -}; - -void pmc_event(struct Pmc * pmc) { - static enum PmcState state = PMC_STATE_DEFAULT; - static uint8_t state_data = 0; - - uint8_t sts = pmc_status(pmc); - - // Read command/data if available - if (sts & PMC_STS_IBF) { - uint8_t data = pmc_read(pmc); - if (sts & PMC_STS_CMD) { - state = PMC_STATE_DEFAULT; - switch (data) { - case 0x80: - state = PMC_STATE_ACPI_READ; - break; - case 0x81: - state = PMC_STATE_ACPI_WRITE; - break; - case 0xEC: - for (;;) { - // Attempt to trigger watchdog reset - ETWCFG |= (1 << 5); - EWDKEYR = 0; - } - break; - } - } else { - switch (state) { - case PMC_STATE_ACPI_READ: - state = PMC_STATE_WRITE; - state_data = acpi_read(data); - break; - case PMC_STATE_ACPI_WRITE: - state = PMC_STATE_ACPI_WRITE_ADDR; - state_data = data; - break; - case PMC_STATE_ACPI_WRITE_ADDR: - state = PMC_STATE_DEFAULT; - acpi_write(state_data, data); - break; - default: - state = PMC_STATE_DEFAULT; - break; - } - } - } - - // Write data if possible - if (!(sts & PMC_STS_OBF)) { - switch (state) { - case PMC_STATE_WRITE: - state = PMC_STATE_DEFAULT; - pmc_write(pmc, state_data); - break; - } - } -} +#include // Main program while running in scratch ROM void main(void) { for (;;) { - pmc_event(&PMC_3); + smfi_event(); } } diff --git a/src/board/system76/lemp9/scratch/pmc.c b/src/board/system76/lemp9/scratch/pmc.c deleted file mode 100644 index 2cd653a..0000000 --- a/src/board/system76/lemp9/scratch/pmc.c +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#define PMC(NUM) { \ - .status = &PM ## NUM ## STS, \ - .data_out = &PM ## NUM ## DO, \ - .data_in = &PM ## NUM ## DI, \ - .control = &PM ## NUM ## CTL, \ -} - -struct Pmc __code PMC_3 = PMC(3); - -uint8_t pmc_status(struct Pmc * pmc) { - return *(pmc->status); -} - -uint8_t pmc_read(struct Pmc * pmc) { - return *(pmc->data_in); -} - -bool pmc_write(struct Pmc * pmc, uint8_t data) { - *(pmc->data_out) = data; - return true; -} diff --git a/src/board/system76/lemp9/scratch/scratch.mk b/src/board/system76/lemp9/scratch/scratch.mk index 8f61c65..08610d3 100644 --- a/src/board/system76/lemp9/scratch/scratch.mk +++ b/src/board/system76/lemp9/scratch/scratch.mk @@ -1,3 +1,7 @@ +SCRATCH_SRC+=\ + $(COMMON_DIR)/version.c \ + $(BOARD_DIR)/smfi.c + SCRATCH_BUILD=$(BUILD)/scratch SCRATCH_OBJ=$(patsubst src/%.c,$(SCRATCH_BUILD)/%.rel,$(SCRATCH_SRC)) SCRATCH_CC=\ diff --git a/src/board/system76/lemp9/scratch/stdio.c b/src/board/system76/lemp9/scratch/stdio.c new file mode 100644 index 0000000..62541dd --- /dev/null +++ b/src/board/system76/lemp9/scratch/stdio.c @@ -0,0 +1,9 @@ +#include + +#include + +int putchar(int c) { + unsigned char byte = (unsigned char)c; + smfi_debug(byte); + return (int)byte; +} diff --git a/src/board/system76/lemp9/smfi.c b/src/board/system76/lemp9/smfi.c index ff95768..04387a0 100644 --- a/src/board/system76/lemp9/smfi.c +++ b/src/board/system76/lemp9/smfi.c @@ -2,7 +2,11 @@ #include #include +#ifndef __SCRATCH__ + #include +#endif #include +#include #include #include @@ -19,84 +23,149 @@ volatile uint8_t __xdata __at(0x105D) HRAMW0AAS; // Host RAM window 1 access allow size volatile uint8_t __xdata __at(0x105E) HRAMW1AAS; -static volatile uint8_t __xdata __at(0xC00) smfi_cmd[256]; -static volatile uint8_t __xdata __at(0xD00) smfi_dbg[256]; +volatile uint8_t __xdata __at(0x103B) ECINDAR0; +volatile uint8_t __xdata __at(0x103C) ECINDAR1; +volatile uint8_t __xdata __at(0x103D) ECINDAR2; +volatile uint8_t __xdata __at(0x103E) ECINDAR3; +volatile uint8_t __xdata __at(0x103F) ECINDDR; -enum SmfiCmd { - SMFI_CMD_NONE = 0, - SMFI_CMD_PROBE = 1, - SMFI_CMD_BOARD = 2, - SMFI_CMD_VERSION = 3, - SMFI_CMD_DEBUG = 4, - //TODO -}; +volatile uint8_t __xdata __at(0x1F01) ETWCFG; +volatile uint8_t __xdata __at(0x1F07) EWDKEYR; -enum SmfiRes { - SMFI_RES_OK = 0, - SMFI_RES_ERR = 1, - //TODO -}; +static volatile uint8_t __xdata __at(0xE00) smfi_cmd[256]; +static volatile uint8_t __xdata __at(0xF00) smfi_dbg[256]; void smfi_init(void) { int i; // Clear command region - for (i = 0; i < ARRAY_SIZE(smfi_cmd); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_cmd); i++) { smfi_cmd[i] = 0x00; } + // Clear host command last + smfi_cmd[0] = 0x00; // Clear debug region - for (i = 0; i < ARRAY_SIZE(smfi_dbg); i++) { + for (i = 1; i < ARRAY_SIZE(smfi_dbg); i++) { smfi_dbg[i] = 0x00; } + // Clear tail last + smfi_dbg[0] = 0x00; - // H2RAM window 0 address 0xC00 - 0xCFF, read/write - HRAMW0BA = 0xC0; + // H2RAM window 0 address 0xE00 - 0xEFF, read/write + HRAMW0BA = 0xE0; HRAMW0AAS = 0x04; - // H2RAM window 1 address 0xD00 - 0xDFF, read/write - HRAMW1BA = 0xD0; + // H2RAM window 1 address 0xF00 - 0xFFF, read/write + HRAMW1BA = 0xF0; HRAMW1AAS = 0x04; // Enable H2RAM window 0 and 1 using LPC I/O HRAMWC |= 0x13; } -void smfi_event(void) { +static enum Result cmd_debug(void) { int i; - if (smfi_cmd[0]) { - // Default to success - smfi_cmd[1] = SMFI_RES_OK; + for (i = 2; i < ARRAY_SIZE(smfi_cmd); i++) { + uint8_t b = smfi_cmd[i]; + if (b == 0) break; + putchar(b); + } + return RES_OK; +} + +static enum Result cmd_spi(void) { + uint8_t flags = smfi_cmd[2]; + +#ifdef __SCRATCH__ + int len = (int)smfi_cmd[3]; + + // Enable chip (internal) + ECINDAR3 = 0x7F; + ECINDAR2 = 0xFF; + ECINDAR1 = 0xFD; + ECINDAR0 = 0x00; + + // Read or write len bytes + int i; + for (i = 0; (i < len) && ((i + 4) < ARRAY_SIZE(smfi_cmd)); i++) { + if (flags & CMD_SPI_FLAG_READ) { + smfi_cmd[i + 4] = ECINDDR; + } else { + ECINDDR = smfi_cmd[i + 4]; + } + } + + // Set actually read/written count + smfi_cmd[3] = (uint8_t)i; + + if (flags & CMD_SPI_FLAG_DISABLE) { + // Disable chip + ECINDAR1 = 0xFE; + ECINDDR = 0; + } + + return RES_OK; +#else + if (flags & CMD_SPI_FLAG_SCRATCH) { + scratch_trampoline(); + } + + // Cannot use SPI bus while running EC from SPI, or trampoline failed + return RES_ERR; +#endif +} + +static enum Result cmd_reset(void) { + // Attempt to trigger watchdog reset + ETWCFG |= (1 << 5); + EWDKEYR = 0; + + // Failed if it got this far + return RES_ERR; +} + +void smfi_event(void) { + if (smfi_cmd[0]) { switch (smfi_cmd[0]) { - case SMFI_CMD_PROBE: + case CMD_PROBE: // Signature smfi_cmd[2] = 0x76; smfi_cmd[3] = 0xEC; // Version smfi_cmd[4] = 0x01; + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_BOARD: + case CMD_BOARD: strncpy(&smfi_cmd[2], board(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; break; - case SMFI_CMD_VERSION: + case CMD_VERSION: strncpy(&smfi_cmd[2], version(), ARRAY_SIZE(smfi_cmd) - 2); + // Always successful + smfi_cmd[1] = RES_OK; + break; + case CMD_DEBUG: + smfi_cmd[1] = cmd_debug(); + break; + case CMD_SPI: + smfi_cmd[1] = cmd_spi(); + break; + case CMD_RESET: + smfi_cmd[1] = cmd_reset(); break; - case SMFI_CMD_DEBUG: - for (i = 2; i < ARRAY_SIZE(smfi_cmd) - 2; i++) { - uint8_t b = smfi_cmd[i]; - if (b == 0) break; - putchar(b); - } default: // Command not found - smfi_cmd[1] = SMFI_RES_ERR; + smfi_cmd[1] = RES_ERR; break; } // Mark command as finished - smfi_cmd[0] = SMFI_CMD_NONE; + smfi_cmd[0] = CMD_NONE; } } diff --git a/src/common/include/common/command.h b/src/common/include/common/command.h new file mode 100644 index 0000000..d37da28 --- /dev/null +++ b/src/common/include/common/command.h @@ -0,0 +1,39 @@ +#ifndef _COMMON_COMMAND_H +#define _COMMON_COMMAND_H + +enum Command { + // Indicates that EC is ready to accept commands + CMD_NONE = 0, + // Probe for System76 EC protocol + CMD_PROBE = 1, + // Read board string + CMD_BOARD = 2, + // Read version string + CMD_VERSION = 3, + // Write bytes to console + CMD_DEBUG = 4, + // Access SPI chip + CMD_SPI = 5, + // Reset EC + CMD_RESET = 6, + //TODO +}; + +enum Result { + // Command executed successfully + RES_OK = 0, + // Command failed with generic error + RES_ERR = 1, + //TODO +}; + +enum CommandSpiFlag { + // Read from SPI chip if set, write otherwise + CMD_SPI_FLAG_READ = (1 << 0), + // Disable SPI chip after executing command + CMD_SPI_FLAG_DISABLE = (1 << 1), + // Run firmware from scratch RAM if necessary + CMD_SPI_FLAG_SCRATCH = (1 << 2), +}; + +#endif // _COMMON_COMMAND_H diff --git a/tool/src/ec.rs b/tool/src/ec.rs index 74cdc39..a93be11 100644 --- a/tool/src/ec.rs +++ b/tool/src/ec.rs @@ -2,6 +2,7 @@ use hwio::{Io, Pio}; use crate::{ Error, + Spi, SuperIo, Timeout, timeout @@ -9,13 +10,20 @@ use crate::{ #[derive(Clone, Copy, Debug)] #[repr(u8)] -pub enum EcCmd { +pub enum Cmd { None = 0, Probe = 1, Board = 2, Version = 3, + Debug = 4, + Spi = 5, + Reset = 6, } +pub const CMD_SPI_FLAG_READ: u8 = (1 << 0); +pub const CMD_SPI_FLAG_DISABLE: u8 = (1 << 1); +pub const CMD_SPI_FLAG_SCRATCH: u8 = (1 << 2); + pub struct Ec { cmd: u16, dbg: u16, @@ -24,8 +32,8 @@ pub struct Ec { impl Ec { /// Probes for a compatible EC - pub unsafe fn new(primary: bool, timeout: T) -> Result { - let mut sio = SuperIo::new(if primary { 0x2E } else { 0x4E }); + pub unsafe fn new(timeout: T) -> Result { + let mut sio = SuperIo::new(0x2E); let id = (sio.read(0x20) as u16) << 8 | @@ -37,8 +45,8 @@ impl Ec { } let mut ec = Ec { - cmd: if primary { 0xC00 } else { 0xE00 }, - dbg: if primary { 0xD00 } else { 0xF00 }, + cmd: 0xE00, + dbg: 0xF00, timeout, }; @@ -68,44 +76,39 @@ impl Ec { ).read() } - /// Returns true if a command can be sent - pub unsafe fn can_command(&mut self) -> bool { - self.read(0) == EcCmd::None as u8 - } - - /// Start an EC command - pub unsafe fn command_start(&mut self, cmd: EcCmd) -> Result<(), Error> { - if self.can_command() { - self.write(0, cmd as u8); + /// Returns Ok if a command can be sent + unsafe fn command_check(&mut self) -> Result<(), Error> { + if self.read(0) == Cmd::None as u8 { Ok(()) } else { Err(Error::WouldBlock) } } - /// Finish an EC command - pub unsafe fn command_finish(&mut self) -> Result<(), Error> { - if self.can_command() { - match self.read(1) { - 0 => Ok(()), - err => Err(Error::Protocol(err)), - } - } else { - Err(Error::WouldBlock) - } + /// Wait until a command can be sent + unsafe fn command_wait(&mut self) -> Result<(), Error> { + self.timeout.reset(); + timeout!(self.timeout, self.command_check()) } - /// Run an EC command (start and finish) - pub unsafe fn command(&mut self, cmd: EcCmd) -> Result<(), Error> { - self.timeout.reset(); - - timeout!(self.timeout, self.command_start(cmd))?; - timeout!(self.timeout, self.command_finish()) + /// Run an EC command + pub unsafe fn command(&mut self, cmd: Cmd) -> Result<(), Error> { + // All previous commands should be finished + self.command_check()?; + // Write command byte + self.write(0, cmd as u8); + // Wait for command to finish + self.command_wait()?; + // Read response byte and test for error + match self.read(1) { + 0 => Ok(()), + err => Err(Error::Protocol(err)), + } } /// Probe for EC pub unsafe fn probe(&mut self) -> Result { - self.command(EcCmd::Probe)?; + self.command(Cmd::Probe)?; let signature = ( self.read(2), self.read(3) @@ -120,7 +123,7 @@ impl Ec { /// Read board from EC pub unsafe fn board(&mut self, data: &mut [u8]) -> Result { - self.command(EcCmd::Board)?; + self.command(Cmd::Board)?; let mut i = 0; while i < data.len() && (i + 2) < 256 { data[i] = self.read((i + 2) as u8); @@ -134,7 +137,7 @@ impl Ec { /// Read version from EC pub unsafe fn version(&mut self, data: &mut [u8]) -> Result { - self.command(EcCmd::Version)?; + self.command(Cmd::Version)?; let mut i = 0; while i < data.len() && (i + 2) < 256 { data[i] = self.read((i + 2) as u8); @@ -145,4 +148,85 @@ impl Ec { } Ok(i) } + + pub unsafe fn spi(&mut self, scratch: bool) -> Result, Error> { + let mut spi = EcSpi { + ec: self, + scratch, + }; + spi.reset()?; + Ok(spi) + } + + pub unsafe fn reset(&mut self) -> Result<(), Error> { + self.command(Cmd::Reset) + } +} + +pub struct EcSpi<'a, T: Timeout> { + ec: &'a mut Ec, + scratch: bool, +} + +impl<'a, T: Timeout> Spi for EcSpi<'a, T> { + /// Disable SPI chip, must be done before and after a transaction + unsafe fn reset(&mut self) -> Result<(), Error> { + let flags = + CMD_SPI_FLAG_DISABLE | + if self.scratch { CMD_SPI_FLAG_SCRATCH } else { 0 }; + + self.ec.write(2, flags); + self.ec.write(3, 0); + self.ec.command(Cmd::Spi)?; + assert_eq!(self.ec.read(3), 0); + + Ok(()) + } + + /// SPI read + unsafe fn read(&mut self, data: &mut [u8]) -> Result { + let flags = + CMD_SPI_FLAG_READ | + if self.scratch { CMD_SPI_FLAG_SCRATCH } else { 0 }; + + for chunk in data.chunks_mut(256 - 4) { + self.ec.write(2, flags); + self.ec.write(3, chunk.len() as u8); + self.ec.command(Cmd::Spi)?; + assert_eq!(self.ec.read(3), chunk.len() as u8); + + for i in 0..chunk.len() { + chunk[i] = self.ec.read(i as u8 + 4); + } + } + + Ok(data.len()) + } + + /// SPI write + unsafe fn write(&mut self, data: &[u8]) -> Result { + let flags = + if self.scratch { CMD_SPI_FLAG_SCRATCH } else { 0 }; + + for chunk in data.chunks(256 - 4) { + for i in 0..chunk.len() { + self.ec.write(i as u8 + 4, chunk[i]); + } + + self.ec.write(2, flags); + self.ec.write(3, chunk.len() as u8); + self.ec.command(Cmd::Spi)?; + assert_eq!(self.ec.read(3), chunk.len() as u8); + } + + Ok(data.len()) + } +} + +impl<'a, T: Timeout> Drop for EcSpi<'a, T> { + fn drop(&mut self) { + unsafe { + let _ = self.reset(); + } + } } diff --git a/tool/src/error.rs b/tool/src/error.rs index 2e76103..fdfbd64 100644 --- a/tool/src/error.rs +++ b/tool/src/error.rs @@ -1,9 +1,11 @@ #[derive(Debug)] pub enum Error { + Parameter, Protocol(u8), Signature((u8, u8)), SuperIoId(u16), Timeout, + Verify, WouldBlock, } diff --git a/tool/src/lib.rs b/tool/src/lib.rs index 043076c..e95400c 100644 --- a/tool/src/lib.rs +++ b/tool/src/lib.rs @@ -15,6 +15,9 @@ mod legacy; pub use self::pmc::Pmc; mod pmc; +pub use self::spi::{Spi, SpiRom}; +mod spi; + pub use self::super_io::SuperIo; mod super_io; diff --git a/tool/src/main.rs b/tool/src/main.rs index e50af69..84e47f0 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -2,6 +2,7 @@ use ectool::{ Ec, Error, Firmware, + SpiRom, Timeout, }; use std::{ @@ -53,7 +54,6 @@ unsafe fn console() -> Result<(), Error> { iopl(); let mut ec = Ec::new( - true, StdTimeout::new(Duration::new(1, 0)), )?; @@ -73,6 +73,98 @@ unsafe fn console() -> Result<(), Error> { } } +unsafe fn flash_inner(ec: &mut Ec, firmware: &Firmware) -> Result<(), Error> { + let rom_size = 128 * 1024; + let sector_size = 1024; + + let mut spi_bus = ec.spi(true)?; + let mut spi = SpiRom::new( + &mut spi_bus, + StdTimeout::new(Duration::new(1, 0)) + ); + + // Read entire ROM + let mut rom = vec![0; rom_size]; + eprintln!("SPI read"); + spi.read_at(0, &mut rom)?; + + eprintln!("Saving ROM to backup.rom"); + fs::write("backup.rom", &rom).map_err(|_| Error::Verify)?; + + let mut matches = true; + for i in 0..rom.len() { + if &rom[i] != firmware.data.get(i).unwrap_or(&0xFF) { + matches = false; + break; + } + } + + if matches { + eprintln!("ROM matches specified firmware"); + return Ok(()); + } + + { + // Chip erase + // eprintln!("SPI chip erase"); + // spi.erase_chip()?; + + // Sector erase + let mut address = 0; + while address < rom_size { + let mut erased = true; + for &b in &rom[address..address + sector_size] { + if b != 0xFF { + erased =false; + break; + } + } + + if erased { + eprintln!("SPI sector already erased {:06X}", address); + address += sector_size; + } else { + eprintln!("SPI sector erase {:06X}", address); + address += spi.erase_sector(address as u32)?; + } + } + + // Read entire ROM + eprintln!("SPI read"); + spi.read_at(0, &mut rom)?; + } + + // Verify chip erase + for i in 0..rom.len() { + if rom[i] != 0xFF { + eprintln!("Failed to erase: {:X} is {:X} instead of {:X}", i, rom[i], 0xFF); + return Err(Error::Verify); + } + } + + // Program + { + eprintln!("SPI AAI word program"); + spi.write_at(0, &firmware.data)?; + + // Read entire ROM + eprintln!("SPI read"); + spi.read_at(0, &mut rom)?; + } + + // Verify program + for i in 0..rom.len() { + if &rom[i] != firmware.data.get(i).unwrap_or(&0xFF) { + eprintln!("Failed to program: {:X} is {:X} instead of {:X}", i, rom[i], firmware.data[i]); + return Err(Error::Verify); + } + } + + eprintln!("Successfully programmed SPI ROM"); + + Ok(()) +} + unsafe fn flash(path: &str) -> Result<(), Error> { //TODO: remove unwraps let firmware_data = fs::read(path).unwrap(); @@ -83,7 +175,6 @@ unsafe fn flash(path: &str) -> Result<(), Error> { iopl(); let mut ec = Ec::new( - true, StdTimeout::new(Duration::new(1, 0)), )?; @@ -107,14 +198,34 @@ unsafe fn flash(path: &str) -> Result<(), Error> { println!("ec version: {:?}", str::from_utf8(ec_version)); } - Ok(()) + // Wait for any key releases + eprintln!("Waiting 5 seconds for all keys to be released"); + thread::sleep(Duration::new(5, 0)); + + eprintln!("Sync"); + let _ = process::Command::new("sync").status(); + + let res = flash_inner(&mut ec, &firmware); + eprintln!("Result: {:X?}", res); + + eprintln!("Sync"); + let _ = process::Command::new("sync").status(); + + eprintln!("System will shut off in 5 seconds"); + thread::sleep(Duration::new(5, 0)); + + eprintln!("Sync"); + let _ = process::Command::new("sync").status(); + + ec.reset()?; + + res } unsafe fn info() -> Result<(), Error> { iopl(); let mut ec = Ec::new( - true, StdTimeout::new(Duration::new(1, 0)), )?; diff --git a/tool/src/spi.rs b/tool/src/spi.rs new file mode 100644 index 0000000..3aab087 --- /dev/null +++ b/tool/src/spi.rs @@ -0,0 +1,165 @@ +use crate::{ + Error, + Timeout, +}; + +pub trait Spi { + unsafe fn reset(&mut self) -> Result<(), Error>; + unsafe fn read(&mut self, data: &mut [u8]) -> Result; + unsafe fn write(&mut self, data: &[u8]) -> Result; +} + + +pub struct SpiRom<'a, S: Spi, T: Timeout> { + spi: &'a mut S, + timeout: T, +} + +impl<'a, S: Spi, T: Timeout> SpiRom<'a, S, T> { + pub fn new(spi: &'a mut S, timeout: T) -> Self { + Self { + spi, + timeout, + } + } + + pub unsafe fn status(&mut self) -> Result { + let mut status = [0]; + + self.spi.reset()?; + self.spi.write(&[0x05])?; + self.spi.read(&mut status)?; + + Ok(status[0]) + } + + pub unsafe fn status_wait(&mut self, mask: u8, value: u8) -> Result<(), Error> { + self.timeout.reset(); + while self.timeout.running() { + if self.status()? & mask == value { + return Ok(()); + } + } + Err(Error::Timeout) + } + + pub unsafe fn write_disable(&mut self) -> Result<(), Error> { + self.spi.reset()?; + self.spi.write(&[0x04])?; + + // Poll status for busy unset and write enable unset + self.status_wait(3, 0)?; + + Ok(()) + } + + pub unsafe fn write_enable(&mut self) -> Result<(), Error> { + self.spi.reset()?; + self.spi.write(&[0x06])?; + + // Poll status for busy unset and write enable set + self.status_wait(3, 2)?; + + Ok(()) + } + + pub unsafe fn erase_chip(&mut self) -> Result<(), Error> { + self.write_enable()?; + + self.spi.reset()?; + self.spi.write(&[0x60])?; + + // Poll status for busy unset + self.status_wait(1, 0)?; + + self.write_disable()?; + + Ok(()) + } + + pub unsafe fn erase_sector(&mut self, address: u32) -> Result { + if (address & 0xFF00_0000) > 0 { + return Err(Error::Parameter); + } + + self.write_enable()?; + + self.spi.reset()?; + self.spi.write(&[ + 0xD7, + (address >> 16) as u8, + (address >> 8) as u8, + address as u8, + ])?; + + // Poll status for busy unset + self.status_wait(1, 0)?; + + self.write_disable()?; + + //TODO: dynamically figure out this value + Ok(1024) + } + + pub unsafe fn read_at(&mut self, address: u32, data: &mut [u8]) -> Result { + if (address & 0xFF00_0000) > 0 { + return Err(Error::Parameter); + } + + self.spi.reset()?; + self.spi.write(&[ + 0x0B, + (address >> 16) as u8, + (address >> 8) as u8, + address as u8, + 0, + ])?; + self.spi.read(data) + } + + pub unsafe fn write_at(&mut self, address: u32, data: &[u8]) -> Result { + if (address & 0xFF00_0000) > 0 { + return Err(Error::Parameter); + } + + self.write_enable()?; + + for (i, word) in data.chunks(2).enumerate() { + let low = *word.get(0).unwrap_or(&0xFF); + let high = *word.get(1).unwrap_or(&0xFF); + + self.spi.reset()?; + if i == 0 { + self.spi.write(&[ + 0xAD, + (address >> 16) as u8, + (address >> 8) as u8, + address as u8, + low, + high + ])?; + } else { + self.spi.write(&[ + 0xAD, + low, + high + ])?; + } + + // Poll status for busy unset + self.status_wait(1, 0)?; + } + + self.write_disable()?; + + Ok(data.len()) + } +} + +impl<'a, S: Spi, T: Timeout> Drop for SpiRom<'a, S, T> { + fn drop(&mut self) { + unsafe { + let _ = self.write_disable(); + } + } +}