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
  13#include <asm/mips-boards/launch.h>
  14
  15extern unsigned long __cps_access_bad_size(void)
  16        __compiletime_error("Bad size for CPS accessor");
  17
  18#define CPS_ACCESSOR_A(unit, off, name)                                 \
  19static inline void *addr_##unit##_##name(void)                          \
  20{                                                                       \
  21        return mips_##unit##_base + (off);                              \
  22}
  23
  24#define CPS_ACCESSOR_R(unit, sz, name)                                  \
  25static 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)                                  \
  48static 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)                                  \
  73static 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                                                                        \
  82static inline void set_##unit##_##name(uint##sz##_t val)                \
  83{                                                                       \
  84        change_##unit##_##name(val, val);                               \
  85}                                                                       \
  86                                                                        \
  87static 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 */
 115static 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 */
 135static 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 */
 168static 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 */
 203static 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 */
 224static 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