diff options
author | Andrew McRae <amcrae@google.com> | 2022-12-05 14:53:18 +1100 |
---|---|---|
committer | Andrew McRae <amcrae@google.com> | 2022-12-05 14:53:18 +1100 |
commit | c9292d8582f8e1e02cf8458ce9969027d7d42241 (patch) | |
tree | b704c36c76136711dba0f9d6d04c711e06ae6762 | |
parent | b2004ee71e310d86995ede82d9e84892a67979e8 (diff) | |
parent | 7d1d331031e9db8bd9c8600fe9f96472d338c508 (diff) | |
download | chrome-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>
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 |