xref: /OK3568_Linux_fs/kernel/tools/power/cpupower/utils/helpers/amd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #if defined(__i386__) || defined(__x86_64__)
3*4882a593Smuzhiyun #include <unistd.h>
4*4882a593Smuzhiyun #include <errno.h>
5*4882a593Smuzhiyun #include <stdio.h>
6*4882a593Smuzhiyun #include <stdint.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <pci/pci.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "helpers/helpers.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define MSR_AMD_PSTATE_STATUS	0xc0010063
13*4882a593Smuzhiyun #define MSR_AMD_PSTATE		0xc0010064
14*4882a593Smuzhiyun #define MSR_AMD_PSTATE_LIMIT	0xc0010061
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun union msr_pstate {
17*4882a593Smuzhiyun 	struct {
18*4882a593Smuzhiyun 		unsigned fid:6;
19*4882a593Smuzhiyun 		unsigned did:3;
20*4882a593Smuzhiyun 		unsigned vid:7;
21*4882a593Smuzhiyun 		unsigned res1:6;
22*4882a593Smuzhiyun 		unsigned nbdid:1;
23*4882a593Smuzhiyun 		unsigned res2:2;
24*4882a593Smuzhiyun 		unsigned nbvid:7;
25*4882a593Smuzhiyun 		unsigned iddval:8;
26*4882a593Smuzhiyun 		unsigned idddiv:2;
27*4882a593Smuzhiyun 		unsigned res3:21;
28*4882a593Smuzhiyun 		unsigned en:1;
29*4882a593Smuzhiyun 	} bits;
30*4882a593Smuzhiyun 	struct {
31*4882a593Smuzhiyun 		unsigned fid:8;
32*4882a593Smuzhiyun 		unsigned did:6;
33*4882a593Smuzhiyun 		unsigned vid:8;
34*4882a593Smuzhiyun 		unsigned iddval:8;
35*4882a593Smuzhiyun 		unsigned idddiv:2;
36*4882a593Smuzhiyun 		unsigned res1:31;
37*4882a593Smuzhiyun 		unsigned en:1;
38*4882a593Smuzhiyun 	} fam17h_bits;
39*4882a593Smuzhiyun 	unsigned long long val;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
get_did(int family,union msr_pstate pstate)42*4882a593Smuzhiyun static int get_did(int family, union msr_pstate pstate)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	int t;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (family == 0x12)
47*4882a593Smuzhiyun 		t = pstate.val & 0xf;
48*4882a593Smuzhiyun 	else if (family == 0x17 || family == 0x18)
49*4882a593Smuzhiyun 		t = pstate.fam17h_bits.did;
50*4882a593Smuzhiyun 	else
51*4882a593Smuzhiyun 		t = pstate.bits.did;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	return t;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
get_cof(int family,union msr_pstate pstate)56*4882a593Smuzhiyun static int get_cof(int family, union msr_pstate pstate)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	int t;
59*4882a593Smuzhiyun 	int fid, did, cof;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	did = get_did(family, pstate);
62*4882a593Smuzhiyun 	if (family == 0x17 || family == 0x18) {
63*4882a593Smuzhiyun 		fid = pstate.fam17h_bits.fid;
64*4882a593Smuzhiyun 		cof = 200 * fid / did;
65*4882a593Smuzhiyun 	} else {
66*4882a593Smuzhiyun 		t = 0x10;
67*4882a593Smuzhiyun 		fid = pstate.bits.fid;
68*4882a593Smuzhiyun 		if (family == 0x11)
69*4882a593Smuzhiyun 			t = 0x8;
70*4882a593Smuzhiyun 		cof = (100 * (fid + t)) >> did;
71*4882a593Smuzhiyun 	}
72*4882a593Smuzhiyun 	return cof;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /* Needs:
76*4882a593Smuzhiyun  * cpu          -> the cpu that gets evaluated
77*4882a593Smuzhiyun  * cpu_family   -> The cpu's family (0x10, 0x12,...)
78*4882a593Smuzhiyun  * boots_states -> how much boost states the machines support
79*4882a593Smuzhiyun  *
80*4882a593Smuzhiyun  * Fills up:
81*4882a593Smuzhiyun  * pstates -> a pointer to an array of size MAX_HW_PSTATES
82*4882a593Smuzhiyun  *            must be initialized with zeros.
83*4882a593Smuzhiyun  *            All available  HW pstates (including boost states)
84*4882a593Smuzhiyun  * no      -> amount of pstates above array got filled up with
85*4882a593Smuzhiyun  *
86*4882a593Smuzhiyun  * returns zero on success, -1 on failure
87*4882a593Smuzhiyun  */
decode_pstates(unsigned int cpu,unsigned int cpu_family,int boost_states,unsigned long * pstates,int * no)88*4882a593Smuzhiyun int decode_pstates(unsigned int cpu, unsigned int cpu_family,
89*4882a593Smuzhiyun 		   int boost_states, unsigned long *pstates, int *no)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	int i, psmax, pscur;
92*4882a593Smuzhiyun 	union msr_pstate pstate;
93*4882a593Smuzhiyun 	unsigned long long val;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/* Only read out frequencies from HW when CPU might be boostable
96*4882a593Smuzhiyun 	   to keep the code as short and clean as possible.
97*4882a593Smuzhiyun 	   Otherwise frequencies are exported via ACPI tables.
98*4882a593Smuzhiyun 	*/
99*4882a593Smuzhiyun 	if (cpu_family < 0x10 || cpu_family == 0x14)
100*4882a593Smuzhiyun 		return -1;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
103*4882a593Smuzhiyun 		return -1;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	psmax = (val >> 4) & 0x7;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
108*4882a593Smuzhiyun 		return -1;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	pscur = val & 0x7;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	pscur += boost_states;
113*4882a593Smuzhiyun 	psmax += boost_states;
114*4882a593Smuzhiyun 	for (i = 0; i <= psmax; i++) {
115*4882a593Smuzhiyun 		if (i >= MAX_HW_PSTATES) {
116*4882a593Smuzhiyun 			fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
117*4882a593Smuzhiyun 				psmax, MAX_HW_PSTATES);
118*4882a593Smuzhiyun 			return -1;
119*4882a593Smuzhiyun 		}
120*4882a593Smuzhiyun 		if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
121*4882a593Smuzhiyun 			return -1;
122*4882a593Smuzhiyun 		if ((cpu_family == 0x17) && (!pstate.fam17h_bits.en))
123*4882a593Smuzhiyun 			continue;
124*4882a593Smuzhiyun 		else if (!pstate.bits.en)
125*4882a593Smuzhiyun 			continue;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 		pstates[i] = get_cof(cpu_family, pstate);
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 	*no = i;
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
amd_pci_get_num_boost_states(int * active,int * states)133*4882a593Smuzhiyun int amd_pci_get_num_boost_states(int *active, int *states)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct pci_access *pci_acc;
136*4882a593Smuzhiyun 	struct pci_dev *device;
137*4882a593Smuzhiyun 	uint8_t val = 0;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	*active = *states = 0;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	device = pci_slot_func_init(&pci_acc, 0x18, 4);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (device == NULL)
144*4882a593Smuzhiyun 		return -ENODEV;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	val = pci_read_byte(device, 0x15c);
147*4882a593Smuzhiyun 	if (val & 3)
148*4882a593Smuzhiyun 		*active = 1;
149*4882a593Smuzhiyun 	else
150*4882a593Smuzhiyun 		*active = 0;
151*4882a593Smuzhiyun 	*states = (val >> 2) & 7;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	pci_cleanup(pci_acc);
154*4882a593Smuzhiyun 	return 0;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun #endif /* defined(__i386__) || defined(__x86_64__) */
157