summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2013-11-27 15:18:20 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-12-04 13:34:50 +0000
commit36eb70c637e0221542f63170139613a52ba71e98 (patch)
tree612a88145b221e7bd03ee077c6413e1796686a50
parentebb54a453d32ccda52a01f0381b47846aaa953f1 (diff)
downloadchrome-ec-36eb70c637e0221542f63170139613a52ba71e98.tar.gz
mec1322: LPC host command support
With this, basic host command functionality is working. We don't have the correct description of LPC memory BAR register yet, so we have to use EMI (embedded memory interface) module for 0x800-0x9ff region. This requires a slightly different protocol, which is in the next CL. BUG=chrome-os-partner:24107 TEST=Wire EVB to Stumpy. 'ectool hello' and 'ectool version' working. BRANCH=None Change-Id: I873b4a455cf692e479321a5c6e18c8f33df60e66 Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/178250 Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
-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