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 12 MODULE_IMPORT_NS("INT340X_THERMAL"); 13 14 struct mmio_reg { 15 int read_only; 16 u32 offset; 17 int bits; 18 u16 mask; 19 u16 shift; 20 }; 21 22 struct 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 */ 29 static 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 39 static 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 48 static 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 60 static 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 71 static 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 82 static 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 90 static 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; 120 match_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 131 static 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 137 static 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 */ 144 static 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 NULL 155 }; 156 157 static 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 static const struct mapping_table *dlvr_mapping; 170 static const struct mmio_reg *dlvr_mmio_regs_table; 171 172 #define RFIM_SHOW(suffix, table)\ 173 static ssize_t suffix##_show(struct device *dev,\ 174 struct device_attribute *attr,\ 175 char *buf)\ 176 {\ 177 const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\ 178 const struct mapping_table *mapping = dlvr_mapping;\ 179 struct proc_thermal_device *proc_priv;\ 180 struct pci_dev *pdev = to_pci_dev(dev);\ 181 const char **match_strs;\ 182 int ret, err;\ 183 u32 reg_val;\ 184 char *str;\ 185 \ 186 proc_priv = pci_get_drvdata(pdev);\ 187 if (table == 1) {\ 188 match_strs = (const char **)dvfs_strings;\ 189 mmio_regs = adl_dvfs_mmio_regs;\ 190 } else if (table == 2) { \ 191 match_strs = (const char **)dlvr_strings;\ 192 } else {\ 193 match_strs = (const char **)fivr_strings;\ 194 mmio_regs = tgl_fivr_mmio_regs;\ 195 } \ 196 ret = match_string(match_strs, -1, attr->attr.name);\ 197 if (ret < 0)\ 198 return ret;\ 199 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 200 ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\ 201 err = get_mapped_string(mapping, attr->attr.name, ret, &str);\ 202 if (!err)\ 203 return sprintf(buf, "%s\n", str);\ 204 if (err == -EOPNOTSUPP)\ 205 return sprintf(buf, "%u\n", ret);\ 206 return err;\ 207 } 208 209 #define RFIM_STORE(suffix, table)\ 210 static ssize_t suffix##_store(struct device *dev,\ 211 struct device_attribute *attr,\ 212 const char *buf, size_t count)\ 213 {\ 214 const struct mmio_reg *mmio_regs = dlvr_mmio_regs_table;\ 215 const struct mapping_table *mapping = dlvr_mapping;\ 216 struct proc_thermal_device *proc_priv;\ 217 struct pci_dev *pdev = to_pci_dev(dev);\ 218 unsigned int input;\ 219 const char **match_strs;\ 220 int ret, err;\ 221 u32 reg_val;\ 222 u32 mask;\ 223 \ 224 proc_priv = pci_get_drvdata(pdev);\ 225 if (table == 1) {\ 226 match_strs = (const char **)dvfs_strings;\ 227 mmio_regs = adl_dvfs_mmio_regs;\ 228 } else if (table == 2) { \ 229 match_strs = (const char **)dlvr_strings;\ 230 } else {\ 231 match_strs = (const char **)fivr_strings;\ 232 mmio_regs = tgl_fivr_mmio_regs;\ 233 } \ 234 \ 235 ret = match_string(match_strs, -1, attr->attr.name);\ 236 if (ret < 0)\ 237 return ret;\ 238 if (mmio_regs[ret].read_only)\ 239 return -EPERM;\ 240 err = get_mapped_value(mapping, attr->attr.name, buf, &input);\ 241 if (err == -EINVAL)\ 242 return err;\ 243 if (err == -EOPNOTSUPP) {\ 244 err = kstrtouint(buf, 10, &input);\ 245 if (err)\ 246 return err;\ 247 } \ 248 mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\ 249 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 250 reg_val &= ~mask;\ 251 reg_val |= (input << mmio_regs[ret].shift);\ 252 writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 253 return count;\ 254 } 255 256 RFIM_SHOW(vco_ref_code_lo, 0) 257 RFIM_SHOW(vco_ref_code_hi, 0) 258 RFIM_SHOW(spread_spectrum_pct, 0) 259 RFIM_SHOW(spread_spectrum_clk_enable, 0) 260 RFIM_SHOW(rfi_vco_ref_code, 0) 261 RFIM_SHOW(fivr_fffc_rev, 0) 262 263 RFIM_STORE(vco_ref_code_lo, 0) 264 RFIM_STORE(vco_ref_code_hi, 0) 265 RFIM_STORE(spread_spectrum_pct, 0) 266 RFIM_STORE(spread_spectrum_clk_enable, 0) 267 RFIM_STORE(rfi_vco_ref_code, 0) 268 RFIM_STORE(fivr_fffc_rev, 0) 269 270 RFIM_SHOW(dlvr_spread_spectrum_pct, 2) 271 RFIM_SHOW(dlvr_control_mode, 2) 272 RFIM_SHOW(dlvr_control_lock, 2) 273 RFIM_SHOW(dlvr_hardware_rev, 2) 274 RFIM_SHOW(dlvr_freq_mhz, 2) 275 RFIM_SHOW(dlvr_pll_busy, 2) 276 RFIM_SHOW(dlvr_freq_select, 2) 277 RFIM_SHOW(dlvr_rfim_enable, 2) 278 279 RFIM_STORE(dlvr_spread_spectrum_pct, 2) 280 RFIM_STORE(dlvr_rfim_enable, 2) 281 RFIM_STORE(dlvr_freq_select, 2) 282 RFIM_STORE(dlvr_control_mode, 2) 283 RFIM_STORE(dlvr_control_lock, 2) 284 285 static DEVICE_ATTR_RW(dlvr_spread_spectrum_pct); 286 static DEVICE_ATTR_RW(dlvr_control_mode); 287 static DEVICE_ATTR_RW(dlvr_control_lock); 288 static DEVICE_ATTR_RW(dlvr_freq_select); 289 static DEVICE_ATTR_RO(dlvr_hardware_rev); 290 static DEVICE_ATTR_RO(dlvr_freq_mhz); 291 static DEVICE_ATTR_RO(dlvr_pll_busy); 292 static DEVICE_ATTR_RW(dlvr_rfim_enable); 293 294 static struct attribute *dlvr_attrs[] = { 295 &dev_attr_dlvr_spread_spectrum_pct.attr, 296 &dev_attr_dlvr_control_mode.attr, 297 &dev_attr_dlvr_control_lock.attr, 298 &dev_attr_dlvr_freq_select.attr, 299 &dev_attr_dlvr_hardware_rev.attr, 300 &dev_attr_dlvr_freq_mhz.attr, 301 &dev_attr_dlvr_pll_busy.attr, 302 &dev_attr_dlvr_rfim_enable.attr, 303 NULL 304 }; 305 306 static const struct attribute_group dlvr_attribute_group = { 307 .attrs = dlvr_attrs, 308 .name = "dlvr" 309 }; 310 311 static DEVICE_ATTR_RW(vco_ref_code_lo); 312 static DEVICE_ATTR_RW(vco_ref_code_hi); 313 static DEVICE_ATTR_RW(spread_spectrum_pct); 314 static DEVICE_ATTR_RW(spread_spectrum_clk_enable); 315 static DEVICE_ATTR_RW(rfi_vco_ref_code); 316 static DEVICE_ATTR_RW(fivr_fffc_rev); 317 318 static struct attribute *fivr_attrs[] = { 319 &dev_attr_vco_ref_code_lo.attr, 320 &dev_attr_vco_ref_code_hi.attr, 321 &dev_attr_spread_spectrum_pct.attr, 322 &dev_attr_spread_spectrum_clk_enable.attr, 323 &dev_attr_rfi_vco_ref_code.attr, 324 &dev_attr_fivr_fffc_rev.attr, 325 NULL 326 }; 327 328 static const struct attribute_group fivr_attribute_group = { 329 .attrs = fivr_attrs, 330 .name = "fivr" 331 }; 332 333 RFIM_SHOW(rfi_restriction_run_busy, 1) 334 RFIM_SHOW(rfi_restriction_err_code, 1) 335 RFIM_SHOW(rfi_restriction_data_rate, 1) 336 RFIM_SHOW(rfi_restriction_data_rate_base, 1) 337 RFIM_SHOW(ddr_data_rate_point_0, 1) 338 RFIM_SHOW(ddr_data_rate_point_1, 1) 339 RFIM_SHOW(ddr_data_rate_point_2, 1) 340 RFIM_SHOW(ddr_data_rate_point_3, 1) 341 RFIM_SHOW(rfi_disable, 1) 342 343 RFIM_STORE(rfi_restriction_run_busy, 1) 344 RFIM_STORE(rfi_restriction_err_code, 1) 345 RFIM_STORE(rfi_restriction_data_rate, 1) 346 RFIM_STORE(rfi_restriction_data_rate_base, 1) 347 RFIM_STORE(rfi_disable, 1) 348 349 static DEVICE_ATTR_RW(rfi_restriction_run_busy); 350 static DEVICE_ATTR_RW(rfi_restriction_err_code); 351 static DEVICE_ATTR_RW(rfi_restriction_data_rate); 352 static DEVICE_ATTR_RW(rfi_restriction_data_rate_base); 353 static DEVICE_ATTR_RO(ddr_data_rate_point_0); 354 static DEVICE_ATTR_RO(ddr_data_rate_point_1); 355 static DEVICE_ATTR_RO(ddr_data_rate_point_2); 356 static DEVICE_ATTR_RO(ddr_data_rate_point_3); 357 static DEVICE_ATTR_RW(rfi_disable); 358 359 static ssize_t rfi_restriction_store(struct device *dev, 360 struct device_attribute *attr, 361 const char *buf, size_t count) 362 { 363 u16 id = 0x0008; 364 u32 input; 365 int ret; 366 367 ret = kstrtou32(buf, 10, &input); 368 if (ret) 369 return ret; 370 371 ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input); 372 if (ret) 373 return ret; 374 375 return count; 376 } 377 378 static ssize_t rfi_restriction_show(struct device *dev, 379 struct device_attribute *attr, 380 char *buf) 381 { 382 u16 id = 0x0007; 383 u64 resp; 384 int ret; 385 386 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 387 if (ret) 388 return ret; 389 390 return sprintf(buf, "%llu\n", resp); 391 } 392 393 static ssize_t ddr_data_rate_show(struct device *dev, 394 struct device_attribute *attr, 395 char *buf) 396 { 397 u16 id = 0x0107; 398 u64 resp; 399 int ret; 400 401 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 402 if (ret) 403 return ret; 404 405 return sprintf(buf, "%llu\n", resp); 406 } 407 408 static DEVICE_ATTR_RW(rfi_restriction); 409 static DEVICE_ATTR_RO(ddr_data_rate); 410 411 static struct attribute *dvfs_attrs[] = { 412 &dev_attr_rfi_restriction_run_busy.attr, 413 &dev_attr_rfi_restriction_err_code.attr, 414 &dev_attr_rfi_restriction_data_rate.attr, 415 &dev_attr_rfi_restriction_data_rate_base.attr, 416 &dev_attr_ddr_data_rate_point_0.attr, 417 &dev_attr_ddr_data_rate_point_1.attr, 418 &dev_attr_ddr_data_rate_point_2.attr, 419 &dev_attr_ddr_data_rate_point_3.attr, 420 &dev_attr_rfi_disable.attr, 421 &dev_attr_ddr_data_rate.attr, 422 &dev_attr_rfi_restriction.attr, 423 NULL 424 }; 425 426 static const struct attribute_group dvfs_attribute_group = { 427 .attrs = dvfs_attrs, 428 .name = "dvfs" 429 }; 430 431 int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 432 { 433 int ret; 434 435 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 436 ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group); 437 if (ret) 438 return ret; 439 } 440 441 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) { 442 switch (pdev->device) { 443 case PCI_DEVICE_ID_INTEL_LNLM_THERMAL: 444 case PCI_DEVICE_ID_INTEL_PTL_THERMAL: 445 dlvr_mmio_regs_table = lnl_dlvr_mmio_regs; 446 dlvr_mapping = lnl_dlvr_mapping; 447 break; 448 default: 449 dlvr_mmio_regs_table = dlvr_mmio_regs; 450 break; 451 } 452 ret = sysfs_create_group(&pdev->dev.kobj, &dlvr_attribute_group); 453 if (ret) 454 return ret; 455 } 456 457 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) { 458 ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group); 459 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 460 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 461 return ret; 462 } 463 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) { 464 sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group); 465 return ret; 466 } 467 } 468 469 return 0; 470 } 471 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 472 473 void proc_thermal_rfim_remove(struct pci_dev *pdev) 474 { 475 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 476 477 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) 478 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 479 480 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) 481 sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group); 482 483 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) 484 sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group); 485 } 486 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 487 488 MODULE_LICENSE("GPL v2"); 489 MODULE_DESCRIPTION("Processor Thermal RFIM Interface"); 490