162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 Red Hat 462306a36Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2014 The Linux Foundation. All rights reserved. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "a3xx_gpu.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define A3XX_INT0_MASK \ 1262306a36Sopenharmony_ci (A3XX_INT0_RBBM_AHB_ERROR | \ 1362306a36Sopenharmony_ci A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \ 1462306a36Sopenharmony_ci A3XX_INT0_CP_T0_PACKET_IN_IB | \ 1562306a36Sopenharmony_ci A3XX_INT0_CP_OPCODE_ERROR | \ 1662306a36Sopenharmony_ci A3XX_INT0_CP_RESERVED_BIT_ERROR | \ 1762306a36Sopenharmony_ci A3XX_INT0_CP_HW_FAULT | \ 1862306a36Sopenharmony_ci A3XX_INT0_CP_IB1_INT | \ 1962306a36Sopenharmony_ci A3XX_INT0_CP_IB2_INT | \ 2062306a36Sopenharmony_ci A3XX_INT0_CP_RB_INT | \ 2162306a36Sopenharmony_ci A3XX_INT0_CP_REG_PROTECT_FAULT | \ 2262306a36Sopenharmony_ci A3XX_INT0_CP_AHB_ERROR_HALT | \ 2362306a36Sopenharmony_ci A3XX_INT0_CACHE_FLUSH_TS | \ 2462306a36Sopenharmony_ci A3XX_INT0_UCHE_OOB_ACCESS) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciextern bool hang_debug; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void a3xx_dump(struct msm_gpu *gpu); 2962306a36Sopenharmony_cistatic bool a3xx_idle(struct msm_gpu *gpu); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct msm_ringbuffer *ring = submit->ring; 3462306a36Sopenharmony_ci unsigned int i; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci for (i = 0; i < submit->nr_cmds; i++) { 3762306a36Sopenharmony_ci switch (submit->cmd[i].type) { 3862306a36Sopenharmony_ci case MSM_SUBMIT_CMD_IB_TARGET_BUF: 3962306a36Sopenharmony_ci /* ignore IB-targets */ 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 4262306a36Sopenharmony_ci /* ignore if there has not been a ctx switch: */ 4362306a36Sopenharmony_ci if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci fallthrough; 4662306a36Sopenharmony_ci case MSM_SUBMIT_CMD_BUF: 4762306a36Sopenharmony_ci OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2); 4862306a36Sopenharmony_ci OUT_RING(ring, lower_32_bits(submit->cmd[i].iova)); 4962306a36Sopenharmony_ci OUT_RING(ring, submit->cmd[i].size); 5062306a36Sopenharmony_ci OUT_PKT2(ring); 5162306a36Sopenharmony_ci break; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); 5662306a36Sopenharmony_ci OUT_RING(ring, submit->seqno); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Flush HLSQ lazy updates to make sure there is nothing 5962306a36Sopenharmony_ci * pending for indirect loads after the timestamp has 6062306a36Sopenharmony_ci * passed: 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci OUT_PKT3(ring, CP_EVENT_WRITE, 1); 6362306a36Sopenharmony_ci OUT_RING(ring, HLSQ_FLUSH); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* wait for idle before cache flush/interrupt */ 6662306a36Sopenharmony_ci OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); 6762306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */ 7062306a36Sopenharmony_ci OUT_PKT3(ring, CP_EVENT_WRITE, 3); 7162306a36Sopenharmony_ci OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ); 7262306a36Sopenharmony_ci OUT_RING(ring, rbmemptr(ring, fence)); 7362306a36Sopenharmony_ci OUT_RING(ring, submit->seqno); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#if 0 7662306a36Sopenharmony_ci /* Dummy set-constant to trigger context rollover */ 7762306a36Sopenharmony_ci OUT_PKT3(ring, CP_SET_CONSTANT, 2); 7862306a36Sopenharmony_ci OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG)); 7962306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic bool a3xx_me_init(struct msm_gpu *gpu) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct msm_ringbuffer *ring = gpu->rb[0]; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci OUT_PKT3(ring, CP_ME_INIT, 17); 9062306a36Sopenharmony_ci OUT_RING(ring, 0x000003f7); 9162306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 9262306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 9362306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 9462306a36Sopenharmony_ci OUT_RING(ring, 0x00000080); 9562306a36Sopenharmony_ci OUT_RING(ring, 0x00000100); 9662306a36Sopenharmony_ci OUT_RING(ring, 0x00000180); 9762306a36Sopenharmony_ci OUT_RING(ring, 0x00006600); 9862306a36Sopenharmony_ci OUT_RING(ring, 0x00000150); 9962306a36Sopenharmony_ci OUT_RING(ring, 0x0000014e); 10062306a36Sopenharmony_ci OUT_RING(ring, 0x00000154); 10162306a36Sopenharmony_ci OUT_RING(ring, 0x00000001); 10262306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 10362306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 10462306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 10562306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 10662306a36Sopenharmony_ci OUT_RING(ring, 0x00000000); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR); 10962306a36Sopenharmony_ci return a3xx_idle(gpu); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int a3xx_hw_init(struct msm_gpu *gpu) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 11562306a36Sopenharmony_ci struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 11662306a36Sopenharmony_ci uint32_t *ptr, len; 11762306a36Sopenharmony_ci int i, ret; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci DBG("%s", gpu->name); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (adreno_is_a305(adreno_gpu)) { 12262306a36Sopenharmony_ci /* Set up 16 deep read/write request queues: */ 12362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 12462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 12562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 12662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 12762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 12862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 12962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 13062306a36Sopenharmony_ci /* Enable WR-REQ: */ 13162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 13262306a36Sopenharmony_ci /* Set up round robin arbitration between both AXI ports: */ 13362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 13462306a36Sopenharmony_ci /* Set up AOOO: */ 13562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 13662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 13762306a36Sopenharmony_ci } else if (adreno_is_a306(adreno_gpu)) { 13862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); 13962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x0000000a); 14062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x0000000a); 14162306a36Sopenharmony_ci } else if (adreno_is_a320(adreno_gpu)) { 14262306a36Sopenharmony_ci /* Set up 16 deep read/write request queues: */ 14362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 14462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 14562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 14662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 14762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 14862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 14962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 15062306a36Sopenharmony_ci /* Enable WR-REQ: */ 15162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 15262306a36Sopenharmony_ci /* Set up round robin arbitration between both AXI ports: */ 15362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 15462306a36Sopenharmony_ci /* Set up AOOO: */ 15562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 15662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 15762306a36Sopenharmony_ci /* Enable 1K sort: */ 15862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); 15962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci } else if (adreno_is_a330v2(adreno_gpu)) { 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * Most of the VBIF registers on 8974v2 have the correct 16462306a36Sopenharmony_ci * values at power on, so we won't modify those if we don't 16562306a36Sopenharmony_ci * need to 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci /* Enable 1k sort: */ 16862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 16962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 17062306a36Sopenharmony_ci /* Enable WR-REQ: */ 17162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 17262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 17362306a36Sopenharmony_ci /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 17462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci } else if (adreno_is_a330(adreno_gpu)) { 17762306a36Sopenharmony_ci /* Set up 16 deep read/write request queues: */ 17862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); 17962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818); 18062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818); 18162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818); 18262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 18362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); 18462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818); 18562306a36Sopenharmony_ci /* Enable WR-REQ: */ 18662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 18762306a36Sopenharmony_ci /* Set up round robin arbitration between both AXI ports: */ 18862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 18962306a36Sopenharmony_ci /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 19062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); 19162306a36Sopenharmony_ci /* Set up AOOO: */ 19262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); 19362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); 19462306a36Sopenharmony_ci /* Enable 1K sort: */ 19562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 19662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 19762306a36Sopenharmony_ci /* Disable VBIF clock gating. This is to enable AXI running 19862306a36Sopenharmony_ci * higher frequency than GPU: 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci } else { 20362306a36Sopenharmony_ci BUG(); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Make all blocks contribute to the GPU BUSY perf counter: */ 20762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Tune the hystersis counters for SP and CP idle detection: */ 21062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10); 21162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Enable the RBBM error reporting bits. This lets us get 21462306a36Sopenharmony_ci * useful information on failure: 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* Enable AHB error reporting: */ 21962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Turn on the power counters: */ 22262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Turn on hang detection - this spews a lot of useful information 22562306a36Sopenharmony_ci * into the RBBM registers on a hang: 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */ 23062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Enable Clock gating: */ 23362306a36Sopenharmony_ci if (adreno_is_a306(adreno_gpu)) 23462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); 23562306a36Sopenharmony_ci else if (adreno_is_a320(adreno_gpu)) 23662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); 23762306a36Sopenharmony_ci else if (adreno_is_a330v2(adreno_gpu)) 23862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); 23962306a36Sopenharmony_ci else if (adreno_is_a330(adreno_gpu)) 24062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (adreno_is_a330v2(adreno_gpu)) 24362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); 24462306a36Sopenharmony_ci else if (adreno_is_a330(adreno_gpu)) 24562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Set the OCMEM base address for A330, etc */ 24862306a36Sopenharmony_ci if (a3xx_gpu->ocmem.hdl) { 24962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, 25062306a36Sopenharmony_ci (unsigned int)(a3xx_gpu->ocmem.base >> 14)); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Turn on performance counters: */ 25462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Enable the perfcntrs that we use.. */ 25762306a36Sopenharmony_ci for (i = 0; i < gpu->num_perfcntrs; i++) { 25862306a36Sopenharmony_ci const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; 25962306a36Sopenharmony_ci gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ret = adreno_hw_init(gpu); 26562306a36Sopenharmony_ci if (ret) 26662306a36Sopenharmony_ci return ret; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * Use the default ringbuffer size and block size but disable the RPTR 27062306a36Sopenharmony_ci * shadow 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_RB_CNTL, 27362306a36Sopenharmony_ci MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Set the ringbuffer address */ 27662306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova)); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* setup access protection: */ 27962306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* RBBM registers */ 28262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040); 28362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080); 28462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc); 28562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108); 28662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140); 28762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* CP registers */ 29062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700); 29162306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8); 29262306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0); 29362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178); 29462306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* RB registers */ 29762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* VBIF registers */ 30062306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* NOTE: PM4/micro-engine firmware registers look to be the same 30362306a36Sopenharmony_ci * for a2xx and a3xx.. we could possibly push that part down to 30462306a36Sopenharmony_ci * adreno_gpu base class. Or push both PM4 and PFP but 30562306a36Sopenharmony_ci * parameterize the pfp ucode addr/data registers.. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Load PM4: */ 30962306a36Sopenharmony_ci ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data); 31062306a36Sopenharmony_ci len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4; 31162306a36Sopenharmony_ci DBG("loading PM4 ucode version: %x", ptr[1]); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_DEBUG, 31462306a36Sopenharmony_ci AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE | 31562306a36Sopenharmony_ci AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE); 31662306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0); 31762306a36Sopenharmony_ci for (i = 1; i < len; i++) 31862306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Load PFP: */ 32162306a36Sopenharmony_ci ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data); 32262306a36Sopenharmony_ci len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4; 32362306a36Sopenharmony_ci DBG("loading PFP ucode version: %x", ptr[5]); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); 32662306a36Sopenharmony_ci for (i = 1; i < len; i++) 32762306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ 33062306a36Sopenharmony_ci if (adreno_is_a305(adreno_gpu) || adreno_is_a306(adreno_gpu) || 33162306a36Sopenharmony_ci adreno_is_a320(adreno_gpu)) { 33262306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 33362306a36Sopenharmony_ci AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | 33462306a36Sopenharmony_ci AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | 33562306a36Sopenharmony_ci AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14)); 33662306a36Sopenharmony_ci } else if (adreno_is_a330(adreno_gpu)) { 33762306a36Sopenharmony_ci /* NOTE: this (value take from downstream android driver) 33862306a36Sopenharmony_ci * includes some bits outside of the known bitfields. But 33962306a36Sopenharmony_ci * A330 has this "MERCIU queue" thing too, which might 34062306a36Sopenharmony_ci * explain a new bitfield or reshuffling: 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* clear ME_HALT to start micro engine */ 34662306a36Sopenharmony_ci gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return a3xx_me_init(gpu) ? 0 : -EINVAL; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void a3xx_recover(struct msm_gpu *gpu) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci int i; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci adreno_dump_info(gpu); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 35862306a36Sopenharmony_ci printk("CP_SCRATCH_REG%d: %u\n", i, 35962306a36Sopenharmony_ci gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i)); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* dump registers before resetting gpu, if enabled: */ 36362306a36Sopenharmony_ci if (hang_debug) 36462306a36Sopenharmony_ci a3xx_dump(gpu); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); 36762306a36Sopenharmony_ci gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); 36862306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); 36962306a36Sopenharmony_ci adreno_recover(gpu); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void a3xx_destroy(struct msm_gpu *gpu) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 37562306a36Sopenharmony_ci struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci DBG("%s", gpu->name); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci adreno_gpu_cleanup(adreno_gpu); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci adreno_gpu_ocmem_cleanup(&a3xx_gpu->ocmem); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci kfree(a3xx_gpu); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic bool a3xx_idle(struct msm_gpu *gpu) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci /* wait for ringbuffer to drain: */ 38962306a36Sopenharmony_ci if (!adreno_idle(gpu, gpu->rb[0])) 39062306a36Sopenharmony_ci return false; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* then wait for GPU to finish: */ 39362306a36Sopenharmony_ci if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & 39462306a36Sopenharmony_ci A3XX_RBBM_STATUS_GPU_BUSY))) { 39562306a36Sopenharmony_ci DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* TODO maybe we need to reset GPU here to recover from hang? */ 39862306a36Sopenharmony_ci return false; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return true; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic irqreturn_t a3xx_irq(struct msm_gpu *gpu) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci uint32_t status; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS); 40962306a36Sopenharmony_ci DBG("%s: %08x", gpu->name, status); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci // TODO 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci msm_gpu_retire(gpu); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return IRQ_HANDLED; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic const unsigned int a3xx_registers[] = { 42162306a36Sopenharmony_ci 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, 42262306a36Sopenharmony_ci 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, 42362306a36Sopenharmony_ci 0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5, 42462306a36Sopenharmony_ci 0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1, 42562306a36Sopenharmony_ci 0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd, 42662306a36Sopenharmony_ci 0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff, 42762306a36Sopenharmony_ci 0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f, 42862306a36Sopenharmony_ci 0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f, 42962306a36Sopenharmony_ci 0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e, 43062306a36Sopenharmony_ci 0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f, 43162306a36Sopenharmony_ci 0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7, 43262306a36Sopenharmony_ci 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05, 43362306a36Sopenharmony_ci 0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65, 43462306a36Sopenharmony_ci 0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7, 43562306a36Sopenharmony_ci 0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09, 43662306a36Sopenharmony_ci 0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069, 43762306a36Sopenharmony_ci 0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075, 43862306a36Sopenharmony_ci 0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109, 43962306a36Sopenharmony_ci 0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115, 44062306a36Sopenharmony_ci 0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0, 44162306a36Sopenharmony_ci 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, 44262306a36Sopenharmony_ci 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, 44362306a36Sopenharmony_ci 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, 44462306a36Sopenharmony_ci 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444, 44562306a36Sopenharmony_ci 0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 44662306a36Sopenharmony_ci 0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 44762306a36Sopenharmony_ci 0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 44862306a36Sopenharmony_ci 0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 44962306a36Sopenharmony_ci 0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 45062306a36Sopenharmony_ci 0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 45162306a36Sopenharmony_ci 0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 45262306a36Sopenharmony_ci 0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 45362306a36Sopenharmony_ci 0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d, 45462306a36Sopenharmony_ci 0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f, 45562306a36Sopenharmony_ci ~0 /* sentinel */ 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* would be nice to not have to duplicate the _show() stuff with printk(): */ 45962306a36Sopenharmony_cistatic void a3xx_dump(struct msm_gpu *gpu) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci printk("status: %08x\n", 46262306a36Sopenharmony_ci gpu_read(gpu, REG_A3XX_RBBM_STATUS)); 46362306a36Sopenharmony_ci adreno_dump(gpu); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!state) 47162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci adreno_gpu_state_get(gpu, state); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return state; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci u64 busy_cycles; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci busy_cycles = gpu_read64(gpu, REG_A3XX_RBBM_PERFCTR_RBBM_1_LO); 48562306a36Sopenharmony_ci *out_sample_rate = clk_get_rate(gpu->core_clk); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return busy_cycles; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR); 49362306a36Sopenharmony_ci return ring->memptrs->rptr; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic const struct adreno_gpu_funcs funcs = { 49762306a36Sopenharmony_ci .base = { 49862306a36Sopenharmony_ci .get_param = adreno_get_param, 49962306a36Sopenharmony_ci .set_param = adreno_set_param, 50062306a36Sopenharmony_ci .hw_init = a3xx_hw_init, 50162306a36Sopenharmony_ci .pm_suspend = msm_gpu_pm_suspend, 50262306a36Sopenharmony_ci .pm_resume = msm_gpu_pm_resume, 50362306a36Sopenharmony_ci .recover = a3xx_recover, 50462306a36Sopenharmony_ci .submit = a3xx_submit, 50562306a36Sopenharmony_ci .active_ring = adreno_active_ring, 50662306a36Sopenharmony_ci .irq = a3xx_irq, 50762306a36Sopenharmony_ci .destroy = a3xx_destroy, 50862306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) 50962306a36Sopenharmony_ci .show = adreno_show, 51062306a36Sopenharmony_ci#endif 51162306a36Sopenharmony_ci .gpu_busy = a3xx_gpu_busy, 51262306a36Sopenharmony_ci .gpu_state_get = a3xx_gpu_state_get, 51362306a36Sopenharmony_ci .gpu_state_put = adreno_gpu_state_put, 51462306a36Sopenharmony_ci .create_address_space = adreno_create_address_space, 51562306a36Sopenharmony_ci .get_rptr = a3xx_get_rptr, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic const struct msm_gpu_perfcntr perfcntrs[] = { 52062306a36Sopenharmony_ci { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO, 52162306a36Sopenharmony_ci SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" }, 52262306a36Sopenharmony_ci { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO, 52362306a36Sopenharmony_ci SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" }, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistruct msm_gpu *a3xx_gpu_init(struct drm_device *dev) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct a3xx_gpu *a3xx_gpu = NULL; 52962306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu; 53062306a36Sopenharmony_ci struct msm_gpu *gpu; 53162306a36Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 53262306a36Sopenharmony_ci struct platform_device *pdev = priv->gpu_pdev; 53362306a36Sopenharmony_ci struct icc_path *ocmem_icc_path; 53462306a36Sopenharmony_ci struct icc_path *icc_path; 53562306a36Sopenharmony_ci int ret; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!pdev) { 53862306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "no a3xx device\n"); 53962306a36Sopenharmony_ci ret = -ENXIO; 54062306a36Sopenharmony_ci goto fail; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL); 54462306a36Sopenharmony_ci if (!a3xx_gpu) { 54562306a36Sopenharmony_ci ret = -ENOMEM; 54662306a36Sopenharmony_ci goto fail; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci adreno_gpu = &a3xx_gpu->base; 55062306a36Sopenharmony_ci gpu = &adreno_gpu->base; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci gpu->perfcntrs = perfcntrs; 55362306a36Sopenharmony_ci gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci adreno_gpu->registers = a3xx_registers; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); 55862306a36Sopenharmony_ci if (ret) 55962306a36Sopenharmony_ci goto fail; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* if needed, allocate gmem: */ 56262306a36Sopenharmony_ci if (adreno_is_a330(adreno_gpu)) { 56362306a36Sopenharmony_ci ret = adreno_gpu_ocmem_init(&adreno_gpu->base.pdev->dev, 56462306a36Sopenharmony_ci adreno_gpu, &a3xx_gpu->ocmem); 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci goto fail; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!gpu->aspace) { 57062306a36Sopenharmony_ci /* TODO we think it is possible to configure the GPU to 57162306a36Sopenharmony_ci * restrict access to VRAM carveout. But the required 57262306a36Sopenharmony_ci * registers are unknown. For now just bail out and 57362306a36Sopenharmony_ci * limp along with just modesetting. If it turns out 57462306a36Sopenharmony_ci * to not be possible to restrict access, then we must 57562306a36Sopenharmony_ci * implement a cmdstream validator. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n"); 57862306a36Sopenharmony_ci if (!allow_vram_carveout) { 57962306a36Sopenharmony_ci ret = -ENXIO; 58062306a36Sopenharmony_ci goto fail; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem"); 58562306a36Sopenharmony_ci if (IS_ERR(icc_path)) { 58662306a36Sopenharmony_ci ret = PTR_ERR(icc_path); 58762306a36Sopenharmony_ci goto fail; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem"); 59162306a36Sopenharmony_ci if (IS_ERR(ocmem_icc_path)) { 59262306a36Sopenharmony_ci ret = PTR_ERR(ocmem_icc_path); 59362306a36Sopenharmony_ci /* allow -ENODATA, ocmem icc is optional */ 59462306a36Sopenharmony_ci if (ret != -ENODATA) 59562306a36Sopenharmony_ci goto fail; 59662306a36Sopenharmony_ci ocmem_icc_path = NULL; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * Set the ICC path to maximum speed for now by multiplying the fastest 60262306a36Sopenharmony_ci * frequency by the bus width (8). We'll want to scale this later on to 60362306a36Sopenharmony_ci * improve battery life. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci icc_set_bw(icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); 60662306a36Sopenharmony_ci icc_set_bw(ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return gpu; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cifail: 61162306a36Sopenharmony_ci if (a3xx_gpu) 61262306a36Sopenharmony_ci a3xx_destroy(&a3xx_gpu->base.base); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return ERR_PTR(ret); 61562306a36Sopenharmony_ci} 616