armv8/fsl-lsch3: Convert flushing L3 to assembly to avoid using stack
authorYork Sun <yorksun@freescale.com>
Tue, 6 Jan 2015 21:18:42 +0000 (13:18 -0800)
committerYork Sun <yorksun@freescale.com>
Tue, 24 Feb 2015 21:08:46 +0000 (13:08 -0800)
Flushing L3 cache in CCN-504 requries d-cache to be disabled. Using
assembly function to guarantee stack is not used before flushing is
completed. Timeout is needed for simualtor on which CCN-504 is not
implemented. Return value can be checked for timeout situation.

Change bootm.c to disable dcache instead of simply flushing, required
by flushing L3.

Signed-off-by: York Sun <yorksun@freescale.com>
arch/arm/cpu/armv8/cache.S
arch/arm/cpu/armv8/cache_v8.c
arch/arm/cpu/armv8/fsl-lsch3/cpu.c
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
arch/arm/include/asm/system.h
arch/arm/lib/bootm.c

index 9c6e8243bb4bc81f731708623e02b5770e5fb163..fa447bce16b862e6710cf7792c9caf0d846f390c 100644 (file)
@@ -155,3 +155,9 @@ ENTRY(__asm_invalidate_icache_all)
        isb     sy
        ret
 ENDPROC(__asm_invalidate_icache_all)
+
+ENTRY(__asm_flush_l3_cache)
+       mov     x0, #0                  /* return status as success */
+       ret
+ENDPROC(__asm_flush_l3_cache)
+       .weak   __asm_flush_l3_cache
index 9dbcdf22afe266e35eb40804b267f51c5f2c8e65..c5ec5297cd39ac4a0730724e0166406a7581f3f6 100644 (file)
@@ -73,17 +73,21 @@ void invalidate_dcache_all(void)
        __asm_invalidate_dcache_all();
 }
 
-void __weak flush_l3_cache(void)
-{
-}
-
 /*
- * Performs a clean & invalidation of the entire data cache at all levels
+ * Performs a clean & invalidation of the entire data cache at all levels.
+ * This function needs to be inline to avoid using stack.
+ * __asm_flush_l3_cache return status of timeout
  */
