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 struct mmio_reg { 13 int read_only; 14 u32 offset; 15 int bits; 16 u16 mask; 17 u16 shift; 18 }; 19 20 /* These will represent sysfs attribute names */ 21 static const char * const fivr_strings[] = { 22 "vco_ref_code_lo", 23 "vco_ref_code_hi", 24 "spread_spectrum_pct", 25 "spread_spectrum_clk_enable", 26 "rfi_vco_ref_code", 27 "fivr_fffc_rev", 28 NULL 29 }; 30 31 static const struct mmio_reg tgl_fivr_mmio_regs[] = { 32 { 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */ 33 { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */ 34 { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */ 35 { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */ 36 { 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */ 37 { 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */ 38 }; 39 40 /* These will represent sysfs attribute names */ 41 static const char * const dvfs_strings[] = { 42 "rfi_restriction_run_busy", 43 "rfi_restriction_err_code", 44 "rfi_restriction_data_rate", 45 "rfi_restriction_data_rate_base", 46 "ddr_data_rate_point_0", 47 "ddr_data_rate_point_1", 48 "ddr_data_rate_point_2", 49 "ddr_data_rate_point_3", 50 "rfi_disable", 51 NULL 52 }; 53 54 static const struct mmio_reg adl_dvfs_mmio_regs[] = { 55 { 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */ 56 { 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */ 57 { 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */ 58 { 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */ 59 { 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */ 60 { 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */ 61 { 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */ 62 { 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */ 63 { 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */ 64 }; 65 66 #define RFIM_SHOW(suffix, table)\ 67 static ssize_t suffix##_show(struct device *dev,\ 68 struct device_attribute *attr,\ 69 char *buf)\ 70 {\ 71 struct proc_thermal_device *proc_priv;\ 72 struct pci_dev *pdev = to_pci_dev(dev);\ 73 const struct mmio_reg *mmio_regs;\ 74 const char **match_strs;\ 75 u32 reg_val;\ 76 int ret;\ 77 \ 78 proc_priv = pci_get_drvdata(pdev);\ 79 if (table) {\ 80 match_strs = (const char **)dvfs_strings;\ 81 mmio_regs = adl_dvfs_mmio_regs;\ 82 } else { \ 83 match_strs = (const char **)fivr_strings;\ 84 mmio_regs = tgl_fivr_mmio_regs;\ 85 } \ 86 \ 87 ret = match_string(match_strs, -1, attr->attr.name);\ 88 if (ret < 0)\ 89 return ret;\ 90 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 91 ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\ 92 return sprintf(buf, "%u\n", ret);\ 93 } 94 95 #define RFIM_STORE(suffix, table)\ 96 static ssize_t suffix##_store(struct device *dev,\ 97 struct device_attribute *attr,\ 98 const char *buf, size_t count)\ 99 {\ 100 struct proc_thermal_device *proc_priv;\ 101 struct pci_dev *pdev = to_pci_dev(dev);\ 102 unsigned int input;\ 103 const char **match_strs;\ 104 const struct mmio_reg *mmio_regs;\ 105 int ret, err;\ 106 u32 reg_val;\ 107 u32 mask;\ 108 \ 109 proc_priv = pci_get_drvdata(pdev);\ 110 if (table) {\ 111 match_strs = (const char **)dvfs_strings;\ 112 mmio_regs = adl_dvfs_mmio_regs;\ 113 } else { \ 114 match_strs = (const char **)fivr_strings;\ 115 mmio_regs = tgl_fivr_mmio_regs;\ 116 } \ 117 \ 118 ret = match_string(match_strs, -1, attr->attr.name);\ 119 if (ret < 0)\ 120 return ret;\ 121 if (mmio_regs[ret].read_only)\ 122 return -EPERM;\ 123 err = kstrtouint(buf, 10, &input);\ 124 if (err)\ 125 return err;\ 126 mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\ 127 reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 128 reg_val &= ~mask;\ 129 reg_val |= (input << mmio_regs[ret].shift);\ 130 writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\ 131 return count;\ 132 } 133 134 RFIM_SHOW(vco_ref_code_lo, 0) 135 RFIM_SHOW(vco_ref_code_hi, 0) 136 RFIM_SHOW(spread_spectrum_pct, 0) 137 RFIM_SHOW(spread_spectrum_clk_enable, 0) 138 RFIM_SHOW(rfi_vco_ref_code, 0) 139 RFIM_SHOW(fivr_fffc_rev, 0) 140 141 RFIM_STORE(vco_ref_code_lo, 0) 142 RFIM_STORE(vco_ref_code_hi, 0) 143 RFIM_STORE(spread_spectrum_pct, 0) 144 RFIM_STORE(spread_spectrum_clk_enable, 0) 145 RFIM_STORE(rfi_vco_ref_code, 0) 146 RFIM_STORE(fivr_fffc_rev, 0) 147 148 static DEVICE_ATTR_RW(vco_ref_code_lo); 149 static DEVICE_ATTR_RW(vco_ref_code_hi); 150 static DEVICE_ATTR_RW(spread_spectrum_pct); 151 static DEVICE_ATTR_RW(spread_spectrum_clk_enable); 152 static DEVICE_ATTR_RW(rfi_vco_ref_code); 153 static DEVICE_ATTR_RW(fivr_fffc_rev); 154 155 static struct attribute *fivr_attrs[] = { 156 &dev_attr_vco_ref_code_lo.attr, 157 &dev_attr_vco_ref_code_hi.attr, 158 &dev_attr_spread_spectrum_pct.attr, 159 &dev_attr_spread_spectrum_clk_enable.attr, 160 &dev_attr_rfi_vco_ref_code.attr, 161 &dev_attr_fivr_fffc_rev.attr, 162 NULL 163 }; 164 165 static const struct attribute_group fivr_attribute_group = { 166 .attrs = fivr_attrs, 167 .name = "fivr" 168 }; 169 170 RFIM_SHOW(rfi_restriction_run_busy, 1) 171 RFIM_SHOW(rfi_restriction_err_code, 1) 172 RFIM_SHOW(rfi_restriction_data_rate, 1) 173 RFIM_SHOW(ddr_data_rate_point_0, 1) 174 RFIM_SHOW(ddr_data_rate_point_1, 1) 175 RFIM_SHOW(ddr_data_rate_point_2, 1) 176 RFIM_SHOW(ddr_data_rate_point_3, 1) 177 RFIM_SHOW(rfi_disable, 1) 178 179 RFIM_STORE(rfi_restriction_run_busy, 1) 180 RFIM_STORE(rfi_restriction_err_code, 1) 181 RFIM_STORE(rfi_restriction_data_rate, 1) 182 RFIM_STORE(rfi_disable, 1) 183 184 static DEVICE_ATTR_RW(rfi_restriction_run_busy); 185 static DEVICE_ATTR_RW(rfi_restriction_err_code); 186 static DEVICE_ATTR_RW(rfi_restriction_data_rate); 187 static DEVICE_ATTR_RO(ddr_data_rate_point_0); 188 static DEVICE_ATTR_RO(ddr_data_rate_point_1); 189 static DEVICE_ATTR_RO(ddr_data_rate_point_2); 190 static DEVICE_ATTR_RO(ddr_data_rate_point_3); 191 static DEVICE_ATTR_RW(rfi_disable); 192 193 static struct attribute *dvfs_attrs[] = { 194 &dev_attr_rfi_restriction_run_busy.attr, 195 &dev_attr_rfi_restriction_err_code.attr, 196 &dev_attr_rfi_restriction_data_rate.attr, 197 &dev_attr_ddr_data_rate_point_0.attr, 198 &dev_attr_ddr_data_rate_point_1.attr, 199 &dev_attr_ddr_data_rate_point_2.attr, 200 &dev_attr_ddr_data_rate_point_3.attr, 201 &dev_attr_rfi_disable.attr, 202 NULL 203 }; 204 205 static const struct attribute_group dvfs_attribute_group = { 206 .attrs = dvfs_attrs, 207 .name = "dvfs" 208 }; 209 210 int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 211 { 212 int ret; 213 214 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 215 ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group); 216 if (ret) 217 return ret; 218 } 219 220 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) { 221 ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group); 222 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) { 223 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 224 return ret; 225 } 226 } 227 228 return 0; 229 } 230 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add); 231 232 void proc_thermal_rfim_remove(struct pci_dev *pdev) 233 { 234 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 235 236 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) 237 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group); 238 239 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) 240 sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group); 241 } 242 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove); 243 244 MODULE_LICENSE("GPL v2"); 245