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