Merge remote-tracking branch cros/main into firmware-dedede-13606.B-master

Generated by: ./util/update_release_branch.py -r --baseboard dedede
--relevant_paths_file util/dedede-relevant-paths.txt firmware-
dedede-13606.B-master

Relevant changes:

git log --oneline 08e58ac3ea..962884aabf -- baseboard/dedede
board/beadrix board/beetley board/blipper board/boten board/boxy
board/bugzzy board/corori2 board/cret board/dexi board/dibbi board/dita
board/drawcia board/galtic board/kracko board/lantis board/madoo
board/magolor board/metaknight board/pirika board/sasuke board/sasukette
board/shotzo board/storo board/taranza board/waddledee board/waddledoo
board/wheelie chip/it83xx common/charge_state.c common/fpsensor/build.mk
common/mkbp_* common/ocpc.c common/usbc/usb_tc_drp_acc_trysrc_sm.c
common/usbc/usb_sm.c common/usbc/*_pd_* common/usbc/dp_alt_mode.c
common/usbc/usb_prl_sm.c common/usbc/usb_pe_drp_sm.c
common/usb_charger.c common/usb_common.c common/usbc_ocp.c
driver/charger/sm5803.* driver/charger/isl923x.* driver/tcpm/raa489000.*
driver/tcpm/it83* include/power/icelake.h include/intel_x86.h
power/icelake.c power/intel_x86.c util/getversion.sh

75f10d98f0 Dita: Update thermal table
81ad5ebbcb usbpd: Move EC_CMD_PD_CONTROL and support func to common source
6961adf3bf buccaneer: Add buccaneer and *-druid to getversion.sh
e6f8ab81b0 util/getversion.sh: Change case to align with style guide
33e27683c8 helipilot: Add extra repo version strings
94fa496082 Keyboard: Check FIFO size only if MKBP keyboard is enabled
2873bbe48b charge: drop CONFIG_USB_PD_PREFER_MV
98f881b323 Dita: Enable HDMI CEC power on
93c90d42df isl9238c: Add option to set input voltage register
33578112d8 config: add CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME
dedf09ebbf Dexi: Enable HDMI CEC power on
46881a0cbd pe: Move pd_set_input_curret_limit to pe_snk_transition_sink_run
684955f9b5 sm5803: reset flag in set mode when discharge

BUG=b:176500425 b:326151163 b:299186434 b:326343480 b:321048580
BUG=b:329847445 b:331290993 b:326538358 b:311552705 b:327137021
BUG=b:330953111 b:321092682
TEST=`make -j buildall`

Force-Relevant-Builds: all
Change-Id: Ic80a9aba652fd16d02f3764c23b888270a3ee887
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/5412894
Reviewed-by: Patryk Duda <patrykd@google.com>
Tested-by: Derek Huang <derekhuang@google.com>
Reviewed-by: Ivan Chen <yulunchen@google.com>
Reviewed-by: Shou-Chieh Hsu <shouchieh@chromium.org>
Commit-Queue: Derek Huang <derekhuang@google.com>
This commit is contained in:
Derek Huang 2024-04-02 14:46:58 +00:00 committed by Chromeos LUCI
commit cc1b9851b6
372 changed files with 15655 additions and 2828 deletions

View File

@ -172,7 +172,31 @@ before_script:
-o "${BUILD_DIR}/${PROJECT}/output/no_zephyr.info"
-r "${BUILD_DIR}/${PROJECT}/output/zephyr.info" "${ZEPHYR_BASE}/**"
"${MODULES_DIR}/**"
"${EC_DIR}/zephyr/drivers/**" "${EC_DIR}/zephyr/include/drivers/**"
"${EC_DIR}/zephyr/drivers/cros_displight/*"
"${EC_DIR}/zephyr/drivers/cros_flash/*"
"${EC_DIR}/zephyr/drivers/cros_kb_raw*"
"${EC_DIR}/zephyr/drivers/cros_kblight/*"
"${EC_DIR}/zephyr/drivers/cros_rtc/*"
"${EC_DIR}/zephyr/drivers/cros_shi/*"
"${EC_DIR}/zephyr/drivers/cros_system/*"
"${EC_DIR}/zephyr/drivers/cros_tabletmode_interrupt/*"
"${EC_DIR}/zephyr/drivers/fingerprint/*"
"${EC_DIR}/zephyr/drivers/keyboard_input/*"
"${EC_DIR}/zephyr/drivers/one_wire_uart/*"
"${EC_DIR}/zephyr/drivers/sm5803/*"
"${EC_DIR}/zephyr/drivers/vivaldi_kbd/*"
"${EC_DIR}/zephyr/include/drivers/cros_displight.h"
"${EC_DIR}/zephyr/include/drivers/cros_flash.h"
"${EC_DIR}/zephyr/include/drivers/cros_kb_raw.h"
"${EC_DIR}/zephyr/include/drivers/cros_rtc.h"
"${EC_DIR}/zephyr/include/drivers/cros_shi.h"
"${EC_DIR}/zephyr/include/drivers/cros_system.h"
"${EC_DIR}/zephyr/include/drivers/fingerprint_sim.h"
"${EC_DIR}/zephyr/include/drivers/fingerprint.h"
"${EC_DIR}/zephyr/include/drivers/one_wire_uart_internal.h"
"${EC_DIR}/zephyr/include/drivers/one_wire_uart_stream.h"
"${EC_DIR}/zephyr/include/drivers/one_wire_uart.h"
"${EC_DIR}/zephyr/include/drivers/vivaldi_kbd.h"
"${EC_DIR}/zephyr/shim/chip/**" "${EC_DIR}/zephyr/shim/core/**"
"/usr/include/**"
"${EC_DIR}/build/**" "${EC_DIR}/twister-out*/**"

View File

@ -3,12 +3,19 @@
* found in the LICENSE file.
*/
/* If we are actually using DRUID in the FP task, we need a bigger stack. */
#ifdef CONFIG_LIB_DRUID_WRAPPER
#define FPSENSOR_TASK_STACK_SIZE 20240
#else
#define FPSENSOR_TASK_STACK_SIZE 4096
#endif
/**
* See CONFIG_TASK_LIST in config.h for details.
*/
#define BASEBOARD_CONFIG_TASK_LIST \
TASK_ALWAYS_RO(RWSIG, rwsig_task, NULL, 1280) \
TASK_ALWAYS(HOOKS, hook_task, NULL, 1024) \
TASK_ALWAYS_RW(FPSENSOR, fp_task, NULL, 4096) \
TASK_ALWAYS_RW(FPSENSOR, fp_task, NULL, FPSENSOR_TASK_STACK_SIZE) \
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, 6144) \
TASK_ALWAYS(CONSOLE, console_task, NULL, CONSOLE_TASK_STACK_SIZE)

View File

@ -44,6 +44,7 @@ test-list-y = \
mpu \
mutex \
mutex_trylock \
mutex_recursive \
panic \
panic_data \
pingpong \

View File

@ -16,6 +16,7 @@
/* Optional features */
#define CONFIG_ASSERT_CCD_MODE_ON_DTS_CONNECT
#define CONFIG_LTO /* Link-Time Optimizations to reduce code size */
#define CONFIG_EMULATED_SYSRQ
#undef CONFIG_UART_TX_BUF_SIZE
#define CONFIG_UART_TX_BUF_SIZE 4096

View File

@ -36,6 +36,25 @@ int console_is_restricted(void)
/* Must come after other header files. */
#include "gpio_list.h"
static void ap_deferred(void)
{
/*
* Behavior:
* AP Active (ex. Intel S0): SLP_L is 1
* AP Suspend (ex. Intel S0ix): SLP_L is 0
*/
int running = gpio_get_level(GPIO_SLP_L);
if (running) { /* S0 */
disable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_RESUME);
} else { /* S0ix */
hook_notify(HOOK_CHIPSET_SUSPEND);
enable_sleep(SLEEP_MASK_AP_RUN);
}
}
DECLARE_DEFERRED(ap_deferred);
static void board_init_transport(void)
{
enum fp_transport_type ret_transport = get_fp_transport_type();
@ -80,13 +99,29 @@ static void board_init(void)
board_init_transport();
if (IS_ENABLED(SECTION_IS_RW)) {
board_init_rw();
}
/* Enable interrupt on PCH power signals */
gpio_enable_interrupt(GPIO_SLP_L);
/* Initialize trng peripheral before kicking off the application to
* avoid incurring that cost when generating random numbers
*/
npcx_trng_hw_init();
if (IS_ENABLED(SECTION_IS_RW)) {
board_init_rw();
}
/*
* Enable the SPI slave interface if the PCH is up.
* Do not use hook_call_deferred(), because ap_deferred() will be
* called after tasks with priority higher than HOOK task (very late).
*/
ap_deferred();
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
/* PCH power state changes */
void slp_event(enum gpio_signal signal)
{
hook_call_deferred(&ap_deferred_data, 0);
}

View File

@ -129,6 +129,8 @@
#define CONFIG_WP_STORAGE_SIZE CONFIG_EC_PROTECTED_STORAGE_SIZE
#define CONFIG_WP_ACTIVE_HIGH
#define CONFIG_OTP_KEY
/*
* We want to prevent flash readout, and use it as indicator of protection
* status.
@ -144,6 +146,8 @@
#undef CONFIG_CONSOLE_UART
#define CONFIG_CONSOLE_UART 0 /* 0:UART1 1:UART2 */
#define NPCX_UART_MODULE2 1 /* 1:GPIO64/65 as UART1 */
#undef CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME
#define CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME 0
#undef CONFIG_UART_TX_BUF_SIZE
#define CONFIG_UART_TX_BUF_SIZE 2048
@ -261,7 +265,7 @@
/* EC rollback protection block */
#define CONFIG_ROLLBACK_OFF \
(CONFIG_EC_PROTECTED_STORAGE_OFF + CONFIG_EC_PROTECTED_STORAGE_SIZE)
#define CONFIG_ROLLBACK_SIZE (128 * 1024 * 2) /* 2 blocks of 128KB each */
#define CONFIG_ROLLBACK_SIZE (64 * 1024 * 2) /* 2 blocks of 64KB each */
/*-------------------------------------------------------------------------*
* RW Signature Verification
@ -292,7 +296,6 @@
#define GPIO_SHI_CS_L GPIO_SPI_HOST_CS_MCU_ODL
#define GPIO_FPS_INT GPIO_FP_MCU_INT_L
#define GPIO_EC_INT_L GPIO_MCU_PLATFORM_INT_L
#define GPIO_SLP_ALT_L GPIO_SLP_L
#ifndef __ASSEMBLER__

View File

@ -7,10 +7,8 @@
#include "console.h"
#include "fpsensor/fpsensor_detect.h"
#include "gpio.h"
#include "hooks.h"
#include "registers.h"
#include "spi.h"
#include "system.h"
#include "task.h"
/*#include "usart_host_command.h"*/
#include "util.h"
@ -24,39 +22,6 @@
/* create alias to fit spi_devices declaration in 80 chars */
#define FP_SPI_CS GPIO_SPI_MCU_CS_FP_L
static void ap_deferred(void)
{
/*
* Behavior:
* AP Active (ex. Intel S0): SLP_L is 1
* AP Suspend (ex. Intel S0ix): SLP_L is 0
* The alternative SLP_ALT_L should be pulled high at all the times.
*
* Legacy Intel behavior:
* in S3: SLP_ALT_L is 0 and SLP_L is X.
* in S0ix: SLP_ALT_L is 1 and SLP_L is 0.
* in S0: SLP_ALT_L is 1 and SLP_L is 1.
* in S5/G3, the FP MCU should not be running.
*/
int running = gpio_get_level(GPIO_SLP_ALT_L) &&
(gpio_get_level(GPIO_SLP_L));
if (running) { /* S0 */
disable_sleep(SLEEP_MASK_AP_RUN);
hook_notify(HOOK_CHIPSET_RESUME);
} else { /* S0ix/S3 */
hook_notify(HOOK_CHIPSET_SUSPEND);
enable_sleep(SLEEP_MASK_AP_RUN);
}
}
DECLARE_DEFERRED(ap_deferred);
/* PCH power state changes */
void slp_event(enum gpio_signal signal)
{
hook_call_deferred(&ap_deferred_data, 0);
}
/* SPI devices */
const struct spi_device_t spi_devices[] = {
/* Fingerprint sensor (SCLK at 4Mhz) */
@ -76,17 +41,6 @@ void board_init_rw(void)
{
/* Configure and enable SPI as master for FP sensor */
configure_fp_sensor_spi();
/* Enable interrupt on PCH power signals */
gpio_enable_interrupt(GPIO_SLP_ALT_L);
gpio_enable_interrupt(GPIO_SLP_L);
/*
* Enable the SPI slave interface if the PCH is up.
* Do not use hook_call_deferred(), because ap_deferred() will be
* called after tasks with priority higher than HOOK task (very late).
*/
ap_deferred();
}
#ifndef HAS_TASK_FPSENSOR

View File

@ -9,6 +9,7 @@ GPIO_INT(HOST_MCU_WP_OD, PIN(A, 4), GPIO_INT_BOTH, switch_interrupt)
/* SHI CS Ready, Low Active. */
GPIO_INT(SPI_HOST_CS_MCU_ODL, PIN(5, 3), GPIO_INT_FALLING,shi_cs_event)
GPIO_INT(SLP_L, PIN(A, 0), GPIO_INT_BOTH, slp_event)
/* Inputs */
GPIO(TRANSPORT_SEL, PIN(4, 3), GPIO_INPUT)
@ -36,7 +37,6 @@ ALTERNATE(PIN_MASK(1, 0x03), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO10/11 */
ALTERNATE(PIN_MASK(7, 0x20), 1, MODULE_UART, 0) /* CR_SIN2 GPIO75 */
ALTERNATE(PIN_MASK(8, 0x40), 1, MODULE_UART, 0) /* CR_SOUT2 GPIO86 */
UNIMPLEMENTED(ENTERING_RW)
#ifdef SECTION_IS_RW

View File

@ -10,7 +10,6 @@
/* Interrupts */
GPIO_INT(FP_MCU_INT_L, PIN(B, 0), GPIO_INT_RISING, fps_event)
GPIO_INT(SLP_L, PIN(A, 0), GPIO_INT_BOTH, slp_event)
/* Inputs */
GPIO(FP_SENSOR_SEL, PIN(4, 4), GPIO_INPUT)
@ -18,9 +17,10 @@ GPIO(FP_SENSOR_SEL, PIN(4, 4), GPIO_INPUT)
/* Outputs */
GPIO(FP_RST_ODL, PIN(9, 6), GPIO_OUT_HIGH)
GPIO(SPI_MCU_CS_FP_L, PIN(A, 6), GPIO_OUT_HIGH)
GPIO(USER_PRES_L, PIN(A, 5), GPIO_ODR_HIGH)
/* SPIP - to fingerprint sensor */
/* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0)
/* SPIP_MISO GPIO95 */
ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0)
ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0)

View File

@ -44,6 +44,8 @@ test-list-y = \
mpu \
mutex \
mutex_trylock \
mutex_recursive \
otp_key \
panic \
panic_data \
pingpong \

View File

@ -55,7 +55,6 @@
* 12.85V * 1.05 = 13.5V
*/
#define PD_MAX_VOLTAGE_MV 12850
#define CONFIG_USB_PD_PREFER_MV
#elif defined(VARIANT_KUKUI_CHARGER_ISL9238)
#define CONFIG_CHARGER_ISL9238C
#define CONFIG_CHARGER_SENSE_RESISTOR_AC 20 /* BOARD_RS1 */

View File

@ -17,39 +17,6 @@
#include "util.h"
#define BAT_LEVEL_PD_LIMIT 85
#define SYSTEM_PLT_MW 3500
/*
* b/143318064: Prefer a voltage above 5V to force it picks a voltage
* above 5V at first. If PREFER_MV is 5V, when desired power is around
* 15W ~ 11W, it would pick 5V/3A initially, and mt6370 can only sink
* around 10W, and cause a low charging efficiency.
*/
#define PREVENT_CURRENT_DROP_MV 6000
#define DEFAULT_PREFER_MV 5000
/*
* We empirically chose 300mA as the limit for when buck inefficiency is
* noticeable.
*/
#define STABLE_CURRENT_DELTA 300
struct pd_pref_config_t pd_pref_config = {
.mv = PREVENT_CURRENT_DROP_MV,
.cv = 70,
.plt_mw = SYSTEM_PLT_MW,
.type = PD_PREFER_BUCK,
};
static void update_plt_suspend(void)
{
pd_pref_config.plt_mw = 0;
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, update_plt_suspend, HOOK_PRIO_DEFAULT);
static void update_plt_resume(void)
{
pd_pref_config.plt_mw = SYSTEM_PLT_MW;
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, update_plt_resume, HOOK_PRIO_DEFAULT);
#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ##args)
@ -170,90 +137,6 @@ static int command_jc(int argc, const char **argv)
}
DECLARE_CONSOLE_COMMAND(jc, command_jc, "", "mt6370 junction temp");
/*
* b/143318064: A workwround for mt6370 bad buck efficiency.
* If the delta of VBUS and VBAT(on krane, desired voltage 4.4V) is too small
* (i.e. < 500mV), the buck throughput will be bounded, and causing that we
* can't drain 5V/3A when battery SoC above around 40%.
* This function watches battery current. If we see battery current drops after
* switching from high voltage to 5V (This will happen if we enable
* CONFIG_USB_PD_PREFER_MV and set prefer votage to 5V), the charger will lost
* power due to the inefficiency (e.g. switch from 9V/1.67A = 15W to 5V/3A,
* but mt6370 would only sink less than 5V/2.4A = 12W), and we will request a
* higher voltage PDO to prevent a slow charging time.
*/
static void battery_desired_curr_dynamic(struct charge_state_data *curr)
{
static int prev_stable_current = CHARGE_CURRENT_UNINITIALIZED;
static int prev_supply_voltage;
int supply_voltage;
int stable_current;
int delta_current;
if (curr->state != ST_CHARGE) {
prev_supply_voltage = 0;
prev_stable_current = CHARGE_CURRENT_UNINITIALIZED;
/*
* Always force higher voltage on first PD negotiation.
* When desired power is around 15W ~ 11W, PD would pick
* 5V/3A initially, but mt6370 can't drain that much, and
* causes a low charging efficiency.
*/
pd_pref_config.mv = PREVENT_CURRENT_DROP_MV;
return;
}
supply_voltage = charge_manager_get_charger_voltage();
stable_current = charge_get_stable_current();
if (!charge_is_current_stable())
return;
if (!prev_supply_voltage)
goto update_charge;
delta_current = prev_stable_current - stable_current;
if (curr->batt.state_of_charge >= pd_pref_config.cv &&
supply_voltage == DEFAULT_PREFER_MV &&
prev_supply_voltage > supply_voltage &&
delta_current > STABLE_CURRENT_DELTA) {
/* Raise perfer voltage above 5000mV */
pd_pref_config.mv = PREVENT_CURRENT_DROP_MV;
/*
* Delay stable current evaluation for 5 mins if we see a
* current drop. It's a reasonable waiting time since that
* the battery desired current can't catch the gap that fast
* in the period.
*/
charge_reset_stable_current_us(5 * MINUTE);
/* Rewrite the stable current to re-evalute desired watt */
charge_set_stable_current(prev_stable_current);
/*
* do not alter current by thermal if we just raising PD
* voltage
*/
thermal_wait_until.val = get_time().val + (10 * SECOND);
} else {
pd_pref_config.mv = DEFAULT_PREFER_MV;
/*
* If the power supply is plugged while battery full,
* the stable_current will always be 0 such that we are unable
* to switch to 5V. We force evaluating PDO to switch to 5V.
*/
if (prev_supply_voltage == supply_voltage && !stable_current &&
!prev_stable_current &&
supply_voltage != DEFAULT_PREFER_MV &&
charge_manager_get_supplier() == CHARGE_SUPPLIER_PD)
pd_set_new_power_request(
charge_manager_get_active_charge_port());
}
update_charge:
prev_supply_voltage = supply_voltage;
prev_stable_current = stable_current;
}
#ifdef CONFIG_BATTERY_SMART
static void charge_enable_eoc_and_te(void)
{
@ -268,8 +151,6 @@ void mt6370_charger_profile_override(struct charge_state_data *curr)
static int previous_chg_limit_mv;
int chg_limit_mv = pd_get_max_voltage();
battery_desired_curr_dynamic(curr);
battery_thermal_control(curr);
#ifdef CONFIG_BATTERY_SMART

View File

@ -0,0 +1,2 @@
# MT8188 / Geralt SCP
fshao@chromium.org

View File

@ -26,10 +26,9 @@ struct mpu_entry mpu_entries[NR_MPU_ENTRIES] = {
/* For SCP sys */
{ 0x70000000, 0x80000000, MPU_ATTR_W | MPU_ATTR_R },
#ifdef CHIP_VARIANT_MT8195
{ 0x10000000, 0x11400000, MPU_ATTR_C | MPU_ATTR_W | MPU_ATTR_R },
{ CONFIG_PANIC_DRAM_BASE,
CONFIG_PANIC_DRAM_BASE + CONFIG_PANIC_DRAM_SIZE,
MPU_ATTR_W | MPU_ATTR_R },
{ CONFIG_DRAM_BASE, DRAM_NC_BASE,
MPU_ATTR_C | MPU_ATTR_W | MPU_ATTR_R },
{ DRAM_NC_BASE, KERNEL_BASE + KERNEL_SIZE, MPU_ATTR_W | MPU_ATTR_R },
#else
{ 0x10000000, 0x11400000, MPU_ATTR_W | MPU_ATTR_R },
#endif

View File

@ -15,10 +15,6 @@
#define CONFIG_POWER_TRACK_HOST_SLEEP_STATE
#define CONFIG_UART_CONSOLE 0
#ifdef CHIP_VARIANT_MT8195
#define CONFIG_PANIC_CONSOLE_OUTPUT
#endif
/* IPI configs */
#define CONFIG_IPC_SHARED_OBJ_BUF_SIZE 288
#define CONFIG_IPC_SHARED_OBJ_ADDR \
@ -49,22 +45,75 @@
#define SCP_IPI_NS_SERVICE 0xFF
/* Access DRAM through cached access */
/*
* (1) DRAM cacheable region
* (2) DRAM non-cacheable region
* (3) Panic data region
* (4) Kernel DMA allocable region
* (5) DRAM end address
*
* base (size)
* ---+-------------------- (1) CONFIG_DRAM_BASE (CONFIG_DRAM_SIZE)
* C | DRAM .text, .rodata
* | DRAM .data LMA
* | DRAM .bss, .data
* ---+-------------------- (2) DRAM_NC_BASE (DRAM_NC_SIZE)
* NC | .dramnc
* +-------------------- (3) CONFIG_PANIC_DRAM_BASE (CONFIG_PANIC_DRAM_SIZE)
* | Panic Data
* +-------------------- (4) KERNEL_BASE (KERNEL_SIZE)
* | Kernel DMA allocable
* | for MDP, etc.
* ---+-------------------- (5) CONFIG_DRAM_SIZE + DRAM_TOTAL_SIZE (NA)
*
* base size
* MT8192
* (1) 0x10000000 0x500000
* (2) 0x10500000 0
* (3) 0x10500000 0
* (4) 0x10500000 0xF00000
* (5) 0x11400000
* MT8195
* (1) 0x10000000 0x4FF000
* (2) 0x104FF000 0
* (3) 0x104FF000 0x1000
* (4) 0x10500000 0xF00000
* (5) 0x11400000
*/
/* size of (1) */
#define CONFIG_DRAM_SIZE \
(DRAM_TOTAL_SIZE - CONFIG_PANIC_DRAM_SIZE - DRAM_NC_SIZE - KERNEL_SIZE)
/* base of (2) */
#define DRAM_NC_BASE (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)
/* base of (3) */
#define CONFIG_PANIC_DRAM_BASE (DRAM_NC_BASE + DRAM_NC_SIZE)
/* base of (4) */
#define KERNEL_BASE (CONFIG_PANIC_DRAM_BASE + CONFIG_PANIC_DRAM_SIZE)
#if defined(CHIP_VARIANT_MT8192)
/* base of (1) */
#define CONFIG_DRAM_BASE 0x10000000
/* Shared memory address in AP physical address space. */
#define CONFIG_DRAM_BASE_LOAD 0x50000000
#define CONFIG_DRAM_SIZE 0x01400000 /* 20 MB */
/* size of (2) */
#define DRAM_NC_SIZE 0
/* size of (3) */
#define CONFIG_PANIC_DRAM_SIZE 0
/* size of (4) */
#define KERNEL_SIZE 0xF00000
/* DRAM total size for (5) */
#define DRAM_TOTAL_SIZE 0x01400000 /* 20 MB */
#endif /* CHIP_VARIANT_MT8192 */
/* Add some space (0x100) before panic for jump data */
#define CONFIG_PANIC_DRAM_BASE (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)
#if defined(CHIP_VARIANT_MT8195)
#define CONFIG_DRAM_BASE 0x10000000
#define CONFIG_DRAM_BASE_LOAD 0x50000000
#define DRAM_NC_SIZE 0
#define CONFIG_PANIC_DRAM_SIZE 0x00001000 /* 4K */
#define CONFIG_PANIC_BASE_OFFSET 0x100 /* reserved for jump data */
#ifdef CHIP_VARIANT_MT8195
#define CONFIG_PANIC_DATA_BASE \
(CONFIG_PANIC_DRAM_BASE + CONFIG_PANIC_BASE_OFFSET)
#endif
#define KERNEL_SIZE 0xF00000
#define DRAM_TOTAL_SIZE 0x01400000 /* 20 MB */
#endif /* CHIP_VARIANT_MT8195 */
/* MPU settings */
#define NR_MPU_ENTRIES 16

View File

@ -210,6 +210,11 @@ __override uint32_t board_override_feature_flags0(uint32_t flags0)
return flags0;
}
__overridable void zork_board_hibernate(void)
{
/* Stub for model specific hibernate callback */
}
void board_hibernate(void)
{
int port;
@ -227,6 +232,8 @@ void board_hibernate(void)
/* Give PD task and PPC chip time to get to 5V */
msleep(900);
}
zork_board_hibernate();
}
__overridable int check_hdmi_hpd_status(void)

