xref: /linux/Documentation/arch/arm/firmware.rst (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1*e790a4ceSJonathan Corbet==========================================================================
2*e790a4ceSJonathan CorbetInterface for registering and calling firmware-specific operations for ARM
3*e790a4ceSJonathan Corbet==========================================================================
4*e790a4ceSJonathan Corbet
5*e790a4ceSJonathan CorbetWritten by Tomasz Figa <t.figa@samsung.com>
6*e790a4ceSJonathan Corbet
7*e790a4ceSJonathan CorbetSome boards are running with secure firmware running in TrustZone secure
8*e790a4ceSJonathan Corbetworld, which changes the way some things have to be initialized. This makes
9*e790a4ceSJonathan Corbeta need to provide an interface for such platforms to specify available firmware
10*e790a4ceSJonathan Corbetoperations and call them when needed.
11*e790a4ceSJonathan Corbet
12*e790a4ceSJonathan CorbetFirmware operations can be specified by filling in a struct firmware_ops
13*e790a4ceSJonathan Corbetwith appropriate callbacks and then registering it with register_firmware_ops()
14*e790a4ceSJonathan Corbetfunction::
15*e790a4ceSJonathan Corbet
16*e790a4ceSJonathan Corbet	void register_firmware_ops(const struct firmware_ops *ops)
17*e790a4ceSJonathan Corbet
18*e790a4ceSJonathan CorbetThe ops pointer must be non-NULL. More information about struct firmware_ops
19*e790a4ceSJonathan Corbetand its members can be found in arch/arm/include/asm/firmware.h header.
20*e790a4ceSJonathan Corbet
21*e790a4ceSJonathan CorbetThere is a default, empty set of operations provided, so there is no need to
22*e790a4ceSJonathan Corbetset anything if platform does not require firmware operations.
23*e790a4ceSJonathan Corbet
24*e790a4ceSJonathan CorbetTo call a firmware operation, a helper macro is provided::
25*e790a4ceSJonathan Corbet
26*e790a4ceSJonathan Corbet	#define call_firmware_op(op, ...)				\
27*e790a4ceSJonathan Corbet		((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
28*e790a4ceSJonathan Corbet
29*e790a4ceSJonathan Corbetthe macro checks if the operation is provided and calls it or otherwise returns
30*e790a4ceSJonathan Corbet-ENOSYS to signal that given operation is not available (for example, to allow
31*e790a4ceSJonathan Corbetfallback to legacy operation).
32*e790a4ceSJonathan Corbet
33*e790a4ceSJonathan CorbetExample of registering firmware operations::
34*e790a4ceSJonathan Corbet
35*e790a4ceSJonathan Corbet	/* board file */
36*e790a4ceSJonathan Corbet
37*e790a4ceSJonathan Corbet	static int platformX_do_idle(void)
38*e790a4ceSJonathan Corbet	{
39*e790a4ceSJonathan Corbet		/* tell platformX firmware to enter idle */
40*e790a4ceSJonathan Corbet		return 0;
41*e790a4ceSJonathan Corbet	}
42*e790a4ceSJonathan Corbet
43*e790a4ceSJonathan Corbet	static int platformX_cpu_boot(int i)
44*e790a4ceSJonathan Corbet	{
45*e790a4ceSJonathan Corbet		/* tell platformX firmware to boot CPU i */
46*e790a4ceSJonathan Corbet		return 0;
47*e790a4ceSJonathan Corbet	}
48*e790a4ceSJonathan Corbet
49*e790a4ceSJonathan Corbet	static const struct firmware_ops platformX_firmware_ops = {
50*e790a4ceSJonathan Corbet		.do_idle        = exynos_do_idle,
51*e790a4ceSJonathan Corbet		.cpu_boot       = exynos_cpu_boot,
52*e790a4ceSJonathan Corbet		/* other operations not available on platformX */
53*e790a4ceSJonathan Corbet	};
54*e790a4ceSJonathan Corbet
55*e790a4ceSJonathan Corbet	/* init_early callback of machine descriptor */
56*e790a4ceSJonathan Corbet	static void __init board_init_early(void)
57*e790a4ceSJonathan Corbet	{
58*e790a4ceSJonathan Corbet		register_firmware_ops(&platformX_firmware_ops);
59*e790a4ceSJonathan Corbet	}
60*e790a4ceSJonathan Corbet
61*e790a4ceSJonathan CorbetExample of using a firmware operation::
62*e790a4ceSJonathan Corbet
63*e790a4ceSJonathan Corbet	/* some platform code, e.g. SMP initialization */
64*e790a4ceSJonathan Corbet
65*e790a4ceSJonathan Corbet	__raw_writel(__pa_symbol(exynos4_secondary_startup),
66*e790a4ceSJonathan Corbet		CPU1_BOOT_REG);
67*e790a4ceSJonathan Corbet
68*e790a4ceSJonathan Corbet	/* Call Exynos specific smc call */
69*e790a4ceSJonathan Corbet	if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
70*e790a4ceSJonathan Corbet		cpu_boot_legacy(...); /* Try legacy way */
71*e790a4ceSJonathan Corbet
72*e790a4ceSJonathan Corbet	gic_raise_softirq(cpumask_of(cpu), 1);
73