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