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