diff options
author | Christian Daudt <csd@broadcom.com> | 2013-05-09 17:21:01 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-05-15 14:39:27 -0400 |
commit | 3b656fed6ff65d6d268da9ed0760c2a58d125771 (patch) | |
tree | 17ec053049fedb78e072fbafd055e8ba712422b2 /arch/arm/mm/cache-l2x0.c | |
parent | faefd550c45d8d314e8f260f21565320355c947f (diff) |
ARM: 7716/1: bcm281xx: Add L2 support for Rev A2 chips
Rev A2 SoCs have an unorthodox memory re-mapping and this needs
to be reflected in the cache operations.
This patch adds new outer cache functions for the l2x0 driver
to support this SoC revision. It also adds a new compatible
value for the cache to enable this functionality.
Updates from V1:
- remove section 1 altogether and note that in comments
- simplify section selection caused by section 1 removal
- BUG_ON just in case section 1 shows up
Signed-off-by: Christian Daudt <csd@broadcom.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm/cache-l2x0.c')
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c465faca51b0..d70e0aba0c9d 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -523,6 +523,147 @@ static void aurora_flush_range(unsigned long start, unsigned long end) | |||
523 | } | 523 | } |
524 | } | 524 | } |
525 | 525 | ||
526 | /* | ||
527 | * For certain Broadcom SoCs, depending on the address range, different offsets | ||
528 | * need to be added to the address before passing it to L2 for | ||
529 | * invalidation/clean/flush | ||
530 | * | ||
531 | * Section Address Range Offset EMI | ||
532 | * 1 0x00000000 - 0x3FFFFFFF 0x80000000 VC | ||
533 | * 2 0x40000000 - 0xBFFFFFFF 0x40000000 SYS | ||
534 | * 3 0xC0000000 - 0xFFFFFFFF 0x80000000 VC | ||
535 | * | ||
536 | * When the start and end addresses have crossed two different sections, we | ||
537 | * need to break the L2 operation into two, each within its own section. | ||
538 | * For example, if we need to invalidate addresses starts at 0xBFFF0000 and | ||
539 | * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2) | ||
540 | * 0xC0000000 - 0xC0001000 | ||
541 | * | ||
542 | * Note 1: | ||
543 | * By breaking a single L2 operation into two, we may potentially suffer some | ||
544 | * performance hit, but keep in mind the cross section case is very rare | ||
545 | * | ||
546 | * Note 2: | ||
547 | * We do not need to handle the case when the start address is in | ||
548 | * Section 1 and the end address is in Section 3, since it is not a valid use | ||
549 | * case | ||
550 | * | ||
551 | * Note 3: | ||
552 | * Section 1 in practical terms can no longer be used on rev A2. Because of | ||
553 | * that the code does not need to handle section 1 at all. | ||
554 | * | ||
555 | */ | ||
556 | #define BCM_SYS_EMI_START_ADDR 0x40000000UL | ||
557 | #define BCM_VC_EMI_SEC3_START_ADDR 0xC0000000UL | ||
558 | |||
559 | #define BCM_SYS_EMI_OFFSET 0x40000000UL | ||
560 | #define BCM_VC_EMI_OFFSET 0x80000000UL | ||
561 | |||
562 | static inline int bcm_addr_is_sys_emi(unsigned long addr) | ||
563 | { | ||
564 | return (addr >= BCM_SYS_EMI_START_ADDR) && | ||
565 | (addr < BCM_VC_EMI_SEC3_START_ADDR); | ||
566 | } | ||
567 | |||
568 | static inline unsigned long bcm_l2_phys_addr(unsigned long addr) | ||
569 | { | ||
570 | if (bcm_addr_is_sys_emi(addr)) | ||
571 | return addr + BCM_SYS_EMI_OFFSET; | ||
572 | else | ||
573 | return addr + BCM_VC_EMI_OFFSET; | ||
574 | } | ||
575 | |||
576 | static void bcm_inv_range(unsigned long start, unsigned long end) | ||
577 | { | ||
578 | unsigned long new_start, new_end; | ||
579 | |||
580 | BUG_ON(start < BCM_SYS_EMI_START_ADDR); | ||
581 | |||
582 | if (unlikely(end <= start)) | ||
583 | return; | ||
584 | |||
585 | new_start = bcm_l2_phys_addr(start); | ||
586 | new_end = bcm_l2_phys_addr(end); | ||
587 | |||
588 | /* normal case, no cross section between start and end */ | ||
589 | if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { | ||
590 | l2x0_inv_range(new_start, new_end); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | /* They cross sections, so it can only be a cross from section | ||
595 | * 2 to section 3 | ||
596 | */ | ||
597 | l2x0_inv_range(new_start, | ||
598 | bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); | ||
599 | l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), | ||
600 | new_end); | ||
601 | } | ||
602 | |||
603 | static void bcm_clean_range(unsigned long start, unsigned long end) | ||
604 | { | ||
605 | unsigned long new_start, new_end; | ||
606 | |||
607 | BUG_ON(start < BCM_SYS_EMI_START_ADDR); | ||
608 | |||
609 | if (unlikely(end <= start)) | ||
610 | return; | ||
611 | |||
612 | if ((end - start) >= l2x0_size) { | ||
613 | l2x0_clean_all(); | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | new_start = bcm_l2_phys_addr(start); | ||
618 | new_end = bcm_l2_phys_addr(end); | ||
619 | |||
620 | /* normal case, no cross section between start and end */ | ||
621 | if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { | ||
622 | l2x0_clean_range(new_start, new_end); | ||
623 | return; | ||
624 | } | ||
625 | |||
626 | /* They cross sections, so it can only be a cross from section | ||
627 | * 2 to section 3 | ||
628 | */ | ||
629 | l2x0_clean_range(new_start, | ||
630 | bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); | ||
631 | l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), | ||
632 | new_end); | ||
633 | } | ||
634 | |||
635 | static void bcm_flush_range(unsigned long start, unsigned long end) | ||
636 | { | ||
637 | unsigned long new_start, new_end; | ||
638 | |||
639 | BUG_ON(start < BCM_SYS_EMI_START_ADDR); | ||
640 | |||
641 | if (unlikely(end <= start)) | ||
642 | return; | ||
643 | |||
644 | if ((end - start) >= l2x0_size) { | ||
645 | l2x0_flush_all(); | ||
646 | return; | ||
647 | } | ||
648 | |||
649 | new_start = bcm_l2_phys_addr(start); | ||
650 | new_end = bcm_l2_phys_addr(end); | ||
651 | |||
652 | /* normal case, no cross section between start and end */ | ||
653 | if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { | ||
654 | l2x0_flush_range(new_start, new_end); | ||
655 | return; | ||
656 | } | ||
657 | |||
658 | /* They cross sections, so it can only be a cross from section | ||
659 | * 2 to section 3 | ||
660 | */ | ||
661 | l2x0_flush_range(new_start, | ||
662 | bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); | ||
663 | l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), | ||
664 | new_end); | ||
665 | } | ||
666 | |||
526 | static void __init l2x0_of_setup(const struct device_node *np, | 667 | static void __init l2x0_of_setup(const struct device_node *np, |
527 | u32 *aux_val, u32 *aux_mask) | 668 | u32 *aux_val, u32 *aux_mask) |
528 | { | 669 | { |
@@ -765,6 +906,21 @@ static const struct l2x0_of_data aurora_no_outer_data = { | |||
765 | }, | 906 | }, |
766 | }; | 907 | }; |
767 | 908 | ||
909 | static const struct l2x0_of_data bcm_l2x0_data = { | ||
910 | .setup = pl310_of_setup, | ||
911 | .save = pl310_save, | ||
912 | .outer_cache = { | ||
913 | .resume = pl310_resume, | ||
914 | .inv_range = bcm_inv_range, | ||
915 | .clean_range = bcm_clean_range, | ||
916 | .flush_range = bcm_flush_range, | ||
917 | .sync = l2x0_cache_sync, | ||
918 | .flush_all = l2x0_flush_all, | ||
919 | .inv_all = l2x0_inv_all, | ||
920 | .disable = l2x0_disable, | ||
921 | }, | ||
922 | }; | ||
923 | |||
768 | static const struct of_device_id l2x0_ids[] __initconst = { | 924 | static const struct of_device_id l2x0_ids[] __initconst = { |
769 | { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, | 925 | { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, |
770 | { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, | 926 | { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, |
@@ -773,6 +929,8 @@ static const struct of_device_id l2x0_ids[] __initconst = { | |||
773 | .data = (void *)&aurora_no_outer_data}, | 929 | .data = (void *)&aurora_no_outer_data}, |
774 | { .compatible = "marvell,aurora-outer-cache", | 930 | { .compatible = "marvell,aurora-outer-cache", |
775 | .data = (void *)&aurora_with_outer_data}, | 931 | .data = (void *)&aurora_with_outer_data}, |
932 | { .compatible = "bcm,bcm11351-a2-pl310-cache", | ||
933 | .data = (void *)&bcm_l2x0_data}, | ||
776 | {} | 934 | {} |
777 | }; | 935 | }; |
778 | 936 | ||