brintos

brintos / linux-shallow public Read only

0
0
Text · 13.5 KiB · 0e2dc14 Raw
489 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * processor thermal device RFIM control4 * 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	NULL37};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	NULL58};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 int match_mapping_table(const struct mapping_table *table, const char *attr_name,91			       bool match_int_value, const u32 value, const char *value_str,92			       char **result_str, u32 *result_int)93{94	bool attr_matched = false;95	int i = 0;96 97	if (!table)98		return -EOPNOTSUPP;99 100	while (table[i].attr_name) {101		if (strncmp(table[i].attr_name, attr_name, strlen(attr_name)))102			goto match_next;103 104		attr_matched = true;105 106		if (match_int_value) {107			if (table[i].value != value)108				goto match_next;109 110			*result_str = (char *)table[i].mapped_str;111			return 0;112		}113 114		if (strncmp(table[i].mapped_str, value_str, strlen(table[i].mapped_str)))115			goto match_next;116 117		*result_int = table[i].value;118 119		return 0;120match_next:121		i++;122	}123 124	/* If attribute name is matched, then the user space value is invalid */125	if (attr_matched)126		return -EINVAL;127 128	return -EOPNOTSUPP;129}130 131static int get_mapped_string(const struct mapping_table *table, const char *attr_name,132			     u32 value, char **result)133{134	return match_mapping_table(table, attr_name, true, value, NULL, result, NULL);135}136 137static int get_mapped_value(const struct mapping_table *table, const char *attr_name,138			    const char *value, unsigned int *result)139{140	return match_mapping_table(table, attr_name, false, 0, value, NULL, result);141}142 143/* These will represent sysfs attribute names */144static const char * const dvfs_strings[] = {145	"rfi_restriction_run_busy",146	"rfi_restriction_err_code",147	"rfi_restriction_data_rate",148	"rfi_restriction_data_rate_base",149	"ddr_data_rate_point_0",150	"ddr_data_rate_point_1",151	"ddr_data_rate_point_2",152	"ddr_data_rate_point_3",153	"rfi_disable",154	NULL155};156 157static const struct mmio_reg adl_dvfs_mmio_regs[] = {158	{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */159	{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */160	{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */161	{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */162	{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */163	{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */164	{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */165	{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */166	{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */167};168 169#define RFIM_SHOW(suffix, table)\170static ssize_t suffix##_show(struct device *dev,\171			      struct device_attribute *attr,\172			      char *buf)\173{\174	const struct mapping_table *mapping = NULL;\175	struct proc_thermal_device *proc_priv;\176	struct pci_dev *pdev = to_pci_dev(dev);\177	const struct mmio_reg *mmio_regs;\178	const char **match_strs;\179	int ret, err;\180	u32 reg_val;\181	char *str;\182\183	proc_priv = pci_get_drvdata(pdev);\184	if (table == 1) {\185		match_strs = (const char **)dvfs_strings;\186		mmio_regs = adl_dvfs_mmio_regs;\187	} else if (table == 2) { \188		match_strs = (const char **)dlvr_strings;\189		if (pdev->device == PCI_DEVICE_ID_INTEL_LNLM_THERMAL) {\190			mmio_regs = lnl_dlvr_mmio_regs;\191			mapping = lnl_dlvr_mapping;\192		} else {\193			mmio_regs = dlvr_mmio_regs;\194		} \195	} else {\196		match_strs = (const char **)fivr_strings;\197		mmio_regs = tgl_fivr_mmio_regs;\198	} \199	ret = match_string(match_strs, -1, attr->attr.name);\200	if (ret < 0)\201		return ret;\202	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\203	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\204	err = get_mapped_string(mapping, attr->attr.name, ret, &str);\205	if (!err)\206		return sprintf(buf, "%s\n", str);\207	if (err == -EOPNOTSUPP)\208		return sprintf(buf, "%u\n", ret);\209	return err;\210}211 212#define RFIM_STORE(suffix, table)\213static ssize_t suffix##_store(struct device *dev,\214			       struct device_attribute *attr,\215			       const char *buf, size_t count)\216{\217	const struct mapping_table *mapping = NULL;\218	struct proc_thermal_device *proc_priv;\219	struct pci_dev *pdev = to_pci_dev(dev);\220	unsigned int input;\221	const char **match_strs;\222	const struct mmio_reg *mmio_regs;\223	int ret, err;\224	u32 reg_val;\225	u32 mask;\226\227	proc_priv = pci_get_drvdata(pdev);\228	if (table == 1) {\229		match_strs = (const char **)dvfs_strings;\230		mmio_regs = adl_dvfs_mmio_regs;\231	} else if (table == 2) { \232		match_strs = (const char **)dlvr_strings;\233		if (pdev->device == PCI_DEVICE_ID_INTEL_LNLM_THERMAL) {\234			mmio_regs = lnl_dlvr_mmio_regs;\235			mapping = lnl_dlvr_mapping;\236		} else {\237			mmio_regs = dlvr_mmio_regs;\238		} \239	} else {\240		match_strs = (const char **)fivr_strings;\241		mmio_regs = tgl_fivr_mmio_regs;\242	} \243	\244	ret = match_string(match_strs, -1, attr->attr.name);\245	if (ret < 0)\246		return ret;\247	if (mmio_regs[ret].read_only)\248		return -EPERM;\249	err = get_mapped_value(mapping, attr->attr.name, buf, &input);\250	if (err == -EINVAL)\251		return err;\252	if (err == -EOPNOTSUPP) {\253		err = kstrtouint(buf, 10, &input);\254		if (err)\255			return err;\256	} \257	mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\258	reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\259	reg_val &= ~mask;\260	reg_val |= (input << mmio_regs[ret].shift);\261	writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\262	return count;\263}264 265RFIM_SHOW(vco_ref_code_lo, 0)266RFIM_SHOW(vco_ref_code_hi, 0)267RFIM_SHOW(spread_spectrum_pct, 0)268RFIM_SHOW(spread_spectrum_clk_enable, 0)269RFIM_SHOW(rfi_vco_ref_code, 0)270RFIM_SHOW(fivr_fffc_rev, 0)271 272RFIM_STORE(vco_ref_code_lo, 0)273RFIM_STORE(vco_ref_code_hi, 0)274RFIM_STORE(spread_spectrum_pct, 0)275RFIM_STORE(spread_spectrum_clk_enable, 0)276RFIM_STORE(rfi_vco_ref_code, 0)277RFIM_STORE(fivr_fffc_rev, 0)278 279RFIM_SHOW(dlvr_spread_spectrum_pct, 2)280RFIM_SHOW(dlvr_control_mode, 2)281RFIM_SHOW(dlvr_control_lock, 2)282RFIM_SHOW(dlvr_hardware_rev, 2)283RFIM_SHOW(dlvr_freq_mhz, 2)284RFIM_SHOW(dlvr_pll_busy, 2)285RFIM_SHOW(dlvr_freq_select, 2)286RFIM_SHOW(dlvr_rfim_enable, 2)287 288RFIM_STORE(dlvr_spread_spectrum_pct, 2)289RFIM_STORE(dlvr_rfim_enable, 2)290RFIM_STORE(dlvr_freq_select, 2)291RFIM_STORE(dlvr_control_mode, 2)292RFIM_STORE(dlvr_control_lock, 2)293 294static DEVICE_ATTR_RW(dlvr_spread_spectrum_pct);295static DEVICE_ATTR_RW(dlvr_control_mode);296static DEVICE_ATTR_RW(dlvr_control_lock);297static DEVICE_ATTR_RW(dlvr_freq_select);298static DEVICE_ATTR_RO(dlvr_hardware_rev);299static DEVICE_ATTR_RO(dlvr_freq_mhz);300static DEVICE_ATTR_RO(dlvr_pll_busy);301static DEVICE_ATTR_RW(dlvr_rfim_enable);302 303static struct attribute *dlvr_attrs[] = {304	&dev_attr_dlvr_spread_spectrum_pct.attr,305	&dev_attr_dlvr_control_mode.attr,306	&dev_attr_dlvr_control_lock.attr,307	&dev_attr_dlvr_freq_select.attr,308	&dev_attr_dlvr_hardware_rev.attr,309	&dev_attr_dlvr_freq_mhz.attr,310	&dev_attr_dlvr_pll_busy.attr,311	&dev_attr_dlvr_rfim_enable.attr,312	NULL313};314 315static const struct attribute_group dlvr_attribute_group = {316	.attrs = dlvr_attrs,317	.name = "dlvr"318};319 320static DEVICE_ATTR_RW(vco_ref_code_lo);321static DEVICE_ATTR_RW(vco_ref_code_hi);322static DEVICE_ATTR_RW(spread_spectrum_pct);323static DEVICE_ATTR_RW(spread_spectrum_clk_enable);324static DEVICE_ATTR_RW(rfi_vco_ref_code);325static DEVICE_ATTR_RW(fivr_fffc_rev);326 327static struct attribute *fivr_attrs[] = {328	&dev_attr_vco_ref_code_lo.attr,329	&dev_attr_vco_ref_code_hi.attr,330	&dev_attr_spread_spectrum_pct.attr,331	&dev_attr_spread_spectrum_clk_enable.attr,332	&dev_attr_rfi_vco_ref_code.attr,333	&dev_attr_fivr_fffc_rev.attr,334	NULL335};336 337static const struct attribute_group fivr_attribute_group = {338	.attrs = fivr_attrs,339	.name = "fivr"340};341 342RFIM_SHOW(rfi_restriction_run_busy, 1)343RFIM_SHOW(rfi_restriction_err_code, 1)344RFIM_SHOW(rfi_restriction_data_rate, 1)345RFIM_SHOW(rfi_restriction_data_rate_base, 1)346RFIM_SHOW(ddr_data_rate_point_0, 1)347RFIM_SHOW(ddr_data_rate_point_1, 1)348RFIM_SHOW(ddr_data_rate_point_2, 1)349RFIM_SHOW(ddr_data_rate_point_3, 1)350RFIM_SHOW(rfi_disable, 1)351 352RFIM_STORE(rfi_restriction_run_busy, 1)353RFIM_STORE(rfi_restriction_err_code, 1)354RFIM_STORE(rfi_restriction_data_rate, 1)355RFIM_STORE(rfi_restriction_data_rate_base, 1)356RFIM_STORE(rfi_disable, 1)357 358static DEVICE_ATTR_RW(rfi_restriction_run_busy);359static DEVICE_ATTR_RW(rfi_restriction_err_code);360static DEVICE_ATTR_RW(rfi_restriction_data_rate);361static DEVICE_ATTR_RW(rfi_restriction_data_rate_base);362static DEVICE_ATTR_RO(ddr_data_rate_point_0);363static DEVICE_ATTR_RO(ddr_data_rate_point_1);364static DEVICE_ATTR_RO(ddr_data_rate_point_2);365static DEVICE_ATTR_RO(ddr_data_rate_point_3);366static DEVICE_ATTR_RW(rfi_disable);367 368static ssize_t rfi_restriction_store(struct device *dev,369				     struct device_attribute *attr,370				     const char *buf, size_t count)371{372	u16 id = 0x0008;373	u32 input;374	int ret;375 376	ret = kstrtou32(buf, 10, &input);377	if (ret)378		return ret;379 380	ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input);381	if (ret)382		return ret;383 384	return count;385}386 387static ssize_t rfi_restriction_show(struct device *dev,388				    struct device_attribute *attr,389				    char *buf)390{391	u16 id = 0x0007;392	u64 resp;393	int ret;394 395	ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);396	if (ret)397		return ret;398 399	return sprintf(buf, "%llu\n", resp);400}401 402static ssize_t ddr_data_rate_show(struct device *dev,403				  struct device_attribute *attr,404				  char *buf)405{406	u16 id = 0x0107;407	u64 resp;408	int ret;409 410	ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp);411	if (ret)412		return ret;413 414	return sprintf(buf, "%llu\n", resp);415}416 417static DEVICE_ATTR_RW(rfi_restriction);418static DEVICE_ATTR_RO(ddr_data_rate);419 420static struct attribute *dvfs_attrs[] = {421	&dev_attr_rfi_restriction_run_busy.attr,422	&dev_attr_rfi_restriction_err_code.attr,423	&dev_attr_rfi_restriction_data_rate.attr,424	&dev_attr_rfi_restriction_data_rate_base.attr,425	&dev_attr_ddr_data_rate_point_0.attr,426	&dev_attr_ddr_data_rate_point_1.attr,427	&dev_attr_ddr_data_rate_point_2.attr,428	&dev_attr_ddr_data_rate_point_3.attr,429	&dev_attr_rfi_disable.attr,430	&dev_attr_ddr_data_rate.attr,431	&dev_attr_rfi_restriction.attr,432	NULL433};434 435static const struct attribute_group dvfs_attribute_group = {436	.attrs = dvfs_attrs,437	.name = "dvfs"438};439 440int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)441{442	int ret;443 444	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {445		ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);446		if (ret)447			return ret;448	}449 450	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {451		ret = sysfs_create_group(&pdev->dev.kobj, &dlvr_attribute_group);452		if (ret)453			return ret;454	}455 456	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {457		ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);458		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {459			sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);460			return ret;461		}462		if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {463			sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);464			return ret;465		}466	}467 468	return 0;469}470EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);471 472void proc_thermal_rfim_remove(struct pci_dev *pdev)473{474	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);475 476	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)477		sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);478 479	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR)480		sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);481 482	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)483		sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);484}485EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);486 487MODULE_LICENSE("GPL v2");488MODULE_DESCRIPTION("Processor Thermal RFIM Interface");489