forked from Qortal/Brooklyn
Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey!
395 lines
8.3 KiB
C
395 lines
8.3 KiB
C
// 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:
|
|
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);
|
|
break;
|
|
case PLL_LOW:
|
|
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);
|
|
break;
|
|
case PLL_LAST:
|
|
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);
|
|
break;
|
|
default:
|
|
dev_err(hdev->dev, "unknown frequency setting\n");
|
|
}
|
|
}
|
|
|
|
int goya_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)
|
|
{
|
|
long value;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false);
|
|
|
|
if (value < 0) {
|
|
dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n",
|
|
value);
|
|
return value;
|
|
}
|
|
|
|
*max_clk = (value / 1000 / 1000);
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true);
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false);
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL)) {
|
|
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;
|
|
}
|
|
|
|
hl_set_frequency(hdev, HL_GOYA_MME_PLL, value);
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL)) {
|
|
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;
|
|
}
|
|
|
|
hl_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, false);
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL)) {
|
|
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;
|
|
}
|
|
|
|
hl_set_frequency(hdev, HL_GOYA_IC_PLL, value);
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true);
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
|
|
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
return -ENODEV;
|
|
|
|
value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, true);
|
|
|
|
if (value < 0)
|
|
return value;
|
|
|
|
return sprintf(buf, "%lu\n", value);
|
|
}
|
|
|
|
static ssize_t pm_mng_profile_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct hl_device *hdev = dev_get_drvdata(dev);
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
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);
|
|
|
|
if (!hl_device_operational(hdev, NULL)) {
|
|
count = -ENODEV;
|
|
goto out;
|
|
}
|
|
|
|
mutex_lock(&hdev->fpriv_list_lock);
|
|
|
|
if (hdev->compute_ctx) {
|
|
dev_err(hdev->dev,
|
|
"Can't change PM profile while compute context is opened on the device\n");
|
|
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) {
|
|
hdev->curr_pll_profile = PLL_HIGH;
|
|
hdev->pm_mng_profile = PM_AUTO;
|
|
hl_device_set_frequency(hdev, PLL_LOW);
|
|
}
|
|
} else if (strncmp("manual", buf, strlen("manual")) == 0) {
|
|
if (hdev->pm_mng_profile == PM_AUTO) {
|
|
/* 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
|
|
*/
|
|
hdev->pm_mng_profile = PM_MANUAL;
|
|
|
|
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;
|
|
}
|
|
} else {
|
|
dev_err(hdev->dev, "value should be auto or manual\n");
|
|
count = -EINVAL;
|
|
}
|
|
|
|
unlock_mutex:
|
|
mutex_unlock(&hdev->fpriv_list_lock);
|
|
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);
|
|
|
|
if (!hl_device_operational(hdev, NULL))
|
|
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;
|
|
|
|
if (!hl_device_operational(hdev, NULL)) {
|
|
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);
|
|
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);
|
|
static DEVICE_ATTR_RW(pm_mng_profile);
|
|
static DEVICE_ATTR_RW(tpc_clk);
|
|
static DEVICE_ATTR_RO(tpc_clk_curr);
|
|
|
|
static struct attribute *goya_dev_attrs[] = {
|
|
&dev_attr_high_pll.attr,
|
|
&dev_attr_ic_clk.attr,
|
|
&dev_attr_ic_clk_curr.attr,
|
|
&dev_attr_mme_clk.attr,
|
|
&dev_attr_mme_clk_curr.attr,
|
|
&dev_attr_pm_mng_profile.attr,
|
|
&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;
|
|
}
|