18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2013-2014 Red Hat
48c2ecf20Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (c) 2014,2017 The Linux Foundation. All rights reserved.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "adreno_gpu.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define ANY_ID 0xff
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cibool hang_debug = false;
148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
158c2ecf20Sopenharmony_cimodule_param_named(hang_debug, hang_debug, bool, 0600);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cibool snapshot_debugbus = false;
188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(snapshot_debugbus, "Include debugbus sections in GPU devcoredump (if not fused off)");
198c2ecf20Sopenharmony_cimodule_param_named(snapshot_debugbus, snapshot_debugbus, bool, 0600);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const struct adreno_info gpulist[] = {
228c2ecf20Sopenharmony_ci	{
238c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(2, 0, 0, 0),
248c2ecf20Sopenharmony_ci		.revn  = 200,
258c2ecf20Sopenharmony_ci		.name  = "A200",
268c2ecf20Sopenharmony_ci		.fw = {
278c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "yamato_pm4.fw",
288c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "yamato_pfp.fw",
298c2ecf20Sopenharmony_ci		},
308c2ecf20Sopenharmony_ci		.gmem  = SZ_256K,
318c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
328c2ecf20Sopenharmony_ci		.init  = a2xx_gpu_init,
338c2ecf20Sopenharmony_ci	}, { /* a200 on i.mx51 has only 128kib gmem */
348c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(2, 0, 0, 1),
358c2ecf20Sopenharmony_ci		.revn  = 201,
368c2ecf20Sopenharmony_ci		.name  = "A200",
378c2ecf20Sopenharmony_ci		.fw = {
388c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "yamato_pm4.fw",
398c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "yamato_pfp.fw",
408c2ecf20Sopenharmony_ci		},
418c2ecf20Sopenharmony_ci		.gmem  = SZ_128K,
428c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
438c2ecf20Sopenharmony_ci		.init  = a2xx_gpu_init,
448c2ecf20Sopenharmony_ci	}, {
458c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(2, 2, 0, ANY_ID),
468c2ecf20Sopenharmony_ci		.revn  = 220,
478c2ecf20Sopenharmony_ci		.name  = "A220",
488c2ecf20Sopenharmony_ci		.fw = {
498c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "leia_pm4_470.fw",
508c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "leia_pfp_470.fw",
518c2ecf20Sopenharmony_ci		},
528c2ecf20Sopenharmony_ci		.gmem  = SZ_512K,
538c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
548c2ecf20Sopenharmony_ci		.init  = a2xx_gpu_init,
558c2ecf20Sopenharmony_ci	}, {
568c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(3, 0, 5, ANY_ID),
578c2ecf20Sopenharmony_ci		.revn  = 305,
588c2ecf20Sopenharmony_ci		.name  = "A305",
598c2ecf20Sopenharmony_ci		.fw = {
608c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a300_pm4.fw",
618c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a300_pfp.fw",
628c2ecf20Sopenharmony_ci		},
638c2ecf20Sopenharmony_ci		.gmem  = SZ_256K,
648c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
658c2ecf20Sopenharmony_ci		.init  = a3xx_gpu_init,
668c2ecf20Sopenharmony_ci	}, {
678c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(3, 0, 6, 0),
688c2ecf20Sopenharmony_ci		.revn  = 307,        /* because a305c is revn==306 */
698c2ecf20Sopenharmony_ci		.name  = "A306",
708c2ecf20Sopenharmony_ci		.fw = {
718c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a300_pm4.fw",
728c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a300_pfp.fw",
738c2ecf20Sopenharmony_ci		},
748c2ecf20Sopenharmony_ci		.gmem  = SZ_128K,
758c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
768c2ecf20Sopenharmony_ci		.init  = a3xx_gpu_init,
778c2ecf20Sopenharmony_ci	}, {
788c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
798c2ecf20Sopenharmony_ci		.revn  = 320,
808c2ecf20Sopenharmony_ci		.name  = "A320",
818c2ecf20Sopenharmony_ci		.fw = {
828c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a300_pm4.fw",
838c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a300_pfp.fw",
848c2ecf20Sopenharmony_ci		},
858c2ecf20Sopenharmony_ci		.gmem  = SZ_512K,
868c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
878c2ecf20Sopenharmony_ci		.init  = a3xx_gpu_init,
888c2ecf20Sopenharmony_ci	}, {
898c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(3, 3, 0, ANY_ID),
908c2ecf20Sopenharmony_ci		.revn  = 330,
918c2ecf20Sopenharmony_ci		.name  = "A330",
928c2ecf20Sopenharmony_ci		.fw = {
938c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a330_pm4.fw",
948c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a330_pfp.fw",
958c2ecf20Sopenharmony_ci		},
968c2ecf20Sopenharmony_ci		.gmem  = SZ_1M,
978c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
988c2ecf20Sopenharmony_ci		.init  = a3xx_gpu_init,
998c2ecf20Sopenharmony_ci	}, {
1008c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(4, 0, 5, ANY_ID),
1018c2ecf20Sopenharmony_ci		.revn  = 405,
1028c2ecf20Sopenharmony_ci		.name  = "A405",
1038c2ecf20Sopenharmony_ci		.fw = {
1048c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a420_pm4.fw",
1058c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a420_pfp.fw",
1068c2ecf20Sopenharmony_ci		},
1078c2ecf20Sopenharmony_ci		.gmem  = SZ_256K,
1088c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
1098c2ecf20Sopenharmony_ci		.init  = a4xx_gpu_init,
1108c2ecf20Sopenharmony_ci	}, {
1118c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(4, 2, 0, ANY_ID),
1128c2ecf20Sopenharmony_ci		.revn  = 420,
1138c2ecf20Sopenharmony_ci		.name  = "A420",
1148c2ecf20Sopenharmony_ci		.fw = {
1158c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a420_pm4.fw",
1168c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a420_pfp.fw",
1178c2ecf20Sopenharmony_ci		},
1188c2ecf20Sopenharmony_ci		.gmem  = (SZ_1M + SZ_512K),
1198c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
1208c2ecf20Sopenharmony_ci		.init  = a4xx_gpu_init,
1218c2ecf20Sopenharmony_ci	}, {
1228c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(4, 3, 0, ANY_ID),
1238c2ecf20Sopenharmony_ci		.revn  = 430,
1248c2ecf20Sopenharmony_ci		.name  = "A430",
1258c2ecf20Sopenharmony_ci		.fw = {
1268c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a420_pm4.fw",
1278c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a420_pfp.fw",
1288c2ecf20Sopenharmony_ci		},
1298c2ecf20Sopenharmony_ci		.gmem  = (SZ_1M + SZ_512K),
1308c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
1318c2ecf20Sopenharmony_ci		.init  = a4xx_gpu_init,
1328c2ecf20Sopenharmony_ci	}, {
1338c2ecf20Sopenharmony_ci		.rev   = ADRENO_REV(5, 1, 0, ANY_ID),
1348c2ecf20Sopenharmony_ci		.revn = 510,
1358c2ecf20Sopenharmony_ci		.name = "A510",
1368c2ecf20Sopenharmony_ci		.fw = {
1378c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a530_pm4.fw",
1388c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a530_pfp.fw",
1398c2ecf20Sopenharmony_ci		},
1408c2ecf20Sopenharmony_ci		.gmem = SZ_256K,
1418c2ecf20Sopenharmony_ci		/*
1428c2ecf20Sopenharmony_ci		 * Increase inactive period to 250 to avoid bouncing
1438c2ecf20Sopenharmony_ci		 * the GDSC which appears to make it grumpy
1448c2ecf20Sopenharmony_ci		 */
1458c2ecf20Sopenharmony_ci		.inactive_period = 250,
1468c2ecf20Sopenharmony_ci		.init = a5xx_gpu_init,
1478c2ecf20Sopenharmony_ci	}, {
1488c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(5, 3, 0, 2),
1498c2ecf20Sopenharmony_ci		.revn = 530,
1508c2ecf20Sopenharmony_ci		.name = "A530",
1518c2ecf20Sopenharmony_ci		.fw = {
1528c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a530_pm4.fw",
1538c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a530_pfp.fw",
1548c2ecf20Sopenharmony_ci			[ADRENO_FW_GPMU] = "a530v3_gpmu.fw2",
1558c2ecf20Sopenharmony_ci		},
1568c2ecf20Sopenharmony_ci		.gmem = SZ_1M,
1578c2ecf20Sopenharmony_ci		/*
1588c2ecf20Sopenharmony_ci		 * Increase inactive period to 250 to avoid bouncing
1598c2ecf20Sopenharmony_ci		 * the GDSC which appears to make it grumpy
1608c2ecf20Sopenharmony_ci		 */
1618c2ecf20Sopenharmony_ci		.inactive_period = 250,
1628c2ecf20Sopenharmony_ci		.quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI |
1638c2ecf20Sopenharmony_ci			ADRENO_QUIRK_FAULT_DETECT_MASK,
1648c2ecf20Sopenharmony_ci		.init = a5xx_gpu_init,
1658c2ecf20Sopenharmony_ci		.zapfw = "a530_zap.mdt",
1668c2ecf20Sopenharmony_ci	}, {
1678c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(5, 4, 0, 2),
1688c2ecf20Sopenharmony_ci		.revn = 540,
1698c2ecf20Sopenharmony_ci		.name = "A540",
1708c2ecf20Sopenharmony_ci		.fw = {
1718c2ecf20Sopenharmony_ci			[ADRENO_FW_PM4] = "a530_pm4.fw",
1728c2ecf20Sopenharmony_ci			[ADRENO_FW_PFP] = "a530_pfp.fw",
1738c2ecf20Sopenharmony_ci			[ADRENO_FW_GPMU] = "a540_gpmu.fw2",
1748c2ecf20Sopenharmony_ci		},
1758c2ecf20Sopenharmony_ci		.gmem = SZ_1M,
1768c2ecf20Sopenharmony_ci		/*
1778c2ecf20Sopenharmony_ci		 * Increase inactive period to 250 to avoid bouncing
1788c2ecf20Sopenharmony_ci		 * the GDSC which appears to make it grumpy
1798c2ecf20Sopenharmony_ci		 */
1808c2ecf20Sopenharmony_ci		.inactive_period = 250,
1818c2ecf20Sopenharmony_ci		.quirks = ADRENO_QUIRK_LMLOADKILL_DISABLE,
1828c2ecf20Sopenharmony_ci		.init = a5xx_gpu_init,
1838c2ecf20Sopenharmony_ci		.zapfw = "a540_zap.mdt",
1848c2ecf20Sopenharmony_ci	}, {
1858c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(6, 1, 8, ANY_ID),
1868c2ecf20Sopenharmony_ci		.revn = 618,
1878c2ecf20Sopenharmony_ci		.name = "A618",
1888c2ecf20Sopenharmony_ci		.fw = {
1898c2ecf20Sopenharmony_ci			[ADRENO_FW_SQE] = "a630_sqe.fw",
1908c2ecf20Sopenharmony_ci			[ADRENO_FW_GMU] = "a630_gmu.bin",
1918c2ecf20Sopenharmony_ci		},
1928c2ecf20Sopenharmony_ci		.gmem = SZ_512K,
1938c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
1948c2ecf20Sopenharmony_ci		.init = a6xx_gpu_init,
1958c2ecf20Sopenharmony_ci	}, {
1968c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(6, 3, 0, ANY_ID),
1978c2ecf20Sopenharmony_ci		.revn = 630,
1988c2ecf20Sopenharmony_ci		.name = "A630",
1998c2ecf20Sopenharmony_ci		.fw = {
2008c2ecf20Sopenharmony_ci			[ADRENO_FW_SQE] = "a630_sqe.fw",
2018c2ecf20Sopenharmony_ci			[ADRENO_FW_GMU] = "a630_gmu.bin",
2028c2ecf20Sopenharmony_ci		},
2038c2ecf20Sopenharmony_ci		.gmem = SZ_1M,
2048c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
2058c2ecf20Sopenharmony_ci		.init = a6xx_gpu_init,
2068c2ecf20Sopenharmony_ci		.zapfw = "a630_zap.mdt",
2078c2ecf20Sopenharmony_ci		.hwcg = a630_hwcg,
2088c2ecf20Sopenharmony_ci	}, {
2098c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(6, 4, 0, ANY_ID),
2108c2ecf20Sopenharmony_ci		.revn = 640,
2118c2ecf20Sopenharmony_ci		.name = "A640",
2128c2ecf20Sopenharmony_ci		.fw = {
2138c2ecf20Sopenharmony_ci			[ADRENO_FW_SQE] = "a630_sqe.fw",
2148c2ecf20Sopenharmony_ci			[ADRENO_FW_GMU] = "a640_gmu.bin",
2158c2ecf20Sopenharmony_ci		},
2168c2ecf20Sopenharmony_ci		.gmem = SZ_1M,
2178c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
2188c2ecf20Sopenharmony_ci		.init = a6xx_gpu_init,
2198c2ecf20Sopenharmony_ci		.zapfw = "a640_zap.mdt",
2208c2ecf20Sopenharmony_ci		.hwcg = a640_hwcg,
2218c2ecf20Sopenharmony_ci	}, {
2228c2ecf20Sopenharmony_ci		.rev = ADRENO_REV(6, 5, 0, ANY_ID),
2238c2ecf20Sopenharmony_ci		.revn = 650,
2248c2ecf20Sopenharmony_ci		.name = "A650",
2258c2ecf20Sopenharmony_ci		.fw = {
2268c2ecf20Sopenharmony_ci			[ADRENO_FW_SQE] = "a650_sqe.fw",
2278c2ecf20Sopenharmony_ci			[ADRENO_FW_GMU] = "a650_gmu.bin",
2288c2ecf20Sopenharmony_ci		},
2298c2ecf20Sopenharmony_ci		.gmem = SZ_1M + SZ_128K,
2308c2ecf20Sopenharmony_ci		.inactive_period = DRM_MSM_INACTIVE_PERIOD,
2318c2ecf20Sopenharmony_ci		.init = a6xx_gpu_init,
2328c2ecf20Sopenharmony_ci		.zapfw = "a650_zap.mdt",
2338c2ecf20Sopenharmony_ci		.hwcg = a650_hwcg,
2348c2ecf20Sopenharmony_ci	},
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a300_pm4.fw");
2388c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a300_pfp.fw");
2398c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a330_pm4.fw");
2408c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a330_pfp.fw");
2418c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a420_pm4.fw");
2428c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a420_pfp.fw");
2438c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_pm4.fw");
2448c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_pfp.fw");
2458c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530v3_gpmu.fw2");
2468c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_zap.mdt");
2478c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_zap.b00");
2488c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_zap.b01");
2498c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a530_zap.b02");
2508c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a630_sqe.fw");
2518c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a630_gmu.bin");
2528c2ecf20Sopenharmony_ciMODULE_FIRMWARE("qcom/a630_zap.mbn");
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic inline bool _rev_match(uint8_t entry, uint8_t id)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	return (entry == ANY_ID) || (entry == id);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ciconst struct adreno_info *adreno_info(struct adreno_rev rev)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	int i;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* identify gpu: */
2648c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
2658c2ecf20Sopenharmony_ci		const struct adreno_info *info = &gpulist[i];
2668c2ecf20Sopenharmony_ci		if (_rev_match(info->rev.core, rev.core) &&
2678c2ecf20Sopenharmony_ci				_rev_match(info->rev.major, rev.major) &&
2688c2ecf20Sopenharmony_ci				_rev_match(info->rev.minor, rev.minor) &&
2698c2ecf20Sopenharmony_ci				_rev_match(info->rev.patchid, rev.patchid))
2708c2ecf20Sopenharmony_ci			return info;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return NULL;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistruct msm_gpu *adreno_load_gpu(struct drm_device *dev)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct msm_drm_private *priv = dev->dev_private;
2798c2ecf20Sopenharmony_ci	struct platform_device *pdev = priv->gpu_pdev;
2808c2ecf20Sopenharmony_ci	struct msm_gpu *gpu = NULL;
2818c2ecf20Sopenharmony_ci	struct adreno_gpu *adreno_gpu;
2828c2ecf20Sopenharmony_ci	int ret;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (pdev)
2858c2ecf20Sopenharmony_ci		gpu = dev_to_gpu(&pdev->dev);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (!gpu) {
2888c2ecf20Sopenharmony_ci		dev_err_once(dev->dev, "no GPU device was found\n");
2898c2ecf20Sopenharmony_ci		return NULL;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	adreno_gpu = to_adreno_gpu(gpu);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/*
2958c2ecf20Sopenharmony_ci	 * The number one reason for HW init to fail is if the firmware isn't
2968c2ecf20Sopenharmony_ci	 * loaded yet. Try that first and don't bother continuing on
2978c2ecf20Sopenharmony_ci	 * otherwise
2988c2ecf20Sopenharmony_ci	 */
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ret = adreno_load_fw(adreno_gpu);
3018c2ecf20Sopenharmony_ci	if (ret)
3028c2ecf20Sopenharmony_ci		return NULL;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/*
3058c2ecf20Sopenharmony_ci	 * Now that we have firmware loaded, and are ready to begin
3068c2ecf20Sopenharmony_ci	 * booting the gpu, go ahead and enable runpm:
3078c2ecf20Sopenharmony_ci	 */
3088c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(&pdev->dev);
3118c2ecf20Sopenharmony_ci	if (ret < 0) {
3128c2ecf20Sopenharmony_ci		pm_runtime_put_sync(&pdev->dev);
3138c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "Couldn't power up the GPU: %d\n", ret);
3148c2ecf20Sopenharmony_ci		return NULL;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	mutex_lock(&dev->struct_mutex);
3188c2ecf20Sopenharmony_ci	ret = msm_gpu_hw_init(gpu);
3198c2ecf20Sopenharmony_ci	mutex_unlock(&dev->struct_mutex);
3208c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(&pdev->dev);
3218c2ecf20Sopenharmony_ci	if (ret) {
3228c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret);
3238c2ecf20Sopenharmony_ci		return NULL;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
3278c2ecf20Sopenharmony_ci	if (gpu->funcs->debugfs_init) {
3288c2ecf20Sopenharmony_ci		gpu->funcs->debugfs_init(gpu, dev->primary);
3298c2ecf20Sopenharmony_ci		gpu->funcs->debugfs_init(gpu, dev->render);
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci#endif
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return gpu;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void set_gpu_pdev(struct drm_device *dev,
3378c2ecf20Sopenharmony_ci		struct platform_device *pdev)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct msm_drm_private *priv = dev->dev_private;
3408c2ecf20Sopenharmony_ci	priv->gpu_pdev = pdev;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int find_chipid(struct device *dev, struct adreno_rev *rev)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct device_node *node = dev->of_node;
3468c2ecf20Sopenharmony_ci	const char *compat;
3478c2ecf20Sopenharmony_ci	int ret;
3488c2ecf20Sopenharmony_ci	u32 chipid;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* first search the compat strings for qcom,adreno-XYZ.W: */
3518c2ecf20Sopenharmony_ci	ret = of_property_read_string_index(node, "compatible", 0, &compat);
3528c2ecf20Sopenharmony_ci	if (ret == 0) {
3538c2ecf20Sopenharmony_ci		unsigned int r, patch;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		if (sscanf(compat, "qcom,adreno-%u.%u", &r, &patch) == 2 ||
3568c2ecf20Sopenharmony_ci		    sscanf(compat, "amd,imageon-%u.%u", &r, &patch) == 2) {
3578c2ecf20Sopenharmony_ci			rev->core = r / 100;
3588c2ecf20Sopenharmony_ci			r %= 100;
3598c2ecf20Sopenharmony_ci			rev->major = r / 10;
3608c2ecf20Sopenharmony_ci			r %= 10;
3618c2ecf20Sopenharmony_ci			rev->minor = r;
3628c2ecf20Sopenharmony_ci			rev->patchid = patch;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci			return 0;
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* and if that fails, fall back to legacy "qcom,chipid" property: */
3698c2ecf20Sopenharmony_ci	ret = of_property_read_u32(node, "qcom,chipid", &chipid);
3708c2ecf20Sopenharmony_ci	if (ret) {
3718c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "could not parse qcom,chipid: %d\n", ret);
3728c2ecf20Sopenharmony_ci		return ret;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	rev->core = (chipid >> 24) & 0xff;
3768c2ecf20Sopenharmony_ci	rev->major = (chipid >> 16) & 0xff;
3778c2ecf20Sopenharmony_ci	rev->minor = (chipid >> 8) & 0xff;
3788c2ecf20Sopenharmony_ci	rev->patchid = (chipid & 0xff);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	dev_warn(dev, "Using legacy qcom,chipid binding!\n");
3818c2ecf20Sopenharmony_ci	dev_warn(dev, "Use compatible qcom,adreno-%u%u%u.%u instead.\n",
3828c2ecf20Sopenharmony_ci		rev->core, rev->major, rev->minor, rev->patchid);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int adreno_bind(struct device *dev, struct device *master, void *data)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	static struct adreno_platform_config config = {};
3908c2ecf20Sopenharmony_ci	const struct adreno_info *info;
3918c2ecf20Sopenharmony_ci	struct drm_device *drm = dev_get_drvdata(master);
3928c2ecf20Sopenharmony_ci	struct msm_drm_private *priv = drm->dev_private;
3938c2ecf20Sopenharmony_ci	struct msm_gpu *gpu;
3948c2ecf20Sopenharmony_ci	int ret;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	ret = find_chipid(dev, &config.rev);
3978c2ecf20Sopenharmony_ci	if (ret)
3988c2ecf20Sopenharmony_ci		return ret;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	dev->platform_data = &config;
4018c2ecf20Sopenharmony_ci	set_gpu_pdev(drm, to_platform_device(dev));
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	info = adreno_info(config.rev);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (!info) {
4068c2ecf20Sopenharmony_ci		dev_warn(drm->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
4078c2ecf20Sopenharmony_ci			config.rev.core, config.rev.major,
4088c2ecf20Sopenharmony_ci			config.rev.minor, config.rev.patchid);
4098c2ecf20Sopenharmony_ci		return -ENXIO;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	DBG("Found GPU: %u.%u.%u.%u", config.rev.core, config.rev.major,
4138c2ecf20Sopenharmony_ci		config.rev.minor, config.rev.patchid);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	priv->is_a2xx = config.rev.core == 2;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	gpu = info->init(drm);
4188c2ecf20Sopenharmony_ci	if (IS_ERR(gpu)) {
4198c2ecf20Sopenharmony_ci		dev_warn(drm->dev, "failed to load adreno gpu\n");
4208c2ecf20Sopenharmony_ci		return PTR_ERR(gpu);
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic void adreno_unbind(struct device *dev, struct device *master,
4278c2ecf20Sopenharmony_ci		void *data)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct msm_gpu *gpu = dev_to_gpu(dev);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	pm_runtime_force_suspend(dev);
4328c2ecf20Sopenharmony_ci	gpu->funcs->destroy(gpu);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	set_gpu_pdev(dev_get_drvdata(master), NULL);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic const struct component_ops a3xx_ops = {
4388c2ecf20Sopenharmony_ci		.bind   = adreno_bind,
4398c2ecf20Sopenharmony_ci		.unbind = adreno_unbind,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic void adreno_device_register_headless(void)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	/* on imx5, we don't have a top-level mdp/dpu node
4458c2ecf20Sopenharmony_ci	 * this creates a dummy node for the driver for that case
4468c2ecf20Sopenharmony_ci	 */
4478c2ecf20Sopenharmony_ci	struct platform_device_info dummy_info = {
4488c2ecf20Sopenharmony_ci		.parent = NULL,
4498c2ecf20Sopenharmony_ci		.name = "msm",
4508c2ecf20Sopenharmony_ci		.id = -1,
4518c2ecf20Sopenharmony_ci		.res = NULL,
4528c2ecf20Sopenharmony_ci		.num_res = 0,
4538c2ecf20Sopenharmony_ci		.data = NULL,
4548c2ecf20Sopenharmony_ci		.size_data = 0,
4558c2ecf20Sopenharmony_ci		.dma_mask = ~0,
4568c2ecf20Sopenharmony_ci	};
4578c2ecf20Sopenharmony_ci	platform_device_register_full(&dummy_info);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int adreno_probe(struct platform_device *pdev)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	int ret;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	ret = component_add(&pdev->dev, &a3xx_ops);
4668c2ecf20Sopenharmony_ci	if (ret)
4678c2ecf20Sopenharmony_ci		return ret;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (of_device_is_compatible(pdev->dev.of_node, "amd,imageon"))
4708c2ecf20Sopenharmony_ci		adreno_device_register_headless();
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int adreno_remove(struct platform_device *pdev)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	component_del(&pdev->dev, &a3xx_ops);
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic const struct of_device_id dt_match[] = {
4828c2ecf20Sopenharmony_ci	{ .compatible = "qcom,adreno" },
4838c2ecf20Sopenharmony_ci	{ .compatible = "qcom,adreno-3xx" },
4848c2ecf20Sopenharmony_ci	/* for compatibility with imx5 gpu: */
4858c2ecf20Sopenharmony_ci	{ .compatible = "amd,imageon" },
4868c2ecf20Sopenharmony_ci	/* for backwards compat w/ downstream kgsl DT files: */
4878c2ecf20Sopenharmony_ci	{ .compatible = "qcom,kgsl-3d0" },
4888c2ecf20Sopenharmony_ci	{}
4898c2ecf20Sopenharmony_ci};
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4928c2ecf20Sopenharmony_cistatic int adreno_resume(struct device *dev)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct msm_gpu *gpu = dev_to_gpu(dev);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	return gpu->funcs->pm_resume(gpu);
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic int adreno_suspend(struct device *dev)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct msm_gpu *gpu = dev_to_gpu(dev);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return gpu->funcs->pm_suspend(gpu);
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci#endif
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic const struct dev_pm_ops adreno_pm_ops = {
5088c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
5098c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL)
5108c2ecf20Sopenharmony_ci};
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic struct platform_driver adreno_driver = {
5138c2ecf20Sopenharmony_ci	.probe = adreno_probe,
5148c2ecf20Sopenharmony_ci	.remove = adreno_remove,
5158c2ecf20Sopenharmony_ci	.driver = {
5168c2ecf20Sopenharmony_ci		.name = "adreno",
5178c2ecf20Sopenharmony_ci		.of_match_table = dt_match,
5188c2ecf20Sopenharmony_ci		.pm = &adreno_pm_ops,
5198c2ecf20Sopenharmony_ci	},
5208c2ecf20Sopenharmony_ci};
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_civoid __init adreno_register(void)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	platform_driver_register(&adreno_driver);
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_civoid __exit adreno_unregister(void)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	platform_driver_unregister(&adreno_driver);
5308c2ecf20Sopenharmony_ci}
531