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 #define RFIM_SHOW(suffix, table)\ 170 static 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)\ 213 static 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 265 RFIM_SHOW(vco_ref_code_lo, 0) 266 RFIM_SHOW(vco_ref_code_hi, 0) 267 RFIM_SHOW(spread_spectrum_pct, 0) 268 RFIM_SHOW(spread_spectrum_clk_enable, 0) 269 RFIM_SHOW(rfi_vco_ref_code, 0) 270 RFIM_SHOW(fivr_fffc_rev, 0) 271 272 RFIM_STORE(vco_ref_code_lo, 0) 273 RFIM_STORE(vco_ref_code_hi, 0) 274 RFIM_STORE(spread_spectrum_pct, 0) 275 RFIM_STORE(spread_spectrum_clk_enable, 0) 276 RFIM_STORE(rfi_vco_ref_code, 0) 277 RFIM_STORE(fivr_fffc_rev, 0) 278 279 RFIM_SHOW(dlvr_spread_spectrum_pct, 2) 280 RFIM_SHOW(dlvr_control_mode, 2) 281 RFIM_SHOW(dlvr_control_lock, 2) 282 RFIM_SHOW(dlvr_hardware_rev, 2) 283 RFIM_SHOW(dlvr_freq_mhz, 2) 284 RFIM_SHOW(dlvr_pll_busy, 2) 285 RFIM_SHOW(dlvr_freq_select, 2) 286 RFIM_SHOW(dlvr_rfim_enable, 2) 287 288 RFIM_STORE(dlvr_spread_spectrum_pct, 2) 289 RFIM_STORE(dlvr_rfim_enable, 2) 290 RFIM_STORE(dlvr_freq_select, 2) 291 RFIM_STORE(dlvr_control_mode, 2) 292 RFIM_STORE(dlvr_control_lock, 2) 293 294 static DEVICE_ATTR_RW(dlvr_spread_spectrum_pct); 295 static DEVICE_ATTR_RW(dlvr_control_mode); 296 static DEVICE_ATTR_RW(dlvr_control_lock); 297 static DEVICE_ATTR_RW(dlvr_freq_select); 298 static DEVICE_ATTR_RO(dlvr_hardware_rev); 299 static DEVICE_ATTR_RO(dlvr_freq_mhz); 300 static DEVICE_ATTR_RO(dlvr_pll_busy); 301 static DEVICE_ATTR_RW(dlvr_rfim_enable); 302 303 static 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 NULL 313 }; 314 315 static const struct attribute_group dlvr_attribute_group = { 316 .attrs = dlvr_attrs, 317 .name = "dlvr" 318 }; 319 320 static DEVICE_ATTR_RW(vco_ref_code_lo); 321 static DEVICE_ATTR_RW(vco_ref_code_hi); 322 static DEVICE_ATTR_RW(spread_spectrum_pct); 323 static DEVICE_ATTR_RW(spread_spectrum_clk_enable); 324 static DEVICE_ATTR_RW(rfi_vco_ref_code); 325 static DEVICE_ATTR_RW(fivr_fffc_rev); 326 327 static 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 NULL 335 }; 336 337 static const struct attribute_group fivr_attribute_group = { 338 .attrs = fivr_attrs, 339 .name = "fivr" 340 }; 341 342 RFIM_SHOW(rfi_restriction_run_busy, 1) 343 RFIM_SHOW(rfi_restriction_err_code, 1) 344 RFIM_SHOW(rfi_restriction_data_rate, 1) 345 RFIM_SHOW(rfi_restriction_data_rate_base, 1) 346 RFIM_SHOW(ddr_data_rate_point_0, 1) 347 RFIM_SHOW(ddr_data_rate_point_1, 1) 348 RFIM_SHOW(ddr_data_rate_point_2, 1) 349 RFIM_SHOW(ddr_data_rate_point_3, 1) 350 RFIM_SHOW(rfi_disable, 1) 351 352 RFIM_STORE(rfi_restriction_run_busy, 1) 353 RFIM_STORE(rfi_restriction_err_code, 1) 354 RFIM_STORE(rfi_restriction_data_rate, 1) 355 RFIM_STORE(rfi_restriction_data_rate_base, 1) 356 RFIM_STORE(rfi_disable, 1) 357 358 static DEVICE_ATTR_RW(rfi_restriction_run_busy); 359 static DEVICE_ATTR_RW(rfi_restriction_err_code); 360 static DEVICE_ATTR_RW(rfi_restriction_data_rate); 361 static DEVICE_ATTR_RW(rfi_restriction_data_rate_base); 362 static DEVICE_ATTR_RO(ddr_data_rate_point_0); 363 static DEVICE_ATTR_RO(ddr_data_rate_point_1); 364 static DEVICE_ATTR_RO(ddr_data_rate_point_2); 365 static DEVICE_ATTR_RO(ddr_data_rate_point_3); 366 static DEVICE_ATTR_RW(rfi_disable); 367 368 static 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 387 static 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 402 static 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 417 static DEVICE_ATTR_RW(rfi_restriction); 418 static DEVICE_ATTR_RO(ddr_data_rate); 419 420 static 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 NULL 433 }; 434 435 static const struct attribute_group dvfs_attribute_group = { 436 .attrs = dvfs_attrs, 437 .name = "dvfs" 438 }; 439 440 int 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 } 470 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 471 472 void 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 } 485 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 486 487 MODULE_LICENSE("GPL v2"); 488 MODULE_DESCRIPTION("Processor Thermal RFIM Interface"); 489