aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Figa <t.figa@samsung.com>2012-12-10 23:58:43 -0500
committerKukjin Kim <kgene.kim@samsung.com>2013-04-08 12:52:06 -0400
commit7366b92a77fc00357294819bb495896d7482f30c (patch)
tree3e3b8293c5e86d19efdfa28069263ae87e5e1246
parentda821eb7d42935b0f7056d98c75fd1150f6636f4 (diff)
ARM: Add interface for registering and calling firmware-specific operations
Some boards are running with secure firmware running in TrustZone secure world, which changes the way some things have to be initialized. This patch adds an interface for platforms to specify available firmware operations and call them. A wrapper macro, call_firmware_op(), checks if the operation is provided and calls it if so, otherwise returns -ENOSYS to allow fallback to legacy operation.. By default no operations are provided. Example of use: In code using firmware ops: __raw_writel(virt_to_phys(exynos4_secondary_startup), CPU1_BOOT_REG); /* Call Exynos specific smc call */ if (call_firmware_op(cpu_boot, cpu) == -ENOSYS) cpu_boot_legacy(...); /* Try legacy way */ gic_raise_softirq(cpumask_of(cpu), 1); In board-/platform-specific code: static int platformX_do_idle(void) { /* tell platformX firmware to enter idle */ return 0; } static int platformX_cpu_boot(int i) { /* tell platformX firmware to boot CPU i */ return 0; } static const struct firmware_ops platformX_firmware_ops = { .do_idle = exynos_do_idle, .cpu_boot = exynos_cpu_boot, /* other operations not available on platformX */ }; static void __init board_init_early(void) { register_firmware_ops(&platformX_firmware_ops); } Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Tomasz Figa <t.figa@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--Documentation/arm/firmware.txt88
-rw-r--r--arch/arm/common/Makefile2
-rw-r--r--arch/arm/common/firmware.c18
-rw-r--r--arch/arm/include/asm/firmware.h66
4 files changed, 174 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 @@
1Interface for registering and calling firmware-specific operations for ARM.
2----
3Written by Tomasz Figa <t.figa@samsung.com>
4
5Some boards are running with secure firmware running in TrustZone secure
6world, which changes the way some things have to be initialized. This makes
7a need to provide an interface for such platforms to specify available firmware
8operations and call them when needed.
9
10Firmware 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
31and then registered with register_firmware_ops function
32
33 void register_firmware_ops(const struct firmware_ops *ops)
34
35the ops pointer must be non-NULL.
36
37There is a default, empty set of operations provided, so there is no need to
38set anything if platform does not require firmware operations.
39
40To 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
45the 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
47fallback to legacy operation).
48
49Example 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
77Example 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);
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index dc8dd0de5c0f..45f7eae93ae0 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -2,6 +2,8 @@
2# Makefile for the linux kernel. 2# Makefile for the linux kernel.
3# 3#
4 4
5obj-y += firmware.o
6
5obj-$(CONFIG_ICST) += icst.o 7obj-$(CONFIG_ICST) += icst.o
6obj-$(CONFIG_SA1111) += sa1111.o 8obj-$(CONFIG_SA1111) += sa1111.o
7obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o 9obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
diff --git a/arch/arm/common/firmware.c b/arch/arm/common/firmware.c
new file mode 100644
index 000000000000..27ddccb1131f
--- /dev/null
+++ b/arch/arm/common/firmware.c
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2012 Samsung Electronics.
3 * Kyungmin Park <kyungmin.park@samsung.com>
4 * Tomasz Figa <t.figa@samsung.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/suspend.h>
13
14#include <asm/firmware.h>
15
16static const struct firmware_ops default_firmware_ops;
17
18const struct firmware_ops *firmware_ops = &default_firmware_ops;
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h
new file mode 100644
index 000000000000..15631300c238
--- /dev/null
+++ b/arch/arm/include/asm/firmware.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2012 Samsung Electronics.
3 * Kyungmin Park <kyungmin.park@samsung.com>
4 * Tomasz Figa <t.figa@samsung.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef __ASM_ARM_FIRMWARE_H
12#define __ASM_ARM_FIRMWARE_H
13
14#include <linux/bug.h>
15
16/*
17 * struct firmware_ops
18 *
19 * A structure to specify available firmware operations.
20 *
21 * A filled up structure can be registered with register_firmware_ops().
22 */
23struct firmware_ops {
24 /*
25 * Enters CPU idle mode
26 */
27 int (*do_idle)(void);
28 /*
29 * Sets boot address of specified physical CPU
30 */
31 int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr);
32 /*
33 * Boots specified physical CPU
34 */
35 int (*cpu_boot)(int cpu);
36 /*
37 * Initializes L2 cache
38 */
39 int (*l2x0_init)(void);
40};
41
42/* Global pointer for current firmware_ops structure, can't be NULL. */
43extern const struct firmware_ops *firmware_ops;
44
45/*
46 * call_firmware_op(op, ...)
47 *
48 * Checks if firmware operation is present and calls it,
49 * otherwise returns -ENOSYS
50 */
51#define call_firmware_op(op, ...) \
52 ((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
53
54/*
55 * register_firmware_ops(ops)
56 *
57 * A function to register platform firmware_ops struct.
58 */
59static inline void register_firmware_ops(const struct firmware_ops *ops)
60{
61 BUG_ON(!ops);
62
63 firmware_ops = ops;
64}
65
66#endif