xref: /openbmc/linux/arch/mips/include/asm/mips-cps.h (revision 413d6ed3)
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