• 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 
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