Blame view

drivers/hwmon/k10temp.c 13.5 KB
6e7c10944   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
3c57e89b4   Clemens Ladisch   hwmon: New driver...
2
  /*
d547552a1   Guenter Roeck   hmon: (k10temp) C...
3
4
   * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h
   *		processor hardware monitoring
3c57e89b4   Clemens Ladisch   hwmon: New driver...
5
6
   *
   * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
d547552a1   Guenter Roeck   hmon: (k10temp) C...
7
   * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net>
c75793892   Guenter Roeck   hwmon: (k10temp) ...
8
9
   *
   * Implementation notes:
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
10
   * - CCD register address information as well as the calculation to
c75793892   Guenter Roeck   hwmon: (k10temp) ...
11
12
13
   *   convert raw register values is from https://github.com/ocerman/zenpower.
   *   The information is not confirmed from chip datasheets, but experiments
   *   suggest that it provides reasonable temperature values.
3c57e89b4   Clemens Ladisch   hwmon: New driver...
14
   */
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
15
  #include <linux/bitops.h>
3c57e89b4   Clemens Ladisch   hwmon: New driver...
16
17
  #include <linux/err.h>
  #include <linux/hwmon.h>
3c57e89b4   Clemens Ladisch   hwmon: New driver...
18
19
20
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/pci.h>
dedf7dce4   Woods, Brian   hwmon/k10temp, x8...
21
  #include <linux/pci_ids.h>
3b031622f   Guenter Roeck   hwmon: (k10temp) ...
22
  #include <asm/amd_nb.h>
3c57e89b4   Clemens Ladisch   hwmon: New driver...
23
  #include <asm/processor.h>
9e5813111   Andre Przywara   hwmon: (k10temp) ...
24
  MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
3c57e89b4   Clemens Ladisch   hwmon: New driver...
25
26
27
28
29
30
  MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
  MODULE_LICENSE("GPL");
  
  static bool force;
  module_param(force, bool, 0444);
  MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
31
32
  /* Provide lock for writing to NB_SMU_IND_ADDR */
  static DEFINE_MUTEX(nb_smu_ind_mutex);
ccaf63b4d   Guenter Roeck   hwmon: (k10temp) ...
33
34
35
  #ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3
  #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3	0x15b3
  #endif
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
36
  /* CPUID function 0x80000001, ebx */
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
37
  #define CPUID_PKGTYPE_MASK	GENMASK(31, 28)
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
38
39
40
41
42
  #define CPUID_PKGTYPE_F		0x00000000
  #define CPUID_PKGTYPE_AM2R2_AM3	0x10000000
  
  /* DRAM controller (PCI function 2) */
  #define REG_DCT0_CONFIG_HIGH		0x094
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
43
  #define  DDR3_MODE			BIT(8)
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
44
45
  
  /* miscellaneous (PCI function 3) */
3c57e89b4   Clemens Ladisch   hwmon: New driver...
46
  #define REG_HARDWARE_THERMAL_CONTROL	0x64
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
47
  #define  HTC_ENABLE			BIT(0)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
48
49
50
51
  
  #define REG_REPORTED_TEMPERATURE	0xa4
  
  #define REG_NORTHBRIDGE_CAPABILITIES	0xe8
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
52
  #define  NB_CAP_HTC			BIT(10)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
53

f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
54
  /*
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
55
56
57
58
   * For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL
   * and REG_REPORTED_TEMPERATURE have been moved to
   * D0F0xBC_xD820_0C64 [Hardware Temperature Control]
   * D0F0xBC_xD820_0CA4 [Reported Temperature Control]
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
59
   */
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
60
  #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET	0xd8200c64
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
61
  #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET	0xd8200ca4
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
62

178224170   Wei Huang   hwmon: (k10temp) ...
63
64
  /* Common for Zen CPU families (Family 17h and 18h) */
  #define ZEN_REPORTED_TEMP_CTRL_OFFSET		0x00059800
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
65

