aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-22 12:18:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-22 12:18:17 -0400
commit7d2b6ef19cf0f98cef17aa5185de3631a618710a (patch)
treed4e87f3c47837fef59ef15273f89f68b73d963af /drivers/firmware
parent5c73cc4b6c83e88863a5de869cc5df3b913aef4a (diff)
parent7415d97ee2b809119270fc3a365968ff8d4f544b (diff)
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson: "Driver updates for v4.1. Some of these are for drivers/soc, where we find more and more SoC-specific drivers these days. Some are for other driver subsystems where we have received acks from the appropriate maintainers. The larger parts of this branch are: - MediaTek support for their PMIC wrapper interface, a high-level interface for talking to the system PMIC over a dedicated I2C interface. - Qualcomm SCM driver has been moved to drivers/firmware. It's used for CPU up/down and needs to be in a shared location for arm/arm64 common code. - cleanup of ARM-CCI PMU code. - another set of cleanusp to the OMAP GPMC code" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (43 commits) soc/mediatek: Remove unused variables clocksource: atmel-st: select MFD_SYSCON soc: mediatek: Add PMIC wrapper for MT8135 and MT8173 SoCs arm-cci: Fix CCI PMU event validation arm-cci: Split the code for PMU vs driver support arm-cci: Get rid of secure transactions for PMU driver arm-cci: Abstract the CCI400 PMU specific definitions arm-cci: Rearrange code for splitting PMU vs driver code drivers: cci: reject groups spanning multiple HW PMUs ARM: at91: remove useless include clocksource: atmel-st: remove mach/hardware dependency clocksource: atmel-st: use syscon/regmap ARM: at91: time: move the system timer driver to drivers/clocksource ARM: at91: properly initialize timer ARM: at91: at91rm9200: remove deprecated arm_pm_restart watchdog: at91rm9200: implement restart handler watchdog: at91rm9200: use the system timer syscon mfd: syscon: Add atmel system timer registers definition ARM: at91/dt: declare atmel,at91rm9200-st as a syscon soc: qcom: gsbi: Add support for ADM CRCI muxing ...
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig4
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/qcom_scm.c494
3 files changed, 500 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 41983883cef4..6517132e5d8b 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -132,6 +132,10 @@ config ISCSI_IBFT
132 detect iSCSI boot parameters dynamically during system boot, say Y. 132 detect iSCSI boot parameters dynamically during system boot, say Y.
133 Otherwise, say N. 133 Otherwise, say N.
134 134
135config QCOM_SCM
136 bool
137 depends on ARM || ARM64
138
135source "drivers/firmware/google/Kconfig" 139source "drivers/firmware/google/Kconfig"
136source "drivers/firmware/efi/Kconfig" 140source "drivers/firmware/efi/Kconfig"
137 141
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 5373dc5b6011..3fdd3912709a 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_DMIID) += dmi-id.o
11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o 11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o 12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
13obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o 13obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
14obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
15CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
14 16
15obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ 17obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
16obj-$(CONFIG_EFI) += efi/ 18obj-$(CONFIG_EFI) += efi/
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
new file mode 100644
index 000000000000..994b50fd997c
--- /dev/null
+++ b/drivers/firmware/qcom_scm.c
@@ -0,0 +1,494 @@
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
2 * Copyright (C) 2015 Linaro Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301, USA.
17 */
18
19#include <linux/slab.h>
20#include <linux/io.h>
21#include <linux/module.h>
22#include <linux/mutex.h>
23#include <linux/errno.h>
24#include <linux/err.h>
25#include <linux/qcom_scm.h>
26
27#include <asm/outercache.h>
28#include <asm/cacheflush.h>
29
30
31#define QCOM_SCM_ENOMEM -5
32#define QCOM_SCM_EOPNOTSUPP -4
33#define QCOM_SCM_EINVAL_ADDR -3
34#define QCOM_SCM_EINVAL_ARG -2
35#define QCOM_SCM_ERROR -1
36#define QCOM_SCM_INTERRUPTED 1
37
38#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
39#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
40#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
41#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
42
43#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
44#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
45#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
46#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
47
48struct qcom_scm_entry {
49 int flag;
50 void *entry;
51};
52
53static struct qcom_scm_entry qcom_scm_wb[] = {
54 { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
55 { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
56 { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
57 { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
58};
59
60static DEFINE_MUTEX(qcom_scm_lock);
61
62/**
63 * struct qcom_scm_command - one SCM command buffer
64 * @len: total available memory for command and response
65 * @buf_offset: start of command buffer
66 * @resp_hdr_offset: start of response buffer
67 * @id: command to be executed
68 * @buf: buffer returned from qcom_scm_get_command_buffer()
69 *
70 * An SCM command is laid out in memory as follows:
71 *
72 * ------------------- <--- struct qcom_scm_command
73 * | command header |
74 * ------------------- <--- qcom_scm_get_command_buffer()
75 * | command buffer |
76 * ------------------- <--- struct qcom_scm_response and
77 * | response header | qcom_scm_command_to_response()
78 * ------------------- <--- qcom_scm_get_response_buffer()
79 * | response buffer |
80 * -------------------
81 *
82 * There can be arbitrary padding between the headers and buffers so
83 * you should always use the appropriate qcom_scm_get_*_buffer() routines
84 * to access the buffers in a safe manner.
85 */
86struct qcom_scm_command {
87 __le32 len;
88 __le32 buf_offset;
89 __le32 resp_hdr_offset;
90 __le32 id;
91 __le32 buf[0];
92};
93
94/**
95 * struct qcom_scm_response - one SCM response buffer
96 * @len: total available memory for response
97 * @buf_offset: start of response data relative to start of qcom_scm_response
98 * @is_complete: indicates if the command has finished processing
99 */
100struct qcom_scm_response {
101 __le32 len;
102 __le32 buf_offset;
103 __le32 is_complete;
104};
105
106/**
107 * alloc_qcom_scm_command() - Allocate an SCM command
108 * @cmd_size: size of the command buffer
109 * @resp_size: size of the response buffer
110 *
111 * Allocate an SCM command, including enough room for the command
112 * and response headers as well as the command and response buffers.
113 *
114 * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails.
115 */
116static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size)
117{
118 struct qcom_scm_command *cmd;
119 size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size +
120 resp_size;
121 u32 offset;
122
123 cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
124 if (cmd) {
125 cmd->len = cpu_to_le32(len);
126 offset = offsetof(struct qcom_scm_command, buf);
127 cmd->buf_offset = cpu_to_le32(offset);
128 cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
129 }
130 return cmd;
131}
132
133/**
134 * free_qcom_scm_command() - Free an SCM command
135 * @cmd: command to free
136 *
137 * Free an SCM command.
138 */
139static inline void free_qcom_scm_command(struct qcom_scm_command *cmd)
140{
141 kfree(cmd);
142}
143
144/**
145 * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
146 * @cmd: command
147 *
148 * Returns a pointer to a response for a command.
149 */
150static inline struct qcom_scm_response *qcom_scm_command_to_response(
151 const struct qcom_scm_command *cmd)
152{
153 return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
154}
155
156/**
157 * qcom_scm_get_command_buffer() - Get a pointer to a command buffer
158 * @cmd: command
159 *
160 * Returns a pointer to the command buffer of a command.
161 */
162static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd)
163{
164 return (void *)cmd->buf;
165}
166
167/**
168 * qcom_scm_get_response_buffer() - Get a pointer to a response buffer
169 * @rsp: response
170 *
171 * Returns a pointer to a response buffer of a response.
172 */
173static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp)
174{
175 return (void *)rsp + le32_to_cpu(rsp->buf_offset);
176}
177
178static int qcom_scm_remap_error(int err)
179{
180 pr_err("qcom_scm_call failed with error code %d\n", err);
181 switch (err) {
182 case QCOM_SCM_ERROR:
183 return -EIO;
184 case QCOM_SCM_EINVAL_ADDR:
185 case QCOM_SCM_EINVAL_ARG:
186 return -EINVAL;
187 case QCOM_SCM_EOPNOTSUPP:
188 return -EOPNOTSUPP;
189 case QCOM_SCM_ENOMEM:
190 return -ENOMEM;
191 }
192 return -EINVAL;
193}
194
195static u32 smc(u32 cmd_addr)
196{
197 int context_id;
198 register u32 r0 asm("r0") = 1;
199 register u32 r1 asm("r1") = (u32)&context_id;
200 register u32 r2 asm("r2") = cmd_addr;
201 do {
202 asm volatile(
203 __asmeq("%0", "r0")
204 __asmeq("%1", "r0")
205 __asmeq("%2", "r1")
206 __asmeq("%3", "r2")
207#ifdef REQUIRES_SEC
208 ".arch_extension sec\n"
209#endif
210 "smc #0 @ switch to secure world\n"
211 : "=r" (r0)
212 : "r" (r0), "r" (r1), "r" (r2)
213 : "r3");
214 } while (r0 == QCOM_SCM_INTERRUPTED);
215
216 return r0;
217}
218
219static int __qcom_scm_call(const struct qcom_scm_command *cmd)
220{
221 int ret;
222 u32 cmd_addr = virt_to_phys(cmd);
223
224 /*
225 * Flush the command buffer so that the secure world sees
226 * the correct data.
227 */
228 __cpuc_flush_dcache_area((void *)cmd, cmd->len);
229 outer_flush_range(cmd_addr, cmd_addr + cmd->len);
230
231 ret = smc(cmd_addr);
232 if (ret < 0)
233 ret = qcom_scm_remap_error(ret);
234
235 return ret;
236}
237
238static void qcom_scm_inv_range(unsigned long start, unsigned long end)
239{
240 u32 cacheline_size, ctr;
241
242 asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
243 cacheline_size = 4 << ((ctr >> 16) & 0xf);
244
245 start = round_down(start, cacheline_size);
246 end = round_up(end, cacheline_size);
247 outer_inv_range(start, end);
248 while (start < end) {
249 asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
250 : "memory");
251 start += cacheline_size;
252 }
253 dsb();
254 isb();
255}
256
257/**
258 * qcom_scm_call() - Send an SCM command
259 * @svc_id: service identifier
260 * @cmd_id: command identifier
261 * @cmd_buf: command buffer
262 * @cmd_len: length of the command buffer
263 * @resp_buf: response buffer
264 * @resp_len: length of the response buffer
265 *
266 * Sends a command to the SCM and waits for the command to finish processing.
267 *
268 * A note on cache maintenance:
269 * Note that any buffers that are expected to be accessed by the secure world
270 * must be flushed before invoking qcom_scm_call and invalidated in the cache
271 * immediately after qcom_scm_call returns. Cache maintenance on the command
272 * and response buffers is taken care of by qcom_scm_call; however, callers are
273 * responsible for any other cached buffers passed over to the secure world.
274 */
275static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
276 size_t cmd_len, void *resp_buf, size_t resp_len)
277{
278 int ret;
279 struct qcom_scm_command *cmd;
280 struct qcom_scm_response *rsp;
281 unsigned long start, end;
282
283 cmd = alloc_qcom_scm_command(cmd_len, resp_len);
284 if (!cmd)
285 return -ENOMEM;
286
287 cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
288 if (cmd_buf)
289 memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
290
291 mutex_lock(&qcom_scm_lock);
292 ret = __qcom_scm_call(cmd);
293 mutex_unlock(&qcom_scm_lock);
294 if (ret)
295 goto out;
296
297 rsp = qcom_scm_command_to_response(cmd);
298 start = (unsigned long)rsp;
299
300 do {
301 qcom_scm_inv_range(start, start + sizeof(*rsp));
302 } while (!rsp->is_complete);
303
304 end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len;
305 qcom_scm_inv_range(start, end);
306
307 if (resp_buf)
308 memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len);
309out:
310 free_qcom_scm_command(cmd);
311 return ret;
312}
313
314#define SCM_CLASS_REGISTER (0x2 << 8)
315#define SCM_MASK_IRQS BIT(5)
316#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
317 SCM_CLASS_REGISTER | \
318 SCM_MASK_IRQS | \
319 (n & 0xf))
320
321/**
322 * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
323 * @svc_id: service identifier
324 * @cmd_id: command identifier
325 * @arg1: first argument
326 *
327 * This shall only be used with commands that are guaranteed to be
328 * uninterruptable, atomic and SMP safe.
329 */
330static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
331{
332 int context_id;
333
334 register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
335 register u32 r1 asm("r1") = (u32)&context_id;
336 register u32 r2 asm("r2") = arg1;
337
338 asm volatile(
339 __asmeq("%0", "r0")
340 __asmeq("%1", "r0")
341 __asmeq("%2", "r1")
342 __asmeq("%3", "r2")
343#ifdef REQUIRES_SEC
344 ".arch_extension sec\n"
345#endif
346 "smc #0 @ switch to secure world\n"
347 : "=r" (r0)
348 : "r" (r0), "r" (r1), "r" (r2)
349 : "r3");
350 return r0;
351}
352
353u32 qcom_scm_get_version(void)
354{
355 int context_id;
356 static u32 version = -1;
357 register u32 r0 asm("r0");
358 register u32 r1 asm("r1");
359
360 if (version != -1)
361 return version;
362
363 mutex_lock(&qcom_scm_lock);
364
365 r0 = 0x1 << 8;
366 r1 = (u32)&context_id;
367 do {
368 asm volatile(
369 __asmeq("%0", "r0")
370 __asmeq("%1", "r1")
371 __asmeq("%2", "r0")
372 __asmeq("%3", "r1")
373#ifdef REQUIRES_SEC
374 ".arch_extension sec\n"
375#endif
376 "smc #0 @ switch to secure world\n"
377 : "=r" (r0), "=r" (r1)
378 : "r" (r0), "r" (r1)
379 : "r2", "r3");
380 } while (r0 == QCOM_SCM_INTERRUPTED);
381
382 version = r1;
383 mutex_unlock(&qcom_scm_lock);
384
385 return version;
386}
387EXPORT_SYMBOL(qcom_scm_get_version);
388
389#define QCOM_SCM_SVC_BOOT 0x1
390#define QCOM_SCM_BOOT_ADDR 0x1
391/*
392 * Set the cold/warm boot address for one of the CPU cores.
393 */
394static int qcom_scm_set_boot_addr(u32 addr, int flags)
395{
396 struct {
397 __le32 flags;
398 __le32 addr;
399 } cmd;
400
401 cmd.addr = cpu_to_le32(addr);
402 cmd.flags = cpu_to_le32(flags);
403 return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
404 &cmd, sizeof(cmd), NULL, 0);
405}
406
407/**
408 * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
409 * @entry: Entry point function for the cpus
410 * @cpus: The cpumask of cpus that will use the entry point
411 *
412 * Set the cold boot address of the cpus. Any cpu outside the supported
413 * range would be removed from the cpu present mask.
414 */
415int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
416{
417 int flags = 0;
418 int cpu;
419 int scm_cb_flags[] = {
420 QCOM_SCM_FLAG_COLDBOOT_CPU0,
421 QCOM_SCM_FLAG_COLDBOOT_CPU1,
422 QCOM_SCM_FLAG_COLDBOOT_CPU2,
423 QCOM_SCM_FLAG_COLDBOOT_CPU3,
424 };
425
426 if (!cpus || (cpus && cpumask_empty(cpus)))
427 return -EINVAL;
428
429 for_each_cpu(cpu, cpus) {
430 if (cpu < ARRAY_SIZE(scm_cb_flags))
431 flags |= scm_cb_flags[cpu];
432 else
433 set_cpu_present(cpu, false);
434 }
435
436 return qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
437}
438EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
439
440/**
441 * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
442 * @entry: Entry point function for the cpus
443 * @cpus: The cpumask of cpus that will use the entry point
444 *
445 * Set the Linux entry point for the SCM to transfer control to when coming
446 * out of a power down. CPU power down may be executed on cpuidle or hotplug.
447 */
448int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
449{
450 int ret;
451 int flags = 0;
452 int cpu;
453
454 /*
455 * Reassign only if we are switching from hotplug entry point
456 * to cpuidle entry point or vice versa.
457 */
458 for_each_cpu(cpu, cpus) {
459 if (entry == qcom_scm_wb[cpu].entry)
460 continue;
461 flags |= qcom_scm_wb[cpu].flag;
462 }
463
464 /* No change in entry function */
465 if (!flags)
466 return 0;
467
468 ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
469 if (!ret) {
470 for_each_cpu(cpu, cpus)
471 qcom_scm_wb[cpu].entry = entry;
472 }
473
474 return ret;
475}
476EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
477
478#define QCOM_SCM_CMD_TERMINATE_PC 0x2
479#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
480
481/**
482 * qcom_scm_cpu_power_down() - Power down the cpu
483 * @flags - Flags to flush cache
484 *
485 * This is an end point to power down cpu. If there was a pending interrupt,
486 * the control would return from this function, otherwise, the cpu jumps to the
487 * warm boot entry point set for this cpu upon reset.
488 */
489void qcom_scm_cpu_power_down(u32 flags)
490{
491 qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
492 flags & QCOM_SCM_FLUSH_FLAG_MASK);
493}
494EXPORT_SYMBOL(qcom_scm_cpu_power_down);