diff options
Diffstat (limited to 'ene_lpc.c')
-rw-r--r-- | ene_lpc.c | 596 |
1 files changed, 0 insertions, 596 deletions
diff --git a/ene_lpc.c b/ene_lpc.c deleted file mode 100644 index 56d65807b..000000000 --- a/ene_lpc.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * 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__ */ |