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 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 88c2ecf20Sopenharmony_ci#include <linux/qcom_scm.h> 98c2ecf20Sopenharmony_ci#include <linux/pm_opp.h> 108c2ecf20Sopenharmony_ci#include <linux/nvmem-consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include "msm_gem.h" 138c2ecf20Sopenharmony_ci#include "msm_mmu.h" 148c2ecf20Sopenharmony_ci#include "a5xx_gpu.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciextern bool hang_debug; 178c2ecf20Sopenharmony_cistatic void a5xx_dump(struct msm_gpu *gpu); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define GPU_PAS_ID 13 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_civoid a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, 228c2ecf20Sopenharmony_ci bool sync) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 258c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 268c2ecf20Sopenharmony_ci uint32_t wptr; 278c2ecf20Sopenharmony_ci unsigned long flags; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* 308c2ecf20Sopenharmony_ci * Most flush operations need to issue a WHERE_AM_I opcode to sync up 318c2ecf20Sopenharmony_ci * the rptr shadow 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci if (a5xx_gpu->has_whereami && sync) { 348c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_WHERE_AM_I, 2); 358c2ecf20Sopenharmony_ci OUT_RING(ring, lower_32_bits(shadowptr(a5xx_gpu, ring))); 368c2ecf20Sopenharmony_ci OUT_RING(ring, upper_32_bits(shadowptr(a5xx_gpu, ring))); 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci spin_lock_irqsave(&ring->preempt_lock, flags); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Copy the shadow to the actual register */ 428c2ecf20Sopenharmony_ci ring->cur = ring->next; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Make sure to wrap wptr if we need to */ 458c2ecf20Sopenharmony_ci wptr = get_wptr(ring); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ring->preempt_lock, flags); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Make sure everything is posted before making a decision */ 508c2ecf20Sopenharmony_ci mb(); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Update HW if this is the current ring and we are not in preempt */ 538c2ecf20Sopenharmony_ci if (a5xx_gpu->cur_ring == ring && !a5xx_in_preempt(a5xx_gpu)) 548c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct msm_drm_private *priv = gpu->dev->dev_private; 608c2ecf20Sopenharmony_ci struct msm_ringbuffer *ring = submit->ring; 618c2ecf20Sopenharmony_ci struct msm_gem_object *obj; 628c2ecf20Sopenharmony_ci uint32_t *ptr, dwords; 638c2ecf20Sopenharmony_ci unsigned int i; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (i = 0; i < submit->nr_cmds; i++) { 668c2ecf20Sopenharmony_ci switch (submit->cmd[i].type) { 678c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_IB_TARGET_BUF: 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 708c2ecf20Sopenharmony_ci if (priv->lastctx == submit->queue->ctx) 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci fallthrough; 738c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_BUF: 748c2ecf20Sopenharmony_ci /* copy commands into RB: */ 758c2ecf20Sopenharmony_ci obj = submit->bos[submit->cmd[i].idx].obj; 768c2ecf20Sopenharmony_ci dwords = submit->cmd[i].size; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ptr = msm_gem_get_vaddr(&obj->base); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* _get_vaddr() shouldn't fail at this point, 818c2ecf20Sopenharmony_ci * since we've already mapped it once in 828c2ecf20Sopenharmony_ci * submit_reloc() 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci if (WARN_ON(IS_ERR_OR_NULL(ptr))) 858c2ecf20Sopenharmony_ci return; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < dwords; i++) { 888c2ecf20Sopenharmony_ci /* normally the OUT_PKTn() would wait 898c2ecf20Sopenharmony_ci * for space for the packet. But since 908c2ecf20Sopenharmony_ci * we just OUT_RING() the whole thing, 918c2ecf20Sopenharmony_ci * need to call adreno_wait_ring() 928c2ecf20Sopenharmony_ci * ourself: 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci adreno_wait_ring(ring, 1); 958c2ecf20Sopenharmony_ci OUT_RING(ring, ptr[i]); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci msm_gem_put_vaddr(&obj->base); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci a5xx_flush(gpu, ring, true); 1058c2ecf20Sopenharmony_ci a5xx_preempt_trigger(gpu); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* we might not necessarily have a cmd from userspace to 1088c2ecf20Sopenharmony_ci * trigger an event to know that submit has completed, so 1098c2ecf20Sopenharmony_ci * do this manually: 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci a5xx_idle(gpu, ring); 1128c2ecf20Sopenharmony_ci ring->memptrs->fence = submit->seqno; 1138c2ecf20Sopenharmony_ci msm_gpu_retire(gpu); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 1198c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 1208c2ecf20Sopenharmony_ci struct msm_drm_private *priv = gpu->dev->dev_private; 1218c2ecf20Sopenharmony_ci struct msm_ringbuffer *ring = submit->ring; 1228c2ecf20Sopenharmony_ci unsigned int i, ibs = 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { 1258c2ecf20Sopenharmony_ci priv->lastctx = NULL; 1268c2ecf20Sopenharmony_ci a5xx_submit_in_rb(gpu, submit); 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); 1318c2ecf20Sopenharmony_ci OUT_RING(ring, 0x02); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Turn off protected mode to write to special registers */ 1348c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 1358c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Set the save preemption record for the ring/command */ 1388c2ecf20Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); 1398c2ecf20Sopenharmony_ci OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[submit->ring->id])); 1408c2ecf20Sopenharmony_ci OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[submit->ring->id])); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* Turn back on protected mode */ 1438c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 1448c2ecf20Sopenharmony_ci OUT_RING(ring, 1); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Enable local preemption for finegrain preemption */ 1478c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); 1488c2ecf20Sopenharmony_ci OUT_RING(ring, 0x1); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */ 1518c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 1528c2ecf20Sopenharmony_ci OUT_RING(ring, 0x02); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Submit the commands */ 1558c2ecf20Sopenharmony_ci for (i = 0; i < submit->nr_cmds; i++) { 1568c2ecf20Sopenharmony_ci switch (submit->cmd[i].type) { 1578c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_IB_TARGET_BUF: 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 1608c2ecf20Sopenharmony_ci if (priv->lastctx == submit->queue->ctx) 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci fallthrough; 1638c2ecf20Sopenharmony_ci case MSM_SUBMIT_CMD_BUF: 1648c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3); 1658c2ecf20Sopenharmony_ci OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); 1668c2ecf20Sopenharmony_ci OUT_RING(ring, upper_32_bits(submit->cmd[i].iova)); 1678c2ecf20Sopenharmony_ci OUT_RING(ring, submit->cmd[i].size); 1688c2ecf20Sopenharmony_ci ibs++; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * Write the render mode to NULL (0) to indicate to the CP that the IBs 1758c2ecf20Sopenharmony_ci * are done rendering - otherwise a lucky preemption would start 1768c2ecf20Sopenharmony_ci * replaying from the last checkpoint 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_SET_RENDER_MODE, 5); 1798c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1808c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1818c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1828c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1838c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Turn off IB level preemptions */ 1868c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 1878c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Write the fence to the scratch register */ 1908c2ecf20Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_SCRATCH_REG(2), 1); 1918c2ecf20Sopenharmony_ci OUT_RING(ring, submit->seqno); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Execute a CACHE_FLUSH_TS event. This will ensure that the 1958c2ecf20Sopenharmony_ci * timestamp is written to the memory and then triggers the interrupt 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_EVENT_WRITE, 4); 1988c2ecf20Sopenharmony_ci OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS) | 1998c2ecf20Sopenharmony_ci CP_EVENT_WRITE_0_IRQ); 2008c2ecf20Sopenharmony_ci OUT_RING(ring, lower_32_bits(rbmemptr(ring, fence))); 2018c2ecf20Sopenharmony_ci OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence))); 2028c2ecf20Sopenharmony_ci OUT_RING(ring, submit->seqno); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Yield the floor on command completion */ 2058c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * If dword[2:1] are non zero, they specify an address for the CP to 2088c2ecf20Sopenharmony_ci * write the value of dword[3] to on preemption complete. Write 0 to 2098c2ecf20Sopenharmony_ci * skip the write 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00); 2128c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00); 2138c2ecf20Sopenharmony_ci /* Data value - not used if the address above is 0 */ 2148c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 2158c2ecf20Sopenharmony_ci /* Set bit 0 to trigger an interrupt on preempt complete */ 2168c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* A WHERE_AM_I packet is not needed after a YIELD */ 2198c2ecf20Sopenharmony_ci a5xx_flush(gpu, ring, false); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Check to see if we need to start preemption */ 2228c2ecf20Sopenharmony_ci a5xx_preempt_trigger(gpu); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const struct { 2268c2ecf20Sopenharmony_ci u32 offset; 2278c2ecf20Sopenharmony_ci u32 value; 2288c2ecf20Sopenharmony_ci} a5xx_hwcg[] = { 2298c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP0, 0x02222222}, 2308c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP1, 0x02222222}, 2318c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP2, 0x02222222}, 2328c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP3, 0x02222222}, 2338c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220}, 2348c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP1, 0x02222220}, 2358c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP2, 0x02222220}, 2368c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP3, 0x02222220}, 2378c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF}, 2388c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP1, 0x0000F3CF}, 2398c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP2, 0x0000F3CF}, 2408c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP3, 0x0000F3CF}, 2418c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP0, 0x00000080}, 2428c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP1, 0x00000080}, 2438c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP2, 0x00000080}, 2448c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP3, 0x00000080}, 2458c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP0, 0x22222222}, 2468c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP1, 0x22222222}, 2478c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP2, 0x22222222}, 2488c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP3, 0x22222222}, 2498c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222}, 2508c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222}, 2518c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP2, 0x22222222}, 2528c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP3, 0x22222222}, 2538c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP0, 0x00002222}, 2548c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP1, 0x00002222}, 2558c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP2, 0x00002222}, 2568c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP3, 0x00002222}, 2578c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP0, 0x77777777}, 2588c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP1, 0x77777777}, 2598c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP2, 0x77777777}, 2608c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP3, 0x77777777}, 2618c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP0, 0x77777777}, 2628c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP1, 0x77777777}, 2638c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP2, 0x77777777}, 2648c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP3, 0x77777777}, 2658c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP0, 0x00007777}, 2668c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP1, 0x00007777}, 2678c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP2, 0x00007777}, 2688c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP3, 0x00007777}, 2698c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP0, 0x11111111}, 2708c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP1, 0x11111111}, 2718c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP2, 0x11111111}, 2728c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP3, 0x11111111}, 2738c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111}, 2748c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP1, 0x11111111}, 2758c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP2, 0x11111111}, 2768c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP3, 0x11111111}, 2778c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP0, 0x00001111}, 2788c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP1, 0x00001111}, 2798c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP2, 0x00001111}, 2808c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP3, 0x00001111}, 2818c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222}, 2828c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222}, 2838c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222}, 2848c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222}, 2858c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_UCHE, 0x00444444}, 2868c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002}, 2878c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB0, 0x22222222}, 2888c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB1, 0x22222222}, 2898c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB2, 0x22222222}, 2908c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB3, 0x22222222}, 2918c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB0, 0x00222222}, 2928c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB1, 0x00222222}, 2938c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB2, 0x00222222}, 2948c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB3, 0x00222222}, 2958c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU0, 0x00022220}, 2968c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU1, 0x00022220}, 2978c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU2, 0x00022220}, 2988c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU3, 0x00022220}, 2998c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RAC, 0x05522222}, 3008c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RAC, 0x00505555}, 3018c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0, 0x04040404}, 3028c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1, 0x04040404}, 3038c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU2, 0x04040404}, 3048c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU3, 0x04040404}, 3058c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RAC, 0x07444044}, 3068c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0, 0x00000002}, 3078c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1, 0x00000002}, 3088c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_2, 0x00000002}, 3098c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_3, 0x00000002}, 3108c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RAC, 0x00010011}, 3118c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222}, 3128c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_GPC, 0x02222222}, 3138c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_VFD, 0x00002222}, 3148c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000}, 3158c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_GPC, 0x04104004}, 3168c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_VFD, 0x00000000}, 3178c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000}, 3188c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000}, 3198c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_GPC, 0x00000200}, 3208c2ecf20Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_VFD, 0x00002222} 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_civoid a5xx_set_hwcg(struct msm_gpu *gpu, bool state) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 3268c2ecf20Sopenharmony_ci unsigned int i; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hwcg); i++) 3298c2ecf20Sopenharmony_ci gpu_write(gpu, a5xx_hwcg[i].offset, 3308c2ecf20Sopenharmony_ci state ? a5xx_hwcg[i].value : 0); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (adreno_is_a540(adreno_gpu)) { 3338c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_DELAY_GPMU, state ? 0x00000770 : 0); 3348c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_HYST_GPMU, state ? 0x00000004 : 0); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0); 3388c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int a5xx_me_init(struct msm_gpu *gpu) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 3448c2ecf20Sopenharmony_ci struct msm_ringbuffer *ring = gpu->rb[0]; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_ME_INIT, 8); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci OUT_RING(ring, 0x0000002F); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Enable multiple hardware contexts */ 3518c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000003); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Enable error detection */ 3548c2ecf20Sopenharmony_ci OUT_RING(ring, 0x20000000); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Don't enable header dump */ 3578c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000000); 3588c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000000); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Specify workarounds for various microcode issues */ 3618c2ecf20Sopenharmony_ci if (adreno_is_a530(adreno_gpu)) { 3628c2ecf20Sopenharmony_ci /* Workaround for token end syncs 3638c2ecf20Sopenharmony_ci * Force a WFI after every direct-render 3D mode draw and every 3648c2ecf20Sopenharmony_ci * 2D mode 3 draw 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci OUT_RING(ring, 0x0000000B); 3678c2ecf20Sopenharmony_ci } else if (adreno_is_a510(adreno_gpu)) { 3688c2ecf20Sopenharmony_ci /* Workaround for token and syncs */ 3698c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000001); 3708c2ecf20Sopenharmony_ci } else { 3718c2ecf20Sopenharmony_ci /* No workarounds enabled */ 3728c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000000); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000000); 3768c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00000000); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci a5xx_flush(gpu, ring, true); 3798c2ecf20Sopenharmony_ci return a5xx_idle(gpu, ring) ? 0 : -EINVAL; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int a5xx_preempt_start(struct msm_gpu *gpu) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 3858c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 3868c2ecf20Sopenharmony_ci struct msm_ringbuffer *ring = gpu->rb[0]; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (gpu->nr_rings == 1) 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Turn off protected mode to write to special registers */ 3928c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 3938c2ecf20Sopenharmony_ci OUT_RING(ring, 0); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Set the save preemption record for the ring/command */ 3968c2ecf20Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); 3978c2ecf20Sopenharmony_ci OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[ring->id])); 3988c2ecf20Sopenharmony_ci OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[ring->id])); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Turn back on protected mode */ 4018c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 4028c2ecf20Sopenharmony_ci OUT_RING(ring, 1); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); 4058c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); 4088c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 4118c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* Yield the floor on command completion */ 4148c2ecf20Sopenharmony_ci OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); 4158c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00); 4168c2ecf20Sopenharmony_ci OUT_RING(ring, 0x00); 4178c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 4188c2ecf20Sopenharmony_ci OUT_RING(ring, 0x01); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* The WHERE_AMI_I packet is not needed after a YIELD is issued */ 4218c2ecf20Sopenharmony_ci a5xx_flush(gpu, ring, false); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return a5xx_idle(gpu, ring) ? 0 : -EINVAL; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void a5xx_ucode_check_version(struct a5xx_gpu *a5xx_gpu, 4278c2ecf20Sopenharmony_ci struct drm_gem_object *obj) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci u32 *buf = msm_gem_get_vaddr_active(obj); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 4328c2ecf20Sopenharmony_ci return; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* 4358c2ecf20Sopenharmony_ci * If the lowest nibble is 0xa that is an indication that this microcode 4368c2ecf20Sopenharmony_ci * has been patched. The actual version is in dword [3] but we only care 4378c2ecf20Sopenharmony_ci * about the patchlevel which is the lowest nibble of dword [3] 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci if (((buf[0] & 0xf) == 0xa) && (buf[2] & 0xf) >= 1) 4408c2ecf20Sopenharmony_ci a5xx_gpu->has_whereami = true; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci msm_gem_put_vaddr(obj); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int a5xx_ucode_init(struct msm_gpu *gpu) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 4488c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 4498c2ecf20Sopenharmony_ci int ret; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!a5xx_gpu->pm4_bo) { 4528c2ecf20Sopenharmony_ci a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu, 4538c2ecf20Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (IS_ERR(a5xx_gpu->pm4_bo)) { 4578c2ecf20Sopenharmony_ci ret = PTR_ERR(a5xx_gpu->pm4_bo); 4588c2ecf20Sopenharmony_ci a5xx_gpu->pm4_bo = NULL; 4598c2ecf20Sopenharmony_ci DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PM4: %d\n", 4608c2ecf20Sopenharmony_ci ret); 4618c2ecf20Sopenharmony_ci return ret; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci msm_gem_object_set_name(a5xx_gpu->pm4_bo, "pm4fw"); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (!a5xx_gpu->pfp_bo) { 4688c2ecf20Sopenharmony_ci a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu, 4698c2ecf20Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (IS_ERR(a5xx_gpu->pfp_bo)) { 4728c2ecf20Sopenharmony_ci ret = PTR_ERR(a5xx_gpu->pfp_bo); 4738c2ecf20Sopenharmony_ci a5xx_gpu->pfp_bo = NULL; 4748c2ecf20Sopenharmony_ci DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PFP: %d\n", 4758c2ecf20Sopenharmony_ci ret); 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci msm_gem_object_set_name(a5xx_gpu->pfp_bo, "pfpfw"); 4808c2ecf20Sopenharmony_ci a5xx_ucode_check_version(a5xx_gpu, a5xx_gpu->pfp_bo); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, 4848c2ecf20Sopenharmony_ci REG_A5XX_CP_ME_INSTR_BASE_HI, a5xx_gpu->pm4_iova); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, 4878c2ecf20Sopenharmony_ci REG_A5XX_CP_PFP_INSTR_BASE_HI, a5xx_gpu->pfp_iova); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci#define SCM_GPU_ZAP_SHADER_RESUME 0 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int a5xx_zap_shader_resume(struct msm_gpu *gpu) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci int ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); 4998c2ecf20Sopenharmony_ci if (ret) 5008c2ecf20Sopenharmony_ci DRM_ERROR("%s: zap-shader resume failed: %d\n", 5018c2ecf20Sopenharmony_ci gpu->name, ret); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return ret; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int a5xx_zap_shader_init(struct msm_gpu *gpu) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci static bool loaded; 5098c2ecf20Sopenharmony_ci int ret; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* 5128c2ecf20Sopenharmony_ci * If the zap shader is already loaded into memory we just need to kick 5138c2ecf20Sopenharmony_ci * the remote processor to reinitialize it 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci if (loaded) 5168c2ecf20Sopenharmony_ci return a5xx_zap_shader_resume(gpu); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ret = adreno_zap_shader_load(gpu, GPU_PAS_ID); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci loaded = !ret; 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ 5258c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ 5268c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ 5278c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ 5288c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ 5298c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \ 5308c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \ 5318c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT | \ 5328c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_SW | \ 5338c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \ 5348c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ 5358c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int a5xx_hw_init(struct msm_gpu *gpu) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 5408c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 5418c2ecf20Sopenharmony_ci int ret; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (adreno_is_a540(adreno_gpu)) 5468c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Make all blocks contribute to the GPU BUSY perf counter */ 5498c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED, 0xFFFFFFFF); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* Enable RBBM error reporting bits */ 5528c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL0, 0x00000001); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_FAULT_DETECT_MASK) { 5558c2ecf20Sopenharmony_ci /* 5568c2ecf20Sopenharmony_ci * Mask out the activity signals from RB1-3 to avoid false 5578c2ecf20Sopenharmony_ci * positives 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL11, 5618c2ecf20Sopenharmony_ci 0xF0000000); 5628c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL12, 5638c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5648c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL13, 5658c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5668c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL14, 5678c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5688c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL15, 5698c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5708c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL16, 5718c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5728c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL17, 5738c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5748c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL18, 5758c2ecf20Sopenharmony_ci 0xFFFFFFFF); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Enable fault detection */ 5798c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_INT_CNTL, 5808c2ecf20Sopenharmony_ci (1 << 30) | 0xFFFF); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* Turn on performance counters */ 5838c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_CNTL, 0x01); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Select CP0 to always count cycles */ 5868c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PERFCTR_CP_SEL_0, PERF_CP_ALWAYS_COUNT); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Select RBBM0 to countable 6 to get the busy status for devfreq */ 5898c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0, 6); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Increase VFD cache access so LRZ and other data gets evicted less */ 5928c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_CACHE_WAYS, 0x02); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* Disable L2 bypass in the UCHE */ 5958c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_LO, 0xFFFF0000); 5968c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_HI, 0x0001FFFF); 5978c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_LO, 0xFFFF0000); 5988c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_HI, 0x0001FFFF); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Set the GMEM VA range (0 to gpu->gmem) */ 6018c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000); 6028c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_HI, 0x00000000); 6038c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO, 6048c2ecf20Sopenharmony_ci 0x00100000 + adreno_gpu->gmem - 1); 6058c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) { 6088c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x20); 6098c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x20); 6108c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); 6118c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x20100D0A); 6128c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 6138c2ecf20Sopenharmony_ci (0x200 << 11 | 0x200 << 22)); 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40); 6168c2ecf20Sopenharmony_ci if (adreno_is_a530(adreno_gpu)) 6178c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40); 6188c2ecf20Sopenharmony_ci if (adreno_is_a540(adreno_gpu)) 6198c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); 6208c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); 6218c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); 6228c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 6238c2ecf20Sopenharmony_ci (0x400 << 11 | 0x300 << 22)); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI) 6278c2ecf20Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8)); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Enable USE_RETENTION_FLOPS */ 6308c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_CHICKEN_DBG, 0x02000000); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Enable ME/PFP split notification */ 6338c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL1, 0xA6FFFFFF); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* 6368c2ecf20Sopenharmony_ci * In A5x, CCU can send context_done event of a particular context to 6378c2ecf20Sopenharmony_ci * UCHE which ultimately reaches CP even when there is valid 6388c2ecf20Sopenharmony_ci * transaction of that context inside CCU. This can let CP to program 6398c2ecf20Sopenharmony_ci * config registers, which will make the "valid transaction" inside 6408c2ecf20Sopenharmony_ci * CCU to be interpreted differently. This can cause gpu fault. This 6418c2ecf20Sopenharmony_ci * bug is fixed in latest A510 revision. To enable this bug fix - 6428c2ecf20Sopenharmony_ci * bit[11] of RB_DBG_ECO_CNTL need to be set to 0, default is 1 6438c2ecf20Sopenharmony_ci * (disable). For older A510 version this bit is unused. 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) 6468c2ecf20Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_RB_DBG_ECO_CNTL, (1 << 11), 0); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* Enable HWCG */ 6498c2ecf20Sopenharmony_ci a5xx_set_hwcg(gpu, true); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL2, 0x0000003F); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Set the highest bank bit */ 6548c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, 2 << 7); 6558c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, 2 << 1); 6568c2ecf20Sopenharmony_ci if (adreno_is_a540(adreno_gpu)) 6578c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, 2); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Protect registers from the CP */ 6608c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT_CNTL, 0x00000007); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* RBBM */ 6638c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(0), ADRENO_PROTECT_RW(0x04, 4)); 6648c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(1), ADRENO_PROTECT_RW(0x08, 8)); 6658c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(2), ADRENO_PROTECT_RW(0x10, 16)); 6668c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(3), ADRENO_PROTECT_RW(0x20, 32)); 6678c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(4), ADRENO_PROTECT_RW(0x40, 64)); 6688c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(5), ADRENO_PROTECT_RW(0x80, 64)); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Content protect */ 6718c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(6), 6728c2ecf20Sopenharmony_ci ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 6738c2ecf20Sopenharmony_ci 16)); 6748c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(7), 6758c2ecf20Sopenharmony_ci ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TRUST_CNTL, 2)); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* CP */ 6788c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(8), ADRENO_PROTECT_RW(0x800, 64)); 6798c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(9), ADRENO_PROTECT_RW(0x840, 8)); 6808c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(10), ADRENO_PROTECT_RW(0x880, 32)); 6818c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(11), ADRENO_PROTECT_RW(0xAA0, 1)); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* RB */ 6848c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(12), ADRENO_PROTECT_RW(0xCC0, 1)); 6858c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(13), ADRENO_PROTECT_RW(0xCF0, 2)); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* VPC */ 6888c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(14), ADRENO_PROTECT_RW(0xE68, 8)); 6898c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(15), ADRENO_PROTECT_RW(0xE70, 4)); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* UCHE */ 6928c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(16), ADRENO_PROTECT_RW(0xE80, 16)); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (adreno_is_a530(adreno_gpu) || adreno_is_a510(adreno_gpu)) 6958c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(17), 6968c2ecf20Sopenharmony_ci ADRENO_PROTECT_RW(0x10000, 0x8000)); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_CNTL, 0); 6998c2ecf20Sopenharmony_ci /* 7008c2ecf20Sopenharmony_ci * Disable the trusted memory range - we don't actually supported secure 7018c2ecf20Sopenharmony_ci * memory rendering at this point in time and we don't want to block off 7028c2ecf20Sopenharmony_ci * part of the virtual memory space. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 7058c2ecf20Sopenharmony_ci REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI, 0x00000000); 7068c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* Put the GPU into 64 bit by default */ 7098c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ADDR_MODE_CNTL, 0x1); 7108c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VSC_ADDR_MODE_CNTL, 0x1); 7118c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_GRAS_ADDR_MODE_CNTL, 0x1); 7128c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RB_ADDR_MODE_CNTL, 0x1); 7138c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_ADDR_MODE_CNTL, 0x1); 7148c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_HLSQ_ADDR_MODE_CNTL, 0x1); 7158c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VFD_ADDR_MODE_CNTL, 0x1); 7168c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VPC_ADDR_MODE_CNTL, 0x1); 7178c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_ADDR_MODE_CNTL, 0x1); 7188c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_SP_ADDR_MODE_CNTL, 0x1); 7198c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_TPL1_ADDR_MODE_CNTL, 0x1); 7208c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* 7238c2ecf20Sopenharmony_ci * VPC corner case with local memory load kill leads to corrupt 7248c2ecf20Sopenharmony_ci * internal state. Normal Disable does not work for all a5x chips. 7258c2ecf20Sopenharmony_ci * So do the following setting to disable it. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_LMLOADKILL_DISABLE) { 7288c2ecf20Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, BIT(23)); 7298c2ecf20Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_HLSQ_DBG_ECO_CNTL, BIT(18), 0); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ret = adreno_hw_init(gpu); 7338c2ecf20Sopenharmony_ci if (ret) 7348c2ecf20Sopenharmony_ci return ret; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!adreno_is_a510(adreno_gpu)) 7378c2ecf20Sopenharmony_ci a5xx_gpmu_ucode_init(gpu); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci ret = a5xx_ucode_init(gpu); 7408c2ecf20Sopenharmony_ci if (ret) 7418c2ecf20Sopenharmony_ci return ret; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Set the ringbuffer address */ 7448c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_RB_BASE, REG_A5XX_CP_RB_BASE_HI, 7458c2ecf20Sopenharmony_ci gpu->rb[0]->iova); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* 7488c2ecf20Sopenharmony_ci * If the microcode supports the WHERE_AM_I opcode then we can use that 7498c2ecf20Sopenharmony_ci * in lieu of the RPTR shadow and enable preemption. Otherwise, we 7508c2ecf20Sopenharmony_ci * can't safely use the RPTR shadow or preemption. In either case, the 7518c2ecf20Sopenharmony_ci * RPTR shadow should be disabled in hardware. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_RB_CNTL, 7548c2ecf20Sopenharmony_ci MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Create a privileged buffer for the RPTR shadow */ 7578c2ecf20Sopenharmony_ci if (a5xx_gpu->has_whereami) { 7588c2ecf20Sopenharmony_ci if (!a5xx_gpu->shadow_bo) { 7598c2ecf20Sopenharmony_ci a5xx_gpu->shadow = msm_gem_kernel_new(gpu->dev, 7608c2ecf20Sopenharmony_ci sizeof(u32) * gpu->nr_rings, 7618c2ecf20Sopenharmony_ci MSM_BO_UNCACHED | MSM_BO_MAP_PRIV, 7628c2ecf20Sopenharmony_ci gpu->aspace, &a5xx_gpu->shadow_bo, 7638c2ecf20Sopenharmony_ci &a5xx_gpu->shadow_iova); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (IS_ERR(a5xx_gpu->shadow)) 7668c2ecf20Sopenharmony_ci return PTR_ERR(a5xx_gpu->shadow); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR, 7708c2ecf20Sopenharmony_ci REG_A5XX_CP_RB_RPTR_ADDR_HI, shadowptr(a5xx_gpu, gpu->rb[0])); 7718c2ecf20Sopenharmony_ci } else if (gpu->nr_rings > 1) { 7728c2ecf20Sopenharmony_ci /* Disable preemption if WHERE_AM_I isn't available */ 7738c2ecf20Sopenharmony_ci a5xx_preempt_fini(gpu); 7748c2ecf20Sopenharmony_ci gpu->nr_rings = 1; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci a5xx_preempt_hw_init(gpu); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Disable the interrupts through the initial bringup stage */ 7808c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK, A5XX_INT_MASK); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Clear ME_HALT to start the micro engine */ 7838c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PFP_ME_CNTL, 0); 7848c2ecf20Sopenharmony_ci ret = a5xx_me_init(gpu); 7858c2ecf20Sopenharmony_ci if (ret) 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = a5xx_power_init(gpu); 7898c2ecf20Sopenharmony_ci if (ret) 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* 7938c2ecf20Sopenharmony_ci * Send a pipeline event stat to get misbehaving counters to start 7948c2ecf20Sopenharmony_ci * ticking correctly 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci if (adreno_is_a530(adreno_gpu)) { 7978c2ecf20Sopenharmony_ci OUT_PKT7(gpu->rb[0], CP_EVENT_WRITE, 1); 7988c2ecf20Sopenharmony_ci OUT_RING(gpu->rb[0], CP_EVENT_WRITE_0_EVENT(STAT_EVENT)); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci a5xx_flush(gpu, gpu->rb[0], true); 8018c2ecf20Sopenharmony_ci if (!a5xx_idle(gpu, gpu->rb[0])) 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* 8068c2ecf20Sopenharmony_ci * If the chip that we are using does support loading one, then 8078c2ecf20Sopenharmony_ci * try to load a zap shader into the secure world. If successful 8088c2ecf20Sopenharmony_ci * we can use the CP to switch out of secure mode. If not then we 8098c2ecf20Sopenharmony_ci * have no resource but to try to switch ourselves out manually. If we 8108c2ecf20Sopenharmony_ci * guessed wrong then access to the RBBM_SECVID_TRUST_CNTL register will 8118c2ecf20Sopenharmony_ci * be blocked and a permissions violation will soon follow. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci ret = a5xx_zap_shader_init(gpu); 8148c2ecf20Sopenharmony_ci if (!ret) { 8158c2ecf20Sopenharmony_ci OUT_PKT7(gpu->rb[0], CP_SET_SECURE_MODE, 1); 8168c2ecf20Sopenharmony_ci OUT_RING(gpu->rb[0], 0x00000000); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci a5xx_flush(gpu, gpu->rb[0], true); 8198c2ecf20Sopenharmony_ci if (!a5xx_idle(gpu, gpu->rb[0])) 8208c2ecf20Sopenharmony_ci return -EINVAL; 8218c2ecf20Sopenharmony_ci } else if (ret == -ENODEV) { 8228c2ecf20Sopenharmony_ci /* 8238c2ecf20Sopenharmony_ci * This device does not use zap shader (but print a warning 8248c2ecf20Sopenharmony_ci * just in case someone got their dt wrong.. hopefully they 8258c2ecf20Sopenharmony_ci * have a debug UART to realize the error of their ways... 8268c2ecf20Sopenharmony_ci * if you mess this up you are about to crash horribly) 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci dev_warn_once(gpu->dev->dev, 8298c2ecf20Sopenharmony_ci "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n"); 8308c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); 8318c2ecf20Sopenharmony_ci } else { 8328c2ecf20Sopenharmony_ci return ret; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* Last step - yield the ringbuffer */ 8368c2ecf20Sopenharmony_ci a5xx_preempt_start(gpu); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic void a5xx_recover(struct msm_gpu *gpu) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci int i; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci adreno_dump_info(gpu); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 8488c2ecf20Sopenharmony_ci printk("CP_SCRATCH_REG%d: %u\n", i, 8498c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(i))); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (hang_debug) 8538c2ecf20Sopenharmony_ci a5xx_dump(gpu); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 1); 8568c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_SW_RESET_CMD); 8578c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 0); 8588c2ecf20Sopenharmony_ci adreno_recover(gpu); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void a5xx_destroy(struct msm_gpu *gpu) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 8648c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci DBG("%s", gpu->name); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci a5xx_preempt_fini(gpu); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (a5xx_gpu->pm4_bo) { 8718c2ecf20Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace); 8728c2ecf20Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pm4_bo); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (a5xx_gpu->pfp_bo) { 8768c2ecf20Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace); 8778c2ecf20Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pfp_bo); 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (a5xx_gpu->gpmu_bo) { 8818c2ecf20Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->gpmu_bo, gpu->aspace); 8828c2ecf20Sopenharmony_ci drm_gem_object_put(a5xx_gpu->gpmu_bo); 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (a5xx_gpu->shadow_bo) { 8868c2ecf20Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->shadow_bo, gpu->aspace); 8878c2ecf20Sopenharmony_ci drm_gem_object_put(a5xx_gpu->shadow_bo); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci adreno_gpu_cleanup(adreno_gpu); 8918c2ecf20Sopenharmony_ci kfree(a5xx_gpu); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic inline bool _a5xx_check_idle(struct msm_gpu *gpu) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci if (gpu_read(gpu, REG_A5XX_RBBM_STATUS) & ~A5XX_RBBM_STATUS_HI_BUSY) 8978c2ecf20Sopenharmony_ci return false; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* 9008c2ecf20Sopenharmony_ci * Nearly every abnormality ends up pausing the GPU and triggering a 9018c2ecf20Sopenharmony_ci * fault so we can safely just watch for this one interrupt to fire 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci return !(gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS) & 9048c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cibool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 9108c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (ring != a5xx_gpu->cur_ring) { 9138c2ecf20Sopenharmony_ci WARN(1, "Tried to idle a non-current ringbuffer\n"); 9148c2ecf20Sopenharmony_ci return false; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* wait for CP to drain ringbuffer: */ 9188c2ecf20Sopenharmony_ci if (!adreno_idle(gpu, ring)) 9198c2ecf20Sopenharmony_ci return false; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (spin_until(_a5xx_check_idle(gpu))) { 9228c2ecf20Sopenharmony_ci DRM_ERROR("%s: %ps: timeout waiting for GPU to idle: status %8.8X irq %8.8X rptr/wptr %d/%d\n", 9238c2ecf20Sopenharmony_ci gpu->name, __builtin_return_address(0), 9248c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS), 9258c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS), 9268c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_RPTR), 9278c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_WPTR)); 9288c2ecf20Sopenharmony_ci return false; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return true; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic int a5xx_fault_handler(void *arg, unsigned long iova, int flags) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct msm_gpu *gpu = arg; 9378c2ecf20Sopenharmony_ci pr_warn_ratelimited("*** gpu fault: iova=%08lx, flags=%d (%u,%u,%u,%u)\n", 9388c2ecf20Sopenharmony_ci iova, flags, 9398c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(4)), 9408c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(5)), 9418c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(6)), 9428c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(7))); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return -EFAULT; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic void a5xx_cp_err_irq(struct msm_gpu *gpu) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_CP_INTERRUPT_STATUS); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (status & A5XX_CP_INT_CP_OPCODE_ERROR) { 9528c2ecf20Sopenharmony_ci u32 val; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, 0); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* 9578c2ecf20Sopenharmony_ci * REG_A5XX_CP_PFP_STAT_DATA is indexed, and we want index 1 so 9588c2ecf20Sopenharmony_ci * read it twice 9598c2ecf20Sopenharmony_ci */ 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); 9628c2ecf20Sopenharmony_ci val = gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | opcode error | possible opcode=0x%8.8X\n", 9658c2ecf20Sopenharmony_ci val); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (status & A5XX_CP_INT_CP_HW_FAULT_ERROR) 9698c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | HW fault | status=0x%8.8X\n", 9708c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_HW_FAULT)); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (status & A5XX_CP_INT_CP_DMA_ERROR) 9738c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | DMA error\n"); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (status & A5XX_CP_INT_CP_REGISTER_PROTECTION_ERROR) { 9768c2ecf20Sopenharmony_ci u32 val = gpu_read(gpu, REG_A5XX_CP_PROTECT_STATUS); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 9798c2ecf20Sopenharmony_ci "CP | protected mode error | %s | addr=0x%8.8X | status=0x%8.8X\n", 9808c2ecf20Sopenharmony_ci val & (1 << 24) ? "WRITE" : "READ", 9818c2ecf20Sopenharmony_ci (val & 0xFFFFF) >> 2, val); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (status & A5XX_CP_INT_CP_AHB_ERROR) { 9858c2ecf20Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_CP_AHB_FAULT); 9868c2ecf20Sopenharmony_ci const char *access[16] = { "reserved", "reserved", 9878c2ecf20Sopenharmony_ci "timestamp lo", "timestamp hi", "pfp read", "pfp write", 9888c2ecf20Sopenharmony_ci "", "", "me read", "me write", "", "", "crashdump read", 9898c2ecf20Sopenharmony_ci "crashdump write" }; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 9928c2ecf20Sopenharmony_ci "CP | AHB error | addr=%X access=%s error=%d | status=0x%8.8X\n", 9938c2ecf20Sopenharmony_ci status & 0xFFFFF, access[(status >> 24) & 0xF], 9948c2ecf20Sopenharmony_ci (status & (1 << 31)), status); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic void a5xx_rbbm_err_irq(struct msm_gpu *gpu, u32 status) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR) { 10018c2ecf20Sopenharmony_ci u32 val = gpu_read(gpu, REG_A5XX_RBBM_AHB_ERROR_STATUS); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 10048c2ecf20Sopenharmony_ci "RBBM | AHB bus error | %s | addr=0x%X | ports=0x%X:0x%X\n", 10058c2ecf20Sopenharmony_ci val & (1 << 28) ? "WRITE" : "READ", 10068c2ecf20Sopenharmony_ci (val & 0xFFFFF) >> 2, (val >> 20) & 0x3, 10078c2ecf20Sopenharmony_ci (val >> 24) & 0xF); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* Clear the error */ 10108c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CMD, (1 << 4)); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Clear the interrupt */ 10138c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, 10148c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT) 10188c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | AHB transfer timeout\n"); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT) 10218c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ME master split | status=0x%X\n", 10228c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_ME_SPLIT_STATUS)); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT) 10258c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | PFP master split | status=0x%X\n", 10268c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_PFP_SPLIT_STATUS)); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT) 10298c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ETS master split | status=0x%X\n", 10308c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_ETS_SPLIT_STATUS)); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) 10338c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB ASYNC overflow\n"); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_BUS_OVERFLOW) 10368c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB bus overflow\n"); 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic void a5xx_uche_err_irq(struct msm_gpu *gpu) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci uint64_t addr = (uint64_t) gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_HI); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci addr |= gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_LO); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "UCHE | Out of bounds access | addr=0x%llX\n", 10468c2ecf20Sopenharmony_ci addr); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic void a5xx_gpmu_err_irq(struct msm_gpu *gpu) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n"); 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic void a5xx_fault_detect_irq(struct msm_gpu *gpu) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci struct drm_device *dev = gpu->dev; 10578c2ecf20Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 10588c2ecf20Sopenharmony_ci struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "gpu fault ring %d fence %x status %8.8X rb %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n", 10618c2ecf20Sopenharmony_ci ring ? ring->id : -1, ring ? ring->seqno : 0, 10628c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS), 10638c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_RPTR), 10648c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_WPTR), 10658c2ecf20Sopenharmony_ci gpu_read64(gpu, REG_A5XX_CP_IB1_BASE, REG_A5XX_CP_IB1_BASE_HI), 10668c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ), 10678c2ecf20Sopenharmony_ci gpu_read64(gpu, REG_A5XX_CP_IB2_BASE, REG_A5XX_CP_IB2_BASE_HI), 10688c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ)); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* Turn off the hangcheck timer to keep it from bothering us */ 10718c2ecf20Sopenharmony_ci del_timer(&gpu->hangcheck_timer); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci queue_work(priv->wq, &gpu->recover_work); 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci#define RBBM_ERROR_MASK \ 10778c2ecf20Sopenharmony_ci (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ 10788c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ 10798c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ 10808c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ 10818c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ 10828c2ecf20Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic irqreturn_t a5xx_irq(struct msm_gpu *gpu) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* 10898c2ecf20Sopenharmony_ci * Clear all the interrupts except RBBM_AHB_ERROR - if we clear it 10908c2ecf20Sopenharmony_ci * before the source is cleared the interrupt will storm. 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, 10938c2ecf20Sopenharmony_ci status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Pass status to a5xx_rbbm_err_irq because we've already cleared it */ 10968c2ecf20Sopenharmony_ci if (status & RBBM_ERROR_MASK) 10978c2ecf20Sopenharmony_ci a5xx_rbbm_err_irq(gpu, status); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR) 11008c2ecf20Sopenharmony_ci a5xx_cp_err_irq(gpu); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT) 11038c2ecf20Sopenharmony_ci a5xx_fault_detect_irq(gpu); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS) 11068c2ecf20Sopenharmony_ci a5xx_uche_err_irq(gpu); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) 11098c2ecf20Sopenharmony_ci a5xx_gpmu_err_irq(gpu); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) { 11128c2ecf20Sopenharmony_ci a5xx_preempt_trigger(gpu); 11138c2ecf20Sopenharmony_ci msm_gpu_retire(gpu); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_SW) 11178c2ecf20Sopenharmony_ci a5xx_preempt_irq(gpu); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic const u32 a5xx_registers[] = { 11238c2ecf20Sopenharmony_ci 0x0000, 0x0002, 0x0004, 0x0020, 0x0022, 0x0026, 0x0029, 0x002B, 11248c2ecf20Sopenharmony_ci 0x002E, 0x0035, 0x0038, 0x0042, 0x0044, 0x0044, 0x0047, 0x0095, 11258c2ecf20Sopenharmony_ci 0x0097, 0x00BB, 0x03A0, 0x0464, 0x0469, 0x046F, 0x04D2, 0x04D3, 11268c2ecf20Sopenharmony_ci 0x04E0, 0x0533, 0x0540, 0x0555, 0x0800, 0x081A, 0x081F, 0x0841, 11278c2ecf20Sopenharmony_ci 0x0860, 0x0860, 0x0880, 0x08A0, 0x0B00, 0x0B12, 0x0B15, 0x0B28, 11288c2ecf20Sopenharmony_ci 0x0B78, 0x0B7F, 0x0BB0, 0x0BBD, 0x0BC0, 0x0BC6, 0x0BD0, 0x0C53, 11298c2ecf20Sopenharmony_ci 0x0C60, 0x0C61, 0x0C80, 0x0C82, 0x0C84, 0x0C85, 0x0C90, 0x0C98, 11308c2ecf20Sopenharmony_ci 0x0CA0, 0x0CA0, 0x0CB0, 0x0CB2, 0x2180, 0x2185, 0x2580, 0x2585, 11318c2ecf20Sopenharmony_ci 0x0CC1, 0x0CC1, 0x0CC4, 0x0CC7, 0x0CCC, 0x0CCC, 0x0CD0, 0x0CD8, 11328c2ecf20Sopenharmony_ci 0x0CE0, 0x0CE5, 0x0CE8, 0x0CE8, 0x0CEC, 0x0CF1, 0x0CFB, 0x0D0E, 11338c2ecf20Sopenharmony_ci 0x2100, 0x211E, 0x2140, 0x2145, 0x2500, 0x251E, 0x2540, 0x2545, 11348c2ecf20Sopenharmony_ci 0x0D10, 0x0D17, 0x0D20, 0x0D23, 0x0D30, 0x0D30, 0x20C0, 0x20C0, 11358c2ecf20Sopenharmony_ci 0x24C0, 0x24C0, 0x0E40, 0x0E43, 0x0E4A, 0x0E4A, 0x0E50, 0x0E57, 11368c2ecf20Sopenharmony_ci 0x0E60, 0x0E7C, 0x0E80, 0x0E8E, 0x0E90, 0x0E96, 0x0EA0, 0x0EA8, 11378c2ecf20Sopenharmony_ci 0x0EB0, 0x0EB2, 0xE140, 0xE147, 0xE150, 0xE187, 0xE1A0, 0xE1A9, 11388c2ecf20Sopenharmony_ci 0xE1B0, 0xE1B6, 0xE1C0, 0xE1C7, 0xE1D0, 0xE1D1, 0xE200, 0xE201, 11398c2ecf20Sopenharmony_ci 0xE210, 0xE21C, 0xE240, 0xE268, 0xE000, 0xE006, 0xE010, 0xE09A, 11408c2ecf20Sopenharmony_ci 0xE0A0, 0xE0A4, 0xE0AA, 0xE0EB, 0xE100, 0xE105, 0xE380, 0xE38F, 11418c2ecf20Sopenharmony_ci 0xE3B0, 0xE3B0, 0xE400, 0xE405, 0xE408, 0xE4E9, 0xE4F0, 0xE4F0, 11428c2ecf20Sopenharmony_ci 0xE280, 0xE280, 0xE282, 0xE2A3, 0xE2A5, 0xE2C2, 0xE940, 0xE947, 11438c2ecf20Sopenharmony_ci 0xE950, 0xE987, 0xE9A0, 0xE9A9, 0xE9B0, 0xE9B6, 0xE9C0, 0xE9C7, 11448c2ecf20Sopenharmony_ci 0xE9D0, 0xE9D1, 0xEA00, 0xEA01, 0xEA10, 0xEA1C, 0xEA40, 0xEA68, 11458c2ecf20Sopenharmony_ci 0xE800, 0xE806, 0xE810, 0xE89A, 0xE8A0, 0xE8A4, 0xE8AA, 0xE8EB, 11468c2ecf20Sopenharmony_ci 0xE900, 0xE905, 0xEB80, 0xEB8F, 0xEBB0, 0xEBB0, 0xEC00, 0xEC05, 11478c2ecf20Sopenharmony_ci 0xEC08, 0xECE9, 0xECF0, 0xECF0, 0xEA80, 0xEA80, 0xEA82, 0xEAA3, 11488c2ecf20Sopenharmony_ci 0xEAA5, 0xEAC2, 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D, 11498c2ecf20Sopenharmony_ci 0XA880, 0xA88D, 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5, 11508c2ecf20Sopenharmony_ci 0xAC60, 0xAC60, ~0, 11518c2ecf20Sopenharmony_ci}; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic void a5xx_dump(struct msm_gpu *gpu) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci DRM_DEV_INFO(gpu->dev->dev, "status: %08x\n", 11568c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS)); 11578c2ecf20Sopenharmony_ci adreno_dump(gpu); 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic int a5xx_pm_resume(struct msm_gpu *gpu) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 11638c2ecf20Sopenharmony_ci int ret; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* Turn on the core power */ 11668c2ecf20Sopenharmony_ci ret = msm_gpu_pm_resume(gpu); 11678c2ecf20Sopenharmony_ci if (ret) 11688c2ecf20Sopenharmony_ci return ret; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) { 11718c2ecf20Sopenharmony_ci /* Halt the sp_input_clk at HM level */ 11728c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0x00000055); 11738c2ecf20Sopenharmony_ci a5xx_set_hwcg(gpu, true); 11748c2ecf20Sopenharmony_ci /* Turn on sp_input_clk at HM level */ 11758c2ecf20Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0xff, 0); 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Turn the RBCCU domain first to limit the chances of voltage droop */ 11808c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Wait 3 usecs before polling */ 11838c2ecf20Sopenharmony_ci udelay(3); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS, 11868c2ecf20Sopenharmony_ci (1 << 20), (1 << 20)); 11878c2ecf20Sopenharmony_ci if (ret) { 11888c2ecf20Sopenharmony_ci DRM_ERROR("%s: timeout waiting for RBCCU GDSC enable: %X\n", 11898c2ecf20Sopenharmony_ci gpu->name, 11908c2ecf20Sopenharmony_ci gpu_read(gpu, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS)); 11918c2ecf20Sopenharmony_ci return ret; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Turn on the SP domain */ 11958c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_GPMU_SP_POWER_CNTL, 0x778000); 11968c2ecf20Sopenharmony_ci ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_SP_PWR_CLK_STATUS, 11978c2ecf20Sopenharmony_ci (1 << 20), (1 << 20)); 11988c2ecf20Sopenharmony_ci if (ret) 11998c2ecf20Sopenharmony_ci DRM_ERROR("%s: timeout waiting for SP GDSC enable\n", 12008c2ecf20Sopenharmony_ci gpu->name); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci return ret; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic int a5xx_pm_suspend(struct msm_gpu *gpu) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 12088c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 12098c2ecf20Sopenharmony_ci u32 mask = 0xf; 12108c2ecf20Sopenharmony_ci int i, ret; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci /* A510 has 3 XIN ports in VBIF */ 12138c2ecf20Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) 12148c2ecf20Sopenharmony_ci mask = 0x7; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* Clear the VBIF pipe before shutting down */ 12178c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, mask); 12188c2ecf20Sopenharmony_ci spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 12198c2ecf20Sopenharmony_ci mask) == mask); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci /* 12248c2ecf20Sopenharmony_ci * Reset the VBIF before power collapse to avoid issue with FIFO 12258c2ecf20Sopenharmony_ci * entries 12268c2ecf20Sopenharmony_ci */ 12278c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); 12288c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci ret = msm_gpu_pm_suspend(gpu); 12318c2ecf20Sopenharmony_ci if (ret) 12328c2ecf20Sopenharmony_ci return ret; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci if (a5xx_gpu->has_whereami) 12358c2ecf20Sopenharmony_ci for (i = 0; i < gpu->nr_rings; i++) 12368c2ecf20Sopenharmony_ci a5xx_gpu->shadow[i] = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO, 12448c2ecf20Sopenharmony_ci REG_A5XX_RBBM_ALWAYSON_COUNTER_HI); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return 0; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistruct a5xx_crashdumper { 12508c2ecf20Sopenharmony_ci void *ptr; 12518c2ecf20Sopenharmony_ci struct drm_gem_object *bo; 12528c2ecf20Sopenharmony_ci u64 iova; 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistruct a5xx_gpu_state { 12568c2ecf20Sopenharmony_ci struct msm_gpu_state base; 12578c2ecf20Sopenharmony_ci u32 *hlsqregs; 12588c2ecf20Sopenharmony_ci}; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int a5xx_crashdumper_init(struct msm_gpu *gpu, 12618c2ecf20Sopenharmony_ci struct a5xx_crashdumper *dumper) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci dumper->ptr = msm_gem_kernel_new_locked(gpu->dev, 12648c2ecf20Sopenharmony_ci SZ_1M, MSM_BO_UNCACHED, gpu->aspace, 12658c2ecf20Sopenharmony_ci &dumper->bo, &dumper->iova); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (!IS_ERR(dumper->ptr)) 12688c2ecf20Sopenharmony_ci msm_gem_object_set_name(dumper->bo, "crashdump"); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(dumper->ptr); 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic int a5xx_crashdumper_run(struct msm_gpu *gpu, 12748c2ecf20Sopenharmony_ci struct a5xx_crashdumper *dumper) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci u32 val; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(dumper->ptr)) 12798c2ecf20Sopenharmony_ci return -EINVAL; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, 12828c2ecf20Sopenharmony_ci REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci return gpu_poll_timeout(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, val, 12878c2ecf20Sopenharmony_ci val & 0x04, 100, 10000); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci/* 12918c2ecf20Sopenharmony_ci * These are a list of the registers that need to be read through the HLSQ 12928c2ecf20Sopenharmony_ci * aperture through the crashdumper. These are not nominally accessible from 12938c2ecf20Sopenharmony_ci * the CPU on a secure platform. 12948c2ecf20Sopenharmony_ci */ 12958c2ecf20Sopenharmony_cistatic const struct { 12968c2ecf20Sopenharmony_ci u32 type; 12978c2ecf20Sopenharmony_ci u32 regoffset; 12988c2ecf20Sopenharmony_ci u32 count; 12998c2ecf20Sopenharmony_ci} a5xx_hlsq_aperture_regs[] = { 13008c2ecf20Sopenharmony_ci { 0x35, 0xe00, 0x32 }, /* HSLQ non-context */ 13018c2ecf20Sopenharmony_ci { 0x31, 0x2080, 0x1 }, /* HLSQ 2D context 0 */ 13028c2ecf20Sopenharmony_ci { 0x33, 0x2480, 0x1 }, /* HLSQ 2D context 1 */ 13038c2ecf20Sopenharmony_ci { 0x32, 0xe780, 0x62 }, /* HLSQ 3D context 0 */ 13048c2ecf20Sopenharmony_ci { 0x34, 0xef80, 0x62 }, /* HLSQ 3D context 1 */ 13058c2ecf20Sopenharmony_ci { 0x3f, 0x0ec0, 0x40 }, /* SP non-context */ 13068c2ecf20Sopenharmony_ci { 0x3d, 0x2040, 0x1 }, /* SP 2D context 0 */ 13078c2ecf20Sopenharmony_ci { 0x3b, 0x2440, 0x1 }, /* SP 2D context 1 */ 13088c2ecf20Sopenharmony_ci { 0x3e, 0xe580, 0x170 }, /* SP 3D context 0 */ 13098c2ecf20Sopenharmony_ci { 0x3c, 0xed80, 0x170 }, /* SP 3D context 1 */ 13108c2ecf20Sopenharmony_ci { 0x3a, 0x0f00, 0x1c }, /* TP non-context */ 13118c2ecf20Sopenharmony_ci { 0x38, 0x2000, 0xa }, /* TP 2D context 0 */ 13128c2ecf20Sopenharmony_ci { 0x36, 0x2400, 0xa }, /* TP 2D context 1 */ 13138c2ecf20Sopenharmony_ci { 0x39, 0xe700, 0x80 }, /* TP 3D context 0 */ 13148c2ecf20Sopenharmony_ci { 0x37, 0xef00, 0x80 }, /* TP 3D context 1 */ 13158c2ecf20Sopenharmony_ci}; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu, 13188c2ecf20Sopenharmony_ci struct a5xx_gpu_state *a5xx_state) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct a5xx_crashdumper dumper = { 0 }; 13218c2ecf20Sopenharmony_ci u32 offset, count = 0; 13228c2ecf20Sopenharmony_ci u64 *ptr; 13238c2ecf20Sopenharmony_ci int i; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (a5xx_crashdumper_init(gpu, &dumper)) 13268c2ecf20Sopenharmony_ci return; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* The script will be written at offset 0 */ 13298c2ecf20Sopenharmony_ci ptr = dumper.ptr; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* Start writing the data at offset 256k */ 13328c2ecf20Sopenharmony_ci offset = dumper.iova + (256 * SZ_1K); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* Count how many additional registers to get from the HLSQ aperture */ 13358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) 13368c2ecf20Sopenharmony_ci count += a5xx_hlsq_aperture_regs[i].count; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci a5xx_state->hlsqregs = kcalloc(count, sizeof(u32), GFP_KERNEL); 13398c2ecf20Sopenharmony_ci if (!a5xx_state->hlsqregs) 13408c2ecf20Sopenharmony_ci return; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* Build the crashdump script */ 13438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { 13448c2ecf20Sopenharmony_ci u32 type = a5xx_hlsq_aperture_regs[i].type; 13458c2ecf20Sopenharmony_ci u32 c = a5xx_hlsq_aperture_regs[i].count; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci /* Write the register to select the desired bank */ 13488c2ecf20Sopenharmony_ci *ptr++ = ((u64) type << 8); 13498c2ecf20Sopenharmony_ci *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_READ_SEL) << 44) | 13508c2ecf20Sopenharmony_ci (1 << 21) | 1; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci *ptr++ = offset; 13538c2ecf20Sopenharmony_ci *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE) << 44) 13548c2ecf20Sopenharmony_ci | c; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci offset += c * sizeof(u32); 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Write two zeros to close off the script */ 13608c2ecf20Sopenharmony_ci *ptr++ = 0; 13618c2ecf20Sopenharmony_ci *ptr++ = 0; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (a5xx_crashdumper_run(gpu, &dumper)) { 13648c2ecf20Sopenharmony_ci kfree(a5xx_state->hlsqregs); 13658c2ecf20Sopenharmony_ci msm_gem_kernel_put(dumper.bo, gpu->aspace, true); 13668c2ecf20Sopenharmony_ci return; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* Copy the data from the crashdumper to the state */ 13708c2ecf20Sopenharmony_ci memcpy(a5xx_state->hlsqregs, dumper.ptr + (256 * SZ_1K), 13718c2ecf20Sopenharmony_ci count * sizeof(u32)); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci msm_gem_kernel_put(dumper.bo, gpu->aspace, true); 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), 13798c2ecf20Sopenharmony_ci GFP_KERNEL); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!a5xx_state) 13828c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci /* Temporarily disable hardware clock gating before reading the hw */ 13858c2ecf20Sopenharmony_ci a5xx_set_hwcg(gpu, false); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* First get the generic state from the adreno core */ 13888c2ecf20Sopenharmony_ci adreno_gpu_state_get(gpu, &(a5xx_state->base)); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci /* Get the HLSQ regs with the help of the crashdumper */ 13938c2ecf20Sopenharmony_ci a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci a5xx_set_hwcg(gpu, true); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci return &a5xx_state->base; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic void a5xx_gpu_state_destroy(struct kref *kref) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci struct msm_gpu_state *state = container_of(kref, 14038c2ecf20Sopenharmony_ci struct msm_gpu_state, ref); 14048c2ecf20Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = container_of(state, 14058c2ecf20Sopenharmony_ci struct a5xx_gpu_state, base); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci kfree(a5xx_state->hlsqregs); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci adreno_gpu_state_destroy(state); 14108c2ecf20Sopenharmony_ci kfree(a5xx_state); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_cistatic int a5xx_gpu_state_put(struct msm_gpu_state *state) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(state)) 14168c2ecf20Sopenharmony_ci return 1; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci return kref_put(&state->ref, a5xx_gpu_state_destroy); 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 14238c2ecf20Sopenharmony_cistatic void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, 14248c2ecf20Sopenharmony_ci struct drm_printer *p) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci int i, j; 14278c2ecf20Sopenharmony_ci u32 pos = 0; 14288c2ecf20Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = container_of(state, 14298c2ecf20Sopenharmony_ci struct a5xx_gpu_state, base); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(state)) 14328c2ecf20Sopenharmony_ci return; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci adreno_show(gpu, state, p); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* Dump the additional a5xx HLSQ registers */ 14378c2ecf20Sopenharmony_ci if (!a5xx_state->hlsqregs) 14388c2ecf20Sopenharmony_ci return; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci drm_printf(p, "registers-hlsq:\n"); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { 14438c2ecf20Sopenharmony_ci u32 o = a5xx_hlsq_aperture_regs[i].regoffset; 14448c2ecf20Sopenharmony_ci u32 c = a5xx_hlsq_aperture_regs[i].count; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci for (j = 0; j < c; j++, pos++, o++) { 14478c2ecf20Sopenharmony_ci /* 14488c2ecf20Sopenharmony_ci * To keep the crashdump simple we pull the entire range 14498c2ecf20Sopenharmony_ci * for each register type but not all of the registers 14508c2ecf20Sopenharmony_ci * in the range are valid. Fortunately invalid registers 14518c2ecf20Sopenharmony_ci * stick out like a sore thumb with a value of 14528c2ecf20Sopenharmony_ci * 0xdeadbeef 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci if (a5xx_state->hlsqregs[pos] == 0xdeadbeef) 14558c2ecf20Sopenharmony_ci continue; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", 14588c2ecf20Sopenharmony_ci o << 2, a5xx_state->hlsqregs[pos]); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci#endif 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 14678c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci return a5xx_gpu->cur_ring; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic unsigned long a5xx_gpu_busy(struct msm_gpu *gpu) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci u64 busy_cycles, busy_time; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* Only read the gpu busy if the hardware is already active */ 14778c2ecf20Sopenharmony_ci if (pm_runtime_get_if_in_use(&gpu->pdev->dev) == 0) 14788c2ecf20Sopenharmony_ci return 0; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, 14818c2ecf20Sopenharmony_ci REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci busy_time = busy_cycles - gpu->devfreq.busy_cycles; 14848c2ecf20Sopenharmony_ci do_div(busy_time, clk_get_rate(gpu->core_clk) / 1000000); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci gpu->devfreq.busy_cycles = busy_cycles; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci pm_runtime_put(&gpu->pdev->dev); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (WARN_ON(busy_time > ~0LU)) 14918c2ecf20Sopenharmony_ci return ~0LU; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci return (unsigned long)busy_time; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic uint32_t a5xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 14998c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (a5xx_gpu->has_whereami) 15028c2ecf20Sopenharmony_ci return a5xx_gpu->shadow[ring->id]; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return ring->memptrs->rptr = gpu_read(gpu, REG_A5XX_CP_RB_RPTR); 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic const struct adreno_gpu_funcs funcs = { 15088c2ecf20Sopenharmony_ci .base = { 15098c2ecf20Sopenharmony_ci .get_param = adreno_get_param, 15108c2ecf20Sopenharmony_ci .hw_init = a5xx_hw_init, 15118c2ecf20Sopenharmony_ci .pm_suspend = a5xx_pm_suspend, 15128c2ecf20Sopenharmony_ci .pm_resume = a5xx_pm_resume, 15138c2ecf20Sopenharmony_ci .recover = a5xx_recover, 15148c2ecf20Sopenharmony_ci .submit = a5xx_submit, 15158c2ecf20Sopenharmony_ci .active_ring = a5xx_active_ring, 15168c2ecf20Sopenharmony_ci .irq = a5xx_irq, 15178c2ecf20Sopenharmony_ci .destroy = a5xx_destroy, 15188c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 15198c2ecf20Sopenharmony_ci .show = a5xx_show, 15208c2ecf20Sopenharmony_ci#endif 15218c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 15228c2ecf20Sopenharmony_ci .debugfs_init = a5xx_debugfs_init, 15238c2ecf20Sopenharmony_ci#endif 15248c2ecf20Sopenharmony_ci .gpu_busy = a5xx_gpu_busy, 15258c2ecf20Sopenharmony_ci .gpu_state_get = a5xx_gpu_state_get, 15268c2ecf20Sopenharmony_ci .gpu_state_put = a5xx_gpu_state_put, 15278c2ecf20Sopenharmony_ci .create_address_space = adreno_iommu_create_address_space, 15288c2ecf20Sopenharmony_ci .get_rptr = a5xx_get_rptr, 15298c2ecf20Sopenharmony_ci }, 15308c2ecf20Sopenharmony_ci .get_timestamp = a5xx_get_timestamp, 15318c2ecf20Sopenharmony_ci}; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic void check_speed_bin(struct device *dev) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci struct nvmem_cell *cell; 15368c2ecf20Sopenharmony_ci u32 val; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* 15398c2ecf20Sopenharmony_ci * If the OPP table specifies a opp-supported-hw property then we have 15408c2ecf20Sopenharmony_ci * to set something with dev_pm_opp_set_supported_hw() or the table 15418c2ecf20Sopenharmony_ci * doesn't get populated so pick an arbitrary value that should 15428c2ecf20Sopenharmony_ci * ensure the default frequencies are selected but not conflict with any 15438c2ecf20Sopenharmony_ci * actual bins 15448c2ecf20Sopenharmony_ci */ 15458c2ecf20Sopenharmony_ci val = 0x80; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci cell = nvmem_cell_get(dev, "speed_bin"); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (!IS_ERR(cell)) { 15508c2ecf20Sopenharmony_ci void *buf = nvmem_cell_read(cell, NULL); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (!IS_ERR(buf)) { 15538c2ecf20Sopenharmony_ci u8 bin = *((u8 *) buf); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci val = (1 << bin); 15568c2ecf20Sopenharmony_ci kfree(buf); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci nvmem_cell_put(cell); 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci dev_pm_opp_set_supported_hw(dev, &val, 1); 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistruct msm_gpu *a5xx_gpu_init(struct drm_device *dev) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 15688c2ecf20Sopenharmony_ci struct platform_device *pdev = priv->gpu_pdev; 15698c2ecf20Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = NULL; 15708c2ecf20Sopenharmony_ci struct adreno_gpu *adreno_gpu; 15718c2ecf20Sopenharmony_ci struct msm_gpu *gpu; 15728c2ecf20Sopenharmony_ci unsigned int nr_rings; 15738c2ecf20Sopenharmony_ci int ret; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (!pdev) { 15768c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "No A5XX device is defined\n"); 15778c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL); 15818c2ecf20Sopenharmony_ci if (!a5xx_gpu) 15828c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci adreno_gpu = &a5xx_gpu->base; 15858c2ecf20Sopenharmony_ci gpu = &adreno_gpu->base; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci adreno_gpu->registers = a5xx_registers; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci a5xx_gpu->lm_leakage = 0x4E001A; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci check_speed_bin(&pdev->dev); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci nr_rings = 4; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) 15968c2ecf20Sopenharmony_ci nr_rings = 1; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, nr_rings); 15998c2ecf20Sopenharmony_ci if (ret) { 16008c2ecf20Sopenharmony_ci a5xx_destroy(&(a5xx_gpu->base.base)); 16018c2ecf20Sopenharmony_ci return ERR_PTR(ret); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (gpu->aspace) 16058c2ecf20Sopenharmony_ci msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu, a5xx_fault_handler); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Set up the preemption specific bits and pieces for each ringbuffer */ 16088c2ecf20Sopenharmony_ci a5xx_preempt_init(gpu); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci return gpu; 16118c2ecf20Sopenharmony_ci} 1612