View File

@ -337,6 +337,14 @@ def all_targets():
core = "cortex-m",
zephyr = False,
)
ec_target(
name = "bujia",
baseboard = "brask",
board = "bujia",
chip = "npcx",
core = "cortex-m",
zephyr = False,
)
ec_target(
name = "burnet",
baseboard = "kukui",
@ -941,6 +949,10 @@ def all_targets():
name = "gothrax",
board = "gothrax",
)
ec_target(
name = "greenbayupoc",
board = "greenbayupoc",
)
ec_target(
name = "grunt",
baseboard = "grunt",
@ -1612,6 +1624,14 @@ def all_targets():
board = "nokris",
extra_modules = ["cmsis"],
)
ec_target(
name = "nova",
baseboard = "brask",
board = "nova",
chip = "npcx",
core = "cortex-m",
zephyr = False,
)
ec_target(
name = "npcx7",
board = "npcx7",
@ -2350,6 +2370,10 @@ def all_targets():
core = "cortex-m",
zephyr = False,
)
ec_target(
name = "wugtrio",
board = "wugtrio",
)
ec_target(
name = "xivu",
board = "xivu",

555
board/bujia/board.c Normal file
View File

@ -0,0 +1,555 @@
/* Copyright 2024 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 "cec.h"
#include "charge_manager.h"
#include "charge_state.h"
#include "common.h"
#include "compile_time_macros.h"
#include "console.h"
#include "cros_board_info.h"
#include "driver/cec/bitbang.h"
#include "driver/tcpm/tcpci.h"
#include "fw_config.h"
#include "gpio.h"
#include "gpio_signal.h"
#include "hooks.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);
/******************************************************************************/
/* Power on Lisbon through CEC */
struct cec_offline_policy lisbon_cec_policy[] = {
{
.command = CEC_MSG_REPORT_PHYSICAL_ADDRESS,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_DEVICE_VENDOR_ID,
.action = CEC_ACTION_POWER_BUTTON,
},
/* Terminator */
{ 0 },
};
/* CEC ports */
static const struct bitbang_cec_config bitbang_cec_config = {
.gpio_out = GPIO_HDMIB_CEC_OUT,
.gpio_in = GPIO_HDMIB_CEC_IN,
.gpio_pull_up = GPIO_HDMIB_CEC_PULL_UP,
};
const struct cec_config_t cec_config[] = {
[CEC_PORT_0] = {
.drv = &bitbang_cec_drv,
.drv_config = &bitbang_cec_config,
.offline_policy = lisbon_cec_policy,
},
};
BUILD_ASSERT(ARRAY_SIZE(cec_config) == CEC_PORT_COUNT);
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:
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_HDMIA_CONN_OC_ODL))
base_5v_power_s5 += PWR_S5_HDMI;
if (!gpio_get_level(GPIO_HDMIB_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_HDMIA_CONN_OC_ODL);
gpio_enable_interrupt(GPIO_HDMIB_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_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;
}
/*
* 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_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);
}
hook_call_deferred(&power_monitor_data, delay);
}

160
board/bujia/board.h Normal file
View File

@ -0,0 +1,160 @@
/* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Lisbon board configuration */
#ifndef __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
#include "compile_time_macros.h"
/* Baseboard features */
#include "baseboard.h"
/* Barrel Jack */
#define DEDICATED_CHARGE_PORT 1
/* HDMI CEC */
#define CONFIG_CEC
#define CONFIG_CEC_BITBANG
/* USB Type A Features */
#define USB_PORT_COUNT 4
#define CONFIG_USB_PORT_POWER_DUMB
#define CONFIG_USBC_RETIMER_PS8811
/* USB Type C and USB PD defines */
#define CONFIG_USB_PD_PPC
#define CONFIG_USB_PD_TCPM_RT1715
#define CONFIG_USBC_RETIMER_PS8818
#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_USB_C0_TCPC NPCX_I2C_PORT1_0
#define I2C_PORT_USB_C0_PPC_BC12 NPCX_I2C_PORT2_0
#define I2C_PORT_USB_C0_MUX NPCX_I2C_PORT3_0
#define I2C_PORT_USB_A2_A3_RT NPCX_I2C_PORT6_1
#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_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
#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_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 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 };
enum cec_port { CEC_PORT_0, CEC_PORT_COUNT };
extern void adp_connect_interrupt(enum gpio_signal signal);
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */

22
board/bujia/build.mk Normal file
View File

@ -0,0 +1,22 @@
# -*- makefile -*-
# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Lisbon 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

23
board/bujia/ec.tasklist Normal file
View File

@ -0,0 +1,23 @@
/* Copyright 2024 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(USB_CHG_P0, 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_INT_C0, pd_interrupt_handler_task, 0, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CEC, cec_task, NULL, LARGER_TASK_STACK_SIZE)

50
board/bujia/fans.c Normal file
View File

@ -0,0 +1,50 @@
/* Copyright 2024 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 = 2000,
.rpm_start = 2000,
.rpm_max = 4700,
};
const struct fan_t fans[FAN_CH_COUNT] = {
[FAN_CH_0] = {
.conf = &fan_conf_0,
.rpm = &fan_rpm_0,
},
};

66
board/bujia/fw_config.c Normal file
View File

@ -0,0 +1,66 @@
/* Copyright 2024 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 lisbon_cbi_fw_config fw_config;
BUILD_ASSERT(sizeof(fw_config) == sizeof(uint32_t));
/*
* FW_CONFIG defaults for lisbon if the CBI.FW_CONFIG data is not
* initialized.
*/
static const union lisbon_cbi_fw_config fw_config_defaults = {
.bj_power = BJ_65W,
.storage = EMMC,
.fvm_support = FVM_NO,
};
/*
* Barrel-jack power adapter ratings.
*/
static const struct {
int voltage;
int current;
} bj_power[] = {
[BJ_65W] = { /* 0 - 65W (also default) */
.voltage = 19000,
.current = 3420
},
[BJ_90W] = { /* 1 - 90W */
.voltage = 19000,
.current = 4740
}
};
/****************************************************************************
* Lisbon 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;
}

44
board/bujia/fw_config.h Normal file
View File

@ -0,0 +1,44 @@
/* Copyright 2024 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_LISBON_FW_CONFIG_H_
#define __BOARD_LISBON_FW_CONFIG_H_
#include <stdint.h>
/****************************************************************************
* CBI FW_CONFIG layout for Lisbon board.
*
* Source of truth is the project/brask/lisbon/config.star configuration file.
*/
enum ec_cfg_bj_power { BJ_65W = 0, BJ_90W = 1 };
enum ec_cfg_storage { EMMC = 0, SSD = 1 };
enum ec_cfg_fvm_support { FVM_NO = 0, FVM_YES = 1 };
union lisbon_cbi_fw_config {
struct {
uint32_t bj_power : 1;
uint32_t storage : 1;
uint32_t fvm_support : 1;
uint32_t reserved_1 : 29;
};
uint32_t raw_value;
};
/**
* Read the cached FW_CONFIG. Guaranteed to have valid values.
*
* @return the FW_CONFIG for the board.
*/
union lisbon_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_LISBON_FW_CONFIG_H_ */

162
board/bujia/gpio.inc Normal file
View File

@ -0,0 +1,162 @@
/* -*- mode:c -*-
*
* Copyright 2024 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(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(HDMIA_CONN_OC_ODL, PIN(5, 0), GPIO_INPUT | GPIO_INT_BOTH, port_ocp_interrupt)
GPIO_INT(HDMIB_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)
/* 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)
/* 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)
/* HDMI CEC */
/* TODO(b/197474873): Enable HDMI CEC */
GPIO(HDMIB_CEC_IN, PIN(4, 0), GPIO_INPUT)
GPIO(HDMIB_CEC_OUT, PIN(D, 3), GPIO_OUT_HIGH | GPIO_OPEN_DRAIN)
GPIO(HDMIB_CEC_PULL_UP, PIN(C, 2), GPIO_OUT_HIGH)
GPIO(HDMIA_CEC_IN, PIN(A, 7), GPIO_INPUT)
GPIO(HDMIA_CEC_OUT, PIN(F, 2), GPIO_OUT_HIGH | GPIO_OPEN_DRAIN)
GPIO(HDMIA_CEC_PULL_UP, PIN(F, 3), GPIO_OUT_HIGH)
/* I2C SCL/SDA */
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_C0_C2_PPC_BC_SCL, PIN(9, 2), GPIO_INPUT)
GPIO(EC_I2C_USB_C0_C2_PPC_BC_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_A2_A3_SCL, PIN(E, 4), GPIO_INPUT)
GPIO(EC_I2C_USB_A2_A3_SDA, PIN(E, 3), 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_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_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_FRS_EN, PIN(9, 4), GPIO_OUT_LOW)
GPIO(USB_C0_HPD, PIN(0, 4), GPIO_OUT_LOW)
GPIO(USB_C0_OC_ODL, PIN(7, 0), 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(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 */
/* 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 */
/* NC pins, enable internal pull-down to avoid floating state. */
GPIO(GPIO02_NC, PIN(0, 2), GPIO_INPUT | GPIO_PULL_DOWN)
/* 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(A, 0))
UNUSED(PIN(A, 2))
UNUSED(PIN(A, 3))
UNUSED(PIN(B, 1))
UNUSED(PIN(B, 5))
UNUSED(PIN(B, 4))
UNUSED(PIN(D, 2))
UNUSED(PIN(D, 4))
UNUSED(PIN(F, 5))
UNUSED(PIN(0, 5))
UNUSED(PIN(1, 1))
UNUSED(PIN(1, 0))
UNUSED(PIN(1, 7))
UNUSED(PIN(1, 6))
UNUSED(PIN(2, 5))
UNUSED(PIN(3, 3))
UNUSED(PIN(3, 6))
UNUSED(PIN(4, 1))
UNUSED(PIN(8, 3))
UNUSED(PIN(9, 3))
UNUSED(PIN(9, 5))
UNUSED(PIN(9, 6))

53
board/bujia/i2c.c Normal file
View File

@ -0,0 +1,53 @@
/* Copyright 2024 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[] = {
{
/* I2C1 */
.name = "tcpc0",
.port = I2C_PORT_USB_C0_TCPC,
.kbps = 1000,
.scl = GPIO_EC_I2C_USB_C0_C2_TCPC_SCL,
.sda = GPIO_EC_I2C_USB_C0_C2_TCPC_SDA,
},
{
/* I2C2 */
.name = "ppc, bc1.2 c0",
.port = I2C_PORT_USB_C0_PPC_BC12,
.kbps = 1000,
.scl = GPIO_EC_I2C_USB_C0_C2_PPC_BC_SCL,
.sda = GPIO_EC_I2C_USB_C0_C2_PPC_BC_SDA,
},
{
/* I2C3 */
.name = "retimer0",
.port = I2C_PORT_USB_C0_MUX,
.kbps = 1000,
.scl = GPIO_EC_I2C_USB_C0_C2_RT_SCL,
.sda = GPIO_EC_I2C_USB_C0_C2_RT_SDA,
},
{
/* I2C6 */
.name = "usba2_retimer, usba3_retimer",
.port = I2C_PORT_USB_A2_A3_RT,
.kbps = 1000,
.scl = GPIO_EC_I2C_USB_A2_A3_SCL,
.sda = GPIO_EC_I2C_USB_A2_A3_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);

260
board/bujia/led.c Normal file
View File

@ -0,0 +1,260 @@
/* Copyright 2024 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 Lisbon.
* 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);
}

33
board/bujia/pwm.c Normal file
View File

@ -0,0 +1,33 @@
/* Copyright 2024 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)
{
pwm_enable(PWM_CH_FAN, 1);
pwm_enable(PWM_CH_LED_RED, 1);
pwm_enable(PWM_CH_LED_GREEN, 1);
}
DECLARE_HOOK(HOOK_INIT, board_pwm_init, HOOK_PRIO_DEFAULT);

109
board/bujia/sensors.c Normal file
View File

@ -0,0 +1,109 @@
/* Copyright 2024 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)
*/
static const struct ec_thermal_config 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(40),
.temp_fan_max = C_TO_K(80),
};
/*
* 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);

162
board/bujia/usbc_config.c Normal file
View File

@ -0,0 +1,162 @@
/* Copyright 2024 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/ps8818_public.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 "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,
},
};
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_PPC_BC12,
.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 int board_c0_ps8818_mux_set(const struct usb_mux *me,
mux_state_t mux_state)
{
if (mux_state & USB_PD_MUX_DP_ENABLED)
gpio_set_level(GPIO_USB_C0_HPD, 1);
else
gpio_set_level(GPIO_USB_C0_HPD, 0);
return 0;
}
const struct usb_mux_chain usb_muxes[] = {
[USBC_PORT_C0] = {
.mux = &(const struct usb_mux) {
.usb_port = USBC_PORT_C0,
.driver = &ps8818_usb_retimer_driver,
.i2c_port = I2C_PORT_USB_C0_MUX,
.i2c_addr_flags = PS8818_I2C_ADDR3_FLAGS,
.board_set = &board_c0_ps8818_mux_set,
},
.next = &usbc0_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_PPC_BC12,
.i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
},
};
BUILD_ASSERT(ARRAY_SIZE(pi3usb9201_bc12_chips) == USBC_PORT_COUNT);
void board_reset_pd_mcu(void)
{
/* Using RT1716, no reset available for 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);
/* Enable TCPC interrupts. */
gpio_enable_interrupt(GPIO_USB_C0_C2_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;
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;
return 0;
}
void tcpc_alert_event(enum gpio_signal signal)
{
schedule_deferred_pd_interrupt(USBC_PORT_C0);
}
void bc12_interrupt(enum gpio_signal signal)
{
usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
}
void ppc_interrupt(enum gpio_signal signal)
{
syv682x_interrupt(USBC_PORT_C0);
}
void retimer_interrupt(enum gpio_signal signal)
{
/*
* TODO(b/179513527): add USB-C support
*/
}

