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