diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2014-12-30 14:28:14 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-30 03:28:13 +0000 |
commit | 1aef41d57744d75e029c5300b905ae884e8ea9df (patch) | |
tree | 8bcdee3d4b9ed1c1d3ae95abba40845f32089248 | |
parent | 3cbff2d21dd7ca85bd5a5b86587625305204e78f (diff) | |
download | chrome-ec-1aef41d57744d75e029c5300b905ae884e8ea9df.tar.gz |
charge_manager: Log charge-related change events
Add the charging events to the PD event log FIFO
and add an ectool to retrieve/decode them.
BUG=chrome-os-partner:33248
TEST=Manual on Samus. Run `ectool --name cros_pd pdlog`, verify that
all log entries are dumped and the content matches expectation.
BRANCH=Samus
Original-Change-Id: I65dd5696cc0487856ab42aff24134bcdfa1a8219
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/238093
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Trybot-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Alec Berg <alecaberg@chromium.org>
(cherry picked from commit bd85bc46360e43b74aa1864565c5ad49b719a804)
Reviewed-on: https://chromium-review.googlesource.com/240838
(cherry picked from commit 97fe3555e00d21f2e5691fb3a7f8eb3a1c371b62)
Signed-off-by: Todd Broch <tbroch@chromium.org>
Change-Id: I46544529ba34ec57dee4940fa9bb834448e12875
Reviewed-on: https://chromium-review.googlesource.com/244223
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
Commit-Queue: Todd Broch <tbroch@chromium.org>
-rw-r--r-- | common/charge_manager.c | 213 | ||||
-rw-r--r-- | util/ectool.c | 171 |
2 files changed, 246 insertions, 138 deletions
diff --git a/common/charge_manager.c b/common/charge_manager.c index 470c20d08c..7fe9028c5c 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -88,6 +88,134 @@ static int charge_manager_is_seeded(void) return 1; } +#ifndef TEST_CHARGE_MANAGER +/** + * Fills passed power_info structure with current info about the passed port. + */ +static void charge_manager_fill_power_info(int port, + struct ec_response_usb_pd_power_info *r) +{ + int sup = CHARGE_SUPPLIER_NONE; + int i; + + /* Determine supplier information to show. */ + if (port == charge_port) + sup = charge_supplier; + else + /* Find highest priority supplier */ + for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) + if (available_charge[i][port].current > 0 && + available_charge[i][port].voltage > 0 && + (sup == CHARGE_SUPPLIER_NONE || + supplier_priority[i] < + supplier_priority[sup] || + (supplier_priority[i] == + supplier_priority[sup] && + POWER(available_charge[i][port]) > + POWER(available_charge[sup] + [port])))) + sup = i; + + /* Fill in power role */ + if (charge_port == port) + r->role = USB_PD_PORT_POWER_SINK; + else if (pd_is_connected(port) && pd_get_role(port) == PD_ROLE_SOURCE) + r->role = USB_PD_PORT_POWER_SOURCE; + else if (sup != CHARGE_SUPPLIER_NONE) + r->role = USB_PD_PORT_POWER_SINK_NOT_CHARGING; + else + r->role = USB_PD_PORT_POWER_DISCONNECTED; + + /* Is port partner dual-role capable */ + r->dualrole = pd_get_partner_dualrole_capable(port); + + if (sup == CHARGE_SUPPLIER_NONE || + r->role == USB_PD_PORT_POWER_SOURCE) { + r->type = USB_CHG_TYPE_NONE; + r->meas.voltage_max = 0; + r->meas.voltage_now = r->role == USB_PD_PORT_POWER_SOURCE ? 5000 + : 0; + r->meas.current_max = 0; + r->max_power = 0; + } else { + switch (sup) { + case CHARGE_SUPPLIER_PD: + r->type = USB_CHG_TYPE_PD; + break; + case CHARGE_SUPPLIER_TYPEC: + r->type = USB_CHG_TYPE_C; + break; + case CHARGE_SUPPLIER_PROPRIETARY: + r->type = USB_CHG_TYPE_PROPRIETARY; + break; + case CHARGE_SUPPLIER_BC12_DCP: + r->type = USB_CHG_TYPE_BC12_DCP; + break; + case CHARGE_SUPPLIER_BC12_CDP: + r->type = USB_CHG_TYPE_BC12_CDP; + break; + case CHARGE_SUPPLIER_BC12_SDP: + r->type = USB_CHG_TYPE_BC12_SDP; + break; + default: + r->type = USB_CHG_TYPE_OTHER; + } + r->meas.voltage_max = available_charge[sup][port].voltage; + r->meas.current_max = available_charge[sup][port].current; + r->max_power = POWER(available_charge[sup][port]); + + /* + * If we are sourcing power, or sinking but not charging, then + * VBUS must be 5V. If we are charging, then read VBUS ADC. + */ + if (r->role == USB_PD_PORT_POWER_SINK_NOT_CHARGING) + r->meas.voltage_now = 5000; + else + r->meas.voltage_now = adc_read_channel(ADC_VBUS); + } +} +#endif /* TEST_CHARGE_MANAGER */ + +#ifdef CONFIG_USB_PD_LOGGING +/** + * Saves a power state log entry with the current info about the passed port. + */ +static void charge_manager_save_log(int port) +{ + uint16_t flags = 0; + struct ec_response_usb_pd_power_info pinfo; + uint16_t voltage_now; + static uint16_t last_voltage[PD_PORT_COUNT]; + static uint16_t last_flags[PD_PORT_COUNT]; + + charge_manager_fill_power_info(port, &pinfo); + + /* Flags are stored in the data field */ + if (port == override_port) + flags |= CHARGE_FLAGS_OVERRIDE; + if (port == delayed_override_port) + flags |= CHARGE_FLAGS_DELAYED_OVERRIDE; + flags |= pinfo.role | (pinfo.type << CHARGE_FLAGS_TYPE_SHIFT) | + (pinfo.dualrole ? CHARGE_FLAGS_DUAL_ROLE : 0); + + /* + * Check for a log change, not considering timestamp. Also, ignore + * voltage_now fluctuations of < 500mV. + */ + voltage_now = pinfo.meas.voltage_now; + if (last_flags[port] == flags && + voltage_now < last_voltage[port] + 500 && + last_voltage[port] < voltage_now + 500) + return; + last_voltage[port] = voltage_now; + last_flags[port] = flags; + + pd_log_event(PD_EVENT_MCU_CHARGE, + PD_LOG_PORT_SIZE(port, sizeof(pinfo.meas)), + flags, &pinfo.meas); +} +#endif /* CONFIG_USB_PD_LOGGING */ + /** * Perform cleanup operations on an override port, when switching to a * different port. This involves switching the port from sink to source, @@ -276,6 +404,12 @@ static void charge_manager_refresh(void) charge_supplier = new_supplier; charge_port = new_port; +#ifdef CONFIG_USB_PD_LOGGING + /* Log possible charge state changes. */ + for (i = 0; i < PD_PORT_COUNT; ++i) + charge_manager_save_log(i); +#endif + /* New power requests must be set only after updating the globals. */ if (updated_new_port != CHARGE_PORT_NONE) pd_set_new_power_request(updated_new_port); @@ -436,89 +570,12 @@ static int hc_pd_power_info(struct host_cmd_handler_args *args) const struct ec_params_usb_pd_power_info *p = args->params; struct ec_response_usb_pd_power_info *r = args->response; int port = p->port; - int sup = CHARGE_SUPPLIER_NONE; - int i; /* If host is asking for the charging port, set port appropriately */ if (port == PD_POWER_CHARGING_PORT) port = charge_port; - /* Determine supplier information to show */ - if (port == charge_port) { - sup = charge_supplier; - } else { - /* Find highest priority supplier */ - for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) { - if (available_charge[i][port].current > 0 && - available_charge[i][port].voltage > 0 && - (sup == CHARGE_SUPPLIER_NONE || - supplier_priority[i] < - supplier_priority[sup] || - (supplier_priority[i] == - supplier_priority[sup] && - POWER(available_charge[i][port]) > - POWER(available_charge[sup] - [port])))) - sup = i; - } - } - - /* Fill in power role */ - if (charge_port == port) - r->role = USB_PD_PORT_POWER_SINK; - else if (pd_is_connected(port) && pd_get_role(port) == PD_ROLE_SOURCE) - r->role = USB_PD_PORT_POWER_SOURCE; - else if (sup != CHARGE_SUPPLIER_NONE) - r->role = USB_PD_PORT_POWER_SINK_NOT_CHARGING; - else - r->role = USB_PD_PORT_POWER_DISCONNECTED; - - /* Is port partner dual-role capable */ - r->dualrole = pd_get_partner_dualrole_capable(port); - - if (sup == CHARGE_SUPPLIER_NONE) { - r->type = USB_CHG_TYPE_NONE; - r->voltage_max = 0; - r->voltage_now = 0; - r->current_max = 0; - r->max_power = 0; - } else { - switch (sup) { - case CHARGE_SUPPLIER_PD: - r->type = USB_CHG_TYPE_PD; - break; - case CHARGE_SUPPLIER_TYPEC: - r->type = USB_CHG_TYPE_C; - break; - case CHARGE_SUPPLIER_PROPRIETARY: - r->type = USB_CHG_TYPE_PROPRIETARY; - break; - case CHARGE_SUPPLIER_BC12_DCP: - r->type = USB_CHG_TYPE_BC12_DCP; - break; - case CHARGE_SUPPLIER_BC12_CDP: - r->type = USB_CHG_TYPE_BC12_CDP; - break; - case CHARGE_SUPPLIER_BC12_SDP: - r->type = USB_CHG_TYPE_BC12_SDP; - break; - default: - r->type = USB_CHG_TYPE_OTHER; - } - r->voltage_max = available_charge[sup][port].voltage; - r->current_max = available_charge[sup][port].current; - r->max_power = POWER(available_charge[sup][port]); - - /* - * If we are sourcing power, or sinking but not charging, then - * VBUS must be 5V. If we are charging, then read VBUS ADC. - */ - if (r->role == USB_PD_PORT_POWER_SOURCE || - r->role == USB_PD_PORT_POWER_SINK_NOT_CHARGING) - r->voltage_now = 5000; - else - r->voltage_now = adc_read_channel(ADC_VBUS); - } + charge_manager_fill_power_info(port, r); args->response_size = sizeof(*r); return EC_RES_SUCCESS; diff --git a/util/ectool.c b/util/ectool.c index 7be3fad5c2..142c248d3f 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -6,6 +6,7 @@ #include <ctype.h> #include <errno.h> #include <getopt.h> +#include <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -137,6 +138,8 @@ const char help_str[] = " Prints saved panic info\n" " pause_in_s5 [on|off]\n" " Whether or not the AP should pause in S5 on shutdown\n" + " pdlog\n" + " Prints the PD event log entries\n" " port80flood\n" " Rapidly write bytes to port 80\n" " port80read\n" @@ -2965,6 +2968,65 @@ int cmd_usb_pd(int argc, char *argv[]) return (rv < 0 ? rv : 0); } +static void print_pd_power_info(struct ec_response_usb_pd_power_info *r) +{ + printf("Power role: "); + + switch (r->role) { + case USB_PD_PORT_POWER_DISCONNECTED: + printf("Disconnected\n"); + break; + case USB_PD_PORT_POWER_SOURCE: + printf("Source\n"); + break; + case USB_PD_PORT_POWER_SINK: + printf("Sink\n"); + break; + case USB_PD_PORT_POWER_SINK_NOT_CHARGING: + printf("Sink (not charging)\n"); + break; + default: + printf("Unknown\n"); + } + + if (r->role != USB_PD_PORT_POWER_DISCONNECTED) { + printf(" %s\n", r->dualrole ? + "Dual-role device" : "Dedicated charger"); + } + + printf(" Charger type: "); + switch (r->type) { + case USB_CHG_TYPE_PD: + printf("PD\n"); + break; + case USB_CHG_TYPE_C: + printf("Type-c\n"); + break; + case USB_CHG_TYPE_PROPRIETARY: + printf("Proprietary\n"); + break; + case USB_CHG_TYPE_BC12_DCP: + printf("BC1.2 DCP\n"); + break; + case USB_CHG_TYPE_BC12_CDP: + printf("BC1.2 CDP\n"); + break; + case USB_CHG_TYPE_BC12_SDP: + printf("BC1.2 SDP\n"); + break; + case USB_CHG_TYPE_OTHER: + printf("Other\n"); + break; + default: + printf("None\n"); + } + printf(" Max charging voltage: %dmV\n", r->meas.voltage_max); + printf(" Current charging voltage: %dmV\n", r->meas.voltage_now); + printf(" Max input current: %dmA\n", r->meas.current_max); + printf(" Max input power: %dmW\n", r->max_power / 1000); + printf("\n"); +} + int cmd_usb_pd_power(int argc, char *argv[]) { struct ec_params_usb_pd_power_info p; @@ -2986,66 +3048,8 @@ int cmd_usb_pd_power(int argc, char *argv[]) if (rv < 0) return rv; - printf("Port %d:\n Power role: ", i); - switch (r->role) { - case USB_PD_PORT_POWER_DISCONNECTED: - printf("Disconnected\n"); - break; - case USB_PD_PORT_POWER_SOURCE: - printf("Source\n"); - break; - case USB_PD_PORT_POWER_SINK: - printf("Sink\n"); - break; - case USB_PD_PORT_POWER_SINK_NOT_CHARGING: - printf("Sink (not charging)\n"); - break; - default: - printf("Unknown\n"); - } - - if (r->role != USB_PD_PORT_POWER_DISCONNECTED) { - printf(" %s\n", r->dualrole ? - "Dual-role device" : "Dedicated charger"); - } - - printf(" Charger type: "); - switch (r->type) { - case USB_CHG_TYPE_PD: - printf("PD\n"); - break; - case USB_CHG_TYPE_C: - printf("Type-c\n"); - break; - case USB_CHG_TYPE_PROPRIETARY: - printf("Proprietary\n"); - break; - case USB_CHG_TYPE_BC12_DCP: - printf("BC1.2 DCP\n"); - break; - case USB_CHG_TYPE_BC12_CDP: - printf("BC1.2 CDP\n"); - break; - case USB_CHG_TYPE_BC12_SDP: - printf("BC1.2 SDP\n"); - break; - case USB_CHG_TYPE_OTHER: - printf("Other\n"); - break; - default: - printf("None\n"); - } - - printf(" Max charging voltage: %dmV\n", - r->voltage_max); - printf(" Current charging voltage: %dmV\n", - r->voltage_now); - printf(" Max input current: %dmA\n", - r->current_max); - printf(" Max input power: %dmW\n", - r->max_power / 1000); - - printf("\n"); + printf("Port %d:\n", i); + print_pd_power_info(r); } return 0; @@ -5232,6 +5236,52 @@ int cmd_charge_port_override(int argc, char *argv[]) return 0; } +int cmd_pd_log(int argc, char *argv[]) +{ + union { + struct ec_response_pd_log r; + uint32_t words[8]; /* space for the payload */ + } u; + struct ec_response_usb_pd_power_info pinfo; + int rv; + + while (1) { + rv = ec_command(EC_CMD_PD_GET_LOG_ENTRY, 0, + NULL, 0, &u, sizeof(u)); + if (rv < 0) + return rv; + + if (u.r.type == PD_EVENT_NO_ENTRY) { + printf("--- END OF LOG ---\n"); + break; + } + + printf("Port: %d, %"PRIu64" ms ago : ", + PD_LOG_PORT(u.r.size_port), + (uint64_t)(u.r.timestamp << PD_LOG_TIMESTAMP_SHIFT) + / 1000); + if (u.r.type == PD_EVENT_MCU_CHARGE) { + if (u.r.data & CHARGE_FLAGS_OVERRIDE) + printf("override "); + if (u.r.data & CHARGE_FLAGS_DELAYED_OVERRIDE) + printf("pending_override "); + printf("\n"); + memcpy(&pinfo.meas, u.r.payload, + sizeof(struct usb_chg_measures)); + pinfo.dualrole = !!(u.r.data & CHARGE_FLAGS_DUAL_ROLE); + pinfo.role = u.r.data & CHARGE_FLAGS_ROLE_MASK; + pinfo.type = (u.r.data & CHARGE_FLAGS_TYPE_MASK) + >> CHARGE_FLAGS_TYPE_SHIFT; + pinfo.max_power = 0; + print_pd_power_info(&pinfo); + } else { /* Unknown type */ + printf(" event %02x\n", u.r.type); + } + } + + return 0; +} + /* NULL-terminated list of commands */ const struct command commands[] = { {"extpwrcurrentlimit", cmd_ext_power_current_limit}, @@ -5285,6 +5335,7 @@ const struct command commands[] = { {"panicinfo", cmd_panic_info}, {"pause_in_s5", cmd_s5}, {"port80read", cmd_port80_read}, + {"pdlog", cmd_pd_log}, {"powerinfo", cmd_power_info}, {"protoinfo", cmd_proto_info}, {"pstoreinfo", cmd_pstore_info}, |