18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci#ifndef __A5XX_GPU_H__ 58c2ecf20Sopenharmony_ci#define __A5XX_GPU_H__ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "adreno_gpu.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* Bringing over the hack from the previous targets */ 108c2ecf20Sopenharmony_ci#undef ROP_COPY 118c2ecf20Sopenharmony_ci#undef ROP_XOR 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "a5xx.xml.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct a5xx_gpu { 168c2ecf20Sopenharmony_ci struct adreno_gpu base; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci struct drm_gem_object *pm4_bo; 198c2ecf20Sopenharmony_ci uint64_t pm4_iova; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci struct drm_gem_object *pfp_bo; 228c2ecf20Sopenharmony_ci uint64_t pfp_iova; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci struct drm_gem_object *gpmu_bo; 258c2ecf20Sopenharmony_ci uint64_t gpmu_iova; 268c2ecf20Sopenharmony_ci uint32_t gpmu_dwords; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci uint32_t lm_leakage; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci struct msm_ringbuffer *cur_ring; 318c2ecf20Sopenharmony_ci struct msm_ringbuffer *next_ring; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS]; 348c2ecf20Sopenharmony_ci struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS]; 358c2ecf20Sopenharmony_ci struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS]; 368c2ecf20Sopenharmony_ci uint64_t preempt_iova[MSM_GPU_MAX_RINGS]; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci atomic_t preempt_state; 398c2ecf20Sopenharmony_ci struct timer_list preempt_timer; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci struct drm_gem_object *shadow_bo; 428c2ecf20Sopenharmony_ci uint64_t shadow_iova; 438c2ecf20Sopenharmony_ci uint32_t *shadow; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* True if the microcode supports the WHERE_AM_I opcode */ 468c2ecf20Sopenharmony_ci bool has_whereami; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 528c2ecf20Sopenharmony_civoid a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor); 538c2ecf20Sopenharmony_ci#endif 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * In order to do lockless preemption we use a simple state machine to progress 578c2ecf20Sopenharmony_ci * through the process. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * PREEMPT_NONE - no preemption in progress. Next state START. 608c2ecf20Sopenharmony_ci * PREEMPT_START - The trigger is evaulating if preemption is possible. Next 618c2ecf20Sopenharmony_ci * states: TRIGGERED, NONE 628c2ecf20Sopenharmony_ci * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next 638c2ecf20Sopenharmony_ci * state: NONE. 648c2ecf20Sopenharmony_ci * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next 658c2ecf20Sopenharmony_ci * states: FAULTED, PENDING 668c2ecf20Sopenharmony_ci * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger 678c2ecf20Sopenharmony_ci * recovery. Next state: N/A 688c2ecf20Sopenharmony_ci * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is 698c2ecf20Sopenharmony_ci * checking the success of the operation. Next state: FAULTED, NONE. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cienum preempt_state { 738c2ecf20Sopenharmony_ci PREEMPT_NONE = 0, 748c2ecf20Sopenharmony_ci PREEMPT_START, 758c2ecf20Sopenharmony_ci PREEMPT_ABORT, 768c2ecf20Sopenharmony_ci PREEMPT_TRIGGERED, 778c2ecf20Sopenharmony_ci PREEMPT_FAULTED, 788c2ecf20Sopenharmony_ci PREEMPT_PENDING, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * struct a5xx_preempt_record is a shared buffer between the microcode and the 838c2ecf20Sopenharmony_ci * CPU to store the state for preemption. The record itself is much larger 848c2ecf20Sopenharmony_ci * (64k) but most of that is used by the CP for storage. 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * There is a preemption record assigned per ringbuffer. When the CPU triggers a 878c2ecf20Sopenharmony_ci * preemption, it fills out the record with the useful information (wptr, ring 888c2ecf20Sopenharmony_ci * base, etc) and the microcode uses that information to set up the CP following 898c2ecf20Sopenharmony_ci * the preemption. When a ring is switched out, the CP will save the ringbuffer 908c2ecf20Sopenharmony_ci * state back to the record. In this way, once the records are properly set up 918c2ecf20Sopenharmony_ci * the CPU can quickly switch back and forth between ringbuffers by only 928c2ecf20Sopenharmony_ci * updating a few registers (often only the wptr). 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * These are the CPU aware registers in the record: 958c2ecf20Sopenharmony_ci * @magic: Must always be 0x27C4BAFC 968c2ecf20Sopenharmony_ci * @info: Type of the record - written 0 by the CPU, updated by the CP 978c2ecf20Sopenharmony_ci * @data: Data field from SET_RENDER_MODE or a checkpoint. Written and used by 988c2ecf20Sopenharmony_ci * the CP 998c2ecf20Sopenharmony_ci * @cntl: Value of RB_CNTL written by CPU, save/restored by CP 1008c2ecf20Sopenharmony_ci * @rptr: Value of RB_RPTR written by CPU, save/restored by CP 1018c2ecf20Sopenharmony_ci * @wptr: Value of RB_WPTR written by CPU, save/restored by CP 1028c2ecf20Sopenharmony_ci * @rptr_addr: Value of RB_RPTR_ADDR written by CPU, save/restored by CP 1038c2ecf20Sopenharmony_ci * @rbase: Value of RB_BASE written by CPU, save/restored by CP 1048c2ecf20Sopenharmony_ci * @counter: GPU address of the storage area for the performance counters 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistruct a5xx_preempt_record { 1078c2ecf20Sopenharmony_ci uint32_t magic; 1088c2ecf20Sopenharmony_ci uint32_t info; 1098c2ecf20Sopenharmony_ci uint32_t data; 1108c2ecf20Sopenharmony_ci uint32_t cntl; 1118c2ecf20Sopenharmony_ci uint32_t rptr; 1128c2ecf20Sopenharmony_ci uint32_t wptr; 1138c2ecf20Sopenharmony_ci uint64_t rptr_addr; 1148c2ecf20Sopenharmony_ci uint64_t rbase; 1158c2ecf20Sopenharmony_ci uint64_t counter; 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Magic identifier for the preemption record */ 1198c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_RECORD_MAGIC 0x27C4BAFCUL 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * Even though the structure above is only a few bytes, we need a full 64k to 1238c2ecf20Sopenharmony_ci * store the entire preemption record from the CP 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_RECORD_SIZE (64 * 1024) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * The preemption counter block is a storage area for the value of the 1298c2ecf20Sopenharmony_ci * preemption counters that are saved immediately before context switch. We 1308c2ecf20Sopenharmony_ci * append it on to the end of the allocation for the preemption record. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_COUNTER_SIZE (16 * 4) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciint a5xx_power_init(struct msm_gpu *gpu); 1368c2ecf20Sopenharmony_civoid a5xx_gpmu_ucode_init(struct msm_gpu *gpu); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline int spin_usecs(struct msm_gpu *gpu, uint32_t usecs, 1398c2ecf20Sopenharmony_ci uint32_t reg, uint32_t mask, uint32_t value) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci while (usecs--) { 1428c2ecf20Sopenharmony_ci udelay(1); 1438c2ecf20Sopenharmony_ci if ((gpu_read(gpu, reg) & mask) == value) 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci cpu_relax(); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define shadowptr(a5xx_gpu, ring) ((a5xx_gpu)->shadow_iova + \ 1528c2ecf20Sopenharmony_ci ((ring)->id * sizeof(uint32_t))) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cibool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); 1558c2ecf20Sopenharmony_civoid a5xx_set_hwcg(struct msm_gpu *gpu, bool state); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_civoid a5xx_preempt_init(struct msm_gpu *gpu); 1588c2ecf20Sopenharmony_civoid a5xx_preempt_hw_init(struct msm_gpu *gpu); 1598c2ecf20Sopenharmony_civoid a5xx_preempt_trigger(struct msm_gpu *gpu); 1608c2ecf20Sopenharmony_civoid a5xx_preempt_irq(struct msm_gpu *gpu); 1618c2ecf20Sopenharmony_civoid a5xx_preempt_fini(struct msm_gpu *gpu); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_civoid a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, bool sync); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Return true if we are in a preempt state */ 1668c2ecf20Sopenharmony_cistatic inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int preempt_state = atomic_read(&a5xx_gpu->preempt_state); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return !(preempt_state == PREEMPT_NONE || 1718c2ecf20Sopenharmony_ci preempt_state == PREEMPT_ABORT); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#endif /* __A5XX_GPU_H__ */ 175