summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-05-11 01:11:52 +0000
committerVincent Palatin <vpalatin@chromium.org>2012-05-18 17:57:51 +0000
commit4c5f1365b50c345ea4f34e353cde31499a9190bd (patch)
tree1239615b03925fe915759bb05bf7ffcdb57906f0
parent3e747005b35accb144ddaf4ca5a5142c19f8851b (diff)
downloadchrome-ec-4c5f1365b50c345ea4f34e353cde31499a9190bd.tar.gz
Use common host command processing for Daisy I2C
This also updates the communication protocol between the EC and the AP in a non backward compatible way. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BUG=chrome-os-partner:9614 TEST=on Daisy with updated kernel driver, use the keyboard in ChromeOS Change-Id: I5a50e9a74b9891153a37ea79318c8a66a1b0c5ca
-rw-r--r--board/daisy/board.h3
-rw-r--r--board/daisy/ec.tasklist3
-rw-r--r--board/snow/board.h3
-rw-r--r--board/snow/ec.tasklist3
-rw-r--r--chip/stm32/build.mk4
-rw-r--r--chip/stm32/i2c.c174
-rw-r--r--chip/stm32/keyboard_scan.c26
-rw-r--r--common/build.mk2
-rw-r--r--common/host_command.c2
-rw-r--r--common/message.c93
-rw-r--r--include/ec_commands.h19
-rw-r--r--include/keyboard_scan.h15
-rw-r--r--include/message.h49
13 files changed, 121 insertions, 275 deletions
diff --git a/board/daisy/board.h b/board/daisy/board.h
index deb8de1e14..b3a9588a37 100644
--- a/board/daisy/board.h
+++ b/board/daisy/board.h
@@ -17,6 +17,9 @@
/* support programming on-chip flash */
#define CONFIG_FLASH
+/* use I2C for host communication */
+#define CONFIG_I2C
+
/* By default, enable all console messages except keyboard */
#define CC_DEFAULT (CC_ALL & ~CC_MASK(CC_KEYSCAN))
diff --git a/board/daisy/ec.tasklist b/board/daisy/ec.tasklist
index 9a14c9098a..24b151ba87 100644
--- a/board/daisy/ec.tasklist
+++ b/board/daisy/ec.tasklist
@@ -18,5 +18,4 @@
TASK(KEYSCAN, keyboard_scan_task, NULL) \
TASK(GAIAPOWER, gaia_power_task, NULL) \
TASK(CONSOLE, console_task, NULL) \
- TASK(SPI_WORK, spi_work_task, NULL) \
- TASK(I2C2_WORK, i2c2_work_task, NULL)
+ TASK(HOSTCMD, host_command_task, NULL)
diff --git a/board/snow/board.h b/board/snow/board.h
index 7d4a1fd3b5..67156dc0ec 100644
--- a/board/snow/board.h
+++ b/board/snow/board.h
@@ -14,6 +14,9 @@
/* Use USART1 as console serial port */
#define CONFIG_CONSOLE_UART 1
+/* use I2C for host communication */
+#define CONFIG_I2C
+
#define USB_CHARGE_PORT_COUNT 0
/* EC drives 13 outputs to keyboard matrix */
diff --git a/board/snow/ec.tasklist b/board/snow/ec.tasklist
index 9a14c9098a..24b151ba87 100644
--- a/board/snow/ec.tasklist
+++ b/board/snow/ec.tasklist
@@ -18,5 +18,4 @@
TASK(KEYSCAN, keyboard_scan_task, NULL) \
TASK(GAIAPOWER, gaia_power_task, NULL) \
TASK(CONSOLE, console_task, NULL) \
- TASK(SPI_WORK, spi_work_task, NULL) \
- TASK(I2C2_WORK, i2c2_work_task, NULL)
+ TASK(HOSTCMD, host_command_task, NULL)
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index 03877cf6fe..013569cd75 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -11,8 +11,8 @@ CORE:=cortex-m
chip-y=dma.o gpio.o hwtimer.o system.o uart.o
chip-y+=jtag-$(CHIP_VARIANT).o clock-$(CHIP_VARIANT).o gpio-$(CHIP_VARIANT).o
-chip-$(CONFIG_TASK_SPI_WORK)+=spi.o
-chip-$(CONFIG_TASK_I2C2_WORK)+=i2c.o
+chip-$(CONFIG_SPI)+=spi.o
+chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_TASK_WATCHDOG)+=watchdog.o
chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o
chip-$(CONFIG_FLASH)+=flash-$(CHIP_VARIANT).o
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index 8ed60e1fe7..2ccecdba16 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -6,12 +6,14 @@
#include "board.h"
#include "common.h"
#include "console.h"
+#include "ec_commands.h"
#include "gpio.h"
#include "hooks.h"
+#include "host_command.h"
#include "i2c.h"
-#include "message.h"
#include "registers.h"
#include "task.h"
+#include "util.h"
/* Console output macros */
#define CPUTS(outstr) cputs(CC_I2C, outstr)
@@ -30,35 +32,15 @@
#define I2C1 STM32_I2C1_PORT
#define I2C2 STM32_I2C2_PORT
-static task_id_t task_waiting_on_port[NUM_PORTS];
-static struct mutex port_mutex[NUM_PORTS];
static uint16_t i2c_sr1[NUM_PORTS];
-/* per-transaction counters */
-static unsigned int tx_byte_count;
-static unsigned int rx_byte_count;
-
-/*
- * i2c_xmit_mode determines what EC sends when AP initiates a
- * read transaction. If AP has not set a transmit mode, then
- * default to NOP.
- */
-static enum message_cmd_t i2c_xmit_mode[NUM_PORTS] = { CMDC_NOP, CMDC_NOP };
-
-/*
- * Our output buffers. These must be large enough for our largest message,
- * including protocol overhead.
- */
-static uint8_t out_msg[32];
+/* buffer for host commands (including error code and checksum) */
+static uint8_t host_buffer[EC_PARAM_SIZE + 2];
+/* current position in host buffer for reception */
+static int rx_index;
-static void wait_rx(int port)
-{
- /* TODO: Add timeouts and error checking for safety */
- while (!(STM32_I2C_SR1(port) & (1 << 6)))
- ;
-}
static void wait_tx(int port)
{
@@ -67,71 +49,59 @@ static void wait_tx(int port)
;
}
-static int i2c_read_raw(int port, void *buf, int len)
+static int i2c_write_raw(int port, void *buf, int len)
{
int i;
uint8_t *data = buf;
- mutex_lock(&port_mutex[port]);
- rx_byte_count = 0;
for (i = 0; i < len; i++) {
- wait_rx(port);
- data[i] = STM32_I2C_DR(port);
- rx_byte_count++;
+ STM32_I2C_DR(port) = data[i];
+ wait_tx(port);
}
- mutex_unlock(&port_mutex[port]);
return len;
}
-static int i2c_write_raw(int port, void *buf, int len)
+static void _send_result(int slot, int result, int size)
{
int i;
- uint8_t *data = buf;
-
- mutex_lock(&port_mutex[port]);
- tx_byte_count = 0;
- for (i = 0; i < len; i++) {
- tx_byte_count++;
- STM32_I2C_DR(port) = data[i];
- wait_tx(port);
+ int len = 1;
+ uint8_t sum = 0;
+
+ ASSERT(slot == 0);
+ /* record the error code */
+ host_buffer[0] = result;
+ if (size) {
+ /* compute checksum */
+ for (i = 1; i <= size; i++)
+ sum += host_buffer[i];
+ host_buffer[size + 1] = sum;
+ len = size + 2;
}
- mutex_unlock(&port_mutex[port]);
- return len;
+ /* send the answer to the AP */
+ i2c_write_raw(I2C2, host_buffer, len);
}
-void i2c2_work_task(void)
+void host_send_result(int slot, int result)
{
- int msg_len;
- uint16_t tmp16;
- task_waiting_on_port[1] = task_get_current();
-
- while (1) {
- task_wait_event(-1);
- tmp16 = i2c_sr1[I2C2];
- if (tmp16 & (1 << 6)) {
- /* RxNE; AP issued write command */
- i2c_read_raw(I2C2, &i2c_xmit_mode[I2C2], 1);
-#ifdef CONFIG_DEBUG
- CPRINTF("%s: i2c2_xmit_mode: %02x\n",
- __func__, i2c_xmit_mode[I2C2]);
-#endif
- } else if (tmp16 & (1 << 7)) {
- /* RxE; AP is waiting for EC response */
- msg_len = message_process_cmd(i2c_xmit_mode[I2C2],
- out_msg, sizeof(out_msg));
- if (msg_len > 0) {
- i2c_write_raw(I2C2, out_msg, msg_len);
- } else {
- CPRINTF("%s: unexpected mode %u\n",
- __func__, i2c_xmit_mode[I2C2]);
- }
+ _send_result(slot, result, 0);
+}
- /* reset EC mode to NOP after transfer is finished */
- i2c_xmit_mode[I2C2] = CMDC_NOP;
- }
- }
+void host_send_response(int slot, const uint8_t *data, int size)
+{
+ uint8_t *out = host_get_buffer(slot);
+
+ if (data != out)
+ memcpy(out, data, size);
+
+ _send_result(slot, EC_RES_SUCCESS, size);
+}
+
+uint8_t *host_get_buffer(int slot)
+{
+ ASSERT(slot == 0);
+ return host_buffer + 1 /* skip room for error code */;
}
static void i2c_event_handler(int port)
@@ -146,32 +116,35 @@ static void i2c_event_handler(int port)
/* cleared by reading SR1 followed by reading SR2 */
STM32_I2C_SR1(port);
STM32_I2C_SR2(port);
-#ifdef CONFIG_DEBUG
- CPRINTF("%s: ADDR\n", __func__);
-#endif
- } else if (i2c_sr1[port] & (1 << 2)) {
- ;
-#ifdef CONFIG_DEBUG
- CPRINTF("%s: BTF\n", __func__);
-#endif
} else if (i2c_sr1[port] & (1 << 4)) {
/* clear STOPF bit by reading SR1 and then writing CR1 */
STM32_I2C_SR1(port);
STM32_I2C_CR1(port) = STM32_I2C_CR1(port);
-#ifdef CONFIG_DEBUG
- CPRINTF("%s: STOPF\n", __func__);
-#endif
- } else {
- ;
-#ifdef CONFIG_DEBUG
- CPRINTF("%s: unknown event\n", __func__);
-#endif
}
- /* RxNE or TxE, wake the worker task */
- if (i2c_sr1[port] & ((1 << 6) | (1 << 7))) {
- if (port == I2C2)
- task_wake(TASK_ID_I2C2_WORK);
+ /* RxNE event */
+ if (i2c_sr1[port] & (1 << 6)) {
+ if (port == I2C2) { /* AP issued write command */
+ if (rx_index >= sizeof(host_buffer) - 1) {
+ rx_index = 0;
+ CPRINTF("I2C message too large\n");
+ }
+ host_buffer[rx_index++] = STM32_I2C_DR(I2C2);
+ }
+ }
+ /* TxE event */
+ if (i2c_sr1[port] & (1 << 7)) {
+ if (port == I2C2) { /* AP is waiting for EC response */
+ if (rx_index) {
+ /* we have an available command : execute it */
+ host_command_received(0, host_buffer[0]);
+ /* reset host buffer after end of transfer */
+ rx_index = 0;
+ } else {
+ /* spurious read : return dummy value */
+ STM32_I2C_DR(port) = 0xec;
+ }
+ }
}
}
static void i2c2_event_interrupt(void) { i2c_event_handler(I2C2); }
@@ -185,13 +158,12 @@ static void i2c_error_handler(int port)
if (i2c_sr1[port] & 1 << 10) {
/* ACK failed (NACK); expected when AP reads final byte.
* Software must clear AF bit. */
- CPRINTF("%s: AF detected\n", __func__);
- }
- CPRINTF("%s: tx byte count: %u, rx_byte_count: %u\n",
- __func__, tx_byte_count, rx_byte_count);
- CPRINTF("%s: I2C_SR1(%s): 0x%04x\n", __func__, port, i2c_sr1[port]);
- CPRINTF("%s: I2C_SR2(%s): 0x%04x\n",
+ } else {
+ CPRINTF("%s: I2C_SR1(%s): 0x%04x\n",
+ __func__, port, i2c_sr1[port]);
+ CPRINTF("%s: I2C_SR2(%s): 0x%04x\n",
__func__, port, STM32_I2C_SR2(port));
+ }
#endif
STM32_I2C_SR1(port) &= ~0xdf00;
@@ -201,8 +173,6 @@ DECLARE_IRQ(STM32_IRQ_I2C2_ER, i2c2_error_interrupt, 2);
static int i2c_init2(void)
{
- int i;
-
/* enable I2C2 clock */
STM32_RCC_APB1ENR |= 1 << 22;
@@ -220,10 +190,6 @@ static int i2c_init2(void)
/* clear status */
STM32_I2C_SR1(I2C2) = 0;
- /* No tasks are waiting on ports */
- for (i = 0; i < NUM_PORTS; i++)
- task_waiting_on_port[i] = TASK_ID_INVALID;
-
/* enable event and error interrupts */
task_enable_irq(STM32_IRQ_I2C2_EV);
task_enable_irq(STM32_IRQ_I2C2_ER);
diff --git a/chip/stm32/keyboard_scan.c b/chip/stm32/keyboard_scan.c
index 14bb331b1b..2784ae1dc2 100644
--- a/chip/stm32/keyboard_scan.c
+++ b/chip/stm32/keyboard_scan.c
@@ -13,6 +13,7 @@
#include "board.h"
#include "console.h"
#include "gpio.h"
+#include "host_command.h"
#include "keyboard.h"
#include "keyboard_scan.h"
#include "registers.h"
@@ -40,9 +41,6 @@ enum COL_INDEX {
/* The keyboard state from the last read */
static uint8_t raw_state[KB_OUTPUTS];
-/* The keyboard state we will return when requested */
-static uint8_t saved_state[KB_OUTPUTS];
-
/* Mask with 1 bits only for keys that actually exist */
static const uint8_t *actual_key_mask;
@@ -386,9 +384,23 @@ int keyboard_scan_recovery_pressed(void)
return 0;
}
-int keyboard_get_scan(uint8_t **buffp, int max_bytes)
+static int keyboard_get_scan(uint8_t *data, int *resp_size)
{
- kb_fifo_remove(saved_state);
- *buffp = saved_state;
- return KB_OUTPUTS;
+ kb_fifo_remove(data);
+ *resp_size = KB_OUTPUTS;
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_MKBP_STATE, keyboard_get_scan);
+
+static int keyboard_get_info(uint8_t *data, int *resp_size)
+{
+ struct ec_response_mkbp_info *r = (struct ec_response_mkbp_info *)data;
+
+ r->rows = 8;
+ r->cols = KB_OUTPUTS;
+
+ *resp_size = sizeof(struct ec_response_mkbp_info);
+ return EC_RES_SUCCESS;
}
+DECLARE_HOST_COMMAND(EC_CMD_MKBP_INFO, keyboard_get_info);
diff --git a/common/build.mk b/common/build.mk
index 3f8e1258a0..99ce6eaffb 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -6,7 +6,7 @@
# Common files build
#
-common-y=main.o message.o util.o console.o uart_buffering.o
+common-y=main.o util.o console.o uart_buffering.o
common-y+=memory_commands.o shared_mem.o system_common.o hooks.o
common-y+=gpio_commands.o version.o
common-$(CONFIG_BATTERY_ATL706486)+=battery_atl706486.o
diff --git a/common/host_command.c b/common/host_command.c
index 7e1a2f53d6..91fcb3af48 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -106,6 +106,7 @@ static int host_command_read_test(uint8_t *data, int *resp_size)
DECLARE_HOST_COMMAND(EC_CMD_READ_TEST, host_command_read_test);
+#ifdef CONFIG_LPC
/* ACPI query event handler. Note that the returned value is NOT actually
* an EC_RES enum; it's 0 if no event was pending, or the 1-based
* index of the lowest bit which was set. */
@@ -126,6 +127,7 @@ static int host_command_acpi_query_event(uint8_t *data, int *resp_size)
}
DECLARE_HOST_COMMAND(EC_CMD_ACPI_QUERY_EVENT,
host_command_acpi_query_event);
+#endif
/* Finds a command by command number. Returns the command structure, or NULL if
diff --git a/common/message.c b/common/message.c
deleted file mode 100644
index 76a451b55b..0000000000
--- a/common/message.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * This handles incoming commands and provides responses.
- *
- * Copyright (c) 2012 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.
- *
- * EC <--> AP message handling.
- */
-
-#include "board.h"
-#include "message.h"
-#include "keyboard_scan.h"
-#include "util.h"
-
-/* EC ID */
-/* (TODO(dhendrix): Define this in board-specific code */
-static const char ec_id[] = "Google Chrome EC";
-
-/* Protocol version (least significant byte in lowest byte position) */
-static const uint8_t proto_ver[] = { 1, 0, 0, 0 };
-
-/**
- * Get the response to a given command
- *
- * @param cmd Command byte to respond to
- * @param buffp Buffer to use for data, or it can be updated to
- * point to a new buffer
- * @param max_len Number of bytes free at *buffp for the response.
- * If the supplied buffer is used, this size must not
- * be exceeded.
- * @return number of bytes in response (which is in *buffp), or -1 on error
- */
-static int message_get_response(int cmd, uint8_t **buffp, int max_len)
-{
- /*
- * Invalid commands are ignored, just returning a stream of 0xff
- * bytes.
- */
- switch (cmd) {
- case CMDC_PROTO_VER:
- *buffp = (uint8_t *)proto_ver;
- return sizeof(proto_ver);
- case CMDC_NOP:
- return 0;
- case CMDC_ID:
- *buffp = (char *)ec_id;
- return sizeof(ec_id) - 1;
-#ifdef CONFIG_TASK_KEYSCAN
- case CMDC_KEY_STATE:
- return keyboard_get_scan(buffp, max_len);
-#endif
- default:
- return -1;
- }
-
- return 0;
-}
-
-int message_process_cmd(int cmd, uint8_t *out_msg, int max_len)
-{
- uint8_t *msg;
- int msg_len;
- int need_copy;
- int sum = 0;
- int i;
-
- msg = out_msg;
- msg_len = message_get_response(cmd, &msg, max_len - MSG_PROTO_BYTES);
- if (msg_len < 0)
- return msg_len;
-
- /*
- * We add MSG_PROTO_BYTES bytes of overhead: truncate the reply
- * if needed.
- */
- if (msg_len + MSG_PROTO_BYTES > max_len)
- msg_len = max_len - MSG_PROTO_BYTES;
- ASSERT(msg_len >= 0 && msg_len < 0xffff);
- need_copy = msg != out_msg;
- ASSERT(!need_copy ||
- msg + msg_len < out_msg ||
- msg > out_msg + sizeof(out_msg));
-
- for (i = 0; i < msg_len; i++) {
- if (need_copy)
- out_msg[i] = msg[i];
- sum += msg[i];
- }
- out_msg[i] = sum;
-
- return msg_len + MSG_PROTO_BYTES;
-}
diff --git a/include/ec_commands.h b/include/ec_commands.h
index ab0142e81d..d71d75c3d5 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -8,6 +8,25 @@
#ifndef __CROS_EC_COMMANDS_H
#define __CROS_EC_COMMANDS_H
+/* Protocol overview
+ *
+ * request: CMD [ P0 P1 P2 ... Pn S ]
+ * response: ERR [ P0 P1 P2 ... Pn S ]
+ *
+ * where the bytes are defined as follow :
+ * - CMD is the command code. (defined by EC_CMD_ constants)
+ * - ERR is the error code. (defined by EC_RES_ constants)
+ * - Px is the optional payload.
+ * it is not sent if the error code is not success.
+ * (defined by ec_params_ and ec_response_ structures)
+ * - S is the checksum which is the sum of all payload bytes.
+ *
+ * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD
+ * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM.
+ * On I2C, all bytes are sent serially in the same message.
+ */
+
+
/* During the development stage, the LPC bus has high error bit rate.
* Using checksum can detect the error and trigger re-transmit.
* FIXME: remove this after mass production.
diff --git a/include/keyboard_scan.h b/include/keyboard_scan.h
index 895fdfd2b8..684885c82a 100644
--- a/include/keyboard_scan.h
+++ b/include/keyboard_scan.h
@@ -16,21 +16,6 @@ int keyboard_scan_init(void);
/* Returns non-zero if recovery key was pressed at boot. */
int keyboard_scan_recovery_pressed(void);
-/**
- * Get the scan data from the keyboard.
- *
- * This returns the results of the last keyboard scan, by pointing the
- * supplied buffer to it, and returning the number of bytes available.
- *
- * The supplied buffer can be used directly if required, but in that case
- * the number of bytes available is limited to 'max_bytes'.
- *
- * @param buffp Pointer to buffer to contain data
- * @param max_bytes Maximum number of bytes available in *buffp
- * @return number of bytes available, or -1 for error
- */
-int keyboard_get_scan(uint8_t **buffp, int max_bytes);
-
/* clear any saved keyboard state (empty FIFO, etc) */
void keyboard_clear_state(void);
diff --git a/include/message.h b/include/message.h
deleted file mode 100644
index 439c6df67e..0000000000
--- a/include/message.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (c) 2012 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.
- */
-
-#ifndef __MESSAGE_IF_H
-#define __MESSAGE_IF_H
-
-#include <common.h>
-
-/* Command interface between EC and AP */
-
-enum {
- MSG_TRAILER_BYTES = 1,
- MSG_PROTO_BYTES = MSG_TRAILER_BYTES,
-};
-
-/* The command codes that we understand */
-enum message_cmd_t {
- /* EC control/status messages */
- CMDC_PROTO_VER = 0x00, /* Protocol version */
- CMDC_NOP, /* No operation / ping */
- CMDC_ID, /* Read EC ID */
-
- /* Functional messages */
- CMDC_KEY_STATE = 0x20, /* Read key state */
-};
-
-
-/**
- * Process a command received and return the response
- *
- * There is no time to compute a reply. The data should be ready
- * immediately. This function can be called in interrupt context.
- *
- * The format of a reply is a sequence of bytes:
- *
- * <msg bytes> <sum>
- *
- * The checksum is calculated as the sum of all message bytes
- *
- * @param cmd Command to process (CMD_...)
- * @param buff Pointer to buffer to store reponse
- * @param max_len Maximum length of buffer
- * @return number of bytes in reply, 0 if none, -1 for unknown command
- */
-int message_process_cmd(int cmd, uint8_t *buff, int max_len);
-
-#endif