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