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