aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 16:43:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-02 16:43:38 -0400
commit3883cbb6c1bda013a3ce2dbdab7dc97c52e4a232 (patch)
tree5b69f83b049d24ac81123ac954ca8c9128e48443 /drivers/bus
parentd2033f2c1d1de2239ded15e478ddb4028f192a15 (diff)
parent1eb92b24e243085d242cf5ffd64829bba70972e1 (diff)
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC specific changes from Arnd Bergmann: "These changes are all to SoC-specific code, a total of 33 branches on 17 platforms were pulled into this. Like last time, Renesas sh-mobile is now the platform with the most changes, followed by OMAP and EXYNOS. Two new platforms, TI Keystone and Rockchips RK3xxx are added in this branch, both containing almost no platform specific code at all, since they are using generic subsystem interfaces for clocks, pinctrl, interrupts etc. The device drivers are getting merged through the respective subsystem maintainer trees. One more SoC (u300) is now multiplatform capable and several others (shmobile, exynos, msm, integrator, kirkwood, clps711x) are moving towards that goal with this series but need more work. Also noteworthy is the work on PCI here, which is traditionally part of the SoC specific code. With the changes done by Thomas Petazzoni, we can now more easily have PCI host controller drivers as loadable modules and keep them separate from the platform code in drivers/pci/host. This has already led to the discovery that three platforms (exynos, spear and imx) are actually using an identical PCIe host controller and will be able to share a driver once support for spear and imx is added." * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (480 commits) ARM: integrator: let pciv3 use mem/premem from device tree ARM: integrator: set local side PCI addresses right ARM: dts: Add pcie controller node for exynos5440-ssdk5440 ARM: dts: Add pcie controller node for Samsung EXYNOS5440 SoC ARM: EXYNOS: Enable PCIe support for Exynos5440 pci: Add PCIe driver for Samsung Exynos ARM: OMAP5: voltagedomain data: remove temporary OMAP4 voltage data ARM: keystone: Move CPU bringup code to dedicated asm file ARM: multiplatform: always pick one CPU type ARM: imx: select syscon for IMX6SL ARM: keystone: select ARM_ERRATA_798181 only for SMP ARM: imx: Synertronixx scb9328 needs to select SOC_IMX1 ARM: OMAP2+: AM43x: resolve SMP related build error dmaengine: edma: enable build for AM33XX ARM: edma: Add EDMA crossbar event mux support ARM: edma: Add DT and runtime PM support to the private EDMA API dmaengine: edma: Add TI EDMA device tree binding arm: add basic support for Rockchip RK3066a boards arm: add debug uarts for rockchip rk29xx and rk3xxx series arm: Add basic clocks for Rockchip rk3066a SoCs ...
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/Kconfig7
-rw-r--r--drivers/bus/Makefile2
-rw-r--r--drivers/bus/arm-cci.c533
3 files changed, 542 insertions, 0 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index b05ecab915c4..5286e2d333b0 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -26,4 +26,11 @@ config OMAP_INTERCONNECT
26 26
27 help 27 help
28 Driver to enable OMAP interconnect error handling driver. 28 Driver to enable OMAP interconnect error handling driver.
29
30config ARM_CCI
31 bool "ARM CCI driver support"
32 depends on ARM
33 help
34 Driver supporting the CCI cache coherent interconnect for ARM
35 platforms.
29endmenu 36endmenu
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 3c7b53c12091..670cea443802 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
7 7
8# Interconnect bus driver for OMAP SoCs. 8# Interconnect bus driver for OMAP SoCs.
9obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o 9obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
10# CCI cache coherent interconnect for ARM platforms
11obj-$(CONFIG_ARM_CCI) += arm-cci.o
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
new file mode 100644
index 000000000000..733288967d4d
--- /dev/null
+++ b/drivers/bus/arm-cci.c
@@ -0,0 +1,533 @@
1/*
2 * CCI cache coherent interconnect driver
3 *
4 * Copyright (C) 2013 ARM Ltd.
5 * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12 * kind, whether express or implied; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/arm-cci.h>
18#include <linux/io.h>
19#include <linux/module.h>
20#include <linux/of_address.h>
21#include <linux/slab.h>
22
23#include <asm/cacheflush.h>
24#include <asm/smp_plat.h>
25
26#define CCI_PORT_CTRL 0x0
27#define CCI_CTRL_STATUS 0xc
28
29#define CCI_ENABLE_SNOOP_REQ 0x1
30#define CCI_ENABLE_DVM_REQ 0x2
31#define CCI_ENABLE_REQ (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ)
32
33struct cci_nb_ports {
34 unsigned int nb_ace;
35 unsigned int nb_ace_lite;
36};
37
38enum cci_ace_port_type {
39 ACE_INVALID_PORT = 0x0,
40 ACE_PORT,
41 ACE_LITE_PORT,
42};
43
44struct cci_ace_port {
45 void __iomem *base;
46 unsigned long phys;
47 enum cci_ace_port_type type;
48 struct device_node *dn;
49};
50
51static struct cci_ace_port *ports;
52static unsigned int nb_cci_ports;
53
54static void __iomem *cci_ctrl_base;
55static unsigned long cci_ctrl_phys;
56
57struct cpu_port {
58 u64 mpidr;
59 u32 port;
60};
61
62/*
63 * Use the port MSB as valid flag, shift can be made dynamic
64 * by computing number of bits required for port indexes.
65 * Code disabling CCI cpu ports runs with D-cache invalidated
66 * and SCTLR bit clear so data accesses must be kept to a minimum
67 * to improve performance; for now shift is left static to
68 * avoid one more data access while disabling the CCI port.
69 */
70#define PORT_VALID_SHIFT 31
71#define PORT_VALID (0x1 << PORT_VALID_SHIFT)
72
73static inline void init_cpu_port(struct cpu_port *port, u32 index, u64 mpidr)
74{
75 port->port = PORT_VALID | index;
76 port->mpidr = mpidr;
77}
78
79static inline bool cpu_port_is_valid(struct cpu_port *port)
80{
81 return !!(port->port & PORT_VALID);
82}
83
84static inline bool cpu_port_match(struct cpu_port *port, u64 mpidr)
85{
86 return port->mpidr == (mpidr & MPIDR_HWID_BITMASK);
87}
88
89static struct cpu_port cpu_port[NR_CPUS];
90
91/**
92 * __cci_ace_get_port - Function to retrieve the port index connected to
93 * a cpu or device.
94 *
95 * @dn: device node of the device to look-up
96 * @type: port type
97 *
98 * Return value:
99 * - CCI port index if success
100 * - -ENODEV if failure
101 */
102static int __cci_ace_get_port(struct device_node *dn, int type)
103{
104 int i;
105 bool ace_match;
106 struct device_node *cci_portn;
107
108 cci_portn = of_parse_phandle(dn, "cci-control-port", 0);
109 for (i = 0; i < nb_cci_ports; i++) {
110 ace_match = ports[i].type == type;
111 if (ace_match && cci_portn == ports[i].dn)
112 return i;
113 }
114 return -ENODEV;
115}
116
117int cci_ace_get_port(struct device_node *dn)
118{
119 return __cci_ace_get_port(dn, ACE_LITE_PORT);
120}
121EXPORT_SYMBOL_GPL(cci_ace_get_port);
122
123static void __init cci_ace_init_ports(void)
124{
125 int port, ac, cpu;
126 u64 hwid;
127 const u32 *cell;
128 struct device_node *cpun, *cpus;
129
130 cpus = of_find_node_by_path("/cpus");
131 if (WARN(!cpus, "Missing cpus node, bailing out\n"))
132 return;
133
134 if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac)))
135 ac = of_n_addr_cells(cpus);
136
137 /*
138 * Port index look-up speeds up the function disabling ports by CPU,
139 * since the logical to port index mapping is done once and does
140 * not change after system boot.
141 * The stashed index array is initialized for all possible CPUs
142 * at probe time.
143 */
144 for_each_child_of_node(cpus, cpun) {
145 if (of_node_cmp(cpun->type, "cpu"))
146 continue;
147 cell = of_get_property(cpun, "reg", NULL);
148 if (WARN(!cell, "%s: missing reg property\n", cpun->full_name))
149 continue;
150
151 hwid = of_read_number(cell, ac);
152 cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK);
153
154 if (cpu < 0 || !cpu_possible(cpu))
155 continue;
156 port = __cci_ace_get_port(cpun, ACE_PORT);
157 if (port < 0)
158 continue;
159
160 init_cpu_port(&cpu_port[cpu], port, cpu_logical_map(cpu));
161 }
162
163 for_each_possible_cpu(cpu) {
164 WARN(!cpu_port_is_valid(&cpu_port[cpu]),
165 "CPU %u does not have an associated CCI port\n",
166 cpu);
167 }
168}
169/*
170 * Functions to enable/disable a CCI interconnect slave port
171 *
172 * They are called by low-level power management code to disable slave
173 * interfaces snoops and DVM broadcast.
174 * Since they may execute with cache data allocation disabled and
175 * after the caches have been cleaned and invalidated the functions provide
176 * no explicit locking since they may run with D-cache disabled, so normal
177 * cacheable kernel locks based on ldrex/strex may not work.
178 * Locking has to be provided by BSP implementations to ensure proper
179 * operations.
180 */
181
182/**
183 * cci_port_control() - function to control a CCI port
184 *
185 * @port: index of the port to setup
186 * @enable: if true enables the port, if false disables it
187 */
188static void notrace cci_port_control(unsigned int port, bool enable)
189{
190 void __iomem *base = ports[port].base;
191
192 writel_relaxed(enable ? CCI_ENABLE_REQ : 0, base + CCI_PORT_CTRL);
193 /*
194 * This function is called from power down procedures
195 * and must not execute any instruction that might
196 * cause the processor to be put in a quiescent state
197 * (eg wfi). Hence, cpu_relax() can not be added to this
198 * read loop to optimize power, since it might hide possibly
199 * disruptive operations.
200 */
201 while (readl_relaxed(cci_ctrl_base + CCI_CTRL_STATUS) & 0x1)
202 ;
203}
204
205/**
206 * cci_disable_port_by_cpu() - function to disable a CCI port by CPU
207 * reference
208 *
209 * @mpidr: mpidr of the CPU whose CCI port should be disabled
210 *
211 * Disabling a CCI port for a CPU implies disabling the CCI port
212 * controlling that CPU cluster. Code disabling CPU CCI ports
213 * must make sure that the CPU running the code is the last active CPU
214 * in the cluster ie all other CPUs are quiescent in a low power state.
215 *
216 * Return:
217 * 0 on success
218 * -ENODEV on port look-up failure
219 */
220int notrace cci_disable_port_by_cpu(u64 mpidr)
221{
222 int cpu;
223 bool is_valid;
224 for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
225 is_valid = cpu_port_is_valid(&cpu_port[cpu]);
226 if (is_valid && cpu_port_match(&cpu_port[cpu], mpidr)) {
227 cci_port_control(cpu_port[cpu].port, false);
228 return 0;
229 }
230 }
231 return -ENODEV;
232}
233EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu);
234
235/**
236 * cci_enable_port_for_self() - enable a CCI port for calling CPU
237 *
238 * Enabling a CCI port for the calling CPU implies enabling the CCI
239 * port controlling that CPU's cluster. Caller must make sure that the
240 * CPU running the code is the first active CPU in the cluster and all
241 * other CPUs are quiescent in a low power state or waiting for this CPU
242 * to complete the CCI initialization.
243 *
244 * Because this is called when the MMU is still off and with no stack,
245 * the code must be position independent and ideally rely on callee
246 * clobbered registers only. To achieve this we must code this function
247 * entirely in assembler.
248 *
249 * On success this returns with the proper CCI port enabled. In case of
250 * any failure this never returns as the inability to enable the CCI is
251 * fatal and there is no possible recovery at this stage.
252 */
253asmlinkage void __naked cci_enable_port_for_self(void)
254{
255 asm volatile ("\n"
256" .arch armv7-a\n"
257" mrc p15, 0, r0, c0, c0, 5 @ get MPIDR value \n"
258" and r0, r0, #"__stringify(MPIDR_HWID_BITMASK)" \n"
259" adr r1, 5f \n"
260" ldr r2, [r1] \n"
261" add r1, r1, r2 @ &cpu_port \n"
262" add ip, r1, %[sizeof_cpu_port] \n"
263
264 /* Loop over the cpu_port array looking for a matching MPIDR */
265"1: ldr r2, [r1, %[offsetof_cpu_port_mpidr_lsb]] \n"
266" cmp r2, r0 @ compare MPIDR \n"
267" bne 2f \n"
268
269 /* Found a match, now test port validity */
270" ldr r3, [r1, %[offsetof_cpu_port_port]] \n"
271" tst r3, #"__stringify(PORT_VALID)" \n"
272" bne 3f \n"
273
274 /* no match, loop with the next cpu_port entry */
275"2: add r1, r1, %[sizeof_struct_cpu_port] \n"
276" cmp r1, ip @ done? \n"
277" blo 1b \n"
278
279 /* CCI port not found -- cheaply try to stall this CPU */
280"cci_port_not_found: \n"
281" wfi \n"
282" wfe \n"
283" b cci_port_not_found \n"
284
285 /* Use matched port index to look up the corresponding ports entry */
286"3: bic r3, r3, #"__stringify(PORT_VALID)" \n"
287" adr r0, 6f \n"
288" ldmia r0, {r1, r2} \n"
289" sub r1, r1, r0 @ virt - phys \n"
290" ldr r0, [r0, r2] @ *(&ports) \n"
291" mov r2, %[sizeof_struct_ace_port] \n"
292" mla r0, r2, r3, r0 @ &ports[index] \n"
293" sub r0, r0, r1 @ virt_to_phys() \n"
294
295 /* Enable the CCI port */
296" ldr r0, [r0, %[offsetof_port_phys]] \n"
297" mov r3, #"__stringify(CCI_ENABLE_REQ)" \n"
298" str r3, [r0, #"__stringify(CCI_PORT_CTRL)"] \n"
299
300 /* poll the status reg for completion */
301" adr r1, 7f \n"
302" ldr r0, [r1] \n"
303" ldr r0, [r0, r1] @ cci_ctrl_base \n"
304"4: ldr r1, [r0, #"__stringify(CCI_CTRL_STATUS)"] \n"
305" tst r1, #1 \n"
306" bne 4b \n"
307
308" mov r0, #0 \n"
309" bx lr \n"
310
311" .align 2 \n"
312"5: .word cpu_port - . \n"
313"6: .word . \n"
314" .word ports - 6b \n"
315"7: .word cci_ctrl_phys - . \n"
316 : :
317 [sizeof_cpu_port] "i" (sizeof(cpu_port)),
318#ifndef __ARMEB__
319 [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)),
320#else
321 [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)+4),
322#endif
323 [offsetof_cpu_port_port] "i" (offsetof(struct cpu_port, port)),
324 [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)),
325 [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)),
326 [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) );
327
328 unreachable();
329}
330
331/**
332 * __cci_control_port_by_device() - function to control a CCI port by device
333 * reference
334 *
335 * @dn: device node pointer of the device whose CCI port should be
336 * controlled
337 * @enable: if true enables the port, if false disables it
338 *
339 * Return:
340 * 0 on success
341 * -ENODEV on port look-up failure
342 */
343int notrace __cci_control_port_by_device(struct device_node *dn, bool enable)
344{
345 int port;
346
347 if (!dn)
348 return -ENODEV;
349
350 port = __cci_ace_get_port(dn, ACE_LITE_PORT);
351 if (WARN_ONCE(port < 0, "node %s ACE lite port look-up failure\n",
352 dn->full_name))
353 return -ENODEV;
354 cci_port_control(port, enable);
355 return 0;
356}
357EXPORT_SYMBOL_GPL(__cci_control_port_by_device);
358
359/**
360 * __cci_control_port_by_index() - function to control a CCI port by port index
361 *
362 * @port: port index previously retrieved with cci_ace_get_port()
363 * @enable: if true enables the port, if false disables it
364 *
365 * Return:
366 * 0 on success
367 * -ENODEV on port index out of range
368 * -EPERM if operation carried out on an ACE PORT
369 */
370int notrace __cci_control_port_by_index(u32 port, bool enable)
371{
372 if (port >= nb_cci_ports || ports[port].type == ACE_INVALID_PORT)
373 return -ENODEV;
374 /*
375 * CCI control for ports connected to CPUS is extremely fragile
376 * and must be made to go through a specific and controlled
377 * interface (ie cci_disable_port_by_cpu(); control by general purpose
378 * indexing is therefore disabled for ACE ports.
379 */
380 if (ports[port].type == ACE_PORT)
381 return -EPERM;
382
383 cci_port_control(port, enable);
384 return 0;
385}
386EXPORT_SYMBOL_GPL(__cci_control_port_by_index);
387
388static const struct cci_nb_ports cci400_ports = {
389 .nb_ace = 2,
390 .nb_ace_lite = 3
391};
392
393static const struct of_device_id arm_cci_matches[] = {
394 {.compatible = "arm,cci-400", .data = &cci400_ports },
395 {},
396};
397
398static const struct of_device_id arm_cci_ctrl_if_matches[] = {
399 {.compatible = "arm,cci-400-ctrl-if", },
400 {},
401};
402
403static int __init cci_probe(void)
404{
405 struct cci_nb_ports const *cci_config;
406 int ret, i, nb_ace = 0, nb_ace_lite = 0;
407 struct device_node *np, *cp;
408 struct resource res;
409 const char *match_str;
410 bool is_ace;
411
412 np = of_find_matching_node(NULL, arm_cci_matches);
413 if (!np)
414 return -ENODEV;
415
416 cci_config = of_match_node(arm_cci_matches, np)->data;
417 if (!cci_config)
418 return -ENODEV;
419
420 nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite;
421
422 ports = kcalloc(sizeof(*ports), nb_cci_ports, GFP_KERNEL);
423 if (!ports)
424 return -ENOMEM;
425
426 ret = of_address_to_resource(np, 0, &res);
427 if (!ret) {
428 cci_ctrl_base = ioremap(res.start, resource_size(&res));
429 cci_ctrl_phys = res.start;
430 }
431 if (ret || !cci_ctrl_base) {
432 WARN(1, "unable to ioremap CCI ctrl\n");
433 ret = -ENXIO;
434 goto memalloc_err;
435 }
436
437 for_each_child_of_node(np, cp) {
438 if (!of_match_node(arm_cci_ctrl_if_matches, cp))
439 continue;
440
441 i = nb_ace + nb_ace_lite;
442
443 if (i >= nb_cci_ports)
444 break;
445
446 if (of_property_read_string(cp, "interface-type",
447 &match_str)) {
448 WARN(1, "node %s missing interface-type property\n",
449 cp->full_name);
450 continue;
451 }
452 is_ace = strcmp(match_str, "ace") == 0;
453 if (!is_ace && strcmp(match_str, "ace-lite")) {
454 WARN(1, "node %s containing invalid interface-type property, skipping it\n",
455 cp->full_name);
456 continue;
457 }
458
459 ret = of_address_to_resource(cp, 0, &res);
460 if (!ret) {
461 ports[i].base = ioremap(res.start, resource_size(&res));
462 ports[i].phys = res.start;
463 }
464 if (ret || !ports[i].base) {
465 WARN(1, "unable to ioremap CCI port %d\n", i);
466 continue;
467 }
468
469 if (is_ace) {
470 if (WARN_ON(nb_ace >= cci_config->nb_ace))
471 continue;
472 ports[i].type = ACE_PORT;
473 ++nb_ace;
474 } else {
475 if (WARN_ON(nb_ace_lite >= cci_config->nb_ace_lite))
476 continue;
477 ports[i].type = ACE_LITE_PORT;
478 ++nb_ace_lite;
479 }
480 ports[i].dn = cp;
481 }
482
483 /* initialize a stashed array of ACE ports to speed-up look-up */
484 cci_ace_init_ports();
485
486 /*
487 * Multi-cluster systems may need this data when non-coherent, during
488 * cluster power-up/power-down. Make sure it reaches main memory.
489 */
490 sync_cache_w(&cci_ctrl_base);
491 sync_cache_w(&cci_ctrl_phys);
492 sync_cache_w(&ports);
493 sync_cache_w(&cpu_port);
494 __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports);
495 pr_info("ARM CCI driver probed\n");
496 return 0;
497
498memalloc_err:
499
500 kfree(ports);
501 return ret;
502}
503
504static int cci_init_status = -EAGAIN;
505static DEFINE_MUTEX(cci_probing);
506
507static int __init cci_init(void)
508{
509 if (cci_init_status != -EAGAIN)
510 return cci_init_status;
511
512 mutex_lock(&cci_probing);
513 if (cci_init_status == -EAGAIN)
514 cci_init_status = cci_probe();
515 mutex_unlock(&cci_probing);
516 return cci_init_status;
517}
518
519/*
520 * To sort out early init calls ordering a helper function is provided to
521 * check if the CCI driver has beed initialized. Function check if the driver
522 * has been initialized, if not it calls the init function that probes
523 * the driver and updates the return value.
524 */
525bool __init cci_probed(void)
526{
527 return cci_init() == 0;
528}
529EXPORT_SYMBOL_GPL(cci_probed);
530
531early_initcall(cci_init);
532MODULE_LICENSE("GPL");
533MODULE_DESCRIPTION("ARM CCI support");