summaryrefslogtreecommitdiff
path: root/include/hooks.h
blob: 5c699f9555ac02773d2c67b85f8baf96e60772b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* 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,

	/* 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,

	/*
	 * System is shutting down.  All suspend rails are still on.
	 *
	 * Hook routines are called from the chipset task.
	 */
	HOOK_CHIPSET_SHUTDOWN,

	/*
	 * 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_CASE_CLOSED_DEBUG_V1
	/*
	 * Case-closed debugging configuration changed.
	 *
	 * Hook routines are called from the TICK, console, or TPM task.
	 */
	HOOK_CCD_CHANGE,
#endif

#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.
	 *
	 * CC lines and VBus are stable when this hook is called.
	 */
	HOOK_USB_PD_CONNECT,
};

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);

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);

#ifdef CONFIG_COMMON_RUNTIME
/**
 * 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 /* CONFIG_COMMON_RUNTIME */
#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 /* CONFIG_COMMON_RUNTIME */

#endif  /* __CROS_EC_HOOKS_H */