18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2020, Jordan Niethe, IBM Corporation.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file contains low level CPU setup functions.
68c2ecf20Sopenharmony_ci * Originally written in assembly by Benjamin Herrenschmidt & various other
78c2ecf20Sopenharmony_ci * authors.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/reg.h>
118c2ecf20Sopenharmony_ci#include <asm/synch.h>
128c2ecf20Sopenharmony_ci#include <linux/bitops.h>
138c2ecf20Sopenharmony_ci#include <asm/cputable.h>
148c2ecf20Sopenharmony_ci#include <asm/cpu_setup_power.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* Disable CPU_FTR_HVMODE and return false if MSR:HV is not set */
178c2ecf20Sopenharmony_cistatic bool init_hvmode_206(struct cpu_spec *t)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	u64 msr;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	msr = mfmsr();
228c2ecf20Sopenharmony_ci	if (msr & MSR_HV)
238c2ecf20Sopenharmony_ci		return true;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	t->cpu_features &= ~(CPU_FTR_HVMODE | CPU_FTR_P9_TM_HV_ASSIST);
268c2ecf20Sopenharmony_ci	return false;
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void init_LPCR_ISA300(u64 lpcr, u64 lpes)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	/* POWER9 has no VRMASD */
328c2ecf20Sopenharmony_ci	lpcr |= (lpes << LPCR_LPES_SH) & LPCR_LPES;
338c2ecf20Sopenharmony_ci	lpcr |= LPCR_PECE0|LPCR_PECE1|LPCR_PECE2;
348c2ecf20Sopenharmony_ci	lpcr |= (4ull << LPCR_DPFD_SH) & LPCR_DPFD;
358c2ecf20Sopenharmony_ci	lpcr &= ~LPCR_HDICE;	/* clear HDICE */
368c2ecf20Sopenharmony_ci	lpcr |= (4ull << LPCR_VC_SH);
378c2ecf20Sopenharmony_ci	mtspr(SPRN_LPCR, lpcr);
388c2ecf20Sopenharmony_ci	isync();
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * Setup a sane LPCR:
438c2ecf20Sopenharmony_ci *   Called with initial LPCR and desired LPES 2-bit value
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci *   LPES = 0b01 (HSRR0/1 used for 0x500)
468c2ecf20Sopenharmony_ci *   PECE = 0b111
478c2ecf20Sopenharmony_ci *   DPFD = 4
488c2ecf20Sopenharmony_ci *   HDICE = 0
498c2ecf20Sopenharmony_ci *   VC = 0b100 (VPM0=1, VPM1=0, ISL=0)
508c2ecf20Sopenharmony_ci *   VRMASD = 0b10000 (L=1, LP=00)
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * Other bits untouched for now
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_cistatic void init_LPCR_ISA206(u64 lpcr, u64 lpes)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	lpcr |= (0x10ull << LPCR_VRMASD_SH) & LPCR_VRMASD;
578c2ecf20Sopenharmony_ci	init_LPCR_ISA300(lpcr, lpes);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void init_FSCR(void)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	u64 fscr;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	fscr = mfspr(SPRN_FSCR);
658c2ecf20Sopenharmony_ci	fscr |= FSCR_TAR|FSCR_EBB;
668c2ecf20Sopenharmony_ci	mtspr(SPRN_FSCR, fscr);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void init_FSCR_power9(void)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	u64 fscr;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	fscr = mfspr(SPRN_FSCR);
748c2ecf20Sopenharmony_ci	fscr |= FSCR_SCV;
758c2ecf20Sopenharmony_ci	mtspr(SPRN_FSCR, fscr);
768c2ecf20Sopenharmony_ci	init_FSCR();
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic void init_FSCR_power10(void)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	u64 fscr;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	fscr = mfspr(SPRN_FSCR);
848c2ecf20Sopenharmony_ci	fscr |= FSCR_PREFIX;
858c2ecf20Sopenharmony_ci	mtspr(SPRN_FSCR, fscr);
868c2ecf20Sopenharmony_ci	init_FSCR_power9();
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void init_HFSCR(void)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	u64 hfscr;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	hfscr = mfspr(SPRN_HFSCR);
948c2ecf20Sopenharmony_ci	hfscr |= HFSCR_TAR|HFSCR_TM|HFSCR_BHRB|HFSCR_PM|HFSCR_DSCR|\
958c2ecf20Sopenharmony_ci		 HFSCR_VECVSX|HFSCR_FP|HFSCR_EBB|HFSCR_MSGP;
968c2ecf20Sopenharmony_ci	mtspr(SPRN_HFSCR, hfscr);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void init_PMU_HV(void)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRC, 0);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void init_PMU_HV_ISA207(void)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRH, 0);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void init_PMU(void)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRA, 0);
1128c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, 0);
1138c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR1, 0);
1148c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR2, 0);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void init_PMU_ISA207(void)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRS, 0);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic void init_PMU_ISA31(void)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR3, 0);
1258c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE);
1268c2ecf20Sopenharmony_ci	mtspr(SPRN_MMCR0, MMCR0_PMCCEXT);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/*
1308c2ecf20Sopenharmony_ci * Note that we can be called twice of pseudo-PVRs.
1318c2ecf20Sopenharmony_ci * The parameter offset is not used.
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_civoid __setup_cpu_power7(unsigned long offset, struct cpu_spec *t)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	if (!init_hvmode_206(t))
1378c2ecf20Sopenharmony_ci		return;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
1408c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
1418c2ecf20Sopenharmony_ci	init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_civoid __restore_cpu_power7(void)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	u64 msr;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	msr = mfmsr();
1498c2ecf20Sopenharmony_ci	if (!(msr & MSR_HV))
1508c2ecf20Sopenharmony_ci		return;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
1538c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
1548c2ecf20Sopenharmony_ci	init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_civoid __setup_cpu_power8(unsigned long offset, struct cpu_spec *t)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	init_FSCR();
1608c2ecf20Sopenharmony_ci	init_PMU();
1618c2ecf20Sopenharmony_ci	init_PMU_ISA207();
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (!init_hvmode_206(t))
1648c2ecf20Sopenharmony_ci		return;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
1678c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
1688c2ecf20Sopenharmony_ci	init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
1698c2ecf20Sopenharmony_ci	init_HFSCR();
1708c2ecf20Sopenharmony_ci	init_PMU_HV();
1718c2ecf20Sopenharmony_ci	init_PMU_HV_ISA207();
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_civoid __restore_cpu_power8(void)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	u64 msr;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	init_FSCR();
1798c2ecf20Sopenharmony_ci	init_PMU();
1808c2ecf20Sopenharmony_ci	init_PMU_ISA207();
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	msr = mfmsr();
1838c2ecf20Sopenharmony_ci	if (!(msr & MSR_HV))
1848c2ecf20Sopenharmony_ci		return;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
1878c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
1888c2ecf20Sopenharmony_ci	init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */
1898c2ecf20Sopenharmony_ci	init_HFSCR();
1908c2ecf20Sopenharmony_ci	init_PMU_HV();
1918c2ecf20Sopenharmony_ci	init_PMU_HV_ISA207();
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_civoid __setup_cpu_power9(unsigned long offset, struct cpu_spec *t)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	init_FSCR_power9();
1978c2ecf20Sopenharmony_ci	init_PMU();
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (!init_hvmode_206(t))
2008c2ecf20Sopenharmony_ci		return;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	mtspr(SPRN_PSSCR, 0);
2038c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
2048c2ecf20Sopenharmony_ci	mtspr(SPRN_PID, 0);
2058c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
2068c2ecf20Sopenharmony_ci	init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
2078c2ecf20Sopenharmony_ci			 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
2088c2ecf20Sopenharmony_ci	init_HFSCR();
2098c2ecf20Sopenharmony_ci	init_PMU_HV();
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_civoid __restore_cpu_power9(void)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	u64 msr;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	init_FSCR_power9();
2178c2ecf20Sopenharmony_ci	init_PMU();
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	msr = mfmsr();
2208c2ecf20Sopenharmony_ci	if (!(msr & MSR_HV))
2218c2ecf20Sopenharmony_ci		return;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	mtspr(SPRN_PSSCR, 0);
2248c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
2258c2ecf20Sopenharmony_ci	mtspr(SPRN_PID, 0);
2268c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
2278c2ecf20Sopenharmony_ci	init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
2288c2ecf20Sopenharmony_ci			 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
2298c2ecf20Sopenharmony_ci	init_HFSCR();
2308c2ecf20Sopenharmony_ci	init_PMU_HV();
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_civoid __setup_cpu_power10(unsigned long offset, struct cpu_spec *t)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	init_FSCR_power10();
2368c2ecf20Sopenharmony_ci	init_PMU();
2378c2ecf20Sopenharmony_ci	init_PMU_ISA31();
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (!init_hvmode_206(t))
2408c2ecf20Sopenharmony_ci		return;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	mtspr(SPRN_PSSCR, 0);
2438c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
2448c2ecf20Sopenharmony_ci	mtspr(SPRN_PID, 0);
2458c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
2468c2ecf20Sopenharmony_ci	init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
2478c2ecf20Sopenharmony_ci			 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
2488c2ecf20Sopenharmony_ci	init_HFSCR();
2498c2ecf20Sopenharmony_ci	init_PMU_HV();
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_civoid __restore_cpu_power10(void)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	u64 msr;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	init_FSCR_power10();
2578c2ecf20Sopenharmony_ci	init_PMU();
2588c2ecf20Sopenharmony_ci	init_PMU_ISA31();
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	msr = mfmsr();
2618c2ecf20Sopenharmony_ci	if (!(msr & MSR_HV))
2628c2ecf20Sopenharmony_ci		return;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	mtspr(SPRN_PSSCR, 0);
2658c2ecf20Sopenharmony_ci	mtspr(SPRN_LPID, 0);
2668c2ecf20Sopenharmony_ci	mtspr(SPRN_PID, 0);
2678c2ecf20Sopenharmony_ci	mtspr(SPRN_PCR, PCR_MASK);
2688c2ecf20Sopenharmony_ci	init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
2698c2ecf20Sopenharmony_ci			 LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
2708c2ecf20Sopenharmony_ci	init_HFSCR();
2718c2ecf20Sopenharmony_ci	init_PMU_HV();
2728c2ecf20Sopenharmony_ci}
273