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_domain.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        pfdev->rstc = devm_reset_control_array_get_optional_exclusive(pfdev->dev);
  22        if (IS_ERR(pfdev->rstc)) {
  23                dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc));
  24                return PTR_ERR(pfdev->rstc);
  25        }
  26
  27        return reset_control_deassert(pfdev->rstc);
  28}
  29
  30static void panfrost_reset_fini(struct panfrost_device *pfdev)
  31{
  32        reset_control_assert(pfdev->rstc);
  33}
  34
  35static int panfrost_clk_init(struct panfrost_device *pfdev)
  36{
  37        int err;
  38        unsigned long rate;
  39
  40        pfdev->clock = devm_clk_get(pfdev->dev, NULL);
  41        if (IS_ERR(pfdev->clock)) {
  42                dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock));
  43                return PTR_ERR(pfdev->clock);
  44        }
  45
  46        rate = clk_get_rate(pfdev->clock);
  47        dev_info(pfdev->dev, "clock rate = %lu\n", rate);
  48
  49        err = clk_prepare_enable(pfdev->clock);
  50        if (err)
  51                return err;
  52
  53        pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus");
  54        if (IS_ERR(pfdev->bus_clock)) {
  55                dev_err(pfdev->dev, "get bus_clock failed %ld\n",
  56                        PTR_ERR(pfdev->bus_clock));
  57                err = PTR_ERR(pfdev->bus_clock);
  58                goto disable_clock;
  59        }
  60
  61        if (pfdev->bus_clock) {
  62                rate = clk_get_rate(pfdev->bus_clock);
  63                dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate);
  64
  65                err = clk_prepare_enable(pfdev->bus_clock);
  66                if (err)
  67                        goto disable_clock;
  68        }
  69
  70        return 0;
  71
  72disable_clock:
  73        clk_disable_unprepare(pfdev->clock);
  74
  75        return err;
  76}
  77
  78static void panfrost_clk_fini(struct panfrost_device *pfdev)
  79{
  80        clk_disable_unprepare(pfdev->bus_clock);
  81        clk_disable_unprepare(pfdev->clock);
  82}
  83
  84static int panfrost_regulator_init(struct panfrost_device *pfdev)
  85{
  86        int ret, i;
  87
  88        pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
  89                                         sizeof(*pfdev->regulators),
  90                                         GFP_KERNEL);
  91        if (!pfdev->regulators)
  92                return -ENOMEM;
  93
  94        for (i = 0; i < pfdev->comp->num_supplies; i++)
  95                pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
  96
  97        ret = devm_regulator_bulk_get(pfdev->dev,
  98                                      pfdev->comp->num_supplies,
  99                                      pfdev->regulators);
 100        if (ret < 0) {
 101                if (ret != -EPROBE_DEFER)
 102                        dev_err(pfdev->dev, "failed to get regulators: %d\n",
 103                                ret);
 104                return ret;
 105        }
 106
 107        ret = regulator_bulk_enable(pfdev->comp->num_supplies,
 108                                    pfdev->regulators);
 109        if (ret < 0) {
 110                dev_err(pfdev->dev, "failed to enable regulators: %d\n", ret);
 111                return ret;
 112        }
 113
 114        return 0;
 115}
 116
 117static void panfrost_regulator_fini(struct panfrost_device *pfdev)
 118{
 119        if (!pfdev->regulators)
 120                return;
 121
 122        regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators);
 123}
 124
 125static void panfrost_pm_domain_fini(struct panfrost_device *pfdev)
 126{
 127        int i;
 128
 129        for (i = 0; i < ARRAY_SIZE(pfdev->pm_domain_devs); i++) {
 130                if (!pfdev->pm_domain_devs[i])
 131                        break;
 132
 133                if (pfdev->pm_domain_links[i])
 134                        device_link_del(pfdev->pm_domain_links[i]);
 135
 136                dev_pm_domain_detach(pfdev->pm_domain_devs[i], true);
 137        }
 138}
 139
 140static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
 141{
 142        int err;
 143        int i, num_domains;
 144
 145        num_domains = of_count_phandle_with_args(pfdev->dev->of_node,
 146                                                 "power-domains",
 147                                                 "#power-domain-cells");
 148
 149        /*
 150         * Single domain is handled by the core, and, if only a single power
 151         * the power domain is requested, the property is optional.
 152         */
 153        if (num_domains < 2 && pfdev->comp->num_pm_domains < 2)
 154                return 0;
 155
 156        if (num_domains != pfdev->comp->num_pm_domains) {
 157                dev_err(pfdev->dev,
 158                        "Incorrect number of power domains: %d provided, %d needed\n",
 159                        num_domains, pfdev->comp->num_pm_domains);
 160                return -EINVAL;
 161        }
 162
 163        if (WARN(num_domains > ARRAY_SIZE(pfdev->pm_domain_devs),
 164                        "Too many supplies in compatible structure.\n"))
 165                return -EINVAL;
 166
 167        for (i = 0; i < num_domains; i++) {
 168                pfdev->pm_domain_devs[i] =
 169                        dev_pm_domain_attach_by_name(pfdev->dev,
 170                                        pfdev->comp->pm_domain_names[i]);
 171                if (IS_ERR_OR_NULL(pfdev->pm_domain_devs[i])) {
 172                        err = PTR_ERR(pfdev->pm_domain_devs[i]) ? : -ENODATA;
 173                        pfdev->pm_domain_devs[i] = NULL;
 174                        dev_err(pfdev->dev,
 175                                "failed to get pm-domain %s(%d): %d\n",
 176                                pfdev->comp->pm_domain_names[i], i, err);
 177                        goto err;
 178                }
 179
 180                pfdev->pm_domain_links[i] = device_link_add(pfdev->dev,
 181                                pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME |
 182                                DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE);
 183                if (!pfdev->pm_domain_links[i]) {
 184                        dev_err(pfdev->pm_domain_devs[i],
 185                                "adding device link failed!\n");
 186                        err = -ENODEV;
 187                        goto err;
 188                }
 189        }
 190
 191        return 0;
 192
 193err:
 194        panfrost_pm_domain_fini(pfdev);
 195        return err;
 196}
 197
 198int panfrost_device_init(struct panfrost_device *pfdev)
 199{
 200        int err;
 201        struct resource *res;
 202
 203        mutex_init(&pfdev->sched_lock);
 204        INIT_LIST_HEAD(&pfdev->scheduled_jobs);
 205        INIT_LIST_HEAD(&pfdev->as_lru_list);
 206
 207        spin_lock_init(&pfdev->as_lock);
 208
 209        err = panfrost_clk_init(pfdev);
 210        if (err) {
 211                dev_err(pfdev->dev, "clk init failed %d\n", err);
 212                return err;
 213        }
 214
 215        err = panfrost_devfreq_init(pfdev);
 216        if (err) {
 217                if (err != -EPROBE_DEFER)
 218                        dev_err(pfdev->dev, "devfreq init failed %d\n", err);
 219                goto out_clk;
 220        }
 221
 222        /* OPP will handle regulators */
 223        if (!pfdev->pfdevfreq.opp_of_table_added) {
 224                err = panfrost_regulator_init(pfdev);
 225                if (err)
 226                        goto out_devfreq;
 227        }
 228
 229        err = panfrost_reset_init(pfdev);
 230        if (err) {
 231                dev_err(pfdev->dev, "reset init failed %d\n", err);
 232                goto out_regulator;
 233        }
 234
 235        err = panfrost_pm_domain_init(pfdev);
 236        if (err)
 237                goto out_reset;
 238
 239        res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0);
 240        pfdev->iomem = devm_ioremap_resource(pfdev->dev, res);
 241        if (IS_ERR(pfdev->iomem)) {
 242                err = PTR_ERR(pfdev->iomem);
 243                goto out_pm_domain;
 244        }
 245
 246        err = panfrost_gpu_init(pfdev);
 247        if (err)
 248                goto out_pm_domain;
 249
 250        err = panfrost_mmu_init(pfdev);
 251        if (err)
 252                goto out_gpu;
 253
 254        err = panfrost_job_init(pfdev);
 255        if (err)
 256                goto out_mmu;
 257
 258        err = panfrost_perfcnt_init(pfdev);
 259        if (err)
 260                goto out_job;
 261
 262        return 0;
 263out_job:
 264        panfrost_job_fini(pfdev);
 265out_mmu:
 266        panfrost_mmu_fini(pfdev);
 267out_gpu:
 268        panfrost_gpu_fini(pfdev);
 269out_pm_domain:
 270        panfrost_pm_domain_fini(pfdev);
 271out_reset:
 272        panfrost_reset_fini(pfdev);
 273out_regulator:
 274        panfrost_regulator_fini(pfdev);
 275out_devfreq:
 276        panfrost_devfreq_fini(pfdev);
 277out_clk:
 278        panfrost_clk_fini(pfdev);
 279        return err;
 280}
 281
 282void panfrost_device_fini(struct panfrost_device *pfdev)
 283{
 284        panfrost_perfcnt_fini(pfdev);
 285        panfrost_job_fini(pfdev);
 286        panfrost_mmu_fini(pfdev);
 287        panfrost_gpu_fini(pfdev);
 288        panfrost_pm_domain_fini(pfdev);
 289        panfrost_reset_fini(pfdev);
 290        panfrost_devfreq_fini(pfdev);
 291        panfrost_regulator_fini(pfdev);
 292        panfrost_clk_fini(pfdev);
 293}
 294
 295#define PANFROST_EXCEPTION(id) \
 296        [DRM_PANFROST_EXCEPTION_ ## id] = { \
 297                .name = #id, \
 298        }
 299
 300struct panfrost_exception_info {
 301        const char *name;
 302};
 303
 304static const struct panfrost_exception_info panfrost_exception_infos[] = {
 305        PANFROST_EXCEPTION(OK),
 306        PANFROST_EXCEPTION(DONE),
 307        PANFROST_EXCEPTION(INTERRUPTED),
 308        PANFROST_EXCEPTION(STOPPED),
 309        PANFROST_EXCEPTION(TERMINATED),
 310        PANFROST_EXCEPTION(KABOOM),
 311        PANFROST_EXCEPTION(EUREKA),
 312        PANFROST_EXCEPTION(ACTIVE),
 313        PANFROST_EXCEPTION(JOB_CONFIG_FAULT),
 314        PANFROST_EXCEPTION(JOB_POWER_FAULT),
 315        PANFROST_EXCEPTION(JOB_READ_FAULT),
 316        PANFROST_EXCEPTION(JOB_WRITE_FAULT),
 317        PANFROST_EXCEPTION(JOB_AFFINITY_FAULT),
 318        PANFROST_EXCEPTION(JOB_BUS_FAULT),
 319        PANFROST_EXCEPTION(INSTR_INVALID_PC),
 320        PANFROST_EXCEPTION(INSTR_INVALID_ENC),
 321        PANFROST_EXCEPTION(INSTR_TYPE_MISMATCH),
 322        PANFROST_EXCEPTION(INSTR_OPERAND_FAULT),
 323        PANFROST_EXCEPTION(INSTR_TLS_FAULT),
 324        PANFROST_EXCEPTION(INSTR_BARRIER_FAULT),
 325        PANFROST_EXCEPTION(INSTR_ALIGN_FAULT),
 326        PANFROST_EXCEPTION(DATA_INVALID_FAULT),
 327        PANFROST_EXCEPTION(TILE_RANGE_FAULT),
 328        PANFROST_EXCEPTION(ADDR_RANGE_FAULT),
 329        PANFROST_EXCEPTION(IMPRECISE_FAULT),
 330        PANFROST_EXCEPTION(OOM),
 331        PANFROST_EXCEPTION(OOM_AFBC),
 332        PANFROST_EXCEPTION(UNKNOWN),
 333        PANFROST_EXCEPTION(DELAYED_BUS_FAULT),
 334        PANFROST_EXCEPTION(GPU_SHAREABILITY_FAULT),
 335        PANFROST_EXCEPTION(SYS_SHAREABILITY_FAULT),
 336        PANFROST_EXCEPTION(GPU_CACHEABILITY_FAULT),
 337        PANFROST_EXCEPTION(TRANSLATION_FAULT_0),
 338        PANFROST_EXCEPTION(TRANSLATION_FAULT_1),
 339        PANFROST_EXCEPTION(TRANSLATION_FAULT_2),
 340        PANFROST_EXCEPTION(TRANSLATION_FAULT_3),
 341        PANFROST_EXCEPTION(TRANSLATION_FAULT_4),
 342        PANFROST_EXCEPTION(TRANSLATION_FAULT_IDENTITY),
 343        PANFROST_EXCEPTION(PERM_FAULT_0),
 344        PANFROST_EXCEPTION(PERM_FAULT_1),
 345        PANFROST_EXCEPTION(PERM_FAULT_2),
 346        PANFROST_EXCEPTION(PERM_FAULT_3),
 347        PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_0),
 348        PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_1),
 349        PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_2),
 350        PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_3),
 351        PANFROST_EXCEPTION(ACCESS_FLAG_0),
 352        PANFROST_EXCEPTION(ACCESS_FLAG_1),
 353        PANFROST_EXCEPTION(ACCESS_FLAG_2),
 354        PANFROST_EXCEPTION(ACCESS_FLAG_3),
 355        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN0),
 356        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN1),
 357        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN2),
 358        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN3),
 359        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT0),
 360        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT1),
 361        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT2),
 362        PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT3),
 363        PANFROST_EXCEPTION(MEM_ATTR_FAULT_0),
 364        PANFROST_EXCEPTION(MEM_ATTR_FAULT_1),
 365        PANFROST_EXCEPTION(MEM_ATTR_FAULT_2),
 366        PANFROST_EXCEPTION(MEM_ATTR_FAULT_3),
 367        PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_0),
 368        PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_1),
 369        PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_2),
 370        PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_3),
 371};
 372
 373const char *panfrost_exception_name(u32 exception_code)
 374{
 375        if (WARN_ON(exception_code >= ARRAY_SIZE(panfrost_exception_infos) ||
 376                    !panfrost_exception_infos[exception_code].name))
 377                return "Unknown exception type";
 378
 379        return panfrost_exception_infos[exception_code].name;
 380}
 381
 382bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
 383                                    u32 exception_code)
 384{
 385        /* Right now, none of the GPU we support need a reset, but this
 386         * might change.
 387         */
 388        return false;
 389}
 390
 391void panfrost_device_reset(struct panfrost_device *pfdev)
 392{
 393        panfrost_gpu_soft_reset(pfdev);
 394
 395        panfrost_gpu_power_on(pfdev);
 396        panfrost_mmu_reset(pfdev);
 397        panfrost_job_enable_interrupts(pfdev);
 398}
 399
 400#ifdef CONFIG_PM
 401int panfrost_device_resume(struct device *dev)
 402{
 403        struct platform_device *pdev = to_platform_device(dev);
 404        struct panfrost_device *pfdev = platform_get_drvdata(pdev);
 405
 406        panfrost_device_reset(pfdev);
 407        panfrost_devfreq_resume(pfdev);
 408
 409        return 0;
 410}
 411
 412int panfrost_device_suspend(struct device *dev)
 413{
 414        struct platform_device *pdev = to_platform_device(dev);
 415        struct panfrost_device *pfdev = platform_get_drvdata(pdev);
 416
 417        if (!panfrost_job_is_idle(pfdev))
 418                return -EBUSY;
 419
 420        panfrost_devfreq_suspend(pfdev);
 421        panfrost_gpu_power_off(pfdev);
 422
 423        return 0;
 424}
 425#endif
 426