11
11
* convert raw register values is from https://github.com/ocerman/zenpower.
12
12
* The information is not confirmed from chip datasheets, but experiments
13
13
* suggest that it provides reasonable temperature values.
14
+ * - Register addresses to read chip voltage and current are also from
15
+ * https://github.com/ocerman/zenpower, and not confirmed from chip
16
+ * datasheets. Current calibration is board specific and not typically
17
+ * shared by board vendors. For this reason, current values are
18
+ * normalized to report 1A/LSB for core current and and 0.25A/LSB for SoC
19
+ * current. Reported values can be adjusted using the sensors configuration
20
+ * file.
21
+ * - It is unknown if the mechanism to read CCD1/CCD2 temperature as well as
22
+ * current and voltage information works on higher-end Ryzen CPUs.
23
+ * Information reported by Windows tools suggests that additional sensors
24
+ * (both temperature and voltage/current) are supported, but their register
25
+ * location is currently unknown.
14
26
*/
15
27
16
28
#include <linux/bitops.h>
@@ -70,9 +82,16 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
70
82
#define F17H_M70H_CCD1_TEMP 0x00059954
71
83
#define F17H_M70H_CCD2_TEMP 0x00059958
72
84
85
+ #define F17H_M01H_SVI 0x0005A000
86
+ #define F17H_M01H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0xc)
87
+ #define F17H_M01H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10)
88
+
73
89
#define CUR_TEMP_SHIFT 21
74
90
#define CUR_TEMP_RANGE_SEL_MASK BIT(19)
75
91
92
+ #define CFACTOR_ICORE 1000000 /* 1A / LSB */
93
+ #define CFACTOR_ISOC 250000 /* 0.25A / LSB */
94
+
76
95
struct k10temp_data {
77
96
struct pci_dev * pdev ;
78
97
void (* read_htcreg )(struct pci_dev * pdev , u32 * regval );
@@ -82,6 +101,9 @@ struct k10temp_data {
82
101
bool show_tdie ;
83
102
bool show_tccd1 ;
84
103
bool show_tccd2 ;
104
+ u32 svi_addr [2 ];
105
+ bool show_current ;
106
+ int cfactor [2 ];
85
107
};
86
108
87
109
struct tctl_offset {
@@ -99,6 +121,16 @@ static const struct tctl_offset tctl_offset_table[] = {
99
121
{ 0x17 , "AMD Ryzen Threadripper 29" , 27000 }, /* 29{20,50,70,90}[W]X */
100
122
};
101
123
124
+ static bool is_threadripper (void )
125
+ {
126
+ return strstr (boot_cpu_data .x86_model_id , "Threadripper" );
127
+ }
128
+
129
+ static bool is_epyc (void )
130
+ {
131
+ return strstr (boot_cpu_data .x86_model_id , "EPYC" );
132
+ }
133
+
102
134
static void read_htcreg_pci (struct pci_dev * pdev , u32 * regval )
103
135
{
104
136
pci_read_config_dword (pdev , REG_HARDWARE_THERMAL_CONTROL , regval );
@@ -157,16 +189,76 @@ const char *k10temp_temp_label[] = {
157
189
"Tccd2" ,
158
190
};
159
191
192
+ const char * k10temp_in_label [] = {
193
+ "Vcore" ,
194
+ "Vsoc" ,
195
+ };
196
+
197
+ const char * k10temp_curr_label [] = {
198
+ "Icore" ,
199
+ "Isoc" ,
200
+ };
201
+
160
202
static int k10temp_read_labels (struct device * dev ,
161
203
enum hwmon_sensor_types type ,
162
204
u32 attr , int channel , const char * * str )
163
205
{
164
- * str = k10temp_temp_label [channel ];
206
+ switch (type ) {
207
+ case hwmon_temp :
208
+ * str = k10temp_temp_label [channel ];
209
+ break ;
210
+ case hwmon_in :
211
+ * str = k10temp_in_label [channel ];
212
+ break ;
213
+ case hwmon_curr :
214
+ * str = k10temp_curr_label [channel ];
215
+ break ;
216
+ default :
217
+ return - EOPNOTSUPP ;
218
+ }
165
219
return 0 ;
166
220
}
167
221
168
- static int k10temp_read (struct device * dev , enum hwmon_sensor_types type ,
169
- u32 attr , int channel , long * val )
222
+ static int k10temp_read_curr (struct device * dev , u32 attr , int channel ,
223
+ long * val )
224
+ {
225
+ struct k10temp_data * data = dev_get_drvdata (dev );
226
+ u32 regval ;
227
+
228
+ switch (attr ) {
229
+ case hwmon_curr_input :
230
+ amd_smn_read (amd_pci_dev_to_node_id (data -> pdev ),
231
+ data -> svi_addr [channel ], & regval );
232
+ * val = DIV_ROUND_CLOSEST (data -> cfactor [channel ] *
233
+ (regval & 0xff ),
234
+ 1000 );
235
+ break ;
236
+ default :
237
+ return - EOPNOTSUPP ;
238
+ }
239
+ return 0 ;
240
+ }
241
+
242
+ static int k10temp_read_in (struct device * dev , u32 attr , int channel , long * val )
243
+ {
244
+ struct k10temp_data * data = dev_get_drvdata (dev );
245
+ u32 regval ;
246
+
247
+ switch (attr ) {
248
+ case hwmon_in_input :
249
+ amd_smn_read (amd_pci_dev_to_node_id (data -> pdev ),
250
+ data -> svi_addr [channel ], & regval );
251
+ regval = (regval >> 16 ) & 0xff ;
252
+ * val = DIV_ROUND_CLOSEST (155000 - regval * 625 , 100 );
253
+ break ;
254
+ default :
255
+ return - EOPNOTSUPP ;
256
+ }
257
+ return 0 ;
258
+ }
259
+
260
+ static int k10temp_read_temp (struct device * dev , u32 attr , int channel ,
261
+ long * val )
170
262
{
171
263
struct k10temp_data * data = dev_get_drvdata (dev );
172
264
u32 regval ;
@@ -216,6 +308,21 @@ static int k10temp_read(struct device *dev, enum hwmon_sensor_types type,
216
308
return 0 ;
217
309
}
218
310
311
+ static int k10temp_read (struct device * dev , enum hwmon_sensor_types type ,
312
+ u32 attr , int channel , long * val )
313
+ {
314
+ switch (type ) {
315
+ case hwmon_temp :
316
+ return k10temp_read_temp (dev , attr , channel , val );
317
+ case hwmon_in :
318
+ return k10temp_read_in (dev , attr , channel , val );
319
+ case hwmon_curr :
320
+ return k10temp_read_curr (dev , attr , channel , val );
321
+ default :
322
+ return - EOPNOTSUPP ;
323
+ }
324
+ }
325
+
219
326
static umode_t k10temp_is_visible (const void * _data ,
220
327
enum hwmon_sensor_types type ,
221
328
u32 attr , int channel )
@@ -290,6 +397,11 @@ static umode_t k10temp_is_visible(const void *_data,
290
397
return 0 ;
291
398
}
292
399
break ;
400
+ case hwmon_in :
401
+ case hwmon_curr :
402
+ if (!data -> show_current )
403
+ return 0 ;
404
+ break ;
293
405
default :
294
406
return 0 ;
295
407
}
@@ -338,6 +450,12 @@ static const struct hwmon_channel_info *k10temp_info[] = {
338
450
HWMON_T_INPUT | HWMON_T_LABEL ,
339
451
HWMON_T_INPUT | HWMON_T_LABEL ,
340
452
HWMON_T_INPUT | HWMON_T_LABEL ),
453
+ HWMON_CHANNEL_INFO (in ,
454
+ HWMON_I_INPUT | HWMON_I_LABEL ,
455
+ HWMON_I_INPUT | HWMON_I_LABEL ),
456
+ HWMON_CHANNEL_INFO (curr ,
457
+ HWMON_C_INPUT | HWMON_C_LABEL ,
458
+ HWMON_C_INPUT | HWMON_C_LABEL ),
341
459
NULL
342
460
};
343
461
@@ -393,9 +511,19 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
393
511
case 0x8 : /* Zen+ */
394
512
case 0x11 : /* Zen APU */
395
513
case 0x18 : /* Zen+ APU */
514
+ data -> show_current = !is_threadripper () && !is_epyc ();
515
+ data -> svi_addr [0 ] = F17H_M01H_SVI_TEL_PLANE0 ;
516
+ data -> svi_addr [1 ] = F17H_M01H_SVI_TEL_PLANE1 ;
517
+ data -> cfactor [0 ] = CFACTOR_ICORE ;
518
+ data -> cfactor [1 ] = CFACTOR_ISOC ;
396
519
break ;
397
520
case 0x31 : /* Zen2 Threadripper */
398
521
case 0x71 : /* Zen2 */
522
+ data -> show_current = !is_threadripper () && !is_epyc ();
523
+ data -> cfactor [0 ] = CFACTOR_ICORE ;
524
+ data -> cfactor [1 ] = CFACTOR_ISOC ;
525
+ data -> svi_addr [0 ] = F17H_M01H_SVI_TEL_PLANE1 ;
526
+ data -> svi_addr [1 ] = F17H_M01H_SVI_TEL_PLANE0 ;
399
527
amd_smn_read (amd_pci_dev_to_node_id (pdev ),
400
528
F17H_M70H_CCD1_TEMP , & regval );
401
529
if (regval & 0xfff )
0 commit comments