| /* Copyright 2013 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. | |
| */ | |
| /* System hooks for Chrome EC */ | |
| #ifndef __CROS_EC_HOOKS_H | |
| #define __CROS_EC_HOOKS_H | |
| #include "common.h" | |
| enum hook_priority { | |
| /* Generic values across all hooks */ | |
| HOOK_PRIO_FIRST = 1, /* Highest priority */ | |
| HOOK_PRIO_DEFAULT = 5000, /* Default priority */ | |
| HOOK_PRIO_LAST = 9999, /* Lowest priority */ | |
| /* Specific hook vales for HOOK_INIT */ | |
| /* DMA inits before ADC, I2C, SPI */ | |
| HOOK_PRIO_INIT_DMA = HOOK_PRIO_FIRST + 1, | |
| /* LPC inits before modules which need memory-mapped I/O */ | |
| HOOK_PRIO_INIT_LPC = HOOK_PRIO_FIRST + 1, | |
| /* | |
| * I2C dependents (battery, sensors, etc), everything but the | |
| * controllers. I2C controller is now initialized in main.c | |
| * TODO(b/138384267): Split this hook up and name the resulting | |
| * ones more semantically. | |
| */ | |
| HOOK_PRIO_INIT_I2C = HOOK_PRIO_FIRST + 2, | |
| /* Chipset inits before modules which need to know its initial state. */ | |
| HOOK_PRIO_INIT_CHIPSET = HOOK_PRIO_FIRST + 3, | |
| /* Lid switch inits before power button */ | |
| HOOK_PRIO_INIT_LID = HOOK_PRIO_FIRST + 4, | |
| /* Power button inits before chipset and switch */ | |
| HOOK_PRIO_INIT_POWER_BUTTON = HOOK_PRIO_FIRST + 5, | |
| /* Init switch states after power button / lid */ | |
| HOOK_PRIO_INIT_SWITCH = HOOK_PRIO_FIRST + 6, | |
| /* Init fan before PWM */ | |
| HOOK_PRIO_INIT_FAN = HOOK_PRIO_FIRST + 7, | |
| /* PWM inits before modules which might use it (LEDs) */ | |
| HOOK_PRIO_INIT_PWM = HOOK_PRIO_FIRST + 8, | |
| /* SPI inits before modules which might use it (sensors) */ | |
| HOOK_PRIO_INIT_SPI = HOOK_PRIO_FIRST + 9, | |
| /* Extpower inits before modules which might use it (battery, LEDs) */ | |
| HOOK_PRIO_INIT_EXTPOWER = HOOK_PRIO_FIRST + 10, | |
| /* Init VBOOT hash later, since it depends on deferred functions */ | |
| HOOK_PRIO_INIT_VBOOT_HASH = HOOK_PRIO_FIRST + 11, | |
| /* Init charge manager before usage in board init */ | |
| HOOK_PRIO_CHARGE_MANAGER_INIT = HOOK_PRIO_FIRST + 12, | |
| HOOK_PRIO_INIT_ADC = HOOK_PRIO_DEFAULT, | |
| HOOK_PRIO_INIT_DAC = HOOK_PRIO_DEFAULT, | |
| /* Specific values to lump temperature-related hooks together */ | |
| HOOK_PRIO_TEMP_SENSOR = 6000, | |
| /* After all sensors have been polled */ | |
| HOOK_PRIO_TEMP_SENSOR_DONE = HOOK_PRIO_TEMP_SENSOR + 1, | |
| }; | |
| enum hook_type { | |
| /* | |
| * System initialization. | |
| * | |
| * Hook routines are called from main(), after all hard-coded inits, | |
| * before task scheduling is enabled. | |
| */ | |
| HOOK_INIT = 0, | |
| /* | |
| * System clock changed frequency. | |
| * | |
| * The "pre" frequency hook is called before we change the frequency. | |
| * There is no way to cancel. Hook routines are always called from | |
| * a task, so it's OK to lock a mutex here. However, they may be called | |
| * from a deferred task on some platforms so callbacks must make sure | |
| * not to do anything that would require some other deferred task to | |
| * run. | |
| */ | |
| HOOK_PRE_FREQ_CHANGE, | |
| HOOK_FREQ_CHANGE, | |
| /* | |
| * About to jump to another image. Modules which need to preserve data | |
| * across such a jump should save it here and restore it in HOOK_INIT. | |
| * | |
| * Hook routines are called from the context which initiates the jump, | |
| * WITH INTERRUPTS DISABLED. | |
| */ | |
| HOOK_SYSJUMP, | |
| /* | |
| * Initialization for components such as PMU to be done before host | |
| * chipset/AP starts up. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_PRE_INIT, | |
| /* System is starting up. All suspend rails are now on. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_STARTUP, | |
| /* | |
| * System is resuming from suspend, or booting and has reached the | |
| * point where all voltage rails are on. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_RESUME, | |
| /* | |
| * System is suspending, or shutting down; all voltage rails are still | |
| * on. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_SUSPEND, | |
| #ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK | |
| /* | |
| * Initialization before the system resumes, like enabling the SPI | |
| * driver such that it can receive a host resume event. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_RESUME_INIT, | |
| /* | |
| * System has suspended. It is paired with CHIPSET_RESUME_INIT hook, | |
| * like reverting the initialization of the SPI driver. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_SUSPEND_COMPLETE, | |
| #endif | |
| /* | |
| * System is shutting down. All suspend rails are still on. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_SHUTDOWN, | |
| /* | |
| * System has already shut down. All the suspend rails are already off. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_SHUTDOWN_COMPLETE, | |
| /* | |
| * System reset in S0. All rails are still up. | |
| * | |
| * Hook routines are called from the chipset task. | |
| */ | |
| HOOK_CHIPSET_RESET, | |
| /* | |
| * AC power plugged in or removed. | |
| * | |
| * Hook routines are called from the TICK task. | |
| */ | |
| HOOK_AC_CHANGE, | |
| /* | |
| * Lid opened or closed. Based on debounced lid state, not raw lid | |
| * GPIO input. | |
| * | |
| * Hook routines are called from the TICK task. | |
| */ | |
| HOOK_LID_CHANGE, | |
| /* | |
| * Device in tablet mode (base behind lid). | |
| * | |
| * Hook routines are called from the TICK task. | |
| */ | |
| HOOK_TABLET_MODE_CHANGE, | |
| /* | |
| * Detachable device connected to a base. | |
| * | |
| * Hook routines are called from the TICK task. | |
| */ | |
| HOOK_BASE_ATTACHED_CHANGE, | |
| /* | |
| * Power button pressed or released. Based on debounced power button | |
| * state, not raw GPIO input. | |
| * | |
| * Hook routines are called from the TICK task. | |
| */ | |
| HOOK_POWER_BUTTON_CHANGE, | |
| /* | |
| * Battery state of charge changed | |
| * | |
| * Hook routines are called from the charger task. | |
| */ | |
| HOOK_BATTERY_SOC_CHANGE, | |
| #ifdef CONFIG_USB_SUSPEND | |
| /* | |
| * Called when there is a change in USB power management status | |
| * (suspended or resumed). | |
| * | |
| * Hook routines are called from HOOKS task. | |
| */ | |
| HOOK_USB_PM_CHANGE, | |
| #endif | |
| /* | |
| * Periodic tick, every HOOK_TICK_INTERVAL. | |
| * | |
| * Hook routines will be called from the TICK task. | |
| */ | |
| HOOK_TICK, | |
| /* | |
| * Periodic tick, every second. | |
| * | |
| * Hook routines will be called from the TICK task. | |
| */ | |
| HOOK_SECOND, | |
| /* | |
| * USB PD cc disconnect event. | |
| */ | |
| HOOK_USB_PD_DISCONNECT, | |
| /* | |
| * USB PD cc connection event. | |
| */ | |
| HOOK_USB_PD_CONNECT, | |
| #ifdef TEST_BUILD | |
| /* | |
| * Special hook types to be used by unit tests of the hooks | |
| * implementation only. | |
| */ | |
| HOOK_TEST_1, | |
| HOOK_TEST_2, | |
| HOOK_TEST_3, | |
| #endif /* TEST_BUILD */ | |
| /* | |
| * Not a hook type (instead the number of hooks). This should | |
| * always be placed at the end of this enumeration. | |
| */ | |
| HOOK_TYPE_COUNT, | |
| }; | |
| struct hook_data { | |
| /* Hook processing routine. */ | |
| void (*routine)(void); | |
| /* Priority; low numbers = higher priority. */ | |
| int priority; | |
| }; | |
| /** | |
| * Call all the hook routines of a specified type. | |
| * | |
| * This function must be called from the correct type-specific context (task); | |
| * see enum hook_type for details. hook_notify() should NEVER be called from | |
| * interrupt context unless specifically allowed for a hook type, because hook | |
| * routines may need to perform task-level calls like usleep() and mutex | |
| * operations that are not valid in interrupt context. Instead of calling a | |
| * hook from interrupt context, use a deferred function. | |
| * | |
| * @param type Type of hook routines to call. | |
| */ | |
| void hook_notify(enum hook_type type); | |
| /* | |
| * CONFIG_PLATFORM_EC_HOOKS is enabled by default during a Zephyr | |
| * build, but can be disabled via Kconfig if desired (leaving the stub | |
| * implementation at the bottom of this file). | |
| */ | |
| #if defined(CONFIG_PLATFORM_EC_HOOKS) | |
| #include "zephyr_hooks_shim.h" | |
| #elif defined(CONFIG_COMMON_RUNTIME) | |
| struct deferred_data { | |
| /* Deferred function pointer */ | |
| void (*routine)(void); | |
| }; | |
| /** | |
| * Start a timer to call a deferred routine. | |
| * | |
| * The routine will be called after at least the specified delay, in the | |
| * context of the hook task. | |
| * | |
| * @param data The deferred_data struct created by invoking DECLARE_DEFERRED(). | |
| * @param us Delay in microseconds until routine will be called. If the | |
| * routine is already pending, subsequent calls will change the | |
| * delay. Pass us=0 to call as soon as possible, or -1 to cancel | |
| * the deferred call. | |
| * | |
| * @return non-zero if error. | |
| */ | |
| int hook_call_deferred(const struct deferred_data *data, int us); | |
| /** | |
| * Register a hook routine. | |
| * | |
| * NOTE: Hook routines must be careful not to leave resources locked which may | |
| * be needed by other hook routines or deferred function calls. This can cause | |
| * a deadlock, because most hooks and all deferred functions are called from | |
| * the same hook task. For example: | |
| * | |
| * hook1(): lock foo | |
| * deferred1(): lock foo, use foo, unlock foo | |
| * hook2(): unlock foo | |
| * | |
| * In this example, hook1() and hook2() lock and unlock a shared resource foo | |
| * (for example, a mutex). If deferred1() attempts to lock the resource, it | |
| * will stall waiting for the resource to be unlocked. But the unlock will | |
| * never happen, because hook2() won't be called by the hook task until | |
| * deferred1() returns. | |
| * | |
| * @param hooktype Type of hook for routine (enum hook_type) | |
| * @param routine Hook routine, with prototype void routine(void) | |
| * @param priority Priority for determining when routine is called vs. | |
| * other hook routines; should be between HOOK_PRIO_FIRST | |
| * and HOOK_PRIO_LAST, and should be HOOK_PRIO_DEFAULT | |
| * unless there's a compelling reason to care about the | |
| * order in which hooks are called. | |
| */ | |
| #define DECLARE_HOOK(hooktype, routine, priority) \ | |
| const struct hook_data __keep __no_sanitize_address \ | |
| CONCAT4(__hook_, hooktype, _, routine) \ | |
| __attribute__((section(".rodata." STRINGIFY(hooktype)))) \ | |
| = {routine, priority} | |
| /** | |
| * Register a deferred function call. | |
| * | |
| * DECLARE_DEFERRED creates a new deferred_data struct with a name constructed | |
| * by concatenating _data to the name of the routine passed. | |
| * | |
| * To call a deferred routine defined as: | |
| * DECLARE_DEFERRED(foo) | |
| * You would call | |
| * hook_call_deferred(&foo_data, delay_in_microseconds); | |
| * | |
| * NOTE: Deferred function call routines must be careful not to leave resources | |
| * locked which may be needed by other hook routines or deferred function | |
| * calls. This can cause a deadlock, because most hooks and all deferred | |
| * functions are called from the same hook task. See DECLARE_HOOK() for an | |
| * example. | |
| * | |
| * @param routine Function pointer, with prototype void routine(void) | |
| */ | |
| #define DECLARE_DEFERRED(routine) \ | |
| const struct deferred_data __keep __no_sanitize_address \ | |
| CONCAT2(routine, _data) \ | |
| __attribute__((section(".rodata.deferred"))) \ | |
| = {routine} | |
| #else | |
| /* | |
| * Stub implementation in case hooks are disabled (neither | |
| * CONFIG_COMMON_RUNTIME nor CONFIG_PLATFORM_EC_HOOKS is defined) | |
| */ | |
| #define hook_call_deferred(unused1, unused2) -1 | |
| #define DECLARE_HOOK(t, func, p) \ | |
| void CONCAT2(unused_hook_, func)(void) { func(); } | |
| #define DECLARE_DEFERRED(func) \ | |
| void CONCAT2(unused_deferred_, func)(void) { func(); } | |
| #endif | |
| #endif /* __CROS_EC_HOOKS_H */ |