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(rfi_restriction_data_rate_base, 1) 176 RFIM_SHOW(ddr_data_rate_point_0, 1) 177 RFIM_SHOW(ddr_data_rate_point_1, 1) 178 RFIM_SHOW(ddr_data_rate_point_2, 1) 179 RFIM_SHOW(ddr_data_rate_point_3, 1) 180 RFIM_SHOW(rfi_disable, 1) 181 182 RFIM_STORE(rfi_restriction_run_busy, 1) 183 RFIM_STORE(rfi_restriction_err_code, 1) 184 RFIM_STORE(rfi_restriction_data_rate, 1) 185 RFIM_STORE(rfi_restriction_data_rate_base, 1) 186 RFIM_STORE(rfi_disable, 1) 187 188 static DEVICE_ATTR_RW(rfi_restriction_run_busy); 189 static DEVICE_ATTR_RW(rfi_restriction_err_code); 190 static DEVICE_ATTR_RW(rfi_restriction_data_rate); 191 static DEVICE_ATTR_RW(rfi_restriction_data_rate_base); 192 static DEVICE_ATTR_RO(ddr_data_rate_point_0); 193 static DEVICE_ATTR_RO(ddr_data_rate_point_1); 194 static DEVICE_ATTR_RO(ddr_data_rate_point_2); 195 static DEVICE_ATTR_RO(ddr_data_rate_point_3); 196 static DEVICE_ATTR_RW(rfi_disable); 197 198 static ssize_t rfi_restriction_store(struct device *dev, 199 struct device_attribute *attr, 200 const char *buf, size_t count) 201 { 202 u16 id = 0x0008; 203 u32 input; 204 int ret; 205 206 ret = kstrtou32(buf, 10, &input); 207 if (ret) 208 return ret; 209 210 ret = processor_thermal_send_mbox_write_cmd(to_pci_dev(dev), id, input); 211 if (ret) 212 return ret; 213 214 return count; 215 } 216 217 static ssize_t rfi_restriction_show(struct device *dev, 218 struct device_attribute *attr, 219 char *buf) 220 { 221 u16 id = 0x0007; 222 u64 resp; 223 int ret; 224 225 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 226 if (ret) 227 return ret; 228 229 return sprintf(buf, "%llu\n", resp); 230 } 231 232 static ssize_t ddr_data_rate_show(struct device *dev, 233 struct device_attribute *attr, 234 char *buf) 235 { 236 u16 id = 0x0107; 237 u64 resp; 238 int ret; 239 240 ret = processor_thermal_send_mbox_read_cmd(to_pci_dev(dev), id, &resp); 241 if (ret) 242 return ret; 243 244 return sprintf(buf, "%llu\n", resp); 245 } 246 247 static DEVICE_ATTR_RW(rfi_restriction); 248 static DEVICE_ATTR_RO(ddr_data_rate); 249 250 static struct attribute *dvfs_attrs[] = { 251 &dev_attr_rfi_restriction_run_busy.attr, 252 &dev_attr_rfi_restriction_err_code.attr, 253 &dev_attr_rfi_restriction_data_rate.attr, 254 &dev_attr_rfi_restriction_data_rate_base.attr, 255 &dev_attr_ddr_data_rate_point_0.attr, 256 &dev_attr_ddr_data_rate_point_1.attr, 257 &dev_attr_ddr_data_rate_point_2.attr, 258 &dev_attr_ddr_data_rate_point_3.attr, 259 &dev_attr_rfi_disable.attr, 260 &dev_attr_ddr_data_rate.attr, 261 &dev_attr_rfi_restriction.attr, 262 NULL 263 }; 264 265 static const struct attribute_group dvfs_attribute_group = { 266 .attrs = dvfs_attrs, 267 .name = "dvfs" 268 }; 269 270 int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 271 { 272 int ret; 273 274 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 275 ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group); 276 if (ret) 277 return ret; 278 } 279 280 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) { 281 ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group); 282 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 283 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 284 return ret; 285 } 286 } 287 288 return 0; 289 } 290 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 291 292 void proc_thermal_rfim_remove(struct pci_dev *pdev) 293 { 294 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 295 296 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) 297 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 298 299 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) 300 sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group); 301 } 302 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 303 304 MODULE_LICENSE("GPL v2"); 305