diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-08 00:23:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-08 00:23:40 -0400 |
commit | 6afd563d4bbc1924b7de9e053324c007e0d36476 (patch) | |
tree | 619c2270f6f09ce8c9eb7f6aa448f07f67ffa8e8 /drivers/firmware | |
parent | b4f33f6ddd0c218e12454e1379de3aaa73f2e8dc (diff) | |
parent | d6db68b2deaa0158d25b236edffcf6dd2117208f (diff) |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann:
"Driver updates for ARM SoCs, including a couple of newly added
drivers:
- The Qualcomm external bus interface 2 (EBI2), used in some of their
mobile phone chips for connecting flash memory, LCD displays or
other peripherals
- Secure monitor firmware for Amlogic SoCs, and an NVMEM driver for
the EFUSE based on that firmware interface.
- Perf support for the AppliedMicro X-Gene performance monitor unit
- Reset driver for STMicroelectronics STM32
- Reset driver for SocioNext UniPhier SoCs
Aside from these, there are minor updates to SoC-specific bus,
clocksource, firmware, pinctrl, reset, rtc and pmic drivers"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (50 commits)
bus: qcom-ebi2: depend on HAS_IOMEM
pinctrl: mvebu: orion5x: Generalise mv88f5181l support for 88f5181
clk: mvebu: Add clk support for the orion5x SoC mv88f5181
dt-bindings: EXYNOS: Add Exynos5433 PMU compatible
clocksource: exynos_mct: Add the support for ARM64
perf: xgene: Add APM X-Gene SoC Performance Monitoring Unit driver
Documentation: Add documentation for APM X-Gene SoC PMU DTS binding
MAINTAINERS: Add entry for APM X-Gene SoC PMU driver
bus: qcom: add EBI2 driver
bus: qcom: add EBI2 device tree bindings
rtc: rtc-pm8xxx: Add support for pm8018 rtc
nvmem: amlogic: Add Amlogic Meson EFUSE driver
firmware: Amlogic: Add secure monitor driver
soc: qcom: smd: Reset rx tail rather than tx
memory: atmel-sdramc: fix a possible NULL dereference
reset: hi6220: allow to compile test driver on other architectures
reset: zynq: add driver Kconfig option
reset: sunxi: add driver Kconfig option
reset: stm32: add driver Kconfig option
reset: socfpga: add driver Kconfig option
...
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/Kconfig | 1 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/meson/Kconfig | 9 | ||||
-rw-r--r-- | drivers/firmware/meson/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/meson/meson_sm.c | 248 | ||||
-rw-r--r-- | drivers/firmware/qcom_scm.c | 19 |
6 files changed, 265 insertions, 14 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 0e22f241403b..bca172d42c74 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig | |||
@@ -209,5 +209,6 @@ config HAVE_ARM_SMCCC | |||
209 | source "drivers/firmware/broadcom/Kconfig" | 209 | source "drivers/firmware/broadcom/Kconfig" |
210 | source "drivers/firmware/google/Kconfig" | 210 | source "drivers/firmware/google/Kconfig" |
211 | source "drivers/firmware/efi/Kconfig" | 211 | source "drivers/firmware/efi/Kconfig" |
212 | source "drivers/firmware/meson/Kconfig" | ||
212 | 213 | ||
213 | endmenu | 214 | endmenu |
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 44a59dcfc398..898ac41fa8b3 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o | |||
22 | CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a | 22 | CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a |
23 | 23 | ||
24 | obj-y += broadcom/ | 24 | obj-y += broadcom/ |
25 | obj-y += meson/ | ||
25 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ | 26 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ |
26 | obj-$(CONFIG_EFI) += efi/ | 27 | obj-$(CONFIG_EFI) += efi/ |
27 | obj-$(CONFIG_UEFI_CPER) += efi/ | 28 | obj-$(CONFIG_UEFI_CPER) += efi/ |
diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig new file mode 100644 index 000000000000..170d7e8bcdfb --- /dev/null +++ b/drivers/firmware/meson/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Amlogic Secure Monitor driver | ||
3 | # | ||
4 | config MESON_SM | ||
5 | bool | ||
6 | default ARCH_MESON | ||
7 | depends on ARM64_4K_PAGES | ||
8 | help | ||
9 | Say y here to enable the Amlogic secure monitor driver | ||
diff --git a/drivers/firmware/meson/Makefile b/drivers/firmware/meson/Makefile new file mode 100644 index 000000000000..9ab3884f96bc --- /dev/null +++ b/drivers/firmware/meson/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_MESON_SM) += meson_sm.o | |||
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c new file mode 100644 index 000000000000..b0d254930ed3 --- /dev/null +++ b/drivers/firmware/meson/meson_sm.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * Amlogic Secure Monitor driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Endless Mobile, Inc. | ||
5 | * Author: Carlo Caione <carlo@endlessm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
13 | */ | ||
14 | |||
15 | #define pr_fmt(fmt) "meson-sm: " fmt | ||
16 | |||
17 | #include <linux/arm-smccc.h> | ||
18 | #include <linux/bug.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/printk.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/sizes.h> | ||
25 | |||
26 | #include <linux/firmware/meson/meson_sm.h> | ||
27 | |||
28 | struct meson_sm_cmd { | ||
29 | unsigned int index; | ||
30 | u32 smc_id; | ||
31 | }; | ||
32 | #define CMD(d, s) { .index = (d), .smc_id = (s), } | ||
33 | |||
34 | struct meson_sm_chip { | ||
35 | unsigned int shmem_size; | ||
36 | u32 cmd_shmem_in_base; | ||
37 | u32 cmd_shmem_out_base; | ||
38 | struct meson_sm_cmd cmd[]; | ||
39 | }; | ||
40 | |||
41 | struct meson_sm_chip gxbb_chip = { | ||
42 | .shmem_size = SZ_4K, | ||
43 | .cmd_shmem_in_base = 0x82000020, | ||
44 | .cmd_shmem_out_base = 0x82000021, | ||
45 | .cmd = { | ||
46 | CMD(SM_EFUSE_READ, 0x82000030), | ||
47 | CMD(SM_EFUSE_WRITE, 0x82000031), | ||
48 | CMD(SM_EFUSE_USER_MAX, 0x82000033), | ||
49 | { /* sentinel */ }, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | struct meson_sm_firmware { | ||
54 | const struct meson_sm_chip *chip; | ||
55 | void __iomem *sm_shmem_in_base; | ||
56 | void __iomem *sm_shmem_out_base; | ||
57 | }; | ||
58 | |||
59 | static struct meson_sm_firmware fw; | ||
60 | |||
61 | static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip, | ||
62 | unsigned int cmd_index) | ||
63 | { | ||
64 | const struct meson_sm_cmd *cmd = chip->cmd; | ||
65 | |||
66 | while (cmd->smc_id && cmd->index != cmd_index) | ||
67 | cmd++; | ||
68 | |||
69 | return cmd->smc_id; | ||
70 | } | ||
71 | |||
72 | static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, | ||
73 | u32 arg3, u32 arg4) | ||
74 | { | ||
75 | struct arm_smccc_res res; | ||
76 | |||
77 | arm_smccc_smc(cmd, arg0, arg1, arg2, arg3, arg4, 0, 0, &res); | ||
78 | return res.a0; | ||
79 | } | ||
80 | |||
81 | static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) | ||
82 | { | ||
83 | u32 sm_phy_base; | ||
84 | |||
85 | sm_phy_base = __meson_sm_call(cmd_shmem, 0, 0, 0, 0, 0); | ||
86 | if (!sm_phy_base) | ||
87 | return 0; | ||
88 | |||
89 | return ioremap_cache(sm_phy_base, size); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * meson_sm_call - generic SMC32 call to the secure-monitor | ||
94 | * | ||
95 | * @cmd_index: Index of the SMC32 function ID | ||
96 | * @ret: Returned value | ||
97 | * @arg0: SMC32 Argument 0 | ||
98 | * @arg1: SMC32 Argument 1 | ||
99 | * @arg2: SMC32 Argument 2 | ||
100 | * @arg3: SMC32 Argument 3 | ||
101 | * @arg4: SMC32 Argument 4 | ||
102 | * | ||
103 | * Return: 0 on success, a negative value on error | ||
104 | */ | ||
105 | int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0, | ||
106 | u32 arg1, u32 arg2, u32 arg3, u32 arg4) | ||
107 | { | ||
108 | u32 cmd, lret; | ||
109 | |||
110 | if (!fw.chip) | ||
111 | return -ENOENT; | ||
112 | |||
113 | cmd = meson_sm_get_cmd(fw.chip, cmd_index); | ||
114 | if (!cmd) | ||
115 | return -EINVAL; | ||
116 | |||
117 | lret = __meson_sm_call(cmd, arg0, arg1, arg2, arg3, arg4); | ||
118 | |||
119 | if (ret) | ||
120 | *ret = lret; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | EXPORT_SYMBOL(meson_sm_call); | ||
125 | |||
126 | /** | ||
127 | * meson_sm_call_read - retrieve data from secure-monitor | ||
128 | * | ||
129 | * @buffer: Buffer to store the retrieved data | ||
130 | * @cmd_index: Index of the SMC32 function ID | ||
131 | * @arg0: SMC32 Argument 0 | ||
132 | * @arg1: SMC32 Argument 1 | ||
133 | * @arg2: SMC32 Argument 2 | ||
134 | * @arg3: SMC32 Argument 3 | ||
135 | * @arg4: SMC32 Argument 4 | ||
136 | * | ||
137 | * Return: size of read data on success, a negative value on error | ||
138 | */ | ||
139 | int meson_sm_call_read(void *buffer, unsigned int cmd_index, u32 arg0, | ||
140 | u32 arg1, u32 arg2, u32 arg3, u32 arg4) | ||
141 | { | ||
142 | u32 size; | ||
143 | |||
144 | if (!fw.chip) | ||
145 | return -ENOENT; | ||
146 | |||
147 | if (!fw.chip->cmd_shmem_out_base) | ||
148 | return -EINVAL; | ||
149 | |||
150 | if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) | ||
151 | return -EINVAL; | ||
152 | |||
153 | if (!size || size > fw.chip->shmem_size) | ||
154 | return -EINVAL; | ||
155 | |||
156 | if (buffer) | ||
157 | memcpy(buffer, fw.sm_shmem_out_base, size); | ||
158 | |||
159 | return size; | ||
160 | } | ||
161 | EXPORT_SYMBOL(meson_sm_call_read); | ||
162 | |||
163 | /** | ||
164 | * meson_sm_call_write - send data to secure-monitor | ||
165 | * | ||
166 | * @buffer: Buffer containing data to send | ||
167 | * @size: Size of the data to send | ||
168 | * @cmd_index: Index of the SMC32 function ID | ||
169 | * @arg0: SMC32 Argument 0 | ||
170 | * @arg1: SMC32 Argument 1 | ||
171 | * @arg2: SMC32 Argument 2 | ||
172 | * @arg3: SMC32 Argument 3 | ||
173 | * @arg4: SMC32 Argument 4 | ||
174 | * | ||
175 | * Return: size of sent data on success, a negative value on error | ||
176 | */ | ||
177 | int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index, | ||
178 | u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) | ||
179 | { | ||
180 | u32 written; | ||
181 | |||
182 | if (!fw.chip) | ||
183 | return -ENOENT; | ||
184 | |||
185 | if (size > fw.chip->shmem_size) | ||
186 | return -EINVAL; | ||
187 | |||
188 | if (!fw.chip->cmd_shmem_in_base) | ||
189 | return -EINVAL; | ||
190 | |||
191 | memcpy(fw.sm_shmem_in_base, buffer, size); | ||
192 | |||
193 | if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) | ||
194 | return -EINVAL; | ||
195 | |||
196 | if (!written) | ||
197 | return -EINVAL; | ||
198 | |||
199 | return written; | ||
200 | } | ||
201 | EXPORT_SYMBOL(meson_sm_call_write); | ||
202 | |||
203 | static const struct of_device_id meson_sm_ids[] = { | ||
204 | { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, | ||
205 | { /* sentinel */ }, | ||
206 | }; | ||
207 | |||
208 | int __init meson_sm_init(void) | ||
209 | { | ||
210 | const struct meson_sm_chip *chip; | ||
211 | const struct of_device_id *matched_np; | ||
212 | struct device_node *np; | ||
213 | |||
214 | np = of_find_matching_node_and_match(NULL, meson_sm_ids, &matched_np); | ||
215 | if (!np) | ||
216 | return -ENODEV; | ||
217 | |||
218 | chip = matched_np->data; | ||
219 | if (!chip) { | ||
220 | pr_err("unable to setup secure-monitor data\n"); | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | if (chip->cmd_shmem_in_base) { | ||
225 | fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, | ||
226 | chip->shmem_size); | ||
227 | if (WARN_ON(!fw.sm_shmem_in_base)) | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | if (chip->cmd_shmem_out_base) { | ||
232 | fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, | ||
233 | chip->shmem_size); | ||
234 | if (WARN_ON(!fw.sm_shmem_out_base)) | ||
235 | goto out_in_base; | ||
236 | } | ||
237 | |||
238 | fw.chip = chip; | ||
239 | pr_info("secure-monitor enabled\n"); | ||
240 | |||
241 | return 0; | ||
242 | |||
243 | out_in_base: | ||
244 | iounmap(fw.sm_shmem_in_base); | ||
245 | out: | ||
246 | return -EINVAL; | ||
247 | } | ||
248 | device_initcall(meson_sm_init); | ||
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index e64a501adbf4..d95c70227c05 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c | |||
@@ -1,4 +1,7 @@ | |||
1 | /* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. | 1 | /* |
2 | * Qualcomm SCM driver | ||
3 | * | ||
4 | * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. | ||
2 | * Copyright (C) 2015 Linaro Ltd. | 5 | * Copyright (C) 2015 Linaro Ltd. |
3 | * | 6 | * |
4 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -12,7 +15,7 @@ | |||
12 | * | 15 | * |
13 | */ | 16 | */ |
14 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
15 | #include <linux/module.h> | 18 | #include <linux/init.h> |
16 | #include <linux/cpumask.h> | 19 | #include <linux/cpumask.h> |
17 | #include <linux/export.h> | 20 | #include <linux/export.h> |
18 | #include <linux/dma-mapping.h> | 21 | #include <linux/dma-mapping.h> |
@@ -376,8 +379,6 @@ static const struct of_device_id qcom_scm_dt_match[] = { | |||
376 | {} | 379 | {} |
377 | }; | 380 | }; |
378 | 381 | ||
379 | MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); | ||
380 | |||
381 | static struct platform_driver qcom_scm_driver = { | 382 | static struct platform_driver qcom_scm_driver = { |
382 | .driver = { | 383 | .driver = { |
383 | .name = "qcom_scm", | 384 | .name = "qcom_scm", |
@@ -414,14 +415,4 @@ static int __init qcom_scm_init(void) | |||
414 | 415 | ||
415 | return platform_driver_register(&qcom_scm_driver); | 416 | return platform_driver_register(&qcom_scm_driver); |
416 | } | 417 | } |
417 | |||
418 | subsys_initcall(qcom_scm_init); | 418 | subsys_initcall(qcom_scm_init); |
419 | |||
420 | static void __exit qcom_scm_exit(void) | ||
421 | { | ||
422 | platform_driver_unregister(&qcom_scm_driver); | ||
423 | } | ||
424 | module_exit(qcom_scm_exit); | ||
425 | |||
426 | MODULE_DESCRIPTION("Qualcomm SCM driver"); | ||
427 | MODULE_LICENSE("GPL v2"); | ||