xref: /illumos-gate/usr/src/uts/intel/sys/amdzen/thm.h (revision 92279cb6e70fd12428e1d9e6270e7e2d877cbeec)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 #ifndef _SYS_AMDZEN_THM_H
17 #define	_SYS_AMDZEN_THM_H
18 
19 #include <sys/bitext.h>
20 #include <sys/amdzen/smn.h>
21 
22 /*
23  * This header covers the SMU's (system management unit) thermal block. The SMU,
24  * often called MP1 in various AMD docs, exists as a single entity in the I/O
25  * die (or a Zen 1 Zeppelin die), leaving most registers at a fixed entry point
26  * and block.
27  *
28  * The thermal block SMN registers are generally shadows or calculated
29  * information based on a series of internal diodes, slewing, and other related
30  * features that exist within the SOC. Only a subset of the overall thermal
31  * registers are described here which are used by us to obtain information. The
32  * majority of the other registers are only used by the SMU and perhaps the PSP.
33  * Note, similar information is provided over the sideband temperature interface
34  * (SB-TSI), which is consumed by the service processor on a system board that
35  * maintains a thermal loop.
36  *
37  * Note, CCDs have their own separate thermal block, SMU::THMCCD.
38  */
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /*
45  * SMU::THM registers, per-die.  This functional unit is present in all Zen CPUs
46  * and is effectively a singleton.
47  */
48 #define	SMU_THM_APERTURE_MASK	0xfffffffffffff800
49 AMDZEN_MAKE_SMN_REG_FN(amdzen_smuthm_smn_reg, SMU_THM, 0x59800,
50     SMU_THM_APERTURE_MASK, 1, 0);
51 
52 /*
53  * SMU::THM::THM_TCON_CUR_TMP -- the primary thermal sensor in a given die. This
54  * is where Tctl generally comes from. Regardless of whether it encodes Tctl or
55  * Tj, the value is measured in 0.125 steps, hence a granularity of 8. The three
56  * lower bits of the temperature are to the right of the decimal.
57  */
58 #define	THM_CURTEMP		SMN_MAKE_REG(0x59800)
59 #define	THM_CURTEMP_GET_TEMP(r)		bitx32(r, 31, 21)
60 #define	THM_CURTEMP_TEMP_DEC_BITS	3
61 #define	THM_CURTEMP_TEMP_DEC_MASK	0x7
62 #define	THM_CURTEMP_TEMP_DEC_GRAN	8
63 #define	THM_CURTEMP_GET_MCM(r)		bitx32(r, 20, 20)
64 #define	THM_CURTEMP_GET_RANGE(r)	bitx32(r, 19, 19)
65 #define	THM_CURTEMP_RANGE_O_225		0
66 #define	THM_CURTEMP_RANGE_N49_206	1
67 #define	THM_CURTEMP_RANGE_ADJ		(-49)
68 #define	THM_CURTEMP_GET_SLEW_SEL(r)	bitx32(r, 18, 18)
69 #define	THM_CURTEMP_GET_TJ_SEL(r)	bitx32(r, 17, 16)
70 #define	THM_CURTEMP_TJ_SEL_TCTL		0
71 #define	THM_CURTEMP_TJ_SEL_TJ		2
72 #define	THM_CURTEMP_TJ_SEL_RW		3
73 #define	THM_CURTEMP_GET_TIME_DOWN(r)	bitx32(r, 12, 8)
74 #define	THM_CURTEMP_GET_SLEW_DOWN_EN(r)	bitx32(r, 7, 7)
75 #define	THM_CURTEMP_GET_MAX_DIFF(r)	bitx32(r, 6, 5)
76 #define	THM_CURTEMP_GET_TIME_UP(r)	bitx32(r, 4, 0)
77 
78 /*
79  * SMU::THM::THM_DIEX_TEMP -- this is a per-die measurement that comes from the
80  * thermal monitor. It measures Tdie and is in degrees C. The value is otherwise
81  * in the same format as described for SMU::THM::THM_TCON_CUR_TMP. Unlike Tctl
82  * above, this has a valid bit that must be consulted. Our understanding is that
83  * the valid bit, once set, will generally remain true.
84  *
85  * This register has a bit of an unfortunate history. The number of these that
86  * are valid and their location unfortunately changes on a per-CPU basis. This
87  * results in a much more complicated function for getting this with
88  * corresponding limits.
89  */
90 static inline uint16_t
THM_DIE_MAX_UNITS(x86_processor_family_t fam)91 THM_DIE_MAX_UNITS(x86_processor_family_t fam)
92 {
93 	switch (fam) {
94 	case X86_PF_AMD_STRIX_HALO:
95 		return (2);
96 	case X86_PF_AMD_NAPLES:
97 	case X86_PF_AMD_PINNACLE_RIDGE:
98 	case X86_PF_AMD_RAVEN_RIDGE:
99 	case X86_PF_AMD_PICASSO:
100 	case X86_PF_AMD_DALI:
101 	case X86_PF_HYGON_DHYANA:
102 		return (4);
103 	case X86_PF_AMD_ROME:
104 	case X86_PF_AMD_RENOIR:
105 	case X86_PF_AMD_MATISSE:
106 	case X86_PF_AMD_VAN_GOGH:
107 	case X86_PF_AMD_MILAN:
108 	case X86_PF_AMD_VERMEER:
109 	case X86_PF_AMD_CEZANNE:
110 	case X86_PF_AMD_MENDOCINO:
111 	case X86_PF_AMD_REMBRANDT:
112 	case X86_PF_AMD_RAPHAEL:
113 	case X86_PF_AMD_PHOENIX:
114 	case X86_PF_AMD_GRANITE_RIDGE:
115 		return (8);
116 	case X86_PF_AMD_GENOA:
117 	case X86_PF_AMD_BERGAMO:
118 		return (12);
119 	case X86_PF_AMD_TURIN:
120 	case X86_PF_AMD_DENSE_TURIN:
121 		return (16);
122 	case X86_PF_AMD_STRIX:
123 	case X86_PF_AMD_KRACKAN:
124 	default:
125 		return (0);
126 	}
127 }
128 
129 static inline smn_reg_t
THM_DIE(uint8_t dieno,x86_processor_family_t fam)130 THM_DIE(uint8_t dieno, x86_processor_family_t fam)
131 {
132 	smn_reg_def_t regdef = { 0 };
133 	regdef.srd_unit = SMN_UNIT_SMU_THM;
134 	regdef.srd_nents = THM_DIE_MAX_UNITS(fam);
135 	ASSERT3U(regdef.srd_nents, !=, 0);
136 
137 	switch (fam) {
138 	case X86_PF_AMD_NAPLES:
139 	case X86_PF_AMD_PINNACLE_RIDGE:
140 	case X86_PF_AMD_RAVEN_RIDGE:
141 	case X86_PF_AMD_PICASSO:
142 	case X86_PF_AMD_DALI:
143 	case X86_PF_HYGON_DHYANA:
144 	case X86_PF_AMD_ROME:
145 	case X86_PF_AMD_RENOIR:
146 	case X86_PF_AMD_MATISSE:
147 	case X86_PF_AMD_VAN_GOGH:
148 	case X86_PF_AMD_MILAN:
149 	case X86_PF_AMD_VERMEER:
150 	case X86_PF_AMD_CEZANNE:
151 		regdef.srd_reg = 0x154;
152 		break;
153 	case X86_PF_AMD_MENDOCINO:
154 	case X86_PF_AMD_REMBRANDT:
155 	case X86_PF_AMD_GENOA:
156 	case X86_PF_AMD_BERGAMO:
157 		regdef.srd_reg = 0x300;
158 		break;
159 	case X86_PF_AMD_RAPHAEL:
160 	case X86_PF_AMD_PHOENIX:
161 	case X86_PF_AMD_GRANITE_RIDGE:
162 		regdef.srd_reg = 0x308;
163 		break;
164 	case X86_PF_AMD_TURIN:
165 	case X86_PF_AMD_DENSE_TURIN:
166 		regdef.srd_reg = 0x1f0;
167 		break;
168 	case X86_PF_AMD_STRIX_HALO:
169 		regdef.srd_reg = 0x78;
170 		break;
171 	default:
172 		panic("encountered unknown family 0x%x while constructing "
173 		    "SMU::THM::THM_DIEX_TEMP", fam);
174 	}
175 
176 	return (amdzen_smuthm_smn_reg(0, regdef, dieno));
177 }
178 #define	THM_DIE_GET_VALID(r)	bitx32(r, 11, 11)
179 #define	THM_DIE_GET_TEMP(r)	bitx32(r, 10, 0)
180 
181 #ifdef __cplusplus
182 }
183 #endif
184 
185 #endif /* _SYS_AMDZEN_THM_H */
186