summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/mec1322_evb/board.h1
-rw-r--r--board/mec1322_evb/ec.tasklist1
-rw-r--r--chip/mec1322/build.mk1
-rw-r--r--chip/mec1322/config_chip.h2
-rw-r--r--chip/mec1322/lpc.c168
-rw-r--r--chip/mec1322/registers.h8
6 files changed, 179 insertions, 2 deletions
diff --git a/board/mec1322_evb/board.h b/board/mec1322_evb/board.h
index ab0c734657..6d44570dbb 100644
--- a/board/mec1322_evb/board.h
+++ b/board/mec1322_evb/board.h
@@ -17,7 +17,6 @@
#undef CONFIG_EOPTION
#undef CONFIG_PSTORE
#undef CONFIG_LID_SWITCH
-#undef CONFIG_LPC
#undef CONFIG_PECI
#undef CONFIG_SWITCH
diff --git a/board/mec1322_evb/ec.tasklist b/board/mec1322_evb/ec.tasklist
index d3ac489b42..09bcb6e06c 100644
--- a/board/mec1322_evb/ec.tasklist
+++ b/board/mec1322_evb/ec.tasklist
@@ -18,4 +18,5 @@
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
diff --git a/chip/mec1322/build.mk b/chip/mec1322/build.mk
index 3c0e4c357f..8ee67de6aa 100644
--- a/chip/mec1322/build.mk
+++ b/chip/mec1322/build.mk
@@ -13,5 +13,6 @@ CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4
# Required chip modules
chip-y=clock.o gpio.o hwtimer.o system.o uart.o jtag.o
+chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
diff --git a/chip/mec1322/config_chip.h b/chip/mec1322/config_chip.h
index 93cb2b4dda..e49db95fed 100644
--- a/chip/mec1322/config_chip.h
+++ b/chip/mec1322/config_chip.h
@@ -82,11 +82,11 @@
#if 0
#define CONFIG_ADC
#define CONFIG_I2C
-#define CONFIG_LPC
#define CONFIG_PECI
#define CONFIG_SWITCH
#define CONFIG_MPU
#endif
+#define CONFIG_LPC
#define CONFIG_FPU
#undef CONFIG_FLASH
diff --git a/chip/mec1322/lpc.c b/chip/mec1322/lpc.c
new file mode 100644
index 0000000000..5ccd7cb43f
--- /dev/null
+++ b/chip/mec1322/lpc.c
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* LPC module for MEC1322 */
+
+#include "console.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "lpc.h"
+#include "registers.h"
+#include "task.h"
+#include "util.h"
+
+static uint8_t mem_mapped[0x200] __attribute__((section(".bss.big_align")));
+
+static struct host_packet lpc_packet;
+static struct host_cmd_handler_args host_cmd_args;
+static uint8_t host_cmd_flags; /* Flags from host command */
+
+static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __attribute__((aligned(4)));
+
+static struct ec_lpc_host_args * const lpc_host_args =
+ (struct ec_lpc_host_args *)mem_mapped;
+
+uint8_t *lpc_get_memmap_range(void)
+{
+ return mem_mapped + 0x100;
+}
+
+static uint8_t *lpc_get_hostcmd_data_range(void)
+{
+ return mem_mapped;
+}
+
+static void lpc_send_response_packet(struct host_packet *pkt)
+{
+ /* Ignore in-progress on LPC since interface is synchronous anyway */
+ if (pkt->driver_result == EC_RES_IN_PROGRESS)
+ return;
+
+ /* Write result to the data byte. */
+ MEC1322_ACPI_EC_EC2OS(1, 0) = pkt->driver_result;
+
+ /* Clear the busy bit, so the host knows the EC is done. */
+ MEC1322_ACPI_EC_STATUS(1) &= ~EC_LPC_STATUS_PROCESSING;
+}
+
+/*
+ * Most registers in LPC module are reset when the host is off. We need to
+ * set up LPC again when the host is starting up.
+ */
+static void setup_lpc(void)
+{
+ uintptr_t ptr = (uintptr_t)mem_mapped;
+
+ /* EMI module only takes alias memory address */
+ if (ptr < 0x120000)
+ ptr = ptr - 0x118000 + 0x20000000;
+
+ /* Set up ACPI1 for 0x200/0x204 */
+ MEC1322_LPC_ACPI_EC1_BAR = 0x02008407;
+ MEC1322_INT_ENABLE(15) |= 1 << 8;
+ MEC1322_INT_BLK_EN |= 1 << 15;
+ task_enable_irq(MEC1322_IRQ_ACPIEC1_IBF);
+
+ /* Set up EMI module for memory mapped region.
+ * TODO(crosbug.com/p/24107): Use LPC memory transaction for this
+ * when we have updated info of memory BAR
+ * register.
+ */
+ MEC1322_LPC_EMI_BAR = 0x0800800f;
+ MEC1322_EMI_MBA0 = ptr;
+ MEC1322_EMI_MRL0 = 0x200;
+ MEC1322_EMI_MWL0 = 0x200;
+
+ /* We support LPC args and version 3 protocol */
+ *(lpc_get_memmap_range() + EC_MEMMAP_HOST_CMD_FLAGS) =
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED |
+ EC_HOST_CMD_FLAG_VERSION_3;
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, setup_lpc, HOOK_PRIO_FIRST);
+
+static void lpc_init(void)
+{
+ /* Activate LPC interface */
+ MEC1322_LPC_ACT |= 1;
+
+ /* Initialize host args and memory map to all zero */
+ memset(lpc_host_args, 0, sizeof(*lpc_host_args));
+ memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE);
+}
+/*
+ * Set prio to higher than default; this way LPC memory mapped data is ready
+ * before other inits try to initialize their memmap data.
+ */
+DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_INIT_LPC);
+
+static void acpi_1_interrupt(void)
+{
+ uint8_t st = MEC1322_ACPI_EC_STATUS(1);
+ if (!(st & EC_LPC_STATUS_FROM_HOST) ||
+ !(st & EC_LPC_STATUS_LAST_CMD))
+ return;
+
+ /* Set the busy bit */
+ MEC1322_ACPI_EC_STATUS(1) |= EC_LPC_STATUS_PROCESSING;
+
+ /*
+ * Read the command byte. This clears the FRMH bit in
+ * the status byte.
+ */
+ host_cmd_args.command = MEC1322_ACPI_EC_OS2EC(1, 0);
+
+ host_cmd_args.result = EC_RES_SUCCESS;
+ host_cmd_flags = lpc_host_args->flags;
+
+ /* We only support new style command (v3) now */
+ if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
+ lpc_packet.send_response = lpc_send_response_packet;
+
+ lpc_packet.request = (const void *)lpc_get_hostcmd_data_range();
+ lpc_packet.request_temp = params_copy;
+ lpc_packet.request_max = sizeof(params_copy);
+ /* Don't know the request size so pass in the entire buffer */
+ lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;
+
+ lpc_packet.response = (void *)lpc_get_hostcmd_data_range();
+ lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
+ lpc_packet.response_size = 0;
+
+ lpc_packet.driver_result = EC_RES_SUCCESS;
+ host_packet_receive(&lpc_packet);
+ return;
+ } else {
+ /* Old style command unsupported */
+ host_cmd_args.result = EC_RES_INVALID_COMMAND;
+ }
+
+ /* Hand off to host command handler */
+ host_command_received(&host_cmd_args);
+}
+DECLARE_IRQ(MEC1322_IRQ_ACPIEC1_IBF, acpi_1_interrupt, 1);
+
+void lpc_set_host_event_state(uint32_t mask)
+{
+ /* TODO(crosbug.com/p/24107): Host event */
+}
+
+void lpc_set_host_event_mask(enum lpc_host_event_type type, uint32_t mask)
+{
+ /* TODO(crosbug.com/p/24107): Host event */
+}
+
+uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
+{
+ /* TODO(crosbug.com/p/24107): Host event */
+ return 0;
+}
+
+/* On boards without a host, this command is used to set up LPC */
+static int lpc_command_init(int argc, char **argv)
+{
+ setup_lpc();
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(lpcinit, lpc_command_init, NULL, NULL, NULL);
diff --git a/chip/mec1322/registers.h b/chip/mec1322/registers.h
index 5d6e09685e..8a134415f1 100644
--- a/chip/mec1322/registers.h
+++ b/chip/mec1322/registers.h
@@ -181,6 +181,14 @@ static inline uintptr_t gpio_port_base(int port_id)
#define MEC1322_PWM_CFG(x) REG32(MEC1322_PWM_BASE(x) + 0x08)
+/* ACPI */
+#define MEC1322_ACPI_EC_BASE(x) (0x400f0c00 + (x) * 0x400)
+#define MEC1322_ACPI_EC_EC2OS(x, y) REG8(MEC1322_ACPI_EC_BASE(x) + 0x100 + (y))
+#define MEC1322_ACPI_EC_STATUS(x) REG8(MEC1322_ACPI_EC_BASE(x) + 0x104)
+#define MEC1322_ACPI_EC_BYTE_CTL(x) REG8(MEC1322_ACPI_EC_BASE(x) + 0x105)
+#define MEC1322_ACPI_EC_OS2EC(x, y) REG8(MEC1322_ACPI_EC_BASE(x) + 0x108 + (y))
+
+
/* IRQ Numbers */
#define MEC1322_IRQ_I2C_0 0
#define MEC1322_IRQ_I2C_1 1