15
board/bujia/usbc_config.h Normal file
View File

@ -0,0 +1,15 @@
/* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Lisbon board-specific USB-C configuration */
#ifndef __CROS_EC_USBC_CONFIG_H
#define __CROS_EC_USBC_CONFIG_H
#define CONFIG_USB_PD_PORT_MAX_COUNT 1
enum usbc_port { USBC_PORT_C0 = 0, USBC_PORT_COUNT };
#endif /* __CROS_EC_USBC_CONFIG_H */

View File

@ -0,0 +1,3 @@
<!-- Add VIF field overrides here. See genvif.c and the Vendor Info File
Definition from the USB-IF.
-->

2
board/cherry_scp/OWNERS Normal file
View File

@ -0,0 +1,2 @@
# MT8188 / Geralt SCP
fshao@chromium.org

View File

@ -9,10 +9,10 @@
#define __CROS_EC_BOARD_H
/*
* By default, enable all console messages except Events:
* By default, enable all console messages excepted HC, ACPI and event:
* The sensor stack is generating a lot of activity.
*/
#define CC_DEFAULT (CC_ALL & ~CC_MASK(CC_EVENTS))
#define CC_DEFAULT (CC_ALL & ~(CC_MASK(CC_EVENTS) | CC_MASK(CC_LPC)))
#undef CONFIG_HOSTCMD_DEBUG_MODE
#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_OFF

View File

@ -79,6 +79,28 @@ const int usb_port_enable[USB_PORT_COUNT] = {
GPIO_EN_USB_A3_VBUS, GPIO_EN_USB_A4_VBUS,
};
/* Power on Dexi through CEC */
struct cec_offline_policy dexi_cec_policy[] = {
{
.command = CEC_MSG_ACTIVE_SOURCE,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_TEXT_VIEW_ON,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_IMAGE_VIEW_ON,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_SET_STREAM_PATH,
.action = CEC_ACTION_POWER_BUTTON,
},
/* Terminator */
{ 0 },
};
/* CEC ports */
static const struct bitbang_cec_config bitbang_cec_config = {
.gpio_out = GPIO_HDMI2_CEC,
@ -92,13 +114,13 @@ const struct cec_config_t cec_config[] = {
[CEC_PORT_0] = {
.drv = &it83xx_cec_drv,
.drv_config = NULL,
.offline_policy = cec_default_policy,
.offline_policy = dexi_cec_policy,
},
/* HDMI2 */
[CEC_PORT_1] = {
.drv = &bitbang_cec_drv,
.drv_config = &bitbang_cec_config,
.offline_policy = cec_default_policy,
.offline_policy = dexi_cec_policy,
},
};
BUILD_ASSERT(ARRAY_SIZE(cec_config) == CEC_PORT_COUNT);

View File

@ -79,6 +79,28 @@ const int usb_port_enable[USB_PORT_COUNT] = {
GPIO_EN_USB_A3_VBUS, GPIO_EN_USB_A4_VBUS,
};
/* Power on Dita through CEC */
struct cec_offline_policy dita_cec_policy[] = {
{
.command = CEC_MSG_ACTIVE_SOURCE,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_TEXT_VIEW_ON,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_IMAGE_VIEW_ON,
.action = CEC_ACTION_POWER_BUTTON,
},
{
.command = CEC_MSG_SET_STREAM_PATH,
.action = CEC_ACTION_POWER_BUTTON,
},
/* Terminator */
{ 0 },
};
/* CEC ports */
static const struct bitbang_cec_config bitbang_cec_config = {
.gpio_out = GPIO_HDMI2_CEC,
@ -92,13 +114,13 @@ const struct cec_config_t cec_config[] = {
[CEC_PORT_0] = {
.drv = &it83xx_cec_drv,
.drv_config = NULL,
.offline_policy = cec_default_policy,
.offline_policy = dita_cec_policy,
},
/* HDMI2 */
[CEC_PORT_1] = {
.drv = &bitbang_cec_drv,
.drv_config = &bitbang_cec_config,
.offline_policy = cec_default_policy,
.offline_policy = dita_cec_policy,
},
};
BUILD_ASSERT(ARRAY_SIZE(cec_config) == CEC_PORT_COUNT);

View File

@ -73,12 +73,12 @@ BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
#define THERMAL_MEMORY \
{ \
.temp_host = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(80), \
[EC_TEMP_THRESH_HALT] = C_TO_K(90), \
}, \
.temp_host_release = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(70), \
[EC_TEMP_THRESH_HALT] = C_TO_K(80), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
}, \
.temp_fan_off = 0, \
.temp_fan_max = 0, \
@ -89,12 +89,12 @@ __maybe_unused static const struct ec_thermal_config thermal_memory =
#define THERMAL_SOC \
{ \
.temp_host = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(80), \
[EC_TEMP_THRESH_HALT] = C_TO_K(90), \
}, \
.temp_host_release = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(70), \
[EC_TEMP_THRESH_HALT] = C_TO_K(80), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
}, \
.temp_fan_off = 0, \
.temp_fan_max = 0, \
@ -104,12 +104,12 @@ __maybe_unused static const struct ec_thermal_config thermal_soc = THERMAL_SOC;
#define THERMAL_AMBIENT \
{ \
.temp_host = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(80), \
[EC_TEMP_THRESH_HALT] = C_TO_K(90), \
}, \
.temp_host_release = { \
[EC_TEMP_THRESH_HIGH] = C_TO_K(70), \
[EC_TEMP_THRESH_HALT] = C_TO_K(80), \
[EC_TEMP_THRESH_HIGH] = C_TO_K(75), \
[EC_TEMP_THRESH_HALT] = C_TO_K(85), \
}, \
.temp_fan_off = 0, \
.temp_fan_max = 0, \

View File

@ -215,6 +215,22 @@ static void board_init(void)
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
static void usart_reinit(struct usart_config const *usart)
{
usart_set_parity(usart, 0);
usart_set_baud(usart, 115200);
usart_set_break(usart, false);
}
static void usart_reinit_all(void)
{
usart_reinit(&usart2);
usart_reinit(&usart3);
usart_reinit(&usart4);
usart_reinit(&usart5);
}
DECLARE_HOOK(HOOK_REINIT, usart_reinit_all, HOOK_PRIO_DEFAULT);
static int command_reinit(int argc, const char **argv)
{
/* Let every module know to re-initialize to power-on state. */

View File

@ -173,6 +173,38 @@ static bool jtag_enabled = false;
static uint16_t jtag_half_period_count =
CPU_CLOCK / DEFAULT_JTAG_CLOCK_HZ / 2 - OVERHEAD_CLOCK_CYCLES;
void queue_blocking_add(struct queue const *q, const void *src, size_t count)
{
while (true) {
size_t progress = queue_add_units(q, src, count);
src += progress;
if (progress >= count)
return;
count -= progress;
/*
* Wait for queue consumer to wake up this task, when there is
* more room in the queue.
*/
task_wait_event(0);
}
}
void queue_blocking_remove(struct queue const *q, void *dest, size_t count)
{
while (true) {
size_t progress = queue_remove_units(q, dest, count);
dest += progress;
if (progress >= count)
return;
count -= progress;
/*
* Wait for queue consumer to wake up this task, when there is
* more data in the queue.
*/
task_wait_event(0);
}
}
/*
* Implementation of handler routines for each CMSIS-DAP command.
*/

View File

@ -9,6 +9,15 @@ extern struct queue const cmsis_dap_rx_queue;
extern uint8_t rx_buffer[256];
extern uint8_t tx_buffer[256];
/*
* Routines to be used in the CMSIS-DAP task to add/remove a possibly large
* number of bytes from the USB queues. These functions can block waiting for
* the host computer, and will not return until the given number of bytes has
* been transferred.
*/
void queue_blocking_add(struct queue const *q, const void *src, size_t count);
void queue_blocking_remove(struct queue const *q, void *dest, size_t count);
/*
* Declaration of handlers of CMSIS-DAP vendor extension commands, implemented
* in other files besides cmsis-dap.c .

View File

@ -1497,42 +1497,6 @@ static void led_tick(void)
}
DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);
size_t queue_add_units(struct queue const *q, const void *src, size_t count);
static void queue_blocking_add(struct queue const *q, const void *src,
size_t count)
{
while (true) {
size_t progress = queue_add_units(q, src, count);
src += progress;
if (progress >= count)
return;
count -= progress;
/*
* Wait for queue consumer to wake up this task, when there is
* more room in the queue.
*/
task_wait_event(0);
}
}
static void queue_blocking_remove(struct queue const *q, void *dest,
size_t count)
{
while (true) {
size_t progress = queue_remove_units(q, dest, count);
dest += progress;
if (progress >= count)
return;
count -= progress;
/*
* Wait for queue consumer to wake up this task, when there is
* more data in the queue.
*/
task_wait_event(0);
}
}
/*
* Declaration of header used in the binary USB protocol (Google HyperDebug
* extensions to CMSIS-DAP protocol.)

View File

@ -28,8 +28,10 @@
* extension" commands.
*
* Vendor extension 0x81 is used when HyperDebug is I2C host, and the header
* byte is immediately followed by a request of the same format as described
* in include/usb_i2c.h.
* byte is immediately followed by a request of the same format as described in
* include/usb_i2c.h, with the extension that the otherwise unused high bit of
* the addr byte is used to request that a STOP condition should not be
* generated.
*
* Vendor extension 0x82 is used when HyperDebug is I2C device, and encodes a
* number of request sub-types.
@ -137,7 +139,7 @@ struct i2c_state_t {
*/
volatile size_t prepared_read_len;
volatile bool prepared_read_sticky;
uint8_t prepared_read_data[256];
uint8_t prepared_read_data[1024];
/*
* If non-zero, I2C host is currently waiting in READ transfer, with
@ -171,6 +173,12 @@ struct i2c_state_t {
const uint8_t I2C_REQ_GET_TRANSCRIPT = 0x00;
const uint8_t I2C_REQ_PREPARE_READ = 0x01;
/*
* Bitfield of the address byte, indicating request to not generate STOP
* condition.
*/
const uint8_t ADDR_NOSTOP = 0x80;
/* Bitfield, Prepare read data request, I2C port field */
const uint8_t PREPARE_READ_FLAG_STICKY = BIT(7);
const uint8_t PREPARE_READ_PORT_MASK = 0x0F;
@ -260,6 +268,7 @@ static void usb_i2c_execute(unsigned int expected_size)
/* Payload is ready to execute. */
int portindex = rx_buffer[1] & 0xf;
uint16_t addr_flags = rx_buffer[2] & 0x7f;
bool no_stop = rx_buffer[2] & ADDR_NOSTOP;
int write_count = ((rx_buffer[1] << 4) & 0xf00) | rx_buffer[3];
int read_count = rx_buffer[4];
int offset = 0; /* Offset for extended reading header. */
@ -287,9 +296,13 @@ static void usb_i2c_execute(unsigned int expected_size)
} else if (portindex >= i2c_ports_used) {
i2c_status = USB_I2C_PORT_INVALID;
} else {
int ret = i2c_xfer(i2c_ports[portindex].port, addr_flags,
rx_buffer + 5 + offset, write_count,
rx_buffer + 5, read_count);
i2c_lock(i2c_ports[portindex].port, 1);
int ret = i2c_xfer_unlocked(
i2c_ports[portindex].port, addr_flags,
rx_buffer + 5 + offset, write_count, rx_buffer + 5,
read_count,
I2C_XFER_START | (no_stop ? 0 : I2C_XFER_STOP));
i2c_lock(i2c_ports[portindex].port, 0);
i2c_status = usb_i2c_map_error(ret);
}
rx_buffer[1] = i2c_status & 0xFF;
@ -387,20 +400,21 @@ void dap_goog_i2c_device(size_t peek_c)
status->transcript_size = head - state->tail;
queue_add_units(&cmsis_dap_tx_queue, rx_buffer,
1 + sizeof(*status));
queue_add_units(&cmsis_dap_tx_queue, state->tail,
status->transcript_size);
queue_blocking_add(&cmsis_dap_tx_queue, state->tail,
status->transcript_size);
} else {
/* Data wraps around */
status->transcript_size =
head - state->tail + sizeof(state->data_buffer);
queue_add_units(&cmsis_dap_tx_queue, rx_buffer,
1 + sizeof(*status));
queue_add_units(&cmsis_dap_tx_queue, state->tail,
state->data_buffer +
sizeof(state->data_buffer) -
state->tail);
queue_add_units(&cmsis_dap_tx_queue, state->data_buffer,
state->head - state->data_buffer);
queue_blocking_add(&cmsis_dap_tx_queue, state->tail,
state->data_buffer +
sizeof(state->data_buffer) -
state->tail);
queue_blocking_add(&cmsis_dap_tx_queue,
state->data_buffer,
state->head - state->data_buffer);
}
state->tail = head;
return;
@ -412,9 +426,10 @@ void dap_goog_i2c_device(size_t peek_c)
uint16_t len = rx_buffer[3] + (rx_buffer[4] << 8);
/* TODO Check that len does not exceed size of
* prepared_data_data */
queue_remove_units(&cmsis_dap_rx_queue, rx_buffer, 5);
queue_remove_units(&cmsis_dap_rx_queue,
state->prepared_read_data, len);
queue_blocking_remove(&cmsis_dap_rx_queue, rx_buffer, 5);
queue_blocking_remove(&cmsis_dap_rx_queue,
state->prepared_read_data, len);
queue_add_unit(&cmsis_dap_tx_queue, rx_buffer);
state->prepared_read_len = len;
state->prepared_read_sticky = sticky;

View File

@ -45,6 +45,7 @@ test-list-y=\
mpu \
mutex \
mutex_trylock \
mutex_recursive \
panic \
panic_data \
pingpong \

566
board/nova/board.c Normal file
View File

@ -0,0 +1,566 @@
/* Copyright 2024 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 "cec.h"
#include "cec_bitbang_chip.h"
#include "charge_manager.h"
#include "charge_state.h"
#include "common.h"
#include "compile_time_macros.h"
#include "console.h"
#include "cros_board_info.h"
#include "driver/cec/bitbang.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 "pse_ltc4291.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);
/*
* The LTC4291 is a power over ethernet (PoE) power sourcing equipment (PSE)
* controller.
*
* Port 1: 100W
* Port 2-4: 15W
*/
const int pse_port_hpmd[4] = {
LTC4291_HPMD_MAX,
LTC4291_HPMD_MIN,
LTC4291_HPMD_MIN,
LTC4291_HPMD_MIN,
};
/******************************************************************************/
/* 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);
/******************************************************************************/
/* CEC ports */
static const struct bitbang_cec_config bitbang_cec_config_b = {
.gpio_out = GPIO_HDMIB_CEC_OUT,
.gpio_in = GPIO_HDMIB_CEC_IN,
.gpio_pull_up = GPIO_HDMIB_CEC_PULL_UP,
.timer = NPCX_CEC_BITBANG_TIMER_A,
};
static const struct bitbang_cec_config bitbang_cec_config_a = {
.gpio_out = GPIO_HDMIA_CEC_OUT,
.gpio_in = GPIO_HDMIA_CEC_IN,
.gpio_pull_up = GPIO_HDMIA_CEC_PULL_UP,
.timer = NPCX_CEC_BITBANG_TIMER_B,
};
const struct cec_config_t cec_config[] = {
[CEC_PORT_0] = {
.drv = &bitbang_cec_drv,
.drv_config = &bitbang_cec_config_b,
.offline_policy = NULL,
},
[CEC_PORT_1] = {
.drv = &bitbang_cec_drv,
.drv_config = &bitbang_cec_config_a,
.offline_policy = NULL,
},
};
BUILD_ASSERT(ARRAY_SIZE(cec_config) == CEC_PORT_COUNT);
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:
pd_set_power_supply_ready(port);
gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 0);
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_REAR_HIGH (5 * 1737)
#define PWR_S5_REAR_LOW (5 * 1055)
#define PWR_S5_HDMI (5 * 580)
#define PWR_S5_MAX (5 * 10000)
#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 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)) {
rear_ports++;
base_5v_power_s5 += PWR_S5_REAR_LOW;
}
if (!gpio_get_level(GPIO_USB_A1_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);
}
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 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_REAR BIT(0)
#define THROT_TYPE_C0 BIT(1)
#define THROT_TYPE_C1 BIT(2)
#define THROT_TYPE_C2 BIT(3)
#define THROT_PROCHOT BIT(4)
/*
* 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 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) {
/*
* 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;
}
}
/*
* 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);
}
hook_call_deferred(&power_monitor_data, delay);
}

195
board/nova/board.h Normal file
View File

@ -0,0 +1,195 @@
/* Copyright 2024 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 CONFIG_CEC_BITBANG
/* USB Type A Features */
#define USB_PORT_COUNT 2
#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_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 */
/* Not support typec adapter. */
/* TODO(b/293975611): Set the max PD to 0W.
*/
#define PD_OPERATING_POWER_MW CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON
#define PD_MAX_POWER_MW 0
#define PD_MAX_CURRENT_MA 0
#define PD_MAX_VOLTAGE_MV 5000
/*
* 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_USB_C0_C2_TCPC NPCX_I2C_PORT1_0
#define I2C_PORT_USB_C1_TCPC NPCX_I2C_PORT0_0
#define I2C_PORT_USB_C0_C2_PPC NPCX_I2C_PORT2_0
#define I2C_PORT_USB_C1_PPC NPCX_I2C_PORT4_1
#define I2C_PORT_USB_C0_C2_BC12 NPCX_I2C_PORT2_0
#define I2C_PORT_USB_C1_BC12 NPCX_I2C_PORT4_1
#define I2C_PORT_USB_C0_C2_MUX NPCX_I2C_PORT3_0
#define I2C_PORT_PSE NPCX_I2C_PORT5_0
#define I2C_PORT_ADB NPCX_I2C_PORT6_1
#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 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
/* PSE */
#define CONFIG_PSE_LTC4291
/*
* 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
#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_WHITE, /* 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 };
enum cec_port { CEC_PORT_0, CEC_PORT_1, CEC_PORT_COUNT };
extern void adp_connect_interrupt(enum gpio_signal signal);
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */

22
board/nova/build.mk Normal file
View File

@ -0,0 +1,22 @@
# -*- makefile -*-
# Copyright 2024 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

28
board/nova/ec.tasklist Normal file
View File

@ -0,0 +1,28 @@
/* Copyright 2024 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(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)

50
board/nova/fans.c Normal file
View File

@ -0,0 +1,50 @@
/* Copyright 2024 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 = 2400,
.rpm_start = 2400,
.rpm_max = 6000,
};
const struct fan_t fans[FAN_CH_COUNT] = {
[FAN_CH_0] = {
.conf = &fan_conf_0,
.rpm = &fan_rpm_0,
},
};

65
board/nova/fw_config.c Normal file
View File

@ -0,0 +1,65 @@
/* Copyright 2024 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;
}

41
board/nova/fw_config.h Normal file
View File

@ -0,0 +1,41 @@
/* Copyright 2024 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_ */

182
board/nova/gpio.inc Normal file
View File

