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