1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Copyright (C) 2017 Imagination Technologies 4 * Author: Paul Burton <paul.burton@mips.com> 5 */ 6 7 #ifndef __MIPS_ASM_MIPS_CPS_H__ 8 #define __MIPS_ASM_MIPS_CPS_H__ 9 10 #include <linux/io.h> 11 #include <linux/types.h> 12 13 #include <asm/mips-boards/launch.h> 14 15 extern unsigned long __cps_access_bad_size(void) 16 __compiletime_error("Bad size for CPS accessor"); 17 18 #define CPS_ACCESSOR_A(unit, off, name) \ 19 static inline void *addr_##unit##_##name(void) \ 20 { \ 21 return mips_##unit##_base + (off); \ 22 } 23 24 #define CPS_ACCESSOR_R(unit, sz, name) \ 25 static inline uint##sz##_t read_##unit##_##name(void) \ 26 { \ 27 uint64_t val64; \ 28 \ 29 switch (sz) { \ 30 case 32: \ 31 return __raw_readl(addr_##unit##_##name()); \ 32 \ 33 case 64: \ 34 if (mips_cm_is64) \ 35 return __raw_readq(addr_##unit##_##name()); \ 36 \ 37 val64 = __raw_readl(addr_##unit##_##name() + 4); \ 38 val64 <<= 32; \ 39 val64 |= __raw_readl(addr_##unit##_##name()); \ 40 return val64; \ 41 \ 42 default: \ 43 return __cps_access_bad_size(); \ 44 } \ 45 } 46 47 #define CPS_ACCESSOR_W(unit, sz, name) \ 48 static inline void write_##unit##_##name(uint##sz##_t val) \ 49 { \ 50 switch (sz) { \ 51 case 32: \ 52 __raw_writel(val, addr_##unit##_##name()); \ 53 break; \ 54 \ 55 case 64: \ 56 if (mips_cm_is64) { \ 57 __raw_writeq(val, addr_##unit##_##name()); \ 58 break; \ 59 } \ 60 \ 61 __raw_writel((uint64_t)val >> 32, \ 62 addr_##unit##_##name() + 4); \ 63 __raw_writel(val, addr_##unit##_##name()); \ 64 break; \ 65 \ 66 default: \ 67 __cps_access_bad_size(); \ 68 break; \ 69 } \ 70 } 71 72 #define CPS_ACCESSOR_M(unit, sz, name) \ 73 static inline void change_##unit##_##name(uint##sz##_t mask, \ 74 uint##sz##_t val) \ 75 { \ 76 uint##sz##_t reg_val = read_##unit##_##name(); \ 77 reg_val &= ~mask; \ 78 reg_val |= val; \ 79 write_##unit##_##name(reg_val); \ 80 } \ 81 \ 82 static inline void set_##unit##_##name(uint##sz##_t val) \ 83 { \ 84 change_##unit##_##name(val, val); \ 85 } \ 86 \ 87 static inline void clear_##unit##_##name(uint##sz##_t val) \ 88 { \ 89 change_##unit##_##name(val, 0); \ 90 } 91 92 #define CPS_ACCESSOR_RO(unit, sz, off, name) \ 93 CPS_ACCESSOR_A(unit, off, name) \ 94 CPS_ACCESSOR_R(unit, sz, name) 95 96 #define CPS_ACCESSOR_WO(unit, sz, off, name) \ 97 CPS_ACCESSOR_A(unit, off, name) \ 98 CPS_ACCESSOR_W(unit, sz, name) 99 100 #define CPS_ACCESSOR_RW(unit, sz, off, name) \ 101 CPS_ACCESSOR_A(unit, off, name) \ 102 CPS_ACCESSOR_R(unit, sz, name) \ 103 CPS_ACCESSOR_W(unit, sz, name) \ 104 CPS_ACCESSOR_M(unit, sz, name) 105 106 #include <asm/mips-cm.h> 107 #include <asm/mips-cpc.h> 108 #include <asm/mips-gic.h> 109 110 /** 111 * mips_cps_numclusters - return the number of clusters present in the system 112 * 113 * Returns the number of clusters in the system. 114 */ 115 static inline unsigned int mips_cps_numclusters(void) 116 { 117 unsigned int num_clusters; 118 119 if (mips_cm_revision() < CM_REV_CM3_5) 120 return 1; 121 122 num_clusters = read_gcr_config() & CM_GCR_CONFIG_NUM_CLUSTERS; 123 num_clusters >>= __ffs(CM_GCR_CONFIG_NUM_CLUSTERS); 124 return num_clusters; 125 } 126 127 /** 128 * mips_cps_cluster_config - return (GCR|CPC)_CONFIG from a cluster 129 * @cluster: the ID of the cluster whose config we want 130 * 131 * Read the value of GCR_CONFIG (or its CPC_CONFIG mirror) from a @cluster. 132 * 133 * Returns the value of GCR_CONFIG. 134 */ 135 static inline uint64_t mips_cps_cluster_config(unsigned int cluster) 136 { 137 uint64_t config; 138 139 if (mips_cm_revision() < CM_REV_CM3_5) { 140 /* 141 * Prior to CM 3.5 we don't have the notion of multiple 142 * clusters so we can trivially read the GCR_CONFIG register 143 * within this cluster. 144 */ 145 WARN_ON(cluster != 0); 146 config = read_gcr_config(); 147 } else { 148 /* 149 * From CM 3.5 onwards we read the CPC_CONFIG mirror of 150 * GCR_CONFIG via the redirect region, since the CPC is always 151 * powered up allowing us not to need to power up the CM. 152 */ 153 mips_cm_lock_other(cluster, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL); 154 config = read_cpc_redir_config(); 155 mips_cm_unlock_other(); 156 } 157 158 return config; 159 } 160 161 /** 162 * mips_cps_numcores - return the number of cores present in a cluster 163 * @cluster: the ID of the cluster whose core count we want 164 * 165 * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or 166 * zero if no Coherence Manager is present. 167 */ 168 static inline unsigned int mips_cps_numcores(unsigned int cluster) 169 { 170 unsigned int ncores; 171 172 if (!mips_cm_present()) 173 return 0; 174 175 /* Add one before masking to handle 0xff indicating no cores */ 176 ncores = (mips_cps_cluster_config(cluster) + 1) & CM_GCR_CONFIG_PCORES; 177 178 if (IS_ENABLED(CONFIG_SOC_MT7621)) { 179 struct cpulaunch *launch; 180 181 /* 182 * Ralink MT7621S SoC is single core, but the GCR_CONFIG method 183 * always reports 2 cores. Check the second core's LAUNCH_FREADY 184 * flag to detect if the second core is missing. This method 185 * only works before the core has been started. 186 */ 187 launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); 188 launch += 2; /* MT7621 has 2 VPEs per core */ 189 if (!(launch->flags & LAUNCH_FREADY)) 190 ncores = 1; 191 } 192 193 return ncores; 194 } 195 196 /** 197 * mips_cps_numiocu - return the number of IOCUs present in a cluster 198 * @cluster: the ID of the cluster whose IOCU count we want 199 * 200 * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero 201 * if no Coherence Manager is present. 202 */ 203 static inline unsigned int mips_cps_numiocu(unsigned int cluster) 204 { 205 unsigned int num_iocu; 206 207 if (!mips_cm_present()) 208 return 0; 209 210 num_iocu = mips_cps_cluster_config(cluster) & CM_GCR_CONFIG_NUMIOCU; 211 num_iocu >>= __ffs(CM_GCR_CONFIG_NUMIOCU); 212 return num_iocu; 213 } 214 215 /** 216 * mips_cps_numvps - return the number of VPs (threads) supported by a core 217 * @cluster: the ID of the cluster containing the core we want to examine 218 * @core: the ID of the core whose VP count we want 219 * 220 * Returns the number of Virtual Processors (VPs, ie. hardware threads) that 221 * are supported by the given @core in the given @cluster. If the core or the 222 * kernel do not support hardware mutlti-threading this returns 1. 223 */ 224 static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int core) 225 { 226 unsigned int cfg; 227 228 if (!mips_cm_present()) 229 return 1; 230 231 if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) 232 && (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp)) 233 return 1; 234 235 mips_cm_lock_other(cluster, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL); 236 237 if (mips_cm_revision() < CM_REV_CM3_5) { 238 /* 239 * Prior to CM 3.5 we can only have one cluster & don't have 240 * CPC_Cx_CONFIG, so we read GCR_Cx_CONFIG. 241 */ 242 cfg = read_gcr_co_config(); 243 } else { 244 /* 245 * From CM 3.5 onwards we read CPC_Cx_CONFIG because the CPC is 246 * always powered, which allows us to not worry about powering 247 * up the cluster's CM here. 248 */ 249 cfg = read_cpc_co_config(); 250 } 251 252 mips_cm_unlock_other(); 253 254 return (cfg + 1) & CM_GCR_Cx_CONFIG_PVPE; 255 } 256 257 #endif /* __MIPS_ASM_MIPS_CPS_H__ */ 258