@ -0,0 +1,182 @@
/* -*- mode:c -*-
*
* Copyright 2024 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(A, 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(A, 2), 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(E, 0), 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(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(5, 0), 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)
/* PSE controller */
GPIO(EC_PSE_PWM_INT, PIN(9, 6), GPIO_INPUT)
GPIO(EC_RST_LTC4291, PIN(9, 7), GPIO_OUT_HIGH)
/* TPU */
GPIO(PP3300_TPU_EN, PIN(2, 6), GPIO_OUT_HIGH)
/* Wake EC */
GPIO(WLAN_PCIE_WAKE_EC, PIN(4, 1), GPIO_INPUT)
GPIO(LAN_WAKE_EC, PIN(9, 3), GPIO_INPUT)
/* ADB Scaler signals */
GPIO(ADB_WAKEUP_EC, PIN(2, 5), GPIO_INPUT)
/* 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)
/* BarrelJack */
GPIO(EN_PPVAR_BJ_ADP_L, PIN(0, 4), 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)
/* HDMI CEC */
/* TODO(b/197474873): Enable HDMI CEC */
GPIO(HDMIA_CEC_IN, PIN(D, 3), GPIO_INPUT)
GPIO(HDMIA_CEC_OUT, PIN(1, 0), GPIO_OUT_HIGH | GPIO_OPEN_DRAIN)
GPIO(HDMIA_CEC_PULL_UP, PIN(1, 1), GPIO_OUT_HIGH)
GPIO(HDMIB_CEC_IN, PIN(4, 0), GPIO_INPUT)
GPIO(HDMIB_CEC_OUT, PIN(2, 7), GPIO_OUT_HIGH | GPIO_OPEN_DRAIN)
GPIO(HDMIB_CEC_PULL_UP, PIN(C, 2), GPIO_OUT_HIGH)
/* I2C SCL/SDA */
GPIO(EC_I2C_LTC_SCL, PIN(3, 3), GPIO_INPUT)
GPIO(EC_I2C_LTC_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_C1_TCPC_SCL, PIN(B, 5), GPIO_INPUT)
GPIO(EC_I2C_USB_C1_TCPC_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_ADB_SCL, PIN(E, 4), GPIO_INPUT)
GPIO(EC_I2C_ADB_SDA, PIN(E, 3), GPIO_INPUT)
GPIO(EC_I2C_USB_C1_PPC_SCL, PIN(F, 3), GPIO_INPUT)
GPIO(EC_I2C_USB_C1_PPC_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_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_OC_SOC_L, PIN(8, 0), GPIO_OUT_HIGH)
/* LED */
/* TODO(b/197471359): LED implementation */
GPIO(LED_WHITE_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)
/* 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, 4)) /* GPIOD4/CRSIN3 */
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(8, 6)) /* GPIO86/TXD/CR_SOUT2 */
UNUSED(PIN(1, 7)) /* KSO2/GPIO17/JTAG_TDI */
UNUSED(PIN(1, 6)) /* KSO03/GPIO16/JTAG_TDO_SWO */
UNUSED(PIN(1, 3)) /* KSO06/GPO13/GP_SEL# */
UNUSED(PIN(1, 2)) /* KSO07/GPO12/JEN# */
UNUSED(PIN(0, 7)) /* KSO10/GPIO07/P80_CLK */
UNUSED(PIN(0, 6)) /* KSO11/GPIO06/P80_DAT */
UNUSED(PIN(0, 5)) /* KSO12/GPIO05 */
UNUSED(PIN(A, 3)) /* SPIP_MOSI/GPIOA3 */
UNUSED(PIN(9, 5)) /* SPIP_MISO/GPIO95 */
UNUSED(PIN(D, 2)) /* PSL_IN1/GPIOD2 */
UNUSED(PIN(0, 2)) /* GPIO02/PSL_IN4 */

77
board/nova/i2c.c Normal file
View File

@ -0,0 +1,77 @@
/* Copyright 2024 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 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,
},
{
/* 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 */
.name = "ppc1",
.port = I2C_PORT_USB_C1_PPC,
.kbps = 400,
.scl = GPIO_EC_I2C_USB_C1_PPC_SCL,
.sda = GPIO_EC_I2C_USB_C1_PPC_SDA,
},
{
/* I2C5 */
.name = "pse",
.port = I2C_PORT_PSE,
.kbps = 400,
.scl = GPIO_EC_I2C_LTC_SCL,
.sda = GPIO_EC_I2C_LTC_SDA,
},
{
/* I2C6 */
.name = "ADB",
.port = I2C_PORT_ADB,
.kbps = 1000,
.scl = GPIO_EC_I2C_ADB_SCL,
.sda = GPIO_EC_I2C_ADB_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);

270
board/nova/led.c Normal file
View File

@ -0,0 +1,270 @@
/* Copyright 2024 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 white - active power
* White 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_WHITE,
/* Number of colors, not a color itself */
LED_COLOR_COUNT
};
static int set_color_power(enum led_color color, int duty)
{
int white = 0;
int red = 0;
if (duty < 0 || 100 < duty)
return EC_ERROR_UNKNOWN;
switch (color) {
case LED_OFF:
break;
case LED_WHITE:
white = 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 (white)
pwm_set_duty(PWM_CH_LED_WHITE, duty);
else
pwm_set_duty(PWM_CH_LED_WHITE, 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_WHITE);
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_WHITE, 100);
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, led_resume, HOOK_PRIO_DEFAULT);
void board_led_auto_control(void)
{
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 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], "white")) {
set_color(id, LED_WHITE, 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|white|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_WHITE] = 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_WHITE])
return set_color(id, LED_WHITE, brightness[EC_LED_COLOR_WHITE]);
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);
}

38
board/nova/pwm.c Normal file
View File

@ -0,0 +1,38 @@
/* Copyright 2024 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_WHITE] = { .channel = 0,
.flags = PWM_CONFIG_DSLEEP,
.freq = 2000 },
[PWM_CH_FAN] = { .channel = 5,
.flags = PWM_CONFIG_OPEN_DRAIN,
.freq = 25000 },
[PWM_CH_LED_RED] = { .channel = 2,
.flags = 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_WHITE, 1);
}
DECLARE_HOOK(HOOK_INIT, board_pwm_init, HOOK_PRIO_DEFAULT);

109
board/nova/sensors.c Normal file
View File

@ -0,0 +1,109 @@
/* Copyright 2024 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)
*/
static const struct ec_thermal_config thermal_cpu = {
.temp_host = {
[EC_TEMP_THRESH_HIGH] = C_TO_K(75),
[EC_TEMP_THRESH_HALT] = C_TO_K(85),
},
.temp_host_release = {
[EC_TEMP_THRESH_HIGH] = C_TO_K(70),
},
.temp_fan_off = C_TO_K(37),
.temp_fan_max = C_TO_K(90),
};
/*
* 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);

415
board/nova/usbc_config.c Normal file
View File

@ -0,0 +1,415 @@
/* Copyright 2024 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/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)
static bool pd_reset_on_resume;
/* 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_ADDR1_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,
},
};
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 = &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,
},
},
};
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_2_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);
/*
* delay for power-on to reset-off and min. assertion time
*/
msleep(20);
gpio_set_level(tcpc_rst, 1);
/* wait for chips to come up */
msleep(50);
}
void pd_reset_deferred(void)
{
/* Only reset port c0 */
pd_execute_hard_reset(USBC_PORT_C0);
}
DECLARE_DEFERRED(pd_reset_deferred);
void pd_enter_suspend_setting(void)
{
pd_reset_on_resume = true;
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, pd_enter_suspend_setting, HOOK_PRIO_DEFAULT);
void pd_reset_resume(void)
{
/*
* Reset the port 0 (TBT port) PD connection 30 seconds after resume to
* ensure correct TBT init.
* TODO(b/296493322): Craft a more targeted fix.
*/
if (pd_reset_on_resume) {
hook_call_deferred(&pd_reset_deferred_data, 30 * SECOND);
pd_reset_on_resume = false;
}
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, pd_reset_resume, HOOK_PRIO_DEFAULT);
void pd_reset_reboot(void)
{
/*
* Reset the port 0 (TBT port) PD connection 30 seconds after reboot to
* ensure correct TBT init.
* TODO(b/296493322): Craft a more targeted fix.
*/
hook_call_deferred(&pd_reset_deferred_data, 30 * SECOND);
}
DECLARE_HOOK(HOOK_CHIPSET_RESET, pd_reset_reboot, HOOK_PRIO_DEFAULT);
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;
}

20
board/nova/usbc_config.h Normal file
View File

@ -0,0 +1,20 @@
/* Copyright 2024 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 */

View File

@ -0,0 +1,3 @@
<!-- Add VIF field overrides here. See genvif.c and the Vendor Info File
Definition from the USB-IF.
-->

View File

@ -54,6 +54,7 @@
/* Sensor console commands */
#define CONFIG_CMD_ACCELS
#define CONFIG_CMD_ACCEL_INFO
#define CONFIG_DYNAMIC_MOTION_SENSOR_COUNT
/* USB Type A Features */
#define USB_PORT_COUNT 1

View File

@ -132,7 +132,7 @@ struct motion_sensor_t motion_sensors[] = {
.max_frequency = LSM6DSO_ODR_MAX_VAL,
},
};
const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
static void baseboard_sensors_init(void)
{
@ -142,6 +142,7 @@ static void baseboard_sensors_init(void)
/* Enable gpio interrupt for base accelgyro sensor */
gpio_enable_interrupt(GPIO_EC_IMU_INT_R_L);
} else {
motion_sensor_count = 0;
gmr_tablet_switch_disable();
/* Base accel is not stuffed, don't allow line to float */
gpio_set_flags(GPIO_EC_ACCEL_INT_R_L,

View File

@ -115,7 +115,7 @@ __override struct keyboard_scan_config keyscan_config = {
},
};
static uint16_t scancode_set2_rgb[KEYBOARD_COLS_MAX][KEYBOARD_ROWS] = {
static scancode_set2_t scancode_set2_rgb = {
{ 0x0000, 0x0000, 0x0014, 0xe01f, 0xe014, 0xe007, 0x0000, 0x0000 },
{ 0x001f, 0x0076, 0x0017, 0x000e, 0x001c, 0x003a, 0x000d, 0x0016 },
{ 0x006c, 0x000c, 0x0004, 0x0006, 0x0005, 0xe071, 0x0026, 0x002a },
@ -132,12 +132,13 @@ static uint16_t scancode_set2_rgb[KEYBOARD_COLS_MAX][KEYBOARD_ROWS] = {
{ 0x0073, 0x0066, 0xe071, 0x005d, 0x005a, 0xe04a, 0x0070, 0x0021 },
{ 0x0023, 0xe05a, 0x0075, 0x0067, 0xe069, 0xe07a, 0x007d, 0x0069 },
};
BUILD_ASSERT(ARRAY_SIZE(scancode_set2_rgb) == KEYBOARD_COLS_MAX);
static void keyboard_matrix_init(void)
{
CPRINTS("%s", __func__);
register_scancode_set2((uint16_t *)&scancode_set2_rgb,
sizeof(scancode_set2_rgb));
register_scancode_set2(&scancode_set2_rgb,
ARRAY_SIZE(scancode_set2_rgb));
}
DECLARE_HOOK(HOOK_INIT, keyboard_matrix_init, HOOK_PRIO_PRE_DEFAULT);

View File

@ -666,7 +666,7 @@ int board_is_c10_gate_enabled(void)
* core rails while in S0 because HDMI should remain powered.
* EN_PP5000_HDMI is a separate EC output on all other boards.
*/
return board_version != 0;
return 0;
}
void board_enable_s0_rails(int enable)

View File

@ -505,3 +505,34 @@ const int usb_port_enable[USBA_PORT_COUNT] = {
IOEX_EN_USB_A0_5V,
GPIO_EN_USB_A1_5V,
};
void board_hibernate_late(void)
{
NPCX_KBSINPU = 0x08;
}
__override void zork_board_hibernate(void)
{
/**
* CONFIG_HIBERNATE_PSL is disabled on vilboz, so PPC is powered while
* EC hibernates. Make sure the source FET is off and sink FET is on.
*/
ppc_vbus_source_enable(0, 0);
ppc_vbus_sink_enable(0, 1);
/**
* Disable the SNKEN gpio on the TCPC so it goes into Hi-Z
* state (same as dead battery state) which allows the board to
* wake from AC.
*
* Disable low power mode temporarily since the SNKEN register
* will be overwritten during low power exit.
*/
pd_prevent_low_power_mode(0, 1);
pd_wait_exit_low_power(0);
/* Delay to allow PD task to settle after low power exit */
msleep(100);
tcpc_update8(0, NCT38XX_REG_CTRL_OUT_EN, NCT38XX_REG_CTRL_OUT_EN_SNKEN,
MASK_CLR);
pd_prevent_low_power_mode(0, 0);
}

View File

@ -14,6 +14,8 @@
#include <stdbool.h>
#undef CONFIG_HIBERNATE_PSL
#define CONFIG_USB_PD_PORT_MAX_COUNT 1
/* USB-A config */

View File

@ -63,9 +63,41 @@ const struct batt_conf_embed board_battery_info[] = {
.start_charging_min_c = 0,
.start_charging_max_c = 45,
.charging_min_c = 0,
.charging_max_c = 45,
.charging_max_c = 55,
.discharging_min_c = -20,
.discharging_max_c = 60,
.discharging_max_c = 70,
},
},
},
/* SWD(Sunwoda) Battery Information */
[BATTERY_SWD] = {
.manuf_name = "SWD",
.device_name = "4434A43",
.config = {
.fuel_gauge = {
.ship_mode = {
.reg_addr = 0x00,
.reg_data = { 0x0010, 0x0010 },
},
.fet = {
.reg_addr = 0x00,
.reg_mask = 0xc000,
.disconnect_val = 0x8000,
.cfet_mask = 0xc000,
.cfet_off_val = 0x4000,
},
},
.batt_info = {
.voltage_max = 17520,
.voltage_normal = 15440, /* mV */
.voltage_min = 12000, /* mV */
.precharge_current = 200, /* mA */
.start_charging_min_c = 0,
.start_charging_max_c = 45,
.charging_min_c = 0,
.charging_max_c = 55,
.discharging_min_c = -20,
.discharging_max_c = 70,
},
},
},

View File

@ -57,3 +57,31 @@ static void mp2964_on_startup(void)
CPRINTF("[mp2964] try to tune MP2964 (%d)\n", status);
}
DECLARE_HOOK(HOOK_CHIPSET_STARTUP, mp2964_on_startup, HOOK_PRIO_FIRST);
static const struct ec_response_keybd_config xol_kb = {
.num_top_row_keys = 14,
.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_DOWN, /* T8 */
TK_KBD_BKLIGHT_UP, /* T9 */
TK_PLAY_PAUSE, /* T10 */
TK_MICMUTE, /* T11 */
TK_VOL_MUTE, /* T12 */
TK_VOL_UP, /* T13 */
TK_VOL_DOWN, /* T14 */
},
.capabilities = KEYBD_CAP_FUNCTION_KEYS | KEYBD_CAP_SCRNLOCK_KEY |
KEYBD_CAP_NUMERIC_KEYPAD,
};
__override const struct ec_response_keybd_config *
board_vivaldi_keybd_config(void)
{
return &xol_kb;
}

View File

