aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
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 /arch/arm/mm
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>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/cache-l2x0.c103
1 files changed, 103 insertions, 0 deletions
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