• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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