@ -10,11 +10,6 @@
#include "compile_time_macros.h"
/*
* Early Xol boards are not set up for vivaldi
*/
#undef CONFIG_KEYBOARD_VIVALDI
/* Baseboard features */
#include "baseboard.h"
@ -140,13 +135,15 @@
#define CONFIG_FANS FAN_CH_COUNT
/* Charger defines */
#define CONFIG_CHARGER_BQ25720
#define CONFIG_CHARGER_BQ25720_VSYS_TH2_CUSTOM
#define CONFIG_CHARGER_BQ25720_VSYS_TH2_DV 70
#define CONFIG_CHARGER_BQ25710
#define CONFIG_CHARGER_BQ25710_SENSE_RESISTOR 10
#define CONFIG_CHARGER_BQ25710_SENSE_RESISTOR_AC 10
#define CONFIG_CHARGER_BQ25710_PSYS_SENSING
/* Keyboard */
#define KEYBOARD_COLS_MAX 18
#define CONFIG_KEYBOARD_KEYPAD
#ifndef __ASSEMBLER__
#include "gpio_signal.h" /* needed by registers.h */
@ -169,7 +166,7 @@ enum temp_sensor_id {
enum ioex_port { IOEX_C0_NCT38XX = 0, IOEX_C2_NCT38XX, IOEX_PORT_COUNT };
enum battery_type { BATTERY_SDI, BATTERY_TYPE_COUNT };
enum battery_type { BATTERY_SDI, BATTERY_SWD, BATTERY_TYPE_COUNT };
enum pwm_channel {
PWM_CH_KBLIGHT = 0, /* PWM3 */

View File

@ -12,10 +12,12 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, HOOKS_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(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_C2, pd_task, NULL, BASEBOARD_PD_TASK_STACK_SIZE) \
TASK_ALWAYS(PD_INT_C0, pd_shared_alert_task, (BIT(1) | BIT(0)), BASEBOARD_PD_INT_TASK_STACK_SIZE)

View File

@ -43,16 +43,6 @@ static void pg_exit_restore_hw(void)
CCU_BCG_GPIO = 0;
}
/**
* on ISH, uart interrupt can only wakeup ISH from low power state via
* CTS pin, but most ISH platforms only have Rx and Tx pins, no CTS pin
* exposed, so, we need block ISH enter low power state for a while when
* console is in use.
* fixed amount of time to keep the console in use flag true after boot in
* order to give a permanent window in which the low speed clock is not used.
*/
#define CONSOLE_IN_USE_ON_BOOT_TIME (15 * SECOND)
/* power management internal context data structure */
struct pm_context {
/* aontask image valid flag */
@ -699,7 +689,7 @@ void __idle(void)
*/
disable_sleep(SLEEP_MASK_CONSOLE);
pm_ctx.console_expire_time.val =
get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
get_time().val + CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME;
while (1) {
t0 = get_time();

View File

@ -40,7 +40,6 @@ static uint32_t ec_sleep;
* Fixed amount of time to keep the console in use flag true after boot in
* order to give a permanent window in which the heavy sleep mode is not used.
*/
#define CONSOLE_IN_USE_ON_BOOT_TIME (15 * SECOND)
static int console_in_use_timeout_sec = 5;
static timestamp_t console_expire_time;
@ -606,7 +605,8 @@ void clock_sleep_mode_wakeup_isr(void)
void __keep __idle_init(void)
{
console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
console_expire_time.val =
get_time().val + CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME;
/* init hw timer and clock source is 32.768 KHz */
ext_timer_ms(LOW_POWER_EXT_TIMER, EXT_PSR_32P768K_HZ, 1, 0, 0xffffffff,
1, 1);

View File

@ -52,7 +52,6 @@ static uint32_t ecia_result[MCHP_INT_GIRQ_NUM];
* boot in order to give a permanent window in which the heavy sleep
* mode is not used.
*/
#define CONSOLE_IN_USE_ON_BOOT_TIME (15 * SECOND)
static int console_in_use_timeout_sec = 60;
static timestamp_t console_expire_time;
#endif /*CONFIG_LOW_POWER_IDLE */
@ -539,7 +538,8 @@ void __idle(void)
htimer_init(); /* hibernation timer initialize */
disable_sleep(SLEEP_MASK_CONSOLE);
console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
console_expire_time.val =
get_time().val + CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME;
/*
* Print when the idle task starts. This is the lowest priority

2
chip/mt_scp/OWNERS Normal file
View File

@ -0,0 +1,2 @@
# MT8188 / Geralt SCP
fshao@chromium.org

View File

@ -10,3 +10,7 @@
#if defined(CHIP_VARIANT_MT8192) || defined(CHIP_VARIANT_MT8195)
#include "rv32i_common/config_chip.h"
#endif
#if defined(CHIP_VARIANT_MT8195)
#include "mt8195/config_chip.h"
#endif

View File

@ -7,3 +7,4 @@
chip-y+=$(CHIP_VARIANT)/uart.o
chip-y+=$(CHIP_VARIANT)/clock.o
chip-y+=$(CHIP_VARIANT)/video.o
chip-y+=$(CHIP_VARIANT)/intc_group.o

View File

@ -0,0 +1,123 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "intc_group.h"
static struct intc_irq_group irqs[SCP_INTC_IRQ_COUNT] = {
/* 0 */
[SCP_IRQ_GIPC_IN0] = { INTC_GRP_7 },
[SCP_IRQ_GIPC_IN1] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN3] = { INTC_GRP_0 },
/* 4 */
[SCP_IRQ_SPM] = { INTC_GRP_0 },
[SCP_IRQ_AP_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_EINT] = { INTC_GRP_0 },
[SCP_IRQ_PMIC] = { INTC_GRP_0 },
/* 8 */
[SCP_IRQ_UART0_TX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_TX] = { INTC_GRP_12 },
[SCP_IRQ_I2C0] = { INTC_GRP_0 },
[SCP_IRQ_I2C1_0] = { INTC_GRP_0 },
/* 12 */
[SCP_IRQ_BUS_DBG_TRACKER] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL] = { INTC_GRP_0 },
[SCP_IRQ_VOW] = { INTC_GRP_0 },
[SCP_IRQ_TIMER0] = { INTC_GRP_6 },
/* 16 */
[SCP_IRQ_TIMER1] = { INTC_GRP_6 },
[SCP_IRQ_TIMER2] = { INTC_GRP_6 },
[SCP_IRQ_TIMER3] = { INTC_GRP_6 },
[SCP_IRQ_TIMER4] = { INTC_GRP_6 },
/* 20 */
[SCP_IRQ_TIMER5] = { INTC_GRP_6 },
[SCP_IRQ_OS_TIMER] = { INTC_GRP_0 },
[SCP_IRQ_UART0_RX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_RX] = { INTC_GRP_12 },
/* 24 */
[SCP_IRQ_GDMA] = { INTC_GRP_0 },
[SCP_IRQ_AUDIO] = { INTC_GRP_0 },
[SCP_IRQ_MD_DSP] = { INTC_GRP_0 },
[SCP_IRQ_ADSP] = { INTC_GRP_0 },
/* 28 */
[SCP_IRQ_CPU_TICK] = { INTC_GRP_0 },
[SCP_IRQ_SPI0] = { INTC_GRP_0 },
[SCP_IRQ_SPI1] = { INTC_GRP_0 },
[SCP_IRQ_SPI2] = { INTC_GRP_0 },
/* 32 */
[SCP_IRQ_NEW_INFRA_SYS_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_DBG] = { INTC_GRP_0 },
[SCP_IRQ_CCIF0] = { INTC_GRP_0 },
[SCP_IRQ_CCIF1] = { INTC_GRP_0 },
/* 36 */
[SCP_IRQ_CCIF2] = { INTC_GRP_0 },
[SCP_IRQ_WDT] = { INTC_GRP_0 },
[SCP_IRQ_USB0] = { INTC_GRP_0 },
[SCP_IRQ_USB1] = { INTC_GRP_0 },
/* 40 */
[SCP_IRQ_DPMAIF] = { INTC_GRP_0 },
[SCP_IRQ_INFRA] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL_CORE] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL2_CORE] = { INTC_GRP_0 },
/* 44 */
[SCP_IRQ_CLK_CTRL2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN4] = { INTC_GRP_0 },
[SCP_IRQ_PERIBUS_TIMEOUT] = { INTC_GRP_0 },
[SCP_IRQ_INFRABUS_TIMEOUT] = { INTC_GRP_0 },
/* 48 */
[SCP_IRQ_MET0] = { INTC_GRP_0 },
[SCP_IRQ_MET1] = { INTC_GRP_0 },
[SCP_IRQ_MET2] = { INTC_GRP_0 },
[SCP_IRQ_MET3] = { INTC_GRP_0 },
/* 52 */
[SCP_IRQ_AP_WDT] = { INTC_GRP_0 },
[SCP_IRQ_L2TCM_SEC_VIO] = { INTC_GRP_0 },
[SCP_IRQ_CPU_TICK1] = { INTC_GRP_0 },
[SCP_IRQ_MAD_DATAIN] = { INTC_GRP_0 },
/* 56 */
[SCP_IRQ_I3C0_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C1_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C2_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_APU_ENGINE] = { INTC_GRP_0 },
/* 60 */
[SCP_IRQ_MBOX0] = { INTC_GRP_0 },
[SCP_IRQ_MBOX1] = { INTC_GRP_0 },
[SCP_IRQ_MBOX2] = { INTC_GRP_0 },
[SCP_IRQ_MBOX3] = { INTC_GRP_0 },
/* 64 */
[SCP_IRQ_MBOX4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_CLK_REQ] = { INTC_GRP_0 },
[SCP_IRQ_BUS_REQ] = { INTC_GRP_0 },
[SCP_IRQ_APSRC_REQ] = { INTC_GRP_0 },
/* 68 */
[SCP_IRQ_APU_MBOX] = { INTC_GRP_0 },
[SCP_IRQ_DEVAPC_SECURE_VIO] = { INTC_GRP_0 },
/* 72 */
/* 76 */
[SCP_IRQ_I2C1_2] = { INTC_GRP_0 },
[SCP_IRQ_I2C2] = { INTC_GRP_0 },
/* 80 */
[SCP_IRQ_AUD2AUDIODSP] = { INTC_GRP_0 },
[SCP_IRQ_AUD2AUDIODSP_2] = { INTC_GRP_0 },
[SCP_IRQ_CONN2ADSP_A2DPOL] = { INTC_GRP_0 },
[SCP_IRQ_CONN2ADSP_BTCVSD] = { INTC_GRP_0 },
/* 84 */
[SCP_IRQ_CONN2ADSP_BLEISO] = { INTC_GRP_0 },
[SCP_IRQ_PCIE2ADSP] = { INTC_GRP_0 },
[SCP_IRQ_APU2ADSP_ENGINE] = { INTC_GRP_0 },
[SCP_IRQ_APU2ADSP_MBOX] = { INTC_GRP_0 },
/* 88 */
[SCP_IRQ_CCIF3] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA0] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA1] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA2] = { INTC_GRP_0 },
/* 92 */
[SCP_IRQ_I2C_DMA3] = { INTC_GRP_0 },
};
BUILD_ASSERT(ARRAY_SIZE(irqs) == SCP_INTC_IRQ_COUNT);
uint8_t intc_irq_group_get(int irq)
{
return irqs[irq].group;
}

View File

@ -6,4 +6,6 @@
# Required chip modules
chip-y+=$(CHIP_VARIANT)/uart.o
chip-y+=$(CHIP_VARIANT)/clock.o
chip-y+=$(CHIP_VARIANT)/clock_s3.o
chip-y+=$(CHIP_VARIANT)/video.o
chip-y+=$(CHIP_VARIANT)/intc_group.o

View File

@ -6,16 +6,14 @@
/* Clocks, PLL and power settings */
#include "clock.h"
#include "clock_s3.h"
#include "common.h"
#include "console.h"
#include "csr.h"
#include "ec_commands.h"
#include "power.h"
#include "registers.h"
#include "scp_timer.h"
#include "scp_watchdog.h"
#include "task.h"
#include "timer.h"
#include <assert.h>
#include <string.h>
@ -23,24 +21,6 @@
#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ##args)
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ##args)
#define TASK_EVENT_SUSPEND TASK_EVENT_CUSTOM_BIT(4)
#define TASK_EVENT_RESUME TASK_EVENT_CUSTOM_BIT(5)
#define CHECK_26M_PERIOD_US 50000
enum scp_sr_state {
SR_S0,
SR_S02S3,
SR_S3,
};
enum scp_clock_source {
SCP_CLK_SYSTEM,
SCP_CLK_32K,
SCP_CLK_ULPOSC1,
SCP_CLK_ULPOSC2_LOW_SPEED,
SCP_CLK_ULPOSC2_HIGH_SPEED,
};
enum {
OPP_ULPOSC2_LOW_SPEED,
OPP_ULPOSC2_HIGH_SPEED,
@ -335,7 +315,7 @@ static void clock_calibrate_ulposc(struct opp_ulposc_cfg *opp)
opp->cali = clock_ulposc_process_cali(opp);
}
static void clock_select_clock(enum scp_clock_source src)
void clock_select_clock(enum scp_clock_source src)
{
uint32_t sel;
uint32_t div;
@ -388,61 +368,13 @@ power_chipset_handle_host_sleep_event(enum host_sleep_event state,
struct host_sleep_event_context *ctx)
{
if (state == HOST_SLEEP_EVENT_S3_SUSPEND) {
CPRINTS("AP suspend");
clock_select_clock(SCP_CLK_ULPOSC2_LOW_SPEED);
task_set_event(TASK_ID_SR, TASK_EVENT_SUSPEND);
} else if (state == HOST_SLEEP_EVENT_S3_RESUME) {
task_set_event(TASK_ID_SR, TASK_EVENT_RESUME);
}
}
void sr_task(void *u)
{
enum scp_sr_state state = SR_S0;
uint32_t event;
uint32_t prev, now;
while (1) {
switch (state) {
case SR_S0:
event = task_wait_event(-1);
if (event & TASK_EVENT_SUSPEND) {
timer_enable(TIMER_SR);
prev = timer_read_raw_sr();
state = SR_S02S3;
}
break;
case SR_S02S3:
event = task_wait_event(CHECK_26M_PERIOD_US);
if (event & TASK_EVENT_RESUME) {
/* suspend is aborted */
timer_disable(TIMER_SR);
state = SR_S0;
} else if (event & TASK_EVENT_TIMER) {
now = timer_read_raw_sr();
if (now != prev) {
/* 26M is still on */
prev = now;
} else {
/* 26M is off */
state = SR_S3;
}
}
break;
case SR_S3:
interrupt_disable();
watchdog_disable();
/* change to 26M to stop core at here */
clock_select_clock(SCP_CLK_SYSTEM);
/* 26M is back */
clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED);
watchdog_enable();
interrupt_enable();
timer_disable(TIMER_SR);
state = SR_S0;
break;
}
clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED);
CPRINTS("AP resume");
}
}

View File

@ -0,0 +1,70 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "clock_s3.h"
#include "common.h"
#include "scp_timer.h"
#include "scp_watchdog.h"
#include "task.h"
#include "timer.h"
#define CHECK_26M_PERIOD_US 50000
enum scp_sr_state {
SR_S0,
SR_S02S3,
SR_S3,
};
void sr_task(void *u)
{
enum scp_sr_state state = SR_S0;
uint32_t event;
uint32_t prev, now;
while (1) {
switch (state) {
case SR_S0:
event = task_wait_event(-1);
if (event & TASK_EVENT_SUSPEND) {
timer_enable(TIMER_SR);
prev = timer_read_raw_sr();
state = SR_S02S3;
}
break;
case SR_S02S3:
event = task_wait_event(CHECK_26M_PERIOD_US);
if (event & TASK_EVENT_RESUME) {
/* suspend is aborted */
timer_disable(TIMER_SR);
state = SR_S0;
} else if (event & TASK_EVENT_TIMER) {
now = timer_read_raw_sr();
if (now != prev) {
/* 26M is still on */
prev = now;
} else {
/* 26M is off */
state = SR_S3;
}
}
break;
case SR_S3:
interrupt_disable();
watchdog_disable();
/* change to 26M to stop core at here */
clock_select_clock(SCP_CLK_SYSTEM);
/* 26M is back */
clock_select_clock(SCP_CLK_ULPOSC2_LOW_SPEED);
watchdog_enable();
interrupt_enable();
timer_disable(TIMER_SR);
state = SR_S0;
break;
}
}
}

View File

@ -0,0 +1,22 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef __CLOCK_S3_H
#define __CLOCK_S3_H
enum scp_clock_source {
SCP_CLK_SYSTEM,
SCP_CLK_32K,
SCP_CLK_ULPOSC1,
SCP_CLK_ULPOSC2_LOW_SPEED,
SCP_CLK_ULPOSC2_HIGH_SPEED,
};
void clock_select_clock(enum scp_clock_source src);
#define TASK_EVENT_SUSPEND TASK_EVENT_CUSTOM_BIT(4)
#define TASK_EVENT_RESUME TASK_EVENT_CUSTOM_BIT(5)
#endif /* __CLOCK_S3_H */

View File

@ -0,0 +1,18 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef __CROS_EC_CONFIG_CHIP_MT8195_H
#define __CROS_EC_CONFIG_CHIP_MT8195_H
#define CONFIG_CHIP_MEMORY_REGIONS
#define CONFIG_PANIC_CONSOLE_OUTPUT
/* Add some space (0x100) before panic for jump data */
#define CONFIG_PANIC_BASE_OFFSET 0x100 /* reserved for jump data */
#define CONFIG_PANIC_DATA_BASE \
(CONFIG_PANIC_DRAM_BASE + CONFIG_PANIC_BASE_OFFSET)
#endif /* __CROS_EC_CONFIG_CHIP_MT8195_H */

View File

@ -0,0 +1,162 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "intc_group.h"
static struct intc_irq_group irqs[SCP_INTC_IRQ_COUNT] = {
/* 0 */
[SCP_IRQ_GIPC_IN0] = { INTC_GRP_7 },
[SCP_IRQ_GIPC_IN1] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN3] = { INTC_GRP_0 },
/* 4 */
[SCP_IRQ_SPM] = { INTC_GRP_0 },
[SCP_IRQ_AP_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_EINT] = { INTC_GRP_0 },
[SCP_IRQ_PMIC] = { INTC_GRP_0 },
/* 8 */
[SCP_IRQ_UART0_TX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_TX] = { INTC_GRP_12 },
[SCP_IRQ_I2C0] = { INTC_GRP_0 },
[SCP_IRQ_I2C1_0] = { INTC_GRP_0 },
/* 12 */
[SCP_IRQ_BUS_DBG_TRACKER] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL] = { INTC_GRP_0 },
[SCP_IRQ_VOW] = { INTC_GRP_0 },
[SCP_IRQ_TIMER0] = { INTC_GRP_6 },
/* 16 */
[SCP_IRQ_TIMER1] = { INTC_GRP_6 },
[SCP_IRQ_TIMER2] = { INTC_GRP_6 },
[SCP_IRQ_TIMER3] = { INTC_GRP_6 },
[SCP_IRQ_TIMER4] = { INTC_GRP_6 },
/* 20 */
[SCP_IRQ_TIMER5] = { INTC_GRP_6 },
[SCP_IRQ_OS_TIMER] = { INTC_GRP_0 },
[SCP_IRQ_UART0_RX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_RX] = { INTC_GRP_12 },
/* 24 */
[SCP_IRQ_GDMA] = { INTC_GRP_0 },
[SCP_IRQ_AUDIO] = { INTC_GRP_0 },
[SCP_IRQ_MD_DSP] = { INTC_GRP_0 },
[SCP_IRQ_ADSP] = { INTC_GRP_0 },
/* 28 */
[SCP_IRQ_CPU_TICK] = { INTC_GRP_0 },
[SCP_IRQ_SPI0] = { INTC_GRP_0 },
[SCP_IRQ_SPI1] = { INTC_GRP_0 },
[SCP_IRQ_SPI2] = { INTC_GRP_0 },
/* 32 */
[SCP_IRQ_NEW_INFRA_SYS_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_DBG] = { INTC_GRP_0 },
[SCP_IRQ_GCE] = { INTC_GRP_0 },
[SCP_IRQ_MDP_GCE] = { INTC_GRP_0 },
/* 36 */
[SCP_IRQ_VDEC] = { INTC_GRP_8 },
[SCP_IRQ_WDT] = { INTC_GRP_0 },
[SCP_IRQ_VDEC_LAT] = { INTC_GRP_8 },
[SCP_IRQ_VDEC1] = { INTC_GRP_8 },
/* 40 */
[SCP_IRQ_VDEC1_LAT] = { INTC_GRP_8 },
[SCP_IRQ_INFRA] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL_CORE] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL2_CORE] = { INTC_GRP_0 },
/* 44 */
[SCP_IRQ_CLK_CTRL2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN4] = { INTC_GRP_0 },
[SCP_IRQ_PERIBUS_TIMEOUT] = { INTC_GRP_0 },
[SCP_IRQ_INFRABUS_TIMEOUT] = { INTC_GRP_0 },
/* 48 */
[SCP_IRQ_MET0] = { INTC_GRP_0 },
[SCP_IRQ_MET1] = { INTC_GRP_0 },
[SCP_IRQ_MET2] = { INTC_GRP_0 },
[SCP_IRQ_MET3] = { INTC_GRP_0 },
/* 52 */
[SCP_IRQ_AP_WDT] = { INTC_GRP_0 },
[SCP_IRQ_L2TCM_SEC_VIO] = { INTC_GRP_0 },
[SCP_IRQ_VDEC_INT_LINE_CNT] = { INTC_GRP_0 },
[SCP_IRQ_VOW_DATAIN] = { INTC_GRP_0 },
/* 56 */
[SCP_IRQ_I3C0_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C1_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_VENC] = { INTC_GRP_8 },
[SCP_IRQ_APU_ENGINE] = { INTC_GRP_0 },
/* 60 */
[SCP_IRQ_MBOX0] = { INTC_GRP_0 },
[SCP_IRQ_MBOX1] = { INTC_GRP_0 },
[SCP_IRQ_MBOX2] = { INTC_GRP_0 },
[SCP_IRQ_MBOX3] = { INTC_GRP_0 },
/* 64 */
[SCP_IRQ_MBOX4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_CLK_REQ] = { INTC_GRP_0 },
[SCP_IRQ_BUS_REQ] = { INTC_GRP_0 },
[SCP_IRQ_APSRC_REQ] = { INTC_GRP_0 },
/* 68 */
[SCP_IRQ_APU_MBOX] = { INTC_GRP_0 },
[SCP_IRQ_DEVAPC_SECURE_VIO] = { INTC_GRP_0 },
[SCP_IRQ_APDMA0] = { INTC_GRP_0 },
[SCP_IRQ_APDMA1] = { INTC_GRP_0 },
/* 72 */
[SCP_IRQ_APDMA2] = { INTC_GRP_0 },
[SCP_IRQ_APDMA3] = { INTC_GRP_0 },
[SCP_IRQ_APDMA4] = { INTC_GRP_0 },
[SCP_IRQ_APDMA5] = { INTC_GRP_0 },
/* 76 */
[SCP_IRQ_HDMIRX_PM_DVI_SQH] = { INTC_GRP_0 },
[SCP_IRQ_HDMIRX_RESERVED] = { INTC_GRP_0 },
[SCP_IRQ_NNA0_0] = { INTC_GRP_0 },
[SCP_IRQ_NNA0_1] = { INTC_GRP_0 },
/* 80 */
[SCP_IRQ_NNA0_2] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_0] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_1] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_2] = { INTC_GRP_0 },
/* 84 */
[SCP_IRQ_JPEGENC] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC_C2] = { INTC_GRP_0 },
[SCP_IRQ_VENC_C1] = { INTC_GRP_8 },
/* 88 */
[SCP_IRQ_JPEGENC_C1] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC_C1] = { INTC_GRP_0 },
[SCP_IRQ_HDMITX] = { INTC_GRP_0 },
[SCP_IRQ_HDMI2] = { INTC_GRP_0 },
/* 92 */
[SCP_IRQ_EARC] = { INTC_GRP_0 },
[SCP_IRQ_CEC] = { INTC_GRP_0 },
[SCP_IRQ_HDMI_DEV_DET] = { INTC_GRP_0 },
[SCP_IRQ_HDMIRX_OUT_ARM_PHY] = { INTC_GRP_0 },
/* 96 */
[SCP_IRQ_I2C2] = { INTC_GRP_0 },
[SCP_IRQ_I2C3] = { INTC_GRP_0 },
[SCP_IRQ_I3C2_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C3_IBI_WAKE] = { INTC_GRP_0 },
/* 100 */
[SCP_IRQ_SYS_I2C_0] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_1] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_2] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_3] = { INTC_GRP_0 },
/* 104 */
[SCP_IRQ_SYS_I2C_4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_5] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_6] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_7] = { INTC_GRP_0 },
/* 108 */
[SCP_IRQ_DISP2ADSP_0] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_1] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_2] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_3] = { INTC_GRP_0 },
/* 112 */
[SCP_IRQ_DISP2ADSP_4] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_0] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_1] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_2] = { INTC_GRP_0 },
/* 116 */
[SCP_IRQ_GCE1_SECURE] = { INTC_GRP_0 },
[SCP_IRQ_GCE_SECURE] = { INTC_GRP_0 },
};
BUILD_ASSERT(ARRAY_SIZE(irqs) == SCP_INTC_IRQ_COUNT);
uint8_t intc_irq_group_get(int irq)
{
return irqs[irq].group;
}

