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 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 
213 static 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 
228 static 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 
243 static DEVICE_ATTR_RW(rfi_restriction);
244 static DEVICE_ATTR_RO(ddr_data_rate);
245 
246 static 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 
260 static const struct attribute_group dvfs_attribute_group = {
261 	.attrs = dvfs_attrs,
262 	.name = "dvfs"
263 };
264 
265 int 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 }
285 EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
286 
287 void 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 }
297 EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
298 
299 MODULE_LICENSE("GPL v2");
300