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 2024 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_NAPLES:
95 case X86_PF_AMD_PINNACLE_RIDGE:
96 case X86_PF_AMD_RAVEN_RIDGE:
97 case X86_PF_AMD_PICASSO:
98 case X86_PF_AMD_DALI:
99 case X86_PF_HYGON_DHYANA:
100 return (4);
101 case X86_PF_AMD_ROME:
102 case X86_PF_AMD_RENOIR:
103 case X86_PF_AMD_MATISSE:
104 case X86_PF_AMD_VAN_GOGH:
105 case X86_PF_AMD_MILAN:
106 case X86_PF_AMD_VERMEER:
107 case X86_PF_AMD_CEZANNE:
108 case X86_PF_AMD_MENDOCINO:
109 case X86_PF_AMD_REMBRANDT:
110 case X86_PF_AMD_RAPHAEL:
111 case X86_PF_AMD_PHOENIX:
112 case X86_PF_AMD_GRANITE_RIDGE:
113 return (8);
114 case X86_PF_AMD_GENOA:
115 case X86_PF_AMD_BERGAMO:
116 return (12);
117 case X86_PF_AMD_TURIN:
118 case X86_PF_AMD_DENSE_TURIN:
119 return (16);
120 case X86_PF_AMD_STRIX:
121 default:
122 return (0);
123 }
124 }
125
126 static inline smn_reg_t
THM_DIE(uint8_t dieno,x86_processor_family_t fam)127 THM_DIE(uint8_t dieno, x86_processor_family_t fam)
128 {
129 smn_reg_def_t regdef = { 0 };
130 regdef.srd_unit = SMN_UNIT_SMU_THM;
131 regdef.srd_nents = THM_DIE_MAX_UNITS(fam);
132 ASSERT3U(regdef.srd_nents, !=, 0);
133
134 switch (fam) {
135 case X86_PF_AMD_NAPLES:
136 case X86_PF_AMD_PINNACLE_RIDGE:
137 case X86_PF_AMD_RAVEN_RIDGE:
138 case X86_PF_AMD_PICASSO:
139 case X86_PF_AMD_DALI:
140 case X86_PF_HYGON_DHYANA:
141 case X86_PF_AMD_ROME:
142 case X86_PF_AMD_RENOIR:
143 case X86_PF_AMD_MATISSE:
144 case X86_PF_AMD_VAN_GOGH:
145 case X86_PF_AMD_MILAN:
146 case X86_PF_AMD_VERMEER:
147 case X86_PF_AMD_CEZANNE:
148 regdef.srd_reg = 0x154;
149 break;
150 case X86_PF_AMD_MENDOCINO:
151 case X86_PF_AMD_REMBRANDT:
152 case X86_PF_AMD_GENOA:
153 case X86_PF_AMD_BERGAMO:
154 regdef.srd_reg = 0x300;
155 break;
156 case X86_PF_AMD_RAPHAEL:
157 case X86_PF_AMD_PHOENIX:
158 case X86_PF_AMD_GRANITE_RIDGE:
159 regdef.srd_reg = 0x308;
160 break;
161 case X86_PF_AMD_TURIN:
162 case X86_PF_AMD_DENSE_TURIN:
163 regdef.srd_reg = 0x1f0;
164 break;
165 default:
166 panic("encountered unknown family 0x%x while constructing "
167 "SMU::THM::THM_DIEX_TEMP", fam);
168 }
169
170 return (amdzen_smuthm_smn_reg(0, regdef, dieno));
171 }
172 #define THM_DIE_GET_VALID(r) bitx32(r, 11, 11)
173 #define THM_DIE_GET_TEMP(r) bitx32(r, 10, 0)
174
175 #ifdef __cplusplus
176 }
177 #endif
178
179 #endif /* _SYS_AMDZEN_THM_H */
180