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