178224170   Wei Huang   hwmon: (k10temp) ...
66
67
68
  #define ZEN_CCD_TEMP(x)				(0x00059954 + ((x) * 4))
  #define ZEN_CCD_TEMP_VALID			BIT(11)
  #define ZEN_CCD_TEMP_MASK			GENMASK(10, 0)
9af0a9aec   Guenter Roeck   hwmon: (k10temp) ...
69

178224170   Wei Huang   hwmon: (k10temp) ...
70
71
  #define ZEN_CUR_TEMP_SHIFT			21
  #define ZEN_CUR_TEMP_RANGE_SEL_MASK		BIT(19)
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
72

178224170   Wei Huang   hwmon: (k10temp) ...
73
  #define ZEN_SVI_BASE				0x0005A000
a6d210da1   Guenter Roeck   hwmon: (k10temp) ...
74

178224170   Wei Huang   hwmon: (k10temp) ...
75
76
77
  /* F17h thermal registers through SMN */
  #define F17H_M01H_SVI_TEL_PLANE0		(ZEN_SVI_BASE + 0xc)
  #define F17H_M01H_SVI_TEL_PLANE1		(ZEN_SVI_BASE + 0x10)
d6144a400   Wei Huang   hwmon: (k10temp) ...
78
79
  #define F17H_M31H_SVI_TEL_PLANE0		(ZEN_SVI_BASE + 0x14)
  #define F17H_M31H_SVI_TEL_PLANE1		(ZEN_SVI_BASE + 0x10)
178224170   Wei Huang   hwmon: (k10temp) ...
80

d6144a400   Wei Huang   hwmon: (k10temp) ...
81
82
83
84
  #define F17H_M01H_CFACTOR_ICORE			1000000	/* 1A / LSB	*/
  #define F17H_M01H_CFACTOR_ISOC			250000	/* 0.25A / LSB	*/
  #define F17H_M31H_CFACTOR_ICORE			1000000	/* 1A / LSB	*/
  #define F17H_M31H_CFACTOR_ISOC			310000	/* 0.31A / LSB	*/
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
85

55163a1c0   Wei Huang   hwmon: (k10temp) ...
86
87
88
89
90
91
  /* F19h thermal registers through SMN */
  #define F19H_M01_SVI_TEL_PLANE0			(ZEN_SVI_BASE + 0x14)
  #define F19H_M01_SVI_TEL_PLANE1			(ZEN_SVI_BASE + 0x10)
  
  #define F19H_M01H_CFACTOR_ICORE			1000000	/* 1A / LSB	*/
  #define F19H_M01H_CFACTOR_ISOC			310000	/* 0.31A / LSB	*/
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
92
93
  struct k10temp_data {
  	struct pci_dev *pdev;
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
94
  	void (*read_htcreg)(struct pci_dev *pdev, u32 *regval);
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
95
  	void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
96
  	int temp_offset;
1b5978897   Guenter Roeck   hwmon: (k10temp) ...
97
  	u32 temp_adjust_mask;
60465245e   Guenter Roeck   hwmon: (k10temp) ...
98
  	u32 show_temp;
60465245e   Guenter Roeck   hwmon: (k10temp) ...
99
  	bool is_zen;
1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
100
  };
60465245e   Guenter Roeck   hwmon: (k10temp) ...
101
102
103
104
105
106
  #define TCTL_BIT	0
  #define TDIE_BIT	1
  #define TCCD_BIT(x)	((x) + 2)
  
  #define HAVE_TEMP(d, channel)	((d)->show_temp & BIT(channel))
  #define HAVE_TDIE(d)		HAVE_TEMP(d, TDIE_BIT)
