diff options
-rw-r--r-- | board/firefly/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | board/fruitpie/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | board/samus/board.c | 14 | ||||
-rw-r--r-- | board/samus/board.h | 1 | ||||
-rw-r--r-- | board/samus/ec.tasklist | 1 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 73 | ||||
-rw-r--r-- | board/zinger/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | common/build.mk | 2 | ||||
-rw-r--r-- | common/charge_state_v2.c | 2 | ||||
-rw-r--r-- | common/host_command_pd.c | 52 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 10 | ||||
-rw-r--r-- | include/charge_state.h | 2 | ||||
-rw-r--r-- | include/config.h | 14 | ||||
-rw-r--r-- | include/ec_commands.h | 19 | ||||
-rw-r--r-- | include/host_command.h | 6 | ||||
-rw-r--r-- | include/usb_pd.h | 7 |
16 files changed, 209 insertions, 9 deletions
diff --git a/board/firefly/usb_pd_policy.c b/board/firefly/usb_pd_policy.c index 0a57d34192..a526702b13 100644 --- a/board/firefly/usb_pd_policy.c +++ b/board/firefly/usb_pd_policy.c @@ -125,3 +125,8 @@ int pd_board_checks(void) return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return 1; +} diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c index 9464b242be..6ebc04385b 100644 --- a/board/fruitpie/usb_pd_policy.c +++ b/board/fruitpie/usb_pd_policy.c @@ -123,3 +123,8 @@ int pd_board_checks(void) { return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return 1; +} diff --git a/board/samus/board.c b/board/samus/board.c index 000c1f0db7..d5a9bead21 100644 --- a/board/samus/board.c +++ b/board/samus/board.c @@ -18,6 +18,7 @@ #include "extpower.h" #include "fan.h" #include "gpio.h" +#include "hooks.h" #include "host_command.h" #include "i2c.h" #include "jtag.h" @@ -39,7 +40,8 @@ static void pd_mcu_interrupt(enum gpio_signal signal) { - ccprintf("PD interrupt!\n"); + /* Exchange status with PD MCU. */ + host_command_pd_send_status(); } /* GPIO signal list. Must match order from enum gpio_signal. */ @@ -90,7 +92,8 @@ const struct gpio_info gpio_list[] = { {"CAPSENSE_INT_L", LM4_GPIO_N, (1<<0), GPIO_INPUT, NULL}, #endif {"PD_MCU_INT_L", LM4_GPIO_J, (1<<5), GPIO_PULL_UP| - GPIO_INT_FALLING, + GPIO_INT_FALLING| + GPIO_INT_DSLEEP, pd_mcu_interrupt}, /* Other inputs */ @@ -338,6 +341,13 @@ struct keyboard_scan_config keyscan_config = { }, }; +/* Initialize board. */ +static void board_init(void) +{ + gpio_enable_interrupt(GPIO_PD_MCU_INT_L); +} +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + #ifdef CONFIG_BATTERY_PRESENT_CUSTOM /** * Physical check of battery presence. diff --git a/board/samus/board.h b/board/samus/board.h index b914964e78..48b1a94be1 100644 --- a/board/samus/board.h +++ b/board/samus/board.h @@ -44,7 +44,6 @@ #define CONFIG_CHARGER_INPUT_CURRENT 2000 #define CONFIG_CHARGER_DISCHARGE_ON_AC #define CONFIG_FANS 2 -#define CONFIG_HOST_CMD_MASTER #define CONFIG_PECI_TJMAX 100 #define CONFIG_PWM #define CONFIG_PWM_KBLIGHT diff --git a/board/samus/ec.tasklist b/board/samus/ec.tasklist index 2b8da9c77b..ab25faa872 100644 --- a/board/samus/ec.tasklist +++ b/board/samus/ec.tasklist @@ -23,6 +23,7 @@ TASK_ALWAYS(CHARGER, charger_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \ + TASK_NOTEST(PDCMD, pd_command_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_ALWAYS(POWERBTN, power_button_task, NULL, TASK_STACK_SIZE) \ diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index ea5f2d1703..2e2a42d182 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -8,6 +8,7 @@ #include "console.h" #include "gpio.h" #include "hooks.h" +#include "host_command.h" #include "registers.h" #include "task.h" #include "timer.h" @@ -33,6 +34,9 @@ const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); /* Cap on the max voltage requested as a sink (in millivolts) */ static unsigned max_mv = -1; /* no cap */ +/* Flag for battery status */ +static int battery_ok; + int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) { int i; @@ -40,6 +44,10 @@ int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) int max_uw = 0; int max_i = -1; + /* Don't negotiate power until battery ok signal is given */ + if (!battery_ok) + return -EC_ERROR_UNKNOWN; + /* Get max power */ for (i = 0; i < cnt; i++) { int uw; @@ -119,7 +127,72 @@ void pd_power_supply_reset(void) gpio_set_level(GPIO_USB_C0_5V_EN, 0); } +static void pd_send_ec_int(void) +{ + gpio_set_level(GPIO_EC_INT_L, 0); + + /* + * Delay long enough to guarantee EC see's the change. Slowest + * EC clock speed is 250kHz in deep sleep -> 4us, and add 1us + * for buffer. + */ + usleep(5); + + gpio_set_level(GPIO_EC_INT_L, 1); +} + int pd_board_checks(void) { + static uint64_t last_time; + + /* + * If battery is not yet ok, signal EC to send status. Avoid + * sending requests too frequently. + */ + if (!battery_ok && (get_time().val - last_time >= SECOND)) { + last_time = get_time().val; + pd_send_ec_int(); + } + return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return battery_ok; +} + +static int command_ec_int(int argc, char **argv) +{ + pd_send_ec_int(); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(ecint, command_ec_int, + "", + "Toggle EC interrupt line", + NULL); + +static int ec_status_host_cmd(struct host_cmd_handler_args *args) +{ + const struct ec_params_pd_status *p = args->params; + struct ec_response_pd_status *r = args->response; + + if (p->batt_soc >= CONFIG_USB_PD_MIN_BATT_CHARGE) { + /* + * When battery is above minimum charge, we know + * that we have enough power remaining for us to + * negotiate power over PD. + */ + CPRINTS("Battery is ok, safe to negotiate power"); + battery_ok = 1; + } else { + battery_ok = 0; + } + + args->response_size = sizeof(*r); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd, + EC_VER_MASK(0)); diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c index 1b52d0876c..04b04fca6b 100644 --- a/board/zinger/usb_pd_policy.c +++ b/board/zinger/usb_pd_policy.c @@ -233,6 +233,11 @@ int pd_board_checks(void) } +int pd_power_negotiation_allowed(void) +{ + return 1; +} + void IRQ_HANDLER(STM32_IRQ_ADC_COMP)(void) { /* cut the power output */ diff --git a/common/build.mk b/common/build.mk index 18c1c47579..09bbfe2564 100644 --- a/common/build.mk +++ b/common/build.mk @@ -43,7 +43,6 @@ common-$(CONFIG_EXTPOWER_SPRING)+=extpower_spring.o common-$(CONFIG_FANS)+=fan.o common-$(CONFIG_FLASH)+=flash.o common-$(CONFIG_FMAP)+=fmap.o -common-$(CONFIG_HOST_CMD_MASTER)+=host_command_master.o common-$(CONFIG_I2C)+=i2c.o common-$(CONFIG_I2C_ARBITRATION)+=i2c_arbitration.o common-$(CONFIG_KEYBOARD_PROTOCOL_8042)+=keyboard_8042.o @@ -72,6 +71,7 @@ common-$(HAS_TASK_CHIPSET)+=chipset.o throttle_ap.o common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o common-$(HAS_TASK_CONSOLE)+=memory_commands.o common-$(HAS_TASK_HOSTCMD)+=acpi.o host_command.o host_event_commands.o +common-$(HAS_TASK_PDCMD)+=host_command_master.o host_command_pd.o common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o common-$(HAS_TASK_LIGHTBAR)+=lb_common.o lightbar.o common-$(HAS_TASK_MOTIONSENSE)+=motion_sense.o math_util.o diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 87ad28561b..6a6a93765d 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -744,6 +744,8 @@ uint32_t charge_get_flags(void) flags |= CHARGE_FLAG_FORCE_IDLE; if (curr.ac) flags |= CHARGE_FLAG_EXTERNAL_POWER; + if (curr.batt.flags & BATT_FLAG_RESPONSIVE) + flags |= CHARGE_FLAG_BATT_RESPONSIVE; return flags; } diff --git a/common/host_command_pd.c b/common/host_command_pd.c new file mode 100644 index 0000000000..5d9a3adf6d --- /dev/null +++ b/common/host_command_pd.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2014 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. + */ + +/* Host command module for PD MCU */ + +#include "charge_state.h" +#include "common.h" +#include "host_command.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +#define TASK_EVENT_EXCHANGE_PD_STATUS TASK_EVENT_CUSTOM(1) + +void host_command_pd_send_status(void) +{ + task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0); +} + +static void pd_exchange_status(void) +{ + struct ec_params_pd_status ec_status; + + /* + * TODO(crosbug.com/p/29499): Change sending state of charge to + * remaining capacity for finer grained control. + */ + /* Send battery state of charge */ + if (charge_get_flags() & CHARGE_FLAG_BATT_RESPONSIVE) + ec_status.batt_soc = charge_get_percent(); + else + ec_status.batt_soc = -1; + + pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status, + sizeof(struct ec_params_pd_status), NULL, 0); +} + +void pd_command_task(void) +{ + + while (1) { + /* Wait for the next command event */ + int evt = task_wait_event(-1); + + /* Process event to send status to PD */ + if (evt & TASK_EVENT_EXCHANGE_PD_STATUS) + pd_exchange_status(); + } +} + diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 214d5f15a0..34a6183cd2 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -495,6 +495,10 @@ static void handle_data_request(void *ctxt, uint16_t head, uint32_t *payload) */ pd_task_state = PD_STATE_SNK_REQUESTED; } + /* + * TODO(crosbug.com/p/28332): if pd_choose_voltage + * returns an error, ignore failure for now. + */ } break; #endif /* CONFIG_USB_PD_DUAL_ROLE */ @@ -886,6 +890,12 @@ void pd_task(void) break; } + /* Don't continue if power negotiation is not allowed */ + if (!pd_power_negotiation_allowed()) { + timeout = PD_T_GET_SOURCE_CAP; + break; + } + res = send_control(ctxt, PD_CTRL_GET_SOURCE_CAP); /* packet was acked => PD capable device) */ if (res >= 0) { diff --git a/include/charge_state.h b/include/charge_state.h index 0da544422f..c23e70c260 100644 --- a/include/charge_state.h +++ b/include/charge_state.h @@ -50,6 +50,8 @@ enum charge_state { #define CHARGE_FLAG_FORCE_IDLE (1 << 0) /* External (AC) power is present */ #define CHARGE_FLAG_EXTERNAL_POWER (1 << 1) +/* Battery is responsive */ +#define CHARGE_FLAG_BATT_RESPONSIVE (1 << 2) /* Debugging constants, in the same order as enum charge_state. This string * table was moved here to sync with enum above. diff --git a/include/config.h b/include/config.h index 464ad50953..43f7cfdbca 100644 --- a/include/config.h +++ b/include/config.h @@ -503,9 +503,6 @@ /*****************************************************************************/ -/* Support EC acting as host master for other MCUs. */ -#undef CONFIG_HOST_CMD_MASTER - /* * Support the host asking the EC about the status of the most recent host * command. @@ -866,12 +863,19 @@ #undef CONFIG_UART_TX_DMA /*****************************************************************************/ +/* USB PD config */ + +/* USB PD MCU slave address for host commands */ +#define CONFIG_USB_PD_I2C_SLAVE_ADDR 0x3c + +/* TODO(crosbug.com/p/29499): Determine threshold for power negotiation */ +/* USB PD minimum battery charge to negotiate for more power */ +#define CONFIG_USB_PD_MIN_BATT_CHARGE 1 /* USB PD transmit uses SPI master */ #undef CONFIG_USB_PD_TX_USES_SPI_MASTER -/* USB PD MCU slave address for host commands */ -#define CONFIG_USB_PD_I2C_SLAVE_ADDR 0x3c +/*****************************************************************************/ /* Support simple control of power to the device's USB ports */ #undef CONFIG_USB_PORT_POWER_DUMB diff --git a/include/ec_commands.h b/include/ec_commands.h index 1526084986..5edd754df3 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2478,6 +2478,25 @@ struct ec_params_reboot_ec { /*****************************************************************************/ /* + * PD commands + * + * These commands are for PD MCU communication. + */ + +/* EC to PD MCU exchange status command */ +#define EC_CMD_PD_EXCHANGE_STATUS 0x100 + +/* Status of EC being sent to PD */ +struct ec_params_pd_status { + int8_t batt_soc; /* battery state of charge */ +} __packed; + +/* Status of PD being sent back to EC */ +struct ec_response_pd_status { +} __packed; + +/*****************************************************************************/ +/* * Deprecated constants. These constants have been renamed for clarity. The * meaning and size has not changed. Programs that use the old names should * switch to the new names soon, as the old names may not be carried forward diff --git a/include/host_command.h b/include/host_command.h index 1fbf0b6554..231ef9a6b8 100644 --- a/include/host_command.h +++ b/include/host_command.h @@ -207,6 +207,12 @@ void host_packet_receive(struct host_packet *pkt); */ void host_throttle_cpu(int throttle); + +/** + * Signal host command task to send status to PD MCU. + */ +void host_command_pd_send_status(void); + /** * Send host command to PD MCU. * diff --git a/include/usb_pd.h b/include/usb_pd.h index 89229079a4..e8f9168aa7 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -185,6 +185,13 @@ void pd_request_source_voltage(int mv); */ int pd_board_checks(void); +/** + * Query if power negotiation is allowed. + * + * @return true if negotation is allowed, false otherwise. + */ +int pd_power_negotiation_allowed(void); + /* * Handle Vendor Defined Message with our vendor ID. * |