1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright 2016-2022 HabanaLabs, Ltd.
5 * All Rights Reserved.
6 */
7
8#include "goyaP.h"
9
10void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)
11{
12	struct goya_device *goya = hdev->asic_specific;
13
14	if (!hdev->pdev)
15		return;
16
17	switch (freq) {
18	case PLL_HIGH:
19		hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);
20		hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);
21		hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);
22		break;
23	case PLL_LOW:
24		hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);
25		hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);
26		hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);
27		break;
28	case PLL_LAST:
29		hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);
30		hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);
31		hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);
32		break;
33	default:
34		dev_err(hdev->dev, "unknown frequency setting\n");
35	}
36}
37
38static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr,
39				char *buf)
40{
41	struct hl_device *hdev = dev_get_drvdata(dev);
42	long value;
43
44	if (!hl_device_operational(hdev, NULL))
45		return -ENODEV;
46
47	value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, false);
48
49	if (value < 0)
50		return value;
51
52	return sprintf(buf, "%lu\n", value);
53}
54
55static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr,
56				const char *buf, size_t count)
57{
58	struct hl_device *hdev = dev_get_drvdata(dev);
59	struct goya_device *goya = hdev->asic_specific;
60	int rc;
61	long value;
62
63	if (!hl_device_operational(hdev, NULL)) {
64		count = -ENODEV;
65		goto fail;
66	}
67
68	if (goya->pm_mng_profile == PM_AUTO) {
69		count = -EPERM;
70		goto fail;
71	}
72
73	rc = kstrtoul(buf, 0, &value);
74
75	if (rc) {
76		count = -EINVAL;
77		goto fail;
78	}
79
80	hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, value);
81	goya->mme_clk = value;
82
83fail:
84	return count;
85}
86
87static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr,
88				char *buf)
89{
90	struct hl_device *hdev = dev_get_drvdata(dev);
91	long value;
92
93	if (!hl_device_operational(hdev, NULL))
94		return -ENODEV;
95
96	value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
97
98	if (value < 0)
99		return value;
100
101	return sprintf(buf, "%lu\n", value);
102}
103
104static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr,
105				const char *buf, size_t count)
106{
107	struct hl_device *hdev = dev_get_drvdata(dev);
108	struct goya_device *goya = hdev->asic_specific;
109	int rc;
110	long value;
111
112	if (!hl_device_operational(hdev, NULL)) {
113		count = -ENODEV;
114		goto fail;
115	}
116
117	if (goya->pm_mng_profile == PM_AUTO) {
118		count = -EPERM;
119		goto fail;
120	}
121
122	rc = kstrtoul(buf, 0, &value);
123
124	if (rc) {
125		count = -EINVAL;
126		goto fail;
127	}
128
129	hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
130	goya->tpc_clk = value;
131
132fail:
133	return count;
134}
135
136static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr,
137				char *buf)
138{
139	struct hl_device *hdev = dev_get_drvdata(dev);
140	long value;
141
142	if (!hl_device_operational(hdev, NULL))
143		return -ENODEV;
144
145	value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, false);
146
147	if (value < 0)
148		return value;
149
150	return sprintf(buf, "%lu\n", value);
151}
152
153static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr,
154				const char *buf, size_t count)
155{
156	struct hl_device *hdev = dev_get_drvdata(dev);
157	struct goya_device *goya = hdev->asic_specific;
158	int rc;
159	long value;
160
161	if (!hl_device_operational(hdev, NULL)) {
162		count = -ENODEV;
163		goto fail;
164	}
165
166	if (goya->pm_mng_profile == PM_AUTO) {
167		count = -EPERM;
168		goto fail;
169	}
170
171	rc = kstrtoul(buf, 0, &value);
172
173	if (rc) {
174		count = -EINVAL;
175		goto fail;
176	}
177
178	hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, value);
179	goya->ic_clk = value;
180
181fail:
182	return count;
183}
184
185static ssize_t mme_clk_curr_show(struct device *dev,
186				struct device_attribute *attr, char *buf)
187{
188	struct hl_device *hdev = dev_get_drvdata(dev);
189	long value;
190
191	if (!hl_device_operational(hdev, NULL))
192		return -ENODEV;
193
194	value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, true);
195
196	if (value < 0)
197		return value;
198
199	return sprintf(buf, "%lu\n", value);
200}
201
202static ssize_t tpc_clk_curr_show(struct device *dev,
203				struct device_attribute *attr, char *buf)
204{
205	struct hl_device *hdev = dev_get_drvdata(dev);
206	long value;
207
208	if (!hl_device_operational(hdev, NULL))
209		return -ENODEV;
210
211	value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
212
213	if (value < 0)
214		return value;
215
216	return sprintf(buf, "%lu\n", value);
217}
218
219static ssize_t ic_clk_curr_show(struct device *dev,
220				struct device_attribute *attr, char *buf)
221{
222	struct hl_device *hdev = dev_get_drvdata(dev);
223	long value;
224
225	if (!hl_device_operational(hdev, NULL))
226		return -ENODEV;
227
228	value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, true);
229
230	if (value < 0)
231		return value;
232
233	return sprintf(buf, "%lu\n", value);
234}
235
236static ssize_t pm_mng_profile_show(struct device *dev,
237				struct device_attribute *attr, char *buf)
238{
239	struct hl_device *hdev = dev_get_drvdata(dev);
240	struct goya_device *goya = hdev->asic_specific;
241
242	if (!hl_device_operational(hdev, NULL))
243		return -ENODEV;
244
245	return sprintf(buf, "%s\n",
246			(goya->pm_mng_profile == PM_AUTO) ? "auto" :
247			(goya->pm_mng_profile == PM_MANUAL) ? "manual" :
248			"unknown");
249}
250
251static ssize_t pm_mng_profile_store(struct device *dev,
252		struct device_attribute *attr, const char *buf, size_t count)
253{
254	struct hl_device *hdev = dev_get_drvdata(dev);
255	struct goya_device *goya = hdev->asic_specific;
256
257	if (!hl_device_operational(hdev, NULL)) {
258		count = -ENODEV;
259		goto out;
260	}
261
262	mutex_lock(&hdev->fpriv_list_lock);
263
264	if (hdev->is_compute_ctx_active) {
265		dev_err(hdev->dev,
266			"Can't change PM profile while compute context is opened on the device\n");
267		count = -EPERM;
268		goto unlock_mutex;
269	}
270
271	if (strncmp("auto", buf, strlen("auto")) == 0) {
272		/* Make sure we are in LOW PLL when changing modes */
273		if (goya->pm_mng_profile == PM_MANUAL) {
274			goya->curr_pll_profile = PLL_HIGH;
275			goya->pm_mng_profile = PM_AUTO;
276			goya_set_frequency(hdev, PLL_LOW);
277		}
278	} else if (strncmp("manual", buf, strlen("manual")) == 0) {
279		if (goya->pm_mng_profile == PM_AUTO) {
280			/* Must release the lock because the work thread also
281			 * takes this lock. But before we release it, set
282			 * the mode to manual so nothing will change if a user
283			 * suddenly opens the device
284			 */
285			goya->pm_mng_profile = PM_MANUAL;
286
287			mutex_unlock(&hdev->fpriv_list_lock);
288
289			/* Flush the current work so we can return to the user
290			 * knowing that he is the only one changing frequencies
291			 */
292			if (goya->goya_work)
293				flush_delayed_work(&goya->goya_work->work_freq);
294
295			return count;
296		}
297	} else {
298		dev_err(hdev->dev, "value should be auto or manual\n");
299		count = -EINVAL;
300	}
301
302unlock_mutex:
303	mutex_unlock(&hdev->fpriv_list_lock);
304out:
305	return count;
306}
307
308static ssize_t high_pll_show(struct device *dev, struct device_attribute *attr,
309				char *buf)
310{
311	struct hl_device *hdev = dev_get_drvdata(dev);
312
313	if (!hl_device_operational(hdev, NULL))
314		return -ENODEV;
315
316	return sprintf(buf, "%u\n", hdev->high_pll);
317}
318
319static ssize_t high_pll_store(struct device *dev, struct device_attribute *attr,
320				const char *buf, size_t count)
321{
322	struct hl_device *hdev = dev_get_drvdata(dev);
323	long value;
324	int rc;
325
326	if (!hl_device_operational(hdev, NULL)) {
327		count = -ENODEV;
328		goto out;
329	}
330
331	rc = kstrtoul(buf, 0, &value);
332
333	if (rc) {
334		count = -EINVAL;
335		goto out;
336	}
337
338	hdev->high_pll = value;
339
340out:
341	return count;
342}
343
344static DEVICE_ATTR_RW(high_pll);
345static DEVICE_ATTR_RW(ic_clk);
346static DEVICE_ATTR_RO(ic_clk_curr);
347static DEVICE_ATTR_RW(mme_clk);
348static DEVICE_ATTR_RO(mme_clk_curr);
349static DEVICE_ATTR_RW(pm_mng_profile);
350static DEVICE_ATTR_RW(tpc_clk);
351static DEVICE_ATTR_RO(tpc_clk_curr);
352
353static struct attribute *goya_clk_dev_attrs[] = {
354	&dev_attr_high_pll.attr,
355	&dev_attr_ic_clk.attr,
356	&dev_attr_ic_clk_curr.attr,
357	&dev_attr_mme_clk.attr,
358	&dev_attr_mme_clk_curr.attr,
359	&dev_attr_pm_mng_profile.attr,
360	&dev_attr_tpc_clk.attr,
361	&dev_attr_tpc_clk_curr.attr,
362	NULL,
363};
364
365static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
366{
367	struct hl_device *hdev = dev_get_drvdata(dev);
368	struct cpucp_info *cpucp_info;
369
370	cpucp_info = &hdev->asic_prop.cpucp_info;
371
372	return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
373}
374
375static DEVICE_ATTR_RO(infineon_ver);
376
377static struct attribute *goya_vrm_dev_attrs[] = {
378	&dev_attr_infineon_ver.attr,
379	NULL,
380};
381
382void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
383				struct attribute_group *dev_vrm_attr_grp)
384{
385	dev_clk_attr_grp->attrs = goya_clk_dev_attrs;
386	dev_vrm_attr_grp->attrs = goya_vrm_dev_attrs;
387}
388