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 /* These will represent sysfs attribute names */ 23 static 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 33 static 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 */ 43 static 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 56 static 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)\ 69 static 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)\ 98 static 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 136 RFIM_SHOW(vco_ref_code_lo, 0) 137 RFIM_SHOW(vco_ref_code_hi, 0) 138 RFIM_SHOW(spread_spectrum_pct, 0) 139 RFIM_SHOW(spread_spectrum_clk_enable, 0) 140 RFIM_SHOW(rfi_vco_ref_code, 0) 141 RFIM_SHOW(fivr_fffc_rev, 0) 142 143 RFIM_STORE(vco_ref_code_lo, 0) 144 RFIM_STORE(vco_ref_code_hi, 0) 145 RFIM_STORE(spread_spectrum_pct, 0) 146 RFIM_STORE(spread_spectrum_clk_enable, 0) 147 RFIM_STORE(rfi_vco_ref_code, 0) 148 RFIM_STORE(fivr_fffc_rev, 0) 149 150 static DEVICE_ATTR_RW(vco_ref_code_lo); 151 static DEVICE_ATTR_RW(vco_ref_code_hi); 152 static DEVICE_ATTR_RW(spread_spectrum_pct); 153 static DEVICE_ATTR_RW(spread_spectrum_clk_enable); 154 static DEVICE_ATTR_RW(rfi_vco_ref_code); 155 static DEVICE_ATTR_RW(fivr_fffc_rev); 156 157 static 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 167 static const struct attribute_group fivr_attribute_group = { 168 .attrs = fivr_attrs, 169 .name = "fivr" 170 }; 171 172 RFIM_SHOW(rfi_restriction_run_busy, 1) 173 RFIM_SHOW(rfi_restriction_err_code, 1) 174 RFIM_SHOW(rfi_restriction_data_rate, 1) 175 RFIM_SHOW(ddr_data_rate_point_0, 1) 176 RFIM_SHOW(ddr_data_rate_point_1, 1) 177 RFIM_SHOW(ddr_data_rate_point_2, 1) 178 RFIM_SHOW(ddr_data_rate_point_3, 1) 179 RFIM_SHOW(rfi_disable, 1) 180 181 RFIM_STORE(rfi_restriction_run_busy, 1) 182 RFIM_STORE(rfi_restriction_err_code, 1) 183 RFIM_STORE(rfi_restriction_data_rate, 1) 184 RFIM_STORE(rfi_disable, 1) 185 186 static DEVICE_ATTR_RW(rfi_restriction_run_busy); 187 static DEVICE_ATTR_RW(rfi_restriction_err_code); 188 static DEVICE_ATTR_RW(rfi_restriction_data_rate); 189 static DEVICE_ATTR_RO(ddr_data_rate_point_0); 190 static DEVICE_ATTR_RO(ddr_data_rate_point_1); 191 static DEVICE_ATTR_RO(ddr_data_rate_point_2); 192 static DEVICE_ATTR_RO(ddr_data_rate_point_3); 193 static DEVICE_ATTR_RW(rfi_disable); 194 195 static 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 214 static 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 229 static 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 244 static DEVICE_ATTR_RW(rfi_restriction); 245 static DEVICE_ATTR_RO(ddr_data_rate); 246 247 static 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 261 static const struct attribute_group dvfs_attribute_group = { 262 .attrs = dvfs_attrs, 263 .name = "dvfs" 264 }; 265 266 int 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 } 286 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 287 288 void 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 } 298 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 299 300 MODULE_LICENSE("GPL v2"); 301