-void flush_dcache_all(void)
+inline void flush_dcache_all(void)
 {
+       int ret;
+
        __asm_flush_dcache_all();
-       flush_l3_cache();
+       ret = __asm_flush_l3_cache();
+       if (ret)
+               debug("flushing dcache returns 0x%x\n", ret);
+       else
+               debug("flushing dcache successfully.\n");
 }
 
 /*
index ada1690ed9e50a31d643c9ef0ddf47bb05ce91d3..2aaac017d2655c5419080ae816fdac7c9c71d08e 100644 (file)
@@ -242,59 +242,6 @@ int arch_cpu_init(void)
        return 0;
 }
 
-/*
- * flush_l3_cache
- * Dickens L3 cache can be flushed by transitioning from FAM to SFONLY power
- * state, by writing to HP-F P-state request register.
- * Fixme: This function should moved to a common file if other SoCs also use
- * the same Dickens.
- */
-#define HNF0_PSTATE_REQ 0x04200010
-#define HNF1_PSTATE_REQ 0x04210010
-#define HNF2_PSTATE_REQ 0x04220010
-#define HNF3_PSTATE_REQ 0x04230010
-#define HNF4_PSTATE_REQ 0x04240010
-#define HNF5_PSTATE_REQ 0x04250010
-#define HNF6_PSTATE_REQ 0x04260010
-#define HNF7_PSTATE_REQ 0x04270010
-#define HNFPSTAT_MASK (0xFFFFFFFFFFFFFFFC)
-#define HNFPSTAT_FAM   0x3
-#define HNFPSTAT_SFONLY 0x01
-
-static void hnf_pstate_req(u64 *ptr, u64 state)
-{
-       int timeout = 1000;
-       out_le64(ptr, (in_le64(ptr) & HNFPSTAT_MASK) | (state & 0x3));
-       ptr++;
-       /* checking if the transition is completed */
-       while (timeout > 0) {
-               if (((in_le64(ptr) & 0x0c) >> 2) == (state & 0x3))
-                       break;
-               udelay(100);
-               timeout--;
-       }
-}
-
-void flush_l3_cache(void)
-{
-       hnf_pstate_req((u64 *)HNF0_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF1_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF2_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF3_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF4_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF5_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF6_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF7_PSTATE_REQ, HNFPSTAT_SFONLY);
-       hnf_pstate_req((u64 *)HNF0_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF1_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF2_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF3_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF4_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF5_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF6_PSTATE_REQ, HNFPSTAT_FAM);
-       hnf_pstate_req((u64 *)HNF7_PSTATE_REQ, HNFPSTAT_FAM);
-}
-
 /*
  * This function is called from lib/board.c.
  * It recreates MMU table in main memory. MMU and d-cache are enabled earlier.
index c2837876b1617dfad139e82ee4f23724b208a7be..886576ef99486034ec7594cc47c607f0e3358c37 100644 (file)
@@ -100,6 +100,84 @@ ENTRY(lowlevel_init)
        ret
 ENDPROC(lowlevel_init)
 
+hnf_pstate_poll:
+       /* x0 has the desired status, return 0 for success, 1 for timeout
+        * clobber x1, x2, x3, x4, x6, x7
+        */
+       mov     x1, x0
+       mov     x7, #0                  /* flag for timeout */
+       mrs     x3, cntpct_el0          /* read timer */
+       add     x3, x3, #1200           /* timeout after 100 microseconds */
+       mov     x0, #0x18
+       movk    x0, #0x420, lsl #16     /* HNF0_PSTATE_STATUS */
+       mov     w6, #8                  /* HN-F node count */
+1:
+       ldr     x2, [x0]
+       cmp     x2, x1                  /* check status */
+       b.eq    2f
+       mrs     x4, cntpct_el0
+       cmp     x4, x3
+       b.ls    1b
+       mov     x7, #1                  /* timeout */
+       b       3f
+2:
+       add     x0, x0, #0x10000        /* move to next node */
+       subs    w6, w6, #1
+       cbnz    w6, 1b
+3:
+       mov     x0, x7
+       ret
+
+hnf_set_pstate:
+       /* x0 has the desired state, clobber x1, x2, x6 */
+       mov     x1, x0
+       /* power state to SFONLY */
+       mov     w6, #8                  /* HN-F node count */
+       mov     x0, #0x10
+       movk    x0, #0x420, lsl #16     /* HNF0_PSTATE_REQ */
+1:     /* set pstate to sfonly */
+       ldr     x2, [x0]
+       and     x2, x2, #0xfffffffffffffffc     /* & HNFPSTAT_MASK */
+       orr     x2, x2, x1
+       str     x2, [x0]
+       add     x0, x0, #0x10000        /* move to next node */
+       subs    w6, w6, #1
+       cbnz    w6, 1b
+
+       ret
+
+ENTRY(__asm_flush_l3_cache)
+       /*
+        * Return status in x0
+        *    success 0
+        *    tmeout 1 for setting SFONLY, 2 for FAM, 3 for both
+        */
+       mov     x29, lr
+       mov     x8, #0
+
+       dsb     sy
+       mov     x0, #0x1                /* HNFPSTAT_SFONLY */
+       bl      hnf_set_pstate
+
+       mov     x0, #0x4                /* SFONLY status */
+       bl      hnf_pstate_poll
+       cbz     x0, 1f
+       mov     x8, #1                  /* timeout */
+1:
+       dsb     sy
+       mov     x0, #0x3                /* HNFPSTAT_FAM */
+       bl      hnf_set_pstate
+
+       mov     x0, #0xc                /* FAM status */
+       bl      hnf_pstate_poll
+       cbz     x0, 1f
+       add     x8, x8, #0x2
+1:
+       mov     x0, x8
+       mov     lr, x29
+       ret
+ENDPROC(__asm_flush_l3_cache)
+
        /* Keep literals not used by the secondary boot code outside it */
        .ltorg
 
index 7820486df00e50405c31d079c497ecdb6a562ed0..2a5bed2e46b67b7adacddc1ed43a395e34c3d9f8 100644 (file)
@@ -70,6 +70,7 @@ void __asm_invalidate_dcache_all(void);
 void __asm_flush_dcache_range(u64 start, u64 end);
 void __asm_invalidate_tlb_all(void);
 void __asm_invalidate_icache_all(void);
+int __asm_flush_l3_cache(void);
 
 void armv8_switch_to_el2(void);
 void armv8_switch_to_el1(void);
index 0c1298a31e733c3e528f7d49a70088f27deece86..2d6b6761548a8e3bcb7baaffdbe0343b7acc8334 100644 (file)
@@ -191,7 +191,7 @@ __weak void setup_board_tags(struct tag **in_params) {}
 static void do_nonsec_virt_switch(void)
 {
        smp_kick_all_cpus();
-       flush_dcache_all();     /* flush cache before swtiching to EL2 */
+       dcache_disable();       /* flush cache before swtiching to EL2 */
        armv8_switch_to_el2();
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
        armv8_switch_to_el1();