1 /* 2 * Copyright (C) 2012-2014 Panasonic Corporation 3 * Copyright (C) 2015-2016 Socionext Inc. 4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <linux/io.h> 11 #include <asm/armv7.h> 12 13 #include "ssc-regs.h" 14 15 #ifdef CONFIG_UNIPHIER_L2CACHE_ON 16 static void uniphier_cache_sync(void) 17 { 18 /* drain internal buffers */ 19 writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE); 20 /* need a read back to confirm */ 21 readl(UNIPHIER_SSCOPE); 22 } 23 24 static void uniphier_cache_maint_all(u32 operation) 25 { 26 /* clear the complete notification flag */ 27 writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS); 28 29 /* try until the command is successfully set */ 30 do { 31 writel(UNIPHIER_SSCOQM_S_ALL | UNIPHIER_SSCOQM_CE | operation, 32 UNIPHIER_SSCOQM); 33 } while (readl(UNIPHIER_SSCOPPQSEF) & 34 (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)); 35 36 /* wait until the operation is completed */ 37 while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF) 38 ; 39 40 uniphier_cache_sync(); 41 } 42 43 void v7_outer_cache_flush_all(void) 44 { 45 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH); 46 } 47 48 void v7_outer_cache_inval_all(void) 49 { 50 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV); 51 } 52 53 static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation) 54 { 55 /* clear the complete notification flag */ 56 writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS); 57 58 /* try until the command is successfully set */ 59 do { 60 writel(UNIPHIER_SSCOQM_S_RANGE | UNIPHIER_SSCOQM_CE | operation, 61 UNIPHIER_SSCOQM); 62 writel(start, UNIPHIER_SSCOQAD); 63 writel(size, UNIPHIER_SSCOQSZ); 64 65 } while (readl(UNIPHIER_SSCOPPQSEF) & 66 (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)); 67 68 /* wait until the operation is completed */ 69 while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF) 70 ; 71 } 72 73 static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation) 74 { 75 u32 size; 76 77 /* 78 * If start address is not aligned to cache-line, 79 * do cache operation for the first cache-line 80 */ 81 start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1); 82 83 size = end - start; 84 85 if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) { 86 /* this means cache operation for all range */ 87 uniphier_cache_maint_all(operation); 88 return; 89 } 90 91 /* 92 * If end address is not aligned to cache-line, 93 * do cache operation for the last cache-line 94 */ 95 size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE); 96 97 while (size) { 98 u32 chunk_size = size > UNIPHIER_SSC_RANGE_OP_MAX_SIZE ? 99 UNIPHIER_SSC_RANGE_OP_MAX_SIZE : size; 100 __uniphier_cache_maint_range(start, chunk_size, operation); 101 102 start += chunk_size; 103 size -= chunk_size; 104 } 105 106 uniphier_cache_sync(); 107 } 108 109 void v7_outer_cache_flush_range(u32 start, u32 end) 110 { 111 uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH); 112 } 113 114 void v7_outer_cache_inval_range(u32 start, u32 end) 115 { 116 if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) { 117 start &= ~(UNIPHIER_SSC_LINE_SIZE - 1); 118 __uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE, 119 UNIPHIER_SSCOQM_CM_FLUSH); 120 start += UNIPHIER_SSC_LINE_SIZE; 121 } 122 123 if (start >= end) { 124 uniphier_cache_sync(); 125 return; 126 } 127 128 if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) { 129 end &= ~(UNIPHIER_SSC_LINE_SIZE - 1); 130 __uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE, 131 UNIPHIER_SSCOQM_CM_FLUSH); 132 } 133 134 if (start >= end) { 135 uniphier_cache_sync(); 136 return; 137 } 138 139 uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV); 140 } 141 142 void v7_outer_cache_enable(void) 143 { 144 u32 tmp; 145 146 writel(U32_MAX, UNIPHIER_SSCLPDAWCR); /* activate all ways */ 147 tmp = readl(UNIPHIER_SSCC); 148 tmp |= UNIPHIER_SSCC_ON; 149 writel(tmp, UNIPHIER_SSCC); 150 } 151 #endif 152 153 void v7_outer_cache_disable(void) 154 { 155 u32 tmp; 156 157 tmp = readl(UNIPHIER_SSCC); 158 tmp &= ~UNIPHIER_SSCC_ON; 159 writel(tmp, UNIPHIER_SSCC); 160 } 161 162 void enable_caches(void) 163 { 164 dcache_enable(); 165 } 166