File Index
Files and directories
Sign in
FILE

processor_thermal_rfim.c

File preview with syntax highlighting.

linux-6.19.14/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * processor thermal device RFIM control
  4 * Copyright (c) 2020, Intel Corporation.
  5 */
  6
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/pci.h>
 10#include "processor_thermal_device.h"
 11
 12MODULE_IMPORT_NS("INT340X_THERMAL");
 13
 14struct mmio_reg {
 15	int read_only;
 16	u32 offset;
 17	int bits;
 18	u16 mask;
 19	u16 shift;
 20};
 21
 22struct mapping_table {
 23	const char *attr_name;
 24	const u32 value;
 25	const char *mapped_str;
 26};
 27
 28/* These will represent sysfs attribute names */
 29static const char * const fivr_strings[] = {
 30	"vco_ref_code_lo",
 31	"vco_ref_code_hi",
 32	"spread_spectrum_pct",
 33	"spread_spectrum_clk_enable",
 34	"rfi_vco_ref_code",
 35	"fivr_fffc_rev",
 36	NULL
 37};
 38
 39static const struct mmio_reg tgl_fivr_mmio_regs[] = {
 40	{ 0, 0x5A18, 3, 0x7, 11}, /* vco_ref_code_lo */
 41	{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
 42	{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
 43	{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
 44	{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
 45	{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
 46};
 47
 48static const char * const dlvr_strings[] = {
 49	"dlvr_spread_spectrum_pct",
 50	"dlvr_control_mode",
 51	"dlvr_control_lock",
 52	"dlvr_rfim_enable",
 53	"dlvr_freq_select",
 54	"dlvr_hardware_rev",
 55	"dlvr_freq_mhz",
 56	"dlvr_pll_busy",
 57	NULL
 58};
 59
 60static const struct mmio_reg dlvr_mmio_regs[] = {
 61	{ 0, 0x15A08, 5, 0x1F, 0}, /* dlvr_spread_spectrum_pct */
 62	{ 0, 0x15A08, 1, 0x1, 5}, /* dlvr_control_mode */
 63	{ 0, 0x15A08, 1, 0x1, 6}, /* dlvr_control_lock */
 64	{ 0, 0x15A08, 1, 0x1, 7}, /* dlvr_rfim_enable */
 65	{ 0, 0x15A08, 12, 0xFFF, 8}, /* dlvr_freq_select */
 66	{ 1, 0x15A10, 2, 0x3, 30}, /* dlvr_hardware_rev */
 67	{ 1, 0x15A10, 16, 0xFFFF, 0}, /* dlvr_freq_mhz */
 68	{ 1, 0x15A10, 1, 0x1, 16}, /* dlvr_pll_busy */
 69};
 70
 71static const struct mmio_reg lnl_dlvr_mmio_regs[] = {
 72	{ 0, 0x5A08, 5, 0x1F, 0}, /* dlvr_spread_spectrum_pct */
 73	{ 0, 0x5A08, 1, 0x1, 5}, /* dlvr_control_mode */
 74	{ 0, 0x5A08, 1, 0x1, 6}, /* dlvr_control_lock */
 75	{ 0, 0x5A08, 1, 0x1, 7}, /* dlvr_rfim_enable */
 76	{ 0, 0x5A08, 2, 0x3, 8}, /* dlvr_freq_select */
 77	{ 1, 0x5A10, 2, 0x3, 30}, /* dlvr_hardware_rev */
 78	{ 1, 0x5A10, 2, 0x3, 0}, /* dlvr_freq_mhz */
 79	{ 1, 0x5A10, 1, 0x1, 23}, /* dlvr_pll_busy */
 80};
 81
 82static const struct mapping_table lnl_dlvr_mapping[] = {
 83	{"dlvr_freq_select", 0, "2227.2"},
 84	{"dlvr_freq_select", 1, "2140"},
 85	{"dlvr_freq_mhz", 0, "2227.2"},
 86	{"dlvr_freq_mhz", 1, "2140"},
 87	{NULL, 0, NULL},
 88};
 89
 90static const struct mmio_reg nvl_dlvr_mmio_regs[] = {
 91	{ 0, 0x19208, 5, 0x1F, 0}, /* dlvr_spread_spectrum_pct */
 92	{ 0, 0x19208, 1, 0x1, 5}, /* dlvr_control_mode */
 93	{ 0, 0x19208, 1, 0x1, 6}, /* dlvr_control_lock */
 94	{ 0, 0x19208, 1, 0x1, 7}, /* dlvr_rfim_enable */
 95	{ 0, 0x19208, 12, 0xFFF, 8}, /* dlvr_freq_select */
 96	{ 1, 0x19210, 2, 0x3, 30}, /* dlvr_hardware_rev */
 97	{ 1, 0x19210, 16, 0xFFFF, 0}, /* dlvr_freq_mhz */
 98	{ 1, 0x19210, 1, 0x1, 16}, /* dlvr_pll_busy */
 99};
100
101static int match_mapping_table(const struct mapping_table *table, const char *attr_name,
102			       bool match_int_value, const u32 value, const char *value_str,
103			       char **result_str, u32 *result_int)
104{
105	bool attr_matched = false;
106	int i = 0;
107
108	if (!table)
109		return -EOPNOTSUPP;
110
111	while (table[i].attr_name) {
112		if (strncmp(table[i].attr_name, attr_name, strlen(attr_name)))
113			goto match_next;
114
115		attr_matched = true;
116
117		if (match_int_value) {
118			if (table[i].value != value)
119				goto match_next;
120
121			*result_str = (char *)table[i].mapped_str;
122			return 0;
123		}
124
125		if (strncmp(table[i].mapped_str, value_str, strlen(table[i].mapped_str)))
126			goto match_next;
127
128		*result_int = table[i].value;
129
130		return 0;
131match_next:
132		i++;
133	}
134
135	/* If attribute name is matched, then the user space value is invalid */
136	if (attr_matched)
137		return -EINVAL;
138
139	return -EOPNOTSUPP;
140}
141
142static int get_mapped_string(const struct mapping_table *table, const char *attr_name,
143			     u32 value, char **result)
144{
145	return match_mapping_table(table, attr_name, true, value, NULL, result, NULL);
146}
147
148static int get_mapped_value(const struct mapping_table *table, const char *attr_name,
149			    const char *value, unsigned int *result)
150{
151	return match_mapping_table(table, attr_name, false, 0, value, NULL, result);
152}
153
154/* These will represent sysfs attribute names */
155static const char * const dvfs_strings[] = {
156	"rfi_restriction_run_busy",
157	"rfi_restriction_err_code",
158	"rfi_restriction_data_rate",
159	"rfi_restriction_data_rate_base",
160	"ddr_data_rate_point_0",
161	"ddr_data_rate_point_1",
162	"ddr_data_rate_point_2",
163	"ddr_data_rate_point_3",
164	"rfi_disable",
165	NULL
166};
167
168static const struct mmio_reg adl_dvfs_mmio_regs[] = {
169	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
170	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
171	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
172	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
173	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
174	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
175	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
176	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
177	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
178};
179
180static const struct mapping_table *dlvr_mapping;
181static const struct mmio_reg *dlvr_mmio_regs_table;
182
183#define RFIM_SHOW(suffix, table)\
184static ssize_t suffix##_show(struct device *dev,\
185			      struct device_attribute *attr,\
186			      char *buf)\
187{\
188	const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\
189	const struct mapping_table *mapping = dlvr_mapping;\
190	struct proc_thermal_device *proc_priv;\
191	struct pci_dev *pdev = to_pci_dev(dev);\
192	const char **match_strs;\
193	int ret, err;\
194	u32 reg_val;\
195	char *str;\
196\
197	proc_priv = pci_get_drvdata(pdev);\
198	if (table == 1) {\
199		match_strs = (const char **)dvfs_strings;\
200		mmio_regs = adl_dvfs_mmio_regs;\
201	} else if (table == 2) { \
202		match_strs = (const char **)dlvr_strings;\
203	} else {\
204		match_strs = (const char **)fivr_strings;\
205		mmio_regs = tgl_fivr_mmio_regs;\
206	} \
207	ret = match_string(match_strs, -1, attr->attr.name);\
208	if (ret < 0)\
209		return ret;\
210	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
211	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
212	err = get_mapped_string(mapping, attr->attr.name, ret, &str);\
213	if (!err)\
214		return sprintf(buf, "%s\n", str);\
215	if (err == -EOPNOTSUPP)\
216		return sprintf(buf, "%u\n", ret);\
217	return err;\
218}
219
220#define RFIM_STORE(suffix, table)\
221static ssize_t suffix##_store(struct device *dev,\
222			       struct device_attribute *attr,\
223			       const char *buf, size_t count)\
224{\
225	const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\
226	const struct mapping_table *mapping = dlvr_mapping;\
227	struct proc_thermal_device *proc_priv;\
228	struct pci_dev *pdev = to_pci_dev(dev);\
229	unsigned int input;\
230	const char **match_strs;\
231	int ret, err;\
232	u32 reg_val;\
233	u32 mask;\
234\
235	proc_priv = pci_get_drvdata(pdev);\
236	if (table == 1) {\
237		match_strs = (const char **)dvfs_strings;\
238		mmio_regs = adl_dvfs_mmio_regs;\
239	} else if (table == 2) { \
240		match_strs = (const char **)dlvr_strings;\
241	} else {\
242		match_strs = (const char **)fivr_strings;\
243		mmio_regs = tgl_fivr_mmio_regs;\
244	} \
245	\
246	ret = match_string(match_strs, -1, attr->attr.name);\
247	if (ret < 0)\
248		return ret;\
249	if (mmio_regs[ret].read_only)\
250		return -EPERM;\
251	err = get_mapped_value(mapping, attr->attr.name, buf, &input);\
252	if (err == -EINVAL)\
253		return err;\
254	if (err == -EOPNOTSUPP) {\
255		err = kstrtouint(buf, 10, &input);\
256		if (err)\
257			return err;\
258	} \
259	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
260	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
261	reg_val &= ~mask;\
262	reg_val |= (input << mmio_regs[ret].shift);\
263	writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
264	return count;\
265}
266
267RFIM_SHOW(vco_ref_code_lo, 0)
268RFIM_SHOW(vco_ref_code_hi, 0)
269RFIM_SHOW(spread_spectrum_pct, 0)
270RFIM_SHOW(spread_spectrum_clk_enable, 0)
271RFIM_SHOW(rfi_vco_ref_code, 0)
272RFIM_SHOW(fivr_fffc_rev, 0)
273
274RFIM_STORE(vco_ref_code_lo, 0)
275RFIM_STORE(vco_ref_code_hi, 0)
276RFIM_STORE(spread_spectrum_pct, 0)
277RFIM_STORE(spread_spectrum_clk_enable, 0)
278RFIM_STORE(rfi_vco_ref_code, 0)
279RFIM_STORE(fivr_fffc_rev, 0)
280
281RFIM_SHOW(dlvr_spread_spectrum_pct, 2)
282RFIM_SHOW(dlvr_control_mode, 2)
283RFIM_SHOW(dlvr_control_lock, 2)
284RFIM_SHOW(dlvr_hardware_rev, 2)
285RFIM_SHOW(dlvr_freq_mhz, 2)
286RFIM_SHOW(dlvr_pll_busy, 2)
287RFIM_SHOW(dlvr_freq_select, 2)
288RFIM_SHOW(dlvr_rfim_enable, 2)
289
290RFIM_STORE(dlvr_spread_spectrum_pct, 2)
291RFIM_STORE(dlvr_rfim_enable, 2)
292RFIM_STORE(dlvr_freq_select, 2)
293RFIM_STORE(dlvr_control_mode, 2)
294RFIM_STORE(dlvr_control_lock, 2)
295
296static DEVICE_ATTR_RW(dlvr_spread_spectrum_pct);
297static DEVICE_ATTR_RW(dlvr_control_mode);
298static DEVICE_ATTR_RW(dlvr_control_lock);
299static DEVICE_ATTR_RW(dlvr_freq_select);
300static DEVICE_ATTR_RO(dlvr_hardware_rev);
301static DEVICE_ATTR_RO(dlvr_freq_mhz);
302static DEVICE_ATTR_RO(dlvr_pll_busy);
303static DEVICE_ATTR_RW(dlvr_rfim_enable);
304
305static struct attribute *dlvr_attrs[] = {
306	&dev_attr_dlvr_spread_spectrum_pct.attr,
307	&dev_attr_dlvr_control_mode.attr,
308	&dev_attr_dlvr_control_lock.attr,
309	&dev_attr_dlvr_freq_select.attr,
310	&dev_attr_dlvr_hardware_rev.attr,
311	&dev_attr_dlvr_freq_mhz.attr,
312	&dev_attr_dlvr_pll_busy.attr,
313	&dev_attr_dlvr_rfim_enable.attr,
314	NULL
315};
316
317static const struct attribute_group dlvr_attribute_group = {
318	.attrs = dlvr_attrs,
319	.name = "dlvr"
320};
321
322static DEVICE_ATTR_RW(vco_ref_code_lo);
323static DEVICE_ATTR_RW(vco_ref_code_hi);
324static DEVICE_ATTR_RW(spread_spectrum_pct);
325static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
326static DEVICE_ATTR_RW(rfi_vco_ref_code);
327static DEVICE_ATTR_RW(fivr_fffc_rev);
328
329static struct attribute *fivr_attrs[] = {
330	&dev_attr_vco_ref_code_lo.attr,
331	&dev_attr_vco_ref_code_hi.attr,
332	&dev_attr_spread_spectrum_pct.attr,
333	&dev_attr_spread_spectrum_clk_enable.attr,
334	&dev_attr_rfi_vco_ref_code.attr,
335	&dev_attr_fivr_fffc_rev.attr,
336	NULL
337};
338
339static const struct attribute_group fivr_attribute_group = {
340	.attrs = fivr_attrs,
341	.name = "fivr"
342};
343
344RFIM_SHOW(rfi_restriction_run_busy, 1)
345RFIM_SHOW(rfi_restriction_err_code, 1)
346RFIM_SHOW(rfi_restriction_data_rate, 1)
347RFIM_SHOW(rfi_restriction_data_rate_base, 1)
348RFIM_SHOW(ddr_data_rate_point_0, 1)
349RFIM_SHOW(ddr_data_rate_point_1, 1)
350RFIM_SHOW(ddr_data_rate_point_2, 1)
351RFIM_SHOW(ddr_data_rate_point_3, 1)
352RFIM_SHOW(rfi_disable, 1)
353
354RFIM_STORE(rfi_restriction_run_busy, 1)
355RFIM_STORE(rfi_restriction_err_code, 1)
356RFIM_STORE(rfi_restriction_data_rate, 1)
357RFIM_STORE(rfi_restriction_data_rate_base, 1)
358RFIM_STORE(rfi_disable, 1)
359
360static DEVICE_ATTR_RW(rfi_restriction_run_busy);
361static DEVICE_ATTR_RW(rfi_restriction_err_code);
362static DEVICE_ATTR_RW(rfi_restriction_data_rate);
363static DEVICE_ATTR_RW(rfi_restriction_data_rate_base);
364static DEVICE_ATTR_RO(ddr_data_rate_point_0);
365static DEVICE_ATTR_RO(ddr_data_rate_point_1);
366static DEVICE_ATTR_RO(ddr_data_rate_point_2);
367static DEVICE_ATTR_RO(ddr_data_rate_point_3);
368static DEVICE_ATTR_RW(rfi_disable);
369
370static ssize_t rfi_restriction_store(struct device *dev,
371				     struct device_attribute *attr,
372				     const char *buf, size_t count)
373{
374	u16 id = 0x0008;
375	u32 input;
376	int ret;
377
378	ret = kstrtou32(buf, 10, &input);
379	if (ret)
380		return ret;
381
382	ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input);
383	if (ret)
384		return ret;
385
386	return count;
387}
388
389static ssize_t rfi_restriction_show(struct device *dev,
390				    struct device_attribute *attr,
391				    char *buf)
392{
393	u16 id = 0x0007;
394	u64 resp;
395	int ret;
396
397	ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);
398	if (ret)
399		return ret;
400
401	return sprintf(buf, "%llu\n", resp);
402}
403
404static ssize_t ddr_data_rate_show(struct device *dev,
405				  struct device_attribute *attr,
406				  char *buf)
407{
408	u16 id = 0x0107;
409	u64 resp;
410	int ret;
411
412	ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);
413	if (ret)
414		return ret;
415
416	return sprintf(buf, "%llu\n", resp);
417}
418
419static DEVICE_ATTR_RW(rfi_restriction);
420static DEVICE_ATTR_RO(ddr_data_rate);
421
422static struct attribute *dvfs_attrs[] = {
423	&dev_attr_rfi_restriction_run_busy.attr,
424	&dev_attr_rfi_restriction_err_code.attr,
425	&dev_attr_rfi_restriction_data_rate.attr,
426	&dev_attr_rfi_restriction_data_rate_base.attr,
427	&dev_attr_ddr_data_rate_point_0.attr,
428	&dev_attr_ddr_data_rate_point_1.attr,
429	&dev_attr_ddr_data_rate_point_2.attr,
430	&dev_attr_ddr_data_rate_point_3.attr,
431	&dev_attr_rfi_disable.attr,
432	&dev_attr_ddr_data_rate.attr,
433	&dev_attr_rfi_restriction.attr,
434	NULL
435};
436
437static const struct attribute_group dvfs_attribute_group = {
438	.attrs = dvfs_attrs,
439	.name = "dvfs"
440};
441
442int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
443{
444	int ret;
445
446	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
447		ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
448		if (ret)
449			return ret;
450	}
451
452	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {
453		switch (pdev->device) {
454		case PCI_DEVICE_ID_INTEL_LNLM_THERMAL:
455		case PCI_DEVICE_ID_INTEL_PTL_THERMAL:
456		case PCI_DEVICE_ID_INTEL_WCL_THERMAL:
457			dlvr_mmio_regs_table = lnl_dlvr_mmio_regs;
458			dlvr_mapping = lnl_dlvr_mapping;
459			break;
460		case PCI_DEVICE_ID_INTEL_NVL_H_THERMAL:
461		case PCI_DEVICE_ID_INTEL_NVL_S_THERMAL:
462			dlvr_mmio_regs_table = nvl_dlvr_mmio_regs;
463			break;
464		default:
465			dlvr_mmio_regs_table = dlvr_mmio_regs;
466			break;
467		}
468		ret = sysfs_create_group(&pdev->dev.kobj, &dlvr_attribute_group);
469		if (ret) {
470			if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
471				sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
472			return ret;
473		}
474	}
475
476	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
477		ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
478		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
479			sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
480			return ret;
481		}
482		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {
483			sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);
484			return ret;
485		}
486	}
487
488	return 0;
489}
490EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
491
492void proc_thermal_rfim_remove(struct pci_dev *pdev)
493{
494	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
495
496	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
497		sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
498
499	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR)
500		sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);
501
502	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
503		sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
504}
505EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
506
507MODULE_LICENSE("GPL v2");
508MODULE_DESCRIPTION("Processor Thermal RFIM Interface");
~/ Read-only file preview.