forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
5.1 KiB
272 lines
5.1 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright 2020, Jordan Niethe, IBM Corporation. |
|
* |
|
* This file contains low level CPU setup functions. |
|
* Originally written in assembly by Benjamin Herrenschmidt & various other |
|
* authors. |
|
*/ |
|
|
|
#include <asm/reg.h> |
|
#include <asm/synch.h> |
|
#include <linux/bitops.h> |
|
#include <asm/cputable.h> |
|
#include <asm/cpu_setup_power.h> |
|
|
|
/* Disable CPU_FTR_HVMODE and return false if MSR:HV is not set */ |
|
static bool init_hvmode_206(struct cpu_spec *t) |
|
{ |
|
u64 msr; |
|
|
|
msr = mfmsr(); |
|
if (msr & MSR_HV) |
|
return true; |
|
|
|
t->cpu_features &= ~(CPU_FTR_HVMODE | CPU_FTR_P9_TM_HV_ASSIST); |
|
return false; |
|
} |
|
|
|
static void init_LPCR_ISA300(u64 lpcr, u64 lpes) |
|
{ |
|
/* POWER9 has no VRMASD */ |
|
lpcr |= (lpes << LPCR_LPES_SH) & LPCR_LPES; |
|
lpcr |= LPCR_PECE0|LPCR_PECE1|LPCR_PECE2; |
|
lpcr |= (4ull << LPCR_DPFD_SH) & LPCR_DPFD; |
|
lpcr &= ~LPCR_HDICE; /* clear HDICE */ |
|
lpcr |= (4ull << LPCR_VC_SH); |
|
mtspr(SPRN_LPCR, lpcr); |
|
isync(); |
|
} |
|
|
|
/* |
|
* Setup a sane LPCR: |
|
* Called with initial LPCR and desired LPES 2-bit value |
|
* |
|
* LPES = 0b01 (HSRR0/1 used for 0x500) |
|
* PECE = 0b111 |
|
* DPFD = 4 |
|
* HDICE = 0 |
|
* VC = 0b100 (VPM0=1, VPM1=0, ISL=0) |
|
* VRMASD = 0b10000 (L=1, LP=00) |
|
* |
|
* Other bits untouched for now |
|
*/ |
|
static void init_LPCR_ISA206(u64 lpcr, u64 lpes) |
|
{ |
|
lpcr |= (0x10ull << LPCR_VRMASD_SH) & LPCR_VRMASD; |
|
init_LPCR_ISA300(lpcr, lpes); |
|
} |
|
|
|
static void init_FSCR(void) |
|
{ |
|
u64 fscr; |
|
|
|
fscr = mfspr(SPRN_FSCR); |
|
fscr |= FSCR_TAR|FSCR_EBB; |
|
mtspr(SPRN_FSCR, fscr); |
|
} |
|
|
|
static void init_FSCR_power9(void) |
|
{ |
|
u64 fscr; |
|
|
|
fscr = mfspr(SPRN_FSCR); |
|
fscr |= FSCR_SCV; |
|
mtspr(SPRN_FSCR, fscr); |
|
init_FSCR(); |
|
} |
|
|
|
static void init_FSCR_power10(void) |
|
{ |
|
u64 fscr; |
|
|
|
fscr = mfspr(SPRN_FSCR); |
|
fscr |= FSCR_PREFIX; |
|
mtspr(SPRN_FSCR, fscr); |
|
init_FSCR_power9(); |
|
} |
|
|
|
static void init_HFSCR(void) |
|
{ |
|
u64 hfscr; |
|
|
|
hfscr = mfspr(SPRN_HFSCR); |
|
hfscr |= HFSCR_TAR|HFSCR_TM|HFSCR_BHRB|HFSCR_PM|HFSCR_DSCR|\ |
|
HFSCR_VECVSX|HFSCR_FP|HFSCR_EBB|HFSCR_MSGP; |
|
mtspr(SPRN_HFSCR, hfscr); |
|
} |
|
|
|
static void init_PMU_HV(void) |
|
{ |
|
mtspr(SPRN_MMCRC, 0); |
|
} |
|
|
|
static void init_PMU_HV_ISA207(void) |
|
{ |
|
mtspr(SPRN_MMCRH, 0); |
|
} |
|
|
|
static void init_PMU(void) |
|
{ |
|
mtspr(SPRN_MMCRA, 0); |
|
mtspr(SPRN_MMCR0, 0); |
|
mtspr(SPRN_MMCR1, 0); |
|
mtspr(SPRN_MMCR2, 0); |
|
} |
|
|
|
static void init_PMU_ISA207(void) |
|
{ |
|
mtspr(SPRN_MMCRS, 0); |
|
} |
|
|
|
static void init_PMU_ISA31(void) |
|
{ |
|
mtspr(SPRN_MMCR3, 0); |
|
mtspr(SPRN_MMCRA, MMCRA_BHRB_DISABLE); |
|
mtspr(SPRN_MMCR0, MMCR0_PMCCEXT); |
|
} |
|
|
|
/* |
|
* Note that we can be called twice of pseudo-PVRs. |
|
* The parameter offset is not used. |
|
*/ |
|
|
|
void __setup_cpu_power7(unsigned long offset, struct cpu_spec *t) |
|
{ |
|
if (!init_hvmode_206(t)) |
|
return; |
|
|
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); |
|
} |
|
|
|
void __restore_cpu_power7(void) |
|
{ |
|
u64 msr; |
|
|
|
msr = mfmsr(); |
|
if (!(msr & MSR_HV)) |
|
return; |
|
|
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA206(mfspr(SPRN_LPCR), LPCR_LPES1 >> LPCR_LPES_SH); |
|
} |
|
|
|
void __setup_cpu_power8(unsigned long offset, struct cpu_spec *t) |
|
{ |
|
init_FSCR(); |
|
init_PMU(); |
|
init_PMU_ISA207(); |
|
|
|
if (!init_hvmode_206(t)) |
|
return; |
|
|
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
init_PMU_HV_ISA207(); |
|
} |
|
|
|
void __restore_cpu_power8(void) |
|
{ |
|
u64 msr; |
|
|
|
init_FSCR(); |
|
init_PMU(); |
|
init_PMU_ISA207(); |
|
|
|
msr = mfmsr(); |
|
if (!(msr & MSR_HV)) |
|
return; |
|
|
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA206(mfspr(SPRN_LPCR) | LPCR_PECEDH, 0); /* LPES = 0 */ |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
init_PMU_HV_ISA207(); |
|
} |
|
|
|
void __setup_cpu_power9(unsigned long offset, struct cpu_spec *t) |
|
{ |
|
init_FSCR_power9(); |
|
init_PMU(); |
|
|
|
if (!init_hvmode_206(t)) |
|
return; |
|
|
|
mtspr(SPRN_PSSCR, 0); |
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ |
|
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
} |
|
|
|
void __restore_cpu_power9(void) |
|
{ |
|
u64 msr; |
|
|
|
init_FSCR_power9(); |
|
init_PMU(); |
|
|
|
msr = mfmsr(); |
|
if (!(msr & MSR_HV)) |
|
return; |
|
|
|
mtspr(SPRN_PSSCR, 0); |
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ |
|
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
} |
|
|
|
void __setup_cpu_power10(unsigned long offset, struct cpu_spec *t) |
|
{ |
|
init_FSCR_power10(); |
|
init_PMU(); |
|
init_PMU_ISA31(); |
|
|
|
if (!init_hvmode_206(t)) |
|
return; |
|
|
|
mtspr(SPRN_PSSCR, 0); |
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ |
|
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
} |
|
|
|
void __restore_cpu_power10(void) |
|
{ |
|
u64 msr; |
|
|
|
init_FSCR_power10(); |
|
init_PMU(); |
|
init_PMU_ISA31(); |
|
|
|
msr = mfmsr(); |
|
if (!(msr & MSR_HV)) |
|
return; |
|
|
|
mtspr(SPRN_PSSCR, 0); |
|
mtspr(SPRN_LPID, 0); |
|
mtspr(SPRN_PID, 0); |
|
mtspr(SPRN_PCR, PCR_MASK); |
|
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\ |
|
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0); |
|
init_HFSCR(); |
|
init_PMU_HV(); |
|
}
|
|
|