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