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 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 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