Linux 6.7-rc7
[linux-modified.git] / arch / mips / include / asm / mips-cps.h
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
14 extern unsigned long __cps_access_bad_size(void)
15         __compiletime_error("Bad size for CPS accessor");
16
17 #define CPS_ACCESSOR_A(unit, off, name)                                 \
18 static inline void *addr_##unit##_##name(void)                          \
19 {                                                                       \
20         return mips_##unit##_base + (off);                              \
21 }
22
23 #define CPS_ACCESSOR_R(unit, sz, name)                                  \
24 static 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)                                  \
47 static 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)                                  \
72 static 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                                                                         \
81 static inline void set_##unit##_##name(uint##sz##_t val)                \
82 {                                                                       \
83         change_##unit##_##name(val, val);                               \
84 }                                                                       \
85                                                                         \
86 static 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  */
114 static 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  */
130 static 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  */
163 static 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  */
180 static 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  */
198 static 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__ */