1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
107
108
109
110
111
112
113
  struct tctl_offset {
  	u8 model;
  	char const *id;
  	int offset;
  };
  
  static const struct tctl_offset tctl_offset_table[] = {
ab5ee2461   Guenter Roeck   hwmon: (k10temp) ...
114
  	{ 0x17, "AMD Ryzen 5 1600X", 20000 },
1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
115
116
  	{ 0x17, "AMD Ryzen 7 1700X", 20000 },
  	{ 0x17, "AMD Ryzen 7 1800X", 20000 },
1b5978897   Guenter Roeck   hwmon: (k10temp) ...
117
  	{ 0x17, "AMD Ryzen 7 2700X", 10000 },
cd6a2064d   Guenter Roeck   hwmon: k10temp: S...
118
119
  	{ 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */
  	{ 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
120
  };
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
121
122
123
124
  static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval)
  {
  	pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval);
  }
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
125
126
127
128
129
130
131
  static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
  {
  	pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
  }
  
  static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
  			      unsigned int base, int offset, u32 *val)
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
132
133
134
  {
  	mutex_lock(&nb_smu_ind_mutex);
  	pci_bus_write_config_dword(pdev->bus, devfn,
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
135
  				   base, offset);
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
136
  	pci_bus_read_config_dword(pdev->bus, devfn,
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
137
  				  base + 4, val);
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
138
139
  	mutex_unlock(&nb_smu_ind_mutex);
  }
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
140
141
142
143
144
  static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval)
  {
  	amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
  			  F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET, regval);
  }
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
145
146
147
148
149
  static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
  {
  	amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
  			  F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
  }
178224170   Wei Huang   hwmon: (k10temp) ...
150
  static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval)
9af0a9aec   Guenter Roeck   hwmon: (k10temp) ...
151
  {
3b031622f   Guenter Roeck   hwmon: (k10temp) ...
152
  	amd_smn_read(amd_pci_dev_to_node_id(pdev),
178224170   Wei Huang   hwmon: (k10temp) ...
153
  		     ZEN_REPORTED_TEMP_CTRL_OFFSET, regval);
9af0a9aec   Guenter Roeck   hwmon: (k10temp) ...
154
  }
d547552a1   Guenter Roeck   hmon: (k10temp) C...
155
  static long get_raw_temp(struct k10temp_data *data)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
156
  {
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
157
  	u32 regval;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
158
  	long temp;
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
159
160
  
  	data->read_tempreg(data->pdev, &regval);
178224170   Wei Huang   hwmon: (k10temp) ...
161
  	temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125;
1b5978897   Guenter Roeck   hwmon: (k10temp) ...
162
163
  	if (regval & data->temp_adjust_mask)
  		temp -= 49000;
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
164
165
  	return temp;
  }
0e786f328   Jason Yan   hwmon: (k10temp) ...
166
  static const char *k10temp_temp_label[] = {
d547552a1   Guenter Roeck   hmon: (k10temp) C...
167
  	"Tctl",
b02c68573   Guenter Roeck   hwmon: (k10temp) ...
168
  	"Tdie",
c75793892   Guenter Roeck   hwmon: (k10temp) ...
169
170
  	"Tccd1",
  	"Tccd2",
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
171
172
173
174
175
176
  	"Tccd3",
  	"Tccd4",
  	"Tccd5",
  	"Tccd6",
  	"Tccd7",
  	"Tccd8",
d547552a1   Guenter Roeck   hmon: (k10temp) C...
177
  };
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
178

d547552a1   Guenter Roeck   hmon: (k10temp) C...
179
180
181
  static int k10temp_read_labels(struct device *dev,
  			       enum hwmon_sensor_types type,
  			       u32 attr, int channel, const char **str)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
182
  {
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
183
184
185
186
  	switch (type) {
  	case hwmon_temp:
  		*str = k10temp_temp_label[channel];
  		break;
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
187
188
189
190
191
192
193
194
  	default:
  		return -EOPNOTSUPP;
  	}
  	return 0;
  }
  
  static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
  			     long *val)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
