mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 15:12:36 +02:00
Add MEC1308 EC programmer
Initial support of Microchip MEC1308 Embedded Controller. BUG=b:156144893 BRANCH=none Signed-off-by: Victor Ding <victording@google.com> Change-Id: I2d51b4bdc0b38b6e488e71b9e774eb6232a2069e Reviewed-on: https://review.coreboot.org/c/flashrom/+/44541 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
This commit is contained in:
parent
436b4155b1
commit
821e44cb4d
23
Makefile
23
Makefile
@ -180,6 +180,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
|
||||
else
|
||||
override CONFIG_FT2232_SPI = no
|
||||
endif
|
||||
ifeq ($(CONFIG_MEC1308), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
|
||||
else
|
||||
override CONFIG_MEC1308 = no
|
||||
endif
|
||||
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
|
||||
else
|
||||
@ -291,6 +296,11 @@ UNSUPPORTED_FEATURES += CONFIG_DRKAISER=yes
|
||||
else
|
||||
override CONFIG_DRKAISER = no
|
||||
endif
|
||||
ifeq ($(CONFIG_MEC1308), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
|
||||
else
|
||||
override CONFIG_MEC1308 = no
|
||||
endif
|
||||
ifeq ($(CONFIG_NICREALTEK), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
|
||||
else
|
||||
@ -401,6 +411,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
|
||||
else
|
||||
override CONFIG_FT2232_SPI = no
|
||||
endif
|
||||
ifeq ($(CONFIG_MEC1308), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
|
||||
else
|
||||
override CONFIG_MEC1308 = no
|
||||
endif
|
||||
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
|
||||
UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
|
||||
else
|
||||
@ -692,6 +707,9 @@ CONFIG_ENE_LPC ?= yes
|
||||
# Always enable FT2232 SPI dongles for now.
|
||||
CONFIG_FT2232_SPI ?= yes
|
||||
|
||||
# Microchip MEC1308 Embedded Controller
|
||||
CONFIG_MEC1308 ?= yes
|
||||
|
||||
# Always enable Altera USB-Blaster dongles for now.
|
||||
CONFIG_USBBLASTER_SPI ?= yes
|
||||
|
||||
@ -878,6 +896,11 @@ FEATURE_CFLAGS += -D'CONFIG_ENE_LPC=1'
|
||||
PROGRAMMER_OBJS += ene_lpc.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MEC1308), yes)
|
||||
FEATURE_CFLAGS += -D'CONFIG_MEC1308=1'
|
||||
PROGRAMMER_OBJS += mec1308.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SERPROG), yes)
|
||||
FEATURE_CFLAGS += -D'CONFIG_SERPROG=1'
|
||||
PROGRAMMER_OBJS += serprog.o
|
||||
|
12
flashrom.c
12
flashrom.c
@ -84,6 +84,18 @@ const struct programmer_entry programmer_table[] = {
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CONFIG_MEC1308 == 1
|
||||
{
|
||||
.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
|
||||
|
||||
#if CONFIG_NIC3COM == 1
|
||||
{
|
||||
.name = "nic3com",
|
||||
|
523
mec1308.c
Normal file
523
mec1308.c
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* 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 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,
|
||||
};
|
||||
|
||||
int mec1308_init(void)
|
||||
{
|
||||
uint16_t sio_port;
|
||||
uint8_t device_id;
|
||||
uint8_t tmp8;
|
||||
int ret = 0;
|
||||
char *p = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
p = extract_programmer_param("type");
|
||||
if (p && strcmp(p, "ec")) {
|
||||
msg_pdbg("mec1308 only supports \"ec\" type devices\n");
|
||||
ret = 1;
|
||||
goto mec1308_init_exit;
|
||||
}
|
||||
|
||||
if (mec1308_get_sio_index(ctx_data, &sio_port) < 0) {
|
||||
msg_pdbg("MEC1308 not found (probe failed).\n");
|
||||
ret = 1;
|
||||
goto mec1308_init_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");
|
||||
ret = 1;
|
||||
goto mec1308_init_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__);
|
||||
ret = 1;
|
||||
goto mec1308_init_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__);
|
||||
ret = 1;
|
||||
goto mec1308_init_exit;
|
||||
}
|
||||
|
||||
if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_DISABLE)) {
|
||||
msg_pdbg("%s: unable to disable SMI\n", __func__);
|
||||
ret = 1;
|
||||
goto mec1308_init_exit;
|
||||
}
|
||||
|
||||
if (register_shutdown(mec1308_shutdown, ctx_data)) {
|
||||
ret = 1;
|
||||
goto mec1308_init_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)) {
|
||||
ret = 1;
|
||||
goto mec1308_init_exit;
|
||||
}
|
||||
|
||||
internal_buses_supported |= BUS_LPC; /* for LPC <--> SPI bridging */
|
||||
spi_master_mec1308.data = ctx_data;
|
||||
register_spi_master(&spi_master_mec1308);
|
||||
msg_pdbg("%s(): successfully initialized mec1308\n", __func__);
|
||||
|
||||
mec1308_init_exit:
|
||||
free(p);
|
||||
if (ret)
|
||||
free(ctx_data);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
@ -48,6 +48,7 @@ config_internal = get_option('config_internal')
|
||||
config_it8212 = get_option('config_it8212')
|
||||
config_linux_mtd = get_option('config_linux_mtd')
|
||||
config_linux_spi = get_option('config_linux_spi')
|
||||
config_mec1308 = get_option('config_mec1308')
|
||||
config_mstarddc_spi = get_option('config_mstarddc_spi')
|
||||
config_nic3com = get_option('config_nic3com')
|
||||
config_nicintel_eeprom = get_option('config_nicintel_eeprom')
|
||||
@ -219,6 +220,10 @@ if config_linux_spi
|
||||
srcs += 'linux_spi.c'
|
||||
cargs += '-DCONFIG_LINUX_SPI=1'
|
||||
endif
|
||||
if config_mec1308
|
||||
srcs += 'mec1308.c'
|
||||
cargs += '-DCONFIG_MEC1308=1'
|
||||
endif
|
||||
if config_mstarddc_spi
|
||||
srcs += 'mstarddc_spi.c'
|
||||
cargs += '-DCONFIG_MSTARDDC_SPI=1'
|
||||
|
@ -20,6 +20,7 @@ option('config_internal_dmi', type : 'boolean', value : true, description : 'Use
|
||||
option('config_it8212', type : 'boolean', value : true, description : 'ITE IT8212F PATA')
|
||||
option('config_linux_mtd', type : 'boolean', value : true, description : 'Linux MTD interfaces')
|
||||
option('config_linux_spi', type : 'boolean', value : true, description : 'Linux spidev interfaces')
|
||||
option('config_mec1308', type : 'boolean', value : true, description : 'Microchip MEC1308 Embedded Controller')
|
||||
option('config_mstarddc_spi', type : 'boolean', value : false, description : 'MSTAR DDC support')
|
||||
option('config_nic3com', type : 'boolean', value : true, description : '3Com NICs')
|
||||
option('config_nicintel_eeprom', type : 'boolean', value : true, description : 'EEPROM on Intel NICs')
|
||||
|
@ -112,6 +112,9 @@ enum programmer {
|
||||
#if CONFIG_USBBLASTER_SPI == 1
|
||||
PROGRAMMER_USBBLASTER_SPI,
|
||||
#endif
|
||||
#if CONFIG_MEC1308 == 1
|
||||
PROGRAMMER_MEC1308,
|
||||
#endif
|
||||
#if CONFIG_MSTARDDC_SPI == 1
|
||||
PROGRAMMER_MSTARDDC_SPI,
|
||||
#endif
|
||||
@ -697,6 +700,11 @@ static inline int try_mtd(void) { return 1; };
|
||||
/* mcp6x_spi.c */
|
||||
int mcp6x_spi_init(int want_spi);
|
||||
|
||||
/* mec1308.c */
|
||||
#if CONFIG_MEC1308 == 1
|
||||
int mec1308_init(void);
|
||||
#endif
|
||||
|
||||
/* sb600spi.c */
|
||||
int sb600_probe_spi(struct pci_dev *dev);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user