12874c5fdSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
2b025d518SPaul Burton /*
3b025d518SPaul Burton * Copyright (C) 2017 Imagination Technologies
4fb615d61SPaul Burton * Author: Paul Burton <paul.burton@mips.com>
5b025d518SPaul Burton */
6b025d518SPaul Burton
7b025d518SPaul Burton #ifndef __MIPS_ASM_MIPS_CPS_H__
8b025d518SPaul Burton #define __MIPS_ASM_MIPS_CPS_H__
9b025d518SPaul Burton
10*4e1fc0a4SGeert Uytterhoeven #include <linux/bitfield.h>
11b025d518SPaul Burton #include <linux/io.h>
12b025d518SPaul Burton #include <linux/types.h>
13b025d518SPaul Burton
14b025d518SPaul Burton extern unsigned long __cps_access_bad_size(void)
15b025d518SPaul Burton __compiletime_error("Bad size for CPS accessor");
16b025d518SPaul Burton
17b025d518SPaul Burton #define CPS_ACCESSOR_A(unit, off, name) \
18b025d518SPaul Burton static inline void *addr_##unit##_##name(void) \
19b025d518SPaul Burton { \
20b025d518SPaul Burton return mips_##unit##_base + (off); \
21b025d518SPaul Burton }
22b025d518SPaul Burton
23b025d518SPaul Burton #define CPS_ACCESSOR_R(unit, sz, name) \
24b025d518SPaul Burton static inline uint##sz##_t read_##unit##_##name(void) \
25b025d518SPaul Burton { \
26b025d518SPaul Burton uint64_t val64; \
27b025d518SPaul Burton \
28b025d518SPaul Burton switch (sz) { \
29b025d518SPaul Burton case 32: \
30b025d518SPaul Burton return __raw_readl(addr_##unit##_##name()); \
31b025d518SPaul Burton \
32b025d518SPaul Burton case 64: \
33b025d518SPaul Burton if (mips_cm_is64) \
34b025d518SPaul Burton return __raw_readq(addr_##unit##_##name()); \
35b025d518SPaul Burton \
36b025d518SPaul Burton val64 = __raw_readl(addr_##unit##_##name() + 4); \
37b025d518SPaul Burton val64 <<= 32; \
38b025d518SPaul Burton val64 |= __raw_readl(addr_##unit##_##name()); \
39b025d518SPaul Burton return val64; \
40b025d518SPaul Burton \
41b025d518SPaul Burton default: \
42b025d518SPaul Burton return __cps_access_bad_size(); \
43b025d518SPaul Burton } \
44b025d518SPaul Burton }
45b025d518SPaul Burton
46b025d518SPaul Burton #define CPS_ACCESSOR_W(unit, sz, name) \
47b025d518SPaul Burton static inline void write_##unit##_##name(uint##sz##_t val) \
48b025d518SPaul Burton { \
49b025d518SPaul Burton switch (sz) { \
50b025d518SPaul Burton case 32: \
51b025d518SPaul Burton __raw_writel(val, addr_##unit##_##name()); \
52b025d518SPaul Burton break; \
53b025d518SPaul Burton \
54b025d518SPaul Burton case 64: \
55b025d518SPaul Burton if (mips_cm_is64) { \
56b025d518SPaul Burton __raw_writeq(val, addr_##unit##_##name()); \
57b025d518SPaul Burton break; \
58b025d518SPaul Burton } \
59b025d518SPaul Burton \
60b025d518SPaul Burton __raw_writel((uint64_t)val >> 32, \
61b025d518SPaul Burton addr_##unit##_##name() + 4); \
62b025d518SPaul Burton __raw_writel(val, addr_##unit##_##name()); \
63b025d518SPaul Burton break; \
64b025d518SPaul Burton \
65b025d518SPaul Burton default: \
66b025d518SPaul Burton __cps_access_bad_size(); \
67b025d518SPaul Burton break; \
68b025d518SPaul Burton } \
69b025d518SPaul Burton }
70b025d518SPaul Burton
71ed7eb5aaSPaul Burton #define CPS_ACCESSOR_M(unit, sz, name) \
72ed7eb5aaSPaul Burton static inline void change_##unit##_##name(uint##sz##_t mask, \
73ed7eb5aaSPaul Burton uint##sz##_t val) \
74ed7eb5aaSPaul Burton { \
75ed7eb5aaSPaul Burton uint##sz##_t reg_val = read_##unit##_##name(); \
76ed7eb5aaSPaul Burton reg_val &= ~mask; \
77ed7eb5aaSPaul Burton reg_val |= val; \
78ed7eb5aaSPaul Burton write_##unit##_##name(reg_val); \
79ed7eb5aaSPaul Burton } \
80ed7eb5aaSPaul Burton \
81ed7eb5aaSPaul Burton static inline void set_##unit##_##name(uint##sz##_t val) \
82ed7eb5aaSPaul Burton { \
83ed7eb5aaSPaul Burton change_##unit##_##name(val, val); \
84ed7eb5aaSPaul Burton } \
85ed7eb5aaSPaul Burton \
86ed7eb5aaSPaul Burton static inline void clear_##unit##_##name(uint##sz##_t val) \
87ed7eb5aaSPaul Burton { \
88ed7eb5aaSPaul Burton change_##unit##_##name(val, 0); \
89ed7eb5aaSPaul Burton }
90ed7eb5aaSPaul Burton
91b025d518SPaul Burton #define CPS_ACCESSOR_RO(unit, sz, off, name) \
92b025d518SPaul Burton CPS_ACCESSOR_A(unit, off, name) \
93b025d518SPaul Burton CPS_ACCESSOR_R(unit, sz, name)
94b025d518SPaul Burton
95b025d518SPaul Burton #define CPS_ACCESSOR_WO(unit, sz, off, name) \
96b025d518SPaul Burton CPS_ACCESSOR_A(unit, off, name) \
97b025d518SPaul Burton CPS_ACCESSOR_W(unit, sz, name)
98b025d518SPaul Burton
99b025d518SPaul Burton #define CPS_ACCESSOR_RW(unit, sz, off, name) \
100b025d518SPaul Burton CPS_ACCESSOR_A(unit, off, name) \
101b025d518SPaul Burton CPS_ACCESSOR_R(unit, sz, name) \
102ed7eb5aaSPaul Burton CPS_ACCESSOR_W(unit, sz, name) \
103ed7eb5aaSPaul Burton CPS_ACCESSOR_M(unit, sz, name)
104b025d518SPaul Burton
105e83f7e02SPaul Burton #include <asm/mips-cm.h>
106e83f7e02SPaul Burton #include <asm/mips-cpc.h>
107582e2b4aSPaul Burton #include <asm/mips-gic.h>
108e83f7e02SPaul Burton
1093c9b4166SPaul Burton /**
1103c9b4166SPaul Burton * mips_cps_numclusters - return the number of clusters present in the system
1113c9b4166SPaul Burton *
1123c9b4166SPaul Burton * Returns the number of clusters in the system.
1133c9b4166SPaul Burton */
mips_cps_numclusters(void)1143c9b4166SPaul Burton static inline unsigned int mips_cps_numclusters(void)
1153c9b4166SPaul Burton {
1163c9b4166SPaul Burton if (mips_cm_revision() < CM_REV_CM3_5)
1173c9b4166SPaul Burton return 1;
1183c9b4166SPaul Burton
119*4e1fc0a4SGeert Uytterhoeven return FIELD_GET(CM_GCR_CONFIG_NUM_CLUSTERS, read_gcr_config());
1203c9b4166SPaul Burton }
1213c9b4166SPaul Burton
1223c9b4166SPaul Burton /**
1233c9b4166SPaul Burton * mips_cps_cluster_config - return (GCR|CPC)_CONFIG from a cluster
1243c9b4166SPaul Burton * @cluster: the ID of the cluster whose config we want
1253c9b4166SPaul Burton *
1263c9b4166SPaul Burton * Read the value of GCR_CONFIG (or its CPC_CONFIG mirror) from a @cluster.
1273c9b4166SPaul Burton *
1283c9b4166SPaul Burton * Returns the value of GCR_CONFIG.
1293c9b4166SPaul Burton */
mips_cps_cluster_config(unsigned int cluster)1303c9b4166SPaul Burton static inline uint64_t mips_cps_cluster_config(unsigned int cluster)
1313c9b4166SPaul Burton {
1323c9b4166SPaul Burton uint64_t config;
1333c9b4166SPaul Burton
1343c9b4166SPaul Burton if (mips_cm_revision() < CM_REV_CM3_5) {
1353c9b4166SPaul Burton /*
1363c9b4166SPaul Burton * Prior to CM 3.5 we don't have the notion of multiple
1373c9b4166SPaul Burton * clusters so we can trivially read the GCR_CONFIG register
1383c9b4166SPaul Burton * within this cluster.
1393c9b4166SPaul Burton */
1403c9b4166SPaul Burton WARN_ON(cluster != 0);
1413c9b4166SPaul Burton config = read_gcr_config();
1423c9b4166SPaul Burton } else {
1433c9b4166SPaul Burton /*
1443c9b4166SPaul Burton * From CM 3.5 onwards we read the CPC_CONFIG mirror of
1453c9b4166SPaul Burton * GCR_CONFIG via the redirect region, since the CPC is always
1463c9b4166SPaul Burton * powered up allowing us not to need to power up the CM.
1473c9b4166SPaul Burton */
1483c9b4166SPaul Burton mips_cm_lock_other(cluster, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
1493c9b4166SPaul Burton config = read_cpc_redir_config();
1503c9b4166SPaul Burton mips_cm_unlock_other();
1513c9b4166SPaul Burton }
1523c9b4166SPaul Burton
1533c9b4166SPaul Burton return config;
1543c9b4166SPaul Burton }
1553c9b4166SPaul Burton
1563c9b4166SPaul Burton /**
1573c9b4166SPaul Burton * mips_cps_numcores - return the number of cores present in a cluster
1583c9b4166SPaul Burton * @cluster: the ID of the cluster whose core count we want
1593c9b4166SPaul Burton *
1603c9b4166SPaul Burton * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
1613c9b4166SPaul Burton * zero if no Coherence Manager is present.
1623c9b4166SPaul Burton */
mips_cps_numcores(unsigned int cluster)1633c9b4166SPaul Burton static inline unsigned int mips_cps_numcores(unsigned int cluster)
1643c9b4166SPaul Burton {
1653c9b4166SPaul Burton if (!mips_cm_present())
1663c9b4166SPaul Burton return 0;
1673c9b4166SPaul Burton
1683c9b4166SPaul Burton /* Add one before masking to handle 0xff indicating no cores */
169*4e1fc0a4SGeert Uytterhoeven return FIELD_GET(CM_GCR_CONFIG_PCORES,
170*4e1fc0a4SGeert Uytterhoeven mips_cps_cluster_config(cluster) + 1);
1713c9b4166SPaul Burton }
1723c9b4166SPaul Burton
1733c9b4166SPaul Burton /**
1743c9b4166SPaul Burton * mips_cps_numiocu - return the number of IOCUs present in a cluster
1753c9b4166SPaul Burton * @cluster: the ID of the cluster whose IOCU count we want
1763c9b4166SPaul Burton *
1773c9b4166SPaul Burton * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
1783c9b4166SPaul Burton * if no Coherence Manager is present.
1793c9b4166SPaul Burton */
mips_cps_numiocu(unsigned int cluster)1803c9b4166SPaul Burton static inline unsigned int mips_cps_numiocu(unsigned int cluster)
1813c9b4166SPaul Burton {
1823c9b4166SPaul Burton if (!mips_cm_present())
1833c9b4166SPaul Burton return 0;
1843c9b4166SPaul Burton
185*4e1fc0a4SGeert Uytterhoeven return FIELD_GET(CM_GCR_CONFIG_NUMIOCU,
186*4e1fc0a4SGeert Uytterhoeven mips_cps_cluster_config(cluster));
1873c9b4166SPaul Burton }
1883c9b4166SPaul Burton
1893c9b4166SPaul Burton /**
1903c9b4166SPaul Burton * mips_cps_numvps - return the number of VPs (threads) supported by a core
1913c9b4166SPaul Burton * @cluster: the ID of the cluster containing the core we want to examine
1923c9b4166SPaul Burton * @core: the ID of the core whose VP count we want
1933c9b4166SPaul Burton *
1943c9b4166SPaul Burton * Returns the number of Virtual Processors (VPs, ie. hardware threads) that
1953c9b4166SPaul Burton * are supported by the given @core in the given @cluster. If the core or the
1963c9b4166SPaul Burton * kernel do not support hardware mutlti-threading this returns 1.
1973c9b4166SPaul Burton */
mips_cps_numvps(unsigned int cluster,unsigned int core)1983c9b4166SPaul Burton static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int core)
1993c9b4166SPaul Burton {
2003c9b4166SPaul Burton unsigned int cfg;
2013c9b4166SPaul Burton
2023c9b4166SPaul Burton if (!mips_cm_present())
2033c9b4166SPaul Burton return 1;
2043c9b4166SPaul Burton
2053c9b4166SPaul Burton if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
2063c9b4166SPaul Burton && (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
2073c9b4166SPaul Burton return 1;
2083c9b4166SPaul Burton
2093c9b4166SPaul Burton mips_cm_lock_other(cluster, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
2103c9b4166SPaul Burton
2113c9b4166SPaul Burton if (mips_cm_revision() < CM_REV_CM3_5) {
2123c9b4166SPaul Burton /*
2133c9b4166SPaul Burton * Prior to CM 3.5 we can only have one cluster & don't have
2143c9b4166SPaul Burton * CPC_Cx_CONFIG, so we read GCR_Cx_CONFIG.
2153c9b4166SPaul Burton */
2163c9b4166SPaul Burton cfg = read_gcr_co_config();
2173c9b4166SPaul Burton } else {
2183c9b4166SPaul Burton /*
2193c9b4166SPaul Burton * From CM 3.5 onwards we read CPC_Cx_CONFIG because the CPC is
2203c9b4166SPaul Burton * always powered, which allows us to not worry about powering
2213c9b4166SPaul Burton * up the cluster's CM here.
2223c9b4166SPaul Burton */
2233c9b4166SPaul Burton cfg = read_cpc_co_config();
2243c9b4166SPaul Burton }
2253c9b4166SPaul Burton
2263c9b4166SPaul Burton mips_cm_unlock_other();
2273c9b4166SPaul Burton
228*4e1fc0a4SGeert Uytterhoeven return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, cfg + 1);
2293c9b4166SPaul Burton }
2303c9b4166SPaul Burton
231b025d518SPaul Burton #endif /* __MIPS_ASM_MIPS_CPS_H__ */
232