processor_thermal_rfim.c (8312B)
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 22/* These will represent sysfs attribute names */ 23static const char * const fivr_strings[] = { 24 "vco_ref_code_lo", 25 "vco_ref_code_hi", 26 "spread_spectrum_pct", 27 "spread_spectrum_clk_enable", 28 "rfi_vco_ref_code", 29 "fivr_fffc_rev", 30 NULL 31}; 32 33static const struct mmio_reg tgl_fivr_mmio_regs[] = { 34 { 0, 0x5A18, 3, 0x7, 11}, /* vco_ref_code_lo */ 35 { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */ 36 { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */ 37 { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */ 38 { 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */ 39 { 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */ 40}; 41 42/* These will represent sysfs attribute names */ 43static const char * const dvfs_strings[] = { 44 "rfi_restriction_run_busy", 45 "rfi_restriction_err_code", 46 "rfi_restriction_data_rate", 47 "rfi_restriction_data_rate_base", 48 "ddr_data_rate_point_0", 49 "ddr_data_rate_point_1", 50 "ddr_data_rate_point_2", 51 "ddr_data_rate_point_3", 52 "rfi_disable", 53 NULL 54}; 55 56static const struct mmio_reg adl_dvfs_mmio_regs[] = { 57 { 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */ 58 { 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */ 59 { 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */ 60 { 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */ 61 { 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */ 62 { 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */ 63 { 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */ 64 { 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */ 65 { 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */ 66}; 67 68#define RFIM_SHOW(suffix, table)\ 69static ssize_t suffix##_show(struct device *dev,\ 70 struct device_attribute *attr,\ 71 char *buf)\ 72{\ 73 struct proc_thermal_device *proc_priv;\ 74 struct pci_dev *pdev = to_pci_dev(dev);\ 75 const struct mmio_reg *mmio_regs;\ 76 const char **match_strs;\ 77 u32 reg_val;\ 78 int ret;\ 79\ 80 proc_priv = pci_get_drvdata(pdev);\ 81 if (table) {\ 82 match_strs = (const char **)dvfs_strings;\ 83 mmio_regs = adl_dvfs_mmio_regs;\ 84 } else { \ 85 match_strs = (const char **)fivr_strings;\ 86 mmio_regs = tgl_fivr_mmio_regs;\ 87 } \ 88 \ 89 ret = match_string(match_strs, -1, attr->attr.name);\ 90 if (ret < 0)\ 91 return ret;\ 92 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 93 ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\ 94 return sprintf(buf, "%u\n", ret);\ 95} 96 97#define RFIM_STORE(suffix, table)\ 98static ssize_t suffix##_store(struct device *dev,\ 99 struct device_attribute *attr,\ 100 const char *buf, size_t count)\ 101{\ 102 struct proc_thermal_device *proc_priv;\ 103 struct pci_dev *pdev = to_pci_dev(dev);\ 104 unsigned int input;\ 105 const char **match_strs;\ 106 const struct mmio_reg *mmio_regs;\ 107 int ret, err;\ 108 u32 reg_val;\ 109 u32 mask;\ 110\ 111 proc_priv = pci_get_drvdata(pdev);\ 112 if (table) {\ 113 match_strs = (const char **)dvfs_strings;\ 114 mmio_regs = adl_dvfs_mmio_regs;\ 115 } else { \ 116 match_strs = (const char **)fivr_strings;\ 117 mmio_regs = tgl_fivr_mmio_regs;\ 118 } \ 119 \ 120 ret = match_string(match_strs, -1, attr->attr.name);\ 121 if (ret < 0)\ 122 return ret;\ 123 if (mmio_regs[ret].read_only)\ 124 return -EPERM;\ 125 err = kstrtouint(buf, 10, &input);\ 126 if (err)\ 127 return err;\ 128 mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\ 129 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 130 reg_val &= ~mask;\ 131 reg_val |= (input << mmio_regs[ret].shift);\ 132 writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 133 return count;\ 134} 135 136RFIM_SHOW(vco_ref_code_lo, 0) 137RFIM_SHOW(vco_ref_code_hi, 0) 138RFIM_SHOW(spread_spectrum_pct, 0) 139RFIM_SHOW(spread_spectrum_clk_enable, 0) 140RFIM_SHOW(rfi_vco_ref_code, 0) 141RFIM_SHOW(fivr_fffc_rev, 0) 142 143RFIM_STORE(vco_ref_code_lo, 0) 144RFIM_STORE(vco_ref_code_hi, 0) 145RFIM_STORE(spread_spectrum_pct, 0) 146RFIM_STORE(spread_spectrum_clk_enable, 0) 147RFIM_STORE(rfi_vco_ref_code, 0) 148RFIM_STORE(fivr_fffc_rev, 0) 149 150static DEVICE_ATTR_RW(vco_ref_code_lo); 151static DEVICE_ATTR_RW(vco_ref_code_hi); 152static DEVICE_ATTR_RW(spread_spectrum_pct); 153static DEVICE_ATTR_RW(spread_spectrum_clk_enable); 154static DEVICE_ATTR_RW(rfi_vco_ref_code); 155static DEVICE_ATTR_RW(fivr_fffc_rev); 156 157static struct attribute *fivr_attrs[] = { 158 &dev_attr_vco_ref_code_lo.attr, 159 &dev_attr_vco_ref_code_hi.attr, 160 &dev_attr_spread_spectrum_pct.attr, 161 &dev_attr_spread_spectrum_clk_enable.attr, 162 &dev_attr_rfi_vco_ref_code.attr, 163 &dev_attr_fivr_fffc_rev.attr, 164 NULL 165}; 166 167static const struct attribute_group fivr_attribute_group = { 168 .attrs = fivr_attrs, 169 .name = "fivr" 170}; 171 172RFIM_SHOW(rfi_restriction_run_busy, 1) 173RFIM_SHOW(rfi_restriction_err_code, 1) 174RFIM_SHOW(rfi_restriction_data_rate, 1) 175RFIM_SHOW(ddr_data_rate_point_0, 1) 176RFIM_SHOW(ddr_data_rate_point_1, 1) 177RFIM_SHOW(ddr_data_rate_point_2, 1) 178RFIM_SHOW(ddr_data_rate_point_3, 1) 179RFIM_SHOW(rfi_disable, 1) 180 181RFIM_STORE(rfi_restriction_run_busy, 1) 182RFIM_STORE(rfi_restriction_err_code, 1) 183RFIM_STORE(rfi_restriction_data_rate, 1) 184RFIM_STORE(rfi_disable, 1) 185 186static DEVICE_ATTR_RW(rfi_restriction_run_busy); 187static DEVICE_ATTR_RW(rfi_restriction_err_code); 188static DEVICE_ATTR_RW(rfi_restriction_data_rate); 189static DEVICE_ATTR_RO(ddr_data_rate_point_0); 190static DEVICE_ATTR_RO(ddr_data_rate_point_1); 191static DEVICE_ATTR_RO(ddr_data_rate_point_2); 192static DEVICE_ATTR_RO(ddr_data_rate_point_3); 193static DEVICE_ATTR_RW(rfi_disable); 194 195static ssize_t rfi_restriction_store(struct device *dev, 196 struct device_attribute *attr, 197 const char *buf, size_t count) 198{ 199 u16 id = 0x0008; 200 u32 input; 201 int ret; 202 203 ret = kstrtou32(buf, 10, &input); 204 if (ret) 205 return ret; 206 207 ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input); 208 if (ret) 209 return ret; 210 211 return count; 212} 213 214static ssize_t rfi_restriction_show(struct device *dev, 215 struct device_attribute *attr, 216 char *buf) 217{ 218 u16 id = 0x0007; 219 u64 resp; 220 int ret; 221 222 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 223 if (ret) 224 return ret; 225 226 return sprintf(buf, "%llu\n", resp); 227} 228 229static ssize_t ddr_data_rate_show(struct device *dev, 230 struct device_attribute *attr, 231 char *buf) 232{ 233 u16 id = 0x0107; 234 u64 resp; 235 int ret; 236 237 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 238 if (ret) 239 return ret; 240 241 return sprintf(buf, "%llu\n", resp); 242} 243 244static DEVICE_ATTR_RW(rfi_restriction); 245static DEVICE_ATTR_RO(ddr_data_rate); 246 247static struct attribute *dvfs_attrs[] = { 248 &dev_attr_rfi_restriction_run_busy.attr, 249 &dev_attr_rfi_restriction_err_code.attr, 250 &dev_attr_rfi_restriction_data_rate.attr, 251 &dev_attr_ddr_data_rate_point_0.attr, 252 &dev_attr_ddr_data_rate_point_1.attr, 253 &dev_attr_ddr_data_rate_point_2.attr, 254 &dev_attr_ddr_data_rate_point_3.attr, 255 &dev_attr_rfi_disable.attr, 256 &dev_attr_ddr_data_rate.attr, 257 &dev_attr_rfi_restriction.attr, 258 NULL 259}; 260 261static const struct attribute_group dvfs_attribute_group = { 262 .attrs = dvfs_attrs, 263 .name = "dvfs" 264}; 265 266int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 267{ 268 int ret; 269 270 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 271 ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group); 272 if (ret) 273 return ret; 274 } 275 276 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) { 277 ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group); 278 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 279 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 280 return ret; 281 } 282 } 283 284 return 0; 285} 286EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 287 288void proc_thermal_rfim_remove(struct pci_dev *pdev) 289{ 290 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 291 292 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) 293 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 294 295 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) 296 sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group); 297} 298EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 299 300MODULE_LICENSE("GPL v2");