goya_hwmgr.c 8.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// SPDX-License-Identifier: GPL-2.0

/*
 * Copyright 2016-2019 HabanaLabs, Ltd.
 * All Rights Reserved.
 */

#include "goyaP.h"

void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)
{
	struct goya_device *goya = hdev->asic_specific;

	switch (freq) {
	case PLL_HIGH:
16 17 18
		hl_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);
		hl_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);
		hl_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);
19 20
		break;
	case PLL_LOW:
21 22 23
		hl_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);
		hl_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);
		hl_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);
24 25
		break;
	case PLL_LAST:
26 27 28
		hl_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);
		hl_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);
		hl_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);
29 30 31 32 33 34
		break;
	default:
		dev_err(hdev->dev, "unknown frequency setting\n");
	}
}

35 36 37 38
int goya_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)
{
	long value;

39
	if (!hl_device_operational(hdev, NULL))
40 41
		return -ENODEV;

42
	value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false);
43 44 45 46 47 48 49 50 51

	if (value < 0) {
		dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n",
			value);
		return value;
	}

	*max_clk = (value / 1000 / 1000);

52
	value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true);
53 54 55 56 57 58 59 60 61 62 63 64 65

	if (value < 0) {
		dev_err(hdev->dev,
			"Failed to retrieve device current clock %ld\n",
			value);
		return value;
	}

	*cur_clk = (value / 1000 / 1000);

	return 0;
}

66 67 68 69 70 71
static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr,
				char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

72
	if (!hl_device_operational(hdev, NULL))
73 74
		return -ENODEV;

75
	value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false);
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	struct goya_device *goya = hdev->asic_specific;
	int rc;
	long value;

91
	if (!hl_device_operational(hdev, NULL)) {
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
		count = -ENODEV;
		goto fail;
	}

	if (hdev->pm_mng_profile == PM_AUTO) {
		count = -EPERM;
		goto fail;
	}

	rc = kstrtoul(buf, 0, &value);

	if (rc) {
		count = -EINVAL;
		goto fail;
	}

108
	hl_set_frequency(hdev, HL_GOYA_MME_PLL, value);
109 110 111 112 113 114 115 116 117 118 119 120
	goya->mme_clk = value;

fail:
	return count;
}

static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr,
				char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

121
	if (!hl_device_operational(hdev, NULL))
122 123
		return -ENODEV;

124
	value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	struct goya_device *goya = hdev->asic_specific;
	int rc;
	long value;

140
	if (!hl_device_operational(hdev, NULL)) {
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
		count = -ENODEV;
		goto fail;
	}

	if (hdev->pm_mng_profile == PM_AUTO) {
		count = -EPERM;
		goto fail;
	}

	rc = kstrtoul(buf, 0, &value);

	if (rc) {
		count = -EINVAL;
		goto fail;
	}

157
	hl_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
158 159 160 161 162 163 164 165 166 167 168 169
	goya->tpc_clk = value;

fail:
	return count;
}

static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr,
				char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

170
	if (!hl_device_operational(hdev, NULL))
171 172
		return -ENODEV;

173
	value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, false);
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	struct goya_device *goya = hdev->asic_specific;
	int rc;
	long value;

189
	if (!hl_device_operational(hdev, NULL)) {
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
		count = -ENODEV;
		goto fail;
	}

	if (hdev->pm_mng_profile == PM_AUTO) {
		count = -EPERM;
		goto fail;
	}

	rc = kstrtoul(buf, 0, &value);

	if (rc) {
		count = -EINVAL;
		goto fail;
	}

206
	hl_set_frequency(hdev, HL_GOYA_IC_PLL, value);
207 208 209 210 211 212 213 214 215 216 217 218
	goya->ic_clk = value;

fail:
	return count;
}

static ssize_t mme_clk_curr_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

219
	if (!hl_device_operational(hdev, NULL))
220 221
		return -ENODEV;

222
	value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true);
223 224 225 226 227 228 229 230 231 232 233 234 235

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

static ssize_t tpc_clk_curr_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

236
	if (!hl_device_operational(hdev, NULL))
237 238
		return -ENODEV;

239
	value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
240 241 242 243 244 245 246 247 248 249 250 251 252

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

static ssize_t ic_clk_curr_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;

