diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2012-05-11 01:11:52 +0000 |
---|---|---|
committer | Vincent Palatin <vpalatin@chromium.org> | 2012-05-18 17:57:51 +0000 |
commit | 4c5f1365b50c345ea4f34e353cde31499a9190bd (patch) | |
tree | 1239615b03925fe915759bb05bf7ffcdb57906f0 /chip | |
parent | 3e747005b35accb144ddaf4ca5a5142c19f8851b (diff) | |
download | chrome-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
Diffstat (limited to 'chip')
-rw-r--r-- | chip/stm32/build.mk | 4 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 174 | ||||
-rw-r--r-- | chip/stm32/keyboard_scan.c | 26 |
3 files changed, 91 insertions, 113 deletions
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); |