cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adreno_device.c (17306B)


      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}