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
This commit is contained in:
Jeremy Soller
2020-02-26 09:04:40 -07:00
committed by GitHub
parent a7e47d8d58
commit 657437e1ce
34 changed files with 826 additions and 791 deletions

View File

@@ -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

View File

@@ -2,7 +2,6 @@
#include <board/acpi.h>
#include <board/gpio.h>
#include <board/pmc.h>
#include <board/scratch.h>
#include <common/debug.h>
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);

View File

@@ -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);

View File

@@ -1,53 +0,0 @@
#ifndef _EC_PMC_H
#define _EC_PMC_H
#include <stdbool.h>
#include <stdint.h>
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

View File

@@ -1,130 +1,8 @@
#include <stdbool.h>
#include <stdint.h>
#include <scratch/pmc.h>
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 <board/smfi.h>
// Main program while running in scratch ROM
void main(void) {
for (;;) {
pmc_event(&PMC_3);
smfi_event();
}
}

View File

@@ -1,23 +0,0 @@
#include <scratch/pmc.h>
#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;
}

View File

@@ -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=\

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include <board/smfi.h>
int putchar(int c) {
unsigned char byte = (unsigned char)c;
smfi_debug(byte);
return (int)byte;
}

View File

@@ -2,7 +2,11 @@
#include <stdio.h>
#include <string.h>
#ifndef __SCRATCH__
#include <board/scratch.h>
#endif
#include <board/smfi.h>
#include <common/command.h>
#include <common/macro.h>
#include <common/version.h>
@@ -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;
}
}

View File

@@ -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

View File

@@ -2,7 +2,6 @@
#include <board/acpi.h>
#include <board/gpio.h>
#include <board/pmc.h>
#include <board/scratch.h>
#include <common/debug.h>
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);

View File

@@ -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);

View File

@@ -1,53 +0,0 @@
#ifndef _EC_PMC_H
#define _EC_PMC_H
#include <stdbool.h>
#include <stdint.h>
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

View File

@@ -1,130 +1,8 @@
#include <stdbool.h>
#include <stdint.h>
#include <scratch/pmc.h>
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 <board/smfi.h>
// Main program while running in scratch ROM
void main(void) {
for (;;) {
pmc_event(&PMC_3);
smfi_event();
}
}

View File

@@ -1,23 +0,0 @@
#include <scratch/pmc.h>
#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;
}

View File

@@ -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=\

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include <board/smfi.h>
int putchar(int c) {
unsigned char byte = (unsigned char)c;
smfi_debug(byte);
return (int)byte;
}

View File

@@ -2,7 +2,11 @@
#include <stdio.h>
#include <string.h>
#ifndef __SCRATCH__
#include <board/scratch.h>
#endif
#include <board/smfi.h>
#include <common/command.h>
#include <common/macro.h>
#include <common/version.h>
@@ -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;
}
}

View File

@@ -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

View File

@@ -2,7 +2,6 @@
#include <board/acpi.h>
#include <board/gpio.h>
#include <board/pmc.h>
#include <board/scratch.h>
#include <common/debug.h>
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);

View File

@@ -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);

View File

@@ -1,53 +0,0 @@
#ifndef _EC_PMC_H
#define _EC_PMC_H
#include <stdbool.h>
#include <stdint.h>
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

View File

@@ -1,130 +1,8 @@
#include <stdbool.h>
#include <stdint.h>
#include <scratch/pmc.h>
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 <board/smfi.h>
// Main program while running in scratch ROM
void main(void) {
for (;;) {
pmc_event(&PMC_3);
smfi_event();
}
}

View File

@@ -1,23 +0,0 @@
#include <scratch/pmc.h>
#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;
}

View File

@@ -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=\

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
#include <board/smfi.h>
int putchar(int c) {
unsigned char byte = (unsigned char)c;
smfi_debug(byte);
return (int)byte;
}

View File

@@ -2,7 +2,11 @@
#include <stdio.h>
#include <string.h>
#ifndef __SCRATCH__
#include <board/scratch.h>
#endif
#include <board/smfi.h>
#include <common/command.h>
#include <common/macro.h>
#include <common/version.h>
@@ -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;
}
}

View File

@@ -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