blob: efd844baec1dab30887f4a4789b64c3ce18d3acc [file] [log] [blame]
Mauro Carvalho Chehabdc7a12b2019-04-14 15:51:10 -03001==========================================================================
2Interface for registering and calling firmware-specific operations for ARM
3==========================================================================
4
Tomasz Figa7366b922012-12-11 13:58:43 +09005Written by Tomasz Figa <t.figa@samsung.com>
6
7Some boards are running with secure firmware running in TrustZone secure
8world, which changes the way some things have to be initialized. This makes
9a need to provide an interface for such platforms to specify available firmware
10operations and call them when needed.
11
Tomasz Figa9c261f82014-09-24 01:24:35 +090012Firmware operations can be specified by filling in a struct firmware_ops
13with appropriate callbacks and then registering it with register_firmware_ops()
Mauro Carvalho Chehabdc7a12b2019-04-14 15:51:10 -030014function::
Tomasz Figa7366b922012-12-11 13:58:43 +090015
16 void register_firmware_ops(const struct firmware_ops *ops)
17
Tomasz Figa9c261f82014-09-24 01:24:35 +090018The ops pointer must be non-NULL. More information about struct firmware_ops
19and its members can be found in arch/arm/include/asm/firmware.h header.
Tomasz Figa7366b922012-12-11 13:58:43 +090020
21There is a default, empty set of operations provided, so there is no need to
22set anything if platform does not require firmware operations.
23
Mauro Carvalho Chehabdc7a12b2019-04-14 15:51:10 -030024To call a firmware operation, a helper macro is provided::
Tomasz Figa7366b922012-12-11 13:58:43 +090025
26 #define call_firmware_op(op, ...) \
27 ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
28
29the macro checks if the operation is provided and calls it or otherwise returns
30-ENOSYS to signal that given operation is not available (for example, to allow
31fallback to legacy operation).
32
Mauro Carvalho Chehabdc7a12b2019-04-14 15:51:10 -030033Example of registering firmware operations::
Tomasz Figa7366b922012-12-11 13:58:43 +090034
35 /* board file */
36
37 static int platformX_do_idle(void)
38 {
39 /* tell platformX firmware to enter idle */
40 return 0;
41 }
42
43 static int platformX_cpu_boot(int i)
44 {
45 /* tell platformX firmware to boot CPU i */
46 return 0;
47 }
48
49 static const struct firmware_ops platformX_firmware_ops = {
50 .do_idle = exynos_do_idle,
51 .cpu_boot = exynos_cpu_boot,
52 /* other operations not available on platformX */
53 };
54
55 /* init_early callback of machine descriptor */
56 static void __init board_init_early(void)
57 {
58 register_firmware_ops(&platformX_firmware_ops);
59 }
60
Mauro Carvalho Chehabdc7a12b2019-04-14 15:51:10 -030061Example of using a firmware operation::
Tomasz Figa7366b922012-12-11 13:58:43 +090062
63 /* some platform code, e.g. SMP initialization */
64
Geert Uytterhoeven7673f5b2017-07-17 15:39:28 +020065 __raw_writel(__pa_symbol(exynos4_secondary_startup),
Tomasz Figa7366b922012-12-11 13:58:43 +090066 CPU1_BOOT_REG);
67
68 /* Call Exynos specific smc call */
69 if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
70 cpu_boot_legacy(...); /* Try legacy way */
71
72 gic_raise_softirq(cpumask_of(cpu), 1);