162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <linux/cpumask.h> 862306a36Sopenharmony_ci#include <linux/firmware/qcom/qcom_scm.h> 962306a36Sopenharmony_ci#include <linux/pm_opp.h> 1062306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include "msm_gem.h" 1362306a36Sopenharmony_ci#include "msm_mmu.h" 1462306a36Sopenharmony_ci#include "a5xx_gpu.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciextern bool hang_debug; 1762306a36Sopenharmony_cistatic void a5xx_dump(struct msm_gpu *gpu); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define GPU_PAS_ID 13 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void update_shadow_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 2462306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (a5xx_gpu->has_whereami) { 2762306a36Sopenharmony_ci OUT_PKT7(ring, CP_WHERE_AM_I, 2); 2862306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(shadowptr(a5xx_gpu, ring))); 2962306a36Sopenharmony_ci OUT_RING(ring, upper_32_bits(shadowptr(a5xx_gpu, ring))); 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_civoid a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, 3462306a36Sopenharmony_ci bool sync) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 3762306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 3862306a36Sopenharmony_ci uint32_t wptr; 3962306a36Sopenharmony_ci unsigned long flags; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * Most flush operations need to issue a WHERE_AM_I opcode to sync up 4362306a36Sopenharmony_ci * the rptr shadow 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci if (sync) 4662306a36Sopenharmony_ci update_shadow_rptr(gpu, ring); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci spin_lock_irqsave(&ring->preempt_lock, flags); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Copy the shadow to the actual register */ 5162306a36Sopenharmony_ci ring->cur = ring->next; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Make sure to wrap wptr if we need to */ 5462306a36Sopenharmony_ci wptr = get_wptr(ring); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci spin_unlock_irqrestore(&ring->preempt_lock, flags); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Make sure everything is posted before making a decision */ 5962306a36Sopenharmony_ci mb(); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Update HW if this is the current ring and we are not in preempt */ 6262306a36Sopenharmony_ci if (a5xx_gpu->cur_ring == ring && !a5xx_in_preempt(a5xx_gpu)) 6362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct msm_ringbuffer *ring = submit->ring; 6962306a36Sopenharmony_ci struct drm_gem_object *obj; 7062306a36Sopenharmony_ci uint32_t *ptr, dwords; 7162306a36Sopenharmony_ci unsigned int i; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci for (i = 0; i < submit->nr_cmds; i++) { 7462306a36Sopenharmony_ci switch (submit->cmd[i].type) { 7562306a36Sopenharmony_ci case MSM_SUBMIT_CMD_IB_TARGET_BUF: 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 7862306a36Sopenharmony_ci if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci fallthrough; 8162306a36Sopenharmony_ci case MSM_SUBMIT_CMD_BUF: 8262306a36Sopenharmony_ci /* copy commands into RB: */ 8362306a36Sopenharmony_ci obj = submit->bos[submit->cmd[i].idx].obj; 8462306a36Sopenharmony_ci dwords = submit->cmd[i].size; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci ptr = msm_gem_get_vaddr(obj); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* _get_vaddr() shouldn't fail at this point, 8962306a36Sopenharmony_ci * since we've already mapped it once in 9062306a36Sopenharmony_ci * submit_reloc() 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci if (WARN_ON(IS_ERR_OR_NULL(ptr))) 9362306a36Sopenharmony_ci return; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (i = 0; i < dwords; i++) { 9662306a36Sopenharmony_ci /* normally the OUT_PKTn() would wait 9762306a36Sopenharmony_ci * for space for the packet. But since 9862306a36Sopenharmony_ci * we just OUT_RING() the whole thing, 9962306a36Sopenharmony_ci * need to call adreno_wait_ring() 10062306a36Sopenharmony_ci * ourself: 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci adreno_wait_ring(ring, 1); 10362306a36Sopenharmony_ci OUT_RING(ring, ptr[i]); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci msm_gem_put_vaddr(obj); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci a5xx_flush(gpu, ring, true); 11362306a36Sopenharmony_ci a5xx_preempt_trigger(gpu); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* we might not necessarily have a cmd from userspace to 11662306a36Sopenharmony_ci * trigger an event to know that submit has completed, so 11762306a36Sopenharmony_ci * do this manually: 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci a5xx_idle(gpu, ring); 12062306a36Sopenharmony_ci ring->memptrs->fence = submit->seqno; 12162306a36Sopenharmony_ci msm_gpu_retire(gpu); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 12762306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 12862306a36Sopenharmony_ci struct msm_ringbuffer *ring = submit->ring; 12962306a36Sopenharmony_ci unsigned int i, ibs = 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { 13262306a36Sopenharmony_ci gpu->cur_ctx_seqno = 0; 13362306a36Sopenharmony_ci a5xx_submit_in_rb(gpu, submit); 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); 13862306a36Sopenharmony_ci OUT_RING(ring, 0x02); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Turn off protected mode to write to special registers */ 14162306a36Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 14262306a36Sopenharmony_ci OUT_RING(ring, 0); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Set the save preemption record for the ring/command */ 14562306a36Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); 14662306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[submit->ring->id])); 14762306a36Sopenharmony_ci OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[submit->ring->id])); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Turn back on protected mode */ 15062306a36Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 15162306a36Sopenharmony_ci OUT_RING(ring, 1); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Enable local preemption for finegrain preemption */ 15462306a36Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); 15562306a36Sopenharmony_ci OUT_RING(ring, 0x1); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */ 15862306a36Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 15962306a36Sopenharmony_ci OUT_RING(ring, 0x02); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Submit the commands */ 16262306a36Sopenharmony_ci for (i = 0; i < submit->nr_cmds; i++) { 16362306a36Sopenharmony_ci switch (submit->cmd[i].type) { 16462306a36Sopenharmony_ci case MSM_SUBMIT_CMD_IB_TARGET_BUF: 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 16762306a36Sopenharmony_ci if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci fallthrough; 17062306a36Sopenharmony_ci case MSM_SUBMIT_CMD_BUF: 17162306a36Sopenharmony_ci OUT_PKT7(ring, CP_INDIRECT_BUFFER_PFE, 3); 17262306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); 17362306a36Sopenharmony_ci OUT_RING(ring, upper_32_bits(submit->cmd[i].iova)); 17462306a36Sopenharmony_ci OUT_RING(ring, submit->cmd[i].size); 17562306a36Sopenharmony_ci ibs++; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Periodically update shadow-wptr if needed, so that we 18162306a36Sopenharmony_ci * can see partial progress of submits with large # of 18262306a36Sopenharmony_ci * cmds.. otherwise we could needlessly stall waiting for 18362306a36Sopenharmony_ci * ringbuffer state, simply due to looking at a shadow 18462306a36Sopenharmony_ci * rptr value that has not been updated 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci if ((ibs % 32) == 0) 18762306a36Sopenharmony_ci update_shadow_rptr(gpu, ring); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Write the render mode to NULL (0) to indicate to the CP that the IBs 19262306a36Sopenharmony_ci * are done rendering - otherwise a lucky preemption would start 19362306a36Sopenharmony_ci * replaying from the last checkpoint 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci OUT_PKT7(ring, CP_SET_RENDER_MODE, 5); 19662306a36Sopenharmony_ci OUT_RING(ring, 0); 19762306a36Sopenharmony_ci OUT_RING(ring, 0); 19862306a36Sopenharmony_ci OUT_RING(ring, 0); 19962306a36Sopenharmony_ci OUT_RING(ring, 0); 20062306a36Sopenharmony_ci OUT_RING(ring, 0); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Turn off IB level preemptions */ 20362306a36Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 20462306a36Sopenharmony_ci OUT_RING(ring, 0x01); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Write the fence to the scratch register */ 20762306a36Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_SCRATCH_REG(2), 1); 20862306a36Sopenharmony_ci OUT_RING(ring, submit->seqno); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* 21162306a36Sopenharmony_ci * Execute a CACHE_FLUSH_TS event. This will ensure that the 21262306a36Sopenharmony_ci * timestamp is written to the memory and then triggers the interrupt 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci OUT_PKT7(ring, CP_EVENT_WRITE, 4); 21562306a36Sopenharmony_ci OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS) | 21662306a36Sopenharmony_ci CP_EVENT_WRITE_0_IRQ); 21762306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(rbmemptr(ring, fence))); 21862306a36Sopenharmony_ci OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence))); 21962306a36Sopenharmony_ci OUT_RING(ring, submit->seqno); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Yield the floor on command completion */ 22262306a36Sopenharmony_ci OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * If dword[2:1] are non zero, they specify an address for the CP to 22562306a36Sopenharmony_ci * write the value of dword[3] to on preemption complete. Write 0 to 22662306a36Sopenharmony_ci * skip the write 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci OUT_RING(ring, 0x00); 22962306a36Sopenharmony_ci OUT_RING(ring, 0x00); 23062306a36Sopenharmony_ci /* Data value - not used if the address above is 0 */ 23162306a36Sopenharmony_ci OUT_RING(ring, 0x01); 23262306a36Sopenharmony_ci /* Set bit 0 to trigger an interrupt on preempt complete */ 23362306a36Sopenharmony_ci OUT_RING(ring, 0x01); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* A WHERE_AM_I packet is not needed after a YIELD */ 23662306a36Sopenharmony_ci a5xx_flush(gpu, ring, false); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Check to see if we need to start preemption */ 23962306a36Sopenharmony_ci a5xx_preempt_trigger(gpu); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const struct adreno_five_hwcg_regs { 24362306a36Sopenharmony_ci u32 offset; 24462306a36Sopenharmony_ci u32 value; 24562306a36Sopenharmony_ci} a5xx_hwcg[] = { 24662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP0, 0x02222222}, 24762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP1, 0x02222222}, 24862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP2, 0x02222222}, 24962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP3, 0x02222222}, 25062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220}, 25162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP1, 0x02222220}, 25262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP2, 0x02222220}, 25362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP3, 0x02222220}, 25462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF}, 25562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP1, 0x0000F3CF}, 25662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP2, 0x0000F3CF}, 25762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP3, 0x0000F3CF}, 25862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP0, 0x00000080}, 25962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP1, 0x00000080}, 26062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP2, 0x00000080}, 26162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP3, 0x00000080}, 26262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP0, 0x22222222}, 26362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP1, 0x22222222}, 26462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP2, 0x22222222}, 26562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP3, 0x22222222}, 26662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222}, 26762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222}, 26862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP2, 0x22222222}, 26962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP3, 0x22222222}, 27062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP0, 0x00002222}, 27162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP1, 0x00002222}, 27262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP2, 0x00002222}, 27362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP3, 0x00002222}, 27462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP0, 0x77777777}, 27562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP1, 0x77777777}, 27662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP2, 0x77777777}, 27762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP3, 0x77777777}, 27862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP0, 0x77777777}, 27962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP1, 0x77777777}, 28062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP2, 0x77777777}, 28162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP3, 0x77777777}, 28262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP0, 0x00007777}, 28362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP1, 0x00007777}, 28462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP2, 0x00007777}, 28562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP3, 0x00007777}, 28662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP0, 0x11111111}, 28762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP1, 0x11111111}, 28862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP2, 0x11111111}, 28962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP3, 0x11111111}, 29062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111}, 29162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP1, 0x11111111}, 29262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP2, 0x11111111}, 29362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP3, 0x11111111}, 29462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP0, 0x00001111}, 29562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP1, 0x00001111}, 29662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP2, 0x00001111}, 29762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP3, 0x00001111}, 29862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222}, 29962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222}, 30062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222}, 30162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222}, 30262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_UCHE, 0x00444444}, 30362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002}, 30462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB0, 0x22222222}, 30562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB1, 0x22222222}, 30662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB2, 0x22222222}, 30762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB3, 0x22222222}, 30862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB0, 0x00222222}, 30962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB1, 0x00222222}, 31062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB2, 0x00222222}, 31162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB3, 0x00222222}, 31262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU0, 0x00022220}, 31362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU1, 0x00022220}, 31462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU2, 0x00022220}, 31562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU3, 0x00022220}, 31662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RAC, 0x05522222}, 31762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RAC, 0x00505555}, 31862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0, 0x04040404}, 31962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1, 0x04040404}, 32062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU2, 0x04040404}, 32162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU3, 0x04040404}, 32262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RAC, 0x07444044}, 32362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0, 0x00000002}, 32462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1, 0x00000002}, 32562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_2, 0x00000002}, 32662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_3, 0x00000002}, 32762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RAC, 0x00010011}, 32862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222}, 32962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_GPC, 0x02222222}, 33062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_VFD, 0x00002222}, 33162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000}, 33262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_GPC, 0x04104004}, 33362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_VFD, 0x00000000}, 33462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000}, 33562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000}, 33662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_GPC, 0x00000200}, 33762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_VFD, 0x00002222} 33862306a36Sopenharmony_ci}, a50x_hwcg[] = { 33962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP0, 0x02222222}, 34062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220}, 34162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF}, 34262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP0, 0x00000080}, 34362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP0, 0x22222222}, 34462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222}, 34562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP0, 0x00002222}, 34662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP0, 0x77777777}, 34762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP0, 0x77777777}, 34862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP0, 0x00007777}, 34962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP0, 0x11111111}, 35062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111}, 35162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP0, 0x00001111}, 35262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222}, 35362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222}, 35462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222}, 35562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222}, 35662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_UCHE, 0x00FFFFF4}, 35762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002}, 35862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB0, 0x22222222}, 35962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB0, 0x00222222}, 36062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU0, 0x00022220}, 36162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RAC, 0x05522222}, 36262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RAC, 0x00505555}, 36362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0, 0x04040404}, 36462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RAC, 0x07444044}, 36562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0, 0x00000002}, 36662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RAC, 0x00010011}, 36762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222}, 36862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_GPC, 0x02222222}, 36962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_VFD, 0x00002222}, 37062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000}, 37162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_GPC, 0x04104004}, 37262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_VFD, 0x00000000}, 37362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000}, 37462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000}, 37562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_GPC, 0x00000200}, 37662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_VFD, 0x00002222}, 37762306a36Sopenharmony_ci}, a512_hwcg[] = { 37862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP0, 0x02222222}, 37962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_SP1, 0x02222222}, 38062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP0, 0x02222220}, 38162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_SP1, 0x02222220}, 38262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP0, 0x0000F3CF}, 38362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_SP1, 0x0000F3CF}, 38462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP0, 0x00000080}, 38562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_SP1, 0x00000080}, 38662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP0, 0x22222222}, 38762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TP1, 0x22222222}, 38862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP0, 0x22222222}, 38962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_TP1, 0x22222222}, 39062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP0, 0x00002222}, 39162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_TP1, 0x00002222}, 39262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP0, 0x77777777}, 39362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TP1, 0x77777777}, 39462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP0, 0x77777777}, 39562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST2_TP1, 0x77777777}, 39662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP0, 0x00007777}, 39762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST3_TP1, 0x00007777}, 39862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP0, 0x11111111}, 39962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TP1, 0x11111111}, 40062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP0, 0x11111111}, 40162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY2_TP1, 0x11111111}, 40262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP0, 0x00001111}, 40362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY3_TP1, 0x00001111}, 40462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_UCHE, 0x22222222}, 40562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_UCHE, 0x22222222}, 40662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL3_UCHE, 0x22222222}, 40762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL4_UCHE, 0x00222222}, 40862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_UCHE, 0x00444444}, 40962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_UCHE, 0x00000002}, 41062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB0, 0x22222222}, 41162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RB1, 0x22222222}, 41262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB0, 0x00222222}, 41362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RB1, 0x00222222}, 41462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU0, 0x00022220}, 41562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_CCU1, 0x00022220}, 41662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_RAC, 0x05522222}, 41762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL2_RAC, 0x00505555}, 41862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0, 0x04040404}, 41962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1, 0x04040404}, 42062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_RAC, 0x07444044}, 42162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0, 0x00000002}, 42262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1, 0x00000002}, 42362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_RAC, 0x00010011}, 42462306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM, 0x04222222}, 42562306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_GPC, 0x02222222}, 42662306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_MODE_VFD, 0x00002222}, 42762306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00000000}, 42862306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_GPC, 0x04104004}, 42962306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_HYST_VFD, 0x00000000}, 43062306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_HLSQ, 0x00000000}, 43162306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00004000}, 43262306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_GPC, 0x00000200}, 43362306a36Sopenharmony_ci {REG_A5XX_RBBM_CLOCK_DELAY_VFD, 0x00002222}, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_civoid a5xx_set_hwcg(struct msm_gpu *gpu, bool state) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 43962306a36Sopenharmony_ci const struct adreno_five_hwcg_regs *regs; 44062306a36Sopenharmony_ci unsigned int i, sz; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) { 44362306a36Sopenharmony_ci regs = a50x_hwcg; 44462306a36Sopenharmony_ci sz = ARRAY_SIZE(a50x_hwcg); 44562306a36Sopenharmony_ci } else if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu)) { 44662306a36Sopenharmony_ci regs = a512_hwcg; 44762306a36Sopenharmony_ci sz = ARRAY_SIZE(a512_hwcg); 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci regs = a5xx_hwcg; 45062306a36Sopenharmony_ci sz = ARRAY_SIZE(a5xx_hwcg); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci for (i = 0; i < sz; i++) 45462306a36Sopenharmony_ci gpu_write(gpu, regs[i].offset, 45562306a36Sopenharmony_ci state ? regs[i].value : 0); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (adreno_is_a540(adreno_gpu)) { 45862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_DELAY_GPMU, state ? 0x00000770 : 0); 45962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_HYST_GPMU, state ? 0x00000004 : 0); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, state ? 0xAAA8AA00 : 0); 46362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_ISDB_CNT, state ? 0x182 : 0x180); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int a5xx_me_init(struct msm_gpu *gpu) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 46962306a36Sopenharmony_ci struct msm_ringbuffer *ring = gpu->rb[0]; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci OUT_PKT7(ring, CP_ME_INIT, 8); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci OUT_RING(ring, 0x0000002F); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Enable multiple hardware contexts */ 47662306a36Sopenharmony_ci OUT_RING(ring, 0x00000003); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Enable error detection */ 47962306a36Sopenharmony_ci OUT_RING(ring, 0x20000000); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* Don't enable header dump */ 48262306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 48362306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Specify workarounds for various microcode issues */ 48662306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a530(adreno_gpu)) { 48762306a36Sopenharmony_ci /* Workaround for token end syncs 48862306a36Sopenharmony_ci * Force a WFI after every direct-render 3D mode draw and every 48962306a36Sopenharmony_ci * 2D mode 3 draw 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci OUT_RING(ring, 0x0000000B); 49262306a36Sopenharmony_ci } else if (adreno_is_a510(adreno_gpu)) { 49362306a36Sopenharmony_ci /* Workaround for token and syncs */ 49462306a36Sopenharmony_ci OUT_RING(ring, 0x00000001); 49562306a36Sopenharmony_ci } else { 49662306a36Sopenharmony_ci /* No workarounds enabled */ 49762306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 50162306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci a5xx_flush(gpu, ring, true); 50462306a36Sopenharmony_ci return a5xx_idle(gpu, ring) ? 0 : -EINVAL; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int a5xx_preempt_start(struct msm_gpu *gpu) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 51062306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 51162306a36Sopenharmony_ci struct msm_ringbuffer *ring = gpu->rb[0]; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (gpu->nr_rings == 1) 51462306a36Sopenharmony_ci return 0; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Turn off protected mode to write to special registers */ 51762306a36Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 51862306a36Sopenharmony_ci OUT_RING(ring, 0); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Set the save preemption record for the ring/command */ 52162306a36Sopenharmony_ci OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2); 52262306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[ring->id])); 52362306a36Sopenharmony_ci OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[ring->id])); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Turn back on protected mode */ 52662306a36Sopenharmony_ci OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); 52762306a36Sopenharmony_ci OUT_RING(ring, 1); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1); 53062306a36Sopenharmony_ci OUT_RING(ring, 0x00); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1); 53362306a36Sopenharmony_ci OUT_RING(ring, 0x01); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci OUT_PKT7(ring, CP_YIELD_ENABLE, 1); 53662306a36Sopenharmony_ci OUT_RING(ring, 0x01); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Yield the floor on command completion */ 53962306a36Sopenharmony_ci OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); 54062306a36Sopenharmony_ci OUT_RING(ring, 0x00); 54162306a36Sopenharmony_ci OUT_RING(ring, 0x00); 54262306a36Sopenharmony_ci OUT_RING(ring, 0x01); 54362306a36Sopenharmony_ci OUT_RING(ring, 0x01); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* The WHERE_AMI_I packet is not needed after a YIELD is issued */ 54662306a36Sopenharmony_ci a5xx_flush(gpu, ring, false); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return a5xx_idle(gpu, ring) ? 0 : -EINVAL; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void a5xx_ucode_check_version(struct a5xx_gpu *a5xx_gpu, 55262306a36Sopenharmony_ci struct drm_gem_object *obj) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci u32 *buf = msm_gem_get_vaddr(obj); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (IS_ERR(buf)) 55762306a36Sopenharmony_ci return; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * If the lowest nibble is 0xa that is an indication that this microcode 56162306a36Sopenharmony_ci * has been patched. The actual version is in dword [3] but we only care 56262306a36Sopenharmony_ci * about the patchlevel which is the lowest nibble of dword [3] 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci if (((buf[0] & 0xf) == 0xa) && (buf[2] & 0xf) >= 1) 56562306a36Sopenharmony_ci a5xx_gpu->has_whereami = true; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci msm_gem_put_vaddr(obj); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int a5xx_ucode_load(struct msm_gpu *gpu) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 57362306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 57462306a36Sopenharmony_ci int ret; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!a5xx_gpu->pm4_bo) { 57762306a36Sopenharmony_ci a5xx_gpu->pm4_bo = adreno_fw_create_bo(gpu, 57862306a36Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PM4], &a5xx_gpu->pm4_iova); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (IS_ERR(a5xx_gpu->pm4_bo)) { 58262306a36Sopenharmony_ci ret = PTR_ERR(a5xx_gpu->pm4_bo); 58362306a36Sopenharmony_ci a5xx_gpu->pm4_bo = NULL; 58462306a36Sopenharmony_ci DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PM4: %d\n", 58562306a36Sopenharmony_ci ret); 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci msm_gem_object_set_name(a5xx_gpu->pm4_bo, "pm4fw"); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (!a5xx_gpu->pfp_bo) { 59362306a36Sopenharmony_ci a5xx_gpu->pfp_bo = adreno_fw_create_bo(gpu, 59462306a36Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PFP], &a5xx_gpu->pfp_iova); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (IS_ERR(a5xx_gpu->pfp_bo)) { 59762306a36Sopenharmony_ci ret = PTR_ERR(a5xx_gpu->pfp_bo); 59862306a36Sopenharmony_ci a5xx_gpu->pfp_bo = NULL; 59962306a36Sopenharmony_ci DRM_DEV_ERROR(gpu->dev->dev, "could not allocate PFP: %d\n", 60062306a36Sopenharmony_ci ret); 60162306a36Sopenharmony_ci return ret; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci msm_gem_object_set_name(a5xx_gpu->pfp_bo, "pfpfw"); 60562306a36Sopenharmony_ci a5xx_ucode_check_version(a5xx_gpu, a5xx_gpu->pfp_bo); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (a5xx_gpu->has_whereami) { 60962306a36Sopenharmony_ci if (!a5xx_gpu->shadow_bo) { 61062306a36Sopenharmony_ci a5xx_gpu->shadow = msm_gem_kernel_new(gpu->dev, 61162306a36Sopenharmony_ci sizeof(u32) * gpu->nr_rings, 61262306a36Sopenharmony_ci MSM_BO_WC | MSM_BO_MAP_PRIV, 61362306a36Sopenharmony_ci gpu->aspace, &a5xx_gpu->shadow_bo, 61462306a36Sopenharmony_ci &a5xx_gpu->shadow_iova); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (IS_ERR(a5xx_gpu->shadow)) 61762306a36Sopenharmony_ci return PTR_ERR(a5xx_gpu->shadow); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci msm_gem_object_set_name(a5xx_gpu->shadow_bo, "shadow"); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci } else if (gpu->nr_rings > 1) { 62262306a36Sopenharmony_ci /* Disable preemption if WHERE_AM_I isn't available */ 62362306a36Sopenharmony_ci a5xx_preempt_fini(gpu); 62462306a36Sopenharmony_ci gpu->nr_rings = 1; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci return 0; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci#define SCM_GPU_ZAP_SHADER_RESUME 0 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int a5xx_zap_shader_resume(struct msm_gpu *gpu) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 63562306a36Sopenharmony_ci int ret; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* 63862306a36Sopenharmony_ci * Adreno 506 have CPZ Retention feature and doesn't require 63962306a36Sopenharmony_ci * to resume zap shader 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu)) 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); 64562306a36Sopenharmony_ci if (ret) 64662306a36Sopenharmony_ci DRM_ERROR("%s: zap-shader resume failed: %d\n", 64762306a36Sopenharmony_ci gpu->name, ret); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int a5xx_zap_shader_init(struct msm_gpu *gpu) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci static bool loaded; 65562306a36Sopenharmony_ci int ret; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * If the zap shader is already loaded into memory we just need to kick 65962306a36Sopenharmony_ci * the remote processor to reinitialize it 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci if (loaded) 66262306a36Sopenharmony_ci return a5xx_zap_shader_resume(gpu); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ret = adreno_zap_shader_load(gpu, GPU_PAS_ID); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci loaded = !ret; 66762306a36Sopenharmony_ci return ret; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ 67162306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ 67262306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ 67362306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ 67462306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ 67562306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW | \ 67662306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_HW_ERROR | \ 67762306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT | \ 67862306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_SW | \ 67962306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | \ 68062306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS | \ 68162306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int a5xx_hw_init(struct msm_gpu *gpu) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 68662306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 68762306a36Sopenharmony_ci u32 regbit; 68862306a36Sopenharmony_ci int ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu) || 69362306a36Sopenharmony_ci adreno_is_a540(adreno_gpu)) 69462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Make all blocks contribute to the GPU BUSY perf counter */ 69762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED, 0xFFFFFFFF); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Enable RBBM error reporting bits */ 70062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL0, 0x00000001); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_FAULT_DETECT_MASK) { 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * Mask out the activity signals from RB1-3 to avoid false 70562306a36Sopenharmony_ci * positives 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL11, 70962306a36Sopenharmony_ci 0xF0000000); 71062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL12, 71162306a36Sopenharmony_ci 0xFFFFFFFF); 71262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL13, 71362306a36Sopenharmony_ci 0xFFFFFFFF); 71462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL14, 71562306a36Sopenharmony_ci 0xFFFFFFFF); 71662306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL15, 71762306a36Sopenharmony_ci 0xFFFFFFFF); 71862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL16, 71962306a36Sopenharmony_ci 0xFFFFFFFF); 72062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL17, 72162306a36Sopenharmony_ci 0xFFFFFFFF); 72262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL18, 72362306a36Sopenharmony_ci 0xFFFFFFFF); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Enable fault detection */ 72762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INTERFACE_HANG_INT_CNTL, 72862306a36Sopenharmony_ci (1 << 30) | 0xFFFF); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Turn on performance counters */ 73162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_CNTL, 0x01); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Select CP0 to always count cycles */ 73462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PERFCTR_CP_SEL_0, PERF_CP_ALWAYS_COUNT); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Select RBBM0 to countable 6 to get the busy status for devfreq */ 73762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0, 6); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Increase VFD cache access so LRZ and other data gets evicted less */ 74062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_CACHE_WAYS, 0x02); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Disable L2 bypass in the UCHE */ 74362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_LO, 0xFFFF0000); 74462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_TRAP_BASE_HI, 0x0001FFFF); 74562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_LO, 0xFFFF0000); 74662306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_WRITE_THRU_BASE_HI, 0x0001FFFF); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Set the GMEM VA range (0 to gpu->gmem) */ 74962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000); 75062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_HI, 0x00000000); 75162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO, 75262306a36Sopenharmony_ci 0x00100000 + adreno_gpu->info->gmem - 1); 75362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || 75662306a36Sopenharmony_ci adreno_is_a510(adreno_gpu)) { 75762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x20); 75862306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) 75962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x20); 76262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); 76362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x20100D0A); 76462306a36Sopenharmony_ci } else { 76562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x40); 76662306a36Sopenharmony_ci if (adreno_is_a530(adreno_gpu)) 76762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x40); 76862306a36Sopenharmony_ci else 76962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); 77062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_2, 0x80000060); 77162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) 77562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 77662306a36Sopenharmony_ci (0x100 << 11 | 0x100 << 22)); 77762306a36Sopenharmony_ci else if (adreno_is_a509(adreno_gpu) || adreno_is_a510(adreno_gpu) || 77862306a36Sopenharmony_ci adreno_is_a512(adreno_gpu)) 77962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 78062306a36Sopenharmony_ci (0x200 << 11 | 0x200 << 22)); 78162306a36Sopenharmony_ci else 78262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 78362306a36Sopenharmony_ci (0x400 << 11 | 0x300 << 22)); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_TWO_PASS_USE_WFI) 78662306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8)); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* 78962306a36Sopenharmony_ci * Disable the RB sampler datapath DP2 clock gating optimization 79062306a36Sopenharmony_ci * for 1-SP GPUs, as it is enabled by default. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || 79362306a36Sopenharmony_ci adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu)) 79462306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_RB_DBG_ECO_CNTL, 0, (1 << 9)); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* Disable UCHE global filter as SP can invalidate/flush independently */ 79762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_MODE_CNTL, BIT(29)); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Enable USE_RETENTION_FLOPS */ 80062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_CHICKEN_DBG, 0x02000000); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* Enable ME/PFP split notification */ 80362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL1, 0xA6FFFFFF); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* 80662306a36Sopenharmony_ci * In A5x, CCU can send context_done event of a particular context to 80762306a36Sopenharmony_ci * UCHE which ultimately reaches CP even when there is valid 80862306a36Sopenharmony_ci * transaction of that context inside CCU. This can let CP to program 80962306a36Sopenharmony_ci * config registers, which will make the "valid transaction" inside 81062306a36Sopenharmony_ci * CCU to be interpreted differently. This can cause gpu fault. This 81162306a36Sopenharmony_ci * bug is fixed in latest A510 revision. To enable this bug fix - 81262306a36Sopenharmony_ci * bit[11] of RB_DBG_ECO_CNTL need to be set to 0, default is 1 81362306a36Sopenharmony_ci * (disable). For older A510 version this bit is unused. 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci if (adreno_is_a510(adreno_gpu)) 81662306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_RB_DBG_ECO_CNTL, (1 << 11), 0); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* Enable HWCG */ 81962306a36Sopenharmony_ci a5xx_set_hwcg(gpu, true); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL2, 0x0000003F); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* Set the highest bank bit */ 82462306a36Sopenharmony_ci if (adreno_is_a540(adreno_gpu) || adreno_is_a530(adreno_gpu)) 82562306a36Sopenharmony_ci regbit = 2; 82662306a36Sopenharmony_ci else 82762306a36Sopenharmony_ci regbit = 1; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, regbit << 7); 83062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, regbit << 1); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu) || 83362306a36Sopenharmony_ci adreno_is_a540(adreno_gpu)) 83462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, regbit); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Disable All flat shading optimization (ALLFLATOPTDIS) */ 83762306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, (1 << 10)); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Protect registers from the CP */ 84062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT_CNTL, 0x00000007); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* RBBM */ 84362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(0), ADRENO_PROTECT_RW(0x04, 4)); 84462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(1), ADRENO_PROTECT_RW(0x08, 8)); 84562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(2), ADRENO_PROTECT_RW(0x10, 16)); 84662306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(3), ADRENO_PROTECT_RW(0x20, 32)); 84762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(4), ADRENO_PROTECT_RW(0x40, 64)); 84862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(5), ADRENO_PROTECT_RW(0x80, 64)); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Content protect */ 85162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(6), 85262306a36Sopenharmony_ci ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 85362306a36Sopenharmony_ci 16)); 85462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(7), 85562306a36Sopenharmony_ci ADRENO_PROTECT_RW(REG_A5XX_RBBM_SECVID_TRUST_CNTL, 2)); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* CP */ 85862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(8), ADRENO_PROTECT_RW(0x800, 64)); 85962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(9), ADRENO_PROTECT_RW(0x840, 8)); 86062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(10), ADRENO_PROTECT_RW(0x880, 32)); 86162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(11), ADRENO_PROTECT_RW(0xAA0, 1)); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* RB */ 86462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(12), ADRENO_PROTECT_RW(0xCC0, 1)); 86562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(13), ADRENO_PROTECT_RW(0xCF0, 2)); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* VPC */ 86862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(14), ADRENO_PROTECT_RW(0xE68, 8)); 86962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(15), ADRENO_PROTECT_RW(0xE70, 16)); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* UCHE */ 87262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(16), ADRENO_PROTECT_RW(0xE80, 16)); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* SMMU */ 87562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PROTECT(17), 87662306a36Sopenharmony_ci ADRENO_PROTECT_RW(0x10000, 0x8000)); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_CNTL, 0); 87962306a36Sopenharmony_ci /* 88062306a36Sopenharmony_ci * Disable the trusted memory range - we don't actually supported secure 88162306a36Sopenharmony_ci * memory rendering at this point in time and we don't want to block off 88262306a36Sopenharmony_ci * part of the virtual memory space. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO, 0x00000000); 88562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE, 0x00000000); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Put the GPU into 64 bit by default */ 88862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ADDR_MODE_CNTL, 0x1); 88962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VSC_ADDR_MODE_CNTL, 0x1); 89062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_GRAS_ADDR_MODE_CNTL, 0x1); 89162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RB_ADDR_MODE_CNTL, 0x1); 89262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_PC_ADDR_MODE_CNTL, 0x1); 89362306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_HLSQ_ADDR_MODE_CNTL, 0x1); 89462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VFD_ADDR_MODE_CNTL, 0x1); 89562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VPC_ADDR_MODE_CNTL, 0x1); 89662306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_UCHE_ADDR_MODE_CNTL, 0x1); 89762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_SP_ADDR_MODE_CNTL, 0x1); 89862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_TPL1_ADDR_MODE_CNTL, 0x1); 89962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* 90262306a36Sopenharmony_ci * VPC corner case with local memory load kill leads to corrupt 90362306a36Sopenharmony_ci * internal state. Normal Disable does not work for all a5x chips. 90462306a36Sopenharmony_ci * So do the following setting to disable it. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci if (adreno_gpu->info->quirks & ADRENO_QUIRK_LMLOADKILL_DISABLE) { 90762306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, BIT(23)); 90862306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_HLSQ_DBG_ECO_CNTL, BIT(18), 0); 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ret = adreno_hw_init(gpu); 91262306a36Sopenharmony_ci if (ret) 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu)) 91662306a36Sopenharmony_ci a5xx_gpmu_ucode_init(gpu); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_ME_INSTR_BASE_LO, a5xx_gpu->pm4_iova); 91962306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_PFP_INSTR_BASE_LO, a5xx_gpu->pfp_iova); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* Set the ringbuffer address */ 92262306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_RB_BASE, gpu->rb[0]->iova); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* 92562306a36Sopenharmony_ci * If the microcode supports the WHERE_AM_I opcode then we can use that 92662306a36Sopenharmony_ci * in lieu of the RPTR shadow and enable preemption. Otherwise, we 92762306a36Sopenharmony_ci * can't safely use the RPTR shadow or preemption. In either case, the 92862306a36Sopenharmony_ci * RPTR shadow should be disabled in hardware. 92962306a36Sopenharmony_ci */ 93062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_RB_CNTL, 93162306a36Sopenharmony_ci MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Configure the RPTR shadow if needed: */ 93462306a36Sopenharmony_ci if (a5xx_gpu->shadow_bo) { 93562306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR, 93662306a36Sopenharmony_ci shadowptr(a5xx_gpu, gpu->rb[0])); 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci a5xx_preempt_hw_init(gpu); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* Disable the interrupts through the initial bringup stage */ 94262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_0_MASK, A5XX_INT_MASK); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Clear ME_HALT to start the micro engine */ 94562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PFP_ME_CNTL, 0); 94662306a36Sopenharmony_ci ret = a5xx_me_init(gpu); 94762306a36Sopenharmony_ci if (ret) 94862306a36Sopenharmony_ci return ret; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci ret = a5xx_power_init(gpu); 95162306a36Sopenharmony_ci if (ret) 95262306a36Sopenharmony_ci return ret; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * Send a pipeline event stat to get misbehaving counters to start 95662306a36Sopenharmony_ci * ticking correctly 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci if (adreno_is_a530(adreno_gpu)) { 95962306a36Sopenharmony_ci OUT_PKT7(gpu->rb[0], CP_EVENT_WRITE, 1); 96062306a36Sopenharmony_ci OUT_RING(gpu->rb[0], CP_EVENT_WRITE_0_EVENT(STAT_EVENT)); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci a5xx_flush(gpu, gpu->rb[0], true); 96362306a36Sopenharmony_ci if (!a5xx_idle(gpu, gpu->rb[0])) 96462306a36Sopenharmony_ci return -EINVAL; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * If the chip that we are using does support loading one, then 96962306a36Sopenharmony_ci * try to load a zap shader into the secure world. If successful 97062306a36Sopenharmony_ci * we can use the CP to switch out of secure mode. If not then we 97162306a36Sopenharmony_ci * have no resource but to try to switch ourselves out manually. If we 97262306a36Sopenharmony_ci * guessed wrong then access to the RBBM_SECVID_TRUST_CNTL register will 97362306a36Sopenharmony_ci * be blocked and a permissions violation will soon follow. 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci ret = a5xx_zap_shader_init(gpu); 97662306a36Sopenharmony_ci if (!ret) { 97762306a36Sopenharmony_ci OUT_PKT7(gpu->rb[0], CP_SET_SECURE_MODE, 1); 97862306a36Sopenharmony_ci OUT_RING(gpu->rb[0], 0x00000000); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci a5xx_flush(gpu, gpu->rb[0], true); 98162306a36Sopenharmony_ci if (!a5xx_idle(gpu, gpu->rb[0])) 98262306a36Sopenharmony_ci return -EINVAL; 98362306a36Sopenharmony_ci } else if (ret == -ENODEV) { 98462306a36Sopenharmony_ci /* 98562306a36Sopenharmony_ci * This device does not use zap shader (but print a warning 98662306a36Sopenharmony_ci * just in case someone got their dt wrong.. hopefully they 98762306a36Sopenharmony_ci * have a debug UART to realize the error of their ways... 98862306a36Sopenharmony_ci * if you mess this up you are about to crash horribly) 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ci dev_warn_once(gpu->dev->dev, 99162306a36Sopenharmony_ci "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n"); 99262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); 99362306a36Sopenharmony_ci } else { 99462306a36Sopenharmony_ci return ret; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Last step - yield the ringbuffer */ 99862306a36Sopenharmony_ci a5xx_preempt_start(gpu); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic void a5xx_recover(struct msm_gpu *gpu) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci int i; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci adreno_dump_info(gpu); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 101062306a36Sopenharmony_ci printk("CP_SCRATCH_REG%d: %u\n", i, 101162306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(i))); 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (hang_debug) 101562306a36Sopenharmony_ci a5xx_dump(gpu); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 1); 101862306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_SW_RESET_CMD); 101962306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_SW_RESET_CMD, 0); 102062306a36Sopenharmony_ci adreno_recover(gpu); 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic void a5xx_destroy(struct msm_gpu *gpu) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 102662306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci DBG("%s", gpu->name); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci a5xx_preempt_fini(gpu); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (a5xx_gpu->pm4_bo) { 103362306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace); 103462306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pm4_bo); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (a5xx_gpu->pfp_bo) { 103862306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace); 103962306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pfp_bo); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (a5xx_gpu->gpmu_bo) { 104362306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->gpmu_bo, gpu->aspace); 104462306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->gpmu_bo); 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (a5xx_gpu->shadow_bo) { 104862306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->shadow_bo, gpu->aspace); 104962306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->shadow_bo); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci adreno_gpu_cleanup(adreno_gpu); 105362306a36Sopenharmony_ci kfree(a5xx_gpu); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic inline bool _a5xx_check_idle(struct msm_gpu *gpu) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci if (gpu_read(gpu, REG_A5XX_RBBM_STATUS) & ~A5XX_RBBM_STATUS_HI_BUSY) 105962306a36Sopenharmony_ci return false; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* 106262306a36Sopenharmony_ci * Nearly every abnormality ends up pausing the GPU and triggering a 106362306a36Sopenharmony_ci * fault so we can safely just watch for this one interrupt to fire 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci return !(gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS) & 106662306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT); 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cibool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 107262306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (ring != a5xx_gpu->cur_ring) { 107562306a36Sopenharmony_ci WARN(1, "Tried to idle a non-current ringbuffer\n"); 107662306a36Sopenharmony_ci return false; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* wait for CP to drain ringbuffer: */ 108062306a36Sopenharmony_ci if (!adreno_idle(gpu, ring)) 108162306a36Sopenharmony_ci return false; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (spin_until(_a5xx_check_idle(gpu))) { 108462306a36Sopenharmony_ci DRM_ERROR("%s: %ps: timeout waiting for GPU to idle: status %8.8X irq %8.8X rptr/wptr %d/%d\n", 108562306a36Sopenharmony_ci gpu->name, __builtin_return_address(0), 108662306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS), 108762306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS), 108862306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_RPTR), 108962306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_WPTR)); 109062306a36Sopenharmony_ci return false; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return true; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int a5xx_fault_handler(void *arg, unsigned long iova, int flags, void *data) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct msm_gpu *gpu = arg; 109962306a36Sopenharmony_ci struct adreno_smmu_fault_info *info = data; 110062306a36Sopenharmony_ci char block[12] = "unknown"; 110162306a36Sopenharmony_ci u32 scratch[] = { 110262306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(4)), 110362306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(5)), 110462306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(6)), 110562306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_SCRATCH_REG(7)), 110662306a36Sopenharmony_ci }; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (info) 110962306a36Sopenharmony_ci snprintf(block, sizeof(block), "%x", info->fsynr1); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return adreno_fault_handler(gpu, iova, flags, info, block, scratch); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic void a5xx_cp_err_irq(struct msm_gpu *gpu) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_CP_INTERRUPT_STATUS); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (status & A5XX_CP_INT_CP_OPCODE_ERROR) { 111962306a36Sopenharmony_ci u32 val; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, 0); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* 112462306a36Sopenharmony_ci * REG_A5XX_CP_PFP_STAT_DATA is indexed, and we want index 1 so 112562306a36Sopenharmony_ci * read it twice 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); 112962306a36Sopenharmony_ci val = gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | opcode error | possible opcode=0x%8.8X\n", 113262306a36Sopenharmony_ci val); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (status & A5XX_CP_INT_CP_HW_FAULT_ERROR) 113662306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | HW fault | status=0x%8.8X\n", 113762306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_HW_FAULT)); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (status & A5XX_CP_INT_CP_DMA_ERROR) 114062306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "CP | DMA error\n"); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (status & A5XX_CP_INT_CP_REGISTER_PROTECTION_ERROR) { 114362306a36Sopenharmony_ci u32 val = gpu_read(gpu, REG_A5XX_CP_PROTECT_STATUS); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 114662306a36Sopenharmony_ci "CP | protected mode error | %s | addr=0x%8.8X | status=0x%8.8X\n", 114762306a36Sopenharmony_ci val & (1 << 24) ? "WRITE" : "READ", 114862306a36Sopenharmony_ci (val & 0xFFFFF) >> 2, val); 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci if (status & A5XX_CP_INT_CP_AHB_ERROR) { 115262306a36Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_CP_AHB_FAULT); 115362306a36Sopenharmony_ci const char *access[16] = { "reserved", "reserved", 115462306a36Sopenharmony_ci "timestamp lo", "timestamp hi", "pfp read", "pfp write", 115562306a36Sopenharmony_ci "", "", "me read", "me write", "", "", "crashdump read", 115662306a36Sopenharmony_ci "crashdump write" }; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 115962306a36Sopenharmony_ci "CP | AHB error | addr=%X access=%s error=%d | status=0x%8.8X\n", 116062306a36Sopenharmony_ci status & 0xFFFFF, access[(status >> 24) & 0xF], 116162306a36Sopenharmony_ci (status & (1 << 31)), status); 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic void a5xx_rbbm_err_irq(struct msm_gpu *gpu, u32 status) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR) { 116862306a36Sopenharmony_ci u32 val = gpu_read(gpu, REG_A5XX_RBBM_AHB_ERROR_STATUS); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, 117162306a36Sopenharmony_ci "RBBM | AHB bus error | %s | addr=0x%X | ports=0x%X:0x%X\n", 117262306a36Sopenharmony_ci val & (1 << 28) ? "WRITE" : "READ", 117362306a36Sopenharmony_ci (val & 0xFFFFF) >> 2, (val >> 20) & 0x3, 117462306a36Sopenharmony_ci (val >> 24) & 0xF); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* Clear the error */ 117762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_AHB_CMD, (1 << 4)); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* Clear the interrupt */ 118062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, 118162306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT) 118562306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | AHB transfer timeout\n"); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT) 118862306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ME master split | status=0x%X\n", 118962306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_ME_SPLIT_STATUS)); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT) 119262306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | PFP master split | status=0x%X\n", 119362306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_PFP_SPLIT_STATUS)); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT) 119662306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ETS master split | status=0x%X\n", 119762306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_AHB_ETS_SPLIT_STATUS)); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) 120062306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB ASYNC overflow\n"); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_RBBM_ATB_BUS_OVERFLOW) 120362306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "RBBM | ATB bus overflow\n"); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void a5xx_uche_err_irq(struct msm_gpu *gpu) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci uint64_t addr = (uint64_t) gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_HI); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci addr |= gpu_read(gpu, REG_A5XX_UCHE_TRAP_LOG_LO); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "UCHE | Out of bounds access | addr=0x%llX\n", 121362306a36Sopenharmony_ci addr); 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic void a5xx_gpmu_err_irq(struct msm_gpu *gpu) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci dev_err_ratelimited(gpu->dev->dev, "GPMU | voltage droop\n"); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic void a5xx_fault_detect_irq(struct msm_gpu *gpu) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct drm_device *dev = gpu->dev; 122462306a36Sopenharmony_ci struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * If stalled on SMMU fault, we could trip the GPU's hang detection, 122862306a36Sopenharmony_ci * but the fault handler will trigger the devcore dump, and we want 122962306a36Sopenharmony_ci * to otherwise resume normally rather than killing the submit, so 123062306a36Sopenharmony_ci * just bail. 123162306a36Sopenharmony_ci */ 123262306a36Sopenharmony_ci if (gpu_read(gpu, REG_A5XX_RBBM_STATUS3) & BIT(24)) 123362306a36Sopenharmony_ci return; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_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", 123662306a36Sopenharmony_ci ring ? ring->id : -1, ring ? ring->fctx->last_fence : 0, 123762306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS), 123862306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_RPTR), 123962306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_RB_WPTR), 124062306a36Sopenharmony_ci gpu_read64(gpu, REG_A5XX_CP_IB1_BASE), 124162306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_IB1_BUFSZ), 124262306a36Sopenharmony_ci gpu_read64(gpu, REG_A5XX_CP_IB2_BASE), 124362306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_IB2_BUFSZ)); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* Turn off the hangcheck timer to keep it from bothering us */ 124662306a36Sopenharmony_ci del_timer(&gpu->hangcheck_timer); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci kthread_queue_work(gpu->worker, &gpu->recover_work); 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci#define RBBM_ERROR_MASK \ 125262306a36Sopenharmony_ci (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ 125362306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ 125462306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ 125562306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT | \ 125662306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT | \ 125762306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW) 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic irqreturn_t a5xx_irq(struct msm_gpu *gpu) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci struct msm_drm_private *priv = gpu->dev->dev_private; 126262306a36Sopenharmony_ci u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* 126562306a36Sopenharmony_ci * Clear all the interrupts except RBBM_AHB_ERROR - if we clear it 126662306a36Sopenharmony_ci * before the source is cleared the interrupt will storm. 126762306a36Sopenharmony_ci */ 126862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, 126962306a36Sopenharmony_ci status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (priv->disable_err_irq) { 127262306a36Sopenharmony_ci status &= A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | 127362306a36Sopenharmony_ci A5XX_RBBM_INT_0_MASK_CP_SW; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Pass status to a5xx_rbbm_err_irq because we've already cleared it */ 127762306a36Sopenharmony_ci if (status & RBBM_ERROR_MASK) 127862306a36Sopenharmony_ci a5xx_rbbm_err_irq(gpu, status); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_HW_ERROR) 128162306a36Sopenharmony_ci a5xx_cp_err_irq(gpu); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT) 128462306a36Sopenharmony_ci a5xx_fault_detect_irq(gpu); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS) 128762306a36Sopenharmony_ci a5xx_uche_err_irq(gpu); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP) 129062306a36Sopenharmony_ci a5xx_gpmu_err_irq(gpu); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) { 129362306a36Sopenharmony_ci a5xx_preempt_trigger(gpu); 129462306a36Sopenharmony_ci msm_gpu_retire(gpu); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (status & A5XX_RBBM_INT_0_MASK_CP_SW) 129862306a36Sopenharmony_ci a5xx_preempt_irq(gpu); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci return IRQ_HANDLED; 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic const u32 a5xx_registers[] = { 130462306a36Sopenharmony_ci 0x0000, 0x0002, 0x0004, 0x0020, 0x0022, 0x0026, 0x0029, 0x002B, 130562306a36Sopenharmony_ci 0x002E, 0x0035, 0x0038, 0x0042, 0x0044, 0x0044, 0x0047, 0x0095, 130662306a36Sopenharmony_ci 0x0097, 0x00BB, 0x03A0, 0x0464, 0x0469, 0x046F, 0x04D2, 0x04D3, 130762306a36Sopenharmony_ci 0x04E0, 0x0533, 0x0540, 0x0555, 0x0800, 0x081A, 0x081F, 0x0841, 130862306a36Sopenharmony_ci 0x0860, 0x0860, 0x0880, 0x08A0, 0x0B00, 0x0B12, 0x0B15, 0x0B28, 130962306a36Sopenharmony_ci 0x0B78, 0x0B7F, 0x0BB0, 0x0BBD, 0x0BC0, 0x0BC6, 0x0BD0, 0x0C53, 131062306a36Sopenharmony_ci 0x0C60, 0x0C61, 0x0C80, 0x0C82, 0x0C84, 0x0C85, 0x0C90, 0x0C98, 131162306a36Sopenharmony_ci 0x0CA0, 0x0CA0, 0x0CB0, 0x0CB2, 0x2180, 0x2185, 0x2580, 0x2585, 131262306a36Sopenharmony_ci 0x0CC1, 0x0CC1, 0x0CC4, 0x0CC7, 0x0CCC, 0x0CCC, 0x0CD0, 0x0CD8, 131362306a36Sopenharmony_ci 0x0CE0, 0x0CE5, 0x0CE8, 0x0CE8, 0x0CEC, 0x0CF1, 0x0CFB, 0x0D0E, 131462306a36Sopenharmony_ci 0x2100, 0x211E, 0x2140, 0x2145, 0x2500, 0x251E, 0x2540, 0x2545, 131562306a36Sopenharmony_ci 0x0D10, 0x0D17, 0x0D20, 0x0D23, 0x0D30, 0x0D30, 0x20C0, 0x20C0, 131662306a36Sopenharmony_ci 0x24C0, 0x24C0, 0x0E40, 0x0E43, 0x0E4A, 0x0E4A, 0x0E50, 0x0E57, 131762306a36Sopenharmony_ci 0x0E60, 0x0E7C, 0x0E80, 0x0E8E, 0x0E90, 0x0E96, 0x0EA0, 0x0EA8, 131862306a36Sopenharmony_ci 0x0EB0, 0x0EB2, 0xE140, 0xE147, 0xE150, 0xE187, 0xE1A0, 0xE1A9, 131962306a36Sopenharmony_ci 0xE1B0, 0xE1B6, 0xE1C0, 0xE1C7, 0xE1D0, 0xE1D1, 0xE200, 0xE201, 132062306a36Sopenharmony_ci 0xE210, 0xE21C, 0xE240, 0xE268, 0xE000, 0xE006, 0xE010, 0xE09A, 132162306a36Sopenharmony_ci 0xE0A0, 0xE0A4, 0xE0AA, 0xE0EB, 0xE100, 0xE105, 0xE380, 0xE38F, 132262306a36Sopenharmony_ci 0xE3B0, 0xE3B0, 0xE400, 0xE405, 0xE408, 0xE4E9, 0xE4F0, 0xE4F0, 132362306a36Sopenharmony_ci 0xE280, 0xE280, 0xE282, 0xE2A3, 0xE2A5, 0xE2C2, 0xE940, 0xE947, 132462306a36Sopenharmony_ci 0xE950, 0xE987, 0xE9A0, 0xE9A9, 0xE9B0, 0xE9B6, 0xE9C0, 0xE9C7, 132562306a36Sopenharmony_ci 0xE9D0, 0xE9D1, 0xEA00, 0xEA01, 0xEA10, 0xEA1C, 0xEA40, 0xEA68, 132662306a36Sopenharmony_ci 0xE800, 0xE806, 0xE810, 0xE89A, 0xE8A0, 0xE8A4, 0xE8AA, 0xE8EB, 132762306a36Sopenharmony_ci 0xE900, 0xE905, 0xEB80, 0xEB8F, 0xEBB0, 0xEBB0, 0xEC00, 0xEC05, 132862306a36Sopenharmony_ci 0xEC08, 0xECE9, 0xECF0, 0xECF0, 0xEA80, 0xEA80, 0xEA82, 0xEAA3, 132962306a36Sopenharmony_ci 0xEAA5, 0xEAC2, 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D, 133062306a36Sopenharmony_ci 0XA880, 0xA88D, 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5, 133162306a36Sopenharmony_ci 0xAC60, 0xAC60, ~0, 133262306a36Sopenharmony_ci}; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic void a5xx_dump(struct msm_gpu *gpu) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci DRM_DEV_INFO(gpu->dev->dev, "status: %08x\n", 133762306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_RBBM_STATUS)); 133862306a36Sopenharmony_ci adreno_dump(gpu); 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic int a5xx_pm_resume(struct msm_gpu *gpu) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 134462306a36Sopenharmony_ci int ret; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* Turn on the core power */ 134762306a36Sopenharmony_ci ret = msm_gpu_pm_resume(gpu); 134862306a36Sopenharmony_ci if (ret) 134962306a36Sopenharmony_ci return ret; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* Adreno 506, 508, 509, 510, 512 needs manual RBBM sus/res control */ 135262306a36Sopenharmony_ci if (!(adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu))) { 135362306a36Sopenharmony_ci /* Halt the sp_input_clk at HM level */ 135462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0x00000055); 135562306a36Sopenharmony_ci a5xx_set_hwcg(gpu, true); 135662306a36Sopenharmony_ci /* Turn on sp_input_clk at HM level */ 135762306a36Sopenharmony_ci gpu_rmw(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0xff, 0); 135862306a36Sopenharmony_ci return 0; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci /* Turn the RBCCU domain first to limit the chances of voltage droop */ 136262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_GPMU_RBCCU_POWER_CNTL, 0x778000); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* Wait 3 usecs before polling */ 136562306a36Sopenharmony_ci udelay(3); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS, 136862306a36Sopenharmony_ci (1 << 20), (1 << 20)); 136962306a36Sopenharmony_ci if (ret) { 137062306a36Sopenharmony_ci DRM_ERROR("%s: timeout waiting for RBCCU GDSC enable: %X\n", 137162306a36Sopenharmony_ci gpu->name, 137262306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS)); 137362306a36Sopenharmony_ci return ret; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* Turn on the SP domain */ 137762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_GPMU_SP_POWER_CNTL, 0x778000); 137862306a36Sopenharmony_ci ret = spin_usecs(gpu, 20, REG_A5XX_GPMU_SP_PWR_CLK_STATUS, 137962306a36Sopenharmony_ci (1 << 20), (1 << 20)); 138062306a36Sopenharmony_ci if (ret) 138162306a36Sopenharmony_ci DRM_ERROR("%s: timeout waiting for SP GDSC enable\n", 138262306a36Sopenharmony_ci gpu->name); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return ret; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int a5xx_pm_suspend(struct msm_gpu *gpu) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 139062306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 139162306a36Sopenharmony_ci u32 mask = 0xf; 139262306a36Sopenharmony_ci int i, ret; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* A506, A508, A510 have 3 XIN ports in VBIF */ 139562306a36Sopenharmony_ci if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || 139662306a36Sopenharmony_ci adreno_is_a510(adreno_gpu)) 139762306a36Sopenharmony_ci mask = 0x7; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* Clear the VBIF pipe before shutting down */ 140062306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, mask); 140162306a36Sopenharmony_ci spin_until((gpu_read(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL1) & 140262306a36Sopenharmony_ci mask) == mask); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_VBIF_XIN_HALT_CTRL0, 0); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* 140762306a36Sopenharmony_ci * Reset the VBIF before power collapse to avoid issue with FIFO 140862306a36Sopenharmony_ci * entries on Adreno A510 and A530 (the others will tend to lock up) 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci if (adreno_is_a510(adreno_gpu) || adreno_is_a530(adreno_gpu)) { 141162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x003C0000); 141262306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_RBBM_BLOCK_SW_RESET_CMD, 0x00000000); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci ret = msm_gpu_pm_suspend(gpu); 141662306a36Sopenharmony_ci if (ret) 141762306a36Sopenharmony_ci return ret; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (a5xx_gpu->has_whereami) 142062306a36Sopenharmony_ci for (i = 0; i < gpu->nr_rings; i++) 142162306a36Sopenharmony_ci a5xx_gpu->shadow[i] = 0; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci return 0; 142462306a36Sopenharmony_ci} 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci return 0; 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_cistruct a5xx_crashdumper { 143462306a36Sopenharmony_ci void *ptr; 143562306a36Sopenharmony_ci struct drm_gem_object *bo; 143662306a36Sopenharmony_ci u64 iova; 143762306a36Sopenharmony_ci}; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistruct a5xx_gpu_state { 144062306a36Sopenharmony_ci struct msm_gpu_state base; 144162306a36Sopenharmony_ci u32 *hlsqregs; 144262306a36Sopenharmony_ci}; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int a5xx_crashdumper_init(struct msm_gpu *gpu, 144562306a36Sopenharmony_ci struct a5xx_crashdumper *dumper) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci dumper->ptr = msm_gem_kernel_new(gpu->dev, 144862306a36Sopenharmony_ci SZ_1M, MSM_BO_WC, gpu->aspace, 144962306a36Sopenharmony_ci &dumper->bo, &dumper->iova); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (!IS_ERR(dumper->ptr)) 145262306a36Sopenharmony_ci msm_gem_object_set_name(dumper->bo, "crashdump"); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(dumper->ptr); 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_cistatic int a5xx_crashdumper_run(struct msm_gpu *gpu, 145862306a36Sopenharmony_ci struct a5xx_crashdumper *dumper) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci u32 val; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (IS_ERR_OR_NULL(dumper->ptr)) 146362306a36Sopenharmony_ci return -EINVAL; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, dumper->iova); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return gpu_poll_timeout(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, val, 147062306a36Sopenharmony_ci val & 0x04, 100, 10000); 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci/* 147462306a36Sopenharmony_ci * These are a list of the registers that need to be read through the HLSQ 147562306a36Sopenharmony_ci * aperture through the crashdumper. These are not nominally accessible from 147662306a36Sopenharmony_ci * the CPU on a secure platform. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_cistatic const struct { 147962306a36Sopenharmony_ci u32 type; 148062306a36Sopenharmony_ci u32 regoffset; 148162306a36Sopenharmony_ci u32 count; 148262306a36Sopenharmony_ci} a5xx_hlsq_aperture_regs[] = { 148362306a36Sopenharmony_ci { 0x35, 0xe00, 0x32 }, /* HSLQ non-context */ 148462306a36Sopenharmony_ci { 0x31, 0x2080, 0x1 }, /* HLSQ 2D context 0 */ 148562306a36Sopenharmony_ci { 0x33, 0x2480, 0x1 }, /* HLSQ 2D context 1 */ 148662306a36Sopenharmony_ci { 0x32, 0xe780, 0x62 }, /* HLSQ 3D context 0 */ 148762306a36Sopenharmony_ci { 0x34, 0xef80, 0x62 }, /* HLSQ 3D context 1 */ 148862306a36Sopenharmony_ci { 0x3f, 0x0ec0, 0x40 }, /* SP non-context */ 148962306a36Sopenharmony_ci { 0x3d, 0x2040, 0x1 }, /* SP 2D context 0 */ 149062306a36Sopenharmony_ci { 0x3b, 0x2440, 0x1 }, /* SP 2D context 1 */ 149162306a36Sopenharmony_ci { 0x3e, 0xe580, 0x170 }, /* SP 3D context 0 */ 149262306a36Sopenharmony_ci { 0x3c, 0xed80, 0x170 }, /* SP 3D context 1 */ 149362306a36Sopenharmony_ci { 0x3a, 0x0f00, 0x1c }, /* TP non-context */ 149462306a36Sopenharmony_ci { 0x38, 0x2000, 0xa }, /* TP 2D context 0 */ 149562306a36Sopenharmony_ci { 0x36, 0x2400, 0xa }, /* TP 2D context 1 */ 149662306a36Sopenharmony_ci { 0x39, 0xe700, 0x80 }, /* TP 3D context 0 */ 149762306a36Sopenharmony_ci { 0x37, 0xef00, 0x80 }, /* TP 3D context 1 */ 149862306a36Sopenharmony_ci}; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu, 150162306a36Sopenharmony_ci struct a5xx_gpu_state *a5xx_state) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct a5xx_crashdumper dumper = { 0 }; 150462306a36Sopenharmony_ci u32 offset, count = 0; 150562306a36Sopenharmony_ci u64 *ptr; 150662306a36Sopenharmony_ci int i; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (a5xx_crashdumper_init(gpu, &dumper)) 150962306a36Sopenharmony_ci return; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* The script will be written at offset 0 */ 151262306a36Sopenharmony_ci ptr = dumper.ptr; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* Start writing the data at offset 256k */ 151562306a36Sopenharmony_ci offset = dumper.iova + (256 * SZ_1K); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci /* Count how many additional registers to get from the HLSQ aperture */ 151862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) 151962306a36Sopenharmony_ci count += a5xx_hlsq_aperture_regs[i].count; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci a5xx_state->hlsqregs = kcalloc(count, sizeof(u32), GFP_KERNEL); 152262306a36Sopenharmony_ci if (!a5xx_state->hlsqregs) 152362306a36Sopenharmony_ci return; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* Build the crashdump script */ 152662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { 152762306a36Sopenharmony_ci u32 type = a5xx_hlsq_aperture_regs[i].type; 152862306a36Sopenharmony_ci u32 c = a5xx_hlsq_aperture_regs[i].count; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* Write the register to select the desired bank */ 153162306a36Sopenharmony_ci *ptr++ = ((u64) type << 8); 153262306a36Sopenharmony_ci *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_READ_SEL) << 44) | 153362306a36Sopenharmony_ci (1 << 21) | 1; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci *ptr++ = offset; 153662306a36Sopenharmony_ci *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE) << 44) 153762306a36Sopenharmony_ci | c; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci offset += c * sizeof(u32); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* Write two zeros to close off the script */ 154362306a36Sopenharmony_ci *ptr++ = 0; 154462306a36Sopenharmony_ci *ptr++ = 0; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci if (a5xx_crashdumper_run(gpu, &dumper)) { 154762306a36Sopenharmony_ci kfree(a5xx_state->hlsqregs); 154862306a36Sopenharmony_ci msm_gem_kernel_put(dumper.bo, gpu->aspace); 154962306a36Sopenharmony_ci return; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* Copy the data from the crashdumper to the state */ 155362306a36Sopenharmony_ci memcpy(a5xx_state->hlsqregs, dumper.ptr + (256 * SZ_1K), 155462306a36Sopenharmony_ci count * sizeof(u32)); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci msm_gem_kernel_put(dumper.bo, gpu->aspace); 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), 156262306a36Sopenharmony_ci GFP_KERNEL); 156362306a36Sopenharmony_ci bool stalled = !!(gpu_read(gpu, REG_A5XX_RBBM_STATUS3) & BIT(24)); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (!a5xx_state) 156662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* Temporarily disable hardware clock gating before reading the hw */ 156962306a36Sopenharmony_ci a5xx_set_hwcg(gpu, false); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* First get the generic state from the adreno core */ 157262306a36Sopenharmony_ci adreno_gpu_state_get(gpu, &(a5xx_state->base)); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci /* 157762306a36Sopenharmony_ci * Get the HLSQ regs with the help of the crashdumper, but only if 157862306a36Sopenharmony_ci * we are not stalled in an iommu fault (in which case the crashdumper 157962306a36Sopenharmony_ci * would not have access to memory) 158062306a36Sopenharmony_ci */ 158162306a36Sopenharmony_ci if (!stalled) 158262306a36Sopenharmony_ci a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci a5xx_set_hwcg(gpu, true); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci return &a5xx_state->base; 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_cistatic void a5xx_gpu_state_destroy(struct kref *kref) 159062306a36Sopenharmony_ci{ 159162306a36Sopenharmony_ci struct msm_gpu_state *state = container_of(kref, 159262306a36Sopenharmony_ci struct msm_gpu_state, ref); 159362306a36Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = container_of(state, 159462306a36Sopenharmony_ci struct a5xx_gpu_state, base); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci kfree(a5xx_state->hlsqregs); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci adreno_gpu_state_destroy(state); 159962306a36Sopenharmony_ci kfree(a5xx_state); 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic int a5xx_gpu_state_put(struct msm_gpu_state *state) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci if (IS_ERR_OR_NULL(state)) 160562306a36Sopenharmony_ci return 1; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci return kref_put(&state->ref, a5xx_gpu_state_destroy); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 161262306a36Sopenharmony_cistatic void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, 161362306a36Sopenharmony_ci struct drm_printer *p) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci int i, j; 161662306a36Sopenharmony_ci u32 pos = 0; 161762306a36Sopenharmony_ci struct a5xx_gpu_state *a5xx_state = container_of(state, 161862306a36Sopenharmony_ci struct a5xx_gpu_state, base); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (IS_ERR_OR_NULL(state)) 162162306a36Sopenharmony_ci return; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci adreno_show(gpu, state, p); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci /* Dump the additional a5xx HLSQ registers */ 162662306a36Sopenharmony_ci if (!a5xx_state->hlsqregs) 162762306a36Sopenharmony_ci return; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci drm_printf(p, "registers-hlsq:\n"); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { 163262306a36Sopenharmony_ci u32 o = a5xx_hlsq_aperture_regs[i].regoffset; 163362306a36Sopenharmony_ci u32 c = a5xx_hlsq_aperture_regs[i].count; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci for (j = 0; j < c; j++, pos++, o++) { 163662306a36Sopenharmony_ci /* 163762306a36Sopenharmony_ci * To keep the crashdump simple we pull the entire range 163862306a36Sopenharmony_ci * for each register type but not all of the registers 163962306a36Sopenharmony_ci * in the range are valid. Fortunately invalid registers 164062306a36Sopenharmony_ci * stick out like a sore thumb with a value of 164162306a36Sopenharmony_ci * 0xdeadbeef 164262306a36Sopenharmony_ci */ 164362306a36Sopenharmony_ci if (a5xx_state->hlsqregs[pos] == 0xdeadbeef) 164462306a36Sopenharmony_ci continue; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", 164762306a36Sopenharmony_ci o << 2, a5xx_state->hlsqregs[pos]); 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci#endif 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistatic struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 165662306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci return a5xx_gpu->cur_ring; 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic u64 a5xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) 166262306a36Sopenharmony_ci{ 166362306a36Sopenharmony_ci u64 busy_cycles; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO); 166662306a36Sopenharmony_ci *out_sample_rate = clk_get_rate(gpu->core_clk); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci return busy_cycles; 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic uint32_t a5xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 167462306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci if (a5xx_gpu->has_whereami) 167762306a36Sopenharmony_ci return a5xx_gpu->shadow[ring->id]; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci return ring->memptrs->rptr = gpu_read(gpu, REG_A5XX_CP_RB_RPTR); 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic const struct adreno_gpu_funcs funcs = { 168362306a36Sopenharmony_ci .base = { 168462306a36Sopenharmony_ci .get_param = adreno_get_param, 168562306a36Sopenharmony_ci .set_param = adreno_set_param, 168662306a36Sopenharmony_ci .hw_init = a5xx_hw_init, 168762306a36Sopenharmony_ci .ucode_load = a5xx_ucode_load, 168862306a36Sopenharmony_ci .pm_suspend = a5xx_pm_suspend, 168962306a36Sopenharmony_ci .pm_resume = a5xx_pm_resume, 169062306a36Sopenharmony_ci .recover = a5xx_recover, 169162306a36Sopenharmony_ci .submit = a5xx_submit, 169262306a36Sopenharmony_ci .active_ring = a5xx_active_ring, 169362306a36Sopenharmony_ci .irq = a5xx_irq, 169462306a36Sopenharmony_ci .destroy = a5xx_destroy, 169562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 169662306a36Sopenharmony_ci .show = a5xx_show, 169762306a36Sopenharmony_ci#endif 169862306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 169962306a36Sopenharmony_ci .debugfs_init = a5xx_debugfs_init, 170062306a36Sopenharmony_ci#endif 170162306a36Sopenharmony_ci .gpu_busy = a5xx_gpu_busy, 170262306a36Sopenharmony_ci .gpu_state_get = a5xx_gpu_state_get, 170362306a36Sopenharmony_ci .gpu_state_put = a5xx_gpu_state_put, 170462306a36Sopenharmony_ci .create_address_space = adreno_create_address_space, 170562306a36Sopenharmony_ci .get_rptr = a5xx_get_rptr, 170662306a36Sopenharmony_ci }, 170762306a36Sopenharmony_ci .get_timestamp = a5xx_get_timestamp, 170862306a36Sopenharmony_ci}; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic void check_speed_bin(struct device *dev) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci struct nvmem_cell *cell; 171362306a36Sopenharmony_ci u32 val; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci /* 171662306a36Sopenharmony_ci * If the OPP table specifies a opp-supported-hw property then we have 171762306a36Sopenharmony_ci * to set something with dev_pm_opp_set_supported_hw() or the table 171862306a36Sopenharmony_ci * doesn't get populated so pick an arbitrary value that should 171962306a36Sopenharmony_ci * ensure the default frequencies are selected but not conflict with any 172062306a36Sopenharmony_ci * actual bins 172162306a36Sopenharmony_ci */ 172262306a36Sopenharmony_ci val = 0x80; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci cell = nvmem_cell_get(dev, "speed_bin"); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (!IS_ERR(cell)) { 172762306a36Sopenharmony_ci void *buf = nvmem_cell_read(cell, NULL); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (!IS_ERR(buf)) { 173062306a36Sopenharmony_ci u8 bin = *((u8 *) buf); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci val = (1 << bin); 173362306a36Sopenharmony_ci kfree(buf); 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci nvmem_cell_put(cell); 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci devm_pm_opp_set_supported_hw(dev, &val, 1); 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistruct msm_gpu *a5xx_gpu_init(struct drm_device *dev) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 174562306a36Sopenharmony_ci struct platform_device *pdev = priv->gpu_pdev; 174662306a36Sopenharmony_ci struct adreno_platform_config *config = pdev->dev.platform_data; 174762306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = NULL; 174862306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu; 174962306a36Sopenharmony_ci struct msm_gpu *gpu; 175062306a36Sopenharmony_ci unsigned int nr_rings; 175162306a36Sopenharmony_ci int ret; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci if (!pdev) { 175462306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "No A5XX device is defined\n"); 175562306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci a5xx_gpu = kzalloc(sizeof(*a5xx_gpu), GFP_KERNEL); 175962306a36Sopenharmony_ci if (!a5xx_gpu) 176062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci adreno_gpu = &a5xx_gpu->base; 176362306a36Sopenharmony_ci gpu = &adreno_gpu->base; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci adreno_gpu->registers = a5xx_registers; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci a5xx_gpu->lm_leakage = 0x4E001A; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci check_speed_bin(&pdev->dev); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci nr_rings = 4; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (config->info->revn == 510) 177462306a36Sopenharmony_ci nr_rings = 1; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, nr_rings); 177762306a36Sopenharmony_ci if (ret) { 177862306a36Sopenharmony_ci a5xx_destroy(&(a5xx_gpu->base.base)); 177962306a36Sopenharmony_ci return ERR_PTR(ret); 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (gpu->aspace) 178362306a36Sopenharmony_ci msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu, a5xx_fault_handler); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Set up the preemption specific bits and pieces for each ringbuffer */ 178662306a36Sopenharmony_ci a5xx_preempt_init(gpu); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci return gpu; 178962306a36Sopenharmony_ci} 1790