linux/drivers/gpu/drm/panfrost/panfrost_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
   3/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
   4
   5#include <linux/clk.h>
   6#include <linux/reset.h>
   7#include <linux/platform_device.h>
   8#include <linux/pm_runtime.h>
   9#include <linux/regulator/consumer.h>
  10
  11#include "panfrost_device.h"
  12#include "panfrost_devfreq.h"
  13#include "panfrost_features.h"
  14#include "panfrost_gpu.h"
  15#include "panfrost_job.h"
  16#include "panfrost_mmu.h"
  17#include "panfrost_perfcnt.h"
  18
  19static int panfrost_reset_init(struct panfrost_device *pfdev)
  20{
  21        int err;
  22
  23        pfdev->rstc = devm_reset_control_array_get(pfdev->dev, false, true);
  24        if (IS_ERR(pfdev->rstc)) {
  25                dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc));
  26                return PTR_ERR(pfdev->rstc);
  27        }
  28
  29        err = reset_control_deassert(pfdev->rstc);
  30        if (err)
  31                return err;
  32
  33        return 0;
  34}
  35
  36static void panfrost_reset_fini(struct panfrost_device *pfdev)
  37{
  38        reset_control_assert(pfdev->rstc);
  39}
  40
  41static int panfrost_clk_init(struct panfrost_device *pfdev)
  42{
  43        int err;
  44        unsigned long rate;
  45
  46        pfdev->clock = devm_clk_get(pfdev->dev, NULL);
  47        if (IS_ERR(pfdev->clock)) {
  48                dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock));
  49                return PTR_ERR(pfdev->clock);
  50        }
  51
  52        rate = clk_get_rate(pfdev->clock);
  53        dev_info(pfdev->dev, "clock rate = %lu\n", rate);
  54
  55        err = clk_prepare_enable(pfdev->clock);
  56        if (err)
  57                return err;
  58
  59        pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus");
  60        if (IS_ERR(pfdev->bus_clock)) {
  61                dev_err(pfdev->dev, "get bus_clock failed %ld\n",
  62                        PTR_ERR(pfdev->bus_clock));
  63                return PTR_ERR(pfdev->bus_clock);
  64        }
  65
  66        if (pfdev->bus_clock) {
  67                rate = clk_get_rate(pfdev->bus_clock);
  68                dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate);
  69
  70                err = clk_prepare_enable(pfdev->bus_clock);
  71                if (err)
  72                        goto disable_clock;
  73        }
  74
  75        return 0;
  76
  77disable_clock:
  78        clk_disable_unprepare(pfdev->clock);
  79
  80        return err;
  81}
  82
  83static void panfrost_clk_fini(struct panfrost_device *pfdev)
  84{
  85        clk_disable_unprepare(pfdev->bus_clock);
  86        clk_disable_unprepare(pfdev->clock);
  87}
  88
  89static int panfrost_regulator_init(struct panfrost_device *pfdev)
  90{
  91        int ret;
  92
  93        pfdev->regulator = devm_regulator_get_optional(pfdev->dev, "mali");
  94        if (IS_ERR(pfdev->regulator)) {
  95                ret = PTR_ERR(pfdev->regulator);
  96                pfdev->regulator = NULL;
  97                if (ret == -ENODEV)
  98                        return 0;
  99                dev_err(pfdev->dev, "failed to get regulator: %d\n", ret);
 100                return ret;
 101        }
 102
 103        ret = regulator_enable(pfdev->regulator);
 104        if (ret < 0) {
 105                dev_err(pfdev->dev, "failed to enable regulator: %d\n", ret);
 106                return ret;
 107        }
 108
 109        return 0;
 110}
 111
 112static void panfrost_regulator_fini(struct panfrost_device *pfdev)
 113{
 114        if (pfdev->regulator)
 115                regulator_disable(pfdev->regulator);
 116}
 117
 118int panfrost_device_init(struct panfrost_device *pfdev)
 119{
 120        int err;
 121        struct resource *res;
 122
 123        mutex_init(&pfdev->sched_lock);
 124        mutex_init(&pfdev->reset_lock);
 125        INIT_LIST_HEAD(&pfdev->scheduled_jobs);
 126
 127        spin_lock_init(&pfdev->hwaccess_lock);
 128
 129        err = panfrost_clk_init(pfdev);
 130        if (err) {
 131                dev_err(pfdev->dev, "clk init failed %d\n", err);
 132                return err;
 133        }
 134
 135        err = panfrost_regulator_init(pfdev);
 136        if (err) {
 137                dev_err(pfdev->dev, "regulator init failed %d\n", err);
 138                goto err_out0;
 139        }
 140
 141        err = panfrost_reset_init(pfdev);
 142        if (err) {
 143                dev_err(pfdev->dev, "reset init failed %d\n", err);
 144                goto err_out1;
 145        }
 146
 147        res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0);
 148        pfdev->iomem = devm_ioremap_resource(pfdev->dev, res);
 149        if (IS_ERR(pfdev->iomem)) {
 150                dev_err(pfdev->dev, "failed to ioremap iomem\n");
 151                err = PTR_ERR(pfdev->iomem);
 152                goto err_out2;
 153        }
 154
 155        err = panfrost_gpu_init(pfdev);
 156        if (err)
 157                goto err_out2;
 158
 159        err = panfrost_mmu_init(pfdev);
 160        if (err)
 161                goto err_out3;
 162
 163        err = panfrost_job_init(pfdev);
 164        if (err)
 165                goto err_out4;
 166
 167        /* runtime PM will wake us up later */
 168        panfrost_gpu_power_off(pfdev);
 169
 170        pm_runtime_set_active(pfdev->dev);
 171        pm_runtime_get_sync(pfdev->dev);
 172        pm_runtime_mark_last_busy(pfdev->dev);
 173        pm_runtime_put_autosuspend(pfdev->dev);
 174
 175        err = panfrost_perfcnt_init(pfdev);
 176        if (err)
 177                goto err_out5;
 178
 179        return 0;
 180err_out5:
 181        panfrost_job_fini(pfdev);
 182err_out4:
 183        panfrost_mmu_fini(pfdev);
 184err_out3:
 185        panfrost_gpu_fini(pfdev);
 186err_out2:
 187        panfrost_reset_fini(pfdev);
 188err_out1:
 189        panfrost_regulator_fini(pfdev);
 190err_out0:
 191        panfrost_clk_fini(pfdev);
 192        return err;
 193}
 194
 195void panfrost_device_fini(struct panfrost_device *pfdev)
 196{
 197        panfrost_perfcnt_fini(pfdev);
 198        panfrost_job_fini(pfdev);
 199        panfrost_mmu_fini(pfdev);
 200        panfrost_gpu_fini(pfdev);
 201        panfrost_reset_fini(pfdev);
 202        panfrost_regulator_fini(pfdev);
 203        panfrost_clk_fini(pfdev);
 204}
 205
 206const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code)
 207{
 208        switch (exception_code) {
 209                /* Non-Fault Status code */
 210        case 0x00: return "NOT_STARTED/IDLE/OK";
 211        case 0x01: return "DONE";
 212        case 0x02: return "INTERRUPTED";
 213        case 0x03: return "STOPPED";
 214        case 0x04: return "TERMINATED";
 215        case 0x08: return "ACTIVE";
 216                /* Job exceptions */
 217        case 0x40: return "JOB_CONFIG_FAULT";
 218        case 0x41: return "JOB_POWER_FAULT";
 219        case 0x42: return "JOB_READ_FAULT";
 220        case 0x43: return "JOB_WRITE_FAULT";
 221        case 0x44: return "JOB_AFFINITY_FAULT";
 222        case 0x48: return "JOB_BUS_FAULT";
 223        case 0x50: return "INSTR_INVALID_PC";
 224        case 0x51: return "INSTR_INVALID_ENC";
 225        case 0x52: return "INSTR_TYPE_MISMATCH";
 226        case 0x53: return "INSTR_OPERAND_FAULT";
 227        case 0x54: return "INSTR_TLS_FAULT";
 228        case 0x55: return "INSTR_BARRIER_FAULT";
 229        case 0x56: return "INSTR_ALIGN_FAULT";
 230        case 0x58: return "DATA_INVALID_FAULT";
 231        case 0x59: return "TILE_RANGE_FAULT";
 232        case 0x5A: return "ADDR_RANGE_FAULT";
 233        case 0x60: return "OUT_OF_MEMORY";
 234                /* GPU exceptions */
 235        case 0x80: return "DELAYED_BUS_FAULT";
 236        case 0x88: return "SHAREABILITY_FAULT";
 237                /* MMU exceptions */
 238        case 0xC1: return "TRANSLATION_FAULT_LEVEL1";
 239        case 0xC2: return "TRANSLATION_FAULT_LEVEL2";
 240        case 0xC3: return "TRANSLATION_FAULT_LEVEL3";
 241        case 0xC4: return "TRANSLATION_FAULT_LEVEL4";
 242        case 0xC8: return "PERMISSION_FAULT";
 243        case 0xC9 ... 0xCF: return "PERMISSION_FAULT";
 244        case 0xD1: return "TRANSTAB_BUS_FAULT_LEVEL1";
 245        case 0xD2: return "TRANSTAB_BUS_FAULT_LEVEL2";
 246        case 0xD3: return "TRANSTAB_BUS_FAULT_LEVEL3";
 247        case 0xD4: return "TRANSTAB_BUS_FAULT_LEVEL4";
 248        case 0xD8: return "ACCESS_FLAG";
 249        case 0xD9 ... 0xDF: return "ACCESS_FLAG";
 250        case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT";
 251        case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT";
 252        }
 253
 254        return "UNKNOWN";
 255}
 256
 257#ifdef CONFIG_PM
 258int panfrost_device_resume(struct device *dev)
 259{
 260        struct platform_device *pdev = to_platform_device(dev);
 261        struct panfrost_device *pfdev = platform_get_drvdata(pdev);
 262
 263        panfrost_gpu_soft_reset(pfdev);
 264
 265        /* TODO: Re-enable all other address spaces */
 266        panfrost_gpu_power_on(pfdev);
 267        panfrost_mmu_enable(pfdev, 0);
 268        panfrost_job_enable_interrupts(pfdev);
 269        panfrost_devfreq_resume(pfdev);
 270
 271        return 0;
 272}
 273
 274int panfrost_device_suspend(struct device *dev)
 275{
 276        struct platform_device *pdev = to_platform_device(dev);
 277        struct panfrost_device *pfdev = platform_get_drvdata(pdev);
 278
 279        if (!panfrost_job_is_idle(pfdev))
 280                return -EBUSY;
 281
 282        panfrost_devfreq_suspend(pfdev);
 283        panfrost_gpu_power_off(pfdev);
 284
 285        return 0;
 286}
 287#endif
 288