FILE
processor_thermal_rfim.c
File preview with syntax highlighting.
linux-6.19.14/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.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.