195
  {
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
196
  	struct k10temp_data *data = dev_get_drvdata(dev);
3c57e89b4   Clemens Ladisch   hwmon: New driver...
197
  	u32 regval;
3c57e89b4   Clemens Ladisch   hwmon: New driver...
198

d547552a1   Guenter Roeck   hmon: (k10temp) C...
199
200
201
  	switch (attr) {
  	case hwmon_temp_input:
  		switch (channel) {
b02c68573   Guenter Roeck   hwmon: (k10temp) ...
202
203
  		case 0:		/* Tctl */
  			*val = get_raw_temp(data);
d547552a1   Guenter Roeck   hmon: (k10temp) C...
204
205
206
  			if (*val < 0)
  				*val = 0;
  			break;
b02c68573   Guenter Roeck   hwmon: (k10temp) ...
207
208
  		case 1:		/* Tdie */
  			*val = get_raw_temp(data) - data->temp_offset;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
209
210
211
  			if (*val < 0)
  				*val = 0;
  			break;
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
212
  		case 2 ... 9:		/* Tccd{1-8} */
c75793892   Guenter Roeck   hwmon: (k10temp) ...
213
  			amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
178224170   Wei Huang   hwmon: (k10temp) ...
214
215
  				     ZEN_CCD_TEMP(channel - 2), &regval);
  			*val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000;
c75793892   Guenter Roeck   hwmon: (k10temp) ...
216
  			break;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  		default:
  			return -EOPNOTSUPP;
  		}
  		break;
  	case hwmon_temp_max:
  		*val = 70 * 1000;
  		break;
  	case hwmon_temp_crit:
  		data->read_htcreg(data->pdev, &regval);
  		*val = ((regval >> 16) & 0x7f) * 500 + 52000;
  		break;
  	case hwmon_temp_crit_hyst:
  		data->read_htcreg(data->pdev, &regval);
  		*val = (((regval >> 16) & 0x7f)
  			- ((regval >> 24) & 0xf)) * 500 + 52000;
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  	return 0;
3c57e89b4   Clemens Ladisch   hwmon: New driver...
237
  }
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
238
239
240
241
242
243
  static int k10temp_read(struct device *dev, enum hwmon_sensor_types type,
  			u32 attr, int channel, long *val)
  {
  	switch (type) {
  	case hwmon_temp:
  		return k10temp_read_temp(dev, attr, channel, val);
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
244
245
246
247
  	default:
  		return -EOPNOTSUPP;
  	}
  }
d547552a1   Guenter Roeck   hmon: (k10temp) C...
248
249
250
  static umode_t k10temp_is_visible(const void *_data,
  				  enum hwmon_sensor_types type,
  				  u32 attr, int channel)
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
251
  {
d547552a1   Guenter Roeck   hmon: (k10temp) C...
252
  	const struct k10temp_data *data = _data;
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
253
  	struct pci_dev *pdev = data->pdev;
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
254
  	u32 reg;
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
255

d547552a1   Guenter Roeck   hmon: (k10temp) C...
256
257
258
259
  	switch (type) {
  	case hwmon_temp:
  		switch (attr) {
  		case hwmon_temp_input:
60465245e   Guenter Roeck   hwmon: (k10temp) ...
260
  			if (!HAVE_TEMP(data, channel))
d547552a1   Guenter Roeck   hmon: (k10temp) C...
261
262
263
  				return 0;
  			break;
  		case hwmon_temp_max:
60465245e   Guenter Roeck   hwmon: (k10temp) ...
264
  			if (channel || data->is_zen)
d547552a1   Guenter Roeck   hmon: (k10temp) C...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  				return 0;
  			break;
  		case hwmon_temp_crit:
  		case hwmon_temp_crit_hyst:
  			if (channel || !data->read_htcreg)
  				return 0;
  
  			pci_read_config_dword(pdev,
  					      REG_NORTHBRIDGE_CAPABILITIES,
  					      &reg);
  			if (!(reg & NB_CAP_HTC))
  				return 0;
  
  			data->read_htcreg(data->pdev, &reg);
  			if (!(reg & HTC_ENABLE))
  				return 0;
  			break;
  		case hwmon_temp_label:
60465245e   Guenter Roeck   hwmon: (k10temp) ...
283
284
  			/* Show temperature labels only on Zen CPUs */
  			if (!data->is_zen || !HAVE_TEMP(data, channel))
c75793892   Guenter Roeck   hwmon: (k10temp) ...
285
  				return 0;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
286
287
  			break;
  		default:
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
288
  			return 0;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
289
  		}
f934c0599   Guenter Roeck   hwmon: (k10temp) ...
290
  		break;
d547552a1   Guenter Roeck   hmon: (k10temp) C...
291
292
  	default:
  		return 0;
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
293
  	}
d547552a1   Guenter Roeck   hmon: (k10temp) C...
294
  	return 0444;
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
295
  }
