linux/drivers/gpu/drm/msm/adreno/adreno_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2013-2014 Red Hat
   4 * Author: Rob Clark <robdclark@gmail.com>
   5 *
   6 * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved.
   7 */
   8
   9#include "adreno_gpu.h"
  10
  11bool hang_debug = false;
  12MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
  13module_param_named(hang_debug, hang_debug, bool, 0600);
  14
  15bool snapshot_debugbus = false;
  16MODULE_PARM_DESC(snapshot_debugbus, "Include debugbus sections in GPU devcoredump (if not fused off)");
  17module_param_named(snapshot_debugbus, snapshot_debugbus, bool, 0600);
  18
  19bool allow_vram_carveout = false;
  20MODULE_PARM_DESC(allow_vram_carveout, "Allow using VRAM Carveout, in place of IOMMU");
  21module_param_named(allow_vram_carveout, allow_vram_carveout, bool, 0600);
  22
  23static const struct adreno_info gpulist[] = {
  24        {
  25                .rev   = ADRENO_REV(2, 0, 0, 0),
  26                .revn  = 200,
  27                .name  = "A200",
  28                .fw = {
  29                        [ADRENO_FW_PM4] = "yamato_pm4.fw",
  30                        [ADRENO_FW_PFP] = "yamato_pfp.fw",
  31                },
  32                .gmem  = SZ_256K,
  33                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  34                .init  = a2xx_gpu_init,
  35        }, { /* a200 on i.mx51 has only 128kib gmem */
  36                .rev   = ADRENO_REV(2, 0, 0, 1),
  37                .revn  = 201,
  38                .name  = "A200",
  39                .fw = {
  40                        [ADRENO_FW_PM4] = "yamato_pm4.fw",
  41                        [ADRENO_FW_PFP] = "yamato_pfp.fw",
  42                },
  43                .gmem  = SZ_128K,
  44                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  45                .init  = a2xx_gpu_init,
  46        }, {
  47                .rev   = ADRENO_REV(2, 2, 0, ANY_ID),
  48                .revn  = 220,
  49                .name  = "A220",
  50                .fw = {
  51                        [ADRENO_FW_PM4] = "leia_pm4_470.fw",
  52                        [ADRENO_FW_PFP] = "leia_pfp_470.fw",
  53                },
  54                .gmem  = SZ_512K,
  55                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  56                .init  = a2xx_gpu_init,
  57        }, {
  58                .rev   = ADRENO_REV(3, 0, 5, ANY_ID),
  59                .revn  = 305,
  60                .name  = "A305",
  61                .fw = {
  62                        [ADRENO_FW_PM4] = "a300_pm4.fw",
  63                        [ADRENO_FW_PFP] = "a300_pfp.fw",
  64                },
  65                .gmem  = SZ_256K,
  66                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  67                .init  = a3xx_gpu_init,
  68        }, {
  69                .rev   = ADRENO_REV(3, 0, 6, 0),
  70                .revn  = 307,        /* because a305c is revn==306 */
  71                .name  = "A306",
  72                .fw = {
  73                        [ADRENO_FW_PM4] = "a300_pm4.fw",
  74                        [ADRENO_FW_PFP] = "a300_pfp.fw",
  75                },
  76                .gmem  = SZ_128K,
  77                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  78                .init  = a3xx_gpu_init,
  79        }, {
  80                .rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
  81                .revn  = 320,
  82                .name  = "A320",
  83                .fw = {
  84                        [ADRENO_FW_PM4] = "a300_pm4.fw",
  85                        [ADRENO_FW_PFP] = "a300_pfp.fw",
  86                },
  87                .gmem  = SZ_512K,
  88                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
  89                .init  = a3xx_gpu_init,
  90        }, {
  91                .rev   = ADRENO_REV(3, 3, 0, ANY_ID),
  92                .revn  = 330,
  93                .name  = "A330",
  94                .fw = {
  95                        [ADRENO_FW_PM4] = "a330_pm4.fw",
  96                        [ADRENO_FW_PFP] = "a330_pfp.fw",
  97                },
  98                .gmem  = SZ_1M,
  99                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 100                .init  = a3xx_gpu_init,
 101        }, {
 102                .rev   = ADRENO_REV(4, 0, 5, ANY_ID),
 103                .revn  = 405,
 104                .name  = "A405",
 105                .fw = {
 106                        [ADRENO_FW_PM4] = "a420_pm4.fw",
 107                        [ADRENO_FW_PFP] = "a420_pfp.fw",
 108                },
 109                .gmem  = SZ_256K,
 110                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 111                .init  = a4xx_gpu_init,
 112        }, {
 113                .rev   = ADRENO_REV(4, 2, 0, ANY_ID),
 114                .revn  = 420,
 115                .name  = "A420",
 116                .fw = {
 117                        [ADRENO_FW_PM4] = "a420_pm4.fw",
 118                        [ADRENO_FW_PFP] = "a420_pfp.fw",
 119                },
 120                .gmem  = (SZ_1M + SZ_512K),
 121                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 122                .init  = a4xx_gpu_init,
 123        }, {
 124                .rev   = ADRENO_REV(4, 3, 0, ANY_ID),
 125                .revn  = 430,
 126                .name  = "A430",
 127                .fw = {
 128                        [ADRENO_FW_PM4] = "a420_pm4.fw",
 129                        [ADRENO_FW_PFP] = "a420_pfp.fw",
 130                },
 131                .gmem  = (SZ_1M + SZ_512K),
 132                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 133                .init  = a4xx_gpu_init,
 134        }, {
 135                .rev   = ADRENO_REV(5, 0, 6, ANY_ID),
 136                .revn = 506,
 137                .name = "A506",
 138                .fw = {
 139                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 140                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 141                },
 142                .gmem = (SZ_128K + SZ_8K),
 143                /*
 144                 * Increase inactive period to 250 to avoid bouncing
 145                 * the GDSC which appears to make it grumpy
 146                 */
 147                .inactive_period = 250,
 148                .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI |
 149                          ADRENO_QUIRK_LMLOADKILL_DISABLE,
 150                .init = a5xx_gpu_init,
 151                .zapfw = "a506_zap.mdt",
 152        }, {
 153                .rev   = ADRENO_REV(5, 0, 8, ANY_ID),
 154                .revn = 508,
 155                .name = "A508",
 156                .fw = {
 157                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 158                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 159                },
 160                .gmem = (SZ_128K + SZ_8K),
 161                /*
 162                 * Increase inactive period to 250 to avoid bouncing
 163                 * the GDSC which appears to make it grumpy
 164                 */
 165                .inactive_period = 250,
 166                .quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
 167                .init = a5xx_gpu_init,
 168                .zapfw = "a508_zap.mdt",
 169        }, {
 170                .rev   = ADRENO_REV(5, 0, 9, ANY_ID),
 171                .revn = 509,
 172                .name = "A509",
 173                .fw = {
 174                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 175                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 176                },
 177                .gmem = (SZ_256K + SZ_16K),
 178                /*
 179                 * Increase inactive period to 250 to avoid bouncing
 180                 * the GDSC which appears to make it grumpy
 181                 */
 182                .inactive_period = 250,
 183                .quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
 184                .init = a5xx_gpu_init,
 185                /* Adreno 509 uses the same ZAP as 512 */
 186                .zapfw = "a512_zap.mdt",
 187        }, {
 188                .rev   = ADRENO_REV(5, 1, 0, ANY_ID),
 189                .revn = 510,
 190                .name = "A510",
 191                .fw = {
 192                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 193                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 194                },
 195                .gmem = SZ_256K,
 196                /*
 197                 * Increase inactive period to 250 to avoid bouncing
 198                 * the GDSC which appears to make it grumpy
 199                 */
 200                .inactive_period = 250,
 201                .init = a5xx_gpu_init,
 202        }, {
 203                .rev   = ADRENO_REV(5, 1, 2, ANY_ID),
 204                .revn = 512,
 205                .name = "A512",
 206                .fw = {
 207                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 208                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 209                },
 210                .gmem = (SZ_256K + SZ_16K),
 211                /*
 212                 * Increase inactive period to 250 to avoid bouncing
 213                 * the GDSC which appears to make it grumpy
 214                 */
 215                .inactive_period = 250,
 216                .quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
 217                .init = a5xx_gpu_init,
 218                .zapfw = "a512_zap.mdt",
 219        }, {
 220                .rev = ADRENO_REV(5, 3, 0, 2),
 221                .revn = 530,
 222                .name = "A530",
 223                .fw = {
 224                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 225                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 226                        [ADRENO_FW_GPMU] = "a530v3_gpmu.fw2",
 227                },
 228                .gmem = SZ_1M,
 229                /*
 230                 * Increase inactive period to 250 to avoid bouncing
 231                 * the GDSC which appears to make it grumpy
 232                 */
 233                .inactive_period = 250,
 234                .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI |
 235                        ADRENO_QUIRK_FAULT_DETECT_MASK,
 236                .init = a5xx_gpu_init,
 237                .zapfw = "a530_zap.mdt",
 238        }, {
 239                .rev = ADRENO_REV(5, 4, 0, ANY_ID),
 240                .revn = 540,
 241                .name = "A540",
 242                .fw = {
 243                        [ADRENO_FW_PM4] = "a530_pm4.fw",
 244                        [ADRENO_FW_PFP] = "a530_pfp.fw",
 245                        [ADRENO_FW_GPMU] = "a540_gpmu.fw2",
 246                },
 247                .gmem = SZ_1M,
 248                /*
 249                 * Increase inactive period to 250 to avoid bouncing
 250                 * the GDSC which appears to make it grumpy
 251                 */
 252                .inactive_period = 250,
 253                .quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
 254                .init = a5xx_gpu_init,
 255                .zapfw = "a540_zap.mdt",
 256        }, {
 257                .rev = ADRENO_REV(6, 1, 8, ANY_ID),
 258                .revn = 618,
 259                .name = "A618",
 260                .fw = {
 261                        [ADRENO_FW_SQE] = "a630_sqe.fw",
 262                        [ADRENO_FW_GMU] = "a630_gmu.bin",
 263                },
 264                .gmem = SZ_512K,
 265                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 266                .init = a6xx_gpu_init,
 267        }, {
 268                .rev = ADRENO_REV(6, 3, 0, ANY_ID),
 269                .revn = 630,
 270                .name = "A630",
 271                .fw = {
 272                        [ADRENO_FW_SQE] = "a630_sqe.fw",
 273                        [ADRENO_FW_GMU] = "a630_gmu.bin",
 274                },
 275                .gmem = SZ_1M,
 276                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 277                .init = a6xx_gpu_init,
 278                .zapfw = "a630_zap.mdt",
 279                .hwcg = a630_hwcg,
 280        }, {
 281                .rev = ADRENO_REV(6, 4, 0, ANY_ID),
 282                .revn = 640,
 283                .name = "A640",
 284                .fw = {
 285                        [ADRENO_FW_SQE] = "a630_sqe.fw",
 286                        [ADRENO_FW_GMU] = "a640_gmu.bin",
 287                },
 288                .gmem = SZ_1M,
 289                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 290                .init = a6xx_gpu_init,
 291                .zapfw = "a640_zap.mdt",
 292                .hwcg = a640_hwcg,
 293        }, {
 294                .rev = ADRENO_REV(6, 5, 0, ANY_ID),
 295                .revn = 650,
 296                .name = "A650",
 297                .fw = {
 298                        [ADRENO_FW_SQE] = "a650_sqe.fw",
 299                        [ADRENO_FW_GMU] = "a650_gmu.bin",
 300                },
 301                .gmem = SZ_1M + SZ_128K,
 302                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 303                .init = a6xx_gpu_init,
 304                .zapfw = "a650_zap.mdt",
 305                .hwcg = a650_hwcg,
 306        }, {
 307                .rev = ADRENO_REV(6, 6, 0, ANY_ID),
 308                .revn = 660,
 309                .name = "A660",
 310                .fw = {
 311                        [ADRENO_FW_SQE] = "a660_sqe.fw",
 312                        [ADRENO_FW_GMU] = "a660_gmu.bin",
 313                },
 314                .gmem = SZ_1M + SZ_512K,
 315                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 316                .init = a6xx_gpu_init,
 317                .zapfw = "a660_zap.mdt",
 318                .hwcg = a660_hwcg,
 319        }, {
 320                .rev = ADRENO_REV(6, 3, 5, ANY_ID),
 321                .fw = {
 322                        [ADRENO_FW_SQE] = "a660_sqe.fw",
 323                        [ADRENO_FW_GMU] = "a660_gmu.bin",
 324                },
 325                .gmem = SZ_512K,
 326                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 327                .init = a6xx_gpu_init,
 328                .hwcg = a660_hwcg,
 329        }, {
 330                .rev = ADRENO_REV(6, 8, 0, ANY_ID),
 331                .revn = 680,
 332                .name = "A680",
 333                .fw = {
 334                        [ADRENO_FW_SQE] = "a630_sqe.fw",
 335                        [ADRENO_FW_GMU] = "a640_gmu.bin",
 336                },
 337                .gmem = SZ_2M,
 338                .inactive_period = DRM_MSM_INACTIVE_PERIOD,
 339                .init = a6xx_gpu_init,
 340                .zapfw = "a640_zap.mdt",
 341                .hwcg = a640_hwcg,
 342        },
 343};
 344
 345MODULE_FIRMWARE("qcom/a300_pm4.fw");
 346MODULE_FIRMWARE("qcom/a300_pfp.fw");
 347MODULE_FIRMWARE("qcom/a330_pm4.fw");
 348MODULE_FIRMWARE("qcom/a330_pfp.fw");
 349MODULE_FIRMWARE("qcom/a420_pm4.fw");
 350MODULE_FIRMWARE("qcom/a420_pfp.fw");
 351MODULE_FIRMWARE("qcom/a530_pm4.fw");
 352MODULE_FIRMWARE("qcom/a530_pfp.fw");
 353MODULE_FIRMWARE("qcom/a530v3_gpmu.fw2");
 354MODULE_FIRMWARE("qcom/a530_zap.mdt");
 355MODULE_FIRMWARE("qcom/a530_zap.b00");
 356MODULE_FIRMWARE("qcom/a530_zap.b01");
 357MODULE_FIRMWARE("qcom/a530_zap.b02");
 358MODULE_FIRMWARE("qcom/a630_sqe.fw");
 359MODULE_FIRMWARE("qcom/a630_gmu.bin");
 360MODULE_FIRMWARE("qcom/a630_zap.mbn");
 361
 362static inline bool _rev_match(uint8_t entry, uint8_t id)
 363{
 364        return (entry == ANY_ID) || (entry == id);
 365}
 366
 367bool adreno_cmp_rev(struct adreno_rev rev1, struct adreno_rev rev2)
 368{
 369
 370        return _rev_match(rev1.core, rev2.core) &&
 371                _rev_match(rev1.major, rev2.major) &&
 372                _rev_match(rev1.minor, rev2.minor) &&
 373                _rev_match(rev1.patchid, rev2.patchid);
 374}
 375
 376const struct adreno_info *adreno_info(struct adreno_rev rev)
 377{
 378        int i;
 379
 380        /* identify gpu: */
 381        for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
 382                const struct adreno_info *info = &gpulist[i];
 383                if (adreno_cmp_rev(info->rev, rev))
 384                        return info;
 385        }
 386
 387        return NULL;
 388}
 389
 390struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
 391{
 392        struct msm_drm_private *priv = dev->dev_private;
 393        struct platform_device *pdev = priv->gpu_pdev;
 394        struct msm_gpu *gpu = NULL;
 395        struct adreno_gpu *adreno_gpu;
 396        int ret;
 397
 398        if (pdev)
 399                gpu = dev_to_gpu(&pdev->dev);
 400
 401        if (!gpu) {
 402                dev_err_once(dev->dev, "no GPU device was found\n");
 403                return NULL;
 404        }
 405
 406        adreno_gpu = to_adreno_gpu(gpu);
 407
 408        /*
 409         * The number one reason for HW init to fail is if the firmware isn't
 410         * loaded yet. Try that first and don't bother continuing on
 411         * otherwise
 412         */
 413
 414        ret = adreno_load_fw(adreno_gpu);
 415        if (ret)
 416                return NULL;
 417
 418        /* Make sure pm runtime is active and reset any previous errors */
 419        pm_runtime_set_active(&pdev->dev);
 420
 421        ret = pm_runtime_get_sync(&pdev->dev);
 422        if (ret < 0) {
 423                pm_runtime_put_sync(&pdev->dev);
 424                DRM_DEV_ERROR(dev->dev, "Couldn't power up the GPU: %d\n", ret);
 425                return NULL;
 426        }
 427
 428        mutex_lock(&gpu->lock);
 429        ret = msm_gpu_hw_init(gpu);
 430        mutex_unlock(&gpu->lock);
 431        pm_runtime_put_autosuspend(&pdev->dev);
 432        if (ret) {
 433                DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
 434                return NULL;
 435        }
 436
 437#ifdef CONFIG_DEBUG_FS
 438        if (gpu->funcs->debugfs_init) {
 439                gpu->funcs->debugfs_init(gpu, dev->primary);
 440                gpu->funcs->debugfs_init(gpu, dev->render);
 441        }
 442#endif
 443
 444        return gpu;
 445}
 446
 447static int find_chipid(struct device *dev, struct adreno_rev *rev)
 448{
 449        struct device_node *node = dev->of_node;
 450        const char *compat;
 451        int ret;
 452        u32 chipid;
 453
 454        /* first search the compat strings for qcom,adreno-XYZ.W: */
 455        ret = of_property_read_string_index(node, "compatible", 0, &compat);
 456        if (ret == 0) {
 457                unsigned int r, patch;
 458
 459                if (sscanf(compat, "qcom,adreno-%u.%u", &r, &patch) == 2 ||
 460                    sscanf(compat, "amd,imageon-%u.%u", &r, &patch) == 2) {
 461                        rev->core = r / 100;
 462                        r %= 100;
 463                        rev->major = r / 10;
 464                        r %= 10;
 465                        rev->minor = r;
 466                        rev->patchid = patch;
 467
 468                        return 0;
 469                }
 470        }
 471
 472        /* and if that fails, fall back to legacy "qcom,chipid" property: */
 473        ret = of_property_read_u32(node, "qcom,chipid", &chipid);
 474        if (ret) {
 475                DRM_DEV_ERROR(dev, "could not parse qcom,chipid: %d\n", ret);
 476                return ret;
 477        }
 478
 479        rev->core = (chipid >> 24) & 0xff;
 480        rev->major = (chipid >> 16) & 0xff;
 481        rev->minor = (chipid >> 8) & 0xff;
 482        rev->patchid = (chipid & 0xff);
 483
 484        dev_warn(dev, "Using legacy qcom,chipid binding!\n");
 485        dev_warn(dev, "Use compatible qcom,adreno-%u%u%u.%u instead.\n",
 486                rev->core, rev->major, rev->minor, rev->patchid);
 487
 488        return 0;
 489}
 490
 491static int adreno_bind(struct device *dev, struct device *master, void *data)
 492{
 493        static struct adreno_platform_config config = {};
 494        const struct adreno_info *info;
 495        struct msm_drm_private *priv = dev_get_drvdata(master);
 496        struct drm_device *drm = priv->dev;
 497        struct msm_gpu *gpu;
 498        int ret;
 499
 500        ret = find_chipid(dev, &config.rev);
 501        if (ret)
 502                return ret;
 503
 504        dev->platform_data = &config;
 505        priv->gpu_pdev = to_platform_device(dev);
 506
 507        info = adreno_info(config.rev);
 508
 509        if (!info) {
 510                dev_warn(drm->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
 511                        config.rev.core, config.rev.major,
 512                        config.rev.minor, config.rev.patchid);
 513                return -ENXIO;
 514        }
 515
 516        DBG("Found GPU: %u.%u.%u.%u", config.rev.core, config.rev.major,
 517                config.rev.minor, config.rev.patchid);
 518
 519        priv->is_a2xx = config.rev.core == 2;
 520        priv->has_cached_coherent = config.rev.core >= 6;
 521
 522        gpu = info->init(drm);
 523        if (IS_ERR(gpu)) {
 524                dev_warn(drm->dev, "failed to load adreno gpu\n");
 525                return PTR_ERR(gpu);
 526        }
 527
 528        return 0;
 529}
 530
 531static void adreno_unbind(struct device *dev, struct device *master,
 532                void *data)
 533{
 534        struct msm_drm_private *priv = dev_get_drvdata(master);
 535        struct msm_gpu *gpu = dev_to_gpu(dev);
 536
 537        pm_runtime_force_suspend(dev);
 538        gpu->funcs->destroy(gpu);
 539
 540        priv->gpu_pdev = NULL;
 541}
 542
 543static const struct component_ops a3xx_ops = {
 544                .bind   = adreno_bind,
 545                .unbind = adreno_unbind,
 546};
 547
 548static void adreno_device_register_headless(void)
 549{
 550        /* on imx5, we don't have a top-level mdp/dpu node
 551         * this creates a dummy node for the driver for that case
 552         */
 553        struct platform_device_info dummy_info = {
 554                .parent = NULL,
 555                .name = "msm",
 556                .id = -1,
 557                .res = NULL,
 558                .num_res = 0,
 559                .data = NULL,
 560                .size_data = 0,
 561                .dma_mask = ~0,
 562        };
 563        platform_device_register_full(&dummy_info);
 564}
 565
 566static int adreno_probe(struct platform_device *pdev)
 567{
 568
 569        int ret;
 570
 571        ret = component_add(&pdev->dev, &a3xx_ops);
 572        if (ret)
 573                return ret;
 574
 575        if (of_device_is_compatible(pdev->dev.of_node, "amd,imageon"))
 576                adreno_device_register_headless();
 577
 578        return 0;
 579}
 580
 581static int adreno_remove(struct platform_device *pdev)
 582{
 583        component_del(&pdev->dev, &a3xx_ops);
 584        return 0;
 585}
 586
 587static void adreno_shutdown(struct platform_device *pdev)
 588{
 589        pm_runtime_force_suspend(&pdev->dev);
 590}
 591
 592static const struct of_device_id dt_match[] = {
 593        { .compatible = "qcom,adreno" },
 594        { .compatible = "qcom,adreno-3xx" },
 595        /* for compatibility with imx5 gpu: */
 596        { .compatible = "amd,imageon" },
 597        /* for backwards compat w/ downstream kgsl DT files: */
 598        { .compatible = "qcom,kgsl-3d0" },
 599        {}
 600};
 601
 602static int adreno_runtime_resume(struct device *dev)
 603{
 604        struct msm_gpu *gpu = dev_to_gpu(dev);
 605
 606        return gpu->funcs->pm_resume(gpu);
 607}
 608
 609static int adreno_runtime_suspend(struct device *dev)
 610{
 611        struct msm_gpu *gpu = dev_to_gpu(dev);
 612
 613        /*
 614         * We should be holding a runpm ref, which will prevent
 615         * runtime suspend.  In the system suspend path, we've
 616         * already waited for active jobs to complete.
 617         */
 618        WARN_ON_ONCE(gpu->active_submits);
 619
 620        return gpu->funcs->pm_suspend(gpu);
 621}
 622
 623static void suspend_scheduler(struct msm_gpu *gpu)
 624{
 625        int i;
 626
 627        /*
 628         * Shut down the scheduler before we force suspend, so that
 629         * suspend isn't racing with scheduler kthread feeding us
 630         * more work.
 631         *
 632         * Note, we just want to park the thread, and let any jobs
 633         * that are already on the hw queue complete normally, as
 634         * opposed to the drm_sched_stop() path used for handling
 635         * faulting/timed-out jobs.  We can't really cancel any jobs
 636         * already on the hw queue without racing with the GPU.
 637         */
 638        for (i = 0; i < gpu->nr_rings; i++) {
 639                struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched;
 640                kthread_park(sched->thread);
 641        }
 642}
 643
 644static void resume_scheduler(struct msm_gpu *gpu)
 645{
 646        int i;
 647
 648        for (i = 0; i < gpu->nr_rings; i++) {
 649                struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched;
 650                kthread_unpark(sched->thread);
 651        }
 652}
 653
 654static int adreno_system_suspend(struct device *dev)
 655{
 656        struct msm_gpu *gpu = dev_to_gpu(dev);
 657        int remaining, ret;
 658
 659        suspend_scheduler(gpu);
 660
 661        remaining = wait_event_timeout(gpu->retire_event,
 662                                       gpu->active_submits == 0,
 663                                       msecs_to_jiffies(1000));
 664        if (remaining == 0) {
 665                dev_err(dev, "Timeout waiting for GPU to suspend\n");
 666                ret = -EBUSY;
 667                goto out;
 668        }
 669
 670        ret = pm_runtime_force_suspend(dev);
 671out:
 672        if (ret)
 673                resume_scheduler(gpu);
 674
 675        return ret;
 676}
 677
 678static int adreno_system_resume(struct device *dev)
 679{
 680        resume_scheduler(dev_to_gpu(dev));
 681        return pm_runtime_force_resume(dev);
 682}
 683
 684static const struct dev_pm_ops adreno_pm_ops = {
 685        SYSTEM_SLEEP_PM_OPS(adreno_system_suspend, adreno_system_resume)
 686        RUNTIME_PM_OPS(adreno_runtime_suspend, adreno_runtime_resume, NULL)
 687};
 688
 689static struct platform_driver adreno_driver = {
 690        .probe = adreno_probe,
 691        .remove = adreno_remove,
 692        .shutdown = adreno_shutdown,
 693        .driver = {
 694                .name = "adreno",
 695                .of_match_table = dt_match,
 696                .pm = &adreno_pm_ops,
 697        },
 698};
 699
 700void __init adreno_register(void)
 701{
 702        platform_driver_register(&adreno_driver);
 703}
 704
 705void __exit adreno_unregister(void)
 706{
 707        platform_driver_unregister(&adreno_driver);
 708}
 709