summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Huang <david.huang@quanta.corp-partner.google.com>2023-02-23 12:20:47 +0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-01 22:55:38 +0000
commit670b102d71c34cc3a906ab16797731073dba9dc8 (patch)
treef861cc07cab42ee3062bc36aa6798182d99bcfee
parentaeaa8eab51e9522175c372b04f39db0fec616930 (diff)
downloadchrome-ec-670b102d71c34cc3a906ab16797731073dba9dc8.tar.gz
hades: Initial EC
Create the initial EC for hades by copying the agah reference board EC files. BUG=b:269387225 BRANCH=None TEST=make BOARD=hades Change-Id: Icfca9f64654f8683aaa6851b823463c740501b3d Signed-off-by: David Huang <david.huang@quanta.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4286378 Tested-by: YH Lin <yueherngl@chromium.org> Code-Coverage: YH Lin <yueherngl@chromium.org> Commit-Queue: YH Lin <yueherngl@chromium.org> Reviewed-by: Boris Mittelberg <bmbm@google.com>
-rw-r--r--board/hades/battery.c107
-rw-r--r--board/hades/board.c117
-rw-r--r--board/hades/board.h216
-rw-r--r--board/hades/build.mk25
-rw-r--r--board/hades/charger_isl9241.c276
-rw-r--r--board/hades/ec.tasklist29
-rw-r--r--board/hades/fans.c66
-rw-r--r--board/hades/fw_config.c40
-rw-r--r--board/hades/fw_config.h38
-rw-r--r--board/hades/gpio.inc135
-rw-r--r--board/hades/i2c.c56
-rw-r--r--board/hades/keyboard.c52
-rw-r--r--board/hades/led.c192
-rw-r--r--board/hades/pwm.c47
-rw-r--r--board/hades/sensors.c135
-rw-r--r--board/hades/usbc_config.c332
-rw-r--r--board/hades/usbc_config.h21
-rw-r--r--board/hades/vif_override.xml3
-rwxr-xr-xutil/build_with_clang.py2
19 files changed, 1888 insertions, 1 deletions
diff --git a/board/hades/battery.c b/board/hades/battery.c
new file mode 100644
index 0000000000..0c94e2835d
--- /dev/null
+++ b/board/hades/battery.c
@@ -0,0 +1,107 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Battery pack vendor provided charging profile
+ */
+
+#include "battery_fuel_gauge.h"
+#include "cbi.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "gpio.h"
+/*
+ * Battery info for all Hades battery types. Note that the fields
+ * start_charging_min/max and charging_min/max are not used for the charger.
+ * The effective temperature limits are given by discharging_min/max_c.
+ *
+ * Fuel Gauge (FG) parameters which are used for determining if the battery
+ * is connected, the appropriate ship mode (battery cutoff) command, and the
+ * charge/discharge FETs status.
+ *
+ * Ship mode (battery cutoff) requires 2 writes to the appropriate smart battery
+ * register. For some batteries, the charge/discharge FET bits are set when
+ * charging/discharging is active, in other types, these bits set mean that
+ * charging/discharging is disabled. Therefore, in addition to the mask for
+ * these bits, a disconnect value must be specified. Note that for TI fuel
+ * gauge, the charge/discharge FET status is found in Operation Status (0x54),
+ * but a read of Manufacturer Access (0x00) will return the lower 16 bits of
+ * Operation status which contains the FET status bits.
+ *
+ * The assumption for battery types supported is that the charge/discharge FET
+ * status can be read with a sb_read() command and therefore, only the register
+ * address, mask, and disconnect value need to be provided.
+ */
+const struct board_batt_params board_battery_info[] = {
+ /* DYNAPACK COSMAX Battery Information */
+ [BATTERY_DYNAPACK_COSMX] = {
+ /* RAJ240045 Fuel Gauge */
+ .fuel_gauge = {
+ .manuf_name = "333-2C-4C-A",
+ .ship_mode = {
+ .reg_addr = 0x00,
+ .reg_data = { 0x0010, 0x0010 },
+ },
+ .fet = {
+ .mfgacc_support = 0,
+ .reg_addr = 0x43,
+ .reg_mask = 0x0003,
+ .disconnect_val = 0x0,
+ }
+ },
+ .batt_info = {
+ .voltage_max = 17600,
+ .voltage_normal = 15400, /* mV */
+ .voltage_min = 12000, /* mV */
+ .precharge_current = 256, /* mA */
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 45,
+ .charging_min_c = 0,
+ .charging_max_c = 50,
+ .discharging_min_c = -10,
+ .discharging_max_c = 60,
+ },
+ },
+ /* DYNAPACK HIGHPOWER Battery Information */
+ [BATTERY_DYNAPACK_HIGHPOWER] = {
+ /* RAJ240045 Fuel Gauge */
+ .fuel_gauge = {
+ .manuf_name = "333-2D-4C-A",
+ .ship_mode = {
+ .reg_addr = 0x00,
+ .reg_data = { 0x0010, 0x0010 },
+ },
+ .fet = {
+ .mfgacc_support = 0,
+ .reg_addr = 0x43,
+ .reg_mask = 0x0003,
+ .disconnect_val = 0x0,
+ }
+ },
+ .batt_info = {
+ .voltage_max = 17600,
+ .voltage_normal = 15400, /* mV */
+ .voltage_min = 12000, /* mV */
+ .precharge_current = 256, /* mA */
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 45,
+ .charging_min_c = 0,
+ .charging_max_c = 50,
+ .discharging_min_c = -10,
+ .discharging_max_c = 60,
+ },
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(board_battery_info) == BATTERY_TYPE_COUNT);
+
+const enum battery_type DEFAULT_BATTERY_TYPE = BATTERY_DYNAPACK_COSMX;
+
+enum battery_present battery_hw_present(void)
+{
+ enum gpio_signal batt_pres;
+
+ batt_pres = GPIO_EC_BATT_PRES_ODL;
+
+ /* The GPIO is low when the battery is physically present */
+ return gpio_get_level(batt_pres) ? BP_NO : BP_YES;
+}
diff --git a/board/hades/board.c b/board/hades/board.c
new file mode 100644
index 0000000000..1f274c3161
--- /dev/null
+++ b/board/hades/board.c
@@ -0,0 +1,117 @@
+/* Copyright 2023 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 "button.h"
+#include "charge_ramp.h"
+#include "charger.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "driver/nvidia_gpu.h"
+#include "fw_config.h"
+#include "gpio.h"
+#include "gpio_signal.h"
+#include "hooks.h"
+#include "keyboard_scan.h"
+#include "lid_switch.h"
+#include "power.h"
+#include "power_button.h"
+#include "registers.h"
+#include "switch.h"
+#include "system.h"
+#include "throttle_ap.h"
+#include "usbc_config.h"
+#include "util.h"
+
+/* Must come after other header files and interrupt handler declarations */
+#include "gpio_list.h"
+
+/* Console output macros */
+#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ##args)
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ##args)
+
+static int block_sequence;
+
+struct d_notify_policy d_notify_policies[] = {
+ AC_ATLEAST_W(100), AC_ATLEAST_W(65), AC_DC,
+ DC_ATLEAST_SOC(20), DC_ATLEAST_SOC(5),
+};
+BUILD_ASSERT(ARRAY_SIZE(d_notify_policies) == D_NOTIFY_COUNT);
+
+__override void board_cbi_init(void)
+{
+}
+
+/* Called on AP S3 -> S0 transition */
+static void board_chipset_resume(void)
+{
+ /* Allow keyboard backlight to be enabled */
+ gpio_set_level(GPIO_EC_KB_BL_EN, 1);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, board_chipset_resume, HOOK_PRIO_DEFAULT);
+
+/* Called on AP S0 -> S3 transition */
+static void board_chipset_suspend(void)
+{
+ /* Turn off the keyboard backlight if it's on. */
+ gpio_set_level(GPIO_EC_KB_BL_EN, 0);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT);
+
+static void board_init(void)
+{
+ if ((system_get_reset_flags() & EC_RESET_FLAG_AP_OFF) ||
+ (keyboard_scan_get_boot_keys() & BOOT_KEY_DOWN_ARROW)) {
+ CPRINTS("PG_PP3300_S5_OD block is enabled");
+ block_sequence = 1;
+ }
+ gpio_enable_interrupt(GPIO_PG_PP3300_S5_OD);
+ gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_ODL);
+
+ nvidia_gpu_init_policy(d_notify_policies);
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+/**
+ * Deferred function to handle GPIO PG_PP3300_S5_OD change
+ */
+static void bypass_pp3300_s5_deferred(void)
+{
+ if (block_sequence) {
+ CPRINTS("PG_PP3300_S5_OD is blocked.");
+ return;
+ }
+
+ gpio_set_level(GPIO_PG_PP3300_S5_EC_SEQ_OD,
+ gpio_get_level(GPIO_PG_PP3300_S5_OD));
+}
+DECLARE_DEFERRED(bypass_pp3300_s5_deferred);
+
+void board_power_interrupt(enum gpio_signal signal)
+{
+ /* Trigger deferred notification of gpio PG_PP3300_S5_OD change */
+ hook_call_deferred(&bypass_pp3300_s5_deferred_data, 0);
+}
+
+static int cc_blockseq(int argc, const char *argv[])
+{
+ if (argc > 1) {
+ if (!parse_bool(argv[1], &block_sequence)) {
+ ccprintf("Invalid argument: %s\n", argv[1]);
+ return EC_ERROR_INVAL;
+ }
+ }
+
+ ccprintf("PG_PP3300_S5_OD block is %s\n",
+ block_sequence ? "enabled" : "disabled");
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(blockseq, cc_blockseq, "[on/off]", NULL);
+
+void gpu_overt_interrupt(enum gpio_signal signal)
+{
+ nvidia_gpu_over_temp(gpio_get_level(signal));
+}
diff --git a/board/hades/board.h b/board/hades/board.h
new file mode 100644
index 0000000000..833529e03e
--- /dev/null
+++ b/board/hades/board.h
@@ -0,0 +1,216 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Hades board configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+#include "compile_time_macros.h"
+
+/* Baseboard features */
+#include "baseboard.h"
+
+/*
+ * Nvidia GPU
+ */
+#define CONFIG_GPU_NVIDIA
+
+/*
+ * This will happen automatically on NPCX9 ES2 and later. Do not remove
+ * until we can confirm all earlier chips are out of service.
+ */
+#define CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP
+
+/*
+ * Hades blocks PG_PP3300_S5_OD instead to control AP power-on.
+ */
+#undef CONFIG_CHIPSET_X86_RSMRST_AFTER_S5
+
+/* Sensors */
+#undef CONFIG_TABLET_MODE
+#undef CONFIG_TABLET_MODE_SWITCH
+#undef CONFIG_GMR_TABLET_MODE
+
+/* Buttons */
+#undef CONFIG_VOLUME_BUTTONS
+
+/* USB Type A Features */
+#define USB_PORT_COUNT 1
+#define CONFIG_USB_PORT_POWER_DUMB
+
+/* USB Type C and USB PD defines */
+#define CONFIG_USB_PD_TCPM_RT1715
+#undef CONFIG_USB_PD_TCPM_NCT38XX
+#define CONFIG_USBC_RETIMER_PS8818
+
+/* I2C speed console command */
+#define CONFIG_CMD_I2C_SPEED
+
+/* I2C control host command */
+#define CONFIG_HOSTCMD_I2C_CONTROL
+
+#define CONFIG_USBC_PPC_SYV682X
+#define CONFIG_USB_PD_FRS_PPC
+#undef CONFIG_SYV682X_HV_ILIM
+#define CONFIG_SYV682X_HV_ILIM SYV682X_HV_ILIM_5_50
+
+#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 */
+
+#define PD_OPERATING_POWER_MW 15000
+#define PD_MAX_POWER_MW 100000
+#define PD_MAX_CURRENT_MA 5000
+#define PD_MAX_VOLTAGE_MV 20000
+
+#undef CONFIG_EXTPOWER_DEBOUNCE_MS
+#define CONFIG_EXTPOWER_DEBOUNCE_MS 500
+
+/*
+ * 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_ENABLE_BACKLIGHT GPIO_EC_EN_EDP_BL
+#define GPIO_ENTERING_RW GPIO_EC_ENTERING_RW
+#define GPIO_KBD_KSO2 GPIO_EC_KSO_02_INV
+#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
+
+/* System has back-lit keyboard */
+#define CONFIG_PWM_KBLIGHT
+
+/* I2C Bus Configuration */
+
+#define I2C_PORT_SENSOR NPCX_I2C_PORT0_0
+
+#define I2C_PORT_USB_C0_TCPC NPCX_I2C_PORT1_0
+#define I2C_PORT_USB_C2_TCPC NPCX_I2C_PORT2_0
+
+#define I2C_PORT_USB_C0_PPC NPCX_I2C_PORT1_0
+#define I2C_PORT_USB_C2_PPC NPCX_I2C_PORT2_0
+
+#define I2C_PORT_USB_C0_BC12 NPCX_I2C_PORT1_0
+#define I2C_PORT_USB_C2_BC12 NPCX_I2C_PORT2_0
+
+#define I2C_PORT_USBA1_RT NPCX_I2C_PORT6_1
+
+#define I2C_PORT_BATTERY NPCX_I2C_PORT5_0
+#define I2C_PORT_CHARGER NPCX_I2C_PORT7_0
+#define I2C_PORT_EEPROM NPCX_I2C_PORT7_0
+
+#define I2C_ADDR_EEPROM_FLAGS 0x50
+
+/* Thermal features */
+#define CONFIG_THERMISTOR
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_POWER
+#define CONFIG_TEMP_SENSOR_FIRST_READ_DELAY_MS 500
+#define CONFIG_STEINHART_HART_3V3_30K9_47K_4050B
+
+#define CONFIG_FANS FAN_CH_COUNT
+
+/* Charger defines */
+#define CONFIG_CHARGER_ISL9241
+#define CONFIG_CHARGER_SENSE_RESISTOR 10
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10
+/* Round down 7700 max current to multiple of 128mA for ISL9241 AC prochot. */
+#define HADES_AC_PROCHOT_CURRENT_MA 7680
+
+/* Barrel jack adapter settings */
+#undef CONFIG_DEDICATED_CHARGE_PORT_COUNT
+#define CONFIG_DEDICATED_CHARGE_PORT_COUNT 1
+/* This is the next available port # after USB-C ports. */
+#define DEDICATED_CHARGE_PORT 2
+
+/*
+ * Older boards have a different ADC assignment.
+ */
+
+#define CONFIG_ADC_CHANNELS_RUNTIME_CONFIG
+
+#ifndef __ASSEMBLER__
+
+#include "gpio_signal.h" /* needed by registers.h */
+#include "registers.h"
+#include "usbc_config.h"
+
+enum adc_channel {
+ ADC_TEMP_SENSOR_1_DDR_SOC,
+ ADC_TEMP_SENSOR_2_GPU,
+ ADC_TEMP_SENSOR_3_CHARGER,
+ ADC_CHARGER_IADP,
+ ADC_ADP_TYP,
+ ADC_CH_COUNT
+};
+
+enum temp_sensor_id {
+ TEMP_SENSOR_1_DDR_SOC,
+ TEMP_SENSOR_2_GPU,
+ TEMP_SENSOR_3_CHARGER,
+ TEMP_SENSOR_COUNT
+};
+
+enum battery_type {
+ BATTERY_DYNAPACK_COSMX,
+ BATTERY_DYNAPACK_HIGHPOWER,
+ BATTERY_TYPE_COUNT
+};
+
+enum pwm_channel {
+ PWM_CH_KBLIGHT = 0, /* PWM3 */
+ PWM_CH_FAN, /* PWM5 */
+ PWM_CH_FAN2, /* PWM4 */
+ PWM_CH_COUNT
+};
+
+enum fan_channel { FAN_CH_0 = 0, FAN_CH_1, FAN_CH_COUNT };
+
+enum mft_channel { MFT_CH_0 = 0, MFT_CH_1, MFT_CH_COUNT };
+
+enum charge_port {
+ CHARGE_PORT_TYPEC0,
+ CHARGE_PORT_TYPEC1,
+ CHARGE_PORT_BARRELJACK,
+};
+
+/**
+ * Interrupt handler for PG_PP3300_S5_OD changes.
+ *
+ * @param signal Signal which triggered the interrupt.
+ */
+void board_power_interrupt(enum gpio_signal signal);
+
+/* IRQ for BJ plug/unplug. */
+void bj_present_interrupt(enum gpio_signal signal);
+
+/* IRQ for over temperature. */
+void gpu_overt_interrupt(enum gpio_signal signal);
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/hades/build.mk b/board/hades/build.mk
new file mode 100644
index 0000000000..e72f79992f
--- /dev/null
+++ b/board/hades/build.mk
@@ -0,0 +1,25 @@
+# -*- makefile -*-
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Hades board specific files build
+#
+
+CHIP:=npcx
+CHIP_FAMILY:=npcx9
+CHIP_VARIANT:=npcx9m3f
+BASEBOARD:=brya
+
+board-y=
+board-y+=battery.o
+board-y+=board.o
+board-y+=charger_isl9241.o
+board-y+=fans.o
+board-y+=fw_config.o
+board-y+=i2c.o
+board-y+=keyboard.o
+board-y+=led.o
+board-y+=pwm.o
+board-y+=sensors.o
+board-y+=usbc_config.o
diff --git a/board/hades/charger_isl9241.c b/board/hades/charger_isl9241.c
new file mode 100644
index 0000000000..4886191fcc
--- /dev/null
+++ b/board/hades/charger_isl9241.c
@@ -0,0 +1,276 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ *
+ * We need to deal with plug / unplug of AC chargers:
+ *
+ * +---------+ +USB +---------+
+ * | BATTERY |------------>| BATTERY |
+ * | |<------------| +USB |
+ * +---------+ -USB +---------+
+ * | ^ | ^
+ * +BJ | | -BJ +BJ | | -BJ
+ * v | v |
+ * +---------+ +USB +---------+
+ * | BATTERY |------------>| BATTERY |
+ * | +BJ |<------------| +BJ+USB |
+ * +---------+ -USB +---------+
+ *
+ * Depending on available battery charge, power rating of the new charger, and
+ * the system power state, transition/throttling may or may not occur but
+ * switching chargers is handled as follows:
+ *
+ * 1. Detects a new charger or removal of an existing charger.
+ * 2. charge_manager_update_charge is called with new charger's info.
+ * 3. board_set_active_charge_port is called.
+ * 3.1 It triggers hard & soft throttling for AP & GPU.
+ * 3.2 It disable active port then enables the new port.
+ * 4. HOOK_POWER_SUPPLY_CHANGE is called. We disables hard throttling.
+ * 5. charger task wakes up on HOOK_POWER_SUPPLY_CHANGE, enables (or disables)
+ * bypass mode.
+ */
+
+#include "charge_manager.h"
+#include "charge_state.h"
+#include "charge_state_v2.h"
+#include "charger.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "driver/charger/isl9241.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "stdbool.h"
+#include "throttle_ap.h"
+#include "usb_pd.h"
+#include "usbc_ppc.h"
+#include "util.h"
+
+#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ##args)
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ##args)
+
+/* Charger Chip Configuration */
+const struct charger_config_t chg_chips[] = {
+ {
+ .i2c_port = I2C_PORT_CHARGER,
+ .i2c_addr_flags = ISL9241_ADDR_FLAGS,
+ .drv = &isl9241_drv,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(chg_chips) == CHARGER_NUM);
+
+static int board_enable_bj_port(bool enable)
+{
+ if (enable) {
+ if (gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL))
+ return EC_ERROR_INVAL;
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 0);
+ } else {
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 1);
+ }
+
+ CPRINTS("BJ power is %sabled", enable ? "en" : "dis");
+
+ return EC_SUCCESS;
+}
+
+static void board_throttle_ap_gpu(void)
+{
+ throttle_ap(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_AC);
+ throttle_gpu(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_AC);
+}
+
+/* Disable all VBUS sink ports except <port>. <port> = -1 disables all ports. */
+static int board_disable_other_vbus_sink(int except_port)
+{
+ int i, r, rv = EC_SUCCESS;
+
+ for (i = 0; i < ppc_cnt; i++) {
+ if (i == except_port)
+ continue;
+ /*
+ * Do not return early if one fails otherwise we can get into a
+ * boot loop assertion failure.
+ */
+ r = ppc_vbus_sink_enable(i, 0);
+ if (r)
+ CPRINTS("Failed to disable sink path C%d (%d)", i, r);
+ rv |= r;
+ }
+
+ return rv;
+}
+
+/* Minimum battery SoC required for switching source port. */
+#define MIN_BATT_FOR_SWITCHING_SOURCE_PORT 1
+
+/*
+ * TODO: Recover from incomplete execution:
+ */
+int board_set_active_charge_port(int port)
+{
+ enum charge_supplier active_supplier = charge_manager_get_supplier();
+ int active_port = charge_manager_get_active_charge_port();
+
+ CPRINTS("Switching charger from P%d (supplier=%d) to P%d", active_port,
+ active_supplier, port);
+
+ if (port == CHARGE_PORT_NONE) {
+ CPRINTS("Disabling all charger ports");
+
+ board_enable_bj_port(false);
+ board_disable_other_vbus_sink(-1);
+
+ return EC_SUCCESS;
+ }
+
+ /* Return on invalid or no-op call. */
+ if (port < 0 || CHARGE_PORT_COUNT <= port) {
+ return EC_ERROR_INVAL;
+ } else if (port == active_port) {
+ return EC_SUCCESS;
+ } else if (board_vbus_source_enabled(port)) {
+ /* Don't charge from a USBC source port */
+ CPRINTS("Don't enable P%d. It's sourcing.", port);
+ return EC_ERROR_INVAL;
+ }
+
+ /*
+ * If we're in S0, throttle AP and GPU. They'll be unthrottled when
+ * a port/supply switch completes (via HOOK_POWER_SUPPLY_CHANGE).
+ *
+ * If we're running currently on a battery (active_supplier == NONE), we
+ * don't need to throttle because we're not disabling any port.
+ */
+ if (chipset_in_state(CHIPSET_STATE_ON) &&
+ active_supplier != CHARGE_SUPPLIER_NONE)
+ board_throttle_ap_gpu();
+
+ /*
+ * We're here for the two cases:
+ * 1. A new charger was connected.
+ * 2. One charger was disconnected and we're switching to another.
+ */
+
+ /*
+ * We need to check the battery if we're switching a source port. If
+ * we're just starting up or no AC was previously plugged, we shouldn't
+ * check the battery. Both cases can be caught by supplier == NONE.
+ */
+ if (active_supplier != CHARGE_SUPPLIER_NONE) {
+ if (charge_get_percent() < MIN_BATT_FOR_SWITCHING_SOURCE_PORT)
+ return EC_ERROR_NOT_POWERED;
+ }
+
+ /* Turn off other ports' sink paths before enabling requested port. */
+ if (is_pd_port(port)) {
+ /*
+ * BJ port is enabled on start-up. So, we need to turn it off
+ * even if we were not previously on BJ.
+ */
+ board_enable_bj_port(false);
+ if (board_disable_other_vbus_sink(port))
+ return EC_ERROR_UNCHANGED;
+
+ /* Enable requested USBC charge port. */
+ if (ppc_vbus_sink_enable(port, 1)) {
+ CPRINTS("Failed to enable sink path for C%d", port);
+ return EC_ERROR_UNKNOWN;
+ }
+ } else if (port == CHARGE_PORT_BARRELJACK) {
+ /*
+ * We can't proceed unless both ports are successfully
+ * disconnected as sources.
+ */
+ if (board_disable_other_vbus_sink(-1))
+ return EC_ERROR_UNKNOWN;
+ board_enable_bj_port(true);
+ }
+
+ CPRINTS("New charger P%d", port);
+
+ return EC_SUCCESS;
+}
+
+static const struct charge_port_info bj_power = {
+ /* 150W (also default) */
+ .voltage = 19500,
+ .current = 7700,
+};
+
+/* Debounce time for BJ plug/unplug */
+#define BJ_DEBOUNCE_MS CONFIG_EXTPOWER_DEBOUNCE_MS
+
+int board_should_charger_bypass(void)
+{
+ return charge_manager_get_active_charge_port() == DEDICATED_CHARGE_PORT;
+}
+
+static void bj_connect(void)
+{
+ static int8_t bj_connected = -1;
+ int connected = !gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL);
+
+ /* Debounce */
+ if (connected == bj_connected)
+ return;
+
+ bj_connected = connected;
+ CPRINTS("BJ %sconnected", connected ? "" : "dis");
+
+ charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED,
+ DEDICATED_CHARGE_PORT,
+ connected ? &bj_power : NULL);
+}
+DECLARE_DEFERRED(bj_connect);
+
+/* This handler shouldn't be needed if ACOK from isl9241 is working. */
+void bj_present_interrupt(enum gpio_signal signal)
+{
+ hook_call_deferred(&bj_connect_data, BJ_DEBOUNCE_MS * MSEC);
+}
+
+void ac_change(void)
+{
+ /*
+ * Serialize. We don't handle USB-C here because we'll get a
+ * notification from TCPC.
+ */
+ hook_call_deferred(&bj_connect_data, 0);
+}
+DECLARE_HOOK(HOOK_AC_CHANGE, ac_change, HOOK_PRIO_DEFAULT);
+
+static void power_supply_changed(void)
+{
+ /*
+ * We've switched to a new charge port (or no port). Hardware throttles
+ * can be removed now. Software throttles may stay enabled and change
+ * as the situation changes.
+ */
+ throttle_ap(THROTTLE_OFF, THROTTLE_HARD, THROTTLE_SRC_AC);
+ /*
+ * Unthrottling GPU is done through a deferred call scheduled when it
+ * was throttled.
+ */
+}
+DECLARE_HOOK(HOOK_POWER_SUPPLY_CHANGE, power_supply_changed, HOOK_PRIO_DEFAULT);
+
+static void bj_state_init(void)
+{
+ /*
+ * 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);
+ }
+
+ bj_connect();
+
+ isl9241_set_ac_prochot(CHARGER_SOLO, HADES_AC_PROCHOT_CURRENT_MA);
+}
+DECLARE_HOOK(HOOK_INIT, bj_state_init, HOOK_PRIO_INIT_CHARGE_MANAGER + 1);
diff --git a/board/hades/ec.tasklist b/board/hades/ec.tasklist
new file mode 100644
index 0000000000..905a3cceca
--- /dev/null
+++ b/board/hades/ec.tasklist
@@ -0,0 +1,29 @@
+/* Copyright 2023 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, HOOKS_TASK_STACK_SIZE) \
+ TASK_ALWAYS(LED, led_task, NULL, 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(CHARGER, charger_task, NULL, BASEBOARD_CHARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, BASEBOARD_CHIPSET_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, CONSOLE_TASK_STACK_SIZE) \
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, BASEBOARD_POWERBTN_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, BASEBOARD_PD_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, BASEBOARD_PD_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, BASEBOARD_PD_INT_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, BASEBOARD_PD_INT_TASK_STACK_SIZE)
diff --git a/board/hades/fans.c b/board/hades/fans.c
new file mode 100644
index 0000000000..0a734331aa
--- /dev/null
+++ b/board/hades/fans.c
@@ -0,0 +1,66 @@
+/* Copyright 2023 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_1,
+ .clk_src = TCKC_LFCLK,
+ .pwm_id = PWM_CH_FAN,
+ },
+ [MFT_CH_1] = {
+ .module = NPCX_MFT_MODULE_2,
+ .clk_src = TCKC_LFCLK,
+ .pwm_id = PWM_CH_FAN2,
+ },
+};
+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,
+};
+
+static const struct fan_conf fan_conf_1 = {
+ .flags = FAN_USE_RPM_MODE,
+ .ch = MFT_CH_1, /* Use MFT id to control fan */
+ .pgood_gpio = -1,
+ .enable_gpio = GPIO_EN_PP5000_FAN2,
+};
+
+static const struct fan_rpm fan_rpm_0 = {
+ .rpm_min = 2500,
+ .rpm_start = 2500,
+ .rpm_max = 4300,
+};
+
+static const struct fan_rpm fan_rpm_1 = {
+ .rpm_min = 2500,
+ .rpm_start = 2500,
+ .rpm_max = 4300,
+};
+
+const struct fan_t fans[FAN_CH_COUNT] = {
+ [FAN_CH_0] = {
+ .conf = &fan_conf_0,
+ .rpm = &fan_rpm_0,
+ },
+ [FAN_CH_1] = {
+ .conf = &fan_conf_1,
+ .rpm = &fan_rpm_1,
+ },
+};
diff --git a/board/hades/fw_config.c b/board/hades/fw_config.c
new file mode 100644
index 0000000000..a49079a9f1
--- /dev/null
+++ b/board/hades/fw_config.c
@@ -0,0 +1,40 @@
+/* Copyright 2023 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_CHIPSET, format, ##args)
+
+static union hades_cbi_fw_config fw_config;
+BUILD_ASSERT(sizeof(fw_config) == sizeof(uint32_t));
+
+/*
+ * FW_CONFIG defaults for hades if the CBI.FW_CONFIG data is not
+ * initialized.
+ */
+static const union hades_cbi_fw_config fw_config_defaults = {
+ .kb_bl = KEYBOARD_BACKLIGHT_ENABLED,
+};
+
+/****************************************************************************
+ * Hades 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;
+ }
+}
+
+union hades_cbi_fw_config get_fw_config(void)
+{
+ return fw_config;
+}
diff --git a/board/hades/fw_config.h b/board/hades/fw_config.h
new file mode 100644
index 0000000000..5f7758bb2a
--- /dev/null
+++ b/board/hades/fw_config.h
@@ -0,0 +1,38 @@
+/* Copyright 2023 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_HADES_FW_CONFIG_H_
+#define __BOARD_HADES_FW_CONFIG_H_
+
+#include <stdint.h>
+
+/****************************************************************************
+ * CBI FW_CONFIG layout for Hades board.
+ *
+ * Source of truth is the project/draco/agah/config.star configuration file.
+ */
+
+enum ec_cfg_keyboard_backlight_type {
+ KEYBOARD_BACKLIGHT_DISABLED = 0,
+ KEYBOARD_BACKLIGHT_ENABLED = 1
+};
+
+union hades_cbi_fw_config {
+ struct {
+ enum ec_cfg_keyboard_backlight_type kb_bl : 1;
+ uint32_t audio : 3;
+ uint32_t reserved_1 : 21;
+ };
+ uint32_t raw_value;
+};
+
+/**
+ * Read the cached FW_CONFIG. Guaranteed to have valid values.
+ *
+ * @return the FW_CONFIG for the board.
+ */
+union hades_cbi_fw_config get_fw_config(void);
+
+#endif /* __BOARD_HADES_FW_CONFIG_H_ */
diff --git a/board/hades/gpio.inc b/board/hades/gpio.inc
new file mode 100644
index 0000000000..c35ecebbdf
--- /dev/null
+++ b/board/hades/gpio.inc
@@ -0,0 +1,135 @@
+/* -*- mode:c -*-
+ *
+ * Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define MODULE_KB MODULE_KEYBOARD_SCAN
+
+/* INTERRUPT GPIOs: */
+GPIO_INT(ACOK_OD, PIN(0, 0), GPIO_INT_BOTH | GPIO_HIB_WAKE_HIGH, 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 | GPIO_HIB_WAKE_LOW, power_button_interrupt)
+GPIO_INT(LID_OPEN, PIN(D, 2), GPIO_INT_BOTH | GPIO_HIB_WAKE_HIGH, lid_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_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(PG_PP3300_S5_OD, PIN(B, 4), GPIO_INT_BOTH | GPIO_PULL_UP, board_power_interrupt)
+GPIO_INT(USB_C2_BC12_INT_ODL, PIN(8, 3), GPIO_INT_FALLING, bc12_interrupt)
+GPIO_INT(USB_C2_TCPC_INT_ODL, PIN(A, 7), GPIO_INT_FALLING, tcpc_alert_event)
+GPIO_INT(USB_C2_PPC_INT_ODL, PIN(7, 0), GPIO_INT_FALLING, ppc_interrupt)
+GPIO_INT(BJ_ADP_PRESENT_ODL, PIN(5, 6), GPIO_INT_BOTH | GPIO_PULL_UP, bj_present_interrupt)
+GPIO_INT(GPU_OVERT_ODL, PIN(5, 0), GPIO_INT_BOTH, gpu_overt_interrupt)
+
+/* USED GPIOs: */
+GPIO(CCD_MODE_ODL, PIN(E, 5), GPIO_INPUT)
+GPIO(CPU_C10_GATE_L, PIN(6, 7), GPIO_INPUT)
+GPIO(EC_BATT_PRES_ODL, PIN(A, 3), GPIO_INPUT)
+GPIO(EC_ENTERING_RW, PIN(0, 3), GPIO_OUT_LOW)
+GPIO(EC_EN_EDP_BL, PIN(D, 3), GPIO_OUT_HIGH)
+GPIO(EC_GSC_PACKET_MODE, PIN(7, 5), GPIO_OUT_LOW)
+GPIO(EC_I2C_BAT_SCL, PIN(3, 3), GPIO_INPUT)
+GPIO(EC_I2C_BAT_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_USB_C2_SCL, PIN(9, 2), GPIO_INPUT)
+GPIO(EC_I2C_USB_C2_SDA, PIN(9, 1), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_SCL, PIN(9, 0), GPIO_INPUT)
+GPIO(EC_I2C_USB_C0_SDA, PIN(8, 7), GPIO_INPUT)
+GPIO(EC_I2C_USBA_RT_SCL, PIN(E, 4), GPIO_INPUT)
+GPIO(EC_I2C_USBA_RT_SDA, PIN(E, 3), GPIO_INPUT)
+GPIO(EC_KB_BL_EN, PIN(8, 6), GPIO_OUT_LOW)
+GPIO(EC_PCHHOT_ODL, PIN(7, 4), GPIO_INPUT)
+GPIO(EC_PCH_INT_ODL, PIN(B, 0), GPIO_ODR_HIGH)
+GPIO(EC_PCH_PWR_BTN_ODL, PIN(C, 1), 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_R_ODL, PIN(C, 0), GPIO_ODR_HIGH)
+GPIO(EC_PROCHOT_ODL, PIN(6, 3), GPIO_ODR_HIGH)
+GPIO(EN_PP5000_FAN, PIN(6, 1), GPIO_OUT_LOW)
+GPIO(EN_PP5000_FAN2, PIN(F, 5), GPIO_OUT_LOW)
+GPIO(EN_PP5000_USBA_R, PIN(D, 7), GPIO_OUT_LOW)
+GPIO(EN_S5_RAILS, PIN(9, 6), GPIO_OUT_LOW)
+GPIO(IMVP9_VRRDY_OD, PIN(4, 3), GPIO_INPUT)
+GPIO(PCH_PWROK, PIN(7, 2), GPIO_OUT_LOW)
+GPIO(SYS_RST_ODL, PIN(C, 5), GPIO_ODR_HIGH)
+GPIO(EC_USB_PCH_C0_OC_ODL, PIN(9, 4), GPIO_ODR_HIGH)
+GPIO(EC_USB_PCH_C2_OC_ODL, PIN(9, 7), GPIO_ODR_HIGH)
+GPIO(USB_C0_FRS_EN, PIN(A, 0), GPIO_OUT_LOW)
+GPIO(VCCST_PWRGD_OD, PIN(A, 4), GPIO_ODR_LOW)
+GPIO(EN_USB_A_LOW_POWER, PIN(9, 3), GPIO_OUT_LOW)
+GPIO(PG_PP3300_S5_EC_SEQ_OD, PIN(B, 5), GPIO_OUT_LOW)
+GPIO(USB_C2_FRS_EN, PIN(D, 4), GPIO_OUT_LOW)
+GPIO(NVIDIA_GPU_ACOFF_ODL, PIN(9, 5), GPIO_ODR_HIGH)
+GPIO(LED_2_L, PIN(C, 3), GPIO_OUT_LOW)
+GPIO(LED_1_L, PIN(C, 4), GPIO_OUT_LOW)
+
+/*
+ * Barrel-jack adapter enable switch. When starting up on a depleted battery,
+ * we'll be powered by either BJ or USB-C but not both. The EC will detect BJ
+ * or USBC and disable the other ports.
+ */
+GPIO(EN_PPVAR_BJ_ADP_L, PIN(A, 2), GPIO_OUT_LOW)
+
+/*
+ * The NPCX keyboard driver does not use named GPIOs to access
+ * keyboard scan pins, so we do not list them in *gpio.inc. However, when
+ * KEYBOARD_COL2_INVERTED is defined, this name is required.
+ */
+GPIO(EC_KSO_02_INV, PIN(1, 7), GPIO_OUT_LOW)
+
+/* 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(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(4, 0x01), 0, MODULE_PWM, 0) /* GPIO40/TA1 */
+ALTERNATE(PIN_MASK(7, 0x08), 0, MODULE_PWM, 0) /* GPIO73/TA2 */
+ALTERNATE(PIN_MASK(8, 0x01), 0, MODULE_PWM, 0) /* GPIO80/PWM3 */
+ALTERNATE(PIN_MASK(B, 0xC0), 0, MODULE_PWM, 0) /* GPIOB7/PWM5, GPIOB6/PWM4 */
+
+/* ADC alternate functions */
+ALTERNATE(PIN_MASK(3, 0x10), 0, MODULE_ADC, 0) /* GPIO34/PS2_DAT2/ADC6 */
+ALTERNATE(PIN_MASK(4, 0x36), 0, MODULE_ADC, 0) /* GPIO42/ADC3/RI_L, GPIO45/ADC0, GPIO44/ADC1, GPIO41/ADC4 */
+
+/* KB alternate functions */
+ALTERNATE(PIN_MASK(0, 0xf0), 0, MODULE_KB, GPIO_ODR_HIGH) /* KSO10&P80_CLK/GPIO07, KSO11&P80_DAT/GPIO06, KSO12/GPIO05, KSO13/GPIO04 */
+ALTERNATE(PIN_MASK(1, 0x7f), 0, MODULE_KB, GPIO_ODR_HIGH) /* KSO06/GPO13/GP_SEL_L, KSO07/GPO12/JEN_L, KSO03/GPIO16/JTAG_TDO0_SWO, KSO04/GPIO15/XNOR, KSO05/GPIO14, KSO08/GPIO11/CR_SOUT1, KSO09/GPIO10/CR_SIN1 */
+ALTERNATE(PIN_MASK(2, 0xfc), 0, MODULE_KB, GPIO_INPUT | GPIO_PULL_UP) /* KSI2/GPIO27/TRACEDATA1, KSI3/GPIO26/TRACEDATA0, KSI4/GPIO25/TRACECLK/GP_SCLK, KSI5/GPIO24/GP_MISO, KSI6/GPIO23/S_SBUB, KSI7/GPIO22/S_SBUA */
+ALTERNATE(PIN_MASK(2, 0x03), 0, MODULE_KB, GPIO_ODR_HIGH) /* KSO00/GPIO21/JTAG_TCK_SWCLK, KSO01/GPIO20/JTAG_TMS_SWIO */
+ALTERNATE(PIN_MASK(3, 0x03), 0, MODULE_KB, GPIO_INPUT | GPIO_PULL_UP) /* KSI0/GPIO31/TRACEDATA3/GP_MOSI, KSI1/GPIO30/TRACEDATA2/GP_CS_L */
+ALTERNATE(PIN_MASK(8, 0x04), 0, MODULE_KB, GPIO_ODR_HIGH) /* KSO14/GPIO82 */
+
+/* PMU alternate functions */
+ALTERNATE(PIN_MASK(0, 0x01), 0, MODULE_PMU, GPIO_INT_BOTH | GPIO_HIB_WAKE_HIGH) /* PSL_IN2_L&GPI00/GPIO00 */
+ALTERNATE(PIN_MASK(0, 0x02), 0, MODULE_PMU, GPIO_INT_BOTH | GPIO_HIB_WAKE_LOW) /* GPIO01/PSL_IN3_L&GPI01 */
+ALTERNATE(PIN_MASK(D, 0x04), 0, MODULE_PMU, GPIO_INT_BOTH | GPIO_HIB_WAKE_HIGH) /* PSL_IN1_L&GPID2/GPIOD2 */
+
+/* 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(0, 2)) /* GPIO02 */
+UNUSED(PIN(6, 6)) /* GPIO66 */
+UNUSED(PIN(5, 7)) /* GPIO57/SER_IRQ/ESPI_ALERT_L */
+UNUSED(PIN(8, 1)) /* GPIO81 */
+UNUSED(PIN(6, 0)) /* GPIO60 */
+UNUSED(PIN(C, 2)) /* GPIOC2 */
+UNUSED(PIN(E, 1)) /* GPIOE1 */
diff --git a/board/hades/i2c.c b/board/hades/i2c.c
new file mode 100644
index 0000000000..bf8c88b211
--- /dev/null
+++ b/board/hades/i2c.c
@@ -0,0 +1,56 @@
+/* Copyright 2023 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 "i2c.h"
+
+#define BOARD_ID_FAST_PLUS_CAPABLE 2
+
+/* I2C port map configuration */
+const struct i2c_port_t i2c_ports[] = {
+ {
+ /* I2C1 */
+ .name = "tcpc0",
+ .port = I2C_PORT_USB_C0_TCPC,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_USB_C0_SCL,
+ .sda = GPIO_EC_I2C_USB_C0_SDA,
+ },
+ {
+ /* I2C2 */
+ .name = "tcpc2",
+ .port = I2C_PORT_USB_C2_TCPC,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_USB_C2_SCL,
+ .sda = GPIO_EC_I2C_USB_C2_SDA,
+ },
+ {
+ /* I2C5 */
+ .name = "battery",
+ .port = I2C_PORT_BATTERY,
+ .kbps = 100,
+ .scl = GPIO_EC_I2C_BAT_SCL,
+ .sda = GPIO_EC_I2C_BAT_SDA,
+ },
+ {
+ /* I2C6 */
+ .name = "usba1",
+ .port = I2C_PORT_USBA1_RT,
+ .kbps = 400,
+ .scl = GPIO_EC_I2C_USBA_RT_SCL,
+ .sda = GPIO_EC_I2C_USBA_RT_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/hades/keyboard.c b/board/hades/keyboard.c
new file mode 100644
index 0000000000..a63feae5c2
--- /dev/null
+++ b/board/hades/keyboard.c
@@ -0,0 +1,52 @@
+/* Copyright 2023 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 "ec_commands.h"
+#include "keyboard_scan.h"
+#include "timer.h"
+
+/* Keyboard scan setting */
+__override struct keyboard_scan_config keyscan_config = {
+ /* Increase from 50 us, because KSO_02 passes through the H1. */
+ .output_settle_us = 80,
+ /* Other values should be the same as the default configuration. */
+ .debounce_down_us = 9 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 3 * MSEC,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = 100 * MSEC,
+ .actual_key_mask = {
+ 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xa4, 0xff, 0xf6, 0x55, 0xfe, 0xff, 0xff, 0xff, /* full set */
+ },
+};
+
+static const struct ec_response_keybd_config keybd = {
+ .num_top_row_keys = 13,
+ .action_keys = {
+ TK_BACK, /* T1 */
+ TK_REFRESH, /* T2 */
+ TK_FULLSCREEN, /* T3 */
+ TK_OVERVIEW, /* T4 */
+ TK_SNAPSHOT, /* T5 */
+ TK_BRIGHTNESS_DOWN, /* T6 */
+ TK_BRIGHTNESS_UP, /* T7 */
+ TK_KBD_BKLIGHT_TOGGLE, /* T8 */
+ TK_PLAY_PAUSE, /* T9 */
+ TK_MICMUTE, /* T10 */
+ TK_VOL_MUTE, /* T11 */
+ TK_VOL_DOWN, /* T12 */
+ TK_VOL_UP, /* T13 */
+ },
+ /* There's no screen lock key on hades */
+ .capabilities = KEYBD_CAP_NUMERIC_KEYPAD,
+};
+
+__override const struct ec_response_keybd_config *
+board_vivaldi_keybd_config(void)
+{
+ return &keybd;
+}
diff --git a/board/hades/led.c b/board/hades/led.c
new file mode 100644
index 0000000000..2781842e79
--- /dev/null
+++ b/board/hades/led.c
@@ -0,0 +1,192 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Battery LED control for Hades
+ */
+
+#include "battery.h"
+#include "charge_manager.h"
+#include "charge_state.h"
+#include "chipset.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "led_common.h"
+#include "task.h"
+
+#include <stdint.h>
+
+#define BAT_LED_ON 0
+#define BAT_LED_OFF 1
+
+#define BATT_LOW_BCT 10
+
+#define LED_TICK_INTERVAL_MS (500 * MSEC)
+#define LED_CYCLE_TIME_MS (2000 * MSEC)
+#define LED_TICKS_PER_CYCLE (LED_CYCLE_TIME_MS / LED_TICK_INTERVAL_MS)
+#define LED_ON_TIME_MS (1000 * MSEC)
+#define LED_ON_TICKS (LED_ON_TIME_MS / LED_TICK_INTERVAL_MS)
+
+const enum ec_led_id supported_led_ids[] = { EC_LED_ID_BATTERY_LED };
+
+const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+
+enum led_color {
+ LED_OFF = 0,
+ LED_AMBER,
+ LED_WHITE,
+ LED_COLOR_COUNT /* Number of colors, not a color itself */
+};
+
+static void led_set_color_battery(enum led_color color)
+{
+ enum gpio_signal amber_led, white_led;
+
+ amber_led = GPIO_LED_1_L;
+ white_led = GPIO_LED_2_L;
+
+ switch (color) {
+ case LED_WHITE:
+ gpio_set_level(white_led, BAT_LED_ON);
+ gpio_set_level(amber_led, BAT_LED_OFF);
+ break;
+ case LED_AMBER:
+ gpio_set_level(white_led, BAT_LED_OFF);
+ gpio_set_level(amber_led, BAT_LED_ON);
+ break;
+ case LED_OFF:
+ gpio_set_level(white_led, BAT_LED_OFF);
+ gpio_set_level(amber_led, BAT_LED_OFF);
+ break;
+ default:
+ break;
+ }
+}
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ switch (led_id) {
+ case EC_LED_ID_BATTERY_LED:
+ brightness_range[EC_LED_COLOR_WHITE] = 1;
+ brightness_range[EC_LED_COLOR_AMBER] = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
+{
+ switch (led_id) {
+ case EC_LED_ID_BATTERY_LED:
+ if (brightness[EC_LED_COLOR_WHITE] != 0)
+ led_set_color_battery(LED_WHITE);
+ else if (brightness[EC_LED_COLOR_AMBER] != 0)
+ led_set_color_battery(LED_AMBER);
+ else
+ led_set_color_battery(LED_OFF);
+ break;
+ default:
+ return EC_ERROR_PARAM1;
+ }
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Set active charge port color to the parameter, turn off all others.
+ * If no port is active (-1), turn off all LEDs.
+ */
+static void set_active_port_color(enum led_color color)
+{
+ if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED))
+ led_set_color_battery(color);
+}
+
+static void led_set_battery(void)
+{
+ static unsigned int battery_ticks;
+ static unsigned int suspend_ticks;
+
+ battery_ticks++;
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND) &&
+ charge_get_state() != PWR_STATE_CHARGE) {
+ suspend_ticks++;
+
+ led_set_color_battery(
+ (suspend_ticks % LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+ LED_WHITE :
+ LED_OFF);
+
+ return;
+ }
+
+ switch (charge_get_state()) {
+ case PWR_STATE_CHARGE:
+ /* Always indicate when charging, even in suspend. */
+ set_active_port_color(LED_AMBER);
+ break;
+ case PWR_STATE_DISCHARGE:
+ /*
+ * Blinking amber LEDs slowly if battery is lower 10
+ * percentage.
+ */
+ if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) {
+ if (charge_get_percent() < BATT_LOW_BCT)
+ led_set_color_battery(
+ (battery_ticks % LED_TICKS_PER_CYCLE <
+ LED_ON_TICKS) ?
+ LED_AMBER :
+ LED_OFF);
+ else
+ led_set_color_battery(LED_OFF);
+ }
+
+ break;
+ case PWR_STATE_ERROR:
+ if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) {
+ led_set_color_battery(
+ (battery_ticks & 0x1) ? LED_AMBER : LED_OFF);
+ }
+
+ break;
+ case PWR_STATE_CHARGE_NEAR_FULL:
+ set_active_port_color(LED_WHITE);
+ break;
+ case PWR_STATE_IDLE: /* External power connected in IDLE */
+ set_active_port_color(LED_WHITE);
+ break;
+ case PWR_STATE_FORCED_IDLE:
+ set_active_port_color(
+ (battery_ticks % LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+ LED_AMBER :
+ LED_OFF);
+ break;
+ default:
+ /* Other states don't alter LED behavior */
+ break;
+ }
+}
+
+void led_task(void *u)
+{
+ uint32_t start_time;
+ uint32_t task_duration;
+
+ while (1) {
+ start_time = get_time().le.lo;
+
+ led_set_battery();
+
+ /* Compute time for this iteration */
+ task_duration = get_time().le.lo - start_time;
+ /*
+ * Compute wait time required to for next desired LED tick. If
+ * the duration exceeds the tick time, then don't sleep.
+ */
+ if (task_duration < LED_TICK_INTERVAL_MS)
+ usleep(LED_TICK_INTERVAL_MS - task_duration);
+ }
+}
diff --git a/board/hades/pwm.c b/board/hades/pwm.c
new file mode 100644
index 0000000000..22c01fc6d9
--- /dev/null
+++ b/board/hades/pwm.c
@@ -0,0 +1,47 @@
+/* Copyright 2023 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_KBLIGHT] = {
+ .channel = 3,
+ .flags = 0,
+ /*
+ * Set PWM frequency to multiple of 50 Hz and 60 Hz to prevent
+ * flicker. Higher frequencies consume similar average power to
+ * lower PWM frequencies, but higher frequencies record a much
+ * lower maximum power.
+ */
+ .freq = 2400,
+ },
+ [PWM_CH_FAN] = {
+ .channel = 5,
+ .flags = PWM_CONFIG_OPEN_DRAIN,
+ .freq = 25000
+ },
+ [PWM_CH_FAN2] = {
+ .channel = 4,
+ .flags = PWM_CONFIG_OPEN_DRAIN,
+ .freq = 25000
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
+
+static void board_pwm_init(void)
+{
+ /*
+ * Turn off all the LEDs.
+ * Turn on the fan at 100%.
+ */
+
+ pwm_enable(PWM_CH_KBLIGHT, 1);
+ pwm_set_duty(PWM_CH_KBLIGHT, 50);
+}
+DECLARE_HOOK(HOOK_INIT, board_pwm_init, HOOK_PRIO_DEFAULT);
diff --git a/board/hades/sensors.c b/board/hades/sensors.c
new file mode 100644
index 0000000000..37b2d6c9c6
--- /dev/null
+++ b/board/hades/sensors.c
@@ -0,0 +1,135 @@
+/* Copyright 2023 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 "common.h"
+#include "hooks.h"
+#include "temp_sensor.h"
+#include "temp_sensor/thermistor.h"
+#include "thermal.h"
+
+/* ADC configuration */
+struct adc_t adc_channels[] = {
+ [ADC_TEMP_SENSOR_1_DDR_SOC] = {
+ .name = "TEMP_DDR_SOC",
+ .input_ch = NPCX_ADC_CH0,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_TEMP_SENSOR_2_GPU] = {
+ .name = "TEMP_GPU",
+ .input_ch = NPCX_ADC_CH1,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_TEMP_SENSOR_3_CHARGER] = {
+ .name = "TEMP_CHARGER",
+ .input_ch = NPCX_ADC_CH6,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_CHARGER_IADP] = {
+ .name = "CHARGER_IADP",
+ .input_ch = NPCX_ADC_CH3,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+ [ADC_ADP_TYP] = {
+ .name = "ADP_TYP",
+ .input_ch = NPCX_ADC_CH4,
+ .factor_mul = ADC_MAX_VOLT,
+ .factor_div = ADC_READ_MAX + 1,
+ .shift = 0,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* Temperature sensor configuration */
+const struct temp_sensor_t temp_sensors[] = {
+ [TEMP_SENSOR_1_DDR_SOC] = {
+ .name = "DDR and SOC",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_1_DDR_SOC,
+ },
+ [TEMP_SENSOR_2_GPU] = {
+ .name = "GPU",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_2_GPU,
+ },
+ [TEMP_SENSOR_3_CHARGER] = {
+ .name = "Charger",
+ .type = TEMP_SENSOR_TYPE_BOARD,
+ .read = get_temp_3v3_30k9_47k_4050b,
+ .idx = ADC_TEMP_SENSOR_3_CHARGER,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+#define THERMAL_CPU \
+ { \
+ .temp_host = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(85), \
+ [EC_TEMP_THRESH_HALT] = C_TO_K(90), \
+ }, \
+ .temp_host_release = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(80), \
+ }, \
+ .temp_fan_off = C_TO_K(35), \
+ .temp_fan_max = C_TO_K(60), \
+ }
+__maybe_unused static const struct ec_thermal_config thermal_cpu = THERMAL_CPU;
+
+#define THERMAL_GPU \
+ { \
+ .temp_host = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(85), \
+ [EC_TEMP_THRESH_HALT] = C_TO_K(90), \
+ }, \
+ .temp_host_release = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(80), \
+ }, \
+ .temp_fan_off = C_TO_K(35), \
+ .temp_fan_max = C_TO_K(60), \
+ }
+__maybe_unused static const struct ec_thermal_config thermal_gpu = THERMAL_GPU;
+
+/*
+ * Inductor limits - used for both charger and PP3300 regulator
+ *
+ * Need to use the lower of the charger IC, PP3300 regulator, and the inductors
+ *
+ * Charger max recommended temperature 125C, max absolute temperature 150C
+ * PP3300 regulator: operating range -40 C to 125 C
+ *
+ * Inductors: limit of 125c
+ * PCB: limit is 80c
+ */
+#define THERMAL_CHARGER \
+ { \
+ .temp_host = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(105), \
+ [EC_TEMP_THRESH_HALT] = C_TO_K(120), \
+ }, \
+ .temp_host_release = { \
+ [EC_TEMP_THRESH_HIGH] = C_TO_K(90), \
+ }, \
+ .temp_fan_off = C_TO_K(35), \
+ .temp_fan_max = C_TO_K(65), \
+ }
+__maybe_unused static const struct ec_thermal_config thermal_charger =
+ THERMAL_CHARGER;
+
+struct ec_thermal_config thermal_params[] = {
+ [TEMP_SENSOR_1_DDR_SOC] = THERMAL_CPU,
+ [TEMP_SENSOR_2_GPU] = THERMAL_GPU,
+ [TEMP_SENSOR_3_CHARGER] = THERMAL_CHARGER,
+};
+BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
diff --git a/board/hades/usbc_config.c b/board/hades/usbc_config.c
new file mode 100644
index 0000000000..7511773cc8
--- /dev/null
+++ b/board/hades/usbc_config.c
@@ -0,0 +1,332 @@
+/* Copyright 2023 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 "charge_ramp.h"
+#include "charger.h"
+#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/ps8818_public.h"
+#include "driver/tcpm/rt1715.h"
+#include "driver/tcpm/tcpci.h"
+#include "ec_commands.h"
+#include "fw_config.h"
+#include "gpio.h"
+#include "gpio_signal.h"
+#include "hooks.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_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_C2_TCPC,
+ .addr_flags = RT1715_I2C_ADDR_FLAGS,
+ },
+ .drv = &rt1715_tcpm_drv,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(tcpc_config) == USBC_PORT_COUNT);
+BUILD_ASSERT(CONFIG_USB_PD_PORT_MAX_COUNT == USBC_PORT_COUNT);
+
+/******************************************************************************/
+/* USB-A charging control */
+
+const int usb_port_enable[USB_PORT_COUNT] = {
+ GPIO_EN_PP5000_USBA_R,
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_port_enable) == USB_PORT_COUNT);
+
+/******************************************************************************/
+
+/* USBC PPC configuration */
+struct ppc_config_t ppc_chips[] = {
+ [USBC_PORT_C0] = {
+ .i2c_port = I2C_PORT_USB_C0_PPC,
+ .i2c_addr_flags = SYV682X_ADDR0_FLAGS,
+ .frs_en = GPIO_USB_C0_FRS_EN,
+ .drv = &syv682x_drv,
+ },
+ [USBC_PORT_C2] = {
+ .i2c_port = I2C_PORT_USB_C2_PPC,
+ .i2c_addr_flags = SYV682X_ADDR2_FLAGS,
+ .frs_en = GPIO_USB_C2_FRS_EN,
+ .drv = &syv682x_drv,
+ },
+};
+
+unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips);
+
+const static struct ps8818_reg_val equalizer_default_table[] = {
+ {
+ .reg = PS8818_REG1_APTX1EQ_10G_LEVEL,
+ .mask = PS8818_EQ_LEVEL_UP_MASK,
+ .val = PS8818_EQ_LEVEL_UP_19DB,
+ },
+ {
+ .reg = PS8818_REG1_APTX2EQ_10G_LEVEL,
+ .mask = PS8818_EQ_LEVEL_UP_MASK,
+ .val = PS8818_EQ_LEVEL_UP_19DB,
+ },
+ {
+ .reg = PS8818_REG1_APTX1EQ_5G_LEVEL,
+ .mask = PS8818_EQ_LEVEL_UP_MASK,
+ .val = PS8818_EQ_LEVEL_UP_19DB,
+ },
+ {
+ .reg = PS8818_REG1_APTX2EQ_5G_LEVEL,
+ .mask = PS8818_EQ_LEVEL_UP_MASK,
+ .val = PS8818_EQ_LEVEL_UP_19DB,
+ },
+ {
+ .reg = PS8818_REG1_RX_PHY,
+ .mask = PS8818_RX_INPUT_TERM_MASK,
+ .val = PS8818_RX_INPUT_TERM_112_OHM,
+ },
+};
+
+#define NUM_EQ_DEFAULT_ARRAY ARRAY_SIZE(equalizer_default_table)
+
+int board_ps8818_mux_set(const struct usb_mux *me, mux_state_t mux_state)
+{
+ int rv = EC_SUCCESS;
+ int i;
+
+ /* USB specific config */
+ if (mux_state & USB_PD_MUX_USB_ENABLED) {
+ /* Boost the USB gain */
+ for (i = 0; i < NUM_EQ_DEFAULT_ARRAY; i++)
+ rv |= ps8818_i2c_field_update8(
+ me, PS8818_REG_PAGE1,
+ equalizer_default_table[i].reg,
+ equalizer_default_table[i].mask,
+ equalizer_default_table[i].val);
+ }
+
+ /* DP specific config */
+ if (mux_state & USB_PD_MUX_DP_ENABLED) {
+ /* Boost the DP gain */
+ rv |= ps8818_i2c_field_update8(me, PS8818_REG_PAGE1,
+ PS8818_REG1_DPEQ_LEVEL,
+ PS8818_DPEQ_LEVEL_UP_MASK,
+ PS8818_DPEQ_LEVEL_UP_19DB);
+ }
+
+ return rv;
+}
+
+const static struct usb_mux_chain usbc2_ps8818 = {
+ .mux =
+ &(const struct usb_mux){
+ .usb_port = USBC_PORT_C2,
+ .i2c_port = I2C_PORT_USB_C2_TCPC,
+ .i2c_addr_flags = PS8818_I2C_ADDR0_FLAGS,
+ .driver = &ps8818_usb_retimer_driver,
+ .board_set = &board_ps8818_mux_set,
+ },
+};
+
+/* USBC mux configuration - Alder Lake includes internal mux */
+const struct usb_mux_chain usb_muxes[] = {
+ [USBC_PORT_C0] = {
+ .mux = &(const struct usb_mux) {
+ .usb_port = USBC_PORT_C0,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ },
+ },
+ [USBC_PORT_C2] = {
+ .mux = &(const struct usb_mux) {
+ .usb_port = USBC_PORT_C2,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ },
+ .next = &usbc2_ps8818,
+ },
+};
+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_BC12,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+ [USBC_PORT_C2] = {
+ .i2c_port = I2C_PORT_USB_C2_BC12,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pi3usb9201_bc12_chips) == USBC_PORT_COUNT);
+
+#ifdef CONFIG_CHARGE_RAMP_SW
+
+#define BC12_MIN_VOLTAGE 4400
+
+/**
+ * Return true if VBUS is too low
+ */
+int board_is_vbus_too_low(int port, enum chg_ramp_vbus_state ramp_state)
+{
+ int voltage;
+
+ if (charger_get_vbus_voltage(port, &voltage))
+ voltage = 0;
+
+ if (voltage == 0) {
+ CPRINTS("%s: must be disconnected", __func__);
+ return 1;
+ }
+
+ if (voltage < BC12_MIN_VOLTAGE) {
+ CPRINTS("%s: port %d: vbus %d lower than %d", __func__, port,
+ voltage, BC12_MIN_VOLTAGE);
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_CHARGE_RAMP_SW */
+
+void board_reset_pd_mcu(void)
+{
+ /* There's no reset pin on TCPC */
+}
+
+static void board_tcpc_init(void)
+{
+ /* Don't reset TCPCs after initial reset */
+ if (!system_jumped_late())
+ board_reset_pd_mcu();
+
+ /* 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_TCPC_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C2_TCPC_INT_ODL);
+
+ /* Enable BC1.2 interrupts. */
+ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C2_BC12_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_TCPC_INT_ODL) == 0)
+ status |= PD_STATUS_TCPC_ALERT_0;
+
+ if (gpio_get_level(GPIO_USB_C2_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;
+
+ 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_TCPC_INT_ODL:
+ schedule_deferred_pd_interrupt(USBC_PORT_C0);
+ break;
+ case GPIO_USB_C2_TCPC_INT_ODL:
+ schedule_deferred_pd_interrupt(USBC_PORT_C2);
+ 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_C2_BC12_INT_ODL:
+ usb_charger_task_set_event(1, 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_C2_PPC_INT_ODL:
+ syv682x_interrupt(USBC_PORT_C2);
+ break;
+ default:
+ break;
+ }
+}
+
+void retimer_interrupt(enum gpio_signal signal)
+{
+}
+
+__override bool board_is_dts_port(int port)
+{
+ return port == USBC_PORT_C0;
+}
+
+__override bool board_is_tbt_usb4_port(int port)
+{
+ return false;
+}
+
+__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/hades/usbc_config.h b/board/hades/usbc_config.h
new file mode 100644
index 0000000000..831dcc1a9f
--- /dev/null
+++ b/board/hades/usbc_config.h
@@ -0,0 +1,21 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Hades board-specific USB-C configuration */
+
+#ifndef __CROS_EC_USBC_CONFIG_H
+#define __CROS_EC_USBC_CONFIG_H
+
+#define CONFIG_USB_PD_PORT_MAX_COUNT 2
+
+enum usbc_port { USBC_PORT_C0 = 0, USBC_PORT_C2, USBC_PORT_COUNT };
+
+struct ps8818_reg_val {
+ uint8_t reg;
+ uint8_t mask;
+ uint16_t val;
+};
+
+#endif /* __CROS_EC_USBC_CONFIG_H */
diff --git a/board/hades/vif_override.xml b/board/hades/vif_override.xml
new file mode 100644
index 0000000000..32736caf64
--- /dev/null
+++ b/board/hades/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/util/build_with_clang.py b/util/build_with_clang.py
index ea3a244797..4d207d68b8 100755
--- a/util/build_with_clang.py
+++ b/util/build_with_clang.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -151,6 +150,7 @@ BOARDS_THAT_COMPILE_SUCCESSFULLY_WITH_CLANG = [
"grunt",
"gumboz",
"guybrush",
+ "hades",
"hatch",
"helios",
"herobrine",