diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-03-15 14:55:53 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-05-29 19:48:15 -0400 |
commit | 6a28cf59ff1144398d9d32d409ed8cbf1215922d (patch) | |
tree | e7f8469ba2efaac1b6d6e2ad45f164eef8b96c77 /arch/arm/mm | |
parent | bda0b74e6a5a4ce25198f55889bb321532c63d92 (diff) |
ARM: l2c: add L2C-210 specific handlers
Add L2C-210 specific cache operation handlers. These are tailored to
the requirements of the L2C-210 cache controller, which doesn't
require any workarounds. We avoid using the way operations during
normal operation, which means we can avoid locking: the only time
we use the way operations are during initialisation, and when
disabling the cache.
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.c | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 9586be73ca4f..d07fa4fc95a3 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -389,6 +389,108 @@ static const struct l2c_init_data l2x0_init_fns __initconst = { | |||
389 | }; | 389 | }; |
390 | 390 | ||
391 | /* | 391 | /* |
392 | * L2C-210 specific code. | ||
393 | * | ||
394 | * The L2C-2x0 PA, set/way and sync operations are atomic, but we must | ||
395 | * ensure that no background operation is running. The way operations | ||
396 | * are all background tasks. | ||
397 | * | ||
398 | * While a background operation is in progress, any new operation is | ||
399 | * ignored (unspecified whether this causes an error.) Thankfully, not | ||
400 | * used on SMP. | ||
401 | * | ||
402 | * Never has a different sync register other than L2X0_CACHE_SYNC, but | ||
403 | * we use sync_reg_offset here so we can share some of this with L2C-310. | ||
404 | */ | ||
405 | static void __l2c210_cache_sync(void __iomem *base) | ||
406 | { | ||
407 | writel_relaxed(0, base + sync_reg_offset); | ||
408 | } | ||
409 | |||
410 | static void __l2c210_op_pa_range(void __iomem *reg, unsigned long start, | ||
411 | unsigned long end) | ||
412 | { | ||
413 | while (start < end) { | ||
414 | writel_relaxed(start, reg); | ||
415 | start += CACHE_LINE_SIZE; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | static void l2c210_inv_range(unsigned long start, unsigned long end) | ||
420 | { | ||
421 | void __iomem *base = l2x0_base; | ||
422 | |||
423 | if (start & (CACHE_LINE_SIZE - 1)) { | ||
424 | start &= ~(CACHE_LINE_SIZE - 1); | ||
425 | writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA); | ||
426 | start += CACHE_LINE_SIZE; | ||
427 | } | ||
428 | |||
429 | if (end & (CACHE_LINE_SIZE - 1)) { | ||
430 | end &= ~(CACHE_LINE_SIZE - 1); | ||
431 | writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA); | ||
432 | } | ||
433 | |||
434 | __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end); | ||
435 | __l2c210_cache_sync(base); | ||
436 | } | ||
437 | |||
438 | static void l2c210_clean_range(unsigned long start, unsigned long end) | ||
439 | { | ||
440 | void __iomem *base = l2x0_base; | ||
441 | |||
442 | start &= ~(CACHE_LINE_SIZE - 1); | ||
443 | __l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end); | ||
444 | __l2c210_cache_sync(base); | ||
445 | } | ||
446 | |||
447 | static void l2c210_flush_range(unsigned long start, unsigned long end) | ||
448 | { | ||
449 | void __iomem *base = l2x0_base; | ||
450 | |||
451 | start &= ~(CACHE_LINE_SIZE - 1); | ||
452 | __l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end); | ||
453 | __l2c210_cache_sync(base); | ||
454 | } | ||
455 | |||
456 | static void l2c210_flush_all(void) | ||
457 | { | ||
458 | void __iomem *base = l2x0_base; | ||
459 | |||
460 | BUG_ON(!irqs_disabled()); | ||
461 | |||
462 | __l2c_op_way(base + L2X0_CLEAN_INV_WAY); | ||
463 | __l2c210_cache_sync(base); | ||
464 | } | ||
465 | |||
466 | static void l2c210_sync(void) | ||
467 | { | ||
468 | __l2c210_cache_sync(l2x0_base); | ||
469 | } | ||
470 | |||
471 | static void l2c210_resume(void) | ||
472 | { | ||
473 | void __iomem *base = l2x0_base; | ||
474 | |||
475 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) | ||
476 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); | ||
477 | } | ||
478 | |||
479 | static const struct l2c_init_data l2c210_data __initconst = { | ||
480 | .num_lock = 1, | ||
481 | .enable = l2c_enable, | ||
482 | .outer_cache = { | ||
483 | .inv_range = l2c210_inv_range, | ||
484 | .clean_range = l2c210_clean_range, | ||
485 | .flush_range = l2c210_flush_range, | ||
486 | .flush_all = l2c210_flush_all, | ||
487 | .disable = l2c_disable, | ||
488 | .sync = l2c210_sync, | ||
489 | .resume = l2c210_resume, | ||
490 | }, | ||
491 | }; | ||
492 | |||
493 | /* | ||
392 | * L2C-310 specific code. | 494 | * L2C-310 specific code. |
393 | * | 495 | * |
394 | * Errata: | 496 | * Errata: |
@@ -623,6 +725,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) | |||
623 | data = &l2x0_init_fns; | 725 | data = &l2x0_init_fns; |
624 | break; | 726 | break; |
625 | 727 | ||
728 | case L2X0_CACHE_ID_PART_L210: | ||
729 | data = &l2c210_data; | ||
730 | break; | ||
731 | |||
626 | case L2X0_CACHE_ID_PART_L310: | 732 | case L2X0_CACHE_ID_PART_L310: |
627 | data = &l2c310_init_fns; | 733 | data = &l2c310_init_fns; |
628 | break; | 734 | break; |
@@ -672,6 +778,21 @@ static void __init l2x0_of_parse(const struct device_node *np, | |||
672 | *aux_mask &= ~mask; | 778 | *aux_mask &= ~mask; |
673 | } | 779 | } |
674 | 780 | ||
781 | static const struct l2c_init_data of_l2c210_data __initconst = { | ||
782 | .num_lock = 1, | ||
783 | .of_parse = l2x0_of_parse, | ||
784 | .enable = l2c_enable, | ||
785 | .outer_cache = { | ||
786 | .inv_range = l2c210_inv_range, | ||
787 | .clean_range = l2c210_clean_range, | ||
788 | .flush_range = l2c210_flush_range, | ||
789 | .flush_all = l2c210_flush_all, | ||
790 | .disable = l2c_disable, | ||
791 | .sync = l2c210_sync, | ||
792 | .resume = l2c210_resume, | ||
793 | }, | ||
794 | }; | ||
795 | |||
675 | static const struct l2c_init_data of_l2x0_data __initconst = { | 796 | static const struct l2c_init_data of_l2x0_data __initconst = { |
676 | .of_parse = l2x0_of_parse, | 797 | .of_parse = l2x0_of_parse, |
677 | .enable = l2x0_enable, | 798 | .enable = l2x0_enable, |
@@ -1117,7 +1238,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = { | |||
1117 | 1238 | ||
1118 | #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } | 1239 | #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } |
1119 | static const struct of_device_id l2x0_ids[] __initconst = { | 1240 | static const struct of_device_id l2x0_ids[] __initconst = { |
1120 | L2C_ID("arm,l210-cache", of_l2x0_data), | 1241 | L2C_ID("arm,l210-cache", of_l2c210_data), |
1121 | L2C_ID("arm,l220-cache", of_l2x0_data), | 1242 | L2C_ID("arm,l220-cache", of_l2x0_data), |
1122 | L2C_ID("arm,pl310-cache", of_pl310_data), | 1243 | L2C_ID("arm,pl310-cache", of_pl310_data), |
1123 | L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), | 1244 | L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), |