summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew McRae <amcrae@google.com>2022-12-05 14:53:18 +1100
committerAndrew McRae <amcrae@google.com>2022-12-05 14:53:18 +1100
commitc9292d8582f8e1e02cf8458ce9969027d7d42241 (patch)
treeb704c36c76136711dba0f9d6d04c711e06ae6762
parentb2004ee71e310d86995ede82d9e84892a67979e8 (diff)
parent7d1d331031e9db8bd9c8600fe9f96472d338c508 (diff)
downloadchrome-ec-c9292d8582f8e1e02cf8458ce9969027d7d42241.tar.gz
Merge remote-tracking branch cros/main into firmware-nissa-15217.B-main
Generated by: ./update_release_branch.py --zephyr -r --board nissa firmware- nissa-15217.B-main Relevant changes: git log --oneline b2004ee71e..7d1d331031 -- zephyr/program/nissa 868032324f Revert "ec: Support logging system boot time info" c8325ba18b ec: Support logging system boot time info 5f4b3e9ba4 xivu: resolve power leakage following nivviks. BRANCH=None BUG=b:249163956 b:260679055 TEST=`make -j buildall` Force-Relevant-Builds: all Change-Id: I72ed374124b336c162f54b79c443ffe631706d49 Signed-off-by: Andrew McRae <amcrae@google.com>
-rw-r--r--Makefile.toolchain7
-rw-r--r--board/gladios/board.c596
-rw-r--r--board/gladios/board.h204
-rw-r--r--board/gladios/build.mk22
-rw-r--r--board/gladios/ec.tasklist29
-rw-r--r--board/gladios/fans.c50
-rw-r--r--board/gladios/fw_config.c65
-rw-r--r--board/gladios/fw_config.h41
-rw-r--r--board/gladios/gpio.inc187
-rw-r--r--board/gladios/i2c.c77
-rw-r--r--board/gladios/led.c260
-rw-r--r--board/gladios/pwm.c39
-rw-r--r--board/gladios/sensors.c114
-rw-r--r--board/gladios/usbc_config.c416
-rw-r--r--board/gladios/usbc_config.h20
-rw-r--r--board/gladios/vif_override.xml3
-rw-r--r--cmake/toolchain-armv7m.cmake4
-rw-r--r--common/dps.c18
-rw-r--r--include/common.h7
-rw-r--r--include/gpio.h10
-rw-r--r--include/test_util.h14
-rwxr-xr-xutil/build_with_clang.py1
-rw-r--r--zephyr/dts/bindings/battery/battery-smart.yaml3
-rw-r--r--zephyr/dts/bindings/battery/lgc,ap19b8k.yaml58
-rw-r--r--zephyr/dts/bindings/battery/panasonic,ap19b5k.yaml58
-rw-r--r--zephyr/dts/bindings/battery/smp,ap18c7k.yaml58
-rw-r--r--zephyr/program/corsola/interrupts_magikarp.dtsi115
-rw-r--r--zephyr/program/corsola/interrupts_tentacruel.dtsi115
-rw-r--r--zephyr/program/corsola/ite_interrupts.dtsi2
-rw-r--r--zephyr/program/corsola/magikarp/project.overlay24
-rw-r--r--zephyr/program/corsola/tentacruel/project.overlay24
-rw-r--r--zephyr/program/corsola/voltorb/project.overlay9
-rw-r--r--zephyr/program/nissa/xivu/overlay.dtsi26
-rw-r--r--zephyr/subsys/ap_pwrseq/power_host_sleep.c13
-rw-r--r--zephyr/test/ap_power/include/test_mocks.h1
-rw-r--r--zephyr/test/ap_power/src/ap_pwrseq.c17
-rw-r--r--zephyr/test/ap_power/src/test_mocks.c3
-rw-r--r--zephyr/test/drivers/dps/CMakeLists.txt2
-rw-r--r--zephyr/test/drivers/dps/src/dps_config.c (renamed from zephyr/test/drivers/dps/src/dps.c)40
-rw-r--r--zephyr/test/drivers/dps/src/dps_selection.c238
-rw-r--r--zephyr/test/krabby/pinctrl.dts10
-rw-r--r--zephyr/test/krabby/testcase.yaml2
42 files changed, 2724 insertions, 278 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain
index 80896e3e40..12e8440763 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -205,13 +205,6 @@ CXXFLAGS=$(CXXFLAGS_WARN)
CXXFLAGS+=-DPROTOBUF_INLINE_NOT_IN_HEADERS=0
ifeq ($(USE_BUILTIN_STDLIB), 1)
CPPFLAGS+=-DUSE_BUILTIN_STDLIB
-else
-# TODO(https://issuetracker.google.com/234507656#comment19): C++ include path
-# should not be necessary.
-CXXFLAGS+=-I/usr/armv7m-cros-eabi/usr/include/c++/v1
-# TODO(https://issuetracker.google.com/254916723): Remove when toolchain is
-# fixed.
-CPPFLAGS+=-D_GNU_SOURCE
endif
ifeq ($(LIBFTDI_NAME),)
diff --git a/board/gladios/board.c b/board/gladios/board.c
new file mode 100644
index 0000000000..318272f4c2
--- /dev/null
+++ b/board/gladios/board.c
@@ -0,0 +1,596 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "adc.h"
+#include "builtin/assert.h"
+#include "button.h"
+#include "charge_manager.h"
+#include "charge_state_v2.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "cros_board_info.h"
+#include "driver/tcpm/tcpci.h"
+#include "fw_config.h"
+#include "gpio.h"
+#include "gpio_signal.h"
+#include "hooks.h"
+#include "peripheral_charger.h"
+#include "power.h"
+#include "power_button.h"
+#include "switch.h"
+#include "throttle_ap.h"
+#include "usbc_config.h"
+#include "usbc_ppc.h"
+
+#include <stdbool.h>
+
+/* Console output macros */
+#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ##args)
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ##args)
+
+static void power_monitor(void);
+DECLARE_DEFERRED(power_monitor);
+
+/******************************************************************************/
+/* USB-A charging control */
+
+const int usb_port_enable[USB_PORT_COUNT] = {
+ GPIO_EN_PP5000_USBA,
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_port_enable) == USB_PORT_COUNT);
+
+extern struct pchg_drv cps8100_drv;
+struct pchg pchgs[] = {
+ [0] = {
+ .cfg = &(const struct pchg_config) {
+ .drv = &cps8100_drv,
+ .i2c_port = I2C_PORT_QI,
+ .irq_pin = GPIO_QI_INT_ODL,
+ .full_percent = 96,
+ .block_size = 128,
+ },
+ .policy = {
+ [PCHG_CHIPSET_STATE_ON] = &pchg_policy_on,
+ [PCHG_CHIPSET_STATE_SUSPEND] = &pchg_policy_suspend,
+ },
+ .events = QUEUE_NULL(PCHG_EVENT_QUEUE_SIZE, enum pchg_event),
+ },
+};
+const int pchg_count = ARRAY_SIZE(pchgs);
+
+__override void board_pchg_power_on(int port, bool on)
+{
+ if (port == 0)
+ gpio_set_level(GPIO_EC_QI_PWR, on);
+ else
+ CPRINTS("%s: Invalid port=%d", __func__, port);
+}
+
+/******************************************************************************/
+
+int board_set_active_charge_port(int port)
+{
+ CPRINTS("Requested charge port change to %d", port);
+
+ /*
+ * The charge manager may ask us to switch to no charger if we're
+ * running off USB-C only but upstream doesn't support PD. It requires
+ * that we accept this switch otherwise it triggers an assert and EC
+ * reset; it's not possible to boot the AP anyway, but we want to avoid
+ * resetting the EC so we can continue to do the "low power" LED blink.
+ */
+ if (port == CHARGE_PORT_NONE)
+ return EC_SUCCESS;
+
+ if (port < 0 || CHARGE_PORT_COUNT <= port)
+ return EC_ERROR_INVAL;
+
+ if (port == charge_manager_get_active_charge_port())
+ return EC_SUCCESS;
+
+ /* Don't charge from a source port */
+ if (board_vbus_source_enabled(port))
+ return EC_ERROR_INVAL;
+
+ if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ int bj_active, bj_requested;
+
+ if (charge_manager_get_active_charge_port() != CHARGE_PORT_NONE)
+ /* Change is only permitted while the system is off */
+ return EC_ERROR_INVAL;
+
+ /*
+ * Current setting is no charge port but the AP is on, so the
+ * charge manager is out of sync (probably because we're
+ * reinitializing after sysjump). Reject requests that aren't
+ * in sync with our outputs.
+ */
+ bj_active = !gpio_get_level(GPIO_EN_PPVAR_BJ_ADP_L);
+ bj_requested = port == CHARGE_PORT_BARRELJACK;
+ if (bj_active != bj_requested)
+ return EC_ERROR_INVAL;
+ }
+
+ CPRINTS("New charger p%d", port);
+
+ switch (port) {
+ case CHARGE_PORT_TYPEC0:
+ case CHARGE_PORT_TYPEC1:
+ case CHARGE_PORT_TYPEC2:
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 1);
+ break;
+ case CHARGE_PORT_BARRELJACK:
+ /* Make sure BJ adapter is sourcing power */
+ if (gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL))
+ return EC_ERROR_INVAL;
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 0);
+ break;
+ default:
+ return EC_ERROR_INVAL;
+ }
+
+ return EC_SUCCESS;
+}
+
+static uint8_t usbc_overcurrent;
+static int32_t base_5v_power_s5;
+static int32_t base_5v_power_z1;
+
+/*
+ * Power usage for each port as measured or estimated.
+ * Units are milliwatts (5v x ma current)
+ */
+
+/* PP5000_S5 loads */
+#define PWR_S5_BASE_LOAD (5 * 1431)
+#define PWR_S5_FRONT_HIGH (5 * 1737)
+#define PWR_S5_FRONT_LOW (5 * 1055)
+#define PWR_S5_REAR_HIGH (5 * 1737)
+#define PWR_S5_REAR_LOW (5 * 1055)
+#define PWR_S5_HDMI (5 * 580)
+#define PWR_S5_MAX (5 * 10000)
+#define FRONT_DELTA (PWR_S5_FRONT_HIGH - PWR_S5_FRONT_LOW)
+#define REAR_DELTA (PWR_S5_REAR_HIGH - PWR_S5_REAR_LOW)
+
+/* PP5000_Z1 loads */
+#define PWR_Z1_BASE_LOAD (5 * 5)
+#define PWR_Z1_C_HIGH (5 * 3600)
+#define PWR_Z1_C_LOW (5 * 2000)
+#define PWR_Z1_MAX (5 * 9000)
+/*
+ * Update the 5V power usage, assuming no throttling,
+ * and invoke the power monitoring.
+ */
+static void update_5v_usage(void)
+{
+ int front_ports = 0;
+ int rear_ports = 0;
+
+ /*
+ * Recalculate the 5V load, assuming no throttling.
+ */
+ base_5v_power_s5 = PWR_S5_BASE_LOAD;
+ if (!gpio_get_level(GPIO_USB_A0_OC_ODL)) {
+ front_ports++;
+ base_5v_power_s5 += PWR_S5_FRONT_LOW;
+ }
+ if (!gpio_get_level(GPIO_USB_A1_OC_ODL)) {
+ front_ports++;
+ base_5v_power_s5 += PWR_S5_FRONT_LOW;
+ }
+ /*
+ * Only 1 front port can run higher power at a time.
+ */
+ if (front_ports > 0)
+ base_5v_power_s5 += PWR_S5_FRONT_HIGH - PWR_S5_FRONT_LOW;
+
+ if (!gpio_get_level(GPIO_USB_A2_OC_ODL)) {
+ rear_ports++;
+ base_5v_power_s5 += PWR_S5_REAR_LOW;
+ }
+ if (!gpio_get_level(GPIO_USB_A3_OC_ODL)) {
+ rear_ports++;
+ base_5v_power_s5 += PWR_S5_REAR_LOW;
+ }
+ /*
+ * Only 1 rear port can run higher power at a time.
+ */
+ if (rear_ports > 0)
+ base_5v_power_s5 += PWR_S5_REAR_HIGH - PWR_S5_REAR_LOW;
+ if (!gpio_get_level(GPIO_HDMI_CONN_OC_ODL))
+ base_5v_power_s5 += PWR_S5_HDMI;
+ base_5v_power_z1 = PWR_Z1_BASE_LOAD;
+ if (usbc_overcurrent)
+ base_5v_power_z1 += PWR_Z1_C_HIGH;
+ /*
+ * Invoke the power handler immediately.
+ */
+ hook_call_deferred(&power_monitor_data, 0);
+}
+DECLARE_DEFERRED(update_5v_usage);
+/*
+ * Start power monitoring after ADCs have been initialised.
+ */
+DECLARE_HOOK(HOOK_INIT, update_5v_usage, HOOK_PRIO_INIT_ADC + 1);
+
+static void port_ocp_interrupt(enum gpio_signal signal)
+{
+ hook_call_deferred(&update_5v_usage_data, 0);
+}
+/* Must come after other header files and interrupt handler declarations */
+#include "gpio_list.h"
+
+/******************************************************************************/
+/*
+ * Barrel jack power supply handling
+ *
+ * EN_PPVAR_BJ_ADP_L must default active to ensure we can power on when the
+ * barrel jack is connected, and the USB-C port can bring the EC up fine in
+ * dead-battery mode. Both the USB-C and barrel jack switches do reverse
+ * protection, so we're safe to turn one on then the other off- but we should
+ * only do that if the system is off since it might still brown out.
+ */
+
+#define ADP_DEBOUNCE_MS 1000 /* Debounce time for BJ plug/unplug */
+/* Debounced connection state of the barrel jack */
+static int8_t adp_connected = -1;
+static void adp_connect_deferred(void)
+{
+ struct charge_port_info pi = { 0 };
+ int connected = !gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL);
+
+ /* Debounce */
+ if (connected == adp_connected)
+ return;
+ if (connected)
+ ec_bj_power(&pi.voltage, &pi.current);
+ charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED,
+ DEDICATED_CHARGE_PORT, &pi);
+ adp_connected = connected;
+}
+DECLARE_DEFERRED(adp_connect_deferred);
+
+/* IRQ for BJ plug/unplug. It shouldn't be called if BJ is the power source. */
+void adp_connect_interrupt(enum gpio_signal signal)
+{
+ hook_call_deferred(&adp_connect_deferred_data, ADP_DEBOUNCE_MS * MSEC);
+}
+
+static void adp_state_init(void)
+{
+ ASSERT(CHARGE_PORT_ENUM_COUNT == CHARGE_PORT_COUNT);
+ /*
+ * Initialize all charge suppliers to 0. The charge manager waits until
+ * all ports have reported in before doing anything.
+ */
+ for (int i = 0; i < CHARGE_PORT_COUNT; i++) {
+ for (int j = 0; j < CHARGE_SUPPLIER_COUNT; j++)
+ charge_manager_update_charge(j, i, NULL);
+ }
+
+ /* Report charge state from the barrel jack. */
+ adp_connect_deferred();
+}
+DECLARE_HOOK(HOOK_INIT, adp_state_init, HOOK_PRIO_INIT_CHARGE_MANAGER + 1);
+
+static void board_init(void)
+{
+ gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_ODL);
+ gpio_enable_interrupt(GPIO_HDMI_CONN_OC_ODL);
+ gpio_enable_interrupt(GPIO_USB_A0_OC_ODL);
+ gpio_enable_interrupt(GPIO_USB_A1_OC_ODL);
+ gpio_enable_interrupt(GPIO_USB_A2_OC_ODL);
+ gpio_enable_interrupt(GPIO_USB_A3_OC_ODL);
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+void board_overcurrent_event(int port, int is_overcurrented)
+{
+ /* Check that port number is valid. */
+ if ((port < 0) || (port >= CONFIG_USB_PD_PORT_MAX_COUNT))
+ return;
+ usbc_overcurrent = is_overcurrented;
+ update_5v_usage();
+}
+/*
+ * Power monitoring and management.
+ *
+ * the power budgets are met without letting the system fall into
+ * power deficit (perhaps causing a brownout).
+ *
+ * There are 2 power budgets that need to be managed:
+ * The overall goal is to gracefully manage the power demand so that
+ * - overall system power as measured on the main power supply rail.
+ * - 5V power delivered to the USB and HDMI ports.
+ *
+ * The actual system power demand is calculated from the VBUS voltage and
+ * the input current (read from a shunt), averaged over 5 readings.
+ * The power budget limit is from the charge manager.
+ *
+ * The 5V power cannot be read directly. Instead, we rely on overcurrent
+ * inputs from the USB and HDMI ports to indicate that the port is in use
+ * (and drawing maximum power).
+ *
+ * There are 3 throttles that can be applied (in priority order):
+ *
+ * - Type A BC1.2 front port restriction (3W)
+ * - Type A BC1.2 rear port restriction (3W)
+ * - Type C PD (throttle to 1.5A if sourcing)
+ * - Turn on PROCHOT, which immediately throttles the CPU.
+ *
+ * The first 3 throttles affect both the system power and the 5V rails.
+ * The third is a last resort to force an immediate CPU throttle to
+ * reduce the overall power use.
+ *
+ * The strategy is to determine what the state of the throttles should be,
+ * and to then turn throttles off or on as needed to match this.
+ *
+ * This function runs on demand, or every 2 ms when the CPU is up,
+ * and continually monitors the power usage, applying the
+ * throttles when necessary.
+ *
+ * All measurements are in milliwatts.
+ */
+#define THROT_TYPE_A_FRONT BIT(0)
+#define THROT_TYPE_A_REAR BIT(1)
+#define THROT_TYPE_C0 BIT(2)
+#define THROT_TYPE_C1 BIT(3)
+#define THROT_TYPE_C2 BIT(4)
+#define THROT_PROCHOT BIT(5)
+
+/*
+ * Power gain if front USB A ports are limited.
+ */
+#define POWER_GAIN_TYPE_A 3200
+/*
+ * Power gain if Type C port is limited.
+ */
+#define POWER_GAIN_TYPE_C 8800
+/*
+ * Power is averaged over 10 ms, with a reading every 2 ms.
+ */
+#define POWER_DELAY_MS 2
+#define POWER_READINGS (10 / POWER_DELAY_MS)
+
+static void power_monitor(void)
+{
+ static uint32_t current_state;
+ static uint32_t history[POWER_READINGS];
+ static uint8_t index;
+ int32_t delay;
+ uint32_t new_state = 0, diff;
+ int32_t headroom_5v_s5 = PWR_S5_MAX - base_5v_power_s5;
+ int32_t headroom_5v_z1 = PWR_Z1_MAX - base_5v_power_z1;
+
+ /*
+ * If CPU is off or suspended, no need to throttle
+ * or restrict power.
+ */
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF | CHIPSET_STATE_SUSPEND)) {
+ /*
+ * Slow down monitoring, assume no throttling required.
+ */
+ delay = 20 * MSEC;
+ /*
+ * Clear the first entry of the power table so that
+ * it is re-initilalised when the CPU starts.
+ */
+ history[0] = 0;
+ } else {
+ int32_t charger_mw;
+
+ delay = POWER_DELAY_MS * MSEC;
+ /*
+ * Get current charger limit (in mw).
+ * If not configured yet, skip.
+ */
+ charger_mw = charge_manager_get_power_limit_uw() / 1000;
+ if (charger_mw != 0) {
+ int32_t gap, total, max, power;
+ int i;
+
+ /*
+ * Read power usage.
+ */
+ power = (adc_read_channel(ADC_VBUS) *
+ adc_read_channel(ADC_PPVAR_IMON)) /
+ 1000;
+ /* Init power table */
+ if (history[0] == 0) {
+ for (i = 0; i < POWER_READINGS; i++)
+ history[i] = power;
+ }
+ /*
+ * Update the power readings and
+ * calculate the average and max.
+ */
+ history[index] = power;
+ index = (index + 1) % POWER_READINGS;
+ total = 0;
+ max = history[0];
+ for (i = 0; i < POWER_READINGS; i++) {
+ total += history[i];
+ if (history[i] > max)
+ max = history[i];
+ }
+ /*
+ * For Type-C power supplies, there is
+ * less tolerance for exceeding the rating,
+ * so use the max power that has been measured
+ * over the measuring period.
+ * For barrel-jack supplies, the rating can be
+ * exceeded briefly, so use the average.
+ */
+ if (charge_manager_get_supplier() == CHARGE_SUPPLIER_PD)
+ power = max;
+ else
+ power = total / POWER_READINGS;
+ /*
+ * Calculate gap, and if negative, power
+ * demand is exceeding configured power budget, so
+ * throttling is required to reduce the demand.
+ */
+ gap = charger_mw - power;
+ /*
+ * Limiting type-A power rear ports.
+ */
+ if (gap <= 0) {
+ new_state |= THROT_TYPE_A_REAR;
+ headroom_5v_s5 += REAR_DELTA;
+ if (!(current_state & THROT_TYPE_A_REAR))
+ gap += POWER_GAIN_TYPE_A;
+ }
+ /*
+ * Limiting type-A power front ports.
+ */
+ if (gap <= 0) {
+ new_state |= THROT_TYPE_A_FRONT;
+ headroom_5v_s5 += FRONT_DELTA;
+ if (!(current_state & THROT_TYPE_A_REAR))
+ gap += POWER_GAIN_TYPE_A;
+ }
+ /*
+ * If the type-C port is sourcing power,
+ * check whether it should be throttled.
+ */
+ if (ppc_is_sourcing_vbus(0) && gap <= 0) {
+ new_state |= THROT_TYPE_C0;
+ headroom_5v_z1 += PWR_Z1_C_HIGH - PWR_Z1_C_LOW;
+ if (!(current_state & THROT_TYPE_C0))
+ gap += POWER_GAIN_TYPE_C;
+ }
+ /*
+ * If the type-C port is sourcing power,
+ * check whether it should be throttled.
+ */
+ if (ppc_is_sourcing_vbus(1) && gap <= 0) {
+ new_state |= THROT_TYPE_C1;
+ headroom_5v_z1 += PWR_Z1_C_HIGH - PWR_Z1_C_LOW;
+ if (!(current_state & THROT_TYPE_C1))
+ gap += POWER_GAIN_TYPE_C;
+ }
+ /*
+ * If the type-C port is sourcing power,
+ * check whether it should be throttled.
+ */
+ if (ppc_is_sourcing_vbus(2) && gap <= 0) {
+ new_state |= THROT_TYPE_C2;
+ headroom_5v_z1 += PWR_Z1_C_HIGH - PWR_Z1_C_LOW;
+ if (!(current_state & THROT_TYPE_C2))
+ gap += POWER_GAIN_TYPE_C;
+ }
+ /*
+ * As a last resort, turn on PROCHOT to
+ * throttle the CPU.
+ */
+ if (gap <= 0)
+ new_state |= THROT_PROCHOT;
+ }
+ }
+ /*
+ * Check the 5v power usage and if necessary,
+ * adjust the throttles in priority order.
+ *
+ * Either throttle may have already been activated by
+ * the overall power control.
+ *
+ * We rely on the overcurrent detection to inform us
+ * if the port is in use.
+ *
+ * - If type C not already throttled:
+ * * If not overcurrent, prefer to limit type C [1].
+ * * If in overcurrentuse:
+ * - limit type A first [2]
+ * - If necessary, limit type C [3].
+ * - If type A not throttled, if necessary limit it [2].
+ */
+ if (headroom_5v_z1 < 0) {
+ /*
+ * Check whether type C is not throttled,
+ * and is not overcurrent.
+ */
+ if (!((new_state & THROT_TYPE_C0) || usbc_overcurrent)) {
+ /*
+ * [1] Type C not in overcurrent, throttle it.
+ */
+ headroom_5v_z1 += PWR_Z1_C_HIGH - PWR_Z1_C_LOW;
+ new_state |= THROT_TYPE_C0;
+ }
+ /*
+ * [2] If still under-budget, limit type C.
+ * No need to check if it is already throttled or not.
+ */
+ if (headroom_5v_z1 < 0)
+ new_state |= THROT_TYPE_C0;
+ }
+ if (headroom_5v_s5 < 0) {
+ /*
+ * [1] If type A rear not already throttled, and power still
+ * needed, limit type A rear.
+ */
+ if (!(new_state & THROT_TYPE_A_REAR) && headroom_5v_s5 < 0) {
+ headroom_5v_s5 += PWR_S5_REAR_HIGH - PWR_S5_REAR_LOW;
+ new_state |= THROT_TYPE_A_REAR;
+ }
+ /*
+ * [2] If type A front not already throttled, and power still
+ * needed, limit type A front.
+ */
+ if (!(new_state & THROT_TYPE_A_FRONT) && headroom_5v_s5 < 0) {
+ headroom_5v_s5 += PWR_S5_FRONT_HIGH - PWR_S5_FRONT_LOW;
+ new_state |= THROT_TYPE_A_FRONT;
+ }
+ }
+ /*
+ * Turn the throttles on or off if they have changed.
+ */
+ diff = new_state ^ current_state;
+ current_state = new_state;
+ if (diff & THROT_PROCHOT) {
+ int prochot = (new_state & THROT_PROCHOT) ? 0 : 1;
+
+ gpio_set_level(GPIO_EC_PROCHOT_ODL, prochot);
+ }
+ if (diff & THROT_TYPE_C0) {
+ enum tcpc_rp_value rp = (new_state & THROT_TYPE_C0) ?
+ TYPEC_RP_1A5 :
+ TYPEC_RP_3A0;
+
+ ppc_set_vbus_source_current_limit(0, rp);
+ tcpm_select_rp_value(0, rp);
+ pd_update_contract(0);
+ }
+ if (diff & THROT_TYPE_C1) {
+ enum tcpc_rp_value rp = (new_state & THROT_TYPE_C1) ?
+ TYPEC_RP_1A5 :
+ TYPEC_RP_3A0;
+
+ ppc_set_vbus_source_current_limit(1, rp);
+ tcpm_select_rp_value(1, rp);
+ pd_update_contract(1);
+ }
+ if (diff & THROT_TYPE_C2) {
+ enum tcpc_rp_value rp = (new_state & THROT_TYPE_C2) ?
+ TYPEC_RP_1A5 :
+ TYPEC_RP_3A0;
+
+ ppc_set_vbus_source_current_limit(2, rp);
+ tcpm_select_rp_value(2, rp);
+ pd_update_contract(2);
+ }
+ if (diff & THROT_TYPE_A_REAR) {
+ int typea_bc = (new_state & THROT_TYPE_A_REAR) ? 1 : 0;
+
+ gpio_set_level(GPIO_USB_A_LOW_PWR0_OD, typea_bc);
+ gpio_set_level(GPIO_USB_A_LOW_PWR1_OD, typea_bc);
+ }
+ if (diff & THROT_TYPE_A_FRONT) {
+ int typea_bc = (new_state & THROT_TYPE_A_FRONT) ? 1 : 0;
+
+ gpio_set_level(GPIO_USB_A_LOW_PWR2_OD, typea_bc);
+ gpio_set_level(GPIO_USB_A_LOW_PWR3_OD, typea_bc);
+ }
+ hook_call_deferred(&power_monitor_data, delay);
+}
diff --git a/board/gladios/board.h b/board/gladios/board.h
new file mode 100644
index 0000000000..7afa678c12
--- /dev/null
+++ b/board/gladios/board.h
@@ -0,0 +1,204 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Brask board configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+#include "compile_time_macros.h"
+
+/* Baseboard features */
+#include "baseboard.h"
+
+#define CONFIG_MP2964
+
+/* Barrel Jack */
+#define DEDICATED_CHARGE_PORT 3
+
+/* HDMI CEC */
+#define CONFIG_CEC
+#define CEC_GPIO_OUT GPIO_HDMI_CEC_OUT
+#define CEC_GPIO_IN GPIO_HDMI_CEC_IN
+#define CEC_GPIO_PULL_UP GPIO_HDMI_CEC_PULL_UP
+
+/* USB Type A Features */
+#define USB_PORT_COUNT 4
+#define CONFIG_USB_PORT_POWER_DUMB
+
+/* USB Type C and USB PD defines */
+#define CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY
+
+#define CONFIG_IO_EXPANDER
+#define CONFIG_IO_EXPANDER_NCT38XX
+#define CONFIG_IO_EXPANDER_PORT_COUNT 2
+
+#define CONFIG_USB_PD_PPC
+#define CONFIG_USB_PD_TCPM_RT1715
+#define CONFIG_USBC_RETIMER_INTEL_BB
+
+#define CONFIG_USBC_RETIMER_KB800X
+#define CONFIG_KB800X_CUSTOM_XBAR
+#define CONFIG_USBC_PPC_SYV682X
+#undef CONFIG_SYV682X_HV_ILIM
+#define CONFIG_SYV682X_HV_ILIM SYV682X_HV_ILIM_5_50
+
+/* TODO: b/177608416 - measure and check these values on brya */
+#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */
+#define PD_POWER_SUPPLY_TURN_OFF_DELAY 30000 /* us */
+#define PD_VCONN_SWAP_DELAY 5000 /* us */
+
+/* The design should support up to 100W. */
+/* TODO(b/197702356): Set the max PD to 60W now and change it
+ * to 100W after we verify it.
+ */
+#define PD_OPERATING_POWER_MW CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON
+#define PD_MAX_POWER_MW 100000
+#define PD_MAX_CURRENT_MA 5000
+#define PD_MAX_VOLTAGE_MV 20000
+
+/*
+ * Macros for GPIO signals used in common code that don't match the
+ * schematic names. Signal names in gpio.inc match the schematic and are
+ * then redefined here to so it's more clear which signal is being used for
+ * which purpose.
+ */
+#define GPIO_AC_PRESENT GPIO_ACOK_OD
+#define GPIO_CPU_PROCHOT GPIO_EC_PROCHOT_ODL
+#define GPIO_EC_INT_L GPIO_EC_PCH_INT_ODL
+#define GPIO_ENTERING_RW GPIO_EC_ENTERING_RW
+#define GPIO_PACKET_MODE_EN GPIO_EC_GSC_PACKET_MODE
+#define GPIO_PCH_PWRBTN_L GPIO_EC_PCH_PWR_BTN_ODL
+#define GPIO_PCH_RSMRST_L GPIO_EC_PCH_RSMRST_L
+#define GPIO_PCH_RTCRST GPIO_EC_PCH_RTCRST
+#define GPIO_PCH_SLP_S0_L GPIO_SYS_SLP_S0IX_L
+#define GPIO_PCH_SLP_S3_L GPIO_SLP_S3_L
+#define GPIO_TEMP_SENSOR_POWER GPIO_SEQ_EC_DSW_PWROK
+
+/*
+ * GPIO_EC_PCH_INT_ODL is used for MKBP events as well as a PCH wakeup
+ * signal.
+ */
+#define GPIO_PCH_WAKE_L GPIO_EC_PCH_INT_ODL
+#define GPIO_PG_EC_ALL_SYS_PWRGD GPIO_SEQ_EC_ALL_SYS_PG
+#define GPIO_PG_EC_DSW_PWROK GPIO_SEQ_EC_DSW_PWROK
+#define GPIO_PG_EC_RSMRST_ODL GPIO_SEQ_EC_RSMRST_ODL
+#define GPIO_POWER_BUTTON_L GPIO_GSC_EC_PWR_BTN_ODL
+#define GPIO_SYS_RESET_L GPIO_SYS_RST_ODL
+#define GPIO_WP_L GPIO_EC_WP_ODL
+#define GPIO_RECOVERY_L GPIO_EC_RECOVERY_BTN_OD
+#define GPIO_RECOVERY_L_2 GPIO_GSC_EC_RECOVERY_BTN_OD
+
+/* I2C Bus Configuration */
+
+#define I2C_PORT_DP_REDRIVER NPCX_I2C_PORT0_0
+
+#define I2C_PORT_USB_C0_C2_TCPC NPCX_I2C_PORT1_0
+#define I2C_PORT_USB_C1_TCPC NPCX_I2C_PORT4_1
+
+#define I2C_PORT_USB_C0_C2_PPC NPCX_I2C_PORT2_0
+#define I2C_PORT_USB_C1_PPC NPCX_I2C_PORT6_1
+
+#define I2C_PORT_USB_C0_C2_BC12 NPCX_I2C_PORT2_0
+#define I2C_PORT_USB_C1_BC12 NPCX_I2C_PORT6_1
+
+#define I2C_PORT_USB_C0_C2_MUX NPCX_I2C_PORT3_0
+#define I2C_PORT_USB_C1_MUX NPCX_I2C_PORT6_1
+
+#define I2C_PORT_QI NPCX_I2C_PORT5_0
+#define I2C_PORT_EEPROM NPCX_I2C_PORT7_0
+#define I2C_PORT_MP2964 NPCX_I2C_PORT7_0
+
+#define I2C_ADDR_EEPROM_FLAGS 0x50
+
+#define I2C_ADDR_MP2964_FLAGS 0x20
+
+#define USBC_PORT_C0_BB_RETIMER_I2C_ADDR 0x58
+#define USBC_PORT_C2_BB_RETIMER_I2C_ADDR 0x59
+
+/* Enabling Thunderbolt-compatible mode */
+#define CONFIG_USB_PD_TBT_COMPAT_MODE
+
+/* Enabling USB4 mode */
+#define CONFIG_USB_PD_USB4
+#define CONFIG_USB_PD_DATA_RESET_MSG
+
+/* Retimer */
+#define CONFIG_USBC_RETIMER_FW_UPDATE
+
+/* Thermal features */
+#define CONFIG_THERMISTOR
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_POWER
+#define CONFIG_STEINHART_HART_3V3_30K9_47K_4050B
+
+/* ADC */
+#define CONFIG_ADC
+
+/*
+ * TODO(b/197478860): Enable the fan control. We need
+ * to check the sensor value and adjust the fan speed.
+ */
+#define CONFIG_FANS FAN_CH_COUNT
+
+/* Include math_util for bitmask_uint64 used in pd_timers */
+#define CONFIG_MATH_UTIL
+
+/* WPC/Qi charger */
+#ifdef SECTION_IS_RW
+#define CONFIG_PERIPHERAL_CHARGER
+#define CONFIG_CPS8100
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include "gpio_signal.h" /* needed by registers.h */
+#include "registers.h"
+#include "usbc_config.h"
+
+enum charge_port {
+ CHARGE_PORT_TYPEC0,
+ CHARGE_PORT_TYPEC1,
+ CHARGE_PORT_TYPEC2,
+ CHARGE_PORT_BARRELJACK,
+ CHARGE_PORT_ENUM_COUNT
+};
+
+enum adc_channel {
+ ADC_TEMP_SENSOR_1_CPU,
+ ADC_TEMP_SENSOR_2_CPU_VR,
+ ADC_TEMP_SENSOR_3_WIFI,
+ ADC_TEMP_SENSOR_4_DIMM,
+ ADC_VBUS,
+ ADC_PPVAR_IMON, /* ADC3 */
+ ADC_CH_COUNT
+};
+
+enum temp_sensor_id {
+ TEMP_SENSOR_1_CPU,
+ TEMP_SENSOR_2_CPU_VR,
+ TEMP_SENSOR_3_WIFI,
+ TEMP_SENSOR_4_DIMM,
+ TEMP_SENSOR_COUNT
+};
+
+enum ioex_port { IOEX_C0_NCT38XX = 0, IOEX_C2_NCT38XX, IOEX_PORT_COUNT };
+
+enum pwm_channel {
+ PWM_CH_LED_GREEN, /* PWM0 */
+ PWM_CH_FAN, /* PWM5 */
+ PWM_CH_LED_RED, /* PWM2 */
+ PWM_CH_COUNT
+};
+
+enum fan_channel { FAN_CH_0 = 0, FAN_CH_COUNT };
+
+enum mft_channel { MFT_CH_0 = 0, MFT_CH_COUNT };
+
+extern void adp_connect_interrupt(enum gpio_signal signal);
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/gladios/build.mk b/board/gladios/build.mk
new file mode 100644
index 0000000000..3de758d1bd
--- /dev/null
+++ b/board/gladios/build.mk
@@ -0,0 +1,22 @@
+# -*- makefile -*-
+# Copyright 2022 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Brask board specific files build
+#
+
+CHIP:=npcx
+CHIP_FAMILY:=npcx9
+CHIP_VARIANT:=npcx9m3f
+BASEBOARD:=brask
+
+board-y=
+board-y+=board.o
+board-y+=fans.o
+board-y+=fw_config.o
+board-y+=i2c.o
+board-y+=led.o
+board-y+=pwm.o
+board-y+=sensors.o
+board-y+=usbc_config.o
diff --git a/board/gladios/ec.tasklist b/board/gladios/ec.tasklist
new file mode 100644
index 0000000000..d16fc35f52
--- /dev/null
+++ b/board/gladios/ec.tasklist
@@ -0,0 +1,29 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * See CONFIG_TASK_LIST in config.h for details.
+ *
+ * USB_CHG_Px tasks must be contiguous (see USB_CHG_PORT_TO_TASK_ID(x)).
+ * PD_Cx tasks must be contiguous (see PD_PORT_TO_TASK_ID(x))
+ */
+
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS_RW(PCHG, pchg_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 0, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P2, usb_charger_task, 0, TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_MUX, usb_mux_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C2, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C0, pd_shared_alert_task, (BIT(2) | BIT(0)), LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CEC, cec_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/gladios/fans.c b/board/gladios/fans.c
new file mode 100644
index 0000000000..3f3ad3ccea
--- /dev/null
+++ b/board/gladios/fans.c
@@ -0,0 +1,50 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Physical fans. These are logically separate from pwm_channels. */
+
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "fan.h"
+#include "fan_chip.h"
+#include "hooks.h"
+#include "pwm.h"
+
+/* MFT channels. These are logically separate from pwm_channels. */
+const struct mft_t mft_channels[] = {
+ [MFT_CH_0] = {
+ .module = NPCX_MFT_MODULE_2,
+ .clk_src = TCKC_LFCLK,
+ .pwm_id = PWM_CH_FAN,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT);
+
+static const struct fan_conf fan_conf_0 = {
+ .flags = FAN_USE_RPM_MODE,
+ .ch = MFT_CH_0, /* Use MFT id to control fan */
+ .pgood_gpio = -1,
+ .enable_gpio = GPIO_EN_PP5000_FAN,
+};
+
+/*
+ * TOOD(b/197478860): need to update for real fan
+ *
+ * Prototype fan spins at about 7200 RPM at 100% PWM.
+ * Set minimum at around 30% PWM.
+ */
+static const struct fan_rpm fan_rpm_0 = {
+ .rpm_min = 2200,
+ .rpm_start = 2200,
+ .rpm_max = 7200,
+};
+
+const struct fan_t fans[FAN_CH_COUNT] = {
+ [FAN_CH_0] = {
+ .conf = &fan_conf_0,
+ .rpm = &fan_rpm_0,
+ },
+};
diff --git a/board/gladios/fw_config.c b/board/gladios/fw_config.c
new file mode 100644
index 0000000000..3ee71e6a0f
--- /dev/null
+++ b/board/gladios/fw_config.c
@@ -0,0 +1,65 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "cbi.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "cros_board_info.h"
+#include "fw_config.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
+
+static union brask_cbi_fw_config fw_config;
+BUILD_ASSERT(sizeof(fw_config) == sizeof(uint32_t));
+
+/*
+ * FW_CONFIG defaults for brask if the CBI.FW_CONFIG data is not
+ * initialized.
+ */
+static const union brask_cbi_fw_config fw_config_defaults = {
+ .audio = DB_NAU88L25B_I2S,
+ .bj_power = BJ_135W,
+};
+
+/*
+ * Barrel-jack power adapter ratings.
+ */
+static const struct {
+ int voltage;
+ int current;
+} bj_power[] = {
+ [BJ_135W] = { /* 0 - 135W (also default) */
+ .voltage = 19500,
+ .current = 6920
+ },
+ [BJ_230W] = { /* 1 - 230W */
+ .voltage = 19500,
+ .current = 11800
+ }
+};
+
+/****************************************************************************
+ * Brask FW_CONFIG access
+ */
+void board_init_fw_config(void)
+{
+ if (cbi_get_fw_config(&fw_config.raw_value)) {
+ CPRINTS("CBI: Read FW_CONFIG failed, using board defaults");
+ fw_config = fw_config_defaults;
+ }
+}
+
+void ec_bj_power(uint32_t *voltage, uint32_t *current)
+{
+ unsigned int bj;
+
+ bj = fw_config.bj_power;
+ /* Out of range value defaults to 0 */
+ if (bj >= ARRAY_SIZE(bj_power))
+ bj = 0;
+ *voltage = bj_power[bj].voltage;
+ *current = bj_power[bj].current;
+}
diff --git a/board/gladios/fw_config.h b/board/gladios/fw_config.h
new file mode 100644
index 0000000000..95d81f1e05
--- /dev/null
+++ b/board/gladios/fw_config.h
@@ -0,0 +1,41 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __BOARD_BRASK_FW_CONFIG_H_
+#define __BOARD_BRASK_FW_CONFIG_H_
+
+#include <stdint.h>
+
+/****************************************************************************
+ * CBI FW_CONFIG layout for Brask board.
+ *
+ * Source of truth is the project/brask/brask/config.star configuration file.
+ */
+enum ec_cfg_audio_type { DB_AUDIO_UNKNOWN = 0, DB_NAU88L25B_I2S = 1 };
+
+enum ec_cfg_bj_power { BJ_135W = 0, BJ_230W = 1 };
+
+union brask_cbi_fw_config {
+ struct {
+ uint32_t audio : 3;
+ uint32_t bj_power : 2;
+ uint32_t reserved_1 : 27;
+ };
+ uint32_t raw_value;
+};
+
+/**
+ * Read the cached FW_CONFIG. Guaranteed to have valid values.
+ *
+ * @return the FW_CONFIG for the board.
+ */
+union brask_cbi_fw_config get_fw_config(void);
+
+/**
+ * Get the barrel-jack power from FW_CONFIG.
+ */
+void ec_bj_power(uint32_t *voltage, uint32_t *current);
+
+#endif /* __BOARD_BRASK_FW_CONFIG_H_ */
diff --git a/board/gladios/gpio.inc b/board/gladios/gpio.inc
new file mode 100644
index 0000000000..51cf0010c6
--- /dev/null
+++ b/board/gladios/gpio.inc
@@ -0,0 +1,187 @@
+/* -*- mode:c -*-
+ *
+ * Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* INTERRUPT GPIOs: */
+
+GPIO_INT(ACOK_OD, PIN(0, 0), GPIO_INT_BOTH, extpower_interrupt)
+GPIO_INT(EC_PROCHOT_IN_L, PIN(F, 0), GPIO_INT_BOTH, throttle_ap_prochot_input_interrupt)
+GPIO_INT(EC_WP_ODL, PIN(A, 1), GPIO_INT_BOTH, switch_interrupt)
+GPIO_INT(GSC_EC_PWR_BTN_ODL, PIN(0, 1), GPIO_INT_BOTH, power_button_interrupt)
+GPIO_INT(SEQ_EC_ALL_SYS_PG, PIN(F, 4), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SEQ_EC_DSW_PWROK, PIN(C, 7), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SEQ_EC_RSMRST_ODL, PIN(E, 2), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SLP_S3_L, PIN(A, 5), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SLP_SUS_L, PIN(F, 1), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SYS_SLP_S0IX_L, PIN(D, 5), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(USB_C0_BC12_INT_ODL, PIN(C, 6), GPIO_INT_FALLING, bc12_interrupt)
+GPIO_INT(USB_C0_C2_TCPC_INT_ODL, PIN(E, 0), GPIO_INT_FALLING, tcpc_alert_event)
+GPIO_INT(USB_C0_PPC_INT_ODL, PIN(6, 2), GPIO_INT_FALLING, ppc_interrupt)
+GPIO_INT(USB_C0_RT_INT_ODL, PIN(B, 1), GPIO_INT_FALLING, retimer_interrupt)
+GPIO_INT(USB_C1_BC12_INT_ODL, PIN(5, 0), GPIO_INT_FALLING, bc12_interrupt)
+GPIO_INT(USB_C1_PPC_INT_ODL, PIN(F, 5), GPIO_INT_FALLING, ppc_interrupt)
+GPIO_INT(USB_C1_TCPC_INT_ODL, PIN(A, 2), GPIO_INT_FALLING, tcpc_alert_event)
+GPIO_INT(USB_C2_BC12_INT_ODL, PIN(8, 3), GPIO_INT_FALLING, bc12_interrupt)
+GPIO_INT(USB_C2_PPC_INT_ODL, PIN(7, 0), GPIO_INT_FALLING, ppc_interrupt)
+GPIO_INT(USB_C2_RT_INT_ODL, PIN(4, 1), GPIO_INT_FALLING, retimer_interrupt)
+GPIO_INT(BJ_ADP_PRESENT_ODL, PIN(8, 2), GPIO_INT_BOTH | GPIO_PULL_UP, adp_connect_interrupt)
+GPIO_INT(EC_RECOVERY_BTN_OD, PIN(2, 3), GPIO_INT_BOTH, button_interrupt)
+GPIO_INT(HDMI_CONN_OC_ODL, PIN(2, 4), GPIO_INPUT | GPIO_INT_BOTH, port_ocp_interrupt)
+GPIO_INT(USB_A0_OC_ODL, PIN(3, 1), GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH, port_ocp_interrupt)
+GPIO_INT(USB_A1_OC_ODL, PIN(3, 0), GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH, port_ocp_interrupt)
+GPIO_INT(USB_A2_OC_ODL, PIN(2, 7), GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH, port_ocp_interrupt)
+GPIO_INT(USB_A3_OC_ODL, PIN(2, 6), GPIO_INPUT | GPIO_PULL_UP | GPIO_INT_BOTH, port_ocp_interrupt)
+#ifdef SECTION_IS_RW
+GPIO_INT(QI_INT_ODL, PIN(9, 6), GPIO_INT_FALLING, pchg_irq)
+#else
+UNIMPLEMENTED(QI_INT_ODL)
+#endif
+
+/* CCD */
+GPIO(CCD_MODE_ODL, PIN(E, 5), GPIO_INPUT)
+
+/* Security */
+GPIO(EC_ENTERING_RW, PIN(0, 3), GPIO_OUT_LOW)
+GPIO(EC_GSC_PACKET_MODE, PIN(7, 5), GPIO_OUT_LOW)
+
+/* Fan */
+GPIO(EN_PP5000_FAN, PIN(6, 1), GPIO_OUT_HIGH)
+
+/* ADC, need to check the usage */
+GPIO(ANALOG_PPVAR_PWR_IN_IMON_EC, PIN(4, 2), GPIO_INPUT)
+
+/* Display */
+GPIO(DP_CONN_OC_ODL, PIN(2, 5), GPIO_INPUT)
+
+
+/* BarrelJack */
+GPIO(EN_PPVAR_BJ_ADP_L, PIN(0, 7), GPIO_OUT_LOW)
+
+/* Chipset PCH */
+GPIO(EC_PCHHOT_ODL, PIN(7, 4), GPIO_INPUT)
+GPIO(EC_PCH_INT_ODL, PIN(B, 0), GPIO_ODR_HIGH)
+GPIO(EC_PCH_RSMRST_L, PIN(A, 6), GPIO_OUT_LOW)
+GPIO(EC_PCH_RTCRST, PIN(7, 6), GPIO_OUT_LOW)
+GPIO(EC_PCH_SYS_PWROK, PIN(3, 7), GPIO_OUT_LOW)
+GPIO(EC_PCH_WAKE_ODL, PIN(C, 0), GPIO_ODR_HIGH)
+GPIO(EC_PROCHOT_ODL, PIN(6, 3), GPIO_ODR_HIGH)
+GPIO(EN_S5_RAILS, PIN(B, 6), GPIO_OUT_LOW)
+GPIO(PCH_PWROK, PIN(7, 2), GPIO_OUT_LOW)
+GPIO(SYS_RST_ODL, PIN(C, 5), GPIO_ODR_HIGH)
+GPIO(VCCST_PWRGD_OD, PIN(A, 4), GPIO_ODR_LOW)
+GPIO(IMVP9_VRRDY_OD, PIN(6, 0), GPIO_INPUT)
+GPIO(CPU_C10_GATE_L, PIN(6, 7), GPIO_INPUT)
+
+/* Button */
+GPIO(EC_PCH_PWR_BTN_ODL, PIN(C, 1), GPIO_ODR_HIGH)
+GPIO(GSC_EC_RECOVERY_BTN_OD, PIN(2, 2), GPIO_INPUT)
+
+/* NFC */
+/* TODO(b/194068530): Enable NFC */
+GPIO(NFC_COIL_ACT_L, PIN(D, 4), GPIO_INPUT)
+GPIO(NFC_LOW_POWER_MODE, PIN(9, 5), GPIO_OUT_HIGH)
+GPIO(NFC_CARD_DET_L, PIN(A, 3), GPIO_INPUT)
+GPIO(EN_NFC_BUZZER, PIN(0, 5), GPIO_OUT_LOW)
+
+/* Wireless Charger */
+GPIO(EC_QI_PWR, PIN(D, 2), GPIO_OUT_LOW)
+GPIO(QI_RESET_L, PIN(9, 3), GPIO_OUT_HIGH)
+
+/* HDMI CEC */
+/* TODO(b/197474873): Enable HDMI CEC */
+GPIO(HDMI_CEC_IN, PIN(4, 0), GPIO_INPUT)
+GPIO(HDMI_CEC_OUT, PIN(D, 3), GPIO_OUT_HIGH | GPIO_OPEN_DRAIN)
+GPIO(HDMI_CEC_PULL_UP, PIN(C, 2), GPIO_OUT_HIGH)
+
+/* I2C SCL/SDA */
+GPIO(EC_I2C_QI_SCL, PIN(3, 3), GPIO_INPUT)
+GPIO(EC_I2C_QI_SDA, PIN(3, 6), GPIO_INPUT)
+GPIO(EC_I2C_MISC_SCL_R, PIN(B, 3), GPIO_INPUT)
+GPIO(EC_I2C_MISC_SDA_R, PIN(B, 2), GPIO_INPUT)
+GPIO(EC_I2C_DP_SCL, PIN(B, 5), GPIO_INPUT)
+GPIO(EC_I2C_DP_SDA, PIN(B, 4), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_PPC_SCL, PIN(9, 2), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_PPC_SDA, PIN(9, 1), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_RT_SCL, PIN(D, 1), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_RT_SDA, PIN(D, 0), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_TCPC_SCL, PIN(9, 0), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_C2_TCPC_SDA, PIN(8, 7), GPIO_INPUT)
+GPIO(EC_I2C_USB_C1_MIX_SCL, PIN(E, 4), GPIO_INPUT)
+GPIO(EC_I2C_USB_C1_MIX_SDA, PIN(E, 3), GPIO_INPUT)
+GPIO(EC_I2C_USB_C1_TCPC_SCL, PIN(F, 3), GPIO_INPUT)
+GPIO(EC_I2C_USB_C1_TCPC_SDA, PIN(F, 2), GPIO_INPUT)
+
+/* USBA */
+GPIO(EN_PP5000_USBA, PIN(D, 7), GPIO_OUT_LOW)
+GPIO(USB_A0_STATUS_L, PIN(2, 1), GPIO_INPUT)
+GPIO(USB_A1_STATUS_L, PIN(2, 0), GPIO_INPUT)
+GPIO(USB_A2_STATUS_L, PIN(1, 7), GPIO_INPUT)
+GPIO(USB_A3_STATUS_L, PIN(1, 6), GPIO_INPUT)
+GPIO(USB_A_LOW_PWR0_OD, PIN(1, 5), GPIO_INPUT | GPIO_PULL_DOWN)
+GPIO(USB_A_LOW_PWR1_OD, PIN(1, 4), GPIO_INPUT | GPIO_PULL_DOWN)
+GPIO(USB_A_LOW_PWR2_OD, PIN(1, 1), GPIO_INPUT | GPIO_PULL_DOWN)
+GPIO(USB_A_LOW_PWR3_OD, PIN(1, 0), GPIO_INPUT | GPIO_PULL_DOWN)
+GPIO(USB_A_OC_SOC_L, PIN(8, 0), GPIO_OUT_HIGH)
+
+/* LED */
+/* TODO(b/197471359): LED implementation */
+GPIO(LED_GREEN_L, PIN(C, 3), GPIO_OUT_LOW)
+GPIO(LED_RED_L, PIN(C, 4), GPIO_OUT_LOW)
+
+/* USBC */
+GPIO(USB_C0_C2_TCPC_RST_ODL, PIN(A, 7), GPIO_ODR_LOW)
+GPIO(USB_C1_FRS_EN, PIN(9, 4), GPIO_OUT_LOW)
+GPIO(USB_C1_RT_INT_ODL, PIN(A, 0), GPIO_INPUT)
+GPIO(USB_C1_RT_RST_R_L, PIN(0, 2), GPIO_OUT_LOW)
+
+/* GPIO02_P2 to PU */
+/* GPIO03_P2 to PU */
+IOEX(USB_C0_OC_ODL, EXPIN(IOEX_C0_NCT38XX, 0, 4), GPIO_ODR_HIGH)
+IOEX(USB_C0_FRS_EN, EXPIN(IOEX_C0_NCT38XX, 0, 6), GPIO_LOW)
+IOEX(USB_C0_RT_RST_ODL, EXPIN(IOEX_C0_NCT38XX, 0, 7), GPIO_ODR_LOW)
+
+IOEX(USB_C2_RT_RST_ODL, EXPIN(IOEX_C2_NCT38XX, 0, 2), GPIO_ODR_LOW)
+IOEX(USB_C1_OC_ODL, EXPIN(IOEX_C2_NCT38XX, 0, 3), GPIO_ODR_HIGH)
+IOEX(USB_C2_OC_ODL, EXPIN(IOEX_C2_NCT38XX, 0, 4), GPIO_ODR_HIGH)
+IOEX(USB_C2_FRS_EN, EXPIN(IOEX_C2_NCT38XX, 0, 6), GPIO_LOW)
+/* GPIO07_P2 to PU */
+
+/* UART alternate functions */
+ALTERNATE(PIN_MASK(6, 0x30), 0, MODULE_UART, 0) /* GPIO64/CR_SIN1, GPO65/CR_SOUT1/FLPRG1_L */
+
+/* I2C alternate functions */
+ALTERNATE(PIN_MASK(3, 0x48), 0, MODULE_I2C, 0) /* GPIO33/I2C5_SCL0/CTS_L, GPIO36/RTS_L/I2C5_SDA0 */
+ALTERNATE(PIN_MASK(8, 0x80), 0, MODULE_I2C, 0) /* GPIO87/I2C1_SDA0 */
+ALTERNATE(PIN_MASK(9, 0x07), 0, MODULE_I2C, 0) /* GPIO92/I2C2_SCL0, GPIO91/I2C2_SDA0, GPIO90/I2C1_SCL0 */
+ALTERNATE(PIN_MASK(B, 0x0c), 0, MODULE_I2C, 0) /* GPIOB3/I2C7_SCL0/DCD_L, GPIOB2/I2C7_SDA0/DSR_L */
+ALTERNATE(PIN_MASK(B, 0x30), 0, MODULE_I2C, 0) /* GPIOB5/I2C0_SCL0, GPIOB4/I2C0_SDA0 */
+ALTERNATE(PIN_MASK(D, 0x03), 0, MODULE_I2C, 0) /* GPIOD1/I2C3_SCL0, GPIOD0/I2C3_SDA0 */
+ALTERNATE(PIN_MASK(E, 0x18), 0, MODULE_I2C, 0) /* GPIOE4/I2C6_SCL1/I3C_SCL, GPIOE3/I2C6_SDA1/I3C_SDA */
+ALTERNATE(PIN_MASK(F, 0x0c), 0, MODULE_I2C, 0) /* GPIOF3/I2C4_SCL1, GPIOF2/I2C4_SDA1 */
+
+/* PWM alternate functions */
+ALTERNATE(PIN_MASK(7, 0x08), 0, MODULE_PWM, 0) /* GPIO73/TA2 */
+ALTERNATE(PIN_MASK(B, 0x80), 0, MODULE_PWM, 0) /* GPIOB7/PWM5 */
+ALTERNATE(PIN_MASK(C, 0x18), 0, MODULE_PWM, 0) /* GPIOC4/PWM2, GPIOC3/PWM0 */
+
+/* ADC alternate functions */
+ALTERNATE(PIN_MASK(3, 0x10), 0, MODULE_ADC, 0) /* GPIO34/PS2_DAT2/ADC6 */
+ALTERNATE(PIN_MASK(4, 0x38), 0, MODULE_ADC, 0) /* GPIO45/ADC0, GPIO44/ADC1, GPIO43/ADC2 */
+ALTERNATE(PIN_MASK(E, 0x02), 0, MODULE_ADC, 0) /* GPIOE1/ADC7 */
+
+/* Unused Pins */
+UNUSED(PIN(D, 6)) /* GPOD6/CR_SOUT3/SHDF_ESPI_L */
+UNUSED(PIN(3, 2)) /* GPO32/TRIS_L */
+UNUSED(PIN(3, 5)) /* GPO35/CR_SOUT4/TEST_L */
+UNUSED(PIN(6, 6)) /* GPIO66 */
+UNUSED(PIN(8, 1)) /* GPIO81/PECI_DATA */
+UNUSED(PIN(5, 6)) /* GPIO56/CLKRUN# */
+UNUSED(PIN(9, 7)) /* GPIO97 */
+UNUSED(PIN(8, 6)) /* GPIO86/TXD/CR_SOUT2 */
+UNUSED(PIN(1, 3)) /* KSO06/GPO13/GP_SEL# */
+UNUSED(PIN(1, 2)) /* KSO07/GPO12/JEN# */
+UNUSED(PIN(0, 6)) /* KSO11/GPIO06/P80_CLK */
+UNUSED(PIN(0, 4)) /* KSO13/GPIO04 */
diff --git a/board/gladios/i2c.c b/board/gladios/i2c.c
new file mode 100644
index 0000000000..45eba1e13c
--- /dev/null
+++ b/board/gladios/i2c.c
@@ -0,0 +1,77 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "compile_time_macros.h"
+#include "i2c.h"
+
+/* I2C port map configuration */
+const struct i2c_port_t i2c_ports[] = {
+ {
+ /* I2C0 */
+ .name = "dp_redriver",
+ .port = I2C_PORT_DP_REDRIVER,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_DP_SCL,
+ .sda = GPIO_EC_I2C_DP_SDA,
+ },
+ {
+ /* I2C1 */
+ .name = "tcpc0,2",
+ .port = I2C_PORT_USB_C0_C2_TCPC,
+ .kbps = 1000,
+ .scl = GPIO_EC_I2C_USB_C0_C2_TCPC_SCL,
+ .sda = GPIO_EC_I2C_USB_C0_C2_TCPC_SDA,
+ },
+ {
+ /* I2C2 */
+ .name = "ppc0,2",
+ .port = I2C_PORT_USB_C0_C2_PPC,
+ .kbps = 1000,
+ .scl = GPIO_EC_I2C_USB_C0_C2_PPC_SCL,
+ .sda = GPIO_EC_I2C_USB_C0_C2_PPC_SDA,
+ },
+ {
+ /* I2C3 */
+ .name = "retimer0,2",
+ .port = I2C_PORT_USB_C0_C2_MUX,
+ .kbps = 1000,
+ .scl = GPIO_EC_I2C_USB_C0_C2_RT_SCL,
+ .sda = GPIO_EC_I2C_USB_C0_C2_RT_SDA,
+ },
+ {
+ /* I2C4 C1 TCPC */
+ .name = "tcpc1",
+ .port = I2C_PORT_USB_C1_TCPC,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_USB_C1_TCPC_SCL,
+ .sda = GPIO_EC_I2C_USB_C1_TCPC_SDA,
+ },
+ {
+ /* I2C5 */
+ .name = "wireless_charger",
+ .port = I2C_PORT_QI,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_QI_SCL,
+ .sda = GPIO_EC_I2C_QI_SDA,
+ },
+ {
+ /* I2C6 */
+ .name = "ppc1",
+ .port = I2C_PORT_USB_C1_PPC,
+ .kbps = 1000,
+ .scl = GPIO_EC_I2C_USB_C1_MIX_SCL,
+ .sda = GPIO_EC_I2C_USB_C1_MIX_SDA,
+ },
+ {
+ /* I2C7 */
+ .name = "eeprom",
+ .port = I2C_PORT_EEPROM,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_MISC_SCL_R,
+ .sda = GPIO_EC_I2C_MISC_SDA_R,
+ },
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
diff --git a/board/gladios/led.c b/board/gladios/led.c
new file mode 100644
index 0000000000..a4b9a0d094
--- /dev/null
+++ b/board/gladios/led.c
@@ -0,0 +1,260 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Power LED control for Brask.
+ * Solid green - active power
+ * Green flashing - suspended
+ * Red flashing - alert
+ * Solid red - critical
+ */
+
+#include "chipset.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "led_common.h"
+#include "pwm.h"
+#include "timer.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_GPIO, format, ##args)
+
+/*
+ * Due to the CSME-Lite processing, upon startup the CPU transitions through
+ * S0->S3->S5->S3->S0, causing the LED to turn on/off/on, so
+ * delay turning off the LED during suspend/shutdown.
+ */
+#define LED_CPU_DELAY_MS (2000 * MSEC)
+
+const enum ec_led_id supported_led_ids[] = { EC_LED_ID_POWER_LED };
+const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+
+enum led_color {
+ LED_OFF = 0,
+ LED_RED,
+ LED_GREEN,
+
+ /* Number of colors, not a color itself */
+ LED_COLOR_COUNT
+};
+
+static int set_color_power(enum led_color color, int duty)
+{
+ int green = 0;
+ int red = 0;
+
+ if (duty < 0 || 100 < duty)
+ return EC_ERROR_UNKNOWN;
+
+ switch (color) {
+ case LED_OFF:
+ break;
+ case LED_GREEN:
+ green = 1;
+ break;
+ case LED_RED:
+ red = 1;
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+
+ if (red)
+ pwm_set_duty(PWM_CH_LED_RED, duty);
+ else
+ pwm_set_duty(PWM_CH_LED_RED, 0);
+
+ if (green)
+ pwm_set_duty(PWM_CH_LED_GREEN, duty);
+ else
+ pwm_set_duty(PWM_CH_LED_GREEN, 0);
+
+ return EC_SUCCESS;
+}
+
+static int set_color(enum ec_led_id id, enum led_color color, int duty)
+{
+ switch (id) {
+ case EC_LED_ID_POWER_LED:
+ return set_color_power(color, duty);
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+}
+
+#define LED_PULSE_US (2 * SECOND)
+/* 40 msec for nice and smooth transition. */
+#define LED_PULSE_TICK_US (40 * MSEC)
+
+/*
+ * When pulsing is enabled, brightness is incremented by <duty_inc> every
+ * <interval> usec from 0 to 100% in LED_PULSE_US usec. Then it's decremented
+ * likewise in LED_PULSE_US usec.
+ */
+static struct {
+ uint32_t interval;
+ int duty_inc;
+ enum led_color color;
+ int duty;
+} led_pulse;
+
+#define CONFIG_TICK(interval, color) \
+ config_tick((interval), 100 / (LED_PULSE_US / (interval)), (color))
+
+static void config_tick(uint32_t interval, int duty_inc, enum led_color color)
+{
+ led_pulse.interval = interval;
+ led_pulse.duty_inc = duty_inc;
+ led_pulse.color = color;
+ led_pulse.duty = 0;
+}
+
+static void pulse_power_led(enum led_color color)
+{
+ set_color(EC_LED_ID_POWER_LED, color, led_pulse.duty);
+ if (led_pulse.duty + led_pulse.duty_inc > 100)
+ led_pulse.duty_inc = led_pulse.duty_inc * -1;
+ else if (led_pulse.duty + led_pulse.duty_inc < 0)
+ led_pulse.duty_inc = led_pulse.duty_inc * -1;
+ led_pulse.duty += led_pulse.duty_inc;
+}
+
+static void led_tick(void);
+DECLARE_DEFERRED(led_tick);
+static void led_tick(void)
+{
+ uint32_t elapsed;
+ uint32_t next = 0;
+ uint32_t start = get_time().le.lo;
+
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ pulse_power_led(led_pulse.color);
+ elapsed = get_time().le.lo - start;
+ next = led_pulse.interval > elapsed ? led_pulse.interval - elapsed : 0;
+ hook_call_deferred(&led_tick_data, next);
+}
+
+static void led_suspend(void)
+{
+ CONFIG_TICK(LED_PULSE_TICK_US, LED_GREEN);
+ led_tick();
+}
+DECLARE_DEFERRED(led_suspend);
+
+static void led_shutdown(void)
+{
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ set_color(EC_LED_ID_POWER_LED, LED_OFF, 0);
+}
+DECLARE_DEFERRED(led_shutdown);
+
+static void led_shutdown_hook(void)
+{
+ hook_call_deferred(&led_tick_data, -1);
+ hook_call_deferred(&led_suspend_data, -1);
+ hook_call_deferred(&led_shutdown_data, LED_CPU_DELAY_MS);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, led_shutdown_hook, HOOK_PRIO_DEFAULT);
+
+static void led_suspend_hook(void)
+{
+ hook_call_deferred(&led_shutdown_data, -1);
+ hook_call_deferred(&led_suspend_data, LED_CPU_DELAY_MS);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, led_suspend_hook, HOOK_PRIO_DEFAULT);
+
+static void led_resume(void)
+{
+ /*
+ * Assume there is no race condition with led_tick, which also
+ * runs in hook_task.
+ */
+ hook_call_deferred(&led_tick_data, -1);
+ /*
+ * Avoid invoking the suspend/shutdown delayed hooks.
+ */
+ hook_call_deferred(&led_suspend_data, -1);
+ hook_call_deferred(&led_shutdown_data, -1);
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ set_color(EC_LED_ID_POWER_LED, LED_GREEN, 100);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, led_resume, HOOK_PRIO_DEFAULT);
+
+void led_alert(int enable)
+{
+ if (enable) {
+ /* Overwrite the current signal */
+ config_tick(1 * SECOND, 100, LED_RED);
+ led_tick();
+ } else {
+ /* Restore the previous signal */
+ if (chipset_in_state(CHIPSET_STATE_ON))
+ led_resume();
+ else if (chipset_in_state(CHIPSET_STATE_SUSPEND))
+ led_suspend_hook();
+ else if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ led_shutdown_hook();
+ }
+}
+
+void show_critical_error(void)
+{
+ hook_call_deferred(&led_tick_data, -1);
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ set_color(EC_LED_ID_POWER_LED, LED_RED, 100);
+}
+
+static int command_led(int argc, const char **argv)
+{
+ enum ec_led_id id = EC_LED_ID_POWER_LED;
+
+ if (argc < 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ if (!strcasecmp(argv[1], "debug")) {
+ led_auto_control(id, !led_auto_control_is_enabled(id));
+ ccprintf("o%s\n", led_auto_control_is_enabled(id) ? "ff" : "n");
+ } else if (!strcasecmp(argv[1], "off")) {
+ set_color(id, LED_OFF, 0);
+ } else if (!strcasecmp(argv[1], "red")) {
+ set_color(id, LED_RED, 100);
+ } else if (!strcasecmp(argv[1], "green")) {
+ set_color(id, LED_GREEN, 100);
+ } else if (!strcasecmp(argv[1], "alert")) {
+ led_alert(1);
+ } else if (!strcasecmp(argv[1], "crit")) {
+ show_critical_error();
+ } else {
+ return EC_ERROR_PARAM1;
+ }
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(led, command_led, "[debug|red|green|off|alert|crit]",
+ "Turn on/off LED.");
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ brightness_range[EC_LED_COLOR_RED] = 100;
+ brightness_range[EC_LED_COLOR_GREEN] = 100;
+}
+
+int led_set_brightness(enum ec_led_id id, const uint8_t *brightness)
+{
+ if (brightness[EC_LED_COLOR_RED])
+ return set_color(id, LED_RED, brightness[EC_LED_COLOR_RED]);
+ else if (brightness[EC_LED_COLOR_GREEN])
+ return set_color(id, LED_GREEN, brightness[EC_LED_COLOR_GREEN]);
+ else
+ return set_color(id, LED_OFF, 0);
+}
+__override void board_set_charge_limit(int port, int supplier, int charge_ma,
+ int max_ma, int charge_mv)
+{
+ /* Blink alert if insufficient power per system_can_boot_ap(). */
+ int insufficient_power =
+ (charge_ma * charge_mv) <
+ (CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON * 1000);
+ led_alert(insufficient_power);
+}
diff --git a/board/gladios/pwm.c b/board/gladios/pwm.c
new file mode 100644
index 0000000000..53e59919ab
--- /dev/null
+++ b/board/gladios/pwm.c
@@ -0,0 +1,39 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "compile_time_macros.h"
+#include "hooks.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+
+const struct pwm_t pwm_channels[] = {
+ [PWM_CH_LED_GREEN] = { .channel = 0,
+ .flags = PWM_CONFIG_ACTIVE_LOW |
+ PWM_CONFIG_DSLEEP,
+ .freq = 2000 },
+ [PWM_CH_FAN] = { .channel = 5,
+ .flags = PWM_CONFIG_OPEN_DRAIN | PWM_CONFIG_DSLEEP,
+ .freq = 1000 },
+ [PWM_CH_LED_RED] = { .channel = 2,
+ .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
+ .freq = 2000 },
+};
+BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
+
+static void board_pwm_init(void)
+{
+ /*
+ * TODO(b/197478860): Turn on the fan at 100% by default
+ * We need to find tune the fan speed according to the
+ * thermal sensor value.
+ */
+ pwm_enable(PWM_CH_FAN, 1);
+ pwm_set_duty(PWM_CH_FAN, 100);
+
+ pwm_enable(PWM_CH_LED_RED, 1);
+ pwm_enable(PWM_CH_LED_GREEN, 1);
+}
+DECLARE_HOOK(HOOK_INIT, board_pwm_init, HOOK_PRIO_DEFAULT);
diff --git a/board/gladios/sensors.c b/board/gladios/sensors.c
new file mode 100644
index 0000000000..13948f60d8
--- /dev/null
+++ b/board/gladios/sensors.c
@@ -0,0 +1,114 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "adc_chip.h"
+#include "common.h"
+#include "hooks.h"
+#include "temp_sensor.h"
+#include "temp_sensor/thermistor.h"
+#include "thermal.h"
+
+/* ADC configuration */
+const struct adc_t adc_channels[] = {
+ [ADC_TEMP_SENSOR_1_CPU] = {
+ .name = "TEMP_CPU",
+ .input_ch = NPCX_ADC_CH0,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_TEMP_SENSOR_2_CPU_VR] = {
+ .name = "TEMP_CPU_VR",
+ .input_ch = NPCX_ADC_CH1,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_TEMP_SENSOR_3_WIFI] = {
+ .name = "TEMP_WIFI",
+ .input_ch = NPCX_ADC_CH6,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_TEMP_SENSOR_4_DIMM] = {
+ .name = "TEMP_DIMM",
+ .input_ch = NPCX_ADC_CH7,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_VBUS] = { /* 5/39 voltage divider */
+ .name = "VBUS",
+ .input_ch = NPCX_ADC_CH2,
+ .factor_mul = ADC_MAX_VOLT * 39,
+ .factor_div = (ADC_READ_MAX + 1) * 5,
+ },
+ [ADC_PPVAR_IMON] = { /* 872.3 mV/A */
+ .name = "PPVAR_IMON",
+ .input_ch = NPCX_ADC_CH3,
+ .factor_mul = ADC_MAX_VOLT * 1433,
+ .factor_div = (ADC_READ_MAX + 1) * 1250,
+ },
+
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* Temperature sensor configuration */
+const struct temp_sensor_t temp_sensors[] = {
+ [TEMP_SENSOR_1_CPU] = { .name = "CPU",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_1_CPU },
+ [TEMP_SENSOR_2_CPU_VR] = { .name = "CPU VR",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_2_CPU_VR },
+ [TEMP_SENSOR_3_WIFI] = { .name = "WIFI",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_3_WIFI },
+ [TEMP_SENSOR_4_DIMM] = { .name = "DIMM",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_4_DIMM },
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/*
+ * TODO(b/180681346): update for Alder Lake/brya
+ *
+ * Tiger Lake specifies 100 C as maximum TDP temperature. THRMTRIP# occurs at
+ * 130 C. However, sensor is located next to DDR, so we need to use the lower
+ * DDR temperature limit (85 C)
+ */
+/*
+ * TODO(b/202062363): Remove when clang is fixed.
+ */
+#define THERMAL_CPU \
+ { \
+ .temp_host = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(70), \
+ [EC_TEMP_THRESH_HALT] = C_TO_K(80), \
+ }, \
+ .temp_host_release = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(65), \
+ }, \
+ .temp_fan_off = C_TO_K(35), \
+ .temp_fan_max = C_TO_K(50), \
+ }
+__maybe_unused static const struct ec_thermal_config thermal_cpu = THERMAL_CPU;
+
+/*
+ * TODO(b/197478860): add the thermal sensor setting
+ */
+/* this should really be "const" */
+struct ec_thermal_config thermal_params[] = {
+ [TEMP_SENSOR_1_CPU] = THERMAL_CPU,
+ [TEMP_SENSOR_2_CPU_VR] = THERMAL_CPU,
+ [TEMP_SENSOR_3_WIFI] = THERMAL_CPU,
+ [TEMP_SENSOR_4_DIMM] = THERMAL_CPU,
+};
+BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
diff --git a/board/gladios/usbc_config.c b/board/gladios/usbc_config.c
new file mode 100644
index 0000000000..125b443f8c
--- /dev/null
+++ b/board/gladios/usbc_config.c
@@ -0,0 +1,416 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "driver/bc12/pi3usb9201_public.h"
+#include "driver/ppc/syv682x_public.h"
+#include "driver/retimer/bb_retimer_public.h"
+#include "driver/retimer/kb800x.h"
+#include "driver/tcpm/nct38xx.h"
+#include "driver/tcpm/rt1715.h"
+#include "driver/tcpm/tcpci.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "gpio_signal.h"
+#include "hooks.h"
+#include "ioexpander.h"
+#include "system.h"
+#include "task.h"
+#include "task_id.h"
+#include "timer.h"
+#include "usb_charge.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+#include "usbc_config.h"
+#include "usbc_ppc.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ##args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ##args)
+
+/* USBC TCPC configuration */
+const struct tcpc_config_t tcpc_config[] = {
+ [USBC_PORT_C0] = {
+ .bus_type = EC_BUS_TYPE_I2C,
+ .i2c_info = {
+ .port = I2C_PORT_USB_C0_C2_TCPC,
+ .addr_flags = NCT38XX_I2C_ADDR1_1_FLAGS,
+ },
+ .drv = &nct38xx_tcpm_drv,
+ .flags = TCPC_FLAGS_TCPCI_REV2_0 |
+ TCPC_FLAGS_NO_DEBUG_ACC_CONTROL,
+ },
+ [USBC_PORT_C1] = {
+ .bus_type = EC_BUS_TYPE_I2C,
+ .i2c_info = {
+ .port = I2C_PORT_USB_C1_TCPC,
+ .addr_flags = RT1715_I2C_ADDR_FLAGS,
+ },
+ .drv = &rt1715_tcpm_drv,
+ },
+ [USBC_PORT_C2] = {
+ .bus_type = EC_BUS_TYPE_I2C,
+ .i2c_info = {
+ .port = I2C_PORT_USB_C0_C2_TCPC,
+ .addr_flags = NCT38XX_I2C_ADDR2_1_FLAGS,
+ },
+ .drv = &nct38xx_tcpm_drv,
+ .flags = TCPC_FLAGS_TCPCI_REV2_0,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(tcpc_config) == USBC_PORT_COUNT);
+BUILD_ASSERT(CONFIG_USB_PD_PORT_MAX_COUNT == USBC_PORT_COUNT);
+
+/* USBC PPC configuration */
+struct ppc_config_t ppc_chips[] = {
+ [USBC_PORT_C0] = {
+ .i2c_port = I2C_PORT_USB_C0_C2_PPC,
+ .i2c_addr_flags = SYV682X_ADDR0_FLAGS,
+ .drv = &syv682x_drv,
+ },
+ [USBC_PORT_C1] = {
+ .i2c_port = I2C_PORT_USB_C1_PPC,
+ .i2c_addr_flags = SYV682X_ADDR0_FLAGS,
+ .drv = &syv682x_drv,
+ },
+ [USBC_PORT_C2] = {
+ .i2c_port = I2C_PORT_USB_C0_C2_PPC,
+ .i2c_addr_flags = SYV682X_ADDR2_FLAGS,
+ .drv = &syv682x_drv,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(ppc_chips) == USBC_PORT_COUNT);
+
+unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips);
+
+/* USBC mux configuration - Alder Lake includes internal mux */
+static const struct usb_mux_chain usbc0_tcss_usb_mux = {
+ .mux =
+ &(const struct usb_mux){
+ .usb_port = USBC_PORT_C0,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ },
+};
+static const struct usb_mux_chain usbc1_tcss_usb_mux = {
+ .mux =
+ &(const struct usb_mux){
+ .usb_port = USBC_PORT_C1,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ },
+};
+static const struct usb_mux_chain usbc2_tcss_usb_mux = {
+ .mux =
+ &(const struct usb_mux){
+ .usb_port = USBC_PORT_C2,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ },
+};
+
+struct kb800x_control_t kb800x_control[] = {
+ [USBC_PORT_C0] = {
+ },
+ [USBC_PORT_C1] = {
+ .retimer_rst_gpio = GPIO_USB_C1_RT_RST_R_L,
+ .ss_lanes = {
+ [KB800X_A0] = KB800X_TX0, [KB800X_A1] = KB800X_RX0,
+ [KB800X_B0] = KB800X_RX1, [KB800X_B1] = KB800X_TX1,
+ [KB800X_C0] = KB800X_RX0, [KB800X_C1] = KB800X_TX0,
+ [KB800X_D0] = KB800X_TX1, [KB800X_D1] = KB800X_RX1,
+ }
+ },
+ [USBC_PORT_C2] = {
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(kb800x_control) == USBC_PORT_COUNT);
+
+const struct usb_mux_chain usb_muxes[] = {
+ [USBC_PORT_C0] = {
+ .mux = &(const struct usb_mux) {
+ .usb_port = USBC_PORT_C0,
+ .driver = &bb_usb_retimer,
+ .hpd_update = bb_retimer_hpd_update,
+ .i2c_port = I2C_PORT_USB_C0_C2_MUX,
+ .i2c_addr_flags = USBC_PORT_C0_BB_RETIMER_I2C_ADDR,
+ },
+ .next = &usbc0_tcss_usb_mux,
+ },
+ [USBC_PORT_C1] = {
+ .mux = &(const struct usb_mux) {
+ .usb_port = USBC_PORT_C1,
+ .driver = &kb800x_usb_mux_driver,
+ .i2c_port = I2C_PORT_USB_C1_MUX,
+ .i2c_addr_flags = KB800X_I2C_ADDR0_FLAGS,
+ },
+ .next = &usbc1_tcss_usb_mux,
+ },
+ [USBC_PORT_C2] = {
+ .mux = &(const struct usb_mux) {
+ .usb_port = USBC_PORT_C2,
+ .driver = &bb_usb_retimer,
+ .hpd_update = bb_retimer_hpd_update,
+ .i2c_port = I2C_PORT_USB_C0_C2_MUX,
+ .i2c_addr_flags = USBC_PORT_C2_BB_RETIMER_I2C_ADDR,
+ },
+ .next = &usbc2_tcss_usb_mux,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == USBC_PORT_COUNT);
+
+/* BC1.2 charger detect configuration */
+const struct pi3usb9201_config_t pi3usb9201_bc12_chips[] = {
+ [USBC_PORT_C0] = {
+ .i2c_port = I2C_PORT_USB_C0_C2_BC12,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+ [USBC_PORT_C1] = {
+ .i2c_port = I2C_PORT_USB_C1_BC12,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+ [USBC_PORT_C2] = {
+ .i2c_port = I2C_PORT_USB_C0_C2_BC12,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_1_FLAGS,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pi3usb9201_bc12_chips) == USBC_PORT_COUNT);
+
+/*
+ * USB C0 and C2 uses burnside bridge chips and have their reset
+ * controlled by their respective TCPC chips acting as GPIO expanders.
+ *
+ * ioex_init() is normally called before we take the TCPCs out of
+ * reset, so we need to start in disabled mode, then explicitly
+ * call ioex_init().
+ */
+
+struct ioexpander_config_t ioex_config[] = {
+ [IOEX_C0_NCT38XX] = {
+ .i2c_host_port = I2C_PORT_USB_C0_C2_TCPC,
+ .i2c_addr_flags = NCT38XX_I2C_ADDR1_1_FLAGS,
+ .drv = &nct38xx_ioexpander_drv,
+ .flags = IOEX_FLAGS_DEFAULT_INIT_DISABLED,
+ },
+ [IOEX_C2_NCT38XX] = {
+ .i2c_host_port = I2C_PORT_USB_C0_C2_TCPC,
+ .i2c_addr_flags = NCT38XX_I2C_ADDR2_1_FLAGS,
+ .drv = &nct38xx_ioexpander_drv,
+ .flags = IOEX_FLAGS_DEFAULT_INIT_DISABLED,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(ioex_config) == CONFIG_IO_EXPANDER_PORT_COUNT);
+
+__override int bb_retimer_power_enable(const struct usb_mux *me, bool enable)
+{
+ enum ioex_signal rst_signal;
+
+ if (me->usb_port == USBC_PORT_C0) {
+ rst_signal = IOEX_USB_C0_RT_RST_ODL;
+ } else if (me->usb_port == USBC_PORT_C2) {
+ rst_signal = IOEX_USB_C2_RT_RST_ODL;
+ } else {
+ return EC_ERROR_INVAL;
+ }
+
+ /*
+ * We do not have a load switch for the burnside bridge chips,
+ * so we only need to sequence reset.
+ */
+
+ if (enable) {
+ /*
+ * Tpw, minimum time from VCC to RESET_N de-assertion is 100us.
+ * For boards that don't provide a load switch control, the
+ * retimer_init() function ensures power is up before calling
+ * this function.
+ */
+ ioex_set_level(rst_signal, 1);
+ /*
+ * Allow 1ms time for the retimer to power up lc_domain
+ * which powers I2C controller within retimer
+ */
+ msleep(1);
+ } else {
+ ioex_set_level(rst_signal, 0);
+ msleep(1);
+ }
+ return EC_SUCCESS;
+}
+
+__override int bb_retimer_reset(const struct usb_mux *me)
+{
+ /*
+ * TODO(b/193402306, b/195375738): Remove this once transition to
+ * QS Silicon is complete
+ */
+ bb_retimer_power_enable(me, false);
+ msleep(5);
+ bb_retimer_power_enable(me, true);
+ msleep(25);
+
+ return EC_SUCCESS;
+}
+
+void board_reset_pd_mcu(void)
+{
+ enum gpio_signal tcpc_rst;
+
+ tcpc_rst = GPIO_USB_C0_C2_TCPC_RST_ODL;
+
+ /*
+ * TODO(b/179648104): figure out correct timing
+ */
+
+ gpio_set_level(tcpc_rst, 0);
+ gpio_set_level(GPIO_USB_C1_RT_RST_R_L, 0);
+
+ /*
+ * delay for power-on to reset-off and min. assertion time
+ */
+
+ msleep(20);
+
+ gpio_set_level(tcpc_rst, 1);
+ gpio_set_level(GPIO_USB_C1_RT_RST_R_L, 1);
+
+ /* wait for chips to come up */
+
+ msleep(50);
+}
+
+static void enable_ioex(int ioex)
+{
+ ioex_init(ioex);
+}
+
+static void board_tcpc_init(void)
+{
+ /* Don't reset TCPCs after initial reset */
+ if (!system_jumped_late()) {
+ board_reset_pd_mcu();
+
+ /*
+ * These IO expander pins are implemented using the
+ * C0/C2 TCPC, so they must be set up after the TCPC has
+ * been taken out of reset.
+ */
+ enable_ioex(IOEX_C0_NCT38XX);
+ enable_ioex(IOEX_C2_NCT38XX);
+ }
+
+ /* Enable PPC interrupts. */
+ gpio_enable_interrupt(GPIO_USB_C0_PPC_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C2_PPC_INT_ODL);
+
+ /* Enable TCPC interrupts. */
+ gpio_enable_interrupt(GPIO_USB_C0_C2_TCPC_INT_ODL);
+
+ gpio_enable_interrupt(GPIO_USB_C1_PPC_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C1_TCPC_INT_ODL);
+}
+DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_CHIPSET);
+
+uint16_t tcpc_get_alert_status(void)
+{
+ uint16_t status = 0;
+
+ if (gpio_get_level(GPIO_USB_C0_C2_TCPC_INT_ODL) == 0)
+ status |= PD_STATUS_TCPC_ALERT_0 | PD_STATUS_TCPC_ALERT_2;
+
+ if (gpio_get_level(GPIO_USB_C1_TCPC_INT_ODL) == 0)
+ status |= PD_STATUS_TCPC_ALERT_1;
+
+ return status;
+}
+
+int ppc_get_alert_status(int port)
+{
+ if (port == USBC_PORT_C0)
+ return gpio_get_level(GPIO_USB_C0_PPC_INT_ODL) == 0;
+ else if (port == USBC_PORT_C1)
+ return gpio_get_level(GPIO_USB_C1_PPC_INT_ODL) == 0;
+ else if (port == USBC_PORT_C2)
+ return gpio_get_level(GPIO_USB_C2_PPC_INT_ODL) == 0;
+ return 0;
+}
+
+void tcpc_alert_event(enum gpio_signal signal)
+{
+ switch (signal) {
+ case GPIO_USB_C0_C2_TCPC_INT_ODL:
+ schedule_deferred_pd_interrupt(USBC_PORT_C0);
+ break;
+ case GPIO_USB_C1_TCPC_INT_ODL:
+ schedule_deferred_pd_interrupt(USBC_PORT_C1);
+ break;
+ default:
+ break;
+ }
+}
+
+void bc12_interrupt(enum gpio_signal signal)
+{
+ switch (signal) {
+ case GPIO_USB_C0_BC12_INT_ODL:
+ usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
+ break;
+ case GPIO_USB_C1_BC12_INT_ODL:
+ usb_charger_task_set_event(1, USB_CHG_EVENT_BC12);
+ break;
+ case GPIO_USB_C2_BC12_INT_ODL:
+ usb_charger_task_set_event(2, USB_CHG_EVENT_BC12);
+ break;
+ default:
+ break;
+ }
+}
+
+void ppc_interrupt(enum gpio_signal signal)
+{
+ switch (signal) {
+ case GPIO_USB_C0_PPC_INT_ODL:
+ syv682x_interrupt(USBC_PORT_C0);
+ break;
+ case GPIO_USB_C1_PPC_INT_ODL:
+ syv682x_interrupt(USBC_PORT_C1);
+ break;
+ case GPIO_USB_C2_PPC_INT_ODL:
+ syv682x_interrupt(USBC_PORT_C2);
+ break;
+ default:
+ break;
+ }
+}
+
+void retimer_interrupt(enum gpio_signal signal)
+{
+ /*
+ * TODO(b/179513527): add USB-C support
+ */
+}
+
+__override bool board_is_dts_port(int port)
+{
+ return port == USBC_PORT_C0;
+}
+
+__override bool board_is_tbt_usb4_port(int port)
+{
+ return true;
+}
+
+__override enum tbt_compat_cable_speed board_get_max_tbt_speed(int port)
+{
+ if (!board_is_tbt_usb4_port(port))
+ return TBT_SS_RES_0;
+
+ return TBT_SS_TBT_GEN3;
+}
diff --git a/board/gladios/usbc_config.h b/board/gladios/usbc_config.h
new file mode 100644
index 0000000000..5e7beae21a
--- /dev/null
+++ b/board/gladios/usbc_config.h
@@ -0,0 +1,20 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Brya board-specific USB-C configuration */
+
+#ifndef __CROS_EC_USBC_CONFIG_H
+#define __CROS_EC_USBC_CONFIG_H
+
+#define CONFIG_USB_PD_PORT_MAX_COUNT 3
+
+enum usbc_port {
+ USBC_PORT_C0 = 0,
+ USBC_PORT_C1,
+ USBC_PORT_C2,
+ USBC_PORT_COUNT
+};
+
+#endif /* __CROS_EC_USBC_CONFIG_H */
diff --git a/board/gladios/vif_override.xml b/board/gladios/vif_override.xml
new file mode 100644
index 0000000000..32736caf64
--- /dev/null
+++ b/board/gladios/vif_override.xml
@@ -0,0 +1,3 @@
+<!-- Add VIF field overrides here. See genvif.c and the Vendor Info File
+ Definition from the USB-IF.
+-->
diff --git a/cmake/toolchain-armv7m.cmake b/cmake/toolchain-armv7m.cmake
index 641b0debf2..48c2ac18a5 100644
--- a/cmake/toolchain-armv7m.cmake
+++ b/cmake/toolchain-armv7m.cmake
@@ -23,10 +23,6 @@ add_compile_options(-Oz)
add_compile_options(-flto)
add_link_options(-flto)
-# TODO(b/234507656): Remove this include when clang is fixed.
-add_compile_options(-I/usr/armv7m-cros-eabi/usr/include/c++/v1)
-# TODO(b/254916723): Remove this define when clang is fixed.
-add_compile_options(-D_GNU_SOURCE)
add_link_options(-lclang_rt.builtins-armv7m)
add_link_options(-lnosys)
diff --git a/common/dps.c b/common/dps.c
index b0751acc39..8facc57c68 100644
--- a/common/dps.c
+++ b/common/dps.c
@@ -169,7 +169,7 @@ bool is_more_efficient(int curr_mv, int prev_mv, int batt_mv, int batt_mw,
*
* @return input_power of the result of vbus * input_curr in mW
*/
-static int get_desired_input_power(int *vbus, int *input_current)
+test_mockable_static int get_desired_input_power(int *vbus, int *input_current)
{
int active_port;
int charger_id;
@@ -197,7 +197,7 @@ static int get_desired_input_power(int *vbus, int *input_current)
return (*vbus) * (*input_current) / 1000;
}
-static int get_battery_target_voltage(int *target_mv)
+test_mockable_static int get_battery_target_voltage(int *target_mv)
{
int charger_id = charge_get_active_chg_chip();
int error = charger_get_voltage(charger_id, target_mv);
@@ -231,7 +231,7 @@ static int get_battery_target_voltage(int *target_mv)
*
* @return 0 if error occurs, else battery efficient voltage in mV
*/
-static int get_efficient_voltage(void)
+test_mockable_static int get_efficient_voltage(void)
{
int eff_mv = 0;
int batt_mv;
@@ -290,13 +290,20 @@ struct pdo_candidate {
return false; \
} while (0)
+test_mockable_static int get_batt_charge_power(void)
+{
+ const struct batt_params *batt = charger_current_battery_params();
+
+ return batt->current * batt->voltage / 1000;
+}
+
/*
* Evaluate the system power if a new PD power request is needed.
*
* @param struct pdo_candidate: The candidate PDO. (Return value)
* @return true if a new power request, or false otherwise.
*/
-__maybe_unused static bool has_new_power_request(struct pdo_candidate *cand)
+test_mockable_static bool has_new_power_request(struct pdo_candidate *cand)
{
int vbus, input_curr, input_pwr;
int input_pwr_avg = 0, input_curr_avg = 0;
@@ -311,7 +318,6 @@ __maybe_unused static bool has_new_power_request(struct pdo_candidate *cand)
static int prev_active_port = CHARGE_PORT_NONE;
static int prev_req_mv;
static int moving_avg_count;
- const struct batt_params *batt = charger_current_battery_params();
/* set a default value in case it early returns. */
UPDATE_CANDIDATE(CHARGE_PORT_NONE, INT32_MAX, 0);
@@ -335,7 +341,7 @@ __maybe_unused static bool has_new_power_request(struct pdo_candidate *cand)
prev_req_mv = req_mv;
req_pwr = req_mv * req_ma / 1000;
- batt_pwr = batt->current * batt->voltage / 1000;
+ batt_pwr = get_batt_charge_power();
input_pwr = get_desired_input_power(&vbus, &input_curr);
if (!input_pwr)
diff --git a/include/common.h b/include/common.h
index 02f7449d81..496fa42247 100644
--- a/include/common.h
+++ b/include/common.h
@@ -8,6 +8,13 @@
#ifndef __CROS_EC_COMMON_H
#define __CROS_EC_COMMON_H
+/*
+ * I don't know why but gcc's preprocessor doesn't like the autoconf.h file,
+ * sometimes. Adding a #line directive anywhere in this file seems to fix the
+ * problem. #line marks the *next* line, so it is off by one.
+ */
+#line 17
+
#include "compile_time_macros.h"
#include <inttypes.h>
diff --git a/include/gpio.h b/include/gpio.h
index 086ed9131f..2c5006a8ec 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -92,6 +92,16 @@
#elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_gpio_emul)
#define GPIO_VOLTAGE_1P8 NATIVE_POSIX_GPIO_VOLTAGE_1P8
#define GPIO_SEL_1P8V GPIO_VOLTAGE_1P8
+#elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_gpio_v2)
+/*
+ * Add GPIO_VOLTAGE_1P8 and GPIO_SEL_1P8V used in common code.
+ * In MEC1727, GPIO_VOLTAGE_1P8 feature is not supported in GPIO control
+ * register, GPIO driver will skip this bit configuration, but MEC1727
+ * supports a group of GPIOs with 1.8V power rail, 1.8V design will be
+ * considered and supported in board circuit design state.
+ */
+#define GPIO_VOLTAGE_1P8 (1U << 11)
+#define GPIO_SEL_1P8V GPIO_VOLTAGE_1P8
#endif
/* GPIO_ALTERNATE not supported by Zephyr */
/* GPIO_LOCKED not supported by Zephyr */
diff --git a/include/test_util.h b/include/test_util.h
index efdee22cc6..e3a9f27ebc 100644
--- a/include/test_util.h
+++ b/include/test_util.h
@@ -55,6 +55,17 @@ extern "C" {
#define __auto_type auto
#endif
+/* Tests comparing complex types that cannot be easily formatted for printing
+ * may define TEST_OPERATOR_INHIBIT_PRINT_EVAL to inhibit printing of the
+ * compared values on failure.
+ */
+#ifdef TEST_OPERATOR_INHIBIT_PRINT_EVAL
+#define TEST_OPERATOR_PRINT_EVAL(fmt, op, _a, _b)
+#else
+#define TEST_OPERATOR_PRINT_EVAL(fmt, op, _a, _b) \
+ ccprintf("\t\tEVAL: " fmt " " #op " " fmt "\n", _a, _b)
+#endif
+
#define TEST_OPERATOR(a, b, op, fmt) \
do { \
__auto_type _a = (a); \
@@ -62,8 +73,7 @@ extern "C" {
if (!(_a op _b)) { \
ccprintf("%s:%d: ASSERTION failed: %s " #op " %s\n", \
__FILE__, __LINE__, #a, #b); \
- ccprintf("\t\tEVAL: " fmt " " #op " " fmt "\n", _a, \
- _b); \
+ TEST_OPERATOR_PRINT_EVAL(fmt, op, _a, _b); \
task_dump_trace(); \
return EC_ERROR_UNKNOWN; \
} else { \
diff --git a/util/build_with_clang.py b/util/build_with_clang.py
index ae707718e4..213df77d8e 100755
--- a/util/build_with_clang.py
+++ b/util/build_with_clang.py
@@ -147,6 +147,7 @@ BOARDS_THAT_COMPILE_SUCCESSFULLY_WITH_CLANG = [
"gelarshie",
"genesis",
"gimble",
+ "gladios",
"grunt",
"gumboz",
"guybrush",
diff --git a/zephyr/dts/bindings/battery/battery-smart.yaml b/zephyr/dts/bindings/battery/battery-smart.yaml
index 5992226291..a5ad7954d2 100644
--- a/zephyr/dts/bindings/battery/battery-smart.yaml
+++ b/zephyr/dts/bindings/battery/battery-smart.yaml
@@ -35,6 +35,7 @@ properties:
- "lgc,ap16l8j"
- "lgc,ap18c8k"
- "lgc,ap19a8k"
+ - "lgc,ap19b8k"
- "lgc,ap19b8m"
- "lgc,l20l3pg2"
- "lgc,xphx8"
@@ -42,7 +43,9 @@ properties:
- "panasonic,ap16l5j"
- "panasonic,ap16l5j-009"
- "panasonic,ap19a5k"
+ - "panasonic,ap19b5k"
- "powertech,batgqa05l22"
+ - "smp,ap18c7k"
- "smp,atlxdy9k"
- "smp,c31n1915"
- "smp,c31n2005"
diff --git a/zephyr/dts/bindings/battery/lgc,ap19b8k.yaml b/zephyr/dts/bindings/battery/lgc,ap19b8k.yaml
new file mode 100644
index 0000000000..e755ec135d
--- /dev/null
+++ b/zephyr/dts/bindings/battery/lgc,ap19b8k.yaml
@@ -0,0 +1,58 @@
+# Copyright 2022 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: "LGC KT0030G022 AP19B8K"
+compatible: "lgc,ap19b8k"
+
+include: battery-smart.yaml
+
+properties:
+ enum-name:
+ type: string
+ default: "lgc,ap19b8k"
+
+ # Fuel gauge
+ manuf_name:
+ default: "LGC KT0030G022"
+ device_name:
+ default: "AP19B8K"
+ ship_mode_reg_addr:
+ default: 0x3A
+ ship_mode_reg_data:
+ default: [ 0xC574, 0xC574 ]
+ # Documentation: b/259913834
+ fet_mfgacc_support:
+ default: 0
+ fet_reg_addr:
+ default: 0x43
+ fet_reg_mask:
+ default: 0x0001
+ fet_disconnect_val:
+ default: 0x0000
+ fet_cfet_mask:
+ default: 0x0002
+ fet_cfet_off_val:
+ default: 0x0000
+
+ # Battery info
+ voltage_max:
+ default: 13050
+ voltage_normal:
+ default: 11250
+ voltage_min:
+ default: 9000
+ precharge_current:
+ default: 256
+ start_charging_min_c:
+ default: 0
+ start_charging_max_c:
+ default: 50
+ charging_min_c:
+ default: 0
+ charging_max_c:
+ default: 60
+ discharging_min_c:
+ default: -20
+ discharging_max_c:
+ default: 75
diff --git a/zephyr/dts/bindings/battery/panasonic,ap19b5k.yaml b/zephyr/dts/bindings/battery/panasonic,ap19b5k.yaml
new file mode 100644
index 0000000000..8cea976a76
--- /dev/null
+++ b/zephyr/dts/bindings/battery/panasonic,ap19b5k.yaml
@@ -0,0 +1,58 @@
+# Copyright 2022 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: "Panasonic KT00305011 AP19B5K"
+compatible: "panasonic,ap19b5k"
+
+include: battery-smart.yaml
+
+properties:
+ enum-name:
+ type: string
+ default: "panasonic,ap19b5k"
+
+ # Fuel gauge
+ manuf_name:
+ default: "PANASONIC KT00305011"
+ device_name:
+ default: "AP19B5K"
+ ship_mode_reg_addr:
+ default: 0x3A
+ ship_mode_reg_data:
+ default: [ 0xC574, 0xC574 ]
+ # Documentation: b/259913834
+ fet_mfgacc_support:
+ default: 0
+ fet_reg_addr:
+ default: 0x0
+ fet_reg_mask:
+ default: 0x4000
+ fet_disconnect_val:
+ default: 0x0000
+ fet_cfet_mask:
+ default: 0x8000
+ fet_cfet_off_val:
+ default: 0x0000
+
+ # Battery info
+ voltage_max:
+ default: 13200
+ voltage_normal:
+ default: 11550
+ voltage_min:
+ default: 9000
+ precharge_current:
+ default: 256
+ start_charging_min_c:
+ default: 0
+ start_charging_max_c:
+ default: 50
+ charging_min_c:
+ default: 0
+ charging_max_c:
+ default: 60
+ discharging_min_c:
+ default: -20
+ discharging_max_c:
+ default: 75
diff --git a/zephyr/dts/bindings/battery/smp,ap18c7k.yaml b/zephyr/dts/bindings/battery/smp,ap18c7k.yaml
new file mode 100644
index 0000000000..e85e5aaf54
--- /dev/null
+++ b/zephyr/dts/bindings/battery/smp,ap18c7k.yaml
@@ -0,0 +1,58 @@
+# Copyright 2022 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: "SMP KT00307011 AP18C7K"
+compatible: "smp,ap18c7k"
+
+include: battery-smart.yaml
+
+properties:
+ enum-name:
+ type: string
+ default: "smp,ap18c7k"
+
+ # Fuel gauge
+ manuf_name:
+ default: "SMP KT00307011"
+ device_name:
+ default: "AP18C7K"
+ ship_mode_reg_addr:
+ default: 0x3A
+ ship_mode_reg_data:
+ default: [ 0xC574, 0xC574 ]
+ # Documentation: b/259913834
+ fet_mfgacc_support:
+ default: 0
+ fet_reg_addr:
+ default: 0x0
+ fet_reg_mask:
+ default: 0x8000
+ fet_disconnect_val:
+ default: 0x0000
+ fet_cfet_mask:
+ default: 0x4000
+ fet_cfet_off_val:
+ default: 0x0000
+
+ # Battery info
+ voltage_max:
+ default: 13200
+ voltage_normal:
+ default: 11550
+ voltage_min:
+ default: 9000
+ precharge_current:
+ default: 256
+ start_charging_min_c:
+ default: 0
+ start_charging_max_c:
+ default: 45
+ charging_min_c:
+ default: 0
+ charging_max_c:
+ default: 60
+ discharging_min_c:
+ default: -20
+ discharging_max_c:
+ default: 75
diff --git a/zephyr/program/corsola/interrupts_magikarp.dtsi b/zephyr/program/corsola/interrupts_magikarp.dtsi
deleted file mode 100644
index 4f4e0ba100..0000000000
--- a/zephyr/program/corsola/interrupts_magikarp.dtsi
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Copyright 2022 The ChromiumOS Authors
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/ {
- aliases {
- int-wp = &int_wp;
- };
-
- gpio-interrupts {
- compatible = "cros-ec,gpio-interrupts";
-
- int_power_button: power_button {
- irq-pin = <&power_button_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_button_interrupt";
- };
- int_volume_up: volume_up {
- irq-pin = <&volume_up_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "button_interrupt";
- };
- int_volume_down: volume_down {
- irq-pin = <&volume_down_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "button_interrupt";
- };
- int_lid_open: lid_open {
- irq-pin = <&lid_open>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "lid_interrupt";
- };
- int_warm_rst: warm_rst {
- irq-pin = <&ap_ec_warm_rst_req>;
- flags = <GPIO_INT_EDGE_RISING>;
- handler = "chipset_reset_request_interrupt";
- };
- int_ap_in_sleep: ap_in_sleep {
- irq-pin = <&ap_in_sleep_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_signal_interrupt";
- };
- int_ap_in_rst: ap_in_rst {
- irq-pin = <&ap_sysrst_odl_r>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_signal_interrupt";
- };
- int_ap_wdtrst: ap_wdtrst {
- irq-pin = <&ap_ec_wdtrst_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "chipset_watchdog_interrupt";
- };
- int_tablet_mode: tablet_mode {
- irq-pin = <&tablet_mode_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "gmr_tablet_switch_isr";
- };
- int_base_imu: base_imu {
- irq-pin = <&base_imu_int_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "motion_interrupt";
- };
- int_lid_imu: lid_imu {
- irq-pin = <&lid_accel_int_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "lis2dw12_interrupt";
- };
- int_ac_present: ac_present {
- irq-pin = <&ac_present>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "extpower_interrupt";
- };
- int_usba: usba {
- irq-pin = <&gpio_ap_xhci_init_done>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "usb_a0_interrupt";
- };
- int_wp: wp {
- irq-pin = <&ec_flash_wp_odl>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "switch_interrupt";
- };
- int_spi0_cs: spi0_cs {
- irq-pin = <&spi0_cs>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "spi_event";
- };
- int_x_ec_gpio2: x_ec_gpio2 {
- irq-pin = <&gpio_x_ec_gpio2>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "x_ec_interrupt";
- };
- int_usb_c0_bc12: usb_c0_bc12 {
- irq-pin = <&usb_c0_bc12_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "bc12_interrupt";
- };
- int_usb_c0_ppc: usb_c0_ppc {
- irq-pin = <&usb_c0_ppc_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "ppc_interrupt";
- };
- int_usb_c1_bc12_charger: usb_c1_bc12_charger {
- irq-pin = <&usb_c1_bc12_charger_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "rt9490_bc12_dt_interrupt";
- };
- int_ccd_mode_odl: ccd-mode-odl {
- irq-pin = <&gpio_ccd_mode_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "ccd_interrupt";
- };
- };
-};
diff --git a/zephyr/program/corsola/interrupts_tentacruel.dtsi b/zephyr/program/corsola/interrupts_tentacruel.dtsi
deleted file mode 100644
index 11229daf36..0000000000
--- a/zephyr/program/corsola/interrupts_tentacruel.dtsi
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Copyright 2022 The ChromiumOS Authors
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/ {
- aliases {
- int-wp = &int_wp;
- };
-
- gpio-interrupts {
- compatible = "cros-ec,gpio-interrupts";
-
- int_power_button: power_button {
- irq-pin = <&power_button_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_button_interrupt";
- };
- int_volume_up: volume_up {
- irq-pin = <&volume_up_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "button_interrupt";
- };
- int_volume_down: volume_down {
- irq-pin = <&volume_down_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "button_interrupt";
- };
- int_lid_open: lid_open {
- irq-pin = <&lid_open>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "lid_interrupt";
- };
- int_warm_rst: warm_rst {
- irq-pin = <&ap_ec_warm_rst_req>;
- flags = <GPIO_INT_EDGE_RISING>;
- handler = "chipset_reset_request_interrupt";
- };
- int_ap_in_sleep: ap_in_sleep {
- irq-pin = <&ap_in_sleep_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_signal_interrupt";
- };
- int_ap_in_rst: ap_in_rst {
- irq-pin = <&ap_sysrst_odl_r>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "power_signal_interrupt";
- };
- int_ap_wdtrst: ap_wdtrst {
- irq-pin = <&ap_ec_wdtrst_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "chipset_watchdog_interrupt";
- };
- int_tablet_mode: tablet_mode {
- irq-pin = <&tablet_mode_l>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "gmr_tablet_switch_isr";
- };
- int_base_imu: base_imu {
- irq-pin = <&base_imu_int_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "motion_interrupt";
- };
- int_lid_imu: lid_imu {
- irq-pin = <&lid_accel_int_l>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "lis2dw12_interrupt";
- };
- int_ac_present: ac_present {
- irq-pin = <&ac_present>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "extpower_interrupt";
- };
- int_usba: usba {
- irq-pin = <&gpio_ap_xhci_init_done>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "usb_a0_interrupt";
- };
- int_wp: wp {
- irq-pin = <&ec_flash_wp_odl>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "switch_interrupt";
- };
- int_spi0_cs: spi0_cs {
- irq-pin = <&spi0_cs>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "spi_event";
- };
- int_x_ec_gpio2: x_ec_gpio2 {
- irq-pin = <&gpio_x_ec_gpio2>;
- flags = <GPIO_INT_EDGE_BOTH>;
- handler = "x_ec_interrupt";
- };
- int_usb_c0_ppc: usb_c0_ppc {
- irq-pin = <&usb_c0_ppc_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "ppc_interrupt";
- };
- int_usb_c0_bc12: usb_c0_bc12 {
- irq-pin = <&usb_c0_bc12_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "bc12_interrupt";
- };
- int_usb_c1_bc12_charger: usb_c1_bc12_charger {
- irq-pin = <&usb_c1_bc12_charger_int_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "rt9490_bc12_dt_interrupt";
- };
- int_ccd_mode_odl: ccd-mode-odl {
- irq-pin = <&gpio_ccd_mode_odl>;
- flags = <GPIO_INT_EDGE_FALLING>;
- handler = "ccd_interrupt";
- };
- };
-};
diff --git a/zephyr/program/corsola/ite_interrupts.dtsi b/zephyr/program/corsola/ite_interrupts.dtsi
index 3caf4660ae..b99effb9eb 100644
--- a/zephyr/program/corsola/ite_interrupts.dtsi
+++ b/zephyr/program/corsola/ite_interrupts.dtsi
@@ -83,7 +83,7 @@
};
int_spi0_cs: spi0_cs {
irq-pin = <&spi0_cs>;
- flags = <GPIO_INT_EDGE_BOTH>;
+ flags = <GPIO_INT_EDGE_FALLING>;
handler = "spi_event";
};
int_x_ec_gpio2: x_ec_gpio2 {
diff --git a/zephyr/program/corsola/magikarp/project.overlay b/zephyr/program/corsola/magikarp/project.overlay
index f4ca85e375..6f69253c6d 100644
--- a/zephyr/program/corsola/magikarp/project.overlay
+++ b/zephyr/program/corsola/magikarp/project.overlay
@@ -14,7 +14,29 @@
#include "../gpio_magikarp.dtsi"
#include "../ite_keyboard.dtsi"
#include "../i2c_magikarp.dtsi"
-#include "../interrupts_magikarp.dtsi"
+#include "../ite_interrupts.dtsi"
#include "../led_magikarp.dtsi"
#include "../motionsense_magikarp.dtsi"
#include "../usbc_magikarp.dtsi"
+
+/ {
+ gpio-interrupts {
+ int_base_imu: base_imu {
+ handler = "motion_interrupt";
+ };
+
+ /delete-node/ usb_c0_ppc_bc12;
+
+ int_usb_c0_ppc: usb_c0_ppc {
+ irq-pin = <&usb_c0_ppc_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "ppc_interrupt";
+ };
+
+ int_usb_c0_bc12: usb_c0_bc12 {
+ irq-pin = <&usb_c0_bc12_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "bc12_interrupt";
+ };
+ };
+};
diff --git a/zephyr/program/corsola/tentacruel/project.overlay b/zephyr/program/corsola/tentacruel/project.overlay
index 79bf2baa3d..411f401a0e 100644
--- a/zephyr/program/corsola/tentacruel/project.overlay
+++ b/zephyr/program/corsola/tentacruel/project.overlay
@@ -14,8 +14,30 @@
#include "../gpio_tentacruel.dtsi"
#include "../ite_keyboard.dtsi"
#include "../i2c_tentacruel.dtsi"
-#include "../interrupts_tentacruel.dtsi"
+#include "../ite_interrupts.dtsi"
#include "../led_tentacruel.dtsi"
#include "../motionsense_tentacruel.dtsi"
#include "../usbc_tentacruel.dtsi"
#include "../thermistor_tentacruel.dtsi"
+
+/ {
+ gpio-interrupts {
+ int_base_imu: base_imu {
+ handler = "motion_interrupt";
+ };
+
+ /delete-node/ usb_c0_ppc_bc12;
+
+ int_usb_c0_ppc: usb_c0_ppc {
+ irq-pin = <&usb_c0_ppc_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "ppc_interrupt";
+ };
+
+ int_usb_c0_bc12: usb_c0_bc12 {
+ irq-pin = <&usb_c0_bc12_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "bc12_interrupt";
+ };
+ };
+};
diff --git a/zephyr/program/corsola/voltorb/project.overlay b/zephyr/program/corsola/voltorb/project.overlay
index 8cd5a2bad8..7d0d2c79e8 100644
--- a/zephyr/program/corsola/voltorb/project.overlay
+++ b/zephyr/program/corsola/voltorb/project.overlay
@@ -42,6 +42,15 @@
cosmx_ap20cbl-2 {
compatible = "cosmx,ap20cbl-2", "battery-smart";
};
+ lgc_ap19b8k {
+ compatible = "lgc,ap19b8k", "battery-smart";
+ };
+ panasonic_ap19b5k {
+ compatible = "panasonic,ap19b5k", "battery-smart";
+ };
+ smp_ap18c7k {
+ compatible = "smp,ap18c7k", "battery-smart";
+ };
};
cros-keyscan {
diff --git a/zephyr/program/nissa/xivu/overlay.dtsi b/zephyr/program/nissa/xivu/overlay.dtsi
index 402f0e2f2f..224eb725d7 100644
--- a/zephyr/program/nissa/xivu/overlay.dtsi
+++ b/zephyr/program/nissa/xivu/overlay.dtsi
@@ -257,10 +257,22 @@
unused-pins {
compatible = "unused-gpios";
unused-gpios =
- <&gpio8 5 0>,
+ <&gpio3 2 0>,
+ <&gpio3 5 0>,
<&gpio3 6 0>,
- <&gpiod 7 0>,
+ <&gpio5 7 0>,
<&gpio6 0 0>,
+ <&gpio6 3 0>,
+ <&gpio7 3 0>,
+ <&gpio8 1 0>,
+ <&gpio8 3 0>,
+ <&gpio8 5 0>,
+ <&gpio8 6 0>,
+ <&gpioa 0 0>,
+ <&gpiob 1 0>,
+ <&gpiob 7 0>,
+ <&gpiod 7 0>,
+ <&gpioc 7 0>,
<&gpiof 2 0>,
<&gpiof 3 0>;
};
@@ -381,3 +393,13 @@
pinctrl-0 = <&espi_lpc_gp46_47_51_52_53_54_55_57>;
pinctrl-names = "default";
};
+
+/*
+ * Declare GPIOs that have leakage current caused by board issues here. NPCX ec
+ * will disable their input buffers before entering deep sleep and restore them
+ * after waking up automatically for better power consumption.
+ */
+&power_leakage_io {
+ leak-gpios = <&gpioa 4 0
+ &gpiof 1 0>;
+};
diff --git a/zephyr/subsys/ap_pwrseq/power_host_sleep.c b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
index bc38215921..5c91b2503e 100644
--- a/zephyr/subsys/ap_pwrseq/power_host_sleep.c
+++ b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
@@ -113,8 +113,17 @@ enum ap_power_sleep_type sleep_state = AP_POWER_SLEEP_NONE;
*/
static void power_s0ix_suspend_clear_masks(void)
{
- backup_sci_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SCI);
- backup_smi_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI);
+ host_event_t sci_mask, smi_mask;
+
+ sci_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SCI);
+ smi_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI);
+
+ /* Do not backup already-cleared SCI/SMI masks. */
+ if (!sci_mask && !smi_mask)
+ return;
+
+ backup_sci_mask = sci_mask;
+ backup_smi_mask = smi_mask;
lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, 0);
lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, 0);
}
diff --git a/zephyr/test/ap_power/include/test_mocks.h b/zephyr/test/ap_power/include/test_mocks.h
index 05e1d823e0..5efa0c7570 100644
--- a/zephyr/test/ap_power/include/test_mocks.h
+++ b/zephyr/test/ap_power/include/test_mocks.h
@@ -19,5 +19,6 @@ DECLARE_FAKE_VALUE_FUNC(int, extpower_is_present);
/* Mocks for common/system.c */
DECLARE_FAKE_VOID_FUNC(system_hibernate, uint32_t, uint32_t);
+DECLARE_FAKE_VALUE_FUNC(int, system_can_boot_ap);
#endif /* __TEST_AP_POWER_TEST_MOCKS_H */
diff --git a/zephyr/test/ap_power/src/ap_pwrseq.c b/zephyr/test/ap_power/src/ap_pwrseq.c
index 6c2fd4fd7f..09277812df 100644
--- a/zephyr/test/ap_power/src/ap_pwrseq.c
+++ b/zephyr/test/ap_power/src/ap_pwrseq.c
@@ -7,6 +7,7 @@
#include "ap_power/ap_power_interface.h"
#include "chipset.h"
#include "emul/emul_power_signals.h"
+#include "test_mocks.h"
#include "test_state.h"
#include <zephyr/drivers/espi.h>
@@ -114,6 +115,22 @@ ZTEST(ap_pwrseq, test_ap_pwrseq_2)
"AP_POWER_HARD_OFF event generated");
}
+ZTEST(ap_pwrseq, test_insufficient_power_blocks_s5)
+{
+ zassert_equal(0,
+ power_signal_emul_load(
+ EMUL_POWER_SIGNAL_TEST_PLATFORM(tp_sys_g3_to_s0)),
+ "Unable to load test platfform `tp_sys_g3_to_s0`");
+ system_can_boot_ap_fake.return_val = 0;
+
+ ap_power_exit_hardoff();
+ k_msleep(5000);
+
+ zassert_equal(40, system_can_boot_ap_fake.call_count);
+ zassert_true(
+ chipset_in_or_transitioning_to_state(CHIPSET_STATE_HARD_OFF));
+}
+
void ap_pwrseq_after_test(void *data)
{
power_signal_emul_unload();
diff --git a/zephyr/test/ap_power/src/test_mocks.c b/zephyr/test/ap_power/src/test_mocks.c
index 9eb8834ff5..b22b9ddd0b 100644
--- a/zephyr/test/ap_power/src/test_mocks.c
+++ b/zephyr/test/ap_power/src/test_mocks.c
@@ -13,6 +13,7 @@ DEFINE_FAKE_VALUE_FUNC(int, extpower_is_present);
/* Mocks for common/system.c */
DEFINE_FAKE_VOID_FUNC(system_hibernate, uint32_t, uint32_t);
+DEFINE_FAKE_VALUE_FUNC(int, system_can_boot_ap);
/**
* @brief Reset all the fakes before each test.
@@ -25,6 +26,8 @@ static void fff_reset_rule_before(const struct ztest_unit_test *test,
RESET_FAKE(extpower_is_present);
RESET_FAKE(system_hibernate);
+ RESET_FAKE(system_can_boot_ap);
+ system_can_boot_ap_fake.return_val = 1;
}
ZTEST_RULE(fff_reset_rule, fff_reset_rule_before, NULL);
diff --git a/zephyr/test/drivers/dps/CMakeLists.txt b/zephyr/test/drivers/dps/CMakeLists.txt
index 0e175e182f..0433fe951b 100644
--- a/zephyr/test/drivers/dps/CMakeLists.txt
+++ b/zephyr/test/drivers/dps/CMakeLists.txt
@@ -2,4 +2,4 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-target_sources(app PRIVATE src/dps.c)
+target_sources(app PRIVATE src/dps_config.c src/dps_selection.c)
diff --git a/zephyr/test/drivers/dps/src/dps.c b/zephyr/test/drivers/dps/src/dps_config.c
index a573da670b..a3c7736e31 100644
--- a/zephyr/test/drivers/dps/src/dps.c
+++ b/zephyr/test/drivers/dps/src/dps_config.c
@@ -11,14 +11,14 @@
#include <zephyr/ztest.h>
-struct dps_fixture {
+struct dps_config_fixture {
struct dps_config_t saved_config;
int saved_debug_level;
};
static void *dps_config_setup(void)
{
- static struct dps_fixture fixture;
+ static struct dps_config_fixture fixture;
fixture.saved_config = *dps_get_config();
fixture.saved_debug_level = *dps_get_debug_level();
@@ -33,14 +33,14 @@ static void dps_config_before(void *data)
static void dps_config_after(void *data)
{
- struct dps_fixture *f = (struct dps_fixture *)data;
+ struct dps_config_fixture *f = (struct dps_config_fixture *)data;
*dps_get_config() = f->saved_config;
*dps_get_debug_level() = f->saved_debug_level;
dps_enable(true);
}
-ZTEST_F(dps, test_enable)
+ZTEST_F(dps_config, test_enable)
{
zassert_true(dps_is_enabled(), NULL);
dps_enable(false);
@@ -49,7 +49,7 @@ ZTEST_F(dps, test_enable)
zassert_true(dps_is_enabled(), NULL);
}
-ZTEST_F(dps, test_config)
+ZTEST_F(dps_config, test_config)
{
struct dps_config_t *config = dps_get_config();
@@ -69,13 +69,13 @@ ZTEST_F(dps, test_config)
*config = fixture->saved_config;
}
-ZTEST(dps, console_cmd__print_info)
+ZTEST(dps_config, console_cmd__print_info)
{
/* Print current status to console */
zassert_ok(shell_execute_cmd(get_ec_shell(), "dps"), NULL);
}
-ZTEST(dps, console_cmd__enable)
+ZTEST(dps_config, console_cmd__enable)
{
/* Disable DPS first, then try enabling */
dps_enable(false);
@@ -86,7 +86,7 @@ ZTEST(dps, console_cmd__enable)
zassert_true(dps_is_enabled(), NULL);
}
-ZTEST(dps, console_cmd__disable)
+ZTEST(dps_config, console_cmd__disable)
{
/* Should already by enabled due to before() function */
zassert_true(dps_is_enabled(), NULL);
@@ -96,13 +96,13 @@ ZTEST(dps, console_cmd__disable)
zassert_false(dps_is_enabled(), NULL);
}
-ZTEST(dps, console_cmd__fakepwr_print)
+ZTEST(dps_config, console_cmd__fakepwr_print)
{
/* Print current fake power status to console */
zassert_ok(shell_execute_cmd(get_ec_shell(), "dps fakepwr"), NULL);
}
-ZTEST(dps, console_cmd__fakepwr_enable_disable)
+ZTEST(dps_config, console_cmd__fakepwr_enable_disable)
{
zassert_false(dps_is_fake_enabled(),
"fakepwr shouldn't be enabled by default");
@@ -119,7 +119,7 @@ ZTEST(dps, console_cmd__fakepwr_enable_disable)
zassert_false(dps_is_fake_enabled(), NULL);
}
-ZTEST(dps, console_cmd__fakepwr_invalid)
+ZTEST(dps_config, console_cmd__fakepwr_invalid)
{
/* Various invalid parameters */
zassert_ok(!shell_execute_cmd(get_ec_shell(), "dps fakepwr 100"), NULL);
@@ -129,7 +129,7 @@ ZTEST(dps, console_cmd__fakepwr_invalid)
NULL);
}
-ZTEST(dps, console_cmd__debuglevel)
+ZTEST(dps_config, console_cmd__debuglevel)
{
zassert_ok(shell_execute_cmd(get_ec_shell(), "dps debug 999"), NULL);
@@ -137,7 +137,7 @@ ZTEST(dps, console_cmd__debuglevel)
*dps_get_debug_level());
}
-ZTEST(dps, console_cmd__setkmore)
+ZTEST(dps_config, console_cmd__setkmore)
{
struct dps_config_t *config = dps_get_config();
char cmd[32];
@@ -165,7 +165,7 @@ ZTEST(dps, console_cmd__setkmore)
config->k_less_pwr + 1);
}
-ZTEST(dps, console_cmd__setkless)
+ZTEST(dps_config, console_cmd__setkless)
{
struct dps_config_t *config = dps_get_config();
char cmd[32];
@@ -193,7 +193,7 @@ ZTEST(dps, console_cmd__setkless)
config->k_more_pwr - 1);
}
-ZTEST(dps, console_cmd__setksample)
+ZTEST(dps_config, console_cmd__setksample)
{
struct dps_config_t *config = dps_get_config();
@@ -209,7 +209,7 @@ ZTEST(dps, console_cmd__setksample)
config->k_sample);
}
-ZTEST(dps, console_cmd__setkwindow)
+ZTEST(dps_config, console_cmd__setkwindow)
{
struct dps_config_t *config = dps_get_config();
@@ -222,7 +222,7 @@ ZTEST(dps, console_cmd__setkwindow)
zassert_equal(4, config->k_window, "k_window is %d", config->k_window);
}
-ZTEST(dps, console_cmd__settcheck)
+ZTEST(dps_config, console_cmd__settcheck)
{
struct dps_config_t *config = dps_get_config();
@@ -237,7 +237,7 @@ ZTEST(dps, console_cmd__settcheck)
config->t_check);
}
-ZTEST(dps, console_cmd__settstable)
+ZTEST(dps_config, console_cmd__settstable)
{
struct dps_config_t *config = dps_get_config();
@@ -252,11 +252,11 @@ ZTEST(dps, console_cmd__settstable)
config->t_stable);
}
-ZTEST(dps, console_cmd__invalid)
+ZTEST(dps_config, console_cmd__invalid)
{
/* Non-existent subcommand should fail */
zassert_ok(!shell_execute_cmd(get_ec_shell(), "dps foobar xyz"), NULL);
}
-ZTEST_SUITE(dps, drivers_predicate_pre_main, dps_config_setup,
+ZTEST_SUITE(dps_config, drivers_predicate_pre_main, dps_config_setup,
dps_config_before, dps_config_after, NULL);
diff --git a/zephyr/test/drivers/dps/src/dps_selection.c b/zephyr/test/drivers/dps/src/dps_selection.c
new file mode 100644
index 0000000000..a06aabc67f
--- /dev/null
+++ b/zephyr/test/drivers/dps/src/dps_selection.c
@@ -0,0 +1,238 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "battery.h"
+#include "charge_state_v2.h"
+#include "console.h"
+#include "dps.h"
+#include "ec_commands.h"
+#include "ec_tasks.h"
+#include "emul/emul_isl923x.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_common.h"
+#include "emul/tcpc/emul_tcpci_partner_drp.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "host_command.h"
+#include "tcpm/tcpci.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_pd.h"
+
+#include <stdint.h>
+
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/fff.h>
+#include <zephyr/kernel.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/ztest.h>
+
+#define TEST_PORT 0
+
+FAKE_VALUE_FUNC(int, get_batt_charge_power, int *);
+FAKE_VALUE_FUNC(int, get_battery_target_voltage, int *);
+FAKE_VALUE_FUNC(int, get_desired_input_power, int *, int *);
+
+struct common_fixture {
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+ struct tcpci_partner_data partner;
+ struct tcpci_snk_emul_data snk_ext;
+ struct tcpci_src_emul_data src_ext;
+ struct tcpci_drp_emul_data drp_ext;
+};
+
+struct dps_selection_fixture {
+ struct common_fixture common;
+};
+
+/* FFF fakes for driver functions. These get assigned to members of the
+ * charger_drv struct
+ */
+static int target_mv_custom_fake;
+static int get_battery_target_voltage_custom_fake(int *target_mv)
+{
+ *target_mv = target_mv_custom_fake;
+
+ return EC_SUCCESS;
+}
+
+static int vbus_custom_fake;
+static int input_current_custom_fake;
+static int get_desired_input_power_custom_fake(int *vbus, int *input_current)
+{
+ *vbus = vbus_custom_fake;
+ *input_current = input_current_custom_fake;
+
+ return vbus_custom_fake * input_current_custom_fake / 1000;
+}
+
+static void reset(void)
+{
+ /* Reset fakes */
+ RESET_FAKE(get_batt_charge_power);
+ RESET_FAKE(get_battery_target_voltage);
+ RESET_FAKE(get_desired_input_power);
+}
+
+static void connect_partner_to_port(const struct emul *tcpc_emul,
+ const struct emul *charger_emul,
+ struct tcpci_partner_data *partner_emul,
+ const struct tcpci_src_emul_data *src_ext)
+{
+ /*
+ * TODO(b/221439302): Updating the TCPCI emulator registers, updating
+ * the charger, and alerting should all be a part of the connect
+ * function.
+ */
+ set_ac_enabled(true);
+ zassert_ok(tcpci_partner_connect_to_tcpci(partner_emul, tcpc_emul),
+ NULL);
+
+ isl923x_emul_set_adc_vbus(charger_emul,
+ PDO_FIXED_GET_VOLT(src_ext->pdo[0]));
+
+ /* Wait for PD negotiation and current ramp. */
+ k_sleep(K_SECONDS(10));
+}
+
+static void disconnect_partner_from_port(const struct emul *tcpc_emul,
+ const struct emul *charger_emul)
+{
+ zassert_ok(tcpci_emul_disconnect_partner(tcpc_emul), NULL);
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+ k_sleep(K_SECONDS(1));
+}
+
+static void *common_setup(void)
+{
+ static struct dps_selection_fixture outer_fixture;
+ struct common_fixture *fixture = &outer_fixture.common;
+ struct tcpci_partner_data *partner = &fixture->partner;
+ struct tcpci_src_emul_data *src_ext = &fixture->src_ext;
+ struct tcpci_snk_emul_data *snk_ext = &fixture->snk_ext;
+
+ tcpci_partner_init(partner, PD_REV30);
+ fixture->partner.extensions = tcpci_drp_emul_init(
+ &fixture->drp_ext, partner, PD_ROLE_SOURCE,
+ tcpci_src_emul_init(src_ext, partner, NULL),
+ tcpci_snk_emul_init(snk_ext, partner, NULL));
+
+ /* Get references for the emulators */
+ fixture->tcpci_emul = EMUL_GET_USBC_BINDING(TEST_PORT, tcpc);
+ fixture->charger_emul = EMUL_GET_USBC_BINDING(TEST_PORT, chg);
+
+ return &outer_fixture;
+}
+
+static void *dps_selection_setup(void)
+{
+ return common_setup();
+}
+
+static void common_before(struct common_fixture *fixture)
+{
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+}
+
+static void dps_selection_before(void *data)
+{
+ struct dps_selection_fixture *outer = data;
+
+ common_before(&outer->common);
+
+ reset();
+}
+
+static void common_after(struct common_fixture *fixture)
+{
+ if (pd_is_connected(TEST_PORT)) {
+ disconnect_partner_from_port(fixture->tcpci_emul,
+ fixture->charger_emul);
+ }
+}
+
+static void dps_selection_after(void *data)
+{
+ struct dps_selection_fixture *outer = data;
+
+ common_after(&outer->common);
+
+ reset();
+}
+
+ZTEST_USER_F(dps_selection, dps_pdo_switch)
+{
+ struct common_fixture *common = &fixture->common;
+ struct tcpci_src_emul_data *src_ext = &common->src_ext;
+ uint32_t *partner_pdo = src_ext->pdo;
+
+ /* Attach a partner with all of the Source Capability attributes that
+ * "pd <port> srccaps" checks for.
+ */
+ partner_pdo[0] =
+ PDO_FIXED(5000, 3000,
+ PDO_FIXED_DUAL_ROLE | PDO_FIXED_UNCONSTRAINED |
+ PDO_FIXED_COMM_CAP | PDO_FIXED_DATA_SWAP |
+ PDO_FIXED_FRS_CURR_MASK);
+ partner_pdo[1] = PDO_FIXED(9000, 3000, PDO_FIXED_UNCONSTRAINED);
+ partner_pdo[2] = PDO_FIXED(10000, 3000, PDO_FIXED_UNCONSTRAINED);
+ partner_pdo[3] = PDO_FIXED(12000, 3000, PDO_FIXED_UNCONSTRAINED);
+ partner_pdo[4] = PDO_FIXED(15000, 3000, PDO_FIXED_UNCONSTRAINED);
+ partner_pdo[5] = PDO_FIXED(20000, 3000, PDO_FIXED_UNCONSTRAINED);
+ connect_partner_to_port(common->tcpci_emul, common->charger_emul,
+ &common->partner, &common->src_ext);
+
+ get_battery_target_voltage_fake.custom_fake =
+ get_battery_target_voltage_custom_fake;
+ get_desired_input_power_fake.custom_fake =
+ get_desired_input_power_custom_fake;
+
+ /* This value is not used if not have board overridden. */
+ get_batt_charge_power_fake.return_val = 5566;
+
+ /* Assume the charge targeting at 9V. */
+ target_mv_custom_fake = 9000;
+
+ k_sleep(K_SECONDS(1));
+ /* Assumes the system sinks 15W. */
+ vbus_custom_fake = 20000;
+ input_current_custom_fake = 750;
+
+ /* DPS should request the PDO with the highest voltage at first. */
+ zassert_equal(pd_get_requested_voltage(TEST_PORT), 20000, NULL);
+
+ /* Wait for DPS to changing voltage */
+ k_sleep(K_SECONDS(20));
+
+ /* DPS should switch to 9V. */
+ zassert_equal(pd_get_requested_voltage(TEST_PORT), 9000, NULL);
+
+ /* Assumes the system sinks 27W/9V/3A. */
+ vbus_custom_fake = 9000;
+ input_current_custom_fake = 3000;
+ k_sleep(K_SECONDS(20));
+ /* PDO 10V/3A should be requested. */
+ zassert_equal(pd_get_requested_voltage(TEST_PORT), 10000, NULL);
+
+ /* Assumes the system sinks 30W/10V/3A. */
+ vbus_custom_fake = 10000;
+ k_sleep(K_SECONDS(20));
+ /* PDO 12V/3A should be requested. */
+ zassert_equal(pd_get_requested_voltage(TEST_PORT), 12000, NULL);
+
+ /* Assumes the system sinks 36W/12V/3A. */
+ vbus_custom_fake = 12000;
+ k_sleep(K_SECONDS(20));
+ /* PDO 15V/3A should be requested. */
+ zassert_equal(pd_get_requested_voltage(TEST_PORT), 15000, NULL);
+}
+
+ZTEST_SUITE(dps_selection, drivers_predicate_post_main, dps_selection_setup,
+ dps_selection_before, dps_selection_after, NULL);
diff --git a/zephyr/test/krabby/pinctrl.dts b/zephyr/test/krabby/pinctrl.dts
index ecc7b88538..fd3b66e419 100644
--- a/zephyr/test/krabby/pinctrl.dts
+++ b/zephyr/test/krabby/pinctrl.dts
@@ -7,3 +7,13 @@
/delete-node/ &pinctrl;
/delete-node/ &{/hibernate-wake-pins};
+
+/ {
+ gpio-interrupts {
+ int_base_imu: base_imu {
+ handler = "motion_interrupt";
+ };
+
+ /delete-node/ usb_c0_ppc_bc12;
+ };
+};
diff --git a/zephyr/test/krabby/testcase.yaml b/zephyr/test/krabby/testcase.yaml
index 781d82db4b..7839427646 100644
--- a/zephyr/test/krabby/testcase.yaml
+++ b/zephyr/test/krabby/testcase.yaml
@@ -11,7 +11,7 @@ tests:
- CONFIG_TEST_KRABBY=y
- CONFIG_MUX_INIT_ADC=y
krabby.tentacruel:
- extra_args: DTC_OVERLAY_FILE="common.dts;adc_temp.dts;../program/corsola/interrupts_tentacruel.dtsi;../program/corsola/gpio_tentacruel.dtsi;../program/corsola/thermistor_tentacruel.dtsi;pinctrl.dts"
+ extra_args: DTC_OVERLAY_FILE="common.dts;adc_temp.dts;../program/corsola/ite_interrupts.dtsi;../program/corsola/gpio_tentacruel.dtsi;../program/corsola/thermistor_tentacruel.dtsi;pinctrl.dts"
extra_configs:
- CONFIG_TEST_TENTACRUEL=y
- CONFIG_PLATFORM_EC_CHARGER_PROFILE_OVERRIDE=y