diff options
Diffstat (limited to 'mec1308.c')
-rw-r--r-- | mec1308.c | 532 |
1 files changed, 0 insertions, 532 deletions
diff --git a/mec1308.c b/mec1308.c deleted file mode 100644 index e9c621494..000000000 --- a/mec1308.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * This file is part of the flashrom project. - * - * Copyright (C) 2010-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 "flash.h" -#include "hwaccess.h" -#include "chipdrivers.h" -#include "programmer.h" -#include "spi.h" - -#define MEC1308_SIO_PORT1 0x2e -#define MEC1308_SIO_PORT2 0x4e -#define MEC1308_SIO_ENTRY_KEY 0x55 -#define MEC1308_SIO_EXIT_KEY 0xaa - -#define MEC1308_SIOCFG_LDN 0x07 /* LDN Bank Selector */ -#define MEC1308_DEVICE_ID_REG 0x20 /* Device ID Register */ -#define MEC1308_DEVICE_ID_VAL 0x4d /* Device ID Value for MEC1308 */ -#define MEC1310_DEVICE_ID_VAL 0x04 /* Device ID Value for MEC1310 */ -#define MEC1308_DEVICE_REV 0x21 /* Device Revision ID Register */ - -#define MEC1308_MBX_CMD 0x82 /* mailbox command register offset */ -#define MEC1308_MBX_EXT_CMD 0x83 /* mailbox ext. command reg offset */ -#define MEC1308_MBX_DATA_START 0x84 /* first mailbox data register offset */ -#define MEC1308_MBX_DATA_END 0x91 /* last mailbox data register offset */ - -static unsigned int mbx_data; /* Mailbox register interface data address*/ - -/* - * These command codes depend on EC firmware. The ones listed below are input - * using the mailbox interface, though others may be input using the ACPI - * interface. Some commands also have an output value (ie pass/failure code) - * which EC writes to the mailbox command register after completion. - */ -#define MEC1308_CMD_SMI_ENABLE 0x84 -#define MEC1308_CMD_SMI_DISABLE 0x85 -#define MEC1308_CMD_ACPI_ENABLE 0x86 -#define MEC1308_CMD_ACPI_DISABLE 0x87 - -/* - * Passthru commands are also input using the mailbox interface. Passthru mode - * enter/start/end commands are special since they require a command word to - * be written to the data registers. Other passthru commands are performed - * after passthru mode has been started. - * - * Multiple passthru mode commands may be issued before ending passthru mode. - * You do not need to enter, start, and end passthru mode for each SPI - * command. However, other mailbox commands might not work when passthru mode - * is enabled. For example, you may read all SPI chip content while in passthru - * mode, but you should exit passthru mode before performing other EC commands - * such as reading fan speed. - */ -#define MEC1308_CMD_PASSTHRU 0x55 /* force EC to process word */ -#define MEC1308_CMD_PASSTHRU_SUCCESS 0xaa /* success code for passthru */ -#define MEC1308_CMD_PASSTHRU_FAIL 0xfe /* failure code for passthru */ -#define MEC1308_CMD_PASSTHRU_ENTER "PathThruMode" /* not a typo... */ -#define MEC1308_CMD_PASSTHRU_START "Start" -#define MEC1308_CMD_PASSTHRU_EXIT "End_Mode" -#define MEC1308_CMD_PASSTHRU_CS_EN 0xf0 /* chip-select enable */ -#define MEC1308_CMD_PASSTHRU_CS_DIS 0xf1 /* chip-select disable */ -#define MEC1308_CMD_PASSTHRU_SEND 0xf2 /* send byte from data0 */ -#define MEC1308_CMD_PASSTHRU_READ 0xf3 /* read byte, place in data0 */ - -typedef struct -{ - unsigned int in_sio_cfgmode; - unsigned int mbx_idx; /* Mailbox register interface index address */ - unsigned int mbx_data; /* Mailbox register interface data address*/ -} mec1308_data_t; - -static void mec1308_sio_enter(mec1308_data_t *ctx_data, uint16_t port) -{ - if (ctx_data->in_sio_cfgmode) - return; - - OUTB(MEC1308_SIO_ENTRY_KEY, port); - ctx_data->in_sio_cfgmode = 1; -} - -static void mec1308_sio_exit(mec1308_data_t *ctx_data, uint16_t port) -{ - if (!ctx_data->in_sio_cfgmode) - return; - - OUTB(MEC1308_SIO_EXIT_KEY, port); - ctx_data->in_sio_cfgmode = 0; -} - -/** probe for super i/o index - * @port: allocated buffer to store port - * - * returns 0 to indicate success, <0 to indicate error - */ -static int mec1308_get_sio_index(mec1308_data_t *ctx_data, uint16_t *port) -{ - uint16_t ports[] = { MEC1308_SIO_PORT1, - MEC1308_SIO_PORT2, - }; - size_t i; - static uint16_t port_internal, port_found = 0; - - if (port_found) { - *port = port_internal; - return 0; - } - - if (rget_io_perms()) - return -1; - - for (i = 0; i < ARRAY_SIZE(ports); i++) { - uint8_t tmp8; - - /* - * Only after config mode has been successfully entered will the - * index port will read back the last value written to it. - * So we will attempt to enter config mode, set the index - * register, and see if the index register retains the value. - * - * Note: It seems to work "best" when using a device ID register - * as the index and reading from the data port before reading - * the index port. - */ - mec1308_sio_enter(ctx_data, ports[i]); - OUTB(MEC1308_DEVICE_ID_REG, ports[i]); - tmp8 = INB(ports[i] + 1); - tmp8 = INB(ports[i]); - if ((tmp8 != MEC1308_DEVICE_ID_REG)) { - ctx_data->in_sio_cfgmode = 0; - continue; - } - - port_internal = ports[i]; - port_found = 1; - break; - } - - if (!port_found) { - msg_cdbg("\nfailed to obtain super i/o index\n"); - return -1; - } - - msg_cdbg("\nsuper i/o index = 0x%04x\n", port_internal); - *port = port_internal; - return 0; -} - -static uint8_t mbx_read(mec1308_data_t *ctx_data, uint8_t idx) -{ - OUTB(idx, ctx_data->mbx_idx); - return INB(mbx_data); -} - -static int mbx_wait(mec1308_data_t *ctx_data) -{ - int i; - int max_attempts = 10000; - int rc = 0; - - for (i = 0; mbx_read(ctx_data, MEC1308_MBX_CMD); i++) { - if (i == max_attempts) { - rc = 1; - break; - } - /* FIXME: This delay adds determinism to the delay period. It - was chosen arbitrarily thru some experiments. */ - programmer_delay(2); - } - - return rc; -} - -static int mbx_write(mec1308_data_t *ctx_data, uint8_t idx, uint8_t data) -{ - int rc = 0; - - if (idx == MEC1308_MBX_CMD && mbx_wait(ctx_data)) { - msg_perr("%s: command register not clear\n", __func__); - return 1; - } - - OUTB(idx, ctx_data->mbx_idx); - OUTB(data, mbx_data); - - if (idx == MEC1308_MBX_CMD) - rc = mbx_wait(ctx_data); - - return rc; -} - -static void mbx_clear(mec1308_data_t *ctx_data) -{ - int reg; - - for (reg = MEC1308_MBX_DATA_START; reg < MEC1308_MBX_DATA_END; reg++) - mbx_write(ctx_data, reg, 0x00); - mbx_write(ctx_data, MEC1308_MBX_CMD, 0x00); -} - -static int mec1308_exit_passthru_mode(mec1308_data_t *ctx_data) -{ - uint8_t tmp8; - size_t i; - - /* exit passthru mode */ - for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_EXIT); i++) { - mbx_write(ctx_data, MEC1308_MBX_DATA_START + i, - MEC1308_CMD_PASSTHRU_EXIT[i]); - } - - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) { - msg_pdbg("%s(): exit passthru command timed out\n", __func__); - return 1; - } - - tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START); - msg_pdbg("%s: result: 0x%02x ", __func__, tmp8); - if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS) { - msg_pdbg("(exited passthru mode)\n"); - } else if (tmp8 == MEC1308_CMD_PASSTHRU_FAIL) { - msg_pdbg("(failed to exit passthru mode)\n"); - } - - return 0; -} - -static int enter_passthru_mode(mec1308_data_t *ctx_data) -{ - uint8_t tmp8; - size_t i; - - /* - * Enter passthru mode. If the EC does not successfully enter passthru - * mode the first time, we'll clear the mailbox and issue the "exit - * passthru mode" command sequence up to 3 times or until it arrives in - * a known state. - * - * Note: This workaround was developed experimentally. - */ - for (i = 0; i < 3; i++) { - size_t j; - - msg_pdbg("%s(): entering passthru mode, attempt %d out of 3\n", - __func__, (int)(i + 1)); - for (j = 0; j < strlen(MEC1308_CMD_PASSTHRU_ENTER); j++) { - mbx_write(ctx_data, MEC1308_MBX_DATA_START + j, - MEC1308_CMD_PASSTHRU_ENTER[j]); - } - - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) - msg_pdbg("%s(): enter passthru command timed out\n", - __func__); - - tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START); - if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS) - break; - - msg_pdbg("%s(): command failed, clearing data registers and " - "issuing full exit passthru command...\n", __func__); - mbx_clear(ctx_data); - mec1308_exit_passthru_mode(ctx_data); - } - - if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) { - msg_perr("%s(): failed to enter passthru mode, result=0x%02x\n", - __func__, tmp8); - return 1; - } - - msg_pdbg("%s(): enter passthru mode return code: 0x%02x\n", - __func__, tmp8); - - /* start passthru mode */ - for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_START); i++) - mbx_write(ctx_data, MEC1308_MBX_DATA_START + i, - MEC1308_CMD_PASSTHRU_START[i]); - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) { - msg_pdbg("%s(): start passthru command timed out\n", __func__); - return 1; - } - tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START); - if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) { - msg_perr("%s(): failed to enter passthru mode, result=%02x\n", - __func__, tmp8); - return 1; - } - msg_pdbg("%s(): start passthru mode return code: 0x%02x\n", - __func__, tmp8); - - return 0; -} - -static int mec1308_shutdown(void *data) -{ - mec1308_data_t *ctx_data = (mec1308_data_t *)data; - - /* Exit passthru mode before performing commands which do not affect - the SPI ROM */ - mec1308_exit_passthru_mode(ctx_data); - - /* Re-enable SMI and ACPI. - FIXME: is there an ordering dependency? */ - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_ENABLE)) - msg_pdbg("%s: unable to re-enable SMI\n", __func__); - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_ENABLE)) - msg_pdbg("%s: unable to re-enable ACPI\n", __func__); - - free(data); - return 0; -} - -static int mec1308_chip_select(mec1308_data_t *ctx_data) -{ - return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_EN); -} - -static int mec1308_chip_deselect(mec1308_data_t *ctx_data) -{ - return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_DIS); -} - -/* - * MEC1308 will not allow direct access to SPI chip from host if EC is - * connected to LPC bus. This function will forward commands issued thru - * mailbox interface to the SPI flash chip. - */ -static int mec1308_spi_send_command(const struct flashctx *flash, unsigned int writecnt, - unsigned int readcnt, - const unsigned char *writearr, - unsigned char *readarr) -{ - int rc = 0; - size_t i; - mec1308_data_t *ctx_data = (mec1308_data_t *)flash->mst->spi.data; - - if (mec1308_chip_select(ctx_data)) - return 1; - - for (i = 0; i < writecnt; i++) { - if (mbx_write(ctx_data, MEC1308_MBX_DATA_START, writearr[i]) || - mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_SEND)) { - msg_pdbg("%s: failed to issue send command\n",__func__); - rc = 1; - goto mec1308_spi_send_command_exit; - } - } - - for (i = 0; i < readcnt; i++) { - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_READ)) { - msg_pdbg("%s: failed to issue read command\n",__func__); - rc = 1; - goto mec1308_spi_send_command_exit; - } - readarr[i] = mbx_read(ctx_data, MEC1308_MBX_DATA_START); - } - -mec1308_spi_send_command_exit: - rc |= mec1308_chip_deselect(ctx_data); - return rc; -} - -static const struct spi_master spi_master_mec1308 = { - .max_data_read = 256, /* FIXME: should be MAX_DATA_READ_UNLIMITED? */ - .max_data_write = 256, /* FIXME: should be MAX_DATA_WRITE_UNLIMITED? */ - .command = mec1308_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = default_spi_read, - .write_256 = default_spi_write_256, - .write_aai = default_spi_write_aai, - .shutdown = mec1308_shutdown, -}; - -static int check_params(void) -{ - int ret = 0; - char *const p = extract_programmer_param("type"); - if (p && strcmp(p, "ec")) { - msg_pdbg("mec1308 only supports \"ec\" type devices\n"); - ret = 1; - } - - free(p); - return ret; -} - -static int mec1308_init(void) -{ - uint16_t sio_port; - uint8_t device_id; - uint8_t tmp8; - mec1308_data_t *ctx_data = NULL; - - msg_pdbg("%s(): entered\n", __func__); - - ctx_data = calloc(1, sizeof(mec1308_data_t)); - if (!ctx_data) { - msg_perr("Unable to allocate space for extra context data.\n"); - return 1; - } - - if (check_params()) - goto init_err_exit; - - if (mec1308_get_sio_index(ctx_data, &sio_port) < 0) { - msg_pdbg("MEC1308 not found (probe failed).\n"); - goto init_err_exit; - } - device_id = sio_read(sio_port, MEC1308_DEVICE_ID_REG); - switch(device_id) { - case MEC1308_DEVICE_ID_VAL: - msg_pdbg("Found EC: MEC1308 (ID:0x%02x,Rev:0x%02x) on " - "sio_port:0x%x.\n", device_id, - sio_read(sio_port, MEC1308_DEVICE_REV), sio_port); - break; - case MEC1310_DEVICE_ID_VAL: - msg_pdbg("Found EC: MEC1310 (ID:0x%02x,Rev:0x%02x) on " - "sio_port:0x%x.\n", device_id, - sio_read(sio_port, MEC1308_DEVICE_REV), sio_port); - break; - default: - msg_pdbg("MEC1308 not found\n"); - goto init_err_exit; - } - - /* - * setup mailbox interface at LDN 9 - */ - sio_write(sio_port, MEC1308_SIOCFG_LDN, 0x09); - tmp8 = sio_read(sio_port, 0x30); - tmp8 |= 1; - sio_write(sio_port, 0x30, tmp8); /* activate logical device */ - - ctx_data->mbx_idx = (unsigned int)sio_read(sio_port, 0x60) << 8 | - sio_read(sio_port, 0x61); - mbx_data = ctx_data->mbx_idx + 1; - msg_pdbg("%s: mbx_idx: 0x%04x, mbx_data: 0x%04x\n", - __func__, ctx_data->mbx_idx, mbx_data); - - /* Exit Super I/O config mode */ - mec1308_sio_exit(ctx_data, sio_port); - - /* Now that we can read the mailbox, we will wait for any remaining - * command to finish.*/ - if (mbx_wait(ctx_data) != 0) { - msg_perr("%s: mailbox is not available\n", __func__); - goto init_err_exit; - } - - /* Further setup -- disable SMI and ACPI. - FIXME: is there an ordering dependency? */ - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_DISABLE)) { - msg_pdbg("%s: unable to disable ACPI\n", __func__); - goto init_err_exit; - } - - if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_DISABLE)) { - msg_pdbg("%s: unable to disable SMI\n", __func__); - goto init_err_exit; - } - - /* - * Enter SPI Pass-Thru Mode after commands which do not require access - * to SPI ROM are complete. We'll start by doing the exit_passthru_mode - * sequence, which is benign if the EC is already in passthru mode. - */ - mec1308_exit_passthru_mode(ctx_data); - - if (enter_passthru_mode(ctx_data)) - goto init_err_cleanup_exit; - - internal_buses_supported |= BUS_LPC; /* for LPC <--> SPI bridging */ - - return register_spi_master(&spi_master_mec1308, ctx_data); - -init_err_cleanup_exit: - mec1308_shutdown(ctx_data); - return 1; - -init_err_exit: - free(ctx_data); - return 1; -} - -const struct programmer_entry programmer_mec1308 = { - .name = "mec1308", - .type = OTHER, - .devs.note = "Microchip MEC1308 Embedded Controller.\n", - .init = mec1308_init, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, - .delay = internal_delay, -}; - -#endif |