blob: ab375ff770743f21ffed3800a551113f0a18ade0 [file] [log] [blame]
/* Copyright 2013 The ChromiumOS Authors
* 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 is in G3. All power rails are now turned off.
*
* Hook routines are called from the chipset task.
*/
HOOK_CHIPSET_HARD_OFF,
/*
* 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 */