summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2022-04-28 15:49:24 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-05-05 23:29:28 +0000
commit212ef472cc13372a0a70351f24fc0e1bbf29de8f (patch)
tree34aaeacf121458b0473830ced021a148f3539838 /common
parent73d4d92b07937932794d0e37d923300e4cb72481 (diff)
downloadchrome-ec-212ef472cc13372a0a70351f24fc0e1bbf29de8f.tar.gz
chargesplash: State machine implementation
This is much of the legwork required for go/cros-charging-splash, at least the portion of connecting the charger from chipset off state. What remains is: - Examining battery state and charger supply to make better decisions about when we can show the splash. - Consider assertion of PROCHOT during bootup of a low power charger, or after display initialization before the power button is pressed. The next CL adds a simple text-based UI on top of this. BUG=b:228370390 BRANCH=none TEST=connect charger and boot to splash on brya (using ghost image) (with full CL stack) TEST=provided integration tests pass Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: Ic114e975109a338ffaa3be977094020251fc36e6 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3575089 Reviewed-by: Diana Z <dzigterman@chromium.org> Reviewed-by: Aaron Massey <aaronmassey@google.com>
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/chargesplash.c255
2 files changed, 256 insertions, 0 deletions
diff --git a/common/build.mk b/common/build.mk
index fc6c2065b0..6c3c1bfc80 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -63,6 +63,7 @@ common-$(CONFIG_CHARGE_MANAGER)+=charge_manager.o
endif
common-$(CONFIG_CHARGE_RAMP_HW)+=charge_ramp.o
common-$(CONFIG_CHARGE_RAMP_SW)+=charge_ramp.o charge_ramp_sw.o
+common-$(CONFIG_CHARGESPLASH)+=chargesplash.o
common-$(CONFIG_CHIP_INIT_ROM_REGION)+=init_rom.o
common-$(CONFIG_CMD_CHARGEN) += chargen.o
common-$(CONFIG_CHARGER)+=charger.o charge_state_v2.o
diff --git a/common/chargesplash.c b/common/chargesplash.c
new file mode 100644
index 0000000000..88bc6a63f1
--- /dev/null
+++ b/common/chargesplash.c
@@ -0,0 +1,255 @@
+/* Copyright 2022 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.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "chipset.h"
+#include "common.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "extpower.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "lid_switch.h"
+#include "power_button.h"
+#include "timer.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) \
+ cprints(CC_USBCHARGE, "chargesplash: " format, ##args)
+
+/*
+ * Was this power on initiated to show a charge splash?
+ *
+ * - Set when powering on for an AC connect.
+ * - Unset when power button is pushed, or the chargesplash request is
+ * cancelled due to AC disconnection.
+ */
+static bool power_on_for_chargesplash;
+
+/* True once the display has come up */
+static bool display_initialized;
+
+/*
+ * True if the chargesplash is locked out, and we must wait until no
+ * requests happen during the chargesplash period until the lockout can
+ * be cleared.
+ */
+static bool locked_out;
+
+/*
+ * A circular buffer of the most recent chargesplash request
+ * timestamps (stored as an integer value of seconds).
+ */
+static int request_log[CONFIG_CHARGESPLASH_MAX_REQUESTS_PER_PERIOD];
+BUILD_ASSERT(CONFIG_CHARGESPLASH_MAX_REQUESTS_PER_PERIOD >= 1,
+ "There must be at least one request allowed per period");
+
+/*
+ * Return true if the timestamp is outside of the tracking period,
+ * false otherwise.
+ */
+static bool timestamp_is_expired(int timestamp, int now)
+{
+ if (!timestamp) {
+ /* The log entry hasn't been filled yet */
+ return true;
+ }
+
+ return (now - timestamp) >= CONFIG_CHARGESPLASH_PERIOD;
+}
+
+/*
+ * Returns true only if all timestamps have been expired, or we aren't
+ * locked out anyway.
+ */
+static bool lockout_can_be_cleared(int now)
+{
+ if (!locked_out)
+ return true;
+
+ for (int i = 0; i < ARRAY_SIZE(request_log); i++) {
+ if (!timestamp_is_expired(request_log[i], now)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * Write the current time into the request log. If the request should
+ * be permitted to cause a boot, return true. Otherwise, if the
+ * chargesplash should be inhibited, return false.
+ */
+static bool log_request(void)
+{
+ static int log_ptr;
+ int now = get_time().val / SECOND;
+ bool inhibit_boot = false;
+
+ if (lockout_can_be_cleared(now)) {
+ locked_out = false;
+ } else {
+ inhibit_boot = true;
+ }
+
+ if (!timestamp_is_expired(request_log[log_ptr], now)) {
+ locked_out = true;
+ inhibit_boot = true;
+ }
+
+ request_log[log_ptr] = now;
+ log_ptr = (log_ptr + 1) % ARRAY_SIZE(request_log);
+ return !inhibit_boot;
+}
+
+/* Manually reset state (via host or UART cmd) */
+static void reset_state(void)
+{
+ power_on_for_chargesplash = false;
+ display_initialized = false;
+ locked_out = false;
+ memset(request_log, 0, sizeof(request_log));
+}
+
+static void request_chargesplash(void)
+{
+ if (!log_request()) {
+ CPRINTS("Locked out, request inhibited");
+ return;
+ }
+
+ CPRINTS("Power on for charge display");
+ power_on_for_chargesplash = true;
+ display_initialized = false;
+ chipset_power_on();
+}
+
+static void display_ready(void)
+{
+ /*
+ * TODO(b/228370390): Consider asserting PROCHOT (on
+ * some platforms) to slow down background boot.
+ */
+
+ CPRINTS("Display initialized");
+ display_initialized = true;
+}
+
+static void handle_ac_change(void)
+{
+ if (extpower_is_present() && !power_on_for_chargesplash) {
+ if (!lid_is_open()) {
+ CPRINTS("Ignore AC connect as lid is closed");
+ return;
+ }
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ request_chargesplash();
+ }
+ }
+}
+DECLARE_HOOK(HOOK_AC_CHANGE, handle_ac_change, HOOK_PRIO_LAST - 1);
+
+static void handle_power_button_change(void)
+{
+ if (power_button_is_pressed()) {
+ reset_state();
+ }
+}
+DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, handle_power_button_change,
+ HOOK_PRIO_FIRST);
+
+static void handle_chipset_shutdown(void)
+{
+ power_on_for_chargesplash = false;
+ display_initialized = false;
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, handle_chipset_shutdown, HOOK_PRIO_DEFAULT);
+
+static int command_chargesplash(int argc, char **argv)
+{
+ if (argc != 2) {
+ return EC_ERROR_PARAM_COUNT;
+ }
+
+ if (!strcasecmp(argv[1], "state")) {
+ ccprintf("requested = %d\n", power_on_for_chargesplash);
+ ccprintf("display_initialized = %d\n", display_initialized);
+ ccprintf("locked_out = %d\n", locked_out);
+
+ ccprintf("\nRequest log (raw data):\n");
+ for (int i = 0; i < ARRAY_SIZE(request_log); i++) {
+ ccprintf(" %d\n", request_log[i]);
+ }
+ return EC_SUCCESS;
+ }
+
+ if (!strcasecmp(argv[1], "request")) {
+ request_chargesplash();
+ return EC_SUCCESS;
+ }
+
+ if (!strcasecmp(argv[1], "reset")) {
+ reset_state();
+ return EC_SUCCESS;
+ }
+
+ if (!strcasecmp(argv[1], "lockout")) {
+ locked_out = true;
+ return EC_SUCCESS;
+ }
+
+ return EC_ERROR_PARAM1;
+}
+DECLARE_CONSOLE_COMMAND(chargesplash, command_chargesplash,
+ "[state|request|reset|lockout]",
+ "Charge splash controls");
+
+static enum ec_status chargesplash_host_cmd(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_chargesplash *params = args->params;
+ struct ec_response_chargesplash *response = args->response;
+
+ if (args->params_size < sizeof(*params)) {
+ return EC_RES_INVALID_PARAM;
+ }
+
+ if (args->response_max < sizeof(*response)) {
+ return EC_RES_INVALID_RESPONSE;
+ }
+
+ switch (params->cmd) {
+ case EC_CHARGESPLASH_GET_STATE:
+ /* No action to do */
+ break;
+ case EC_CHARGESPLASH_DISPLAY_READY:
+ if (power_on_for_chargesplash) {
+ display_ready();
+ }
+ break;
+ case EC_CHARGESPLASH_REQUEST:
+ request_chargesplash();
+ break;
+ case EC_CHARGESPLASH_RESET:
+ reset_state();
+ break;
+ case EC_CHARGESPLASH_LOCKOUT:
+ locked_out = true;
+ break;
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ /* All commands return the (possibly updated) state */
+ response->requested = power_on_for_chargesplash;
+ response->display_initialized = display_initialized;
+ response->locked_out = locked_out;
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_CHARGESPLASH, chargesplash_host_cmd,
+ EC_VER_MASK(0));