6c931ae1c   Bill Pemberton   hwmon: remove use...
296
  static bool has_erratum_319(struct pci_dev *pdev)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
297
  {
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
298
299
300
301
  	u32 pkg_type, reg_dram_cfg;
  
  	if (boot_cpu_data.x86 != 0x10)
  		return false;
3c57e89b4   Clemens Ladisch   hwmon: New driver...
302
  	/*
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
303
304
  	 * Erratum 319: The thermal sensor of Socket F/AM2+ processors
  	 *              may be unreliable.
3c57e89b4   Clemens Ladisch   hwmon: New driver...
305
  	 */
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
306
307
308
309
310
  	pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK;
  	if (pkg_type == CPUID_PKGTYPE_F)
  		return true;
  	if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3)
  		return false;
eefc2d9e3   Jean Delvare   hwmon: (k10temp) ...
311
  	/* DDR3 memory implies socket AM3, which is good */
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
312
313
314
  	pci_bus_read_config_dword(pdev->bus,
  				  PCI_DEVFN(PCI_SLOT(pdev->devfn), 2),
  				  REG_DCT0_CONFIG_HIGH, &reg_dram_cfg);
eefc2d9e3   Jean Delvare   hwmon: (k10temp) ...
315
316
317
318
319
320
321
322
323
324
  	if (reg_dram_cfg & DDR3_MODE)
  		return false;
  
  	/*
  	 * Unfortunately it is possible to run a socket AM3 CPU with DDR2
  	 * memory. We blacklist all the cores which do exist in socket AM2+
  	 * format. It still isn't perfect, as RB-C2 cores exist in both AM2+
  	 * and AM3 formats, but that's the best we can do.
  	 */
  	return boot_cpu_data.x86_model < 4 ||
b399151cb   Jia Zhang   x86/cpu: Rename c...
325
  	       (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2);
3c57e89b4   Clemens Ladisch   hwmon: New driver...
326
  }
d547552a1   Guenter Roeck   hmon: (k10temp) C...
327
328
329
330
331
  static const struct hwmon_channel_info *k10temp_info[] = {
  	HWMON_CHANNEL_INFO(temp,
  			   HWMON_T_INPUT | HWMON_T_MAX |
  			   HWMON_T_CRIT | HWMON_T_CRIT_HYST |
  			   HWMON_T_LABEL,
c75793892   Guenter Roeck   hwmon: (k10temp) ...
332
333
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
334
335
336
337
338
339
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
  			   HWMON_T_INPUT | HWMON_T_LABEL,
d547552a1   Guenter Roeck   hmon: (k10temp) C...
340
  			   HWMON_T_INPUT | HWMON_T_LABEL),
b00647c46   Guenter Roeck   hwmon: (k10temp) ...
341
342
343
344
345
346
  	HWMON_CHANNEL_INFO(in,
  			   HWMON_I_INPUT | HWMON_I_LABEL,
  			   HWMON_I_INPUT | HWMON_I_LABEL),
  	HWMON_CHANNEL_INFO(curr,
  			   HWMON_C_INPUT | HWMON_C_LABEL,
  			   HWMON_C_INPUT | HWMON_C_LABEL),
d547552a1   Guenter Roeck   hmon: (k10temp) C...
347
348
349
350
351
352
353
354
355
356
357
358
359
  	NULL
  };
  
  static const struct hwmon_ops k10temp_hwmon_ops = {
  	.is_visible = k10temp_is_visible,
  	.read = k10temp_read,
  	.read_string = k10temp_read_labels,
  };
  
  static const struct hwmon_chip_info k10temp_chip_info = {
  	.ops = &k10temp_hwmon_ops,
  	.info = k10temp_info,
  };
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
360
361
362
363
364
365
366
367
  static void k10temp_get_ccd_support(struct pci_dev *pdev,
  				    struct k10temp_data *data, int limit)
  {
  	u32 regval;
  	int i;
  
  	for (i = 0; i < limit; i++) {
  		amd_smn_read(amd_pci_dev_to_node_id(pdev),
178224170   Wei Huang   hwmon: (k10temp) ...
368
369
  			     ZEN_CCD_TEMP(i), &regval);
  		if (regval & ZEN_CCD_TEMP_VALID)
60465245e   Guenter Roeck   hwmon: (k10temp) ...
370
  			data->show_temp |= BIT(TCCD_BIT(i));
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
371
372
  	}
  }