View File

@ -22,6 +22,6 @@ endif
# Optional chip modules
chip-$(CONFIG_COMMON_TIMER)+=rv32i_common/hrtimer.o
chip-$(CONFIG_IPI)+=rv32i_common/ipi.o rv32i_common/ipi_table.o
chip-$(CONFIG_IPI)+=rv32i_common/ipi.o rv32i_common/ipi_table.o rv32i_common/ipi_ops.o
chip-$(CONFIG_WATCHDOG)+=rv32i_common/watchdog.o
chip-$(HAS_TASK_HOSTCMD)+=rv32i_common/hostcmd.o

View File

@ -59,7 +59,7 @@ void cache_init(void)
*/
static enum { PMU_SELECT_I = 0, PMU_SELECT_D, PMU_SELECT_C } pmu_select;
int command_enable_pmu(int argc, const char **argv)
static int command_enable_pmu(int argc, const char **argv)
{
static const char *const selectors[] = {
[PMU_SELECT_I] = "I",
@ -142,7 +142,7 @@ int command_enable_pmu(int argc, const char **argv)
DECLARE_SAFE_CONSOLE_COMMAND(enable_pmu, command_enable_pmu, "[I | D | C]",
"Enable PMU");
int command_disable_pmu(int argc, const char **argv)
static int command_disable_pmu(int argc, const char **argv)
{
clear_csr(CSR_PMU_MPMUCTR,
CSR_PMU_MPMUCTR_C | CSR_PMU_MPMUCTR_I | CSR_PMU_MPMUCTR_H3 |
@ -152,7 +152,7 @@ int command_disable_pmu(int argc, const char **argv)
DECLARE_SAFE_CONSOLE_COMMAND(disable_pmu, command_disable_pmu, NULL,
"Disable PMU");
int command_show_pmu(int argc, const char **argv)
static int command_show_pmu(int argc, const char **argv)
{
uint64_t val3, val4, val5;
uint32_t p;

View File

@ -20,7 +20,13 @@
#define TIMER_SYSTEM 5
#define TIMER_EVENT 3
#ifdef CHIP_VARIANT_MT8195
#define TIMER_CLOCK_MHZ 31
#else
#define TIMER_CLOCK_MHZ 32.5
#endif
#define OVERFLOW_TICKS (TIMER_CLOCK_MHZ * 0x100000000 - 1)
/* High 32-bit for system timer. */

View File

@ -7,306 +7,9 @@
#include "console.h"
#include "csr.h"
#include "intc.h"
#include "intc_group.h"
#include "registers.h"
/*
* INTC_GRP_0 is reserved. See swirq of syscall_handler() in
* core/riscv-rv32i/task.c for more details.
*
* Lower group has higher priority. Group 0 has highest priority.
*/
enum INTC_GROUP {
INTC_GRP_0 = 0x0,
INTC_GRP_1,
INTC_GRP_2,
INTC_GRP_3,
INTC_GRP_4,
INTC_GRP_5,
INTC_GRP_6,
INTC_GRP_7,
INTC_GRP_8,
INTC_GRP_9,
INTC_GRP_10,
INTC_GRP_11,
INTC_GRP_12,
INTC_GRP_13,
INTC_GRP_14,
};
#ifdef BOARD_ASURADA_SCP
static struct {
uint8_t group;
} irqs[SCP_INTC_IRQ_COUNT] = {
/* 0 */
[SCP_IRQ_GIPC_IN0] = { INTC_GRP_7 },
[SCP_IRQ_GIPC_IN1] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN3] = { INTC_GRP_0 },
/* 4 */
[SCP_IRQ_SPM] = { INTC_GRP_0 },
[SCP_IRQ_AP_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_EINT] = { INTC_GRP_0 },
[SCP_IRQ_PMIC] = { INTC_GRP_0 },
/* 8 */
[SCP_IRQ_UART0_TX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_TX] = { INTC_GRP_12 },
[SCP_IRQ_I2C0] = { INTC_GRP_0 },
[SCP_IRQ_I2C1_0] = { INTC_GRP_0 },
/* 12 */
[SCP_IRQ_BUS_DBG_TRACKER] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL] = { INTC_GRP_0 },
[SCP_IRQ_VOW] = { INTC_GRP_0 },
[SCP_IRQ_TIMER0] = { INTC_GRP_6 },
/* 16 */
[SCP_IRQ_TIMER1] = { INTC_GRP_6 },
[SCP_IRQ_TIMER2] = { INTC_GRP_6 },
[SCP_IRQ_TIMER3] = { INTC_GRP_6 },
[SCP_IRQ_TIMER4] = { INTC_GRP_6 },
/* 20 */
[SCP_IRQ_TIMER5] = { INTC_GRP_6 },
[SCP_IRQ_OS_TIMER] = { INTC_GRP_0 },
[SCP_IRQ_UART0_RX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_RX] = { INTC_GRP_12 },
/* 24 */
[SCP_IRQ_GDMA] = { INTC_GRP_0 },
[SCP_IRQ_AUDIO] = { INTC_GRP_0 },
[SCP_IRQ_MD_DSP] = { INTC_GRP_0 },
[SCP_IRQ_ADSP] = { INTC_GRP_0 },
/* 28 */
[SCP_IRQ_CPU_TICK] = { INTC_GRP_0 },
[SCP_IRQ_SPI0] = { INTC_GRP_0 },
[SCP_IRQ_SPI1] = { INTC_GRP_0 },
[SCP_IRQ_SPI2] = { INTC_GRP_0 },
/* 32 */
[SCP_IRQ_NEW_INFRA_SYS_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_DBG] = { INTC_GRP_0 },
[SCP_IRQ_CCIF0] = { INTC_GRP_0 },
[SCP_IRQ_CCIF1] = { INTC_GRP_0 },
/* 36 */
[SCP_IRQ_CCIF2] = { INTC_GRP_0 },
[SCP_IRQ_WDT] = { INTC_GRP_0 },
[SCP_IRQ_USB0] = { INTC_GRP_0 },
[SCP_IRQ_USB1] = { INTC_GRP_0 },
/* 40 */
[SCP_IRQ_DPMAIF] = { INTC_GRP_0 },
[SCP_IRQ_INFRA] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL_CORE] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL2_CORE] = { INTC_GRP_0 },
/* 44 */
[SCP_IRQ_CLK_CTRL2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN4] = { INTC_GRP_0 },
[SCP_IRQ_PERIBUS_TIMEOUT] = { INTC_GRP_0 },
[SCP_IRQ_INFRABUS_TIMEOUT] = { INTC_GRP_0 },
/* 48 */
[SCP_IRQ_MET0] = { INTC_GRP_0 },
[SCP_IRQ_MET1] = { INTC_GRP_0 },
[SCP_IRQ_MET2] = { INTC_GRP_0 },
[SCP_IRQ_MET3] = { INTC_GRP_0 },
/* 52 */
[SCP_IRQ_AP_WDT] = { INTC_GRP_0 },
[SCP_IRQ_L2TCM_SEC_VIO] = { INTC_GRP_0 },
[SCP_IRQ_CPU_TICK1] = { INTC_GRP_0 },
[SCP_IRQ_MAD_DATAIN] = { INTC_GRP_0 },
/* 56 */
[SCP_IRQ_I3C0_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C1_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C2_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_APU_ENGINE] = { INTC_GRP_0 },
/* 60 */
[SCP_IRQ_MBOX0] = { INTC_GRP_0 },
[SCP_IRQ_MBOX1] = { INTC_GRP_0 },
[SCP_IRQ_MBOX2] = { INTC_GRP_0 },
[SCP_IRQ_MBOX3] = { INTC_GRP_0 },
/* 64 */
[SCP_IRQ_MBOX4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_CLK_REQ] = { INTC_GRP_0 },
[SCP_IRQ_BUS_REQ] = { INTC_GRP_0 },
[SCP_IRQ_APSRC_REQ] = { INTC_GRP_0 },
/* 68 */
[SCP_IRQ_APU_MBOX] = { INTC_GRP_0 },
[SCP_IRQ_DEVAPC_SECURE_VIO] = { INTC_GRP_0 },
/* 72 */
/* 76 */
[SCP_IRQ_I2C1_2] = { INTC_GRP_0 },
[SCP_IRQ_I2C2] = { INTC_GRP_0 },
/* 80 */
[SCP_IRQ_AUD2AUDIODSP] = { INTC_GRP_0 },
[SCP_IRQ_AUD2AUDIODSP_2] = { INTC_GRP_0 },
[SCP_IRQ_CONN2ADSP_A2DPOL] = { INTC_GRP_0 },
[SCP_IRQ_CONN2ADSP_BTCVSD] = { INTC_GRP_0 },
/* 84 */
[SCP_IRQ_CONN2ADSP_BLEISO] = { INTC_GRP_0 },
[SCP_IRQ_PCIE2ADSP] = { INTC_GRP_0 },
[SCP_IRQ_APU2ADSP_ENGINE] = { INTC_GRP_0 },
[SCP_IRQ_APU2ADSP_MBOX] = { INTC_GRP_0 },
/* 88 */
[SCP_IRQ_CCIF3] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA0] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA1] = { INTC_GRP_0 },
[SCP_IRQ_I2C_DMA2] = { INTC_GRP_0 },
/* 92 */
[SCP_IRQ_I2C_DMA3] = { INTC_GRP_0 },
};
BUILD_ASSERT(ARRAY_SIZE(irqs) == SCP_INTC_IRQ_COUNT);
#endif
#ifdef BOARD_CHERRY_SCP
static struct {
uint8_t group;
} irqs[SCP_INTC_IRQ_COUNT] = {
/* 0 */
[SCP_IRQ_GIPC_IN0] = { INTC_GRP_7 },
[SCP_IRQ_GIPC_IN1] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN3] = { INTC_GRP_0 },
/* 4 */
[SCP_IRQ_SPM] = { INTC_GRP_0 },
[SCP_IRQ_AP_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_EINT] = { INTC_GRP_0 },
[SCP_IRQ_PMIC] = { INTC_GRP_0 },
/* 8 */
[SCP_IRQ_UART0_TX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_TX] = { INTC_GRP_12 },
[SCP_IRQ_I2C0] = { INTC_GRP_0 },
[SCP_IRQ_I2C1_0] = { INTC_GRP_0 },
/* 12 */
[SCP_IRQ_BUS_DBG_TRACKER] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL] = { INTC_GRP_0 },
[SCP_IRQ_VOW] = { INTC_GRP_0 },
[SCP_IRQ_TIMER0] = { INTC_GRP_6 },
/* 16 */
[SCP_IRQ_TIMER1] = { INTC_GRP_6 },
[SCP_IRQ_TIMER2] = { INTC_GRP_6 },
[SCP_IRQ_TIMER3] = { INTC_GRP_6 },
[SCP_IRQ_TIMER4] = { INTC_GRP_6 },
/* 20 */
[SCP_IRQ_TIMER5] = { INTC_GRP_6 },
[SCP_IRQ_OS_TIMER] = { INTC_GRP_0 },
[SCP_IRQ_UART0_RX] = { INTC_GRP_12 },
[SCP_IRQ_UART1_RX] = { INTC_GRP_12 },
/* 24 */
[SCP_IRQ_GDMA] = { INTC_GRP_0 },
[SCP_IRQ_AUDIO] = { INTC_GRP_0 },
[SCP_IRQ_MD_DSP] = { INTC_GRP_0 },
[SCP_IRQ_ADSP] = { INTC_GRP_0 },
/* 28 */
[SCP_IRQ_CPU_TICK] = { INTC_GRP_0 },
[SCP_IRQ_SPI0] = { INTC_GRP_0 },
[SCP_IRQ_SPI1] = { INTC_GRP_0 },
[SCP_IRQ_SPI2] = { INTC_GRP_0 },
/* 32 */
[SCP_IRQ_NEW_INFRA_SYS_CIRQ] = { INTC_GRP_0 },
[SCP_IRQ_DBG] = { INTC_GRP_0 },
[SCP_IRQ_GCE] = { INTC_GRP_0 },
[SCP_IRQ_MDP_GCE] = { INTC_GRP_0 },
/* 36 */
[SCP_IRQ_VDEC] = { INTC_GRP_8 },
[SCP_IRQ_WDT] = { INTC_GRP_0 },
[SCP_IRQ_VDEC_LAT] = { INTC_GRP_8 },
[SCP_IRQ_VDEC1] = { INTC_GRP_8 },
/* 40 */
[SCP_IRQ_VDEC1_LAT] = { INTC_GRP_8 },
[SCP_IRQ_INFRA] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL_CORE] = { INTC_GRP_0 },
[SCP_IRQ_CLK_CTRL2_CORE] = { INTC_GRP_0 },
/* 44 */
[SCP_IRQ_CLK_CTRL2] = { INTC_GRP_0 },
[SCP_IRQ_GIPC_IN4] = { INTC_GRP_0 },
[SCP_IRQ_PERIBUS_TIMEOUT] = { INTC_GRP_0 },
[SCP_IRQ_INFRABUS_TIMEOUT] = { INTC_GRP_0 },
/* 48 */
[SCP_IRQ_MET0] = { INTC_GRP_0 },
[SCP_IRQ_MET1] = { INTC_GRP_0 },
[SCP_IRQ_MET2] = { INTC_GRP_0 },
[SCP_IRQ_MET3] = { INTC_GRP_0 },
/* 52 */
[SCP_IRQ_AP_WDT] = { INTC_GRP_0 },
[SCP_IRQ_L2TCM_SEC_VIO] = { INTC_GRP_0 },
[SCP_IRQ_VDEC_INT_LINE_CNT] = { INTC_GRP_0 },
[SCP_IRQ_VOW_DATAIN] = { INTC_GRP_0 },
/* 56 */
[SCP_IRQ_I3C0_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C1_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_VENC] = { INTC_GRP_8 },
[SCP_IRQ_APU_ENGINE] = { INTC_GRP_0 },
/* 60 */
[SCP_IRQ_MBOX0] = { INTC_GRP_0 },
[SCP_IRQ_MBOX1] = { INTC_GRP_0 },
[SCP_IRQ_MBOX2] = { INTC_GRP_0 },
[SCP_IRQ_MBOX3] = { INTC_GRP_0 },
/* 64 */
[SCP_IRQ_MBOX4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_CLK_REQ] = { INTC_GRP_0 },
[SCP_IRQ_BUS_REQ] = { INTC_GRP_0 },
[SCP_IRQ_APSRC_REQ] = { INTC_GRP_0 },
/* 68 */
[SCP_IRQ_APU_MBOX] = { INTC_GRP_0 },
[SCP_IRQ_DEVAPC_SECURE_VIO] = { INTC_GRP_0 },
[SCP_IRQ_APDMA0] = { INTC_GRP_0 },
[SCP_IRQ_APDMA1] = { INTC_GRP_0 },
/* 72 */
[SCP_IRQ_APDMA2] = { INTC_GRP_0 },
[SCP_IRQ_APDMA3] = { INTC_GRP_0 },
[SCP_IRQ_APDMA4] = { INTC_GRP_0 },
[SCP_IRQ_APDMA5] = { INTC_GRP_0 },
/* 76 */
[SCP_IRQ_HDMIRX_PM_DVI_SQH] = { INTC_GRP_0 },
[SCP_IRQ_HDMIRX_RESERVED] = { INTC_GRP_0 },
[SCP_IRQ_NNA0_0] = { INTC_GRP_0 },
[SCP_IRQ_NNA0_1] = { INTC_GRP_0 },
/* 80 */
[SCP_IRQ_NNA0_2] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_0] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_1] = { INTC_GRP_0 },
[SCP_IRQ_NNA1_2] = { INTC_GRP_0 },
/* 84 */
[SCP_IRQ_JPEGENC] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC_C2] = { INTC_GRP_0 },
[SCP_IRQ_VENC_C1] = { INTC_GRP_8 },
/* 88 */
[SCP_IRQ_JPEGENC_C1] = { INTC_GRP_0 },
[SCP_IRQ_JPEGDEC_C1] = { INTC_GRP_0 },
[SCP_IRQ_HDMITX] = { INTC_GRP_0 },
[SCP_IRQ_HDMI2] = { INTC_GRP_0 },
/* 92 */
[SCP_IRQ_EARC] = { INTC_GRP_0 },
[SCP_IRQ_CEC] = { INTC_GRP_0 },
[SCP_IRQ_HDMI_DEV_DET] = { INTC_GRP_0 },
[SCP_IRQ_HDMIRX_OUT_ARM_PHY] = { INTC_GRP_0 },
/* 96 */
[SCP_IRQ_I2C2] = { INTC_GRP_0 },
[SCP_IRQ_I2C3] = { INTC_GRP_0 },
[SCP_IRQ_I3C2_IBI_WAKE] = { INTC_GRP_0 },
[SCP_IRQ_I3C3_IBI_WAKE] = { INTC_GRP_0 },
/* 100 */
[SCP_IRQ_SYS_I2C_0] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_1] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_2] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_3] = { INTC_GRP_0 },
/* 104 */
[SCP_IRQ_SYS_I2C_4] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_5] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_6] = { INTC_GRP_0 },
[SCP_IRQ_SYS_I2C_7] = { INTC_GRP_0 },
/* 108 */
[SCP_IRQ_DISP2ADSP_0] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_1] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_2] = { INTC_GRP_0 },
[SCP_IRQ_DISP2ADSP_3] = { INTC_GRP_0 },
/* 112 */
[SCP_IRQ_DISP2ADSP_4] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_0] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_1] = { INTC_GRP_0 },
[SCP_IRQ_VDO1_DISP_MON2ADSP_2] = { INTC_GRP_0 },
/* 116 */
[SCP_IRQ_GCE1_SECURE] = { INTC_GRP_0 },
[SCP_IRQ_GCE_SECURE] = { INTC_GRP_0 },
};
BUILD_ASSERT(ARRAY_SIZE(irqs) == SCP_INTC_IRQ_COUNT);
#endif
/*
* Find current interrupt source.
*
@ -342,7 +45,7 @@ error:
int chip_get_intc_group(int irq)
{
return irqs[irq].group;
return intc_irq_group_get(irq);
}
void chip_enable_irq(int irq)
@ -350,7 +53,7 @@ void chip_enable_irq(int irq)
unsigned int word, group, mask;
word = SCP_INTC_WORD(irq);
group = irqs[irq].group;
group = intc_irq_group_get(irq);
mask = BIT(SCP_INTC_BIT(irq));
/* disable interrupt */
@ -376,7 +79,7 @@ void chip_disable_irq(int irq)
void chip_clear_pending_irq(int irq)
{
unsigned int group = irqs[irq].group;
unsigned int group = intc_irq_group_get(irq);
/* must clear interrupt source before writing this */
write_csr(CSR_VIC_MIEMS, group);
@ -387,7 +90,7 @@ int chip_trigger_irq(int irq)
extern volatile int ec_int;
ec_int = irq;
return irqs[irq].group;
return intc_irq_group_get(irq);
}
void chip_init_irqs(void)

View File

