17198e6b0SRob Clark /* 27198e6b0SRob Clark * Copyright (C) 2013 Red Hat 37198e6b0SRob Clark * Author: Rob Clark <robdclark@gmail.com> 47198e6b0SRob Clark * 57198e6b0SRob Clark * This program is free software; you can redistribute it and/or modify it 67198e6b0SRob Clark * under the terms of the GNU General Public License version 2 as published by 77198e6b0SRob Clark * the Free Software Foundation. 87198e6b0SRob Clark * 97198e6b0SRob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 107198e6b0SRob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 117198e6b0SRob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 127198e6b0SRob Clark * more details. 137198e6b0SRob Clark * 147198e6b0SRob Clark * You should have received a copy of the GNU General Public License along with 157198e6b0SRob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 167198e6b0SRob Clark */ 177198e6b0SRob Clark 1855459968SRob Clark #ifdef CONFIG_MSM_OCMEM 1955459968SRob Clark # include <mach/ocmem.h> 2055459968SRob Clark #endif 2155459968SRob Clark 227198e6b0SRob Clark #include "a3xx_gpu.h" 237198e6b0SRob Clark 247198e6b0SRob Clark #define A3XX_INT0_MASK \ 257198e6b0SRob Clark (A3XX_INT0_RBBM_AHB_ERROR | \ 267198e6b0SRob Clark A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \ 277198e6b0SRob Clark A3XX_INT0_CP_T0_PACKET_IN_IB | \ 287198e6b0SRob Clark A3XX_INT0_CP_OPCODE_ERROR | \ 297198e6b0SRob Clark A3XX_INT0_CP_RESERVED_BIT_ERROR | \ 307198e6b0SRob Clark A3XX_INT0_CP_HW_FAULT | \ 317198e6b0SRob Clark A3XX_INT0_CP_IB1_INT | \ 327198e6b0SRob Clark A3XX_INT0_CP_IB2_INT | \ 337198e6b0SRob Clark A3XX_INT0_CP_RB_INT | \ 347198e6b0SRob Clark A3XX_INT0_CP_REG_PROTECT_FAULT | \ 357198e6b0SRob Clark A3XX_INT0_CP_AHB_ERROR_HALT | \ 367198e6b0SRob Clark A3XX_INT0_UCHE_OOB_ACCESS) 377198e6b0SRob Clark 383526e9fbSRob Clark extern bool hang_debug; 395b6ef08eSRob Clark 405b6ef08eSRob Clark static void a3xx_dump(struct msm_gpu *gpu); 415b6ef08eSRob Clark 427198e6b0SRob Clark static void a3xx_me_init(struct msm_gpu *gpu) 437198e6b0SRob Clark { 447198e6b0SRob Clark struct msm_ringbuffer *ring = gpu->rb; 457198e6b0SRob Clark 467198e6b0SRob Clark OUT_PKT3(ring, CP_ME_INIT, 17); 477198e6b0SRob Clark OUT_RING(ring, 0x000003f7); 487198e6b0SRob Clark OUT_RING(ring, 0x00000000); 497198e6b0SRob Clark OUT_RING(ring, 0x00000000); 507198e6b0SRob Clark OUT_RING(ring, 0x00000000); 517198e6b0SRob Clark OUT_RING(ring, 0x00000080); 527198e6b0SRob Clark OUT_RING(ring, 0x00000100); 537198e6b0SRob Clark OUT_RING(ring, 0x00000180); 547198e6b0SRob Clark OUT_RING(ring, 0x00006600); 557198e6b0SRob Clark OUT_RING(ring, 0x00000150); 567198e6b0SRob Clark OUT_RING(ring, 0x0000014e); 577198e6b0SRob Clark OUT_RING(ring, 0x00000154); 587198e6b0SRob Clark OUT_RING(ring, 0x00000001); 597198e6b0SRob Clark OUT_RING(ring, 0x00000000); 607198e6b0SRob Clark OUT_RING(ring, 0x00000000); 617198e6b0SRob Clark OUT_RING(ring, 0x00000000); 627198e6b0SRob Clark OUT_RING(ring, 0x00000000); 637198e6b0SRob Clark OUT_RING(ring, 0x00000000); 647198e6b0SRob Clark 657198e6b0SRob Clark gpu->funcs->flush(gpu); 667198e6b0SRob Clark gpu->funcs->idle(gpu); 677198e6b0SRob Clark } 687198e6b0SRob Clark 697198e6b0SRob Clark static int a3xx_hw_init(struct msm_gpu *gpu) 707198e6b0SRob Clark { 717198e6b0SRob Clark struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 7255459968SRob Clark struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 737198e6b0SRob Clark uint32_t *ptr, len; 747198e6b0SRob Clark int i, ret; 757198e6b0SRob Clark 767198e6b0SRob Clark DBG("%s", gpu->name); 777198e6b0SRob Clark 787198e6b0SRob Clark if (adreno_is_a305(adreno_gpu)) { 797198e6b0SRob Clark /* Set up 16 deep read/write request queues: */ 807198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 817198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 827198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 837198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 847198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 857198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 867198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 877198e6b0SRob Clark /* Enable WR-REQ: */ 887198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 897198e6b0SRob Clark /* Set up round robin arbitration between both AXI ports: */ 907198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 917198e6b0SRob Clark /* Set up AOOO: */ 927198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 937198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 947198e6b0SRob Clark 957198e6b0SRob Clark } else if (adreno_is_a320(adreno_gpu)) { 967198e6b0SRob Clark /* Set up 16 deep read/write request queues: */ 977198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 987198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 997198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 1007198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 1017198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 1027198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 1037198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 1047198e6b0SRob Clark /* Enable WR-REQ: */ 1057198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 1067198e6b0SRob Clark /* Set up round robin arbitration between both AXI ports: */ 1077198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 1087198e6b0SRob Clark /* Set up AOOO: */ 1097198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 1107198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 1117198e6b0SRob Clark /* Enable 1K sort: */ 1127198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); 1137198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 1147198e6b0SRob Clark 11555459968SRob Clark } else if (adreno_is_a330v2(adreno_gpu)) { 11655459968SRob Clark /* 11755459968SRob Clark * Most of the VBIF registers on 8974v2 have the correct 11855459968SRob Clark * values at power on, so we won't modify those if we don't 11955459968SRob Clark * need to 12055459968SRob Clark */ 12155459968SRob Clark /* Enable 1k sort: */ 12255459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 12355459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 12455459968SRob Clark /* Enable WR-REQ: */ 12555459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 12655459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 12755459968SRob Clark /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 12855459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); 12955459968SRob Clark 1307198e6b0SRob Clark } else if (adreno_is_a330(adreno_gpu)) { 1317198e6b0SRob Clark /* Set up 16 deep read/write request queues: */ 1327198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); 1337198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818); 1347198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818); 1357198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818); 1367198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 1377198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); 1387198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818); 1397198e6b0SRob Clark /* Enable WR-REQ: */ 1407198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 1417198e6b0SRob Clark /* Set up round robin arbitration between both AXI ports: */ 1427198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 1437198e6b0SRob Clark /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 1447198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); 1457198e6b0SRob Clark /* Set up AOOO: */ 14655459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); 14755459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); 1487198e6b0SRob Clark /* Enable 1K sort: */ 14955459968SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 1507198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 1517198e6b0SRob Clark /* Disable VBIF clock gating. This is to enable AXI running 1527198e6b0SRob Clark * higher frequency than GPU: 1537198e6b0SRob Clark */ 1547198e6b0SRob Clark gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001); 1557198e6b0SRob Clark 1567198e6b0SRob Clark } else { 1577198e6b0SRob Clark BUG(); 1587198e6b0SRob Clark } 1597198e6b0SRob Clark 1607198e6b0SRob Clark /* Make all blocks contribute to the GPU BUSY perf counter: */ 1617198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); 1627198e6b0SRob Clark 1637198e6b0SRob Clark /* Tune the hystersis counters for SP and CP idle detection: */ 1647198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10); 1657198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); 1667198e6b0SRob Clark 1677198e6b0SRob Clark /* Enable the RBBM error reporting bits. This lets us get 1687198e6b0SRob Clark * useful information on failure: 1697198e6b0SRob Clark */ 1707198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001); 1717198e6b0SRob Clark 1727198e6b0SRob Clark /* Enable AHB error reporting: */ 1737198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff); 1747198e6b0SRob Clark 1757198e6b0SRob Clark /* Turn on the power counters: */ 1767198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000); 1777198e6b0SRob Clark 1787198e6b0SRob Clark /* Turn on hang detection - this spews a lot of useful information 1797198e6b0SRob Clark * into the RBBM registers on a hang: 1807198e6b0SRob Clark */ 1817198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff); 1827198e6b0SRob Clark 1837198e6b0SRob Clark /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */ 1847198e6b0SRob Clark gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); 1857198e6b0SRob Clark 1867198e6b0SRob Clark /* Enable Clock gating: */ 18755459968SRob Clark if (adreno_is_a320(adreno_gpu)) 1887198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); 18955459968SRob Clark else if (adreno_is_a330v2(adreno_gpu)) 19055459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); 19155459968SRob Clark else if (adreno_is_a330(adreno_gpu)) 19255459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); 1937198e6b0SRob Clark 19455459968SRob Clark if (adreno_is_a330v2(adreno_gpu)) 19555459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); 19655459968SRob Clark else if (adreno_is_a330(adreno_gpu)) 19755459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); 19855459968SRob Clark 19955459968SRob Clark /* Set the OCMEM base address for A330, etc */ 20055459968SRob Clark if (a3xx_gpu->ocmem_hdl) { 20155459968SRob Clark gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, 20255459968SRob Clark (unsigned int)(a3xx_gpu->ocmem_base >> 14)); 20355459968SRob Clark } 2047198e6b0SRob Clark 2057198e6b0SRob Clark /* Turn on performance counters: */ 2067198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01); 2077198e6b0SRob Clark 20870c70f09SRob Clark /* Enable the perfcntrs that we use.. */ 20970c70f09SRob Clark for (i = 0; i < gpu->num_perfcntrs; i++) { 21070c70f09SRob Clark const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; 21170c70f09SRob Clark gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val); 21270c70f09SRob Clark } 2137198e6b0SRob Clark 2147198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK); 2157198e6b0SRob Clark 2167198e6b0SRob Clark ret = adreno_hw_init(gpu); 2177198e6b0SRob Clark if (ret) 2187198e6b0SRob Clark return ret; 2197198e6b0SRob Clark 2207198e6b0SRob Clark /* setup access protection: */ 2217198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007); 2227198e6b0SRob Clark 2237198e6b0SRob Clark /* RBBM registers */ 2247198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040); 2257198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080); 2267198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc); 2277198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108); 2287198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140); 2297198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400); 2307198e6b0SRob Clark 2317198e6b0SRob Clark /* CP registers */ 2327198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700); 2337198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8); 2347198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0); 2357198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178); 2367198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180); 2377198e6b0SRob Clark 2387198e6b0SRob Clark /* RB registers */ 2397198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300); 2407198e6b0SRob Clark 2417198e6b0SRob Clark /* VBIF registers */ 2427198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000); 2437198e6b0SRob Clark 2447198e6b0SRob Clark /* NOTE: PM4/micro-engine firmware registers look to be the same 2457198e6b0SRob Clark * for a2xx and a3xx.. we could possibly push that part down to 2467198e6b0SRob Clark * adreno_gpu base class. Or push both PM4 and PFP but 2477198e6b0SRob Clark * parameterize the pfp ucode addr/data registers.. 2487198e6b0SRob Clark */ 2497198e6b0SRob Clark 2507198e6b0SRob Clark /* Load PM4: */ 2517198e6b0SRob Clark ptr = (uint32_t *)(adreno_gpu->pm4->data); 2527198e6b0SRob Clark len = adreno_gpu->pm4->size / 4; 253e529c7e6SRob Clark DBG("loading PM4 ucode version: %x", ptr[1]); 2547198e6b0SRob Clark 2557198e6b0SRob Clark gpu_write(gpu, REG_AXXX_CP_DEBUG, 2567198e6b0SRob Clark AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE | 2577198e6b0SRob Clark AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE); 2587198e6b0SRob Clark gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0); 2597198e6b0SRob Clark for (i = 1; i < len; i++) 2607198e6b0SRob Clark gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); 2617198e6b0SRob Clark 2627198e6b0SRob Clark /* Load PFP: */ 2637198e6b0SRob Clark ptr = (uint32_t *)(adreno_gpu->pfp->data); 2647198e6b0SRob Clark len = adreno_gpu->pfp->size / 4; 265e529c7e6SRob Clark DBG("loading PFP ucode version: %x", ptr[5]); 2667198e6b0SRob Clark 2677198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); 2687198e6b0SRob Clark for (i = 1; i < len; i++) 2697198e6b0SRob Clark gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); 2707198e6b0SRob Clark 2717198e6b0SRob Clark /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ 27255459968SRob Clark if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) { 2737198e6b0SRob Clark gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 2747198e6b0SRob Clark AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | 2757198e6b0SRob Clark AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | 2767198e6b0SRob Clark AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14)); 27755459968SRob Clark } else if (adreno_is_a330(adreno_gpu)) { 27855459968SRob Clark /* NOTE: this (value take from downstream android driver) 27955459968SRob Clark * includes some bits outside of the known bitfields. But 28055459968SRob Clark * A330 has this "MERCIU queue" thing too, which might 28155459968SRob Clark * explain a new bitfield or reshuffling: 28255459968SRob Clark */ 28355459968SRob Clark gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008); 28455459968SRob Clark } 2857198e6b0SRob Clark 2867198e6b0SRob Clark /* clear ME_HALT to start micro engine */ 2877198e6b0SRob Clark gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); 2887198e6b0SRob Clark 2897198e6b0SRob Clark a3xx_me_init(gpu); 2907198e6b0SRob Clark 2917198e6b0SRob Clark return 0; 2927198e6b0SRob Clark } 2937198e6b0SRob Clark 29455459968SRob Clark static void a3xx_recover(struct msm_gpu *gpu) 29555459968SRob Clark { 2965b6ef08eSRob Clark /* dump registers before resetting gpu, if enabled: */ 2975b6ef08eSRob Clark if (hang_debug) 2985b6ef08eSRob Clark a3xx_dump(gpu); 29955459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); 30055459968SRob Clark gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); 30155459968SRob Clark gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); 30255459968SRob Clark adreno_recover(gpu); 30355459968SRob Clark } 30455459968SRob Clark 3057198e6b0SRob Clark static void a3xx_destroy(struct msm_gpu *gpu) 3067198e6b0SRob Clark { 3077198e6b0SRob Clark struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 3087198e6b0SRob Clark struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 3097198e6b0SRob Clark 3107198e6b0SRob Clark DBG("%s", gpu->name); 3117198e6b0SRob Clark 3127198e6b0SRob Clark adreno_gpu_cleanup(adreno_gpu); 31355459968SRob Clark 31455459968SRob Clark #ifdef CONFIG_MSM_OCMEM 31555459968SRob Clark if (a3xx_gpu->ocmem_base) 31655459968SRob Clark ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); 31755459968SRob Clark #endif 31855459968SRob Clark 3197198e6b0SRob Clark kfree(a3xx_gpu); 3207198e6b0SRob Clark } 3217198e6b0SRob Clark 3227198e6b0SRob Clark static void a3xx_idle(struct msm_gpu *gpu) 3237198e6b0SRob Clark { 3247198e6b0SRob Clark /* wait for ringbuffer to drain: */ 3257198e6b0SRob Clark adreno_idle(gpu); 3267198e6b0SRob Clark 3277198e6b0SRob Clark /* then wait for GPU to finish: */ 3280963756fSRob Clark if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & 3290963756fSRob Clark A3XX_RBBM_STATUS_GPU_BUSY))) 3300963756fSRob Clark DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); 3317198e6b0SRob Clark 3327198e6b0SRob Clark /* TODO maybe we need to reset GPU here to recover from hang? */ 3337198e6b0SRob Clark } 3347198e6b0SRob Clark 3357198e6b0SRob Clark static irqreturn_t a3xx_irq(struct msm_gpu *gpu) 3367198e6b0SRob Clark { 3377198e6b0SRob Clark uint32_t status; 3387198e6b0SRob Clark 3397198e6b0SRob Clark status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS); 3407198e6b0SRob Clark DBG("%s: %08x", gpu->name, status); 3417198e6b0SRob Clark 3427198e6b0SRob Clark // TODO 3437198e6b0SRob Clark 3447198e6b0SRob Clark gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status); 3457198e6b0SRob Clark 3467198e6b0SRob Clark msm_gpu_retire(gpu); 3477198e6b0SRob Clark 3487198e6b0SRob Clark return IRQ_HANDLED; 3497198e6b0SRob Clark } 3507198e6b0SRob Clark 3517198e6b0SRob Clark static const unsigned int a3xx_registers[] = { 3527198e6b0SRob Clark 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, 3537198e6b0SRob Clark 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, 3547198e6b0SRob Clark 0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5, 3557198e6b0SRob Clark 0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1, 3567198e6b0SRob Clark 0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd, 3577198e6b0SRob Clark 0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff, 3587198e6b0SRob Clark 0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f, 3597198e6b0SRob Clark 0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f, 3607198e6b0SRob Clark 0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e, 3617198e6b0SRob Clark 0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f, 3627198e6b0SRob Clark 0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7, 3637198e6b0SRob Clark 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05, 3647198e6b0SRob Clark 0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65, 3657198e6b0SRob Clark 0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7, 3667198e6b0SRob Clark 0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09, 3677198e6b0SRob Clark 0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069, 3687198e6b0SRob Clark 0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075, 3697198e6b0SRob Clark 0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109, 3707198e6b0SRob Clark 0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115, 3717198e6b0SRob Clark 0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0, 3727198e6b0SRob Clark 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, 3737198e6b0SRob Clark 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, 3747198e6b0SRob Clark 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, 3757198e6b0SRob Clark 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356, 3767198e6b0SRob Clark 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d, 3777198e6b0SRob Clark 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472, 3787198e6b0SRob Clark 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef, 3797198e6b0SRob Clark 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511, 3807198e6b0SRob Clark 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed, 3817198e6b0SRob Clark 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a, 3827198e6b0SRob Clark 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce, 3837198e6b0SRob Clark 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec, 3847198e6b0SRob Clark 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749, 3857198e6b0SRob Clark 0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d, 3867198e6b0SRob Clark 0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036, 3877198e6b0SRob Clark 0x303c, 0x303c, 0x305e, 0x305f, 388*3bcefb04SRob Clark ~0 /* sentinel */ 3897198e6b0SRob Clark }; 3907198e6b0SRob Clark 3915b6ef08eSRob Clark #ifdef CONFIG_DEBUG_FS 3927198e6b0SRob Clark static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) 3937198e6b0SRob Clark { 39437d77c3aSRob Clark gpu->funcs->pm_resume(gpu); 3957198e6b0SRob Clark seq_printf(m, "status: %08x\n", 3967198e6b0SRob Clark gpu_read(gpu, REG_A3XX_RBBM_STATUS)); 39737d77c3aSRob Clark gpu->funcs->pm_suspend(gpu); 398*3bcefb04SRob Clark adreno_show(gpu, m); 3997198e6b0SRob Clark } 4007198e6b0SRob Clark #endif 4017198e6b0SRob Clark 4025b6ef08eSRob Clark /* would be nice to not have to duplicate the _show() stuff with printk(): */ 4035b6ef08eSRob Clark static void a3xx_dump(struct msm_gpu *gpu) 4045b6ef08eSRob Clark { 4055b6ef08eSRob Clark printk("status: %08x\n", 4065b6ef08eSRob Clark gpu_read(gpu, REG_A3XX_RBBM_STATUS)); 407*3bcefb04SRob Clark adreno_dump(gpu); 4085b6ef08eSRob Clark } 4095b6ef08eSRob Clark 4107198e6b0SRob Clark static const struct adreno_gpu_funcs funcs = { 4117198e6b0SRob Clark .base = { 4127198e6b0SRob Clark .get_param = adreno_get_param, 4137198e6b0SRob Clark .hw_init = a3xx_hw_init, 4147198e6b0SRob Clark .pm_suspend = msm_gpu_pm_suspend, 4157198e6b0SRob Clark .pm_resume = msm_gpu_pm_resume, 41655459968SRob Clark .recover = a3xx_recover, 4177198e6b0SRob Clark .last_fence = adreno_last_fence, 4187198e6b0SRob Clark .submit = adreno_submit, 4197198e6b0SRob Clark .flush = adreno_flush, 4207198e6b0SRob Clark .idle = a3xx_idle, 4217198e6b0SRob Clark .irq = a3xx_irq, 4227198e6b0SRob Clark .destroy = a3xx_destroy, 4237198e6b0SRob Clark #ifdef CONFIG_DEBUG_FS 4247198e6b0SRob Clark .show = a3xx_show, 4257198e6b0SRob Clark #endif 4267198e6b0SRob Clark }, 4277198e6b0SRob Clark }; 4287198e6b0SRob Clark 42970c70f09SRob Clark static const struct msm_gpu_perfcntr perfcntrs[] = { 43070c70f09SRob Clark { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO, 43170c70f09SRob Clark SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" }, 43270c70f09SRob Clark { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO, 43370c70f09SRob Clark SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" }, 43470c70f09SRob Clark }; 43570c70f09SRob Clark 4367198e6b0SRob Clark struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) 4377198e6b0SRob Clark { 4387198e6b0SRob Clark struct a3xx_gpu *a3xx_gpu = NULL; 43955459968SRob Clark struct adreno_gpu *adreno_gpu; 4407198e6b0SRob Clark struct msm_gpu *gpu; 441060530f1SRob Clark struct msm_drm_private *priv = dev->dev_private; 442060530f1SRob Clark struct platform_device *pdev = priv->gpu_pdev; 4437198e6b0SRob Clark int ret; 4447198e6b0SRob Clark 4457198e6b0SRob Clark if (!pdev) { 4467198e6b0SRob Clark dev_err(dev->dev, "no a3xx device\n"); 4477198e6b0SRob Clark ret = -ENXIO; 4487198e6b0SRob Clark goto fail; 4497198e6b0SRob Clark } 4507198e6b0SRob Clark 4517198e6b0SRob Clark a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL); 4527198e6b0SRob Clark if (!a3xx_gpu) { 4537198e6b0SRob Clark ret = -ENOMEM; 4547198e6b0SRob Clark goto fail; 4557198e6b0SRob Clark } 4567198e6b0SRob Clark 45755459968SRob Clark adreno_gpu = &a3xx_gpu->base; 45855459968SRob Clark gpu = &adreno_gpu->base; 4597198e6b0SRob Clark 4607198e6b0SRob Clark a3xx_gpu->pdev = pdev; 4617198e6b0SRob Clark 46270c70f09SRob Clark gpu->perfcntrs = perfcntrs; 46370c70f09SRob Clark gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); 46470c70f09SRob Clark 465*3bcefb04SRob Clark adreno_gpu->registers = a3xx_registers; 466*3bcefb04SRob Clark 4673526e9fbSRob Clark ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs); 4687198e6b0SRob Clark if (ret) 4697198e6b0SRob Clark goto fail; 4707198e6b0SRob Clark 47155459968SRob Clark /* if needed, allocate gmem: */ 47255459968SRob Clark if (adreno_is_a330(adreno_gpu)) { 47355459968SRob Clark #ifdef CONFIG_MSM_OCMEM 47455459968SRob Clark /* TODO this is different/missing upstream: */ 47555459968SRob Clark struct ocmem_buf *ocmem_hdl = 47655459968SRob Clark ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); 47755459968SRob Clark 47855459968SRob Clark a3xx_gpu->ocmem_hdl = ocmem_hdl; 47955459968SRob Clark a3xx_gpu->ocmem_base = ocmem_hdl->addr; 48055459968SRob Clark adreno_gpu->gmem = ocmem_hdl->len; 48155459968SRob Clark DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, 48255459968SRob Clark a3xx_gpu->ocmem_base); 48355459968SRob Clark #endif 48455459968SRob Clark } 48555459968SRob Clark 486871d812aSRob Clark if (!gpu->mmu) { 487871d812aSRob Clark /* TODO we think it is possible to configure the GPU to 488871d812aSRob Clark * restrict access to VRAM carveout. But the required 489871d812aSRob Clark * registers are unknown. For now just bail out and 490871d812aSRob Clark * limp along with just modesetting. If it turns out 491871d812aSRob Clark * to not be possible to restrict access, then we must 492871d812aSRob Clark * implement a cmdstream validator. 493871d812aSRob Clark */ 494871d812aSRob Clark dev_err(dev->dev, "No memory protection without IOMMU\n"); 495871d812aSRob Clark ret = -ENXIO; 496871d812aSRob Clark goto fail; 497871d812aSRob Clark } 498871d812aSRob Clark 499871d812aSRob Clark return gpu; 5007198e6b0SRob Clark 5017198e6b0SRob Clark fail: 5027198e6b0SRob Clark if (a3xx_gpu) 5037198e6b0SRob Clark a3xx_destroy(&a3xx_gpu->base.base); 5047198e6b0SRob Clark 5057198e6b0SRob Clark return ERR_PTR(ret); 5067198e6b0SRob Clark } 507