diff options
Diffstat (limited to 'Documentation/arm/firmware.txt')
-rw-r--r-- | Documentation/arm/firmware.txt | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt new file mode 100644 index 000000000000..c2e468fe7b0b --- /dev/null +++ b/Documentation/arm/firmware.txt | |||
@@ -0,0 +1,88 @@ | |||
1 | Interface for registering and calling firmware-specific operations for ARM. | ||
2 | ---- | ||
3 | Written by Tomasz Figa <t.figa@samsung.com> | ||
4 | |||
5 | Some boards are running with secure firmware running in TrustZone secure | ||
6 | world, which changes the way some things have to be initialized. This makes | ||
7 | a need to provide an interface for such platforms to specify available firmware | ||
8 | operations and call them when needed. | ||
9 | |||
10 | Firmware operations can be specified using struct firmware_ops | ||
11 | |||
12 | struct firmware_ops { | ||
13 | /* | ||
14 | * Enters CPU idle mode | ||
15 | */ | ||
16 | int (*do_idle)(void); | ||
17 | /* | ||
18 | * Sets boot address of specified physical CPU | ||
19 | */ | ||
20 | int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr); | ||
21 | /* | ||
22 | * Boots specified physical CPU | ||
23 | */ | ||
24 | int (*cpu_boot)(int cpu); | ||
25 | /* | ||
26 | * Initializes L2 cache | ||
27 | */ | ||
28 | int (*l2x0_init)(void); | ||
29 | }; | ||
30 | |||
31 | and then registered with register_firmware_ops function | ||
32 | |||
33 | void register_firmware_ops(const struct firmware_ops *ops) | ||
34 | |||
35 | the ops pointer must be non-NULL. | ||
36 | |||
37 | There is a default, empty set of operations provided, so there is no need to | ||
38 | set anything if platform does not require firmware operations. | ||
39 | |||
40 | To call a firmware operation, a helper macro is provided | ||
41 | |||
42 | #define call_firmware_op(op, ...) \ | ||
43 | ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS)) | ||
44 | |||
45 | the macro checks if the operation is provided and calls it or otherwise returns | ||
46 | -ENOSYS to signal that given operation is not available (for example, to allow | ||
47 | fallback to legacy operation). | ||
48 | |||
49 | Example of registering firmware operations: | ||
50 | |||
51 | /* board file */ | ||
52 | |||
53 | static int platformX_do_idle(void) | ||
54 | { | ||
55 | /* tell platformX firmware to enter idle */ | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int platformX_cpu_boot(int i) | ||
60 | { | ||
61 | /* tell platformX firmware to boot CPU i */ | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static const struct firmware_ops platformX_firmware_ops = { | ||
66 | .do_idle = exynos_do_idle, | ||
67 | .cpu_boot = exynos_cpu_boot, | ||
68 | /* other operations not available on platformX */ | ||
69 | }; | ||
70 | |||
71 | /* init_early callback of machine descriptor */ | ||
72 | static void __init board_init_early(void) | ||
73 | { | ||
74 | register_firmware_ops(&platformX_firmware_ops); | ||
75 | } | ||
76 | |||
77 | Example of using a firmware operation: | ||
78 | |||
79 | /* some platform code, e.g. SMP initialization */ | ||
80 | |||
81 | __raw_writel(virt_to_phys(exynos4_secondary_startup), | ||
82 | CPU1_BOOT_REG); | ||
83 | |||
84 | /* Call Exynos specific smc call */ | ||
85 | if (call_firmware_op(cpu_boot, cpu) == -ENOSYS) | ||
86 | cpu_boot_legacy(...); /* Try legacy way */ | ||
87 | |||
88 | gic_raise_softirq(cpumask_of(cpu), 1); | ||