18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Etnaviv Project 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/component.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-fence.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/thermal.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "etnaviv_cmdbuf.h" 198c2ecf20Sopenharmony_ci#include "etnaviv_dump.h" 208c2ecf20Sopenharmony_ci#include "etnaviv_gpu.h" 218c2ecf20Sopenharmony_ci#include "etnaviv_gem.h" 228c2ecf20Sopenharmony_ci#include "etnaviv_mmu.h" 238c2ecf20Sopenharmony_ci#include "etnaviv_perfmon.h" 248c2ecf20Sopenharmony_ci#include "etnaviv_sched.h" 258c2ecf20Sopenharmony_ci#include "common.xml.h" 268c2ecf20Sopenharmony_ci#include "state.xml.h" 278c2ecf20Sopenharmony_ci#include "state_hi.xml.h" 288c2ecf20Sopenharmony_ci#include "cmdstream.xml.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifndef PHYS_OFFSET 318c2ecf20Sopenharmony_ci#define PHYS_OFFSET 0 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct platform_device_id gpu_ids[] = { 358c2ecf20Sopenharmony_ci { .name = "etnaviv-gpu,2d" }, 368c2ecf20Sopenharmony_ci { }, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Driver functions: 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciint etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = gpu->drm->dev_private; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci switch (param) { 488c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_MODEL: 498c2ecf20Sopenharmony_ci *value = gpu->identity.model; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_REVISION: 538c2ecf20Sopenharmony_ci *value = gpu->identity.revision; 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_0: 578c2ecf20Sopenharmony_ci *value = gpu->identity.features; 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_1: 618c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features0; 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_2: 658c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features1; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_3: 698c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features2; 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_4: 738c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features3; 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_5: 778c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features4; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_6: 818c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features5; 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_7: 858c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features6; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_8: 898c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features7; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_9: 938c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features8; 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_10: 978c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features9; 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_11: 1018c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features10; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_FEATURES_12: 1058c2ecf20Sopenharmony_ci *value = gpu->identity.minor_features11; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_STREAM_COUNT: 1098c2ecf20Sopenharmony_ci *value = gpu->identity.stream_count; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_REGISTER_MAX: 1138c2ecf20Sopenharmony_ci *value = gpu->identity.register_max; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_THREAD_COUNT: 1178c2ecf20Sopenharmony_ci *value = gpu->identity.thread_count; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE: 1218c2ecf20Sopenharmony_ci *value = gpu->identity.vertex_cache_size; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT: 1258c2ecf20Sopenharmony_ci *value = gpu->identity.shader_core_count; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_PIXEL_PIPES: 1298c2ecf20Sopenharmony_ci *value = gpu->identity.pixel_pipes; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE: 1338c2ecf20Sopenharmony_ci *value = gpu->identity.vertex_output_buffer_size; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_BUFFER_SIZE: 1378c2ecf20Sopenharmony_ci *value = gpu->identity.buffer_size; 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT: 1418c2ecf20Sopenharmony_ci *value = gpu->identity.instruction_count; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_NUM_CONSTANTS: 1458c2ecf20Sopenharmony_ci *value = gpu->identity.num_constants; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_GPU_NUM_VARYINGS: 1498c2ecf20Sopenharmony_ci *value = gpu->identity.varyings_count; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci case ETNAVIV_PARAM_SOFTPIN_START_ADDR: 1538c2ecf20Sopenharmony_ci if (priv->mmu_global->version == ETNAVIV_IOMMU_V2) 1548c2ecf20Sopenharmony_ci *value = ETNAVIV_SOFTPIN_START_ADDRESS; 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci *value = ~0ULL; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci default: 1608c2ecf20Sopenharmony_ci DBG("%s: invalid param: %u", dev_name(gpu->dev), param); 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define etnaviv_is_model_rev(gpu, mod, rev) \ 1698c2ecf20Sopenharmony_ci ((gpu)->identity.model == chipModel_##mod && \ 1708c2ecf20Sopenharmony_ci (gpu)->identity.revision == rev) 1718c2ecf20Sopenharmony_ci#define etnaviv_field(val, field) \ 1728c2ecf20Sopenharmony_ci (((val) & field##__MASK) >> field##__SHIFT) 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void etnaviv_hw_specs(struct etnaviv_gpu *gpu) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci if (gpu->identity.minor_features0 & 1778c2ecf20Sopenharmony_ci chipMinorFeatures0_MORE_MINOR_FEATURES) { 1788c2ecf20Sopenharmony_ci u32 specs[4]; 1798c2ecf20Sopenharmony_ci unsigned int streams; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS); 1828c2ecf20Sopenharmony_ci specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2); 1838c2ecf20Sopenharmony_ci specs[2] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_3); 1848c2ecf20Sopenharmony_ci specs[3] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_4); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci gpu->identity.stream_count = etnaviv_field(specs[0], 1878c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_STREAM_COUNT); 1888c2ecf20Sopenharmony_ci gpu->identity.register_max = etnaviv_field(specs[0], 1898c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_REGISTER_MAX); 1908c2ecf20Sopenharmony_ci gpu->identity.thread_count = etnaviv_field(specs[0], 1918c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_THREAD_COUNT); 1928c2ecf20Sopenharmony_ci gpu->identity.vertex_cache_size = etnaviv_field(specs[0], 1938c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE); 1948c2ecf20Sopenharmony_ci gpu->identity.shader_core_count = etnaviv_field(specs[0], 1958c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT); 1968c2ecf20Sopenharmony_ci gpu->identity.pixel_pipes = etnaviv_field(specs[0], 1978c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_PIXEL_PIPES); 1988c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 1998c2ecf20Sopenharmony_ci etnaviv_field(specs[0], 2008c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci gpu->identity.buffer_size = etnaviv_field(specs[1], 2038c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE); 2048c2ecf20Sopenharmony_ci gpu->identity.instruction_count = etnaviv_field(specs[1], 2058c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT); 2068c2ecf20Sopenharmony_ci gpu->identity.num_constants = etnaviv_field(specs[1], 2078c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci gpu->identity.varyings_count = etnaviv_field(specs[2], 2108c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_3_VARYINGS_COUNT); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* This overrides the value from older register if non-zero */ 2138c2ecf20Sopenharmony_ci streams = etnaviv_field(specs[3], 2148c2ecf20Sopenharmony_ci VIVS_HI_CHIP_SPECS_4_STREAM_COUNT); 2158c2ecf20Sopenharmony_ci if (streams) 2168c2ecf20Sopenharmony_ci gpu->identity.stream_count = streams; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Fill in the stream count if not specified */ 2208c2ecf20Sopenharmony_ci if (gpu->identity.stream_count == 0) { 2218c2ecf20Sopenharmony_ci if (gpu->identity.model >= 0x1000) 2228c2ecf20Sopenharmony_ci gpu->identity.stream_count = 4; 2238c2ecf20Sopenharmony_ci else 2248c2ecf20Sopenharmony_ci gpu->identity.stream_count = 1; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Convert the register max value */ 2288c2ecf20Sopenharmony_ci if (gpu->identity.register_max) 2298c2ecf20Sopenharmony_ci gpu->identity.register_max = 1 << gpu->identity.register_max; 2308c2ecf20Sopenharmony_ci else if (gpu->identity.model == chipModel_GC400) 2318c2ecf20Sopenharmony_ci gpu->identity.register_max = 32; 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci gpu->identity.register_max = 64; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Convert thread count */ 2368c2ecf20Sopenharmony_ci if (gpu->identity.thread_count) 2378c2ecf20Sopenharmony_ci gpu->identity.thread_count = 1 << gpu->identity.thread_count; 2388c2ecf20Sopenharmony_ci else if (gpu->identity.model == chipModel_GC400) 2398c2ecf20Sopenharmony_ci gpu->identity.thread_count = 64; 2408c2ecf20Sopenharmony_ci else if (gpu->identity.model == chipModel_GC500 || 2418c2ecf20Sopenharmony_ci gpu->identity.model == chipModel_GC530) 2428c2ecf20Sopenharmony_ci gpu->identity.thread_count = 128; 2438c2ecf20Sopenharmony_ci else 2448c2ecf20Sopenharmony_ci gpu->identity.thread_count = 256; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (gpu->identity.vertex_cache_size == 0) 2478c2ecf20Sopenharmony_ci gpu->identity.vertex_cache_size = 8; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (gpu->identity.shader_core_count == 0) { 2508c2ecf20Sopenharmony_ci if (gpu->identity.model >= 0x1000) 2518c2ecf20Sopenharmony_ci gpu->identity.shader_core_count = 2; 2528c2ecf20Sopenharmony_ci else 2538c2ecf20Sopenharmony_ci gpu->identity.shader_core_count = 1; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (gpu->identity.pixel_pipes == 0) 2578c2ecf20Sopenharmony_ci gpu->identity.pixel_pipes = 1; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Convert virtex buffer size */ 2608c2ecf20Sopenharmony_ci if (gpu->identity.vertex_output_buffer_size) { 2618c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 2628c2ecf20Sopenharmony_ci 1 << gpu->identity.vertex_output_buffer_size; 2638c2ecf20Sopenharmony_ci } else if (gpu->identity.model == chipModel_GC400) { 2648c2ecf20Sopenharmony_ci if (gpu->identity.revision < 0x4000) 2658c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 512; 2668c2ecf20Sopenharmony_ci else if (gpu->identity.revision < 0x4200) 2678c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 256; 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 128; 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size = 512; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci switch (gpu->identity.instruction_count) { 2758c2ecf20Sopenharmony_ci case 0: 2768c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC2000, 0x5108) || 2778c2ecf20Sopenharmony_ci gpu->identity.model == chipModel_GC880) 2788c2ecf20Sopenharmony_ci gpu->identity.instruction_count = 512; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci gpu->identity.instruction_count = 256; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci case 1: 2848c2ecf20Sopenharmony_ci gpu->identity.instruction_count = 1024; 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci case 2: 2888c2ecf20Sopenharmony_ci gpu->identity.instruction_count = 2048; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci gpu->identity.instruction_count = 256; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (gpu->identity.num_constants == 0) 2978c2ecf20Sopenharmony_ci gpu->identity.num_constants = 168; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (gpu->identity.varyings_count == 0) { 3008c2ecf20Sopenharmony_ci if (gpu->identity.minor_features1 & chipMinorFeatures1_HALTI0) 3018c2ecf20Sopenharmony_ci gpu->identity.varyings_count = 12; 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci gpu->identity.varyings_count = 8; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * For some cores, two varyings are consumed for position, so the 3088c2ecf20Sopenharmony_ci * maximum varying count needs to be reduced by one. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC5000, 0x5434) || 3118c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC4000, 0x5222) || 3128c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC4000, 0x5245) || 3138c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC4000, 0x5208) || 3148c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC3000, 0x5435) || 3158c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC2200, 0x5244) || 3168c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC2100, 0x5108) || 3178c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC2000, 0x5108) || 3188c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC1500, 0x5246) || 3198c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC880, 0x5107) || 3208c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC880, 0x5106)) 3218c2ecf20Sopenharmony_ci gpu->identity.varyings_count -= 1; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void etnaviv_hw_identify(struct etnaviv_gpu *gpu) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci u32 chipIdentity; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Special case for older graphic cores. */ 3318c2ecf20Sopenharmony_ci if (etnaviv_field(chipIdentity, VIVS_HI_CHIP_IDENTITY_FAMILY) == 0x01) { 3328c2ecf20Sopenharmony_ci gpu->identity.model = chipModel_GC500; 3338c2ecf20Sopenharmony_ci gpu->identity.revision = etnaviv_field(chipIdentity, 3348c2ecf20Sopenharmony_ci VIVS_HI_CHIP_IDENTITY_REVISION); 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL); 3398c2ecf20Sopenharmony_ci gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV); 3408c2ecf20Sopenharmony_ci gpu->identity.customer_id = gpu_read(gpu, VIVS_HI_CHIP_CUSTOMER_ID); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Reading these two registers on GC600 rev 0x19 result in a 3448c2ecf20Sopenharmony_ci * unhandled fault: external abort on non-linefetch 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci if (!etnaviv_is_model_rev(gpu, GC600, 0x19)) { 3478c2ecf20Sopenharmony_ci gpu->identity.product_id = gpu_read(gpu, VIVS_HI_CHIP_PRODUCT_ID); 3488c2ecf20Sopenharmony_ci gpu->identity.eco_id = gpu_read(gpu, VIVS_HI_CHIP_ECO_ID); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* 3528c2ecf20Sopenharmony_ci * !!!! HACK ALERT !!!! 3538c2ecf20Sopenharmony_ci * Because people change device IDs without letting software 3548c2ecf20Sopenharmony_ci * know about it - here is the hack to make it all look the 3558c2ecf20Sopenharmony_ci * same. Only for GC400 family. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci if ((gpu->identity.model & 0xff00) == 0x0400 && 3588c2ecf20Sopenharmony_ci gpu->identity.model != chipModel_GC420) { 3598c2ecf20Sopenharmony_ci gpu->identity.model = gpu->identity.model & 0x0400; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Another special case */ 3638c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC300, 0x2201)) { 3648c2ecf20Sopenharmony_ci u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (chipDate == 0x20080814 && chipTime == 0x12051100) { 3678c2ecf20Sopenharmony_ci /* 3688c2ecf20Sopenharmony_ci * This IP has an ECO; put the correct 3698c2ecf20Sopenharmony_ci * revision in it. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci gpu->identity.revision = 0x1051; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * NXP likes to call the GPU on the i.MX6QP GC2000+, but in 3778c2ecf20Sopenharmony_ci * reality it's just a re-branded GC3000. We can identify this 3788c2ecf20Sopenharmony_ci * core by the upper half of the revision register being all 1. 3798c2ecf20Sopenharmony_ci * Fix model/rev here, so all other places can refer to this 3808c2ecf20Sopenharmony_ci * core by its real identity. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC2000, 0xffff5450)) { 3838c2ecf20Sopenharmony_ci gpu->identity.model = chipModel_GC3000; 3848c2ecf20Sopenharmony_ci gpu->identity.revision &= 0xffff; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC1000, 0x5037) && (chipDate == 0x20120617)) 3888c2ecf20Sopenharmony_ci gpu->identity.eco_id = 1; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC320, 0x5303) && (chipDate == 0x20140511)) 3918c2ecf20Sopenharmony_ci gpu->identity.eco_id = 1; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci dev_info(gpu->dev, "model: GC%x, revision: %x\n", 3958c2ecf20Sopenharmony_ci gpu->identity.model, gpu->identity.revision); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * If there is a match in the HWDB, we aren't interested in the 4008c2ecf20Sopenharmony_ci * remaining register values, as they might be wrong. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci if (etnaviv_fill_identity_from_hwdb(gpu)) 4038c2ecf20Sopenharmony_ci return; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Disable fast clear on GC700. */ 4088c2ecf20Sopenharmony_ci if (gpu->identity.model == chipModel_GC700) 4098c2ecf20Sopenharmony_ci gpu->identity.features &= ~chipFeatures_FAST_CLEAR; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* These models/revisions don't have the 2D pipe bit */ 4128c2ecf20Sopenharmony_ci if ((gpu->identity.model == chipModel_GC500 && 4138c2ecf20Sopenharmony_ci gpu->identity.revision <= 2) || 4148c2ecf20Sopenharmony_ci gpu->identity.model == chipModel_GC300) 4158c2ecf20Sopenharmony_ci gpu->identity.features |= chipFeatures_PIPE_2D; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if ((gpu->identity.model == chipModel_GC500 && 4188c2ecf20Sopenharmony_ci gpu->identity.revision < 2) || 4198c2ecf20Sopenharmony_ci (gpu->identity.model == chipModel_GC300 && 4208c2ecf20Sopenharmony_ci gpu->identity.revision < 0x2000)) { 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these 4248c2ecf20Sopenharmony_ci * registers. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci gpu->identity.minor_features0 = 0; 4278c2ecf20Sopenharmony_ci gpu->identity.minor_features1 = 0; 4288c2ecf20Sopenharmony_ci gpu->identity.minor_features2 = 0; 4298c2ecf20Sopenharmony_ci gpu->identity.minor_features3 = 0; 4308c2ecf20Sopenharmony_ci gpu->identity.minor_features4 = 0; 4318c2ecf20Sopenharmony_ci gpu->identity.minor_features5 = 0; 4328c2ecf20Sopenharmony_ci } else 4338c2ecf20Sopenharmony_ci gpu->identity.minor_features0 = 4348c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (gpu->identity.minor_features0 & 4378c2ecf20Sopenharmony_ci chipMinorFeatures0_MORE_MINOR_FEATURES) { 4388c2ecf20Sopenharmony_ci gpu->identity.minor_features1 = 4398c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1); 4408c2ecf20Sopenharmony_ci gpu->identity.minor_features2 = 4418c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2); 4428c2ecf20Sopenharmony_ci gpu->identity.minor_features3 = 4438c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3); 4448c2ecf20Sopenharmony_ci gpu->identity.minor_features4 = 4458c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_4); 4468c2ecf20Sopenharmony_ci gpu->identity.minor_features5 = 4478c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5); 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* GC600/300 idle register reports zero bits where modules aren't present */ 4518c2ecf20Sopenharmony_ci if (gpu->identity.model == chipModel_GC600 || 4528c2ecf20Sopenharmony_ci gpu->identity.model == chipModel_GC300) 4538c2ecf20Sopenharmony_ci gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | 4548c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_RA | 4558c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_SE | 4568c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_PA | 4578c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_SH | 4588c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_PE | 4598c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_DE | 4608c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_FE; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci etnaviv_hw_specs(gpu); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock | 4688c2ecf20Sopenharmony_ci VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD); 4698c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void etnaviv_gpu_update_clock(struct etnaviv_gpu *gpu) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci if (gpu->identity.minor_features2 & 4758c2ecf20Sopenharmony_ci chipMinorFeatures2_DYNAMIC_FREQUENCY_SCALING) { 4768c2ecf20Sopenharmony_ci clk_set_rate(gpu->clk_core, 4778c2ecf20Sopenharmony_ci gpu->base_rate_core >> gpu->freq_scale); 4788c2ecf20Sopenharmony_ci clk_set_rate(gpu->clk_shader, 4798c2ecf20Sopenharmony_ci gpu->base_rate_shader >> gpu->freq_scale); 4808c2ecf20Sopenharmony_ci } else { 4818c2ecf20Sopenharmony_ci unsigned int fscale = 1 << (6 - gpu->freq_scale); 4828c2ecf20Sopenharmony_ci u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci clock &= ~VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK; 4858c2ecf20Sopenharmony_ci clock |= VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale); 4868c2ecf20Sopenharmony_ci etnaviv_gpu_load_clock(gpu, clock); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int etnaviv_hw_reset(struct etnaviv_gpu *gpu) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci u32 control, idle; 4938c2ecf20Sopenharmony_ci unsigned long timeout; 4948c2ecf20Sopenharmony_ci bool failed = true; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* We hope that the GPU resets in under one second */ 4978c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(1000); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci while (time_is_after_jiffies(timeout)) { 5008c2ecf20Sopenharmony_ci /* enable clock */ 5018c2ecf20Sopenharmony_ci unsigned int fscale = 1 << (6 - gpu->freq_scale); 5028c2ecf20Sopenharmony_ci control = VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(fscale); 5038c2ecf20Sopenharmony_ci etnaviv_gpu_load_clock(gpu, control); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* isolate the GPU. */ 5068c2ecf20Sopenharmony_ci control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; 5078c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (gpu->sec_mode == ETNA_SEC_KERNEL) { 5108c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_MMUv2_AHB_CONTROL, 5118c2ecf20Sopenharmony_ci VIVS_MMUv2_AHB_CONTROL_RESET); 5128c2ecf20Sopenharmony_ci } else { 5138c2ecf20Sopenharmony_ci /* set soft reset. */ 5148c2ecf20Sopenharmony_ci control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET; 5158c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* wait for reset. */ 5198c2ecf20Sopenharmony_ci usleep_range(10, 20); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* reset soft reset bit. */ 5228c2ecf20Sopenharmony_ci control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET; 5238c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* reset GPU isolation. */ 5268c2ecf20Sopenharmony_ci control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; 5278c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* read idle register. */ 5308c2ecf20Sopenharmony_ci idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* try resetting again if FE is not idle */ 5338c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { 5348c2ecf20Sopenharmony_ci dev_dbg(gpu->dev, "FE is not idle\n"); 5358c2ecf20Sopenharmony_ci continue; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* read reset register. */ 5398c2ecf20Sopenharmony_ci control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* is the GPU idle? */ 5428c2ecf20Sopenharmony_ci if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) || 5438c2ecf20Sopenharmony_ci ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) { 5448c2ecf20Sopenharmony_ci dev_dbg(gpu->dev, "GPU is not idle\n"); 5458c2ecf20Sopenharmony_ci continue; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* disable debug registers, as they are not normally needed */ 5498c2ecf20Sopenharmony_ci control |= VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS; 5508c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci failed = false; 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (failed) { 5578c2ecf20Sopenharmony_ci idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); 5588c2ecf20Sopenharmony_ci control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n", 5618c2ecf20Sopenharmony_ci idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ", 5628c2ecf20Sopenharmony_ci control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ", 5638c2ecf20Sopenharmony_ci control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not "); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return -EBUSY; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* We rely on the GPU running, so program the clock */ 5698c2ecf20Sopenharmony_ci etnaviv_gpu_update_clock(gpu); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci gpu->fe_running = false; 5728c2ecf20Sopenharmony_ci gpu->exec_state = -1; 5738c2ecf20Sopenharmony_ci if (gpu->mmu_context) 5748c2ecf20Sopenharmony_ci etnaviv_iommu_context_put(gpu->mmu_context); 5758c2ecf20Sopenharmony_ci gpu->mmu_context = NULL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci u32 pmc, ppc; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* enable clock gating */ 5858c2ecf20Sopenharmony_ci ppc = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); 5868c2ecf20Sopenharmony_ci ppc |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Disable stall module clock gating for 4.3.0.1 and 4.3.0.2 revs */ 5898c2ecf20Sopenharmony_ci if (gpu->identity.revision == 0x4301 || 5908c2ecf20Sopenharmony_ci gpu->identity.revision == 0x4302) 5918c2ecf20Sopenharmony_ci ppc |= VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_PM_POWER_CONTROLS, ppc); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci pmc = gpu_read(gpu, VIVS_PM_MODULE_CONTROLS); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Disable PA clock gating for GC400+ without bugfix except for GC420 */ 5988c2ecf20Sopenharmony_ci if (gpu->identity.model >= chipModel_GC400 && 5998c2ecf20Sopenharmony_ci gpu->identity.model != chipModel_GC420 && 6008c2ecf20Sopenharmony_ci !(gpu->identity.minor_features3 & chipMinorFeatures3_BUG_FIXES12)) 6018c2ecf20Sopenharmony_ci pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PA; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* 6048c2ecf20Sopenharmony_ci * Disable PE clock gating on revs < 5.0.0.0 when HZ is 6058c2ecf20Sopenharmony_ci * present without a bug fix. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci if (gpu->identity.revision < 0x5000 && 6088c2ecf20Sopenharmony_ci gpu->identity.minor_features0 & chipMinorFeatures0_HZ && 6098c2ecf20Sopenharmony_ci !(gpu->identity.minor_features1 & 6108c2ecf20Sopenharmony_ci chipMinorFeatures1_DISABLE_PE_GATING)) 6118c2ecf20Sopenharmony_ci pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (gpu->identity.revision < 0x5422) 6148c2ecf20Sopenharmony_ci pmc |= BIT(15); /* Unknown bit */ 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Disable TX clock gating on affected core revisions. */ 6178c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC4000, 0x5222) || 6188c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC2000, 0x5108)) 6198c2ecf20Sopenharmony_ci pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ; 6228c2ecf20Sopenharmony_ci pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_PM_MODULE_CONTROLS, pmc); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_civoid etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS, address); 6308c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_FE_COMMAND_CONTROL, 6318c2ecf20Sopenharmony_ci VIVS_FE_COMMAND_CONTROL_ENABLE | 6328c2ecf20Sopenharmony_ci VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (gpu->sec_mode == ETNA_SEC_KERNEL) { 6358c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_MMUv2_SEC_COMMAND_CONTROL, 6368c2ecf20Sopenharmony_ci VIVS_MMUv2_SEC_COMMAND_CONTROL_ENABLE | 6378c2ecf20Sopenharmony_ci VIVS_MMUv2_SEC_COMMAND_CONTROL_PREFETCH(prefetch)); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci gpu->fe_running = true; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void etnaviv_gpu_start_fe_idleloop(struct etnaviv_gpu *gpu, 6448c2ecf20Sopenharmony_ci struct etnaviv_iommu_context *context) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci u16 prefetch; 6478c2ecf20Sopenharmony_ci u32 address; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* setup the MMU */ 6508c2ecf20Sopenharmony_ci etnaviv_iommu_restore(gpu, context); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Start command processor */ 6538c2ecf20Sopenharmony_ci prefetch = etnaviv_buffer_init(gpu); 6548c2ecf20Sopenharmony_ci address = etnaviv_cmdbuf_get_va(&gpu->buffer, 6558c2ecf20Sopenharmony_ci &gpu->mmu_context->cmdbuf_mapping); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci etnaviv_gpu_start_fe(gpu, address, prefetch); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci /* 6638c2ecf20Sopenharmony_ci * Base value for VIVS_PM_PULSE_EATER register on models where it 6648c2ecf20Sopenharmony_ci * cannot be read, extracted from vivante kernel driver. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci u32 pulse_eater = 0x01590880; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC4000, 0x5208) || 6698c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC4000, 0x5222)) { 6708c2ecf20Sopenharmony_ci pulse_eater |= BIT(23); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC1000, 0x5039) || 6758c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC1000, 0x5040)) { 6768c2ecf20Sopenharmony_ci pulse_eater &= ~BIT(16); 6778c2ecf20Sopenharmony_ci pulse_eater |= BIT(17); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if ((gpu->identity.revision > 0x5420) && 6818c2ecf20Sopenharmony_ci (gpu->identity.features & chipFeatures_PIPE_3D)) 6828c2ecf20Sopenharmony_ci { 6838c2ecf20Sopenharmony_ci /* Performance fix: disable internal DFS */ 6848c2ecf20Sopenharmony_ci pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER); 6858c2ecf20Sopenharmony_ci pulse_eater |= BIT(18); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci if ((etnaviv_is_model_rev(gpu, GC320, 0x5007) || 6948c2ecf20Sopenharmony_ci etnaviv_is_model_rev(gpu, GC320, 0x5220)) && 6958c2ecf20Sopenharmony_ci gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400) { 6968c2ecf20Sopenharmony_ci u32 mc_memory_debug; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (gpu->identity.revision == 0x5007) 7018c2ecf20Sopenharmony_ci mc_memory_debug |= 0x0c; 7028c2ecf20Sopenharmony_ci else 7038c2ecf20Sopenharmony_ci mc_memory_debug |= 0x08; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* enable module-level clock gating */ 7098c2ecf20Sopenharmony_ci etnaviv_gpu_enable_mlcg(gpu); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* 7128c2ecf20Sopenharmony_ci * Update GPU AXI cache atttribute to "cacheable, no allocate". 7138c2ecf20Sopenharmony_ci * This is necessary to prevent the iMX6 SoC locking up. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_AXI_CONFIG, 7168c2ecf20Sopenharmony_ci VIVS_HI_AXI_CONFIG_AWCACHE(2) | 7178c2ecf20Sopenharmony_ci VIVS_HI_AXI_CONFIG_ARCACHE(2)); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* GC2000 rev 5108 needs a special bus config */ 7208c2ecf20Sopenharmony_ci if (etnaviv_is_model_rev(gpu, GC2000, 0x5108)) { 7218c2ecf20Sopenharmony_ci u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG); 7228c2ecf20Sopenharmony_ci bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK | 7238c2ecf20Sopenharmony_ci VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK); 7248c2ecf20Sopenharmony_ci bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) | 7258c2ecf20Sopenharmony_ci VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0); 7268c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (gpu->sec_mode == ETNA_SEC_KERNEL) { 7308c2ecf20Sopenharmony_ci u32 val = gpu_read(gpu, VIVS_MMUv2_AHB_CONTROL); 7318c2ecf20Sopenharmony_ci val |= VIVS_MMUv2_AHB_CONTROL_NONSEC_ACCESS; 7328c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_MMUv2_AHB_CONTROL, val); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* setup the pulse eater */ 7368c2ecf20Sopenharmony_ci etnaviv_gpu_setup_pulse_eater(gpu); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciint etnaviv_gpu_init(struct etnaviv_gpu *gpu) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = gpu->drm->dev_private; 7448c2ecf20Sopenharmony_ci int ret, i; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(gpu->dev); 7478c2ecf20Sopenharmony_ci if (ret < 0) { 7488c2ecf20Sopenharmony_ci dev_err(gpu->dev, "Failed to enable GPU power domain\n"); 7498c2ecf20Sopenharmony_ci goto pm_put; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci etnaviv_hw_identify(gpu); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (gpu->identity.model == 0) { 7558c2ecf20Sopenharmony_ci dev_err(gpu->dev, "Unknown GPU model\n"); 7568c2ecf20Sopenharmony_ci ret = -ENXIO; 7578c2ecf20Sopenharmony_ci goto fail; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Exclude VG cores with FE2.0 */ 7618c2ecf20Sopenharmony_ci if (gpu->identity.features & chipFeatures_PIPE_VG && 7628c2ecf20Sopenharmony_ci gpu->identity.features & chipFeatures_FE20) { 7638c2ecf20Sopenharmony_ci dev_info(gpu->dev, "Ignoring GPU with VG and FE2.0\n"); 7648c2ecf20Sopenharmony_ci ret = -ENXIO; 7658c2ecf20Sopenharmony_ci goto fail; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* 7698c2ecf20Sopenharmony_ci * On cores with security features supported, we claim control over the 7708c2ecf20Sopenharmony_ci * security states. 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if ((gpu->identity.minor_features7 & chipMinorFeatures7_BIT_SECURITY) && 7738c2ecf20Sopenharmony_ci (gpu->identity.minor_features10 & chipMinorFeatures10_SECURITY_AHB)) 7748c2ecf20Sopenharmony_ci gpu->sec_mode = ETNA_SEC_KERNEL; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ret = etnaviv_hw_reset(gpu); 7778c2ecf20Sopenharmony_ci if (ret) { 7788c2ecf20Sopenharmony_ci dev_err(gpu->dev, "GPU reset failed\n"); 7798c2ecf20Sopenharmony_ci goto fail; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ret = etnaviv_iommu_global_init(gpu); 7838c2ecf20Sopenharmony_ci if (ret) 7848c2ecf20Sopenharmony_ci goto fail; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* 7878c2ecf20Sopenharmony_ci * Set the GPU linear window to be at the end of the DMA window, where 7888c2ecf20Sopenharmony_ci * the CMA area is likely to reside. This ensures that we are able to 7898c2ecf20Sopenharmony_ci * map the command buffers while having the linear window overlap as 7908c2ecf20Sopenharmony_ci * much RAM as possible, so we can optimize mappings for other buffers. 7918c2ecf20Sopenharmony_ci * 7928c2ecf20Sopenharmony_ci * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads 7938c2ecf20Sopenharmony_ci * to different views of the memory on the individual engines. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci if (!(gpu->identity.features & chipFeatures_PIPE_3D) || 7968c2ecf20Sopenharmony_ci (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) { 7978c2ecf20Sopenharmony_ci u32 dma_mask = (u32)dma_get_required_mask(gpu->dev); 7988c2ecf20Sopenharmony_ci if (dma_mask < PHYS_OFFSET + SZ_2G) 7998c2ecf20Sopenharmony_ci priv->mmu_global->memory_base = PHYS_OFFSET; 8008c2ecf20Sopenharmony_ci else 8018c2ecf20Sopenharmony_ci priv->mmu_global->memory_base = dma_mask - SZ_2G + 1; 8028c2ecf20Sopenharmony_ci } else if (PHYS_OFFSET >= SZ_2G) { 8038c2ecf20Sopenharmony_ci dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n"); 8048c2ecf20Sopenharmony_ci priv->mmu_global->memory_base = PHYS_OFFSET; 8058c2ecf20Sopenharmony_ci gpu->identity.features &= ~chipFeatures_FAST_CLEAR; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* 8098c2ecf20Sopenharmony_ci * If the GPU is part of a system with DMA addressing limitations, 8108c2ecf20Sopenharmony_ci * request pages for our SHM backend buffers from the DMA32 zone to 8118c2ecf20Sopenharmony_ci * hopefully avoid performance killing SWIOTLB bounce buffering. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci if (dma_addressing_limited(gpu->dev)) 8148c2ecf20Sopenharmony_ci priv->shm_gfp_mask |= GFP_DMA32; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* Create buffer: */ 8178c2ecf20Sopenharmony_ci ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer, 8188c2ecf20Sopenharmony_ci PAGE_SIZE); 8198c2ecf20Sopenharmony_ci if (ret) { 8208c2ecf20Sopenharmony_ci dev_err(gpu->dev, "could not create command buffer\n"); 8218c2ecf20Sopenharmony_ci goto fail; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Setup event management */ 8258c2ecf20Sopenharmony_ci spin_lock_init(&gpu->event_spinlock); 8268c2ecf20Sopenharmony_ci init_completion(&gpu->event_free); 8278c2ecf20Sopenharmony_ci bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); 8288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gpu->event); i++) 8298c2ecf20Sopenharmony_ci complete(&gpu->event_free); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Now program the hardware */ 8328c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 8338c2ecf20Sopenharmony_ci etnaviv_gpu_hw_init(gpu); 8348c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 8378c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gpu->dev); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci gpu->initialized = true; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cifail: 8448c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 8458c2ecf20Sopenharmony_cipm_put: 8468c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gpu->dev); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return ret; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 8528c2ecf20Sopenharmony_cistruct dma_debug { 8538c2ecf20Sopenharmony_ci u32 address[2]; 8548c2ecf20Sopenharmony_ci u32 state[2]; 8558c2ecf20Sopenharmony_ci}; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci u32 i; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); 8628c2ecf20Sopenharmony_ci debug->state[0] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci for (i = 0; i < 500; i++) { 8658c2ecf20Sopenharmony_ci debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); 8668c2ecf20Sopenharmony_ci debug->state[1] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (debug->address[0] != debug->address[1]) 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (debug->state[0] != debug->state[1]) 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciint etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct dma_debug debug; 8798c2ecf20Sopenharmony_ci u32 dma_lo, dma_hi, axi, idle; 8808c2ecf20Sopenharmony_ci int ret; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci seq_printf(m, "%s Status:\n", dev_name(gpu->dev)); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(gpu->dev); 8858c2ecf20Sopenharmony_ci if (ret < 0) 8868c2ecf20Sopenharmony_ci goto pm_put; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW); 8898c2ecf20Sopenharmony_ci dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH); 8908c2ecf20Sopenharmony_ci axi = gpu_read(gpu, VIVS_HI_AXI_STATUS); 8918c2ecf20Sopenharmony_ci idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci verify_dma(gpu, &debug); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci seq_puts(m, "\tidentity\n"); 8968c2ecf20Sopenharmony_ci seq_printf(m, "\t model: 0x%x\n", gpu->identity.model); 8978c2ecf20Sopenharmony_ci seq_printf(m, "\t revision: 0x%x\n", gpu->identity.revision); 8988c2ecf20Sopenharmony_ci seq_printf(m, "\t product_id: 0x%x\n", gpu->identity.product_id); 8998c2ecf20Sopenharmony_ci seq_printf(m, "\t customer_id: 0x%x\n", gpu->identity.customer_id); 9008c2ecf20Sopenharmony_ci seq_printf(m, "\t eco_id: 0x%x\n", gpu->identity.eco_id); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci seq_puts(m, "\tfeatures\n"); 9038c2ecf20Sopenharmony_ci seq_printf(m, "\t major_features: 0x%08x\n", 9048c2ecf20Sopenharmony_ci gpu->identity.features); 9058c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features0: 0x%08x\n", 9068c2ecf20Sopenharmony_ci gpu->identity.minor_features0); 9078c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features1: 0x%08x\n", 9088c2ecf20Sopenharmony_ci gpu->identity.minor_features1); 9098c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features2: 0x%08x\n", 9108c2ecf20Sopenharmony_ci gpu->identity.minor_features2); 9118c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features3: 0x%08x\n", 9128c2ecf20Sopenharmony_ci gpu->identity.minor_features3); 9138c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features4: 0x%08x\n", 9148c2ecf20Sopenharmony_ci gpu->identity.minor_features4); 9158c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features5: 0x%08x\n", 9168c2ecf20Sopenharmony_ci gpu->identity.minor_features5); 9178c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features6: 0x%08x\n", 9188c2ecf20Sopenharmony_ci gpu->identity.minor_features6); 9198c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features7: 0x%08x\n", 9208c2ecf20Sopenharmony_ci gpu->identity.minor_features7); 9218c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features8: 0x%08x\n", 9228c2ecf20Sopenharmony_ci gpu->identity.minor_features8); 9238c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features9: 0x%08x\n", 9248c2ecf20Sopenharmony_ci gpu->identity.minor_features9); 9258c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features10: 0x%08x\n", 9268c2ecf20Sopenharmony_ci gpu->identity.minor_features10); 9278c2ecf20Sopenharmony_ci seq_printf(m, "\t minor_features11: 0x%08x\n", 9288c2ecf20Sopenharmony_ci gpu->identity.minor_features11); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci seq_puts(m, "\tspecs\n"); 9318c2ecf20Sopenharmony_ci seq_printf(m, "\t stream_count: %d\n", 9328c2ecf20Sopenharmony_ci gpu->identity.stream_count); 9338c2ecf20Sopenharmony_ci seq_printf(m, "\t register_max: %d\n", 9348c2ecf20Sopenharmony_ci gpu->identity.register_max); 9358c2ecf20Sopenharmony_ci seq_printf(m, "\t thread_count: %d\n", 9368c2ecf20Sopenharmony_ci gpu->identity.thread_count); 9378c2ecf20Sopenharmony_ci seq_printf(m, "\t vertex_cache_size: %d\n", 9388c2ecf20Sopenharmony_ci gpu->identity.vertex_cache_size); 9398c2ecf20Sopenharmony_ci seq_printf(m, "\t shader_core_count: %d\n", 9408c2ecf20Sopenharmony_ci gpu->identity.shader_core_count); 9418c2ecf20Sopenharmony_ci seq_printf(m, "\t pixel_pipes: %d\n", 9428c2ecf20Sopenharmony_ci gpu->identity.pixel_pipes); 9438c2ecf20Sopenharmony_ci seq_printf(m, "\t vertex_output_buffer_size: %d\n", 9448c2ecf20Sopenharmony_ci gpu->identity.vertex_output_buffer_size); 9458c2ecf20Sopenharmony_ci seq_printf(m, "\t buffer_size: %d\n", 9468c2ecf20Sopenharmony_ci gpu->identity.buffer_size); 9478c2ecf20Sopenharmony_ci seq_printf(m, "\t instruction_count: %d\n", 9488c2ecf20Sopenharmony_ci gpu->identity.instruction_count); 9498c2ecf20Sopenharmony_ci seq_printf(m, "\t num_constants: %d\n", 9508c2ecf20Sopenharmony_ci gpu->identity.num_constants); 9518c2ecf20Sopenharmony_ci seq_printf(m, "\t varyings_count: %d\n", 9528c2ecf20Sopenharmony_ci gpu->identity.varyings_count); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci seq_printf(m, "\taxi: 0x%08x\n", axi); 9558c2ecf20Sopenharmony_ci seq_printf(m, "\tidle: 0x%08x\n", idle); 9568c2ecf20Sopenharmony_ci idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP; 9578c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) 9588c2ecf20Sopenharmony_ci seq_puts(m, "\t FE is not idle\n"); 9598c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_DE) == 0) 9608c2ecf20Sopenharmony_ci seq_puts(m, "\t DE is not idle\n"); 9618c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_PE) == 0) 9628c2ecf20Sopenharmony_ci seq_puts(m, "\t PE is not idle\n"); 9638c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_SH) == 0) 9648c2ecf20Sopenharmony_ci seq_puts(m, "\t SH is not idle\n"); 9658c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_PA) == 0) 9668c2ecf20Sopenharmony_ci seq_puts(m, "\t PA is not idle\n"); 9678c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_SE) == 0) 9688c2ecf20Sopenharmony_ci seq_puts(m, "\t SE is not idle\n"); 9698c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_RA) == 0) 9708c2ecf20Sopenharmony_ci seq_puts(m, "\t RA is not idle\n"); 9718c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_TX) == 0) 9728c2ecf20Sopenharmony_ci seq_puts(m, "\t TX is not idle\n"); 9738c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_VG) == 0) 9748c2ecf20Sopenharmony_ci seq_puts(m, "\t VG is not idle\n"); 9758c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_IM) == 0) 9768c2ecf20Sopenharmony_ci seq_puts(m, "\t IM is not idle\n"); 9778c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_FP) == 0) 9788c2ecf20Sopenharmony_ci seq_puts(m, "\t FP is not idle\n"); 9798c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_TS) == 0) 9808c2ecf20Sopenharmony_ci seq_puts(m, "\t TS is not idle\n"); 9818c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_BL) == 0) 9828c2ecf20Sopenharmony_ci seq_puts(m, "\t BL is not idle\n"); 9838c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_ASYNCFE) == 0) 9848c2ecf20Sopenharmony_ci seq_puts(m, "\t ASYNCFE is not idle\n"); 9858c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_MC) == 0) 9868c2ecf20Sopenharmony_ci seq_puts(m, "\t MC is not idle\n"); 9878c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_PPA) == 0) 9888c2ecf20Sopenharmony_ci seq_puts(m, "\t PPA is not idle\n"); 9898c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_WD) == 0) 9908c2ecf20Sopenharmony_ci seq_puts(m, "\t WD is not idle\n"); 9918c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_NN) == 0) 9928c2ecf20Sopenharmony_ci seq_puts(m, "\t NN is not idle\n"); 9938c2ecf20Sopenharmony_ci if ((idle & VIVS_HI_IDLE_STATE_TP) == 0) 9948c2ecf20Sopenharmony_ci seq_puts(m, "\t TP is not idle\n"); 9958c2ecf20Sopenharmony_ci if (idle & VIVS_HI_IDLE_STATE_AXI_LP) 9968c2ecf20Sopenharmony_ci seq_puts(m, "\t AXI low power mode\n"); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (gpu->identity.features & chipFeatures_DEBUG_MODE) { 9998c2ecf20Sopenharmony_ci u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0); 10008c2ecf20Sopenharmony_ci u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1); 10018c2ecf20Sopenharmony_ci u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci seq_puts(m, "\tMC\n"); 10048c2ecf20Sopenharmony_ci seq_printf(m, "\t read0: 0x%08x\n", read0); 10058c2ecf20Sopenharmony_ci seq_printf(m, "\t read1: 0x%08x\n", read1); 10068c2ecf20Sopenharmony_ci seq_printf(m, "\t write: 0x%08x\n", write); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci seq_puts(m, "\tDMA "); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (debug.address[0] == debug.address[1] && 10128c2ecf20Sopenharmony_ci debug.state[0] == debug.state[1]) { 10138c2ecf20Sopenharmony_ci seq_puts(m, "seems to be stuck\n"); 10148c2ecf20Sopenharmony_ci } else if (debug.address[0] == debug.address[1]) { 10158c2ecf20Sopenharmony_ci seq_puts(m, "address is constant\n"); 10168c2ecf20Sopenharmony_ci } else { 10178c2ecf20Sopenharmony_ci seq_puts(m, "is running\n"); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]); 10218c2ecf20Sopenharmony_ci seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]); 10228c2ecf20Sopenharmony_ci seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]); 10238c2ecf20Sopenharmony_ci seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]); 10248c2ecf20Sopenharmony_ci seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n", 10258c2ecf20Sopenharmony_ci dma_lo, dma_hi); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ret = 0; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 10308c2ecf20Sopenharmony_cipm_put: 10318c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gpu->dev); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return ret; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci#endif 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_civoid etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci unsigned int i = 0; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci dev_err(gpu->dev, "recover hung GPU!\n"); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (pm_runtime_get_sync(gpu->dev) < 0) 10448c2ecf20Sopenharmony_ci goto pm_put; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci etnaviv_hw_reset(gpu); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* complete all events, the GPU won't do it after the reset */ 10518c2ecf20Sopenharmony_ci spin_lock(&gpu->event_spinlock); 10528c2ecf20Sopenharmony_ci for_each_set_bit_from(i, gpu->event_bitmap, ETNA_NR_EVENTS) 10538c2ecf20Sopenharmony_ci complete(&gpu->event_free); 10548c2ecf20Sopenharmony_ci bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); 10558c2ecf20Sopenharmony_ci spin_unlock(&gpu->event_spinlock); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci etnaviv_gpu_hw_init(gpu); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 10608c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 10618c2ecf20Sopenharmony_cipm_put: 10628c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gpu->dev); 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci/* fence object management */ 10668c2ecf20Sopenharmony_cistruct etnaviv_fence { 10678c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 10688c2ecf20Sopenharmony_ci struct dma_fence base; 10698c2ecf20Sopenharmony_ci}; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic inline struct etnaviv_fence *to_etnaviv_fence(struct dma_fence *fence) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci return container_of(fence, struct etnaviv_fence, base); 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic const char *etnaviv_fence_get_driver_name(struct dma_fence *fence) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci return "etnaviv"; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic const char *etnaviv_fence_get_timeline_name(struct dma_fence *fence) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct etnaviv_fence *f = to_etnaviv_fence(fence); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return dev_name(f->gpu->dev); 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic bool etnaviv_fence_signaled(struct dma_fence *fence) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct etnaviv_fence *f = to_etnaviv_fence(fence); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return (s32)(f->gpu->completed_fence - f->base.seqno) >= 0; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void etnaviv_fence_release(struct dma_fence *fence) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct etnaviv_fence *f = to_etnaviv_fence(fence); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci kfree_rcu(f, base.rcu); 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic const struct dma_fence_ops etnaviv_fence_ops = { 11038c2ecf20Sopenharmony_ci .get_driver_name = etnaviv_fence_get_driver_name, 11048c2ecf20Sopenharmony_ci .get_timeline_name = etnaviv_fence_get_timeline_name, 11058c2ecf20Sopenharmony_ci .signaled = etnaviv_fence_signaled, 11068c2ecf20Sopenharmony_ci .release = etnaviv_fence_release, 11078c2ecf20Sopenharmony_ci}; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct etnaviv_fence *f; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* 11148c2ecf20Sopenharmony_ci * GPU lock must already be held, otherwise fence completion order might 11158c2ecf20Sopenharmony_ci * not match the seqno order assigned here. 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ci lockdep_assert_held(&gpu->lock); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci f = kzalloc(sizeof(*f), GFP_KERNEL); 11208c2ecf20Sopenharmony_ci if (!f) 11218c2ecf20Sopenharmony_ci return NULL; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci f->gpu = gpu; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci dma_fence_init(&f->base, &etnaviv_fence_ops, &gpu->fence_spinlock, 11268c2ecf20Sopenharmony_ci gpu->fence_context, ++gpu->next_fence); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return &f->base; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/* returns true if fence a comes after fence b */ 11328c2ecf20Sopenharmony_cistatic inline bool fence_after(u32 a, u32 b) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci return (s32)(a - b) > 0; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci/* 11388c2ecf20Sopenharmony_ci * event management: 11398c2ecf20Sopenharmony_ci */ 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic int event_alloc(struct etnaviv_gpu *gpu, unsigned nr_events, 11428c2ecf20Sopenharmony_ci unsigned int *events) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(10 * 10000); 11458c2ecf20Sopenharmony_ci unsigned i, acquired = 0; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci for (i = 0; i < nr_events; i++) { 11488c2ecf20Sopenharmony_ci unsigned long ret; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout(&gpu->event_free, timeout); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (!ret) { 11538c2ecf20Sopenharmony_ci dev_err(gpu->dev, "wait_for_completion_timeout failed"); 11548c2ecf20Sopenharmony_ci goto out; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci acquired++; 11588c2ecf20Sopenharmony_ci timeout = ret; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci spin_lock(&gpu->event_spinlock); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci for (i = 0; i < nr_events; i++) { 11648c2ecf20Sopenharmony_ci int event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci events[i] = event; 11678c2ecf20Sopenharmony_ci memset(&gpu->event[event], 0, sizeof(struct etnaviv_event)); 11688c2ecf20Sopenharmony_ci set_bit(event, gpu->event_bitmap); 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci spin_unlock(&gpu->event_spinlock); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ciout: 11768c2ecf20Sopenharmony_ci for (i = 0; i < acquired; i++) 11778c2ecf20Sopenharmony_ci complete(&gpu->event_free); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci return -EBUSY; 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic void event_free(struct etnaviv_gpu *gpu, unsigned int event) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci if (!test_bit(event, gpu->event_bitmap)) { 11858c2ecf20Sopenharmony_ci dev_warn(gpu->dev, "event %u is already marked as free", 11868c2ecf20Sopenharmony_ci event); 11878c2ecf20Sopenharmony_ci } else { 11888c2ecf20Sopenharmony_ci clear_bit(event, gpu->event_bitmap); 11898c2ecf20Sopenharmony_ci complete(&gpu->event_free); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci/* 11948c2ecf20Sopenharmony_ci * Cmdstream submission/retirement: 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_ciint etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, 11978c2ecf20Sopenharmony_ci u32 id, struct drm_etnaviv_timespec *timeout) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct dma_fence *fence; 12008c2ecf20Sopenharmony_ci int ret; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* 12038c2ecf20Sopenharmony_ci * Look up the fence and take a reference. We might still find a fence 12048c2ecf20Sopenharmony_ci * whose refcount has already dropped to zero. dma_fence_get_rcu 12058c2ecf20Sopenharmony_ci * pretends we didn't find a fence in that case. 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_ci rcu_read_lock(); 12088c2ecf20Sopenharmony_ci fence = idr_find(&gpu->fence_idr, id); 12098c2ecf20Sopenharmony_ci if (fence) 12108c2ecf20Sopenharmony_ci fence = dma_fence_get_rcu(fence); 12118c2ecf20Sopenharmony_ci rcu_read_unlock(); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (!fence) 12148c2ecf20Sopenharmony_ci return 0; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (!timeout) { 12178c2ecf20Sopenharmony_ci /* No timeout was requested: just test for completion */ 12188c2ecf20Sopenharmony_ci ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY; 12198c2ecf20Sopenharmony_ci } else { 12208c2ecf20Sopenharmony_ci unsigned long remaining = etnaviv_timeout_to_jiffies(timeout); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci ret = dma_fence_wait_timeout(fence, true, remaining); 12238c2ecf20Sopenharmony_ci if (ret == 0) 12248c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 12258c2ecf20Sopenharmony_ci else if (ret != -ERESTARTSYS) 12268c2ecf20Sopenharmony_ci ret = 0; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci dma_fence_put(fence); 12318c2ecf20Sopenharmony_ci return ret; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci/* 12358c2ecf20Sopenharmony_ci * Wait for an object to become inactive. This, on it's own, is not race 12368c2ecf20Sopenharmony_ci * free: the object is moved by the scheduler off the active list, and 12378c2ecf20Sopenharmony_ci * then the iova is put. Moreover, the object could be re-submitted just 12388c2ecf20Sopenharmony_ci * after we notice that it's become inactive. 12398c2ecf20Sopenharmony_ci * 12408c2ecf20Sopenharmony_ci * Although the retirement happens under the gpu lock, we don't want to hold 12418c2ecf20Sopenharmony_ci * that lock in this function while waiting. 12428c2ecf20Sopenharmony_ci */ 12438c2ecf20Sopenharmony_ciint etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, 12448c2ecf20Sopenharmony_ci struct etnaviv_gem_object *etnaviv_obj, 12458c2ecf20Sopenharmony_ci struct drm_etnaviv_timespec *timeout) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci unsigned long remaining; 12488c2ecf20Sopenharmony_ci long ret; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (!timeout) 12518c2ecf20Sopenharmony_ci return !is_active(etnaviv_obj) ? 0 : -EBUSY; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci remaining = etnaviv_timeout_to_jiffies(timeout); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(gpu->fence_event, 12568c2ecf20Sopenharmony_ci !is_active(etnaviv_obj), 12578c2ecf20Sopenharmony_ci remaining); 12588c2ecf20Sopenharmony_ci if (ret > 0) 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci else if (ret == -ERESTARTSYS) 12618c2ecf20Sopenharmony_ci return -ERESTARTSYS; 12628c2ecf20Sopenharmony_ci else 12638c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cistatic void sync_point_perfmon_sample(struct etnaviv_gpu *gpu, 12678c2ecf20Sopenharmony_ci struct etnaviv_event *event, unsigned int flags) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci const struct etnaviv_gem_submit *submit = event->submit; 12708c2ecf20Sopenharmony_ci unsigned int i; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci for (i = 0; i < submit->nr_pmrs; i++) { 12738c2ecf20Sopenharmony_ci const struct etnaviv_perfmon_request *pmr = submit->pmrs + i; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (pmr->flags == flags) 12768c2ecf20Sopenharmony_ci etnaviv_perfmon_process(gpu, pmr, submit->exec_state); 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu, 12818c2ecf20Sopenharmony_ci struct etnaviv_event *event) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci u32 val; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* disable clock gating */ 12868c2ecf20Sopenharmony_ci val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); 12878c2ecf20Sopenharmony_ci val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; 12888c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* enable debug register */ 12918c2ecf20Sopenharmony_ci val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 12928c2ecf20Sopenharmony_ci val &= ~VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS; 12938c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_PRE); 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, 12998c2ecf20Sopenharmony_ci struct etnaviv_event *event) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci const struct etnaviv_gem_submit *submit = event->submit; 13028c2ecf20Sopenharmony_ci unsigned int i; 13038c2ecf20Sopenharmony_ci u32 val; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_POST); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci for (i = 0; i < submit->nr_pmrs; i++) { 13088c2ecf20Sopenharmony_ci const struct etnaviv_perfmon_request *pmr = submit->pmrs + i; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci *pmr->bo_vma = pmr->sequence; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* disable debug register */ 13148c2ecf20Sopenharmony_ci val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 13158c2ecf20Sopenharmony_ci val |= VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS; 13168c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci /* enable clock gating */ 13198c2ecf20Sopenharmony_ci val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); 13208c2ecf20Sopenharmony_ci val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; 13218c2ecf20Sopenharmony_ci gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci/* add bo's to gpu's ring, and kick gpu: */ 13268c2ecf20Sopenharmony_cistruct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = submit->gpu; 13298c2ecf20Sopenharmony_ci struct dma_fence *gpu_fence; 13308c2ecf20Sopenharmony_ci unsigned int i, nr_events = 1, event[3]; 13318c2ecf20Sopenharmony_ci int ret; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (!submit->runtime_resumed) { 13348c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(gpu->dev); 13358c2ecf20Sopenharmony_ci if (ret < 0) { 13368c2ecf20Sopenharmony_ci pm_runtime_put_noidle(gpu->dev); 13378c2ecf20Sopenharmony_ci return NULL; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci submit->runtime_resumed = true; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* 13438c2ecf20Sopenharmony_ci * if there are performance monitor requests we need to have 13448c2ecf20Sopenharmony_ci * - a sync point to re-configure gpu and process ETNA_PM_PROCESS_PRE 13458c2ecf20Sopenharmony_ci * requests. 13468c2ecf20Sopenharmony_ci * - a sync point to re-configure gpu, process ETNA_PM_PROCESS_POST requests 13478c2ecf20Sopenharmony_ci * and update the sequence number for userspace. 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci if (submit->nr_pmrs) 13508c2ecf20Sopenharmony_ci nr_events = 3; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci ret = event_alloc(gpu, nr_events, event); 13538c2ecf20Sopenharmony_ci if (ret) { 13548c2ecf20Sopenharmony_ci DRM_ERROR("no free events\n"); 13558c2ecf20Sopenharmony_ci pm_runtime_put_noidle(gpu->dev); 13568c2ecf20Sopenharmony_ci return NULL; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci gpu_fence = etnaviv_gpu_fence_alloc(gpu); 13628c2ecf20Sopenharmony_ci if (!gpu_fence) { 13638c2ecf20Sopenharmony_ci for (i = 0; i < nr_events; i++) 13648c2ecf20Sopenharmony_ci event_free(gpu, event[i]); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci goto out_unlock; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (!gpu->fe_running) 13708c2ecf20Sopenharmony_ci etnaviv_gpu_start_fe_idleloop(gpu, submit->mmu_context); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (submit->prev_mmu_context) 13738c2ecf20Sopenharmony_ci etnaviv_iommu_context_put(submit->prev_mmu_context); 13748c2ecf20Sopenharmony_ci submit->prev_mmu_context = etnaviv_iommu_context_get(gpu->mmu_context); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (submit->nr_pmrs) { 13778c2ecf20Sopenharmony_ci gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; 13788c2ecf20Sopenharmony_ci kref_get(&submit->refcount); 13798c2ecf20Sopenharmony_ci gpu->event[event[1]].submit = submit; 13808c2ecf20Sopenharmony_ci etnaviv_sync_point_queue(gpu, event[1]); 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci gpu->event[event[0]].fence = gpu_fence; 13848c2ecf20Sopenharmony_ci submit->cmdbuf.user_size = submit->cmdbuf.size - 8; 13858c2ecf20Sopenharmony_ci etnaviv_buffer_queue(gpu, submit->exec_state, submit->mmu_context, 13868c2ecf20Sopenharmony_ci event[0], &submit->cmdbuf); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (submit->nr_pmrs) { 13898c2ecf20Sopenharmony_ci gpu->event[event[2]].sync_point = &sync_point_perfmon_sample_post; 13908c2ecf20Sopenharmony_ci kref_get(&submit->refcount); 13918c2ecf20Sopenharmony_ci gpu->event[event[2]].submit = submit; 13928c2ecf20Sopenharmony_ci etnaviv_sync_point_queue(gpu, event[2]); 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ciout_unlock: 13968c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci return gpu_fence; 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic void sync_point_worker(struct work_struct *work) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, 14048c2ecf20Sopenharmony_ci sync_point_work); 14058c2ecf20Sopenharmony_ci struct etnaviv_event *event = &gpu->event[gpu->sync_point_event]; 14068c2ecf20Sopenharmony_ci u32 addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci event->sync_point(gpu, event); 14098c2ecf20Sopenharmony_ci etnaviv_submit_put(event->submit); 14108c2ecf20Sopenharmony_ci event_free(gpu, gpu->sync_point_event); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* restart FE last to avoid GPU and IRQ racing against this worker */ 14138c2ecf20Sopenharmony_ci etnaviv_gpu_start_fe(gpu, addr + 2, 2); 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic void dump_mmu_fault(struct etnaviv_gpu *gpu) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci u32 status_reg, status; 14198c2ecf20Sopenharmony_ci int i; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (gpu->sec_mode == ETNA_SEC_NONE) 14228c2ecf20Sopenharmony_ci status_reg = VIVS_MMUv2_STATUS; 14238c2ecf20Sopenharmony_ci else 14248c2ecf20Sopenharmony_ci status_reg = VIVS_MMUv2_SEC_STATUS; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci status = gpu_read(gpu, status_reg); 14278c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev, "MMU fault status 0x%08x\n", status); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 14308c2ecf20Sopenharmony_ci u32 address_reg; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (!(status & (VIVS_MMUv2_STATUS_EXCEPTION0__MASK << (i * 4)))) 14338c2ecf20Sopenharmony_ci continue; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (gpu->sec_mode == ETNA_SEC_NONE) 14368c2ecf20Sopenharmony_ci address_reg = VIVS_MMUv2_EXCEPTION_ADDR(i); 14378c2ecf20Sopenharmony_ci else 14388c2ecf20Sopenharmony_ci address_reg = VIVS_MMUv2_SEC_EXCEPTION_ADDR; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev, "MMU %d fault addr 0x%08x\n", i, 14418c2ecf20Sopenharmony_ci gpu_read(gpu, address_reg)); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic irqreturn_t irq_handler(int irq, void *data) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = data; 14488c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (intr != 0) { 14538c2ecf20Sopenharmony_ci int event; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci dev_dbg(gpu->dev, "intr 0x%08x\n", intr); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) { 14608c2ecf20Sopenharmony_ci dev_err(gpu->dev, "AXI bus error\n"); 14618c2ecf20Sopenharmony_ci intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (intr & VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION) { 14658c2ecf20Sopenharmony_ci dump_mmu_fault(gpu); 14668c2ecf20Sopenharmony_ci intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci while ((event = ffs(intr)) != 0) { 14708c2ecf20Sopenharmony_ci struct dma_fence *fence; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci event -= 1; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci intr &= ~(1 << event); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci dev_dbg(gpu->dev, "event %u\n", event); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (gpu->event[event].sync_point) { 14798c2ecf20Sopenharmony_ci gpu->sync_point_event = event; 14808c2ecf20Sopenharmony_ci queue_work(gpu->wq, &gpu->sync_point_work); 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci fence = gpu->event[event].fence; 14848c2ecf20Sopenharmony_ci if (!fence) 14858c2ecf20Sopenharmony_ci continue; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci gpu->event[event].fence = NULL; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* 14908c2ecf20Sopenharmony_ci * Events can be processed out of order. Eg, 14918c2ecf20Sopenharmony_ci * - allocate and queue event 0 14928c2ecf20Sopenharmony_ci * - allocate event 1 14938c2ecf20Sopenharmony_ci * - event 0 completes, we process it 14948c2ecf20Sopenharmony_ci * - allocate and queue event 0 14958c2ecf20Sopenharmony_ci * - event 1 and event 0 complete 14968c2ecf20Sopenharmony_ci * we can end up processing event 0 first, then 1. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci if (fence_after(fence->seqno, gpu->completed_fence)) 14998c2ecf20Sopenharmony_ci gpu->completed_fence = fence->seqno; 15008c2ecf20Sopenharmony_ci dma_fence_signal(fence); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci event_free(gpu, event); 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return ret; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci int ret; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci ret = clk_prepare_enable(gpu->clk_reg); 15168c2ecf20Sopenharmony_ci if (ret) 15178c2ecf20Sopenharmony_ci return ret; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci ret = clk_prepare_enable(gpu->clk_bus); 15208c2ecf20Sopenharmony_ci if (ret) 15218c2ecf20Sopenharmony_ci goto disable_clk_reg; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci ret = clk_prepare_enable(gpu->clk_core); 15248c2ecf20Sopenharmony_ci if (ret) 15258c2ecf20Sopenharmony_ci goto disable_clk_bus; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci ret = clk_prepare_enable(gpu->clk_shader); 15288c2ecf20Sopenharmony_ci if (ret) 15298c2ecf20Sopenharmony_ci goto disable_clk_core; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci return 0; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cidisable_clk_core: 15348c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_core); 15358c2ecf20Sopenharmony_cidisable_clk_bus: 15368c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_bus); 15378c2ecf20Sopenharmony_cidisable_clk_reg: 15388c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_reg); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return ret; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_shader); 15468c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_core); 15478c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_bus); 15488c2ecf20Sopenharmony_ci clk_disable_unprepare(gpu->clk_reg); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci return 0; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ciint etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci do { 15588c2ecf20Sopenharmony_ci u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if ((idle & gpu->idle_mask) == gpu->idle_mask) 15618c2ecf20Sopenharmony_ci return 0; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (time_is_before_jiffies(timeout)) { 15648c2ecf20Sopenharmony_ci dev_warn(gpu->dev, 15658c2ecf20Sopenharmony_ci "timed out waiting for idle: idle=0x%x\n", 15668c2ecf20Sopenharmony_ci idle); 15678c2ecf20Sopenharmony_ci return -ETIMEDOUT; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci udelay(5); 15718c2ecf20Sopenharmony_ci } while (1); 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_cistatic int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci if (gpu->initialized && gpu->fe_running) { 15778c2ecf20Sopenharmony_ci /* Replace the last WAIT with END */ 15788c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 15798c2ecf20Sopenharmony_ci etnaviv_buffer_end(gpu); 15808c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* 15838c2ecf20Sopenharmony_ci * We know that only the FE is busy here, this should 15848c2ecf20Sopenharmony_ci * happen quickly (as the WAIT is only 200 cycles). If 15858c2ecf20Sopenharmony_ci * we fail, just warn and continue. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci etnaviv_gpu_wait_idle(gpu, 100); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci gpu->fe_running = false; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci gpu->exec_state = -1; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci return etnaviv_gpu_clk_disable(gpu); 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 15988c2ecf20Sopenharmony_cistatic int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci int ret; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci ret = mutex_lock_killable(&gpu->lock); 16038c2ecf20Sopenharmony_ci if (ret) 16048c2ecf20Sopenharmony_ci return ret; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci etnaviv_gpu_update_clock(gpu); 16078c2ecf20Sopenharmony_ci etnaviv_gpu_hw_init(gpu); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return 0; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci#endif 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic int 16168c2ecf20Sopenharmony_cietnaviv_gpu_cooling_get_max_state(struct thermal_cooling_device *cdev, 16178c2ecf20Sopenharmony_ci unsigned long *state) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci *state = 6; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci return 0; 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_cistatic int 16258c2ecf20Sopenharmony_cietnaviv_gpu_cooling_get_cur_state(struct thermal_cooling_device *cdev, 16268c2ecf20Sopenharmony_ci unsigned long *state) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = cdev->devdata; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci *state = gpu->freq_scale; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci return 0; 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_cistatic int 16368c2ecf20Sopenharmony_cietnaviv_gpu_cooling_set_cur_state(struct thermal_cooling_device *cdev, 16378c2ecf20Sopenharmony_ci unsigned long state) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = cdev->devdata; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci mutex_lock(&gpu->lock); 16428c2ecf20Sopenharmony_ci gpu->freq_scale = state; 16438c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(gpu->dev)) 16448c2ecf20Sopenharmony_ci etnaviv_gpu_update_clock(gpu); 16458c2ecf20Sopenharmony_ci mutex_unlock(&gpu->lock); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return 0; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic struct thermal_cooling_device_ops cooling_ops = { 16518c2ecf20Sopenharmony_ci .get_max_state = etnaviv_gpu_cooling_get_max_state, 16528c2ecf20Sopenharmony_ci .get_cur_state = etnaviv_gpu_cooling_get_cur_state, 16538c2ecf20Sopenharmony_ci .set_cur_state = etnaviv_gpu_cooling_set_cur_state, 16548c2ecf20Sopenharmony_ci}; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic int etnaviv_gpu_bind(struct device *dev, struct device *master, 16578c2ecf20Sopenharmony_ci void *data) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct drm_device *drm = data; 16608c2ecf20Sopenharmony_ci struct etnaviv_drm_private *priv = drm->dev_private; 16618c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = dev_get_drvdata(dev); 16628c2ecf20Sopenharmony_ci int ret; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) { 16658c2ecf20Sopenharmony_ci gpu->cooling = thermal_of_cooling_device_register(dev->of_node, 16668c2ecf20Sopenharmony_ci (char *)dev_name(dev), gpu, &cooling_ops); 16678c2ecf20Sopenharmony_ci if (IS_ERR(gpu->cooling)) 16688c2ecf20Sopenharmony_ci return PTR_ERR(gpu->cooling); 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci gpu->wq = alloc_ordered_workqueue(dev_name(dev), 0); 16728c2ecf20Sopenharmony_ci if (!gpu->wq) { 16738c2ecf20Sopenharmony_ci ret = -ENOMEM; 16748c2ecf20Sopenharmony_ci goto out_thermal; 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci ret = etnaviv_sched_init(gpu); 16788c2ecf20Sopenharmony_ci if (ret) 16798c2ecf20Sopenharmony_ci goto out_workqueue; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16828c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(gpu->dev); 16838c2ecf20Sopenharmony_ci#else 16848c2ecf20Sopenharmony_ci ret = etnaviv_gpu_clk_enable(gpu); 16858c2ecf20Sopenharmony_ci#endif 16868c2ecf20Sopenharmony_ci if (ret < 0) 16878c2ecf20Sopenharmony_ci goto out_sched; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci gpu->drm = drm; 16918c2ecf20Sopenharmony_ci gpu->fence_context = dma_fence_context_alloc(1); 16928c2ecf20Sopenharmony_ci idr_init(&gpu->fence_idr); 16938c2ecf20Sopenharmony_ci spin_lock_init(&gpu->fence_spinlock); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci INIT_WORK(&gpu->sync_point_work, sync_point_worker); 16968c2ecf20Sopenharmony_ci init_waitqueue_head(&gpu->fence_event); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci priv->gpu[priv->num_gpus++] = gpu; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(gpu->dev); 17018c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(gpu->dev); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci return 0; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ciout_sched: 17068c2ecf20Sopenharmony_ci etnaviv_sched_fini(gpu); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ciout_workqueue: 17098c2ecf20Sopenharmony_ci destroy_workqueue(gpu->wq); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ciout_thermal: 17128c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) 17138c2ecf20Sopenharmony_ci thermal_cooling_device_unregister(gpu->cooling); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci return ret; 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic void etnaviv_gpu_unbind(struct device *dev, struct device *master, 17198c2ecf20Sopenharmony_ci void *data) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = dev_get_drvdata(dev); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci DBG("%s", dev_name(gpu->dev)); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci flush_workqueue(gpu->wq); 17268c2ecf20Sopenharmony_ci destroy_workqueue(gpu->wq); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci etnaviv_sched_fini(gpu); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 17318c2ecf20Sopenharmony_ci pm_runtime_get_sync(gpu->dev); 17328c2ecf20Sopenharmony_ci pm_runtime_put_sync_suspend(gpu->dev); 17338c2ecf20Sopenharmony_ci#else 17348c2ecf20Sopenharmony_ci etnaviv_gpu_hw_suspend(gpu); 17358c2ecf20Sopenharmony_ci#endif 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (gpu->mmu_context) 17388c2ecf20Sopenharmony_ci etnaviv_iommu_context_put(gpu->mmu_context); 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (gpu->initialized) { 17418c2ecf20Sopenharmony_ci etnaviv_cmdbuf_free(&gpu->buffer); 17428c2ecf20Sopenharmony_ci etnaviv_iommu_global_fini(gpu); 17438c2ecf20Sopenharmony_ci gpu->initialized = false; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci gpu->drm = NULL; 17478c2ecf20Sopenharmony_ci idr_destroy(&gpu->fence_idr); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) 17508c2ecf20Sopenharmony_ci thermal_cooling_device_unregister(gpu->cooling); 17518c2ecf20Sopenharmony_ci gpu->cooling = NULL; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic const struct component_ops gpu_ops = { 17558c2ecf20Sopenharmony_ci .bind = etnaviv_gpu_bind, 17568c2ecf20Sopenharmony_ci .unbind = etnaviv_gpu_unbind, 17578c2ecf20Sopenharmony_ci}; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic const struct of_device_id etnaviv_gpu_match[] = { 17608c2ecf20Sopenharmony_ci { 17618c2ecf20Sopenharmony_ci .compatible = "vivante,gc" 17628c2ecf20Sopenharmony_ci }, 17638c2ecf20Sopenharmony_ci { /* sentinel */ } 17648c2ecf20Sopenharmony_ci}; 17658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, etnaviv_gpu_match); 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_cistatic int etnaviv_gpu_platform_probe(struct platform_device *pdev) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 17708c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu; 17718c2ecf20Sopenharmony_ci int err; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL); 17748c2ecf20Sopenharmony_ci if (!gpu) 17758c2ecf20Sopenharmony_ci return -ENOMEM; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci gpu->dev = &pdev->dev; 17788c2ecf20Sopenharmony_ci mutex_init(&gpu->lock); 17798c2ecf20Sopenharmony_ci mutex_init(&gpu->fence_lock); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Map registers: */ 17828c2ecf20Sopenharmony_ci gpu->mmio = devm_platform_ioremap_resource(pdev, 0); 17838c2ecf20Sopenharmony_ci if (IS_ERR(gpu->mmio)) 17848c2ecf20Sopenharmony_ci return PTR_ERR(gpu->mmio); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* Get Interrupt: */ 17878c2ecf20Sopenharmony_ci gpu->irq = platform_get_irq(pdev, 0); 17888c2ecf20Sopenharmony_ci if (gpu->irq < 0) { 17898c2ecf20Sopenharmony_ci dev_err(dev, "failed to get irq: %d\n", gpu->irq); 17908c2ecf20Sopenharmony_ci return gpu->irq; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0, 17948c2ecf20Sopenharmony_ci dev_name(gpu->dev), gpu); 17958c2ecf20Sopenharmony_ci if (err) { 17968c2ecf20Sopenharmony_ci dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err); 17978c2ecf20Sopenharmony_ci return err; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci /* Get Clocks: */ 18018c2ecf20Sopenharmony_ci gpu->clk_reg = devm_clk_get_optional(&pdev->dev, "reg"); 18028c2ecf20Sopenharmony_ci DBG("clk_reg: %p", gpu->clk_reg); 18038c2ecf20Sopenharmony_ci if (IS_ERR(gpu->clk_reg)) 18048c2ecf20Sopenharmony_ci return PTR_ERR(gpu->clk_reg); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci gpu->clk_bus = devm_clk_get_optional(&pdev->dev, "bus"); 18078c2ecf20Sopenharmony_ci DBG("clk_bus: %p", gpu->clk_bus); 18088c2ecf20Sopenharmony_ci if (IS_ERR(gpu->clk_bus)) 18098c2ecf20Sopenharmony_ci return PTR_ERR(gpu->clk_bus); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci gpu->clk_core = devm_clk_get(&pdev->dev, "core"); 18128c2ecf20Sopenharmony_ci DBG("clk_core: %p", gpu->clk_core); 18138c2ecf20Sopenharmony_ci if (IS_ERR(gpu->clk_core)) 18148c2ecf20Sopenharmony_ci return PTR_ERR(gpu->clk_core); 18158c2ecf20Sopenharmony_ci gpu->base_rate_core = clk_get_rate(gpu->clk_core); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci gpu->clk_shader = devm_clk_get_optional(&pdev->dev, "shader"); 18188c2ecf20Sopenharmony_ci DBG("clk_shader: %p", gpu->clk_shader); 18198c2ecf20Sopenharmony_ci if (IS_ERR(gpu->clk_shader)) 18208c2ecf20Sopenharmony_ci return PTR_ERR(gpu->clk_shader); 18218c2ecf20Sopenharmony_ci gpu->base_rate_shader = clk_get_rate(gpu->clk_shader); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* TODO: figure out max mapped size */ 18248c2ecf20Sopenharmony_ci dev_set_drvdata(dev, gpu); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* 18278c2ecf20Sopenharmony_ci * We treat the device as initially suspended. The runtime PM 18288c2ecf20Sopenharmony_ci * autosuspend delay is rather arbitary: no measurements have 18298c2ecf20Sopenharmony_ci * yet been performed to determine an appropriate value. 18308c2ecf20Sopenharmony_ci */ 18318c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(gpu->dev); 18328c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(gpu->dev, 200); 18338c2ecf20Sopenharmony_ci pm_runtime_enable(gpu->dev); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci err = component_add(&pdev->dev, &gpu_ops); 18368c2ecf20Sopenharmony_ci if (err < 0) { 18378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register component: %d\n", err); 18388c2ecf20Sopenharmony_ci return err; 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci return 0; 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic int etnaviv_gpu_platform_remove(struct platform_device *pdev) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci component_del(&pdev->dev, &gpu_ops); 18478c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 18488c2ecf20Sopenharmony_ci return 0; 18498c2ecf20Sopenharmony_ci} 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 18528c2ecf20Sopenharmony_cistatic int etnaviv_gpu_rpm_suspend(struct device *dev) 18538c2ecf20Sopenharmony_ci{ 18548c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = dev_get_drvdata(dev); 18558c2ecf20Sopenharmony_ci u32 idle, mask; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci /* If there are any jobs in the HW queue, we're not idle */ 18588c2ecf20Sopenharmony_ci if (atomic_read(&gpu->sched.hw_rq_count)) 18598c2ecf20Sopenharmony_ci return -EBUSY; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* Check whether the hardware (except FE and MC) is idle */ 18628c2ecf20Sopenharmony_ci mask = gpu->idle_mask & ~(VIVS_HI_IDLE_STATE_FE | 18638c2ecf20Sopenharmony_ci VIVS_HI_IDLE_STATE_MC); 18648c2ecf20Sopenharmony_ci idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask; 18658c2ecf20Sopenharmony_ci if (idle != mask) { 18668c2ecf20Sopenharmony_ci dev_warn_ratelimited(dev, "GPU not yet idle, mask: 0x%08x\n", 18678c2ecf20Sopenharmony_ci idle); 18688c2ecf20Sopenharmony_ci return -EBUSY; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci return etnaviv_gpu_hw_suspend(gpu); 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cistatic int etnaviv_gpu_rpm_resume(struct device *dev) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct etnaviv_gpu *gpu = dev_get_drvdata(dev); 18778c2ecf20Sopenharmony_ci int ret; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci ret = etnaviv_gpu_clk_enable(gpu); 18808c2ecf20Sopenharmony_ci if (ret) 18818c2ecf20Sopenharmony_ci return ret; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* Re-initialise the basic hardware state */ 18848c2ecf20Sopenharmony_ci if (gpu->drm && gpu->initialized) { 18858c2ecf20Sopenharmony_ci ret = etnaviv_gpu_hw_resume(gpu); 18868c2ecf20Sopenharmony_ci if (ret) { 18878c2ecf20Sopenharmony_ci etnaviv_gpu_clk_disable(gpu); 18888c2ecf20Sopenharmony_ci return ret; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci return 0; 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci#endif 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic const struct dev_pm_ops etnaviv_gpu_pm_ops = { 18978c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume, 18988c2ecf20Sopenharmony_ci NULL) 18998c2ecf20Sopenharmony_ci}; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistruct platform_driver etnaviv_gpu_driver = { 19028c2ecf20Sopenharmony_ci .driver = { 19038c2ecf20Sopenharmony_ci .name = "etnaviv-gpu", 19048c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19058c2ecf20Sopenharmony_ci .pm = &etnaviv_gpu_pm_ops, 19068c2ecf20Sopenharmony_ci .of_match_table = etnaviv_gpu_match, 19078c2ecf20Sopenharmony_ci }, 19088c2ecf20Sopenharmony_ci .probe = etnaviv_gpu_platform_probe, 19098c2ecf20Sopenharmony_ci .remove = etnaviv_gpu_platform_remove, 19108c2ecf20Sopenharmony_ci .id_table = gpu_ids, 19118c2ecf20Sopenharmony_ci}; 1912