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
goya_set_pll_profile(struct hl_device * hdev,enum hl_pll_frequency freq)10 void 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
goya_get_clk_rate(struct hl_device * hdev,u32 * cur_clk,u32 * max_clk)35 int 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
mme_clk_show(struct device * dev,struct device_attribute * attr,char * buf)66 static 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
mme_clk_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)83 static 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
111 fail:
112 return count;
113 }
114
tpc_clk_show(struct device * dev,struct device_attribute * attr,char * buf)115 static 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
tpc_clk_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)132 static 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
160 fail:
161 return count;
162 }
163
ic_clk_show(struct device * dev,struct device_attribute * attr,char * buf)164 static 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
ic_clk_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)181 static 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
209 fail:
210 return count;
211 }
212
mme_clk_curr_show(struct device * dev,struct device_attribute * attr,char * buf)213 static 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
tpc_clk_curr_show(struct device * dev,struct device_attribute * attr,char * buf)230 static 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
ic_clk_curr_show(struct device * dev,struct device_attribute * attr,char * buf)247 static 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
pm_mng_profile_show(struct device * dev,struct device_attribute * attr,char * buf)264 static 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
pm_mng_profile_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)278 static 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
327 unlock_mutex:
328 mutex_unlock(&hdev->fpriv_list_lock);
329 out:
330 return count;
331 }
332
high_pll_show(struct device * dev,struct device_attribute * attr,char * buf)333 static 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
high_pll_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)344 static 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
365 out:
366 return count;
367 }
368
369 static DEVICE_ATTR_RW(high_pll);
370 static DEVICE_ATTR_RW(ic_clk);
371 static DEVICE_ATTR_RO(ic_clk_curr);
372 static DEVICE_ATTR_RW(mme_clk);
373 static DEVICE_ATTR_RO(mme_clk_curr);
374 static DEVICE_ATTR_RW(pm_mng_profile);
375 static DEVICE_ATTR_RW(tpc_clk);
376 static DEVICE_ATTR_RO(tpc_clk_curr);
377
378 static 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
goya_add_device_attr(struct hl_device * hdev,struct attribute_group * dev_attr_grp)390 void 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