]> Git Repo - J-linux.git/blob - drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / thermal / intel / int340x_thermal / processor_thermal_rfim.c
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");
This page took 0.060464 seconds and 4 git commands to generate.