linux/arch/powerpc/kernel/cpu_setup_power.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2020, Jordan Niethe, IBM Corporation.
   4 *
   5 * This file contains low level CPU setup functions.
   6 * Originally written in assembly by Benjamin Herrenschmidt & various other
   7 * authors.
   8 */
   9
  10#include <asm/reg.h>
  11#include <asm/synch.h>
  12#include <linux/bitops.h>
  13#include <asm/cputable.h>
  14#include <asm/cpu_setup_power.h>
  15
  16/* Disable CPU_FTR_HVMODE and return false if MSR:HV is not set */
  17static bool init_hvmode_206(struct cpu_spec *t)
  18{
  19        u64 msr;
  20
  21        msr = mfmsr();
  22        if (msr & MSR_HV)
  23                return true;
  24
  25        t->cpu_features &= ~(CPU_FTR_HVMODE | CPU_FTR_P9_TM_HV_ASSIST);
  26        return false;
  27}
  28
  29static void init_LPCR_ISA300(u64 lpcr, u64 lpes)
  30{
  31        /* POWER9 has no VRMASD */
  32        lpcr |= (lpes << LPCR_LPES_SH) & LPCR_LPES;
  33        lpcr |= LPCR_PECE0|LPCR_PECE1|LPCR_PECE2;
  34        lpcr |= (4ull << LPCR_DPFD_SH) & LPCR_DPFD;
  35        lpcr &= ~LPCR_HDICE;    /* clear HDICE */
  36        lpcr |= (4ull << LPCR_VC_SH);
  37        mtspr(SPRN_LPCR, lpcr);
  38        isync();
  39}
  40
  41/*
  42 * Setup a sane LPCR:
  43 *   Called with initial LPCR and desired LPES 2-bit value
  44 *
  45 *   LPES = 0b01 (HSRR0/1 used for 0x500)
  46 *   PECE = 0b111
  47 *   DPFD = 4
  48 *   HDICE = 0
  49 *   VC = 0b100 (VPM0=1, VPM1=0, ISL=0)
  50 *   VRMASD = 0b10000 (L=1, LP=00)
  51 *
  52 * Other bits untouched for now
  53 */
  54static void init_LPCR_ISA206(u64 lpcr, u64 lpes)
  55{
  56        lpcr |= (0x10ull << LPCR_VRMASD_SH) & LPCR_VRMASD;
  57        init_LPCR_ISA300(lpcr, lpes);
  58}
  59
  60static void init_FSCR(void)
  61{
  62        u64 fscr;
  63
  64        fscr = mfspr(SPRN_FSCR);
  65        fscr |= FSCR_TAR|FSCR_EBB;
  66        mtspr(SPRN_FSCR, fscr);
  67}
  68
  69static void init_FSCR_power9(void)
  70{
  71        u64 fscr;
  72
  73        fscr = mfspr(SPRN_FSCR);
  74        fscr |= FSCR_SCV;
  75        mtspr(SPRN_FSCR, fscr);
  76        init_FSCR();
  77}
  78
  79static void init_FSCR_power10(void)
  80{
  81        u64 fscr;
  82
  83        fscr = mfspr(SPRN_FSCR);
  84        fscr |= FSCR_PREFIX;
  85        mtspr(SPRN_FSCR, fscr);
  86        init_FSCR_power9();
  87}
  88
  89static void init_HFSCR(void)
  90{
  91        u64 hfscr;
  92
  93        hfscr = mfspr(SPRN_HFSCR);
  94        hfscr |= HFSCR_TAR|HFSCR_TM|HFSCR_BHRB|HFSCR_PM|HFSCR_DSCR|\
  95                 HFSCR_VECVSX|HFSCR_FP|HFSCR_EBB|HFSCR_MSGP;
  96        mtspr(SPRN_HFSCR, hfscr);
  97}
  98
  99static void init_PMU_HV(void)
 100{
 101        mtspr(SPRN_MMCRC, 0);
 102}
 103
 104static void init_PMU_HV_ISA207(void)
 105{
 106        mtspr(SPRN_MMCRH, 0);
 107}
 108
 109static void init_PMU(void)
 110{
 111        mtspr(SPRN_MMCRA, 0);
 112        mtspr(SPRN_MMCR0, 0);
 113        mtspr(SPRN_MMCR1, 0);
 114        mtspr(SPRN_MMCR2, 0);
 115}
 116
 117static void init_PMU_ISA207(void)
 118{
 119        mtspr(SPRN_MMCRS, 0);
 120}
 121
 122static void init_PMU_ISA31(void)
 123{
 124        mtspr(SPRN_MMCR3, 0);
 125        mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE);
 126        mtspr(SPRN_MMCR0, MMCR0_PMCCEXT);
 127}
 128
 129/*
 130 * Note that we can be called twice of pseudo-PVRs.
 131 * The parameter offset is not used.
 132 */
 133
 134void __setup_cpu_power7(unsigned long offset, struct cpu_spec *t)
 135{
 136        if (!init_hvmode_206(t))
 137                return;
 138
 139        mtspr(SPRN_LPID, 0);
 140        mtspr(SPRN_PCR, PCR_MASK);
 141        init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH);
 142}
 143
 144void __restore_cpu_power7(void)
 145{
 146        u64 msr;
 147
 148        msr = mfmsr();
 149        if (!(msr & MSR_HV))
 150                return;
 151
 152        mtspr(SPRN_LPID, 0);
 153        mtspr(SPRN_PCR, PCR_MASK);
 154        init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH);
 155}
 156
 157void __setup_cpu_power8(unsigned long offset, struct cpu_spec *t)
 158{
 159        init_FSCR();
 160        init_PMU();
 161        init_PMU_ISA207();
 162
 163        if (!init_hvmode_206(t))
 164                return;
 165
 166        mtspr(SPRN_LPID, 0);
 167        mtspr(SPRN_PCR, PCR_MASK);
 168        init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
 169        init_HFSCR();
 170        init_PMU_HV();
 171        init_PMU_HV_ISA207();
 172}
 173
 174void __restore_cpu_power8(void)
 175{
 176        u64 msr;
 177
 178        init_FSCR();
 179        init_PMU();
 180        init_PMU_ISA207();
 181
 182        msr = mfmsr();
 183        if (!(msr & MSR_HV))
 184                return;
 185
 186        mtspr(SPRN_LPID, 0);
 187        mtspr(SPRN_PCR, PCR_MASK);
 188        init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
 189        init_HFSCR();
 190        init_PMU_HV();
 191        init_PMU_HV_ISA207();
 192}
 193
 194void __setup_cpu_power9(unsigned long offset, struct cpu_spec *t)
 195{
 196        init_FSCR_power9();
 197        init_PMU();
 198
 199        if (!init_hvmode_206(t))
 200                return;
 201
 202        mtspr(SPRN_PSSCR, 0);
 203        mtspr(SPRN_LPID, 0);
 204        mtspr(SPRN_PID, 0);
 205        mtspr(SPRN_PCR, PCR_MASK);
 206        init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
 207                         LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
 208        init_HFSCR();
 209        init_PMU_HV();
 210}
 211
 212void __restore_cpu_power9(void)
 213{
 214        u64 msr;
 215
 216        init_FSCR_power9();
 217        init_PMU();
 218
 219        msr = mfmsr();
 220        if (!(msr & MSR_HV))
 221                return;
 222
 223        mtspr(SPRN_PSSCR, 0);
 224        mtspr(SPRN_LPID, 0);
 225        mtspr(SPRN_PID, 0);
 226        mtspr(SPRN_PCR, PCR_MASK);
 227        init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
 228                         LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
 229        init_HFSCR();
 230        init_PMU_HV();
 231}
 232
 233void __setup_cpu_power10(unsigned long offset, struct cpu_spec *t)
 234{
 235        init_FSCR_power10();
 236        init_PMU();
 237        init_PMU_ISA31();
 238
 239        if (!init_hvmode_206(t))
 240                return;
 241
 242        mtspr(SPRN_PSSCR, 0);
 243        mtspr(SPRN_LPID, 0);
 244        mtspr(SPRN_PID, 0);
 245        mtspr(SPRN_PCR, PCR_MASK);
 246        init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
 247                         LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
 248        init_HFSCR();
 249        init_PMU_HV();
 250}
 251
 252void __restore_cpu_power10(void)
 253{
 254        u64 msr;
 255
 256        init_FSCR_power10();
 257        init_PMU();
 258        init_PMU_ISA31();
 259
 260        msr = mfmsr();
 261        if (!(msr & MSR_HV))
 262                return;
 263
 264        mtspr(SPRN_PSSCR, 0);
 265        mtspr(SPRN_LPID, 0);
 266        mtspr(SPRN_PID, 0);
 267        mtspr(SPRN_PCR, PCR_MASK);
 268        init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
 269                         LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
 270        init_HFSCR();
 271        init_PMU_HV();
 272}
 273