aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Herring <rob.herring@calxeda.com>2011-08-03 13:12:05 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-10-17 04:11:30 -0400
commit8c369264b6de3b2ab796f330a4d85770a6b8b033 (patch)
treed0982a16d310ce24858107db2847c7ff326d5b1d
parentd0a77454c70d0449a5f87087deb8f0cb15145e90 (diff)
ARM: 7009/1: l2x0: Add OF based initialization
This adds probing for ARM L2x0 cache controllers via device tree. Support includes the L210, L220, and PL310 controllers. The binding allows setting up cache RAM latencies and filter addresses (PL310 only). Signed-off-by: Rob Herring <rob.herring@calxeda.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Olof Johansson <olof@lixom.net> Acked-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--Documentation/devicetree/bindings/arm/l2cc.txt42
-rw-r--r--arch/arm/include/asm/hardware/cache-l2x0.h17
-rw-r--r--arch/arm/mm/cache-l2x0.c103
3 files changed, 162 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
new file mode 100644
index 000000000000..f50e021a0998
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -0,0 +1,42 @@
1* ARM L2 Cache Controller
2
3ARM cores often have a separate level 2 cache controller. There are various
4implementations of the L2 cache controller with compatible programming models.
5The ARM L2 cache representation in the device tree should be done as follows:
6
7Required properties:
8
9- compatible : should be one of:
10 "arm,pl310-cache"
11 "arm,l220-cache"
12 "arm,l210-cache"
13- cache-unified : Specifies the cache is a unified cache.
14- cache-level : Should be set to 2 for a level 2 cache.
15- reg : Physical base address and size of cache controller's memory mapped
16 registers.
17
18Optional properties:
19
20- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
21 read, write and setup latencies. Minimum valid values are 1. Controllers
22 without setup latency control should use a value of 0.
23- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
24 read, write and setup latencies. Controllers without setup latency control
25 should use 0. Controllers without separate read and write Tag RAM latency
26 values should only use the first cell.
27- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
28- arm,filter-ranges : <start length> Starting address and length of window to
29 filter. Addresses in the filter window are directed to the M1 port. Other
30 addresses will go to the M0 port.
31
32Example:
33
34L2: cache-controller {
35 compatible = "arm,pl310-cache";
36 reg = <0xfff12000 0x1000>;
37 arm,data-latency = <1 1 1>;
38 arm,tag-latency = <2 2 2>;
39 arm,filter-latency = <0x80000000 0x8000000>;
40 cache-unified;
41 cache-level = <2>;
42};
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 99a6ed7e1bfd..c48cb1e1c46c 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -52,6 +52,8 @@
52#define L2X0_LOCKDOWN_WAY_D_BASE 0x900 52#define L2X0_LOCKDOWN_WAY_D_BASE 0x900
53#define L2X0_LOCKDOWN_WAY_I_BASE 0x904 53#define L2X0_LOCKDOWN_WAY_I_BASE 0x904
54#define L2X0_LOCKDOWN_STRIDE 0x08 54#define L2X0_LOCKDOWN_STRIDE 0x08
55#define L2X0_ADDR_FILTER_START 0xC00
56#define L2X0_ADDR_FILTER_END 0xC04
55#define L2X0_TEST_OPERATION 0xF00 57#define L2X0_TEST_OPERATION 0xF00
56#define L2X0_LINE_DATA 0xF10 58#define L2X0_LINE_DATA 0xF10
57#define L2X0_LINE_TAG 0xF30 59#define L2X0_LINE_TAG 0xF30
@@ -67,6 +69,14 @@
67#define L2X0_CACHE_ID_PART_L310 (3 << 6) 69#define L2X0_CACHE_ID_PART_L310 (3 << 6)
68 70
69#define L2X0_AUX_CTRL_MASK 0xc0000fff 71#define L2X0_AUX_CTRL_MASK 0xc0000fff
72#define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0
73#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7
74#define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3
75#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3)
76#define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6
77#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6)
78#define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9
79#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9)
70#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16 80#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
71#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17 81#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
72#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17) 82#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
@@ -77,8 +87,15 @@
77#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29 87#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29
78#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30 88#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
79 89
90#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0
91#define L2X0_LATENCY_CTRL_RD_SHIFT 4
92#define L2X0_LATENCY_CTRL_WR_SHIFT 8
93
94#define L2X0_ADDR_FILTER_EN 1
95
80#ifndef __ASSEMBLY__ 96#ifndef __ASSEMBLY__
81extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); 97extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
98extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask);
82#endif 99#endif
83 100
84#endif 101#endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 9ecfdb511951..db4484f5bf98 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -16,9 +16,12 @@
16 * along with this program; if not, write to the Free Software 16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */ 18 */
19#include <linux/err.h>
19#include <linux/init.h> 20#include <linux/init.h>
20#include <linux/spinlock.h> 21#include <linux/spinlock.h>
21#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/of.h>
24#include <linux/of_address.h>
22 25
23#include <asm/cacheflush.h> 26#include <asm/cacheflush.h>
24#include <asm/hardware/cache-l2x0.h> 27#include <asm/hardware/cache-l2x0.h>
@@ -372,3 +375,103 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
372 printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", 375 printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
373 ways, cache_id, aux, l2x0_size); 376 ways, cache_id, aux, l2x0_size);
374} 377}
378
379#ifdef CONFIG_OF
380static void __init l2x0_of_setup(const struct device_node *np,
381 __u32 *aux_val, __u32 *aux_mask)
382{
383 u32 data[2] = { 0, 0 };
384 u32 tag = 0;
385 u32 dirty = 0;
386 u32 val = 0, mask = 0;
387
388 of_property_read_u32(np, "arm,tag-latency", &tag);
389 if (tag) {
390 mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
391 val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
392 }
393
394 of_property_read_u32_array(np, "arm,data-latency",
395 data, ARRAY_SIZE(data));
396 if (data[0] && data[1]) {
397 mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
398 L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
399 val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
400 ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
401 }
402
403 of_property_read_u32(np, "arm,dirty-latency", &dirty);
404 if (dirty) {
405 mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
406 val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
407 }
408
409 *aux_val &= ~mask;
410 *aux_val |= val;
411 *aux_mask &= ~mask;
412}
413
414static void __init pl310_of_setup(const struct device_node *np,
415 __u32 *aux_val, __u32 *aux_mask)
416{
417 u32 data[3] = { 0, 0, 0 };
418 u32 tag[3] = { 0, 0, 0 };
419 u32 filter[2] = { 0, 0 };
420
421 of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
422 if (tag[0] && tag[1] && tag[2])
423 writel_relaxed(
424 ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
425 ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
426 ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
427 l2x0_base + L2X0_TAG_LATENCY_CTRL);
428
429 of_property_read_u32_array(np, "arm,data-latency",
430 data, ARRAY_SIZE(data));
431 if (data[0] && data[1] && data[2])
432 writel_relaxed(
433 ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
434 ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
435 ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
436 l2x0_base + L2X0_DATA_LATENCY_CTRL);
437
438 of_property_read_u32_array(np, "arm,filter-ranges",
439 filter, ARRAY_SIZE(filter));
440 if (filter[0] && filter[1]) {
441 writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
442 l2x0_base + L2X0_ADDR_FILTER_END);
443 writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
444 l2x0_base + L2X0_ADDR_FILTER_START);
445 }
446}
447
448static const struct of_device_id l2x0_ids[] __initconst = {
449 { .compatible = "arm,pl310-cache", .data = pl310_of_setup },
450 { .compatible = "arm,l220-cache", .data = l2x0_of_setup },
451 { .compatible = "arm,l210-cache", .data = l2x0_of_setup },
452 {}
453};
454
455int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask)
456{
457 struct device_node *np;
458 void (*l2_setup)(const struct device_node *np,
459 __u32 *aux_val, __u32 *aux_mask);
460
461 np = of_find_matching_node(NULL, l2x0_ids);
462 if (!np)
463 return -ENODEV;
464 l2x0_base = of_iomap(np, 0);
465 if (!l2x0_base)
466 return -ENOMEM;
467
468 /* L2 configuration can only be changed if the cache is disabled */
469 if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
470 l2_setup = of_match_node(l2x0_ids, np)->data;
471 if (l2_setup)
472 l2_setup(np, &aux_val, &aux_mask);
473 }
474 l2x0_init(l2x0_base, aux_val, aux_mask);
475 return 0;
476}
477#endif