1 /* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifdef CONFIG_MSM_OCMEM 19 # include <mach/ocmem.h> 20 #endif 21 22 #include "a3xx_gpu.h" 23 24 #define A3XX_INT0_MASK \ 25 (A3XX_INT0_RBBM_AHB_ERROR | \ 26 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \ 27 A3XX_INT0_CP_T0_PACKET_IN_IB | \ 28 A3XX_INT0_CP_OPCODE_ERROR | \ 29 A3XX_INT0_CP_RESERVED_BIT_ERROR | \ 30 A3XX_INT0_CP_HW_FAULT | \ 31 A3XX_INT0_CP_IB1_INT | \ 32 A3XX_INT0_CP_IB2_INT | \ 33 A3XX_INT0_CP_RB_INT | \ 34 A3XX_INT0_CP_REG_PROTECT_FAULT | \ 35 A3XX_INT0_CP_AHB_ERROR_HALT | \ 36 A3XX_INT0_UCHE_OOB_ACCESS) 37 38 extern bool hang_debug; 39 40 static void a3xx_dump(struct msm_gpu *gpu); 41 42 static void a3xx_me_init(struct msm_gpu *gpu) 43 { 44 struct msm_ringbuffer *ring = gpu->rb; 45 46 OUT_PKT3(ring, CP_ME_INIT, 17); 47 OUT_RING(ring, 0x000003f7); 48 OUT_RING(ring, 0x00000000); 49 OUT_RING(ring, 0x00000000); 50 OUT_RING(ring, 0x00000000); 51 OUT_RING(ring, 0x00000080); 52 OUT_RING(ring, 0x00000100); 53 OUT_RING(ring, 0x00000180); 54 OUT_RING(ring, 0x00006600); 55 OUT_RING(ring, 0x00000150); 56 OUT_RING(ring, 0x0000014e); 57 OUT_RING(ring, 0x00000154); 58 OUT_RING(ring, 0x00000001); 59 OUT_RING(ring, 0x00000000); 60 OUT_RING(ring, 0x00000000); 61 OUT_RING(ring, 0x00000000); 62 OUT_RING(ring, 0x00000000); 63 OUT_RING(ring, 0x00000000); 64 65 gpu->funcs->flush(gpu); 66 gpu->funcs->idle(gpu); 67 } 68 69 static int a3xx_hw_init(struct msm_gpu *gpu) 70 { 71 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 72 struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 73 uint32_t *ptr, len; 74 int i, ret; 75 76 DBG("%s", gpu->name); 77 78 if (adreno_is_a305(adreno_gpu)) { 79 /* Set up 16 deep read/write request queues: */ 80 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 81 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 82 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 83 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 84 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 85 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 86 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 87 /* Enable WR-REQ: */ 88 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 89 /* Set up round robin arbitration between both AXI ports: */ 90 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 91 /* Set up AOOO: */ 92 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 93 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 94 95 } else if (adreno_is_a320(adreno_gpu)) { 96 /* Set up 16 deep read/write request queues: */ 97 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); 98 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); 99 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); 100 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); 101 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 102 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); 103 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); 104 /* Enable WR-REQ: */ 105 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); 106 /* Set up round robin arbitration between both AXI ports: */ 107 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 108 /* Set up AOOO: */ 109 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); 110 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); 111 /* Enable 1K sort: */ 112 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); 113 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 114 115 } else if (adreno_is_a330v2(adreno_gpu)) { 116 /* 117 * Most of the VBIF registers on 8974v2 have the correct 118 * values at power on, so we won't modify those if we don't 119 * need to 120 */ 121 /* Enable 1k sort: */ 122 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 123 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 124 /* Enable WR-REQ: */ 125 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 126 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 127 /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 128 gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); 129 130 } else if (adreno_is_a330(adreno_gpu)) { 131 /* Set up 16 deep read/write request queues: */ 132 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); 133 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818); 134 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818); 135 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818); 136 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); 137 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); 138 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818); 139 /* Enable WR-REQ: */ 140 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); 141 /* Set up round robin arbitration between both AXI ports: */ 142 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); 143 /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ 144 gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); 145 /* Set up AOOO: */ 146 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); 147 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); 148 /* Enable 1K sort: */ 149 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); 150 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); 151 /* Disable VBIF clock gating. This is to enable AXI running 152 * higher frequency than GPU: 153 */ 154 gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001); 155 156 } else { 157 BUG(); 158 } 159 160 /* Make all blocks contribute to the GPU BUSY perf counter: */ 161 gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); 162 163 /* Tune the hystersis counters for SP and CP idle detection: */ 164 gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10); 165 gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); 166 167 /* Enable the RBBM error reporting bits. This lets us get 168 * useful information on failure: 169 */ 170 gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001); 171 172 /* Enable AHB error reporting: */ 173 gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff); 174 175 /* Turn on the power counters: */ 176 gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000); 177 178 /* Turn on hang detection - this spews a lot of useful information 179 * into the RBBM registers on a hang: 180 */ 181 gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff); 182 183 /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */ 184 gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); 185 186 /* Enable Clock gating: */ 187 if (adreno_is_a320(adreno_gpu)) 188 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); 189 else if (adreno_is_a330v2(adreno_gpu)) 190 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); 191 else if (adreno_is_a330(adreno_gpu)) 192 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); 193 194 if (adreno_is_a330v2(adreno_gpu)) 195 gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); 196 else if (adreno_is_a330(adreno_gpu)) 197 gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); 198 199 /* Set the OCMEM base address for A330, etc */ 200 if (a3xx_gpu->ocmem_hdl) { 201 gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, 202 (unsigned int)(a3xx_gpu->ocmem_base >> 14)); 203 } 204 205 /* Turn on performance counters: */ 206 gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01); 207 208 /* Enable the perfcntrs that we use.. */ 209 for (i = 0; i < gpu->num_perfcntrs; i++) { 210 const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; 211 gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val); 212 } 213 214 gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK); 215 216 ret = adreno_hw_init(gpu); 217 if (ret) 218 return ret; 219 220 /* setup access protection: */ 221 gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007); 222 223 /* RBBM registers */ 224 gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040); 225 gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080); 226 gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc); 227 gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108); 228 gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140); 229 gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400); 230 231 /* CP registers */ 232 gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700); 233 gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8); 234 gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0); 235 gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178); 236 gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180); 237 238 /* RB registers */ 239 gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300); 240 241 /* VBIF registers */ 242 gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000); 243 244 /* NOTE: PM4/micro-engine firmware registers look to be the same 245 * for a2xx and a3xx.. we could possibly push that part down to 246 * adreno_gpu base class. Or push both PM4 and PFP but 247 * parameterize the pfp ucode addr/data registers.. 248 */ 249 250 /* Load PM4: */ 251 ptr = (uint32_t *)(adreno_gpu->pm4->data); 252 len = adreno_gpu->pm4->size / 4; 253 DBG("loading PM4 ucode version: %x", ptr[1]); 254 255 gpu_write(gpu, REG_AXXX_CP_DEBUG, 256 AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE | 257 AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE); 258 gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0); 259 for (i = 1; i < len; i++) 260 gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]); 261 262 /* Load PFP: */ 263 ptr = (uint32_t *)(adreno_gpu->pfp->data); 264 len = adreno_gpu->pfp->size / 4; 265 DBG("loading PFP ucode version: %x", ptr[5]); 266 267 gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); 268 for (i = 1; i < len; i++) 269 gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); 270 271 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ 272 if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) { 273 gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 274 AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | 275 AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | 276 AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14)); 277 } else if (adreno_is_a330(adreno_gpu)) { 278 /* NOTE: this (value take from downstream android driver) 279 * includes some bits outside of the known bitfields. But 280 * A330 has this "MERCIU queue" thing too, which might 281 * explain a new bitfield or reshuffling: 282 */ 283 gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008); 284 } 285 286 /* clear ME_HALT to start micro engine */ 287 gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); 288 289 a3xx_me_init(gpu); 290 291 return 0; 292 } 293 294 static void a3xx_recover(struct msm_gpu *gpu) 295 { 296 /* dump registers before resetting gpu, if enabled: */ 297 if (hang_debug) 298 a3xx_dump(gpu); 299 gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); 300 gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); 301 gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); 302 adreno_recover(gpu); 303 } 304 305 static void a3xx_destroy(struct msm_gpu *gpu) 306 { 307 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 308 struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); 309 310 DBG("%s", gpu->name); 311 312 adreno_gpu_cleanup(adreno_gpu); 313 314 #ifdef CONFIG_MSM_OCMEM 315 if (a3xx_gpu->ocmem_base) 316 ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); 317 #endif 318 319 kfree(a3xx_gpu); 320 } 321 322 static void a3xx_idle(struct msm_gpu *gpu) 323 { 324 /* wait for ringbuffer to drain: */ 325 adreno_idle(gpu); 326 327 /* then wait for GPU to finish: */ 328 if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & 329 A3XX_RBBM_STATUS_GPU_BUSY))) 330 DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); 331 332 /* TODO maybe we need to reset GPU here to recover from hang? */ 333 } 334 335 static irqreturn_t a3xx_irq(struct msm_gpu *gpu) 336 { 337 uint32_t status; 338 339 status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS); 340 DBG("%s: %08x", gpu->name, status); 341 342 // TODO 343 344 gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status); 345 346 msm_gpu_retire(gpu); 347 348 return IRQ_HANDLED; 349 } 350 351 static const unsigned int a3xx_registers[] = { 352 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, 353 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, 354 0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5, 355 0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1, 356 0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd, 357 0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff, 358 0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f, 359 0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f, 360 0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e, 361 0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f, 362 0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7, 363 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05, 364 0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65, 365 0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7, 366 0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09, 367 0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069, 368 0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075, 369 0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109, 370 0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115, 371 0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0, 372 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, 373 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, 374 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, 375 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356, 376 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d, 377 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472, 378 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef, 379 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511, 380 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed, 381 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a, 382 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce, 383 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec, 384 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749, 385 0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d, 386 0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036, 387 0x303c, 0x303c, 0x305e, 0x305f, 388 ~0 /* sentinel */ 389 }; 390 391 #ifdef CONFIG_DEBUG_FS 392 static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) 393 { 394 gpu->funcs->pm_resume(gpu); 395 seq_printf(m, "status: %08x\n", 396 gpu_read(gpu, REG_A3XX_RBBM_STATUS)); 397 gpu->funcs->pm_suspend(gpu); 398 adreno_show(gpu, m); 399 } 400 #endif 401 402 /* would be nice to not have to duplicate the _show() stuff with printk(): */ 403 static void a3xx_dump(struct msm_gpu *gpu) 404 { 405 printk("status: %08x\n", 406 gpu_read(gpu, REG_A3XX_RBBM_STATUS)); 407 adreno_dump(gpu); 408 } 409 410 static const struct adreno_gpu_funcs funcs = { 411 .base = { 412 .get_param = adreno_get_param, 413 .hw_init = a3xx_hw_init, 414 .pm_suspend = msm_gpu_pm_suspend, 415 .pm_resume = msm_gpu_pm_resume, 416 .recover = a3xx_recover, 417 .last_fence = adreno_last_fence, 418 .submit = adreno_submit, 419 .flush = adreno_flush, 420 .idle = a3xx_idle, 421 .irq = a3xx_irq, 422 .destroy = a3xx_destroy, 423 #ifdef CONFIG_DEBUG_FS 424 .show = a3xx_show, 425 #endif 426 }, 427 }; 428 429 static const struct msm_gpu_perfcntr perfcntrs[] = { 430 { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO, 431 SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" }, 432 { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO, 433 SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" }, 434 }; 435 436 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) 437 { 438 struct a3xx_gpu *a3xx_gpu = NULL; 439 struct adreno_gpu *adreno_gpu; 440 struct msm_gpu *gpu; 441 struct msm_drm_private *priv = dev->dev_private; 442 struct platform_device *pdev = priv->gpu_pdev; 443 int ret; 444 445 if (!pdev) { 446 dev_err(dev->dev, "no a3xx device\n"); 447 ret = -ENXIO; 448 goto fail; 449 } 450 451 a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL); 452 if (!a3xx_gpu) { 453 ret = -ENOMEM; 454 goto fail; 455 } 456 457 adreno_gpu = &a3xx_gpu->base; 458 gpu = &adreno_gpu->base; 459 460 a3xx_gpu->pdev = pdev; 461 462 gpu->perfcntrs = perfcntrs; 463 gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs); 464 465 adreno_gpu->registers = a3xx_registers; 466 467 ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs); 468 if (ret) 469 goto fail; 470 471 /* if needed, allocate gmem: */ 472 if (adreno_is_a330(adreno_gpu)) { 473 #ifdef CONFIG_MSM_OCMEM 474 /* TODO this is different/missing upstream: */ 475 struct ocmem_buf *ocmem_hdl = 476 ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); 477 478 a3xx_gpu->ocmem_hdl = ocmem_hdl; 479 a3xx_gpu->ocmem_base = ocmem_hdl->addr; 480 adreno_gpu->gmem = ocmem_hdl->len; 481 DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, 482 a3xx_gpu->ocmem_base); 483 #endif 484 } 485 486 if (!gpu->mmu) { 487 /* TODO we think it is possible to configure the GPU to 488 * restrict access to VRAM carveout. But the required 489 * registers are unknown. For now just bail out and 490 * limp along with just modesetting. If it turns out 491 * to not be possible to restrict access, then we must 492 * implement a cmdstream validator. 493 */ 494 dev_err(dev->dev, "No memory protection without IOMMU\n"); 495 ret = -ENXIO; 496 goto fail; 497 } 498 499 return gpu; 500 501 fail: 502 if (a3xx_gpu) 503 a3xx_destroy(&a3xx_gpu->base.base); 504 505 return ERR_PTR(ret); 506 } 507