@ -0,0 +1,42 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef __CROS_EC_INTC_GROUP_H
#define __CROS_EC_INTC_GROUP_H
#include "common.h"
#include "intc.h"
/*
* INTC_GRP_0 is reserved. See swirq of syscall_handler() in
* core/riscv-rv32i/task.c for more details.
*
* Lower group has higher priority. Group 0 has highest priority.
*/
enum INTC_GROUP {
INTC_GRP_0 = 0x0,
INTC_GRP_1,
INTC_GRP_2,
INTC_GRP_3,
INTC_GRP_4,
INTC_GRP_5,
INTC_GRP_6,
INTC_GRP_7,
INTC_GRP_8,
INTC_GRP_9,
INTC_GRP_10,
INTC_GRP_11,
INTC_GRP_12,
INTC_GRP_13,
INTC_GRP_14,
};
struct intc_irq_group {
uint8_t group;
};
uint8_t intc_irq_group_get(int irq);
#endif /* __CROS_EC_INTC_GROUP_H */

View File

@ -44,7 +44,7 @@ void ipi_enable_irq(void)
static int ipi_is_busy(void)
{
return SCP_SCP2APMCU_IPC_SET & IPC_SCP2HOST;
return ipi_op_scp2ap_is_irq_set();
}
static void ipi_wake_ap(int32_t id)
@ -53,7 +53,7 @@ static void ipi_wake_ap(int32_t id)
return;
if (*ipi_wakeup_table[id])
SCP_SCP2SPM_IPC_SET = IPC_SCP2HOST;
ipi_op_wake_ap();
}
int ipi_send(int32_t id, const void *buf, uint32_t len, int wait)
@ -105,7 +105,7 @@ int ipi_send(int32_t id, const void *buf, uint32_t len, int wait)
/* interrupt AP to handle the message */
ipi_wake_ap(id);
SCP_SCP2APMCU_IPC_SET = IPC_SCP2HOST;
ipi_op_scp2ap_irq_set();
if (wait)
while (ipi_is_busy())
@ -118,6 +118,17 @@ error:
return ret;
}
#ifndef HAVE_PRIVATE_MT_SCP
__overridable uint32_t video_get_dec_capability(void)
{
return 0;
}
__overridable uint32_t video_get_enc_capability(void)
{
return 0;
}
#endif
static void ipi_enable_deferred(void)
{
struct scp_run_t scp_run;
@ -174,9 +185,9 @@ static void irq_group7_handler(void)
{
extern volatile int ec_int;
if (SCP_GIPC_IN_SET & GIPC_IN(0)) {
if (ipi_op_ap2scp_is_irq_set()) {
ipi_handler();
SCP_GIPC_IN_CLR = GIPC_IN(0);
ipi_op_ap2scp_irq_clr();
asm volatile("fence.i" ::: "memory");
task_clear_pending_irq(ec_int);
}

View File

@ -62,6 +62,13 @@ void ipi_enable_irq(void);
extern void (*const ipi_handler_table[])(int32_t, void *, uint32_t);
extern int *const ipi_wakeup_table[];
/* IPI operations */
void ipi_op_wake_ap(void);
int ipi_op_scp2ap_is_irq_set(void);
void ipi_op_scp2ap_irq_set(void);
void ipi_op_ap2scp_irq_clr(void);
int ipi_op_ap2scp_is_irq_set(void);
/* Helper macros to build the IPI handler and wakeup functions. */
#define IPI_HANDLER(id) CONCAT3(ipi_, id, _handler)
#define IPI_WAKEUP(id) CONCAT3(ipi_, id, _wakeup)

View File

@ -0,0 +1,32 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "ipi_chip.h"
#include "registers.h"
void ipi_op_wake_ap(void)
{
SCP_SCP2SPM_IPC_SET = IPC_SCP2HOST;
}
int ipi_op_scp2ap_is_irq_set(void)
{
return SCP_SCP2APMCU_IPC_SET & IPC_SCP2HOST;
}
void ipi_op_scp2ap_irq_set(void)
{
SCP_SCP2APMCU_IPC_SET = IPC_SCP2HOST;
}
void ipi_op_ap2scp_irq_clr(void)
{
SCP_GIPC_IN_CLR = GIPC_IN(0);
}
int ipi_op_ap2scp_is_irq_set(void)
{
return SCP_GIPC_IN_SET & GIPC_IN(0);
}

View File

@ -0,0 +1,7 @@
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
REGION(dramnc_bss, rw, DRAM_NC_BASE, DRAM_NC_SIZE) /* DRAM uncached 1M-4K */
REGION(panic, !rwx, CONFIG_PANIC_DRAM_BASE, CONFIG_PANIC_DRAM_SIZE) /* panic data */
REGION(kernel, !rwx, KERNEL_BASE, KERNEL_SIZE) /* kernel allocable */

View File

@ -37,6 +37,7 @@ chip-$(CONFIG_HOST_INTERFACE_ESPI)+=espi.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_HOST_INTERFACE_SHI)+=shi.o
chip-$(CONFIG_CEC_BITBANG)+=cec_bitbang.o
chip-$(CONFIG_OTP_KEY)+=otp_key.o
# pwm functions are implemented with the fan functions
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_SPI)+=spi.o

View File

@ -40,7 +40,6 @@ static uint64_t idle_dsleep_time_us;
* Fixed amount of time to keep the console in use flag true after boot in
* order to give a permanent window in which the low speed clock is not used.
*/
#define CONSOLE_IN_USE_ON_BOOT_TIME (15 * SECOND)
static int console_in_use_timeout_sec = 15;
static timestamp_t console_expire_time;
#endif
@ -325,7 +324,8 @@ void __idle(void)
* time in order to give a fixed window on boot in which the low speed
* clock will not be used in idle.
*/
console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
console_expire_time.val =
get_time().val + CONFIG_CONSOLE_IN_USE_ON_BOOT_TIME;
while (1) {
/*

View File

@ -20,6 +20,9 @@
#include "util.h"
#include "watchdog.h"
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ##args)
#define FLASH_SYSJUMP_TAG 0x5750 /* "WP" - Write Protect */
#define FLASH_HOOK_VERSION 1
@ -182,6 +185,23 @@ static void flash_get_status(uint8_t *sr1, uint8_t *sr2)
crec_flash_lock_mapped_storage(0);
}
#ifdef NPCX_INT_FLASH_SUPPORT
static int is_int_flash_protected(void)
{
return IS_BIT_SET(NPCX_DEV_CTL4, NPCX_DEV_CTL4_WP_IF);
}
static void flash_protect_int_flash(int enable)
{
/*
* Please notice the type of WP_IF bit is R/W1S. Once it's set,
* only rebooting EC can clear it.
*/
if (enable && !is_int_flash_protected())
SET_BIT(NPCX_DEV_CTL4, NPCX_DEV_CTL4_WP_IF);
}
#endif
/* Check if Status Register Protect bit 0 is set */
static int flash_check_status_reg_srp(void)
{
@ -194,9 +214,16 @@ static int flash_check_status_reg_srp(void)
static int flash_set_status(uint8_t sr1, uint8_t sr2)
{
if (flash_check_status_reg_srp() &&
(crec_flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED)) {
return EC_ERROR_ACCESS_DENIED;
if (flash_check_status_reg_srp()) {
#ifdef NPCX_INT_FLASH_SUPPORT
if (is_int_flash_protected()) {
return EC_ERROR_ACCESS_DENIED;
}
#else
if (crec_flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED) {
return EC_ERROR_ACCESS_DENIED;
}
#endif
}
/* Lock physical flash operations */
@ -239,23 +266,6 @@ static void flash_set_quad_enable(int enable)
flash_set_status(sr1, sr2);
}
#ifdef NPCX_INT_FLASH_SUPPORT
static int is_int_flash_protected(void)
{
return IS_BIT_SET(NPCX_DEV_CTL4, NPCX_DEV_CTL4_WP_IF);
}
static void flash_protect_int_flash(int enable)
{
/*
* Please notice the type of WP_IF bit is R/W1S. Once it's set,
* only rebooting EC can clear it.
*/
if (enable && !is_int_flash_protected())
SET_BIT(NPCX_DEV_CTL4, NPCX_DEV_CTL4_WP_IF);
}
#endif
#ifdef CONFIG_HOSTCMD_FLASH_SPI_INFO
void flash_get_mfr_dev_id(uint8_t *dest)
@ -779,6 +789,50 @@ int crec_flash_pre_init(void)
* available. */
flash_set_quad_enable(0);
#ifdef NPCX_INT_FLASH_SUPPORT
/*
* Fix situation when flash protect bit (SRP0) is enabled, but the size
* of protected area is 0 or it's not possible to decode protected range
* from SR1 and SR2 registers (spi_flash_reg_to_protect() returned
* error). This situation can occur if flashing was interrupted
* e.g. flashrom was killed while reading from flash:
* http://b/328066864#comment12
*
* Status registers can be modified only when the SRP0 bit and the WP_IF
* bit (in DEV_CTL4 register) are not enabled at the same time. The
* WP_IF bit is cleared when MCU reboots, it means that once enabled,
* the bit can't be cleared by the software.
*
* The WP_IF bit is set by flash_protect_int_flash() function based on
* GPIO_WP status. In our case, the WP_IF bit is clear in RO (because we
* are after reboot), but not in RW (because it will be set later in
* this function).
*
* Clearing the status registers before the WP_IF bit is enabled avoids
* situation in which we protect status registers with size of protected
* area set to 0. We rely on other parts of the system to enable
* protection like we rely on them to enable protection when HW WP is
* enabled for the first time.
*/
if (!is_int_flash_protected()) {
uint8_t sr1, sr2;
unsigned int prot_start, prot_length;
int rv;
flash_get_status(&sr1, &sr2);
rv = spi_flash_reg_to_protect(sr1, sr2, &prot_start,
&prot_length);
if (rv || ((sr1 & SPI_FLASH_SR1_SRP0) && prot_length == 0)) {
rv = flash_set_status(0, 0);
if (rv) {
CPRINTS("Failed to clear invalid status: %d",
rv);
}
}
}
#endif
/*
* Protect status registers of internal spi-flash if WP# is active
* during ec initialization.

120
chip/npcx/otp_key.c Normal file
View File

@ -0,0 +1,120 @@
/* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* One-Time Programmable (OTP) Key */
#include "common.h"
#include "console.h"
#include "openssl/mem.h"
#include "otp_key.h"
#include "panic.h"
#include "printf.h"
#include "registers.h"
#include "rom_chip.h"
#include "system.h"
#include "task.h"
#include "trng.h"
#include "util.h"
void otp_key_init(void)
{
enum API_RETURN_STATUS_T status = API_RET_OTP_STATUS_FAIL;
status = otpi_power(true);
if (status != API_RET_OTP_STATUS_OK) {
ccprintf("ERROR! %s failed %x\n", __func__, status);
software_panic(PANIC_SW_ASSERT, task_get_current());
}
}
void otp_key_exit(void)
{
enum API_RETURN_STATUS_T status = API_RET_OTP_STATUS_FAIL;
status = otpi_power(false);
if (status != API_RET_OTP_STATUS_OK)
ccprintf("ERROR! %s failed %x\n", __func__, status);
}
enum ec_error_list otp_key_read(uint8_t *key_buffer)
{
enum API_RETURN_STATUS_T status = API_RET_OTP_STATUS_FAIL;
uint8_t i;
if (key_buffer == NULL)
return EC_ERROR_INVAL;
for (i = 0; i < OTP_KEY_SIZE_BYTES; i++) {
status = otpi_read(OTP_KEY_ADDR + i, &key_buffer[i]);
if (status != API_RET_OTP_STATUS_OK)
return EC_ERROR_UNKNOWN;
}
return EC_SUCCESS;
}
static enum ec_error_list otp_key_write(uint8_t *key_buffer)
{
enum API_RETURN_STATUS_T status = API_RET_OTP_STATUS_FAIL;
uint8_t i;
if (key_buffer == NULL)
return EC_ERROR_INVAL;
for (i = 0; i < OTP_KEY_SIZE_BYTES; i++) {
status = otpi_write(OTP_KEY_ADDR + i, key_buffer[i]);
if (status != API_RET_OTP_STATUS_OK)
return EC_ERROR_UNKNOWN;
}
return EC_SUCCESS;
}
enum ec_error_list otp_key_provision(void)
{
enum API_RETURN_STATUS_T otpi_status = API_RET_OTP_STATUS_FAIL;
enum ec_error_list ec_status = EC_ERROR_UNKNOWN;
uint8_t otp_key_buffer[OTP_KEY_SIZE_BYTES] = { 0 };
ec_status = otp_key_read(otp_key_buffer);
if (ec_status != EC_SUCCESS) {
ccprints("Failed to read OTP key with status=%d", ec_status);
return ec_status;
}
/*
* If the stored bytes are not trivial (all 0's or all 1's),
* key already written, return.
*/
if (!bytes_are_trivial(otp_key_buffer, OTP_KEY_SIZE_BYTES))
return EC_SUCCESS;
/* Otherwise, generate and write key. */
trng_init();
trng_rand_bytes(otp_key_buffer, OTP_KEY_SIZE_BYTES);
trng_exit();
if (bytes_are_trivial(otp_key_buffer, OTP_KEY_SIZE_BYTES)) {
ccprintf("ERROR! %s RNG failed!\n", __func__);
software_panic(PANIC_SW_BAD_RNG, task_get_current());
}
ec_status = otp_key_write(otp_key_buffer);
if (ec_status != EC_SUCCESS) {
ccprints("failed to write OTP key, status=%d", ec_status);
return EC_ERROR_UNKNOWN;
}
OPENSSL_cleanse(otp_key_buffer, OTP_KEY_SIZE_BYTES);
otpi_status = otpi_write_protect(OTP_KEY_ADDR, OTP_KEY_SIZE_BYTES);
if (otpi_status != API_RET_OTP_STATUS_OK) {
ccprints("failed to write protect OTP key, status=%d",
otpi_status);
return EC_ERROR_UNKNOWN;
}
return EC_SUCCESS;
}

View File

@ -6,9 +6,11 @@
#ifndef __CROS_EC_ROM_CHIP_H_
#define __CROS_EC_ROM_CHIP_H_
#include "util.h"
/******************************************************************************/
/*
* Enumerations of ROM api functions
* Enumerations of ROM API functions
*/
enum API_SIGN_OPTIONS_T {
SIGN_NO_CHECK = 0,
@ -44,33 +46,7 @@ enum API_RETURN_STATUS_T {
/******************************************************************************/
/*
* Macro functions of ROM api functions
* TODO(b/323098079): Update functions to avoid macro style
*/
#define ADDR_DOWNLOAD_FROM_FLASH (*(volatile uint32_t *)0x40)
#define download_from_flash(src_offset, dest_addr, size, sign, exe_addr, \
status) \
(((download_from_flash_ptr)ADDR_DOWNLOAD_FROM_FLASH)( \
src_offset, dest_addr, size, sign, exe_addr, status))
#define ADDR_OTPI_POWER (*(volatile uint32_t *)0x4C)
#define otpi_power(on) (((otpi_power_ptr)ADDR_OTPI_POWER)(on))
#define ADDR_OTPI_READ (*(volatile uint32_t *)0x50)
#define otpi_read(address, data) \
(((otpi_read_ptr)ADDR_OTPI_READ)(address, data))
#define ADDR_OTPI_WRITE (*(volatile uint32_t *)0x54)
#define otpi_write(address, data) \
(((otpi_write_ptr)ADDR_OTPI_WRITE)(address, data))
#define ADDR_OTPI_WRITE_PROTECT (*(volatile uint32_t *)0x5C)
#define otpi_write_protect(address, size) \
(((otpi_write_prot_ptr)ADDR_OTPI_WRITE_PROTECT)(address, size))
/******************************************************************************/
/*
* Declarations of ROM api functions
* Declarations of ROM API functions
*/
/*
@ -111,4 +87,55 @@ typedef enum API_RETURN_STATUS_T (*otpi_write_ptr)(uint32_t address,
typedef enum API_RETURN_STATUS_T (*otpi_write_prot_ptr)(uint32_t address,
uint32_t size);
/******************************************************************************/
/*
* Inline functions for ROM APIs
*/
static const volatile uint32_t *ADDR_DOWNLOAD_FROM_FLASH = (uint32_t *)0x40;
static inline void download_from_flash(uint32_t src_offset, uint32_t dest_addr,
uint32_t size,
enum API_SIGN_OPTIONS_T sign,
uint32_t exe_addr,
enum API_RETURN_STATUS_T *status)
{
((download_from_flash_ptr)*ADDR_DOWNLOAD_FROM_FLASH)(
src_offset, dest_addr, size, sign, exe_addr, status);
}
#ifndef HAS_MOCK_OTPI
static const volatile uint32_t *ADDR_OTPI_POWER = (uint32_t *)0x4C;
static inline enum API_RETURN_STATUS_T otpi_power(bool on)
{
return ((otpi_power_ptr)*ADDR_OTPI_POWER)(on);
}
static const volatile uint32_t *ADDR_OTPI_READ = (uint32_t *)0x50;
static inline enum API_RETURN_STATUS_T otpi_read(uint32_t address,
uint8_t *data)
{
return ((otpi_read_ptr)*ADDR_OTPI_READ)(address, data);
}
static const volatile uint32_t *ADDR_OTPI_WRITE = (uint32_t *)0x54;
static inline enum API_RETURN_STATUS_T otpi_write(uint32_t address,
uint8_t data)
{
return ((otpi_write_ptr)*ADDR_OTPI_WRITE)(address, data);
}
static const volatile uint32_t *ADDR_OTPI_WRITE_PROTECT = (uint32_t *)0x5C;
static inline enum API_RETURN_STATUS_T otpi_write_protect(uint32_t address,
uint32_t size)
{
return ((otpi_write_prot_ptr)*ADDR_OTPI_WRITE_PROTECT)(address, size);
}
#else
extern enum API_RETURN_STATUS_T otpi_power(bool on);
extern enum API_RETURN_STATUS_T otpi_read(uint32_t address, uint8_t *data);
extern enum API_RETURN_STATUS_T otpi_write(uint32_t address, uint8_t data);
extern enum API_RETURN_STATUS_T otpi_write_protect(uint32_t address,
uint32_t size);
#endif
#endif /* __CROS_EC_ROM_CHIP_H_ */

View File

@ -3,7 +3,18 @@
* found in the LICENSE file.
*/
/* Hardware Random Number Generator */
/*
* Deterministic Random Bit Generator (DRBG) using Nuvoton Cryptographic
* Library (NCL) APIs.
*
* Note that despite the name of this file, it is not a non-deterministic random
* bit generator (NRBG) aka true random number generator (TRNG).
*
* This DRBG follows NIST SP 800-90A Rev. 1.
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf
* and has been validated:
* https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4603
*/
#include "common.h"
#include "console.h"
@ -172,18 +183,45 @@ void npcx_trng_hw_init(void)
return;
}
/* Configure trng to generate new 128 byte random seed every N (second
* parameter) calls to NCL_DRBG->generate()
/* Disable automatic reseeding since it takes a long time and can cause
* host commands to timeout. See See b/322827873 for more details.
*
* The DRBG algorithm used is Hash_DRBG, which has a maxmium of 2^48
* requests between reseeds (reseed_interval). See NIST SP 800-90A Rev.
* 1, Section 10.1: DRBG Mechanisms Based on Hash Functions.
*
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf#page=47
*/
state_p->trng_init = NCL_DRBG->config(ctx_p, 100, false);
const uint32_t reseed_interval = UINT32_MAX;
state_p->trng_init = NCL_DRBG->config(ctx_p, reseed_interval, false);
if (state_p->trng_init != NCL_STATUS_OK) {
ccprintf("ERROR! DRBG config returned %x\r",
state_p->trng_init);
return;
}
/* NIST SP 800-90A Rev. 1 Section 8.4 states:
*
* The pseudorandom bits returned from a DRBG shall not be used for any
* application that requires a higher security strength than the DRBG is
* instantiated to support. The security strength provided in these
* returned bits is the minimum of the security strength supported by
* the DRBG and the length of the bit string returned, i.e.:
*
* Security_strength_of_output =
* min(output_length, DRBG_security_strength)
*
* A concatenation of bit strings resulting from multiple calls to a
* DRBG will not provide a security strength for the concatenated string
* that is greater than the instantiated security strength of the DRBG.
* For example, two 128-bit output strings requested from a DRBG that
* supports a 128-bit security strength cannot be concatenated to form a
* 256-bit string with a security strength of 256 bits.
*
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf#page=23
*/
state_p->trng_init = NCL_DRBG->instantiate(
ctx_p, NCL_DRBG_SECURITY_STRENGTH_128b, NULL, 0);
ctx_p, NCL_DRBG_SECURITY_STRENGTH_256b, NULL, 0);
if (state_p->trng_init != NCL_STATUS_OK) {
ccprintf("ERROR! DRBG instantiate returned %x\r",
state_p->trng_init);

View File

@ -65,16 +65,6 @@ static const struct dma_option dma_rx_option = {
*/
#define SPI_CMD_RX_TIMEOUT_US 8192
#ifdef CONFIG_SPI_PROTOCOL_V2
/*
* Offset of output parameters needs to account for pad and framing bytes and
* one last past-end byte at the end so any additional bytes clocked out by
* the AP will have a known and identifiable value.
*/
#define SPI_PROTO2_OFFSET (EC_PROTO2_RESPONSE_HEADER_BYTES + 2)
#define SPI_PROTO2_OVERHEAD \
(SPI_PROTO2_OFFSET + EC_PROTO2_RESPONSE_TRAILER_BYTES + 1)
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
/*
* Max data size for a version 3 request/response packet. This is big enough
* to handle a request/response header, flash write offset/size, and 512 bytes
@ -119,9 +109,6 @@ static uint8_t out_msg[SPI_MAX_RESPONSE_SIZE + sizeof(out_preamble) +
EC_SPI_PAST_END_LENGTH] __aligned(4) __uncached;
static uint8_t in_msg[SPI_MAX_REQUEST_SIZE] __aligned(4) __uncached;
static uint8_t enabled;
#ifdef CONFIG_SPI_PROTOCOL_V2
static struct host_cmd_handler_args args;
#endif
static struct host_packet spi_packet;
/*
@ -191,81 +178,6 @@ static int wait_for_bytes(dma_chan_t *rxdma, int needed, enum gpio_signal nss)
}
}
#ifdef CONFIG_SPI_PROTOCOL_V2
/**
* Send a reply on a given port.
*
* The format of a reply is as per the command interface, with a number of
* preamble bytes before it.
*
* The format of a reply is a sequence of bytes:
*
* <hdr> <status> <len> <msg bytes> <sum> [<preamble byte>...]
*
* The hdr byte is just a tag to indicate that the real message follows. It
* signals the end of any preamble required by the interface.
*
* The length is the entire packet size, including the header, length bytes,
* message payload, checksum, and postamble byte.
*
* The preamble is at least 2 bytes, but can be longer if the STM takes ages
* to react to the incoming message. Since we send our first byte as the AP
* sends us the command, we clearly can't send anything sensible for that
* byte. The second byte must be written to the output register just when the
* command byte is ready (I think), so we can't do anything there either.
* Any processing we do may increase this delay. That's the reason for the
* preamble.
*
* It is interesting to note that it seems to be possible to run the SPI
* interface faster than the CPU clock with this approach.
*
* We keep an eye on the NSS line - if this goes high then the transaction is
* over so there is no point in trying to send the reply.
*
* @param txdma TX DMA channel to send on
* @param status Status result to send
* @param msg_ptr Message payload to send, which normally starts
* SPI_PROTO2_OFFSET bytes into out_msg
* @param msg_len Number of message bytes to send
*/
static void reply(dma_chan_t *txdma, enum ec_status status, char *msg_ptr,
int msg_len)
{
char *msg = out_msg;
int need_copy = msg_ptr != msg + SPI_PROTO2_OFFSET;
int sum, i;
ASSERT(msg_len + SPI_PROTO2_OVERHEAD <= sizeof(out_msg));
/* Add our header bytes - the first one might not actually be sent */
msg[0] = EC_SPI_PROCESSING;
msg[1] = EC_SPI_FRAME_START;
msg[2] = status;
msg[3] = msg_len & 0xff;
/*
* Calculate the checksum; includes the status and message length bytes
* but not the pad and framing bytes since those are stripped by the AP
* driver.
*/
sum = status + msg_len;
for (i = 0; i < msg_len; i++) {
int ch = msg_ptr[i];
sum += ch;
if (need_copy)
msg[i + SPI_PROTO2_OFFSET] = ch;
}
/* Add the checksum and get ready to send */
msg[SPI_PROTO2_OFFSET + msg_len] = sum & 0xff;
msg[SPI_PROTO2_OFFSET + msg_len + 1] = EC_SPI_PAST_END;
dma_prepare_tx(&dma_tx_option, msg_len + SPI_PROTO2_OVERHEAD, msg);
/* Kick off the DMA to send the data */
dma_go(txdma);
}
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
/**
* Sends a byte over SPI without DMA
*
@ -365,44 +277,6 @@ static void check_setup_transaction_later(void)
}
}
#ifdef CONFIG_SPI_PROTOCOL_V2
/**
* Called for V2 protocol to indicate that a command has completed
*
* Some commands can continue for a while. This function is called by
* host_command when it completes.
*
*/
static void spi_send_response(struct host_cmd_handler_args *args)
{
enum ec_status result = args->result;
dma_chan_t *txdma;
/*
* If we're not processing, then the AP has already terminated the
* transaction, and won't be listening for a response.
*/
if (state != SPI_STATE_PROCESSING)
return;
/* state == SPI_STATE_PROCESSING */
if (args->response_size > args->response_max)
result = EC_RES_INVALID_RESPONSE;
/* Transmit the reply */
txdma = dma_get_channel(STM32_DMAC_SPI1_TX);
reply(txdma, result, args->response, args->response_size);
/*
* Before the state is set to SENDING, any CS de-assertion would
* set setup_transaction_later to 1.
*/
state = SPI_STATE_SENDING;
check_setup_transaction_later();
}
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
/**
* Called to send a response back to the host.
*
@ -559,54 +433,8 @@ void spi_event(enum gpio_signal signal)
return;
} else if (in_msg[0] >= EC_CMD_VERSION0) {
#ifdef CONFIG_SPI_PROTOCOL_V2
/*
* Protocol version 2
*
* TODO(crosbug.com/p/20257): Remove once kernel supports
* version 3.
*/
#ifdef CHIP_FAMILY_STM32F0
CPRINTS("WARNING: Protocol version 2 is not supported on the F0"
" line due to crosbug.com/p/31390");
#endif
args.version = in_msg[0] - EC_CMD_VERSION0;
args.command = in_msg[1];
args.params_size = in_msg[2];
/* Wait for parameters */
if (wait_for_bytes(rxdma, 3 + args.params_size, GPIO_SPI1_NSS))
goto spi_event_error;
/*
* Params are not 32-bit aligned in protocol version 2. As a
* workaround, move them to the beginning of the input buffer
* so they are aligned.
*/
if (args.params_size)
memmove(in_msg, in_msg + 3, args.params_size);
args.params = in_msg;
args.send_response = spi_send_response;
/* Allow room for the header bytes */
args.response = out_msg + SPI_PROTO2_OFFSET;
args.response_max = sizeof(out_msg) - SPI_PROTO2_OVERHEAD;
args.response_size = 0;
args.result = EC_RES_SUCCESS;
/* Move to processing state */
state = SPI_STATE_PROCESSING;
tx_status(EC_SPI_PROCESSING);
host_command_received(&args);
return;
#else /* !defined(CONFIG_SPI_PROTOCOL_V2) */
/* Protocol version 2 is deprecated. */
CPRINTS("ERROR: Protocol V2 is not supported!");
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
}
spi_event_error:
@ -733,9 +561,6 @@ enum ec_status spi_get_protocol_info(struct host_cmd_handler_args *args)
struct ec_response_get_protocol_info *r = args->response;
memset(r, 0, sizeof(*r));
#ifdef CONFIG_SPI_PROTOCOL_V2
r->protocol_versions |= BIT(2);
#endif
r->protocol_versions |= BIT(3);
r->max_request_packet_size = SPI_MAX_REQUEST_SIZE;
r->max_response_packet_size = SPI_MAX_RESPONSE_SIZE;

View File

@ -35,7 +35,7 @@ const static int batt_host_shutdown_pct = CONFIG_BATT_HOST_SHUTDOWN_PERCENTAGE;
#ifdef CONFIG_BATTERY_CUT_OFF
#ifndef CONFIG_BATTERY_CUTOFF_DELAY_US
#define CONFIG_BATTERY_CUTOFF_DELAY_US (1 * SECOND)
#define CONFIG_BATTERY_CUTOFF_DELAY_US (1500 * MSEC)
#endif
static enum battery_cutoff_states battery_cutoff_state =
@ -346,6 +346,8 @@ static const int cutoff_poll_msec = 250;
static void battery_cutoff_clear(void)
{
if (battery_cutoff_state == BATTERY_CUTOFF_STATE_SCHEDULED)
CUTOFFPRINTS("unscheduled");
battery_cutoff_state = BATTERY_CUTOFF_STATE_NORMAL;
hook_call_deferred(&pending_cutoff_deferred_data, -1);
}
@ -357,10 +359,14 @@ static int battery_cutoff_start(void)
/* Reset previous attempt */
battery_cutoff_clear();
/*
* Set BATTERY_CUTOFF_STATE_IN_PROGRESS here to ensure other
* communication with the battery will be refrained from.
*/
battery_cutoff_state = BATTERY_CUTOFF_STATE_IN_PROGRESS;
/* Send a request to the battery. */
rv = board_cut_off_battery();
if (rv == EC_RES_SUCCESS) {
battery_cutoff_state = BATTERY_CUTOFF_STATE_IN_PROGRESS;
cutoff_timeout.val = get_time().val +
CONFIG_BATTERY_CUTOFF_TIMEOUT_MSEC * MSEC;
CUTOFFPRINTS("started (timeout in %u msec)",
@ -425,24 +431,12 @@ static void pending_cutoff_deferred(void)
}
DECLARE_DEFERRED(pending_cutoff_deferred);
static void battery_on_ac_change(void)
static void ac_change(void)
{
if (extpower_is_present()) {
/* Plugged */
if (battery_cutoff_state == BATTERY_CUTOFF_STATE_SCHEDULED)
CUTOFFPRINTS("unscheduled");
battery_cutoff_clear();
}
}
DECLARE_HOOK(HOOK_AC_CHANGE, battery_on_ac_change, HOOK_PRIO_DEFAULT);
#ifdef CONFIG_CHARGE_MANAGER
static void power_supply_change(void)
{
static bool had_active_charge_port;
int port = charge_manager_get_active_charge_port();
static bool was_ac_on;
bool key = false;
CUTOFFPRINTS("AC %s", extpower_is_present() ? "on" : "off");
if (IS_ENABLED(HAS_TASK_KEYSCAN))
key = keyboard_scan_get_boot_keys() & BIT(BOOT_KEY_REFRESH);
@ -453,27 +447,36 @@ static void power_supply_change(void)
#endif
if (!key) {
/*
* Need to set had_active_charge_port also here because refresh
* boot key can be registered when the power button is released.
*/
if (port != CHARGE_PORT_NONE)
had_active_charge_port = true;
return;
}
if (port != CHARGE_PORT_NONE) {
had_active_charge_port = true;
if (key) {
/* Cancel cutoff if AC is backoff again */
hook_call_deferred(&pending_cutoff_deferred_data, -1);
CUTOFFPRINTS("backoff: P%d is active", port);
if (extpower_is_present()) {
/*
* Need to cancel cutoff here because the AC adapter may
* glitch, which appears as On->Off->On sequence.
*/
battery_cutoff_clear();
/*
* Need to set was_ac_on here because refresh boot key
* can be registered when the power button is released.
*/
was_ac_on = true;
}
return;
}
if (!had_active_charge_port) {
CUTOFFPRINTS("backoff: Haven't had active charge port");
/* Refresh key (or equivalent) is down. */
if (extpower_is_present()) {
/*
* 1. AC is (still) on. Waiting for unplug.
* 2. AC came back after cutoff is triggered (and while waiting
* for CONFIG_BATTERY_CUTOFF_DELAY_US).
*/
battery_cutoff_clear();
was_ac_on = true;
return;
}
if (!was_ac_on) {
CUTOFFPRINTS("backoff: Haven't seen AC on");
return;
}
@ -482,8 +485,8 @@ static void power_supply_change(void)
hook_call_deferred(&pending_cutoff_deferred_data,
CONFIG_BATTERY_CUTOFF_DELAY_US);
}
DECLARE_HOOK(HOOK_POWER_SUPPLY_CHANGE, power_supply_change, HOOK_PRIO_DEFAULT);
#endif
DECLARE_HOOK(HOOK_AC_CHANGE, ac_change, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_INIT, ac_change, HOOK_PRIO_DEFAULT);
static enum ec_status battery_command_cutoff(struct host_cmd_handler_args *args)
{

View File

@ -1178,9 +1178,6 @@ void pd_set_input_current_limit(int port, uint32_t max_ma,
{
struct charge_port_info charge;
if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV))
charge_reset_stable_current();
charge.current = max_ma;
charge.voltage = supply_voltage;
charge_manager_update_charge(CHARGE_SUPPLIER_PD, port, &charge);

View File

@ -128,25 +128,6 @@ struct state {
bool is_charging_progress_displayed;
} local_state;
/*
* The timestamp when the battery charging current becomes stable.
* When a new charging status happens, charger needs several seconds to
* stabilize the battery charging current.
* stable_current should be evaluated when stable_ts expired.
* stable_ts should be reset if the charger input voltage/current changes,
* or a new battery charging voltage/request happened.
* By evaluating stable_current, we can evaluate the battery's desired charging
* power desired_mw. This allow us to have a better charging efficiency by
* negotiating the most fit PDO, i.e. the PDO provides the power just enough for
* the system and battery, or the PDO with preferred voltage.
*/
STATIC_IF(CONFIG_USB_PD_PREFER_MV) timestamp_t stable_ts;
/* battery charging current evaluated after stable_ts expired */
STATIC_IF(CONFIG_USB_PD_PREFER_MV) int stable_current;
/* battery desired power in mW. This is used to negotiate the suitable PDO */
STATIC_IF(CONFIG_USB_PD_PREFER_MV) int desired_mw;
STATIC_IF_NOT(CONFIG_USB_PD_PREFER_MV) struct pd_pref_config_t pd_pref_config;
/* Is battery connected but unresponsive after precharge? */
static int battery_seems_dead;
@ -557,10 +538,6 @@ int charge_request(bool use_curr, bool is_full)
if (IS_ENABLED(CONFIG_OCPC) && r3)
return r3;
if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV) &&
(prev_volt != voltage || prev_curr != current))
charge_reset_stable_current();
prev_volt = voltage;
prev_curr = current;
@ -1206,18 +1183,6 @@ static void charger_setup(const struct charger_info *info)
prev_bp = BP_NOT_INIT;
curr.desired_input_current = get_desired_input_current(info);
if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV)) {
/* init battery desired power */
desired_mw =
curr.batt.desired_current * curr.batt.desired_voltage;
/*
* Battery charging current needs time to be stable when a
* new charge happens. Start the timer so we can evaluate the
* stable current when timeout.
*/
charge_reset_stable_current();
}
battery_level_shutdown = board_set_battery_level_shutdown();
}
@ -1301,11 +1266,6 @@ static void process_battery_present_change(const struct charger_info *info,
/* Decide on the charge state we are in */
static void decide_charge_state(int *need_staticp, int *battery_criticalp)
{
/* battery current stable now, so save the current. */
if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV) &&
get_time().val > stable_ts.val && curr.batt.current >= 0)
stable_current = curr.batt.current;
/*
* Now decide what we want to do about it. We'll normally just pass
* along whatever the battery wants to the charger. Note that if
@ -1472,54 +1432,6 @@ static void adjust_requested_vi(const struct charger_info *const info,
}
}
/* Handle selection of the preferred voltage */
static void process_preferred_voltage(void)
{
int is_pd_supply;
int port;
int bat_spec_desired_mw;
int prev_plt_and_desired_mw;
/* sjg@: Attempt to get code coverage on this function b/281109948 */
if (!IS_ENABLED(CONFIG_USB_PD_PREFER_MV))
return;
is_pd_supply = charge_manager_get_supplier() == CHARGE_SUPPLIER_PD;
port = charge_manager_get_active_charge_port();
bat_spec_desired_mw =
curr.batt.desired_current * curr.batt.desired_voltage / 1000;
/* save previous plt_and_desired_mw, since it will be updated below */
prev_plt_and_desired_mw = charge_get_plt_plus_bat_desired_mw();
/*
* Update desired power by the following rules:
* 1. If the battery is not charging with PD, we reset the desired_mw to
* the battery spec. The actual desired_mw will be evaluated when it
* starts charging with PD again.
* 2. If the battery SoC under battery's constant voltage percent (this
* is a rough value that can be applied to most batteries), the battery
* can fully sink the power, the desired power should be the same as the
* battery spec, and we don't need to use evaluated value
* stable_current.
* 3. If the battery SoC is above battery's constant voltage percent,
* the real battery desired charging power will decrease slowly and so
* does the charging current. We can evaluate the battery desired power
* by the product of stable_current and battery voltage.
*/
if (!is_pd_supply)
desired_mw = bat_spec_desired_mw;
else if (curr.batt.state_of_charge < pd_pref_config.cv)
desired_mw = bat_spec_desired_mw;
else if (stable_current != CHARGE_CURRENT_UNINITIALIZED)
desired_mw = curr.batt.voltage * stable_current / 1000;
/* if the plt_and_desired_mw changes, re-evaluate PDO */
if (is_pd_supply &&
prev_plt_and_desired_mw != charge_get_plt_plus_bat_desired_mw())
pd_set_new_power_request(port);
}
/* Calculate the sleep duration, before we run around the task loop again */
int calculate_sleep_dur(int battery_critical, int sleep_usec)
{
@ -1688,8 +1600,6 @@ void charger_task(void *u)
adjust_requested_vi(info, is_full);
process_preferred_voltage();
/* Report our state */
local_state.is_full = is_full;
@ -2071,50 +1981,6 @@ int charge_get_active_chg_chip(void)
#endif
}
#ifdef CONFIG_USB_PD_PREFER_MV
bool charge_is_current_stable(void)
{
return get_time().val >= stable_ts.val;
}
int charge_get_plt_plus_bat_desired_mw(void)
{
/*
* Ideally, the system consuming power could be evaluated by
* "IBus * VBus - battery charging power". But in practice,
* most charger drivers don't implement IBUS ADC reading,
* so we use system PLT instead as an alterntaive approach.
*/
return pd_pref_config.plt_mw + desired_mw;
}
int charge_get_stable_current(void)
{
return stable_current;
}
void charge_set_stable_current(int ma)
{
stable_current = ma;
}
void charge_reset_stable_current_us(uint64_t us)
{
timestamp_t now = get_time();
if (stable_ts.val < now.val + us)
stable_ts.val = now.val + us;
stable_current = CHARGE_CURRENT_UNINITIALIZED;
}
void charge_reset_stable_current(void)
{
/* it takes 8 to 10 seconds to stabilize battery current in practice */
charge_reset_stable_current_us(10 * SECOND);
}
#endif
#ifdef CONFIG_OCPC
void trigger_ocpc_reset(void)
{

Some files were not shown because too many files have changed in this diff Show More