253
	if (!hl_device_operational(hdev, NULL))
254 255
		return -ENODEV;

256
	value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, true);
257 258 259 260 261 262 263

	if (value < 0)
		return value;

	return sprintf(buf, "%lu\n", value);
}

264 265 266 267 268
static ssize_t pm_mng_profile_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);

269
	if (!hl_device_operational(hdev, NULL))
270 271 272 273 274 275 276 277 278 279 280 281 282
		return -ENODEV;

	return sprintf(buf, "%s\n",
			(hdev->pm_mng_profile == PM_AUTO) ? "auto" :
			(hdev->pm_mng_profile == PM_MANUAL) ? "manual" :
			"unknown");
}

static ssize_t pm_mng_profile_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct hl_device *hdev = dev_get_drvdata(dev);

283
	if (!hl_device_operational(hdev, NULL)) {
284 285 286 287
		count = -ENODEV;
		goto out;
	}

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 294 295 296 297 298 299
		count = -EPERM;
		goto unlock_mutex;
	}

	if (strncmp("auto", buf, strlen("auto")) == 0) {
		/* Make sure we are in LOW PLL when changing modes */
		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 305
		}
	} else if (strncmp("manual", buf, strlen("manual")) == 0) {
		if (hdev->pm_mng_profile == PM_AUTO) {
306 307 308 309 310
			/* Must release the lock because the work thread also
			 * takes this lock. But before we release it, set
			 * the mode to manual so nothing will change if a user
			 * suddenly opens the device
			 */
311
			hdev->pm_mng_profile = PM_MANUAL;
312 313 314 315 316 317 318 319 320

			mutex_unlock(&hdev->fpriv_list_lock);

			/* Flush the current work so we can return to the user
			 * knowing that he is the only one changing frequencies
			 */
			flush_delayed_work(&hdev->work_freq);

			return count;
321 322 323 324 325 326 327
		}
	} else {
		dev_err(hdev->dev, "value should be auto or manual\n");
		count = -EINVAL;
	}

unlock_mutex:
328
	mutex_unlock(&hdev->fpriv_list_lock);
329 330 331 332 333 334 335 336 337
out:
	return count;
}

static ssize_t high_pll_show(struct device *dev, struct device_attribute *attr,
				char *buf)
{
	struct hl_device *hdev = dev_get_drvdata(dev);

338
	if (!hl_device_operational(hdev, NULL))
339 340 341 342 343 344 345 346 347 348 349 350
		return -ENODEV;

	return sprintf(buf, "%u\n", hdev->high_pll);
}

static ssize_t high_pll_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	struct hl_device *hdev = dev_get_drvdata(dev);
	long value;
	int rc;

351
	if (!hl_device_operational(hdev, NULL)) {
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
		count = -ENODEV;
		goto out;
	}

	rc = kstrtoul(buf, 0, &value);

	if (rc) {
		count = -EINVAL;
		goto out;
	}

	hdev->high_pll = value;

out:
	return count;
}

static DEVICE_ATTR_RW(high_pll);
370 371 372 373
static DEVICE_ATTR_RW(ic_clk);
static DEVICE_ATTR_RO(ic_clk_curr);
static DEVICE_ATTR_RW(mme_clk);
static DEVICE_ATTR_RO(mme_clk_curr);
374
static DEVICE_ATTR_RW(pm_mng_profile);
375 376 377 378
static DEVICE_ATTR_RW(tpc_clk);
static DEVICE_ATTR_RO(tpc_clk_curr);

static struct attribute *goya_dev_attrs[] = {
379
	&dev_attr_high_pll.attr,
380 381 382 383
	&dev_attr_ic_clk.attr,
	&dev_attr_ic_clk_curr.attr,
	&dev_attr_mme_clk.attr,
	&dev_attr_mme_clk_curr.attr,
384
	&dev_attr_pm_mng_profile.attr,
385 386 387 388 389 390 391 392 393 394
	&dev_attr_tpc_clk.attr,
	&dev_attr_tpc_clk_curr.attr,
	NULL,
};

void goya_add_device_attr(struct hl_device *hdev,
			struct attribute_group *dev_attr_grp)
{
	dev_attr_grp->attrs = goya_dev_attrs;
}