388 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright 2016-2022 HabanaLabs, Ltd.5 * All Rights Reserved.6 */7 8#include "goyaP.h"9 10void 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 38static 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 55static 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 83fail:84 return count;85}86 87static 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 104static 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 132fail:133 return count;134}135 136static 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 153static 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 181fail:182 return count;183}184 185static 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 202static 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 219static 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 236static 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 251static 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 also281 * takes this lock. But before we release it, set282 * the mode to manual so nothing will change if a user283 * suddenly opens the device284 */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 user290 * knowing that he is the only one changing frequencies291 */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 302unlock_mutex:303 mutex_unlock(&hdev->fpriv_list_lock);304out:305 return count;306}307 308static 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 319static 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 340out:341 return count;342}343 344static DEVICE_ATTR_RW(high_pll);345static DEVICE_ATTR_RW(ic_clk);346static DEVICE_ATTR_RO(ic_clk_curr);347static DEVICE_ATTR_RW(mme_clk);348static DEVICE_ATTR_RO(mme_clk_curr);349static DEVICE_ATTR_RW(pm_mng_profile);350static DEVICE_ATTR_RW(tpc_clk);351static DEVICE_ATTR_RO(tpc_clk_curr);352 353static 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 365static 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 375static DEVICE_ATTR_RO(infineon_ver);376 377static struct attribute *goya_vrm_dev_attrs[] = {378 &dev_attr_infineon_ver.attr,379 NULL,380};381 382void 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