summaryrefslogtreecommitdiffstats
path: root/ene_lpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ene_lpc.c')
-rw-r--r--ene_lpc.c596
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__ */