Path: blob/master/drivers/accel/habanalabs/goya/goya_hwmgr.c
26439 views
// SPDX-License-Identifier: GPL-2.012/*3* Copyright 2016-2022 HabanaLabs, Ltd.4* All Rights Reserved.5*/67#include "goyaP.h"89void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)10{11struct goya_device *goya = hdev->asic_specific;1213if (!hdev->pdev)14return;1516switch (freq) {17case PLL_HIGH:18hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);19hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);20hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);21break;22case PLL_LOW:23hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);24hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);25hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);26break;27case PLL_LAST:28hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);29hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);30hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);31break;32default:33dev_err(hdev->dev, "unknown frequency setting\n");34}35}3637static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr,38char *buf)39{40struct hl_device *hdev = dev_get_drvdata(dev);41long value;4243if (!hl_device_operational(hdev, NULL))44return -ENODEV;4546value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, false);4748if (value < 0)49return value;5051return sprintf(buf, "%lu\n", value);52}5354static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr,55const char *buf, size_t count)56{57struct hl_device *hdev = dev_get_drvdata(dev);58struct goya_device *goya = hdev->asic_specific;59int rc;60long value;6162if (!hl_device_operational(hdev, NULL)) {63count = -ENODEV;64goto fail;65}6667if (goya->pm_mng_profile == PM_AUTO) {68count = -EPERM;69goto fail;70}7172rc = kstrtoul(buf, 0, &value);7374if (rc) {75count = -EINVAL;76goto fail;77}7879hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, value);80goya->mme_clk = value;8182fail:83return count;84}8586static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr,87char *buf)88{89struct hl_device *hdev = dev_get_drvdata(dev);90long value;9192if (!hl_device_operational(hdev, NULL))93return -ENODEV;9495value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, false);9697if (value < 0)98return value;99100return sprintf(buf, "%lu\n", value);101}102103static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr,104const char *buf, size_t count)105{106struct hl_device *hdev = dev_get_drvdata(dev);107struct goya_device *goya = hdev->asic_specific;108int rc;109long value;110111if (!hl_device_operational(hdev, NULL)) {112count = -ENODEV;113goto fail;114}115116if (goya->pm_mng_profile == PM_AUTO) {117count = -EPERM;118goto fail;119}120121rc = kstrtoul(buf, 0, &value);122123if (rc) {124count = -EINVAL;125goto fail;126}127128hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, value);129goya->tpc_clk = value;130131fail:132return count;133}134135static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr,136char *buf)137{138struct hl_device *hdev = dev_get_drvdata(dev);139long value;140141if (!hl_device_operational(hdev, NULL))142return -ENODEV;143144value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, false);145146if (value < 0)147return value;148149return sprintf(buf, "%lu\n", value);150}151152static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr,153const char *buf, size_t count)154{155struct hl_device *hdev = dev_get_drvdata(dev);156struct goya_device *goya = hdev->asic_specific;157int rc;158long value;159160if (!hl_device_operational(hdev, NULL)) {161count = -ENODEV;162goto fail;163}164165if (goya->pm_mng_profile == PM_AUTO) {166count = -EPERM;167goto fail;168}169170rc = kstrtoul(buf, 0, &value);171172if (rc) {173count = -EINVAL;174goto fail;175}176177hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, value);178goya->ic_clk = value;179180fail:181return count;182}183184static ssize_t mme_clk_curr_show(struct device *dev,185struct device_attribute *attr, char *buf)186{187struct hl_device *hdev = dev_get_drvdata(dev);188long value;189190if (!hl_device_operational(hdev, NULL))191return -ENODEV;192193value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, true);194195if (value < 0)196return value;197198return sprintf(buf, "%lu\n", value);199}200201static ssize_t tpc_clk_curr_show(struct device *dev,202struct device_attribute *attr, char *buf)203{204struct hl_device *hdev = dev_get_drvdata(dev);205long value;206207if (!hl_device_operational(hdev, NULL))208return -ENODEV;209210value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, true);211212if (value < 0)213return value;214215return sprintf(buf, "%lu\n", value);216}217218static ssize_t ic_clk_curr_show(struct device *dev,219struct device_attribute *attr, char *buf)220{221struct hl_device *hdev = dev_get_drvdata(dev);222long value;223224if (!hl_device_operational(hdev, NULL))225return -ENODEV;226227value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, true);228229if (value < 0)230return value;231232return sprintf(buf, "%lu\n", value);233}234235static ssize_t pm_mng_profile_show(struct device *dev,236struct device_attribute *attr, char *buf)237{238struct hl_device *hdev = dev_get_drvdata(dev);239struct goya_device *goya = hdev->asic_specific;240241if (!hl_device_operational(hdev, NULL))242return -ENODEV;243244return sprintf(buf, "%s\n",245(goya->pm_mng_profile == PM_AUTO) ? "auto" :246(goya->pm_mng_profile == PM_MANUAL) ? "manual" :247"unknown");248}249250static ssize_t pm_mng_profile_store(struct device *dev,251struct device_attribute *attr, const char *buf, size_t count)252{253struct hl_device *hdev = dev_get_drvdata(dev);254struct goya_device *goya = hdev->asic_specific;255256if (!hl_device_operational(hdev, NULL)) {257count = -ENODEV;258goto out;259}260261mutex_lock(&hdev->fpriv_list_lock);262263if (hdev->is_compute_ctx_active) {264dev_err(hdev->dev,265"Can't change PM profile while compute context is opened on the device\n");266count = -EPERM;267goto unlock_mutex;268}269270if (strncmp("auto", buf, strlen("auto")) == 0) {271/* Make sure we are in LOW PLL when changing modes */272if (goya->pm_mng_profile == PM_MANUAL) {273goya->curr_pll_profile = PLL_HIGH;274goya->pm_mng_profile = PM_AUTO;275goya_set_frequency(hdev, PLL_LOW);276}277} else if (strncmp("manual", buf, strlen("manual")) == 0) {278if (goya->pm_mng_profile == PM_AUTO) {279/* Must release the lock because the work thread also280* takes this lock. But before we release it, set281* the mode to manual so nothing will change if a user282* suddenly opens the device283*/284goya->pm_mng_profile = PM_MANUAL;285286mutex_unlock(&hdev->fpriv_list_lock);287288/* Flush the current work so we can return to the user289* knowing that he is the only one changing frequencies290*/291if (goya->goya_work)292flush_delayed_work(&goya->goya_work->work_freq);293294return count;295}296} else {297dev_err(hdev->dev, "value should be auto or manual\n");298count = -EINVAL;299}300301unlock_mutex:302mutex_unlock(&hdev->fpriv_list_lock);303out:304return count;305}306307static ssize_t high_pll_show(struct device *dev, struct device_attribute *attr,308char *buf)309{310struct hl_device *hdev = dev_get_drvdata(dev);311312if (!hl_device_operational(hdev, NULL))313return -ENODEV;314315return sprintf(buf, "%u\n", hdev->high_pll);316}317318static ssize_t high_pll_store(struct device *dev, struct device_attribute *attr,319const char *buf, size_t count)320{321struct hl_device *hdev = dev_get_drvdata(dev);322long value;323int rc;324325if (!hl_device_operational(hdev, NULL)) {326count = -ENODEV;327goto out;328}329330rc = kstrtoul(buf, 0, &value);331332if (rc) {333count = -EINVAL;334goto out;335}336337hdev->high_pll = value;338339out:340return count;341}342343static DEVICE_ATTR_RW(high_pll);344static DEVICE_ATTR_RW(ic_clk);345static DEVICE_ATTR_RO(ic_clk_curr);346static DEVICE_ATTR_RW(mme_clk);347static DEVICE_ATTR_RO(mme_clk_curr);348static DEVICE_ATTR_RW(pm_mng_profile);349static DEVICE_ATTR_RW(tpc_clk);350static DEVICE_ATTR_RO(tpc_clk_curr);351352static struct attribute *goya_clk_dev_attrs[] = {353&dev_attr_high_pll.attr,354&dev_attr_ic_clk.attr,355&dev_attr_ic_clk_curr.attr,356&dev_attr_mme_clk.attr,357&dev_attr_mme_clk_curr.attr,358&dev_attr_pm_mng_profile.attr,359&dev_attr_tpc_clk.attr,360&dev_attr_tpc_clk_curr.attr,361NULL,362};363364static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)365{366struct hl_device *hdev = dev_get_drvdata(dev);367struct cpucp_info *cpucp_info;368369cpucp_info = &hdev->asic_prop.cpucp_info;370371return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));372}373374static DEVICE_ATTR_RO(infineon_ver);375376static struct attribute *goya_vrm_dev_attrs[] = {377&dev_attr_infineon_ver.attr,378NULL,379};380381void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,382struct attribute_group *dev_vrm_attr_grp)383{384dev_clk_attr_grp->attrs = goya_clk_dev_attrs;385dev_vrm_attr_grp->attrs = goya_vrm_dev_attrs;386}387388389