d547552a1   Guenter Roeck   hmon: (k10temp) C...
373
  static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3c57e89b4   Clemens Ladisch   hwmon: New driver...
374
  {
c5114a1cd   Clemens Ladisch   hwmon: (k10temp) ...
375
  	int unreliable = has_erratum_319(pdev);
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
376
  	struct device *dev = &pdev->dev;
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
377
  	struct k10temp_data *data;
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
378
  	struct device *hwmon_dev;
1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
379
  	int i;
3c57e89b4   Clemens Ladisch   hwmon: New driver...
380

3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
381
382
383
384
385
386
387
388
  	if (unreliable) {
  		if (!force) {
  			dev_err(dev,
  				"unreliable CPU thermal sensor; monitoring disabled
  ");
  			return -ENODEV;
  		}
  		dev_warn(dev,
3c57e89b4   Clemens Ladisch   hwmon: New driver...
389
390
  			 "unreliable CPU thermal sensor; check erratum 319
  ");
3e3e10225   Guenter Roeck   hwmon: (k10temp) ...
391
  	}
3c57e89b4   Clemens Ladisch   hwmon: New driver...
392

68546abf7   Guenter Roeck   hwmon: (k10temp) ...
393
394
395
396
397
  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	data->pdev = pdev;
60465245e   Guenter Roeck   hwmon: (k10temp) ...
398
  	data->show_temp |= BIT(TCTL_BIT);	/* Always show Tctl */
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
399

53dfa0088   Guenter Roeck   hwmon: (k10temp) ...
400
401
402
  	if (boot_cpu_data.x86 == 0x15 &&
  	    ((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
  	     (boot_cpu_data.x86_model & 0xf0) == 0x70)) {
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
403
  		data->read_htcreg = read_htcreg_nb_f15;
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
404
  		data->read_tempreg = read_tempreg_nb_f15;
d93217d84   Pu Wen   hwmon: (k10temp) ...
405
  	} else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
178224170   Wei Huang   hwmon: (k10temp) ...
406
407
  		data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK;
  		data->read_tempreg = read_tempreg_nb_zen;
60465245e   Guenter Roeck   hwmon: (k10temp) ...
408
409
  		data->show_temp |= BIT(TDIE_BIT);	/* show Tdie */
  		data->is_zen = true;
c75793892   Guenter Roeck   hwmon: (k10temp) ...
410
411
412
413
414
415
  
  		switch (boot_cpu_data.x86_model) {
  		case 0x1:	/* Zen */
  		case 0x8:	/* Zen+ */
  		case 0x11:	/* Zen APU */
  		case 0x18:	/* Zen+ APU */
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
416
  			k10temp_get_ccd_support(pdev, data, 4);
c75793892   Guenter Roeck   hwmon: (k10temp) ...
417
418
419
  			break;
  		case 0x31:	/* Zen2 Threadripper */
  		case 0x71:	/* Zen2 */
fd8bdb23b   Guenter Roeck   hwmon: (k10temp) ...
420
  			k10temp_get_ccd_support(pdev, data, 8);
c75793892   Guenter Roeck   hwmon: (k10temp) ...
421
422
  			break;
  		}
55163a1c0   Wei Huang   hwmon: (k10temp) ...
423
424
425
426
427
428
429
430
  	} else if (boot_cpu_data.x86 == 0x19) {
  		data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK;
  		data->read_tempreg = read_tempreg_nb_zen;
  		data->show_temp |= BIT(TDIE_BIT);
  		data->is_zen = true;
  
  		switch (boot_cpu_data.x86_model) {
  		case 0x0 ... 0x1:	/* Zen3 */
55163a1c0   Wei Huang   hwmon: (k10temp) ...
431
432
433
  			k10temp_get_ccd_support(pdev, data, 8);
  			break;
  		}
1b5978897   Guenter Roeck   hwmon: (k10temp) ...
434
  	} else {
40626a1bf   Guenter Roeck   hwmon: (k10temp) ...
435
  		data->read_htcreg = read_htcreg_pci;
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
436
  		data->read_tempreg = read_tempreg_pci;
1b5978897   Guenter Roeck   hwmon: (k10temp) ...
437
  	}
68546abf7   Guenter Roeck   hwmon: (k10temp) ...
438

1b50b7763   Guenter Roeck   hwmon: (k10temp) ...
439
440
441
442
443
444
445
446
447
  	for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
  		const struct tctl_offset *entry = &tctl_offset_table[i];
  
  		if (boot_cpu_data.x86 == entry->model &&
  		    strstr(boot_cpu_data.x86_model_id, entry->id)) {
  			data->temp_offset = entry->offset;
  			break;
  		}
  	}
d547552a1   Guenter Roeck   hmon: (k10temp) C...
448
449
450
  	hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data,
  							 &k10temp_chip_info,
  							 NULL);
8999eabf3   Guenter Roeck   hwmon: (k10temp) ...
451
  	return PTR_ERR_OR_ZERO(hwmon_dev);
3c57e89b4   Clemens Ladisch   hwmon: New driver...
452
  }
