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 */ 17 static 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 29 static 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 */ 54 static 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 60 static 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 69 static 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 79 static 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 89 static 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 99 static void init_PMU_HV(void) 100 { 101 mtspr(SPRN_MMCRC, 0); 102 } 103 104 static void init_PMU_HV_ISA207(void) 105 { 106 mtspr(SPRN_MMCRH, 0); 107 } 108 109 static 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 117 static void init_PMU_ISA207(void) 118 { 119 mtspr(SPRN_MMCRS, 0); 120 } 121 122 static 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 134 void __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 144 void __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 157 void __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 174 void __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 194 void __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 212 void __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 233 void __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 252 void __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