1
2
3
4
5
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/pci.h>
10#include "processor_thermal_device.h"
11
12struct mmio_reg {
13 int read_only;
14 u32 offset;
15 int bits;
16 u16 mask;
17 u16 shift;
18};
19
20
21static 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
31static const struct mmio_reg tgl_fivr_mmio_regs[] = {
32 { 0, 0x5A18, 3, 0x7, 12},
33 { 0, 0x5A18, 8, 0xFF, 16},
34 { 0, 0x5A08, 8, 0xFF, 0},
35 { 0, 0x5A08, 1, 0x1, 8},
36 { 1, 0x5A10, 12, 0xFFF, 0},
37 { 1, 0x5A14, 2, 0x3, 1},
38};
39
40
41static 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
54static const struct mmio_reg adl_dvfs_mmio_regs[] = {
55 { 0, 0x5A38, 1, 0x1, 31},
56 { 0, 0x5A38, 7, 0x7F, 24},
57 { 0, 0x5A38, 8, 0xFF, 16},
58 { 0, 0x5A38, 16, 0xFFFF, 0},
59 { 0, 0x5A30, 10, 0x3FF, 0},
60 { 0, 0x5A30, 10, 0x3FF, 10},
61 { 0, 0x5A30, 10, 0x3FF, 20},
62 { 0, 0x5A30, 10, 0x3FF, 30},
63 { 0, 0x5A40, 1, 0x1, 0},
64};
65
66#define RFIM_SHOW(suffix, table)\
67static 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)\
96static 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
134RFIM_SHOW(vco_ref_code_lo, 0)
135RFIM_SHOW(vco_ref_code_hi, 0)
136RFIM_SHOW(spread_spectrum_pct, 0)
137RFIM_SHOW(spread_spectrum_clk_enable, 0)
138RFIM_SHOW(rfi_vco_ref_code, 0)
139RFIM_SHOW(fivr_fffc_rev, 0)
140
141RFIM_STORE(vco_ref_code_lo, 0)
142RFIM_STORE(vco_ref_code_hi, 0)
143RFIM_STORE(spread_spectrum_pct, 0)
144RFIM_STORE(spread_spectrum_clk_enable, 0)
145RFIM_STORE(rfi_vco_ref_code, 0)
146RFIM_STORE(fivr_fffc_rev, 0)
147
148static DEVICE_ATTR_RW(vco_ref_code_lo);
149static DEVICE_ATTR_RW(vco_ref_code_hi);
150static DEVICE_ATTR_RW(spread_spectrum_pct);
151static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
152static DEVICE_ATTR_RW(rfi_vco_ref_code);
153static DEVICE_ATTR_RW(fivr_fffc_rev);
154
155static 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
165static const struct attribute_group fivr_attribute_group = {
166 .attrs = fivr_attrs,
167 .name = "fivr"
168};
169
170RFIM_SHOW(rfi_restriction_run_busy, 1)
171RFIM_SHOW(rfi_restriction_err_code, 1)
172RFIM_SHOW(rfi_restriction_data_rate, 1)
173RFIM_SHOW(ddr_data_rate_point_0, 1)
174RFIM_SHOW(ddr_data_rate_point_1, 1)
175RFIM_SHOW(ddr_data_rate_point_2, 1)
176RFIM_SHOW(ddr_data_rate_point_3, 1)
177RFIM_SHOW(rfi_disable, 1)
178
179RFIM_STORE(rfi_restriction_run_busy, 1)
180RFIM_STORE(rfi_restriction_err_code, 1)
181RFIM_STORE(rfi_restriction_data_rate, 1)
182RFIM_STORE(rfi_disable, 1)
183
184static DEVICE_ATTR_RW(rfi_restriction_run_busy);
185static DEVICE_ATTR_RW(rfi_restriction_err_code);
186static DEVICE_ATTR_RW(rfi_restriction_data_rate);
187static DEVICE_ATTR_RO(ddr_data_rate_point_0);
188static DEVICE_ATTR_RO(ddr_data_rate_point_1);
189static DEVICE_ATTR_RO(ddr_data_rate_point_2);
190static DEVICE_ATTR_RO(ddr_data_rate_point_3);
191static DEVICE_ATTR_RW(rfi_disable);
192
193static ssize_t rfi_restriction_store(struct device *dev,
194 struct device_attribute *attr,
195 const char *buf, size_t count)
196{
197 u16 cmd_id = 0x0008;
198 u32 cmd_resp;
199 u32 input;
200 int ret;
201
202 ret = kstrtou32(buf, 10, &input);
203 if (ret)
204 return ret;
205
206 ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp);
207 if (ret)
208 return ret;
209
210 return count;
211}
212
213static ssize_t rfi_restriction_show(struct device *dev,
214 struct device_attribute *attr,
215 char *buf)
216{
217 u16 cmd_id = 0x0007;
218 u32 cmd_resp;
219 int ret;
220
221 ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
222 if (ret)
223 return ret;
224
225 return sprintf(buf, "%u\n", cmd_resp);
226}
227
228static ssize_t ddr_data_rate_show(struct device *dev,
229 struct device_attribute *attr,
230 char *buf)
231{
232 u16 cmd_id = 0x0107;
233 u32 cmd_resp;
234 int ret;
235
236 ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
237 if (ret)
238 return ret;
239
240 return sprintf(buf, "%u\n", cmd_resp);
241}
242
243static DEVICE_ATTR_RW(rfi_restriction);
244static DEVICE_ATTR_RO(ddr_data_rate);
245
246static struct attribute *dvfs_attrs[] = {
247 &dev_attr_rfi_restriction_run_busy.attr,
248 &dev_attr_rfi_restriction_err_code.attr,
249 &dev_attr_rfi_restriction_data_rate.attr,
250 &dev_attr_ddr_data_rate_point_0.attr,
251 &dev_attr_ddr_data_rate_point_1.attr,
252 &dev_attr_ddr_data_rate_point_2.attr,
253 &dev_attr_ddr_data_rate_point_3.attr,
254 &dev_attr_rfi_disable.attr,
255 &dev_attr_ddr_data_rate.attr,
256 &dev_attr_rfi_restriction.attr,
257 NULL
258};
259
260static const struct attribute_group dvfs_attribute_group = {
261 .attrs = dvfs_attrs,
262 .name = "dvfs"
263};
264
265int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
266{
267 int ret;
268
269 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
270 ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
271 if (ret)
272 return ret;
273 }
274
275 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
276 ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
277 if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
278 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
279 return ret;
280 }
281 }
282
283 return 0;
284}
285EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
286
287void proc_thermal_rfim_remove(struct pci_dev *pdev)
288{
289 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
290
291 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
292 sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
293
294 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
295 sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
296}
297EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
298
299MODULE_LICENSE("GPL v2");
300