Victor Ding has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Add ENE LPC programmer
Initial support of ENE LPC interface keyboard controller.
BUG=b:156140422 BRANCH=none
Signed-off-by: Victor Ding victording@google.com Change-Id: I970afd8c1bd92c159c60e09f22e2f18c0433729d --- M Makefile A ene_lpc.c M flashrom.c M meson.build M meson_options.txt M programmer.h 6 files changed, 642 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/80/44580/1
diff --git a/Makefile b/Makefile index 803529f..85b4850 100644 --- a/Makefile +++ b/Makefile @@ -170,6 +170,11 @@ else override CONFIG_DEVELOPERBOX_SPI = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_FT2232_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else @@ -271,6 +276,11 @@ else override CONFIG_ATAPROMISE = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_IT8212), yes) UNSUPPORTED_FEATURES += CONFIG_IT8212=yes else @@ -381,6 +391,11 @@ else override CONFIG_DEVELOPERBOX_SPI = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_FT2232_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else @@ -671,6 +686,9 @@ # Promise ATA controller support. CONFIG_ATAPROMISE ?= no
+# ENE LPC interface keyboard controller +CONFIG_ENE_LPC ?= yes + # Always enable FT2232 SPI dongles for now. CONFIG_FT2232_SPI ?= yes
@@ -855,6 +873,11 @@ NEED_LIBPCI += CONFIG_INTERNAL endif
+ifeq ($(CONFIG_ENE_LPC), yes) +FEATURE_CFLAGS += -D'CONFIG_ENE_LPC=1' +PROGRAMMER_OBJS += ene_lpc.o +endif + ifeq ($(CONFIG_SERPROG), yes) FEATURE_CFLAGS += -D'CONFIG_SERPROG=1' PROGRAMMER_OBJS += serprog.o diff --git a/ene_lpc.c b/ene_lpc.c new file mode 100644 index 0000000..701e84e --- /dev/null +++ b/ene_lpc.c @@ -0,0 +1,593 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Google or the names of contributors or + * licensors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * GOOGLE INC AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * GOOGLE OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF GOOGLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#if defined(__i386__) || defined(__x86_64__) +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + +#include "chipdrivers.h" +#include "flash.h" +#include "programmer.h" +#include "hwaccess.h" +#include "spi.h" + +/* MCU registers */ +#define REG_EC_HWVER 0xff00 +#define REG_EC_FWVER 0xff01 +#define REG_EC_EDIID 0xff24 +#define REG_8051_CTRL 0xff14 +#define REG_EC_EXTCMD 0xff10 + +#define CPU_RESET 1 + +/* MCU SPI peripheral registers */ +#define REG_SPI_DATA 0xfeab +#define REG_SPI_COMMAND 0xfeac +#define REG_SPI_CONFIG 0xfead + +#define CFG_CSn_FORCE_LOW (1 << 4) +#define CFG_COMMAND_WRITE_ENABLE (1 << 3) +#define CFG_STATUS (1 << 1) +#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0) + +/* Timeout */ +#define EC_COMMAND_TIMEOUT 4 +#define EC_RESTART_TIMEOUT 10 +#define ENE_SPI_DELAY_CYCLE 4 +#define EC_PAUSE_TIMEOUT 12 +#define EC_RESET_TRIES 3 + +#define ENE_KB94X_PAUSE_WAKEUP_PORT 0x64 + +#define MASK_INPUT_BUFFER_FULL 2 +#define MASK_OUTPUT_BUFFER_FULL 1 + +const int port_ene_bank = 1; +const int port_ene_offset = 2; +const int port_ene_data = 3; + +/* Supported ENE ECs, ENE_LAST should always be LAST member */ +enum ene_chip_id { + ENE_KB932 = 0, + ENE_KB94X, + ENE_LAST +}; + +/* EC state */ +enum ene_ec_state { + EC_STATE_NORMAL, + EC_STATE_IDLE, + EC_STATE_RESET, + EC_STATE_UNKNOWN +}; + +/* chip-specific parameters */ +typedef struct { + enum ene_chip_id chip_id; + uint8_t hwver; + uint8_t ediid; + uint32_t port_bios; + uint32_t port_ec_command; + uint32_t port_ec_data; + uint8_t ec_reset_cmd; + uint8_t ec_reset_data; + uint8_t ec_restart_cmd; + uint8_t ec_restart_data; + uint8_t ec_pause_cmd; + uint8_t ec_pause_data; + uint16_t ec_status_buf; + uint8_t ec_is_stopping; + uint8_t ec_is_running; + uint8_t ec_is_pausing; + uint32_t port_io_base; +} ene_chip_t; + +typedef struct +{ + /* pointer to table entry of identified chip */ + ene_chip_t *chip; + /* current ec state */ + enum ene_ec_state ec_state; + struct timeval pause_begin; +} ene_lpc_data_t; + +/* table of supported chips + parameters */ +static ene_chip_t ene_chips[] = { + { + ENE_KB932, /* chip_id */ + 0xa2, 0x02, /* hwver + ediid */ + 0x66, /* port_bios */ + 0x6c, 0x68, /* port_ec_{command,data} */ + 0x59, 0xf2, /* ec_reset_{cmd,data} */ + 0x59, 0xf9, /* ec_restart_{cmd,data} */ + 0x59, 0xf1, /* ec_pause_{cmd,data} */ + 0xf554, /* ec_status_buf */ + 0xa5, 0x00, /* ec_is_{stopping,running} masks */ + 0x33, /* ec_is_pausing mask */ + 0xfd60 /* port_io_base */ + }, + { + ENE_KB94X, /* chip_id */ + 0xa3, 0x05, /* hwver + ediid */ + 0x66, /* port_bios */ + 0x66, 0x68, /* port_ec_{command,data} */ + 0x7d, 0x10, /* ec_reset_{cmd,data} */ + 0x7f, 0x10, /* ec_restart_{cmd,data} */ + 0x7e, 0x10, /* ec_pause_{cmd,data} */ + 0xf710, /* ec_status_buf */ + 0x02, 0x00, /* ec_is_{stopping,running} masks */ + 0x01, /* ec_is_pausing mask */ + 0x0380 /* port_io_base */ + } +}; + +static void ec_command(const ene_chip_t *chip, uint8_t cmd, uint8_t data) +{ + struct timeval begin, now; + + /* Spin wait for EC input buffer empty */ + gettimeofday(&begin, NULL); + while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: buf not empty\n", __func__); + return; + } + } + + /* Write command */ + OUTB(cmd, chip->port_ec_command); + + if (chip->chip_id == ENE_KB932) { + /* Spin wait for EC input buffer empty */ + gettimeofday(&begin, NULL); + while (INB(chip->port_ec_command) & + MASK_INPUT_BUFFER_FULL) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: buf not empty\n", __func__); + return; + } + } + /* Write data */ + OUTB(data, chip->port_ec_data); + } +} + +static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr) +{ + uint8_t bank; + uint8_t offset; + uint8_t data; + uint32_t port_io_base; + + bank = addr >> 8; + offset = addr & 0xff; + port_io_base = chip->port_io_base; + + OUTB(bank, port_io_base + port_ene_bank); + OUTB(offset, port_io_base + port_ene_offset); + data = INB(port_io_base + port_ene_data); + + return data; +} + +static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data) +{ + uint8_t bank; + uint8_t offset; + uint32_t port_io_base; + + bank = addr >> 8; + offset = addr & 0xff; + port_io_base = chip->port_io_base; + + OUTB(bank, port_io_base + port_ene_bank); + OUTB(offset, port_io_base + port_ene_offset); + + OUTB(data, port_io_base + port_ene_data); +} + +/** + * wait_cycles, wait for n LPC bus clock cycles + * + * @param n: number of LPC cycles to wait + * @return void + */ +static void wait_cycles(const ene_chip_t *chip,int n) +{ + while (n--) + INB(chip->port_io_base + port_ene_bank); +} + +static int is_spicmd_write(uint8_t cmd) +{ + switch (cmd) { + case JEDEC_WREN: + /* Chip Write Enable */ + case JEDEC_EWSR: + /* Write Status Enable */ + case JEDEC_CE_60: + /* Chip Erase 0x60 */ + case JEDEC_CE_C7: + /* Chip Erase 0xc7 */ + case JEDEC_BE_52: + /* Block Erase 0x52 */ + case JEDEC_BE_D8: + /* Block Erase 0xd8 */ + case JEDEC_BE_D7: + /* Block Erase 0xd7 */ + case JEDEC_SE: + /* Sector Erase */ + case JEDEC_BYTE_PROGRAM: + /* Write memory byte */ + case JEDEC_AAI_WORD_PROGRAM: + /* Write AAI word */ + return 1; + } + return 0; +} + +static void ene_spi_start(const ene_chip_t *chip) +{ + int cfg; + + cfg = ene_read(chip, REG_SPI_CONFIG); + cfg |= CFG_CSn_FORCE_LOW; + cfg |= CFG_COMMAND_WRITE_ENABLE; + ene_write(chip, REG_SPI_CONFIG, cfg); + + wait_cycles(chip, ENE_SPI_DELAY_CYCLE); +} + +static void ene_spi_end(const ene_chip_t *chip) +{ + int cfg; + + cfg = ene_read(chip, REG_SPI_CONFIG); + cfg &= ~CFG_CSn_FORCE_LOW; + cfg |= CFG_COMMAND_WRITE_ENABLE; + ene_write(chip, REG_SPI_CONFIG, cfg); + + wait_cycles(chip, ENE_SPI_DELAY_CYCLE); +} + +static int ene_spi_wait(const ene_chip_t *chip) +{ + struct timeval begin, now; + + gettimeofday(&begin, NULL); + while(ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: spi busy\n", __func__); + return 1; + } + } + return 0; +} + +static int ene_pause_ec(ene_lpc_data_t *ctx_data) +{ + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + if (!chip->ec_pause_cmd) + return -1; + + /* EC prepare pause */ + ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data); + + gettimeofday(&begin, NULL); + /* Spin wait for EC ready */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_pausing) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to pause ec\n", __func__); + return -1; + } + } + + + gettimeofday(&ctx_data->pause_begin, NULL); + ctx_data->ec_state = EC_STATE_IDLE; + return 0; +} + +static int ene_resume_ec(ene_lpc_data_t *ctx_data) +{ + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + if (chip->chip_id == ENE_KB94X) + OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT); + else + /* Trigger 8051 interrupt to resume */ + ene_write(chip, REG_EC_EXTCMD, 0xff); + + gettimeofday(&begin, NULL); + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_running) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to resume ec\n", __func__); + return -1; + } + } + + ctx_data->ec_state = EC_STATE_NORMAL; + return 0; +} + +static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data) +{ + struct timeval pause_now; + gettimeofday(&pause_now, NULL); + if ((pause_now.tv_sec - ctx_data->pause_begin.tv_sec) >= + EC_PAUSE_TIMEOUT) { + if(ene_resume_ec(ctx_data) == 0) + ene_pause_ec(ctx_data); + + } + return 0; +} + +static int ene_reset_ec(ene_lpc_data_t *ctx_data) +{ + uint8_t reg; + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + gettimeofday(&begin, NULL); + + /* EC prepare reset */ + ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data); + + /* Spin wait for EC ready */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_stopping) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to reset ec\n", __func__); + return -1; + } + } + + /* Wait 1 second */ + sleep(1); + + /* Reset 8051 */ + reg = ene_read(chip, REG_8051_CTRL); + reg |= CPU_RESET; + ene_write(chip, REG_8051_CTRL, reg); + + ctx_data->ec_state = EC_STATE_RESET; + return 0; +} + +static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data) +{ + if (ene_pause_ec(ctx_data)) + return ene_reset_ec(ctx_data); + return 0; +} + +static int ene_spi_send_command(const struct flashctx *flash, + unsigned int writecnt, + unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned int i; + int tries = EC_RESET_TRIES; + ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data; + const ene_chip_t *chip = ctx_data->chip; + + if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) { + do { + /* Enter reset mode if we need to write/erase */ + if (ene_resume_ec(ctx_data)) + continue; + + if (!ene_reset_ec(ctx_data)) + break; + } while (--tries > 0); + + if (!tries) { + msg_perr("%s: EC failed reset, skipping write\n", __func__); + ctx_data->ec_state = EC_STATE_IDLE; + return 1; + } + } + else if(chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE) + ene_pause_timeout_check(ctx_data); + + ene_spi_start(chip); + + for (i = 0; i < writecnt; i++) { + ene_write(chip, REG_SPI_COMMAND, writearr[i]); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: write count %d\n", __func__, i); + return 1; + } + } + + for (i = 0; i < readcnt; i++) { + /* Push data by clock the serial bus */ + ene_write(chip, REG_SPI_COMMAND, 0); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: read count %d\n", __func__, i); + return 1; + } + readarr[i] = ene_read(chip, REG_SPI_DATA); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: read count %d\n", __func__, i); + return 1; + } + } + + ene_spi_end(chip); + return 0; +} + +static int ene_leave_flash_mode(void *data) +{ + ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data; + const ene_chip_t *chip = ctx_data->chip; + int rv = 0; + uint8_t reg; + struct timeval begin, now; + + if (ctx_data->ec_state == EC_STATE_RESET) { + reg = ene_read(chip, REG_8051_CTRL); + reg &= ~CPU_RESET; + ene_write(chip, REG_8051_CTRL, reg); + + gettimeofday(&begin, NULL); + /* EC restart */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_running) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_RESTART_TIMEOUT) { + msg_pdbg("%s: ec restart busy\n", __func__); + rv = 1; + goto exit; + } + } + msg_pdbg("%s: send ec restart\n", __func__); + ec_command(chip, chip->ec_restart_cmd, + chip->ec_restart_data); + + ctx_data->ec_state = EC_STATE_NORMAL; + rv = 0; + goto exit; + } + + rv = ene_resume_ec(ctx_data); + +exit: + /* + * Trigger ec interrupt after pause/reset by sending 0x80 + * to bios command port. + */ + OUTB(0x80, chip->port_bios); + free(data); + return rv; +} + +static struct spi_master spi_master_ene = { + .max_data_read = 256, + .max_data_write = 256, + .command = ene_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, +}; + +int ene_lpc_init() +{ + uint8_t hwver, ediid, i; + int ret = 0; + char *p = NULL; + ene_lpc_data_t *ctx_data = NULL; + + msg_pdbg("%s\n", __func__); + + ctx_data = calloc(1, sizeof(ene_lpc_data_t)); + if (!ctx_data) { + msg_perr("Unable to allocate space for extra context data.\n"); + return 1; + } + ctx_data->ec_state = EC_STATE_NORMAL; + + p = extract_programmer_param("type"); + if (p && strcmp(p, "ec")) { + msg_pdbg("ene_lpc only supports "ec" type devices\n"); + ret = 1; + goto ene_probe_spi_flash_exit; + } + + for (i = 0; i < ENE_LAST; ++i) { + ctx_data->chip = &ene_chips[i]; + + hwver = ene_read(ctx_data->chip, REG_EC_HWVER); + ediid = ene_read(ctx_data->chip, REG_EC_EDIID); + + if(hwver == ene_chips[i].hwver && + ediid == ene_chips[i].ediid) { + break; + } + } + + if (i == ENE_LAST) { + msg_pdbg("ENE EC not found (probe failed)\n"); + ret = 1; + goto ene_probe_spi_flash_exit; + } + + /* TODO: probe the EC stop protocol + * + * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c + */ + + + if (register_shutdown(ene_leave_flash_mode, ctx_data)) { + ret = 1; + goto ene_probe_spi_flash_exit; + } + + ene_enter_flash_mode(ctx_data); + + internal_buses_supported |= BUS_LPC; + spi_master_ene.data = ctx_data; + register_spi_master(&spi_master_ene); + msg_pdbg("%s: successfully initialized ene\n", __func__); + +ene_probe_spi_flash_exit: + free(p); + if (ret) + free(ctx_data); + return ret; +} + +#endif /* __i386__ || __x86_64__ */ diff --git a/flashrom.c b/flashrom.c index 4a30986..35ac6f5 100644 --- a/flashrom.c +++ b/flashrom.c @@ -279,6 +279,18 @@ }, #endif
+#if CONFIG_ENE_LPC == 1 + { + .name = "ene_lpc", + .type = OTHER, + .devs.note = "ENE LPC interface keyboard controller\n", + .init = ene_lpc_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + #if CONFIG_RAYER_SPI == 1 { .name = "rayer_spi", diff --git a/meson.build b/meson.build index 04176f3..180b5dd 100644 --- a/meson.build +++ b/meson.build @@ -40,6 +40,7 @@ config_digilent_spi = get_option('config_digilent_spi') config_drkaiser = get_option('config_drkaiser') config_dummy = get_option('config_dummy') +config_ene_lpc = get_option('config_ene_lpc') config_ft2232_spi = get_option('config_ft2232_spi') config_gfxnvidia = get_option('config_gfxnvidia') config_raiden = get_option('config_raiden') @@ -202,6 +203,10 @@ cargs += '-DCONFIG_INTERNAL_DMI=1' endif endif +if config_ene_lpc + srcs += 'ene_lpc.c' + cargs += '-DCONFIG_ENE_LPC=1' +endif if config_it8212 srcs += 'it8212.c' cargs += '-DCONFIG_IT8212=1' diff --git a/meson_options.txt b/meson_options.txt index ac48e4e..ba5130b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,6 +11,7 @@ option('config_digilent_spi', type : 'boolean', value : true, description : 'Digilent Development board JTAG') option('config_drkaiser', type : 'boolean', value : true, description : 'Dr. Kaiser') option('config_dummy', type : 'boolean', value : true, description : 'dummy tracing') +option('config_ene_lpc', type : 'boolean', value : true, description : 'ENE LPC interface keyboard controller') option('config_ft2232_spi', type : 'boolean', value : true, description : 'FT2232 SPI dongles') option('config_gfxnvidia', type : 'boolean', value : true, description : 'NVIDIA graphics cards') option('config_raiden', type : 'boolean', value : true, description : 'ChromiumOS Servo DUT debug board') diff --git a/programmer.h b/programmer.h index c5cab18..b3bc700 100644 --- a/programmer.h +++ b/programmer.h @@ -61,6 +61,9 @@ #if CONFIG_ATAPROMISE == 1 PROGRAMMER_ATAPROMISE, #endif +#if CONFIG_ENE_LPC == 1 + PROGRAMMER_ENE_LPC, +#endif #if CONFIG_IT8212 == 1 PROGRAMMER_IT8212, #endif @@ -578,6 +581,11 @@ extern const struct dev_entry devs_digilent_spi[]; #endif
+/* ene_lpc.c */ +#if CONFIG_ENE_LPC == 1 +int ene_lpc_init(void); +#endif + /* jlink_spi.c */ #if CONFIG_JLINK_SPI == 1 int jlink_spi_init(void);
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 1: Code-Review+2
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 1:
(1 comment)
https://review.coreboot.org/c/flashrom/+/44580/1/ene_lpc.c File ene_lpc.c:
PS1: Is this license compatible with the rest of flashrom? If possible, it would be nice to have dual licensing (like on raiden_debug_spi.c)
Hello build bot (Jenkins), Nico Huber, Edward O'Callaghan, Angel Pons,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/44580
to look at the new patch set (#2).
Change subject: Add ENE LPC programmer ......................................................................
Add ENE LPC programmer
Initial support of ENE LPC interface keyboard controller.
BUG=b:156140422 BRANCH=none
Signed-off-by: Victor Ding victording@google.com Change-Id: I970afd8c1bd92c159c60e09f22e2f18c0433729d --- M Makefile A ene_lpc.c M flashrom.c M meson.build M meson_options.txt M programmer.h 6 files changed, 645 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/80/44580/2
Victor Ding has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 2:
(1 comment)
https://review.coreboot.org/c/flashrom/+/44580/1/ene_lpc.c File ene_lpc.c:
PS1:
Is this license compatible with the rest of flashrom? If possible, it would be nice to have dual lic […]
Thank you for reviewing. As the original authors, we can change the license. I've update it to the same one as `raiden_debug_spi.c`.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 2: Code-Review+2
Edward O'Callaghan has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 2: Code-Review+2
Edward O'Callaghan has submitted this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Add ENE LPC programmer
Initial support of ENE LPC interface keyboard controller.
BUG=b:156140422 BRANCH=none
Signed-off-by: Victor Ding victording@google.com Change-Id: I970afd8c1bd92c159c60e09f22e2f18c0433729d Reviewed-on: https://review.coreboot.org/c/flashrom/+/44580 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Angel Pons th3fanbus@gmail.com Reviewed-by: Edward O'Callaghan quasisec@chromium.org --- M Makefile A ene_lpc.c M flashrom.c M meson.build M meson_options.txt M programmer.h 6 files changed, 645 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved Edward O'Callaghan: Looks good to me, approved
diff --git a/Makefile b/Makefile index 803529f..85b4850 100644 --- a/Makefile +++ b/Makefile @@ -170,6 +170,11 @@ else override CONFIG_DEVELOPERBOX_SPI = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_FT2232_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else @@ -271,6 +276,11 @@ else override CONFIG_ATAPROMISE = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_IT8212), yes) UNSUPPORTED_FEATURES += CONFIG_IT8212=yes else @@ -381,6 +391,11 @@ else override CONFIG_DEVELOPERBOX_SPI = no endif +ifeq ($(CONFIG_ENE_LPC), yes) +UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes +else +override CONFIG_ENE_LPC = no +endif ifeq ($(CONFIG_FT2232_SPI), yes) UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else @@ -671,6 +686,9 @@ # Promise ATA controller support. CONFIG_ATAPROMISE ?= no
+# ENE LPC interface keyboard controller +CONFIG_ENE_LPC ?= yes + # Always enable FT2232 SPI dongles for now. CONFIG_FT2232_SPI ?= yes
@@ -855,6 +873,11 @@ NEED_LIBPCI += CONFIG_INTERNAL endif
+ifeq ($(CONFIG_ENE_LPC), yes) +FEATURE_CFLAGS += -D'CONFIG_ENE_LPC=1' +PROGRAMMER_OBJS += ene_lpc.o +endif + ifeq ($(CONFIG_SERPROG), yes) FEATURE_CFLAGS += -D'CONFIG_SERPROG=1' PROGRAMMER_OBJS += serprog.o diff --git a/ene_lpc.c b/ene_lpc.c new file mode 100644 index 0000000..56d6580 --- /dev/null +++ b/ene_lpc.c @@ -0,0 +1,596 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012-2020, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#if defined(__i386__) || defined(__x86_64__) +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + +#include "chipdrivers.h" +#include "flash.h" +#include "programmer.h" +#include "hwaccess.h" +#include "spi.h" + +/* MCU registers */ +#define REG_EC_HWVER 0xff00 +#define REG_EC_FWVER 0xff01 +#define REG_EC_EDIID 0xff24 +#define REG_8051_CTRL 0xff14 +#define REG_EC_EXTCMD 0xff10 + +#define CPU_RESET 1 + +/* MCU SPI peripheral registers */ +#define REG_SPI_DATA 0xfeab +#define REG_SPI_COMMAND 0xfeac +#define REG_SPI_CONFIG 0xfead + +#define CFG_CSn_FORCE_LOW (1 << 4) +#define CFG_COMMAND_WRITE_ENABLE (1 << 3) +#define CFG_STATUS (1 << 1) +#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0) + +/* Timeout */ +#define EC_COMMAND_TIMEOUT 4 +#define EC_RESTART_TIMEOUT 10 +#define ENE_SPI_DELAY_CYCLE 4 +#define EC_PAUSE_TIMEOUT 12 +#define EC_RESET_TRIES 3 + +#define ENE_KB94X_PAUSE_WAKEUP_PORT 0x64 + +#define MASK_INPUT_BUFFER_FULL 2 +#define MASK_OUTPUT_BUFFER_FULL 1 + +const int port_ene_bank = 1; +const int port_ene_offset = 2; +const int port_ene_data = 3; + +/* Supported ENE ECs, ENE_LAST should always be LAST member */ +enum ene_chip_id { + ENE_KB932 = 0, + ENE_KB94X, + ENE_LAST +}; + +/* EC state */ +enum ene_ec_state { + EC_STATE_NORMAL, + EC_STATE_IDLE, + EC_STATE_RESET, + EC_STATE_UNKNOWN +}; + +/* chip-specific parameters */ +typedef struct { + enum ene_chip_id chip_id; + uint8_t hwver; + uint8_t ediid; + uint32_t port_bios; + uint32_t port_ec_command; + uint32_t port_ec_data; + uint8_t ec_reset_cmd; + uint8_t ec_reset_data; + uint8_t ec_restart_cmd; + uint8_t ec_restart_data; + uint8_t ec_pause_cmd; + uint8_t ec_pause_data; + uint16_t ec_status_buf; + uint8_t ec_is_stopping; + uint8_t ec_is_running; + uint8_t ec_is_pausing; + uint32_t port_io_base; +} ene_chip_t; + +typedef struct +{ + /* pointer to table entry of identified chip */ + ene_chip_t *chip; + /* current ec state */ + enum ene_ec_state ec_state; + struct timeval pause_begin; +} ene_lpc_data_t; + +/* table of supported chips + parameters */ +static ene_chip_t ene_chips[] = { + { + ENE_KB932, /* chip_id */ + 0xa2, 0x02, /* hwver + ediid */ + 0x66, /* port_bios */ + 0x6c, 0x68, /* port_ec_{command,data} */ + 0x59, 0xf2, /* ec_reset_{cmd,data} */ + 0x59, 0xf9, /* ec_restart_{cmd,data} */ + 0x59, 0xf1, /* ec_pause_{cmd,data} */ + 0xf554, /* ec_status_buf */ + 0xa5, 0x00, /* ec_is_{stopping,running} masks */ + 0x33, /* ec_is_pausing mask */ + 0xfd60 /* port_io_base */ + }, + { + ENE_KB94X, /* chip_id */ + 0xa3, 0x05, /* hwver + ediid */ + 0x66, /* port_bios */ + 0x66, 0x68, /* port_ec_{command,data} */ + 0x7d, 0x10, /* ec_reset_{cmd,data} */ + 0x7f, 0x10, /* ec_restart_{cmd,data} */ + 0x7e, 0x10, /* ec_pause_{cmd,data} */ + 0xf710, /* ec_status_buf */ + 0x02, 0x00, /* ec_is_{stopping,running} masks */ + 0x01, /* ec_is_pausing mask */ + 0x0380 /* port_io_base */ + } +}; + +static void ec_command(const ene_chip_t *chip, uint8_t cmd, uint8_t data) +{ + struct timeval begin, now; + + /* Spin wait for EC input buffer empty */ + gettimeofday(&begin, NULL); + while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: buf not empty\n", __func__); + return; + } + } + + /* Write command */ + OUTB(cmd, chip->port_ec_command); + + if (chip->chip_id == ENE_KB932) { + /* Spin wait for EC input buffer empty */ + gettimeofday(&begin, NULL); + while (INB(chip->port_ec_command) & + MASK_INPUT_BUFFER_FULL) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: buf not empty\n", __func__); + return; + } + } + /* Write data */ + OUTB(data, chip->port_ec_data); + } +} + +static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr) +{ + uint8_t bank; + uint8_t offset; + uint8_t data; + uint32_t port_io_base; + + bank = addr >> 8; + offset = addr & 0xff; + port_io_base = chip->port_io_base; + + OUTB(bank, port_io_base + port_ene_bank); + OUTB(offset, port_io_base + port_ene_offset); + data = INB(port_io_base + port_ene_data); + + return data; +} + +static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data) +{ + uint8_t bank; + uint8_t offset; + uint32_t port_io_base; + + bank = addr >> 8; + offset = addr & 0xff; + port_io_base = chip->port_io_base; + + OUTB(bank, port_io_base + port_ene_bank); + OUTB(offset, port_io_base + port_ene_offset); + + OUTB(data, port_io_base + port_ene_data); +} + +/** + * wait_cycles, wait for n LPC bus clock cycles + * + * @param n: number of LPC cycles to wait + * @return void + */ +static void wait_cycles(const ene_chip_t *chip,int n) +{ + while (n--) + INB(chip->port_io_base + port_ene_bank); +} + +static int is_spicmd_write(uint8_t cmd) +{ + switch (cmd) { + case JEDEC_WREN: + /* Chip Write Enable */ + case JEDEC_EWSR: + /* Write Status Enable */ + case JEDEC_CE_60: + /* Chip Erase 0x60 */ + case JEDEC_CE_C7: + /* Chip Erase 0xc7 */ + case JEDEC_BE_52: + /* Block Erase 0x52 */ + case JEDEC_BE_D8: + /* Block Erase 0xd8 */ + case JEDEC_BE_D7: + /* Block Erase 0xd7 */ + case JEDEC_SE: + /* Sector Erase */ + case JEDEC_BYTE_PROGRAM: + /* Write memory byte */ + case JEDEC_AAI_WORD_PROGRAM: + /* Write AAI word */ + return 1; + } + return 0; +} + +static void ene_spi_start(const ene_chip_t *chip) +{ + int cfg; + + cfg = ene_read(chip, REG_SPI_CONFIG); + cfg |= CFG_CSn_FORCE_LOW; + cfg |= CFG_COMMAND_WRITE_ENABLE; + ene_write(chip, REG_SPI_CONFIG, cfg); + + wait_cycles(chip, ENE_SPI_DELAY_CYCLE); +} + +static void ene_spi_end(const ene_chip_t *chip) +{ + int cfg; + + cfg = ene_read(chip, REG_SPI_CONFIG); + cfg &= ~CFG_CSn_FORCE_LOW; + cfg |= CFG_COMMAND_WRITE_ENABLE; + ene_write(chip, REG_SPI_CONFIG, cfg); + + wait_cycles(chip, ENE_SPI_DELAY_CYCLE); +} + +static int ene_spi_wait(const ene_chip_t *chip) +{ + struct timeval begin, now; + + gettimeofday(&begin, NULL); + while(ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: spi busy\n", __func__); + return 1; + } + } + return 0; +} + +static int ene_pause_ec(ene_lpc_data_t *ctx_data) +{ + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + if (!chip->ec_pause_cmd) + return -1; + + /* EC prepare pause */ + ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data); + + gettimeofday(&begin, NULL); + /* Spin wait for EC ready */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_pausing) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to pause ec\n", __func__); + return -1; + } + } + + + gettimeofday(&ctx_data->pause_begin, NULL); + ctx_data->ec_state = EC_STATE_IDLE; + return 0; +} + +static int ene_resume_ec(ene_lpc_data_t *ctx_data) +{ + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + if (chip->chip_id == ENE_KB94X) + OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT); + else + /* Trigger 8051 interrupt to resume */ + ene_write(chip, REG_EC_EXTCMD, 0xff); + + gettimeofday(&begin, NULL); + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_running) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to resume ec\n", __func__); + return -1; + } + } + + ctx_data->ec_state = EC_STATE_NORMAL; + return 0; +} + +static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data) +{ + struct timeval pause_now; + gettimeofday(&pause_now, NULL); + if ((pause_now.tv_sec - ctx_data->pause_begin.tv_sec) >= + EC_PAUSE_TIMEOUT) { + if(ene_resume_ec(ctx_data) == 0) + ene_pause_ec(ctx_data); + + } + return 0; +} + +static int ene_reset_ec(ene_lpc_data_t *ctx_data) +{ + uint8_t reg; + struct timeval begin, now; + const ene_chip_t *chip = ctx_data->chip; + + gettimeofday(&begin, NULL); + + /* EC prepare reset */ + ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data); + + /* Spin wait for EC ready */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_stopping) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_COMMAND_TIMEOUT) { + msg_pdbg("%s: unable to reset ec\n", __func__); + return -1; + } + } + + /* Wait 1 second */ + sleep(1); + + /* Reset 8051 */ + reg = ene_read(chip, REG_8051_CTRL); + reg |= CPU_RESET; + ene_write(chip, REG_8051_CTRL, reg); + + ctx_data->ec_state = EC_STATE_RESET; + return 0; +} + +static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data) +{ + if (ene_pause_ec(ctx_data)) + return ene_reset_ec(ctx_data); + return 0; +} + +static int ene_spi_send_command(const struct flashctx *flash, + unsigned int writecnt, + unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned int i; + int tries = EC_RESET_TRIES; + ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data; + const ene_chip_t *chip = ctx_data->chip; + + if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) { + do { + /* Enter reset mode if we need to write/erase */ + if (ene_resume_ec(ctx_data)) + continue; + + if (!ene_reset_ec(ctx_data)) + break; + } while (--tries > 0); + + if (!tries) { + msg_perr("%s: EC failed reset, skipping write\n", __func__); + ctx_data->ec_state = EC_STATE_IDLE; + return 1; + } + } + else if(chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE) + ene_pause_timeout_check(ctx_data); + + ene_spi_start(chip); + + for (i = 0; i < writecnt; i++) { + ene_write(chip, REG_SPI_COMMAND, writearr[i]); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: write count %d\n", __func__, i); + return 1; + } + } + + for (i = 0; i < readcnt; i++) { + /* Push data by clock the serial bus */ + ene_write(chip, REG_SPI_COMMAND, 0); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: read count %d\n", __func__, i); + return 1; + } + readarr[i] = ene_read(chip, REG_SPI_DATA); + if (ene_spi_wait(chip)) { + msg_pdbg("%s: read count %d\n", __func__, i); + return 1; + } + } + + ene_spi_end(chip); + return 0; +} + +static int ene_leave_flash_mode(void *data) +{ + ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data; + const ene_chip_t *chip = ctx_data->chip; + int rv = 0; + uint8_t reg; + struct timeval begin, now; + + if (ctx_data->ec_state == EC_STATE_RESET) { + reg = ene_read(chip, REG_8051_CTRL); + reg &= ~CPU_RESET; + ene_write(chip, REG_8051_CTRL, reg); + + gettimeofday(&begin, NULL); + /* EC restart */ + while (ene_read(chip, chip->ec_status_buf) != + chip->ec_is_running) { + gettimeofday(&now, NULL); + if ((now.tv_sec - begin.tv_sec) >= + EC_RESTART_TIMEOUT) { + msg_pdbg("%s: ec restart busy\n", __func__); + rv = 1; + goto exit; + } + } + msg_pdbg("%s: send ec restart\n", __func__); + ec_command(chip, chip->ec_restart_cmd, + chip->ec_restart_data); + + ctx_data->ec_state = EC_STATE_NORMAL; + rv = 0; + goto exit; + } + + rv = ene_resume_ec(ctx_data); + +exit: + /* + * Trigger ec interrupt after pause/reset by sending 0x80 + * to bios command port. + */ + OUTB(0x80, chip->port_bios); + free(data); + return rv; +} + +static struct spi_master spi_master_ene = { + .max_data_read = 256, + .max_data_write = 256, + .command = ene_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, +}; + +int ene_lpc_init() +{ + uint8_t hwver, ediid, i; + int ret = 0; + char *p = NULL; + ene_lpc_data_t *ctx_data = NULL; + + msg_pdbg("%s\n", __func__); + + ctx_data = calloc(1, sizeof(ene_lpc_data_t)); + if (!ctx_data) { + msg_perr("Unable to allocate space for extra context data.\n"); + return 1; + } + ctx_data->ec_state = EC_STATE_NORMAL; + + p = extract_programmer_param("type"); + if (p && strcmp(p, "ec")) { + msg_pdbg("ene_lpc only supports "ec" type devices\n"); + ret = 1; + goto ene_probe_spi_flash_exit; + } + + for (i = 0; i < ENE_LAST; ++i) { + ctx_data->chip = &ene_chips[i]; + + hwver = ene_read(ctx_data->chip, REG_EC_HWVER); + ediid = ene_read(ctx_data->chip, REG_EC_EDIID); + + if(hwver == ene_chips[i].hwver && + ediid == ene_chips[i].ediid) { + break; + } + } + + if (i == ENE_LAST) { + msg_pdbg("ENE EC not found (probe failed)\n"); + ret = 1; + goto ene_probe_spi_flash_exit; + } + + /* TODO: probe the EC stop protocol + * + * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c + */ + + + if (register_shutdown(ene_leave_flash_mode, ctx_data)) { + ret = 1; + goto ene_probe_spi_flash_exit; + } + + ene_enter_flash_mode(ctx_data); + + internal_buses_supported |= BUS_LPC; + spi_master_ene.data = ctx_data; + register_spi_master(&spi_master_ene); + msg_pdbg("%s: successfully initialized ene\n", __func__); + +ene_probe_spi_flash_exit: + free(p); + if (ret) + free(ctx_data); + return ret; +} + +#endif /* __i386__ || __x86_64__ */ diff --git a/flashrom.c b/flashrom.c index 4a30986..35ac6f5 100644 --- a/flashrom.c +++ b/flashrom.c @@ -279,6 +279,18 @@ }, #endif
+#if CONFIG_ENE_LPC == 1 + { + .name = "ene_lpc", + .type = OTHER, + .devs.note = "ENE LPC interface keyboard controller\n", + .init = ene_lpc_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + #if CONFIG_RAYER_SPI == 1 { .name = "rayer_spi", diff --git a/meson.build b/meson.build index 04176f3..180b5dd 100644 --- a/meson.build +++ b/meson.build @@ -40,6 +40,7 @@ config_digilent_spi = get_option('config_digilent_spi') config_drkaiser = get_option('config_drkaiser') config_dummy = get_option('config_dummy') +config_ene_lpc = get_option('config_ene_lpc') config_ft2232_spi = get_option('config_ft2232_spi') config_gfxnvidia = get_option('config_gfxnvidia') config_raiden = get_option('config_raiden') @@ -202,6 +203,10 @@ cargs += '-DCONFIG_INTERNAL_DMI=1' endif endif +if config_ene_lpc + srcs += 'ene_lpc.c' + cargs += '-DCONFIG_ENE_LPC=1' +endif if config_it8212 srcs += 'it8212.c' cargs += '-DCONFIG_IT8212=1' diff --git a/meson_options.txt b/meson_options.txt index ac48e4e..ba5130b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,6 +11,7 @@ option('config_digilent_spi', type : 'boolean', value : true, description : 'Digilent Development board JTAG') option('config_drkaiser', type : 'boolean', value : true, description : 'Dr. Kaiser') option('config_dummy', type : 'boolean', value : true, description : 'dummy tracing') +option('config_ene_lpc', type : 'boolean', value : true, description : 'ENE LPC interface keyboard controller') option('config_ft2232_spi', type : 'boolean', value : true, description : 'FT2232 SPI dongles') option('config_gfxnvidia', type : 'boolean', value : true, description : 'NVIDIA graphics cards') option('config_raiden', type : 'boolean', value : true, description : 'ChromiumOS Servo DUT debug board') diff --git a/programmer.h b/programmer.h index c5cab18..b3bc700 100644 --- a/programmer.h +++ b/programmer.h @@ -61,6 +61,9 @@ #if CONFIG_ATAPROMISE == 1 PROGRAMMER_ATAPROMISE, #endif +#if CONFIG_ENE_LPC == 1 + PROGRAMMER_ENE_LPC, +#endif #if CONFIG_IT8212 == 1 PROGRAMMER_IT8212, #endif @@ -578,6 +581,11 @@ extern const struct dev_entry devs_digilent_spi[]; #endif
+/* ene_lpc.c */ +#if CONFIG_ENE_LPC == 1 +int ene_lpc_init(void); +#endif + /* jlink_spi.c */ #if CONFIG_JLINK_SPI == 1 int jlink_spi_init(void);
Attention is currently required from: Victor Ding. Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(1 comment)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/c6ea2e6b_953f1329 PS3, Line 177: endif Why?
Attention is currently required from: Victor Ding. Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(1 comment)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/d0bd956e_35a61f0c PS3, Line 398: endif Why?
Victor Ding has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(2 comments)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/ee2cda66_465b40a0 PS3, Line 177: endif
Why?
The code was ported from Chromium's flashrom fork, I don't think it has ever been verified on DOS; therefore, I decided this configuration shouldn't be allowed until tested when submitting this patch. WDYT?
https://review.coreboot.org/c/flashrom/+/44580/comment/ffca9ecf_af15850c PS3, Line 398: endif
Why?
The code was ported from Chromium's flashrom fork, I don't think it has ever been verified on libpayload; therefore, I decided this configuration shouldn't be allowed until tested when submitting this patch. WDYT?
Attention is currently required from: Victor Ding. Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(1 comment)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/328ad7a2_a994a4df PS3, Line 177: endif
The code was ported from Chromium's flashrom fork, I don't think it has ever been verified on DOS; t […]
We do not verify every change to common code on DOS either. What makes this code special so that it needs extra verification, I wouldn't know. But it's good to know that there was a reason. As it was placed below the libusb comment, it looked like an accident.
Victor Ding has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(1 comment)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/b2d76b72_6477e50e PS3, Line 177: endif
We do not verify every change to common code on DOS either. What makes this […]
There is nothing special. I thought they had to be verified but I was unable to test them. I'll create a patch to allow them build again DOS and libpayload.
Attention is currently required from: Victor Ding. Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(1 comment)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/fc55a63d_1ec0190a PS3, Line 177: endif
There is nothing special.
Good to know.
I thought they had to be verified but I was unable to test them.
I understand that testing on exotic platforms is annoying. However, you (and everyone else) can use `util/manibuilder` to build-test flashrom on many different platforms, including DOS using DJGPP (DJ's GNU Programming Platform). The toolchain that DJGPP uses is rather unusual, and can catch subtle issues like the one CB:52473 fixed.
I'll create a patch to allow them build again DOS and libpayload.
CB:55889 for ENE, CB:55890 for MEC1308.
Victor Ding has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/44580 )
Change subject: Add ENE LPC programmer ......................................................................
Patch Set 3:
(2 comments)
File Makefile:
https://review.coreboot.org/c/flashrom/+/44580/comment/8fa68765_49577d92 PS3, Line 177: endif
There is nothing special. […]
The programmer has been deleted by CB:56475.
https://review.coreboot.org/c/flashrom/+/44580/comment/bcf495e1_71ea934c PS3, Line 398: endif
The code was ported from Chromium's flashrom fork, I don't think it has ever been verified on libpay […]
The programmer has been deleted by CB:56475.