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.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, MMCR0_FC); 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_FC | MMCR0_PMCCEXT); 127} 128 129static void init_DEXCR(void) 130{ 131 mtspr(SPRN_DEXCR, DEXCR_INIT); 132 mtspr(SPRN_HASHKEYR, 0); 133} 134 135/* 136 * Note that we can be called twice of pseudo-PVRs. 137 * The parameter offset is not used. 138 */ 139 140void __setup_cpu_power7(unsigned long offset, struct cpu_spec *t) 141{ 142 if (!init_hvmode_206(t)) 143 return; 144 145 mtspr(SPRN_LPID, 0); 146 mtspr(SPRN_AMOR, ~0); 147 mtspr(SPRN_PCR, PCR_MASK); 148 init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); 149} 150 151void __restore_cpu_power7(void) 152{ 153 u64 msr; 154 155 msr = mfmsr(); 156 if (!(msr & MSR_HV)) 157 return; 158 159 mtspr(SPRN_LPID, 0); 160 mtspr(SPRN_AMOR, ~0); 161 mtspr(SPRN_PCR, PCR_MASK); 162 init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); 163} 164 165void __setup_cpu_power8(unsigned long offset, struct cpu_spec *t) 166{ 167 init_FSCR(); 168 init_PMU(); 169 init_PMU_ISA207(); 170 171 if (!init_hvmode_206(t)) 172 return; 173 174 mtspr(SPRN_LPID, 0); 175 mtspr(SPRN_AMOR, ~0); 176 mtspr(SPRN_PCR, PCR_MASK); 177 init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ 178 init_HFSCR(); 179 init_PMU_HV(); 180 init_PMU_HV_ISA207(); 181} 182 183void __restore_cpu_power8(void) 184{ 185 u64 msr; 186 187 init_FSCR(); 188 init_PMU(); 189 init_PMU_ISA207(); 190 191 msr = mfmsr(); 192 if (!(msr & MSR_HV)) 193 return; 194 195 mtspr(SPRN_LPID, 0); 196 mtspr(SPRN_AMOR, ~0); 197 mtspr(SPRN_PCR, PCR_MASK); 198 init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ 199 init_HFSCR(); 200 init_PMU_HV(); 201 init_PMU_HV_ISA207(); 202} 203 204void __setup_cpu_power9(unsigned long offset, struct cpu_spec *t) 205{ 206 init_FSCR_power9(); 207 init_PMU(); 208 209 if (!init_hvmode_206(t)) 210 return; 211 212 mtspr(SPRN_PSSCR, 0); 213 mtspr(SPRN_LPID, 0); 214 mtspr(SPRN_PID, 0); 215 mtspr(SPRN_AMOR, ~0); 216 mtspr(SPRN_PCR, PCR_MASK); 217 init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ 218 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); 219 init_HFSCR(); 220 init_PMU_HV(); 221} 222 223void __restore_cpu_power9(void) 224{ 225 u64 msr; 226 227 init_FSCR_power9(); 228 init_PMU(); 229 230 msr = mfmsr(); 231 if (!(msr & MSR_HV)) 232 return; 233 234 mtspr(SPRN_PSSCR, 0); 235 mtspr(SPRN_LPID, 0); 236 mtspr(SPRN_PID, 0); 237 mtspr(SPRN_AMOR, ~0); 238 mtspr(SPRN_PCR, PCR_MASK); 239 init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ 240 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); 241 init_HFSCR(); 242 init_PMU_HV(); 243} 244 245void __setup_cpu_power10(unsigned long offset, struct cpu_spec *t) 246{ 247 init_FSCR_power10(); 248 init_PMU(); 249 init_PMU_ISA31(); 250 init_DEXCR(); 251 252 if (!init_hvmode_206(t)) 253 return; 254 255 mtspr(SPRN_PSSCR, 0); 256 mtspr(SPRN_LPID, 0); 257 mtspr(SPRN_PID, 0); 258 mtspr(SPRN_AMOR, ~0); 259 mtspr(SPRN_PCR, PCR_MASK); 260 init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ 261 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); 262 init_HFSCR(); 263 init_PMU_HV(); 264} 265 266void __restore_cpu_power10(void) 267{ 268 u64 msr; 269 270 init_FSCR_power10(); 271 init_PMU(); 272 init_PMU_ISA31(); 273 init_DEXCR(); 274 275 msr = mfmsr(); 276 if (!(msr & MSR_HV)) 277 return; 278 279 mtspr(SPRN_PSSCR, 0); 280 mtspr(SPRN_LPID, 0); 281 mtspr(SPRN_PID, 0); 282 mtspr(SPRN_AMOR, ~0); 283 mtspr(SPRN_PCR, PCR_MASK); 284 init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ 285 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); 286 init_HFSCR(); 287 init_PMU_HV(); 288} 289