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