diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2017-12-13 15:47:03 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-12-20 05:49:33 -0800 |
commit | 6f9b5d62a0e284eff547c552b223571b84c66a32 (patch) | |
tree | 364706f8f68425d714860dd4454b4f55349f9667 | |
parent | 363853006e95854c4319126666636d0bd483cfcf (diff) | |
download | chrome-ec-6f9b5d62a0e284eff547c552b223571b84c66a32.tar.gz |
ec_ec_comm_slave: EC-EC communication slave task and functions
This adds functions required for the slave in EC-EC communication,
including the task that processes requests from the master.
This also adds required CONFIG_EC_EC_COMM_SLAVE/MASTER/BATTERY
config options.
BRANCH=none
BUG=b:65697962
TEST=Build wand and lux boards, flash it, EC-EC communication works.
Change-Id: I772d9023a830f4fbc37316ca31e4da8240de7324
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/828180
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/ec_ec_comm_slave.c | 280 | ||||
-rw-r--r-- | include/config.h | 14 | ||||
-rw-r--r-- | include/ec_ec_comm_slave.h | 28 |
4 files changed, 323 insertions, 0 deletions
diff --git a/common/build.mk b/common/build.mk index e48a7f2c35..2af1a0e3f7 100644 --- a/common/build.mk +++ b/common/build.mk @@ -46,6 +46,7 @@ common-$(CONFIG_DEDICATED_RECOVERY_BUTTON)+=button.o common-$(CONFIG_DEVICE_EVENT)+=device_event.o common-$(CONFIG_DEVICE_STATE)+=device_state.o common-$(CONFIG_DPTF)+=dptf.o +common-$(CONFIG_EC_EC_COMM_SLAVE)+=ec_ec_comm_slave.o common-$(CONFIG_EXTENSION_COMMAND)+=extension.o common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o common-$(CONFIG_FANS)+=fan.o pwm.o diff --git a/common/ec_ec_comm_slave.c b/common/ec_ec_comm_slave.c new file mode 100644 index 0000000000..40bfef3492 --- /dev/null +++ b/common/ec_ec_comm_slave.c @@ -0,0 +1,280 @@ +/* Copyright 2017 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-EC communication, task and functions for slave. + */ + +#include "common.h" +#include "battery.h" +#include "charge_state_v2.h" +#include "console.h" +#include "crc8.h" +#include "ec_commands.h" +#include "ec_ec_comm_slave.h" +#include "hwtimer.h" +#include "queue.h" +#include "queue_policies.h" +#include "task.h" +#include "util.h" + +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) + +/* Print extra debugging information */ +#undef EXTRA_DEBUG + +/* + * TODO(b:65697620): Move these to some other C file, depending on a config + * option. + */ +struct ec_response_battery_static_info base_battery_static; +struct ec_response_battery_dynamic_info base_battery_dynamic; + +/* + * Our command parameter buffer must be big enough to fit any command + * parameter, and crc byte. + */ +#define LARGEST_PARAMS_SIZE 8 + +BUILD_ASSERT(LARGEST_PARAMS_SIZE >= + sizeof(struct ec_params_battery_static_info)); +BUILD_ASSERT(LARGEST_PARAMS_SIZE >= + sizeof(struct ec_params_battery_dynamic_info)); +BUILD_ASSERT(LARGEST_PARAMS_SIZE >= + sizeof(struct ec_params_charger_control)); + +#define COMMAND_BUFFER_PARAMS_SIZE (LARGEST_PARAMS_SIZE + 1) + +/* + * Maximum time needed to read a full command, commands are at most 17 bytes, so + * should not take more than 2ms to be sent at 115200 bps. + */ +#define COMMAND_TIMEOUT_US (5 * MSEC) + + +void ec_ec_comm_slave_written(struct consumer const *consumer, size_t count) +{ + task_wake(TASK_ID_ECCOMM); +} + +/* + * Discard all data from the input queue. + * + * Note that we always sleep for 1ms after clearing the queue, to make sure + * that we give enough time for the next byte to arrive. + */ +static void discard_queue(void) +{ + do { + queue_advance_head(&ec_ec_comm_slave_input, + queue_count(&ec_ec_comm_slave_input)); + usleep(1 * MSEC); + } while (queue_count(&ec_ec_comm_slave_input) > 0); +} + +/* Write response to master. */ +static void write_response(uint16_t res, int seq, const void *data, int len) +{ + struct ec_host_response4 header; + uint8_t crc; + + header.fields0 = + 4 | /* version */ + EC_PACKET4_0_IS_RESPONSE_MASK | /* is_response */ + (seq << EC_PACKET4_0_SEQ_NUM_SHIFT); /* seq_num */ + /* Set data_crc_present if there is data */ + header.fields1 = (len > 0) ? EC_PACKET4_1_DATA_CRC_PRESENT_MASK : 0; + header.result = res; + header.data_len = len; + header.reserved = 0; + header.header_crc = + crc8((uint8_t *)&header, sizeof(header)-1); + QUEUE_ADD_UNITS(&ec_ec_comm_slave_output, + (uint8_t *)&header, sizeof(header)); + + if (len > 0) { + QUEUE_ADD_UNITS(&ec_ec_comm_slave_output, data, len); + crc = crc8(data, len); + QUEUE_ADD_UNITS(&ec_ec_comm_slave_output, &crc, sizeof(crc)); + } +} + +/* + * Read len bytes into buffer. Waiting up to COMMAND_TIMEOUT_US after start. + * + * Returns EC_SUCCESS or EC_ERROR_TIMEOUT. + */ +static int read_data(void *buffer, size_t len, uint32_t start) +{ + uint32_t delta; + + while (queue_count(&ec_ec_comm_slave_input) < len) { + delta = __hw_clock_source_read() - start; + if (delta >= COMMAND_TIMEOUT_US) + return EC_ERROR_TIMEOUT; + + /* Every incoming byte wakes the task. */ + task_wait_event(COMMAND_TIMEOUT_US - delta); + } + + /* Fetch header */ + QUEUE_REMOVE_UNITS(&ec_ec_comm_slave_input, buffer, len); + + return EC_SUCCESS; +} + +#ifdef CONFIG_EC_EC_COMM_BATTERY +static void handle_cmd_charger_control( + const struct ec_params_charger_control *params, + int data_len, int seq) +{ + int ret = EC_RES_SUCCESS; + + if (data_len != sizeof(*params)) { + ret = EC_RES_INVALID_COMMAND; + goto out; + } + + if (params->max_current >= 0) { + charger_enable_otg_power(0); + charge_set_input_current_limit( + MIN(MAX_CURRENT_MA, params->max_current), 0); + } else { + if (-params->max_current > MAX_OTG_CURRENT_MA || + params->otg_voltage > MAX_OTG_VOLTAGE_MV) { + ret = EC_RES_INVALID_PARAM; + goto out; + } + + /* Reset input current to minimum. */ + charge_set_input_current_limit(CONFIG_CHARGER_INPUT_CURRENT, 0); + /* Setup and enable "OTG". */ + charger_set_otg_current_voltage(-params->max_current, + params->otg_voltage); + charger_enable_otg_power(1); + } + +out: + write_response(ret, seq, NULL, 0); +} +#endif + +void ec_ec_comm_slave_task(void *u) +{ + struct ec_host_request4 header; + /* + * If CONFIG_HOSTCMD_ALIGNED is set, it is important that params is + * aligned on a 32-bit boundary. + */ + uint8_t __aligned(4) params[COMMAND_BUFFER_PARAMS_SIZE]; + unsigned int len, seq, hascrc, cmdver; + uint32_t start; + + while (1) { + task_wait_event(-1); + + if (queue_count(&ec_ec_comm_slave_input) == 0) + continue; + + /* We got some data, start timeout counter. */ + start = __hw_clock_source_read(); + + /* Wait for whole header to be available and read it. */ + if (read_data(&header, sizeof(header), start)) { + CPRINTS("%s timeout (header)", __func__); + goto discard; + } + +#ifdef EXTRA_DEBUG + CPRINTS("%s f0=%02x f1=%02x cmd=%02x, length=%d", __func__, + header.fields0, header.fields1, + header.command, header.data_len); +#endif + + /* Ignore response (we wrote that ourselves) */ + if (header.fields0 & EC_PACKET4_0_IS_RESPONSE_MASK) + goto discard; + + /* Validate version and crc. */ + if ((header.fields0 & EC_PACKET4_0_STRUCT_VERSION_MASK) != 4 || + header.header_crc != + crc8((uint8_t *)&header, sizeof(header)-1)) { + CPRINTS("%s header/crc error", __func__); + goto discard; + } + + len = header.data_len; + hascrc = header.fields1 & EC_PACKET4_1_DATA_CRC_PRESENT_MASK; + if (hascrc) + len += 1; + + /* + * Ignore commands that are too long to fit in our buffer. + */ + if (len > sizeof(params)) { + CPRINTS("%s len error (%d)", __func__, len); + /* Discard the data first, then write error back. */ + discard_queue(); + write_response(EC_RES_OVERFLOW, seq, NULL, 0); + goto discard; + } + + seq = (header.fields0 & EC_PACKET4_0_SEQ_NUM_MASK) >> + EC_PACKET4_0_SEQ_NUM_SHIFT; + + cmdver = header.fields1 & EC_PACKET4_1_COMMAND_VERSION_MASK; + + /* Wait for the rest of the data to be available and read it. */ + if (read_data(params, len, start)) { + CPRINTS("%s timeout (data)", __func__); + goto discard; + } + + /* Check data CRC */ + if (hascrc && params[len-1] != crc8(params, len-1)) { + CPRINTS("%s data crc error", __func__); + write_response(EC_RES_INVALID_CHECKSUM, seq, NULL, 0); + goto discard; + } + + /* For now, all commands have version 0. */ + if (cmdver != 0) { + CPRINTS("%s bad command version", __func__); + write_response(EC_RES_INVALID_VERSION, seq, NULL, 0); + continue; + } + + switch (header.command) { +#ifdef CONFIG_EC_EC_COMM_BATTERY + case EC_CMD_BATTERY_GET_STATIC: + /* Note that we ignore the battery index parameter. */ + write_response(EC_RES_SUCCESS, seq, + &base_battery_static, + sizeof(base_battery_static)); + break; + case EC_CMD_BATTERY_GET_DYNAMIC: + /* Note that we ignore the battery index parameter. */ + write_response(EC_RES_SUCCESS, seq, + &base_battery_dynamic, + sizeof(base_battery_dynamic)); + break; + case EC_CMD_CHARGER_CONTROL: { + handle_cmd_charger_control((void *)params, + header.data_len, seq); + break; + } +#endif + default: + write_response(EC_RES_INVALID_COMMAND, seq, + NULL, 0); + } + + continue; +discard: + /* + * Some error occurred: discard all data in the queue. + */ + discard_queue(); + } +} diff --git a/include/config.h b/include/config.h index 35f0821080..19b342acc3 100644 --- a/include/config.h +++ b/include/config.h @@ -882,6 +882,20 @@ /* Enable verbose output to UART console and extra timestamp print precision. */ #define CONFIG_CONSOLE_VERBOSE +/*****************************************************************************/ +/* Support for EC-EC communication */ + +/* + * Board is master or slave in EC-EC communication. + */ +#undef CONFIG_EC_EC_COMM_MASTER +#undef CONFIG_EC_EC_COMM_SLAVE + +/* + * Board support battery-related functions in EC-EC communication. + */ +#undef CONFIG_EC_EC_COMM_BATTERY + /* * Enable the experimental console. * diff --git a/include/ec_ec_comm_slave.h b/include/ec_ec_comm_slave.h new file mode 100644 index 0000000000..1954018319 --- /dev/null +++ b/include/ec_ec_comm_slave.h @@ -0,0 +1,28 @@ +/* Copyright 2017 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-EC communication, functions and definition for slave. + */ + +#ifndef EC_EC_COMM_SLAVE_H_ +#define EC_EC_COMM_SLAVE_H_ + +#include <stdint.h> +#include "consumer.h" +#include "queue.h" + +#if defined(CONFIG_EC_EC_COMM_SLAVE) && defined(CONFIG_EC_EC_COMM_BATTERY) +#define CONFIG_EC_EC_COMM_BATTERY_SLAVE +#endif + +/* TODO(b:65697620): Move these to battery.h, depending on a config option. */ +extern struct ec_response_battery_static_info base_battery_static; +extern struct ec_response_battery_dynamic_info base_battery_dynamic; + +extern struct queue const ec_ec_comm_slave_input; +extern struct queue const ec_ec_comm_slave_output; + +void ec_ec_comm_slave_written(struct consumer const *consumer, size_t count); + +#endif /* EC_EC_COMM_SLAVE_H_ */ |