cd9bb0564   Jingoo Han   hwmon: remove DEF...
453
  static const struct pci_device_id k10temp_id_table[] = {
3c57e89b4   Clemens Ladisch   hwmon: New driver...
454
455
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
aa4790a62   Clemens Ladisch   hwmon: (k10temp) ...
456
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
9e5813111   Andre Przywara   hwmon: (k10temp) ...
457
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
24214449b   Borislav Petkov   x86, amd_nb: Expo...
458
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
d303b1b5f   Phil Pokorny   hwmon: (k10temp) ...
459
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
f89ce2706   Aravind Gopalakrishnan   hwmon: (k10temp) ...
460
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
ccaf63b4d   Guenter Roeck   hwmon: (k10temp) ...
461
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) },
30b146d1c   Wei Hu   hwmon: (k10temp) ...
462
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
ec0159503   Aravind Gopalakrishnan   hwmon: (k10temp) ...
463
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
9af0a9aec   Guenter Roeck   hwmon: (k10temp) ...
464
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
3b031622f   Guenter Roeck   hwmon: (k10temp) ...
465
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
210ba1201   Woods, Brian   hwmon/k10temp: Ad...
466
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
279f0b3a4   Alexander Monakov   hwmon: (k10temp) ...
467
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
12163cfbf   Marcel Bocu   hwmon: (k10temp) ...
468
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
55163a1c0   Wei Huang   hwmon: (k10temp) ...
469
  	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
d93217d84   Pu Wen   hwmon: (k10temp) ...
470
  	{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
3c57e89b4   Clemens Ladisch   hwmon: New driver...
471
472
473
474
475
476
477
478
  	{}
  };
  MODULE_DEVICE_TABLE(pci, k10temp_id_table);
  
  static struct pci_driver k10temp_driver = {
  	.name = "k10temp",
  	.id_table = k10temp_id_table,
  	.probe = k10temp_probe,
3c57e89b4   Clemens Ladisch   hwmon: New driver...
479
  };
f71f5a550   Axel Lin   hwmon: use module...
480
  module_pci_driver(k10temp_driver);