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.sh75f10d98f0
Dita: Update thermal table81ad5ebbcb
usbpd: Move EC_CMD_PD_CONTROL and support func to common source6961adf3bf
buccaneer: Add buccaneer and *-druid to getversion.she6f8ab81b0
util/getversion.sh: Change case to align with style guide33e27683c8
helipilot: Add extra repo version strings94fa496082
Keyboard: Check FIFO size only if MKBP keyboard is enabled2873bbe48b
charge: drop CONFIG_USB_PD_PREFER_MV98f881b323
Dita: Enable HDMI CEC power on93c90d42df
isl9238c: Add option to set input voltage register33578112d8
config: add CONFIG_CONSOLE_IN_USE_ON_BOOT_TIMEdedf09ebbf
Dexi: Enable HDMI CEC power on46881a0cbd
pe: Move pd_set_input_curret_limit to pe_snk_transition_sink_run684955f9b5
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:
commit
cc1b9851b6
|
@ -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*/**"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -44,6 +44,7 @@ test-list-y = \
|
|||
mpu \
|
||||
mutex \
|
||||
mutex_trylock \
|
||||
mutex_recursive \
|
||||
panic \
|
||||
panic_data \
|
||||
pingpong \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -44,6 +44,8 @@ test-list-y = \
|
|||
mpu \
|
||||
mutex \
|
||||
mutex_trylock \
|
||||
mutex_recursive \
|
||||
otp_key \
|
||||
panic \
|
||||
panic_data \
|
||||
pingpong \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# MT8188 / Geralt SCP
|
||||
fshao@chromium.org
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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)
|
|
@ -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,
|
||||
},
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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))
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
|
@ -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
|
||||
*/
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,3 @@
|
|||
<!-- Add VIF field overrides here. See genvif.c and the Vendor Info File
|
||||
Definition from the USB-IF.
|
||||
-->
|
|
@ -0,0 +1,2 @@
|
|||
# MT8188 / Geralt SCP
|
||||
fshao@chromium.org
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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 .
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -45,6 +45,7 @@ test-list-y=\
|
|||
mpu \
|
||||
mutex \
|
||||
mutex_trylock \
|
||||
mutex_recursive \
|
||||
panic \
|
||||
panic_data \
|
||||
pingpong \
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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)
|
|
@ -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,
|
||||
},
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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 */
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,3 @@
|
|||
<!-- Add VIF field overrides here. See genvif.c and the Vendor Info File
|
||||
Definition from the USB-IF.
|
||||
-->
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#undef CONFIG_HIBERNATE_PSL
|
||||
|
||||
#define CONFIG_USB_PD_PORT_MAX_COUNT 1
|
||||
|
||||
/* USB-A config */
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# MT8188 / Geralt SCP
|
||||
fshao@chromium.org
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
/*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
175
chip/stm32/spi.c
175
chip/stm32/spi.c
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue