treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / gpu / drm / msm / adreno / a3xx_gpu.c
blobb67f888727264805e3d487f17162b6c28ea970b0
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
6 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
7 */
9 #include "a3xx_gpu.h"
11 #define A3XX_INT0_MASK \
12 (A3XX_INT0_RBBM_AHB_ERROR | \
13 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
14 A3XX_INT0_CP_T0_PACKET_IN_IB | \
15 A3XX_INT0_CP_OPCODE_ERROR | \
16 A3XX_INT0_CP_RESERVED_BIT_ERROR | \
17 A3XX_INT0_CP_HW_FAULT | \
18 A3XX_INT0_CP_IB1_INT | \
19 A3XX_INT0_CP_IB2_INT | \
20 A3XX_INT0_CP_RB_INT | \
21 A3XX_INT0_CP_REG_PROTECT_FAULT | \
22 A3XX_INT0_CP_AHB_ERROR_HALT | \
23 A3XX_INT0_CACHE_FLUSH_TS | \
24 A3XX_INT0_UCHE_OOB_ACCESS)
26 extern bool hang_debug;
28 static void a3xx_dump(struct msm_gpu *gpu);
29 static bool a3xx_idle(struct msm_gpu *gpu);
31 static bool a3xx_me_init(struct msm_gpu *gpu)
33 struct msm_ringbuffer *ring = gpu->rb[0];
35 OUT_PKT3(ring, CP_ME_INIT, 17);
36 OUT_RING(ring, 0x000003f7);
37 OUT_RING(ring, 0x00000000);
38 OUT_RING(ring, 0x00000000);
39 OUT_RING(ring, 0x00000000);
40 OUT_RING(ring, 0x00000080);
41 OUT_RING(ring, 0x00000100);
42 OUT_RING(ring, 0x00000180);
43 OUT_RING(ring, 0x00006600);
44 OUT_RING(ring, 0x00000150);
45 OUT_RING(ring, 0x0000014e);
46 OUT_RING(ring, 0x00000154);
47 OUT_RING(ring, 0x00000001);
48 OUT_RING(ring, 0x00000000);
49 OUT_RING(ring, 0x00000000);
50 OUT_RING(ring, 0x00000000);
51 OUT_RING(ring, 0x00000000);
52 OUT_RING(ring, 0x00000000);
54 gpu->funcs->flush(gpu, ring);
55 return a3xx_idle(gpu);
58 static int a3xx_hw_init(struct msm_gpu *gpu)
60 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
61 struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
62 uint32_t *ptr, len;
63 int i, ret;
65 DBG("%s", gpu->name);
67 if (adreno_is_a305(adreno_gpu)) {
68 /* Set up 16 deep read/write request queues: */
69 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
70 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
71 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
72 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
73 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
74 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
75 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
76 /* Enable WR-REQ: */
77 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
78 /* Set up round robin arbitration between both AXI ports: */
79 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
80 /* Set up AOOO: */
81 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
82 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
83 } else if (adreno_is_a306(adreno_gpu)) {
84 gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
85 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x0000000a);
86 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x0000000a);
87 } else if (adreno_is_a320(adreno_gpu)) {
88 /* Set up 16 deep read/write request queues: */
89 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
90 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
91 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
92 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
93 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
94 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
95 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
96 /* Enable WR-REQ: */
97 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
98 /* Set up round robin arbitration between both AXI ports: */
99 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
100 /* Set up AOOO: */
101 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
102 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
103 /* Enable 1K sort: */
104 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);
105 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
107 } else if (adreno_is_a330v2(adreno_gpu)) {
109 * Most of the VBIF registers on 8974v2 have the correct
110 * values at power on, so we won't modify those if we don't
111 * need to
113 /* Enable 1k sort: */
114 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
115 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
116 /* Enable WR-REQ: */
117 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
118 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
119 /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
120 gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
122 } else if (adreno_is_a330(adreno_gpu)) {
123 /* Set up 16 deep read/write request queues: */
124 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
125 gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
126 gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
127 gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
128 gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
129 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
130 gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
131 /* Enable WR-REQ: */
132 gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
133 /* Set up round robin arbitration between both AXI ports: */
134 gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
135 /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
136 gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
137 /* Set up AOOO: */
138 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f);
139 gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f);
140 /* Enable 1K sort: */
141 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
142 gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
143 /* Disable VBIF clock gating. This is to enable AXI running
144 * higher frequency than GPU:
146 gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001);
148 } else {
149 BUG();
152 /* Make all blocks contribute to the GPU BUSY perf counter: */
153 gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
155 /* Tune the hystersis counters for SP and CP idle detection: */
156 gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10);
157 gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
159 /* Enable the RBBM error reporting bits. This lets us get
160 * useful information on failure:
162 gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001);
164 /* Enable AHB error reporting: */
165 gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff);
167 /* Turn on the power counters: */
168 gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000);
170 /* Turn on hang detection - this spews a lot of useful information
171 * into the RBBM registers on a hang:
173 gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff);
175 /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */
176 gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
178 /* Enable Clock gating: */
179 if (adreno_is_a306(adreno_gpu))
180 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
181 else if (adreno_is_a320(adreno_gpu))
182 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
183 else if (adreno_is_a330v2(adreno_gpu))
184 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
185 else if (adreno_is_a330(adreno_gpu))
186 gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff);
188 if (adreno_is_a330v2(adreno_gpu))
189 gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455);
190 else if (adreno_is_a330(adreno_gpu))
191 gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000);
193 /* Set the OCMEM base address for A330, etc */
194 if (a3xx_gpu->ocmem.hdl) {
195 gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
196 (unsigned int)(a3xx_gpu->ocmem.base >> 14));
199 /* Turn on performance counters: */
200 gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
202 /* Enable the perfcntrs that we use.. */
203 for (i = 0; i < gpu->num_perfcntrs; i++) {
204 const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
205 gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
208 gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
210 ret = adreno_hw_init(gpu);
211 if (ret)
212 return ret;
214 /* setup access protection: */
215 gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
217 /* RBBM registers */
218 gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040);
219 gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080);
220 gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc);
221 gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108);
222 gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140);
223 gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400);
225 /* CP registers */
226 gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700);
227 gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8);
228 gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0);
229 gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178);
230 gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180);
232 /* RB registers */
233 gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300);
235 /* VBIF registers */
236 gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000);
238 /* NOTE: PM4/micro-engine firmware registers look to be the same
239 * for a2xx and a3xx.. we could possibly push that part down to
240 * adreno_gpu base class. Or push both PM4 and PFP but
241 * parameterize the pfp ucode addr/data registers..
244 /* Load PM4: */
245 ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
246 len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
247 DBG("loading PM4 ucode version: %x", ptr[1]);
249 gpu_write(gpu, REG_AXXX_CP_DEBUG,
250 AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |
251 AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
252 gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
253 for (i = 1; i < len; i++)
254 gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
256 /* Load PFP: */
257 ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
258 len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
259 DBG("loading PFP ucode version: %x", ptr[5]);
261 gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
262 for (i = 1; i < len; i++)
263 gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);
265 /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
266 if (adreno_is_a305(adreno_gpu) || adreno_is_a306(adreno_gpu) ||
267 adreno_is_a320(adreno_gpu)) {
268 gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,
269 AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |
270 AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |
271 AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));
272 } else if (adreno_is_a330(adreno_gpu)) {
273 /* NOTE: this (value take from downstream android driver)
274 * includes some bits outside of the known bitfields. But
275 * A330 has this "MERCIU queue" thing too, which might
276 * explain a new bitfield or reshuffling:
278 gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008);
281 /* clear ME_HALT to start micro engine */
282 gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
284 return a3xx_me_init(gpu) ? 0 : -EINVAL;
287 static void a3xx_recover(struct msm_gpu *gpu)
289 int i;
291 adreno_dump_info(gpu);
293 for (i = 0; i < 8; i++) {
294 printk("CP_SCRATCH_REG%d: %u\n", i,
295 gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
298 /* dump registers before resetting gpu, if enabled: */
299 if (hang_debug)
300 a3xx_dump(gpu);
302 gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
303 gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
304 gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
305 adreno_recover(gpu);
308 static void a3xx_destroy(struct msm_gpu *gpu)
310 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
311 struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
313 DBG("%s", gpu->name);
315 adreno_gpu_cleanup(adreno_gpu);
317 adreno_gpu_ocmem_cleanup(&a3xx_gpu->ocmem);
319 kfree(a3xx_gpu);
322 static bool a3xx_idle(struct msm_gpu *gpu)
324 /* wait for ringbuffer to drain: */
325 if (!adreno_idle(gpu, gpu->rb[0]))
326 return false;
328 /* then wait for GPU to finish: */
329 if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
330 A3XX_RBBM_STATUS_GPU_BUSY))) {
331 DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
333 /* TODO maybe we need to reset GPU here to recover from hang? */
334 return false;
337 return true;
340 static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
342 uint32_t status;
344 status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS);
345 DBG("%s: %08x", gpu->name, status);
347 // TODO
349 gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status);
351 msm_gpu_retire(gpu);
353 return IRQ_HANDLED;
356 static const unsigned int a3xx_registers[] = {
357 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
358 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
359 0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,
360 0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,
361 0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,
362 0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,
363 0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,
364 0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,
365 0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
366 0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
367 0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
368 0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
369 0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
370 0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
371 0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
372 0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
373 0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,
374 0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
375 0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
376 0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
377 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
378 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
379 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
380 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444,
381 0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470,
382 0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3,
383 0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e,
384 0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea,
385 0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617,
386 0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0,
387 0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9,
388 0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
389 0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d,
390 0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f,
391 ~0 /* sentinel */
394 /* would be nice to not have to duplicate the _show() stuff with printk(): */
395 static void a3xx_dump(struct msm_gpu *gpu)
397 printk("status: %08x\n",
398 gpu_read(gpu, REG_A3XX_RBBM_STATUS));
399 adreno_dump(gpu);
402 static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu)
404 struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
406 if (!state)
407 return ERR_PTR(-ENOMEM);
409 adreno_gpu_state_get(gpu, state);
411 state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
413 return state;
416 /* Register offset defines for A3XX */
417 static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
418 REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
419 REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI),
420 REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
421 REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI),
422 REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
423 REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
424 REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
427 static const struct adreno_gpu_funcs funcs = {
428 .base = {
429 .get_param = adreno_get_param,
430 .hw_init = a3xx_hw_init,
431 .pm_suspend = msm_gpu_pm_suspend,
432 .pm_resume = msm_gpu_pm_resume,
433 .recover = a3xx_recover,
434 .submit = adreno_submit,
435 .flush = adreno_flush,
436 .active_ring = adreno_active_ring,
437 .irq = a3xx_irq,
438 .destroy = a3xx_destroy,
439 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
440 .show = adreno_show,
441 #endif
442 .gpu_state_get = a3xx_gpu_state_get,
443 .gpu_state_put = adreno_gpu_state_put,
447 static const struct msm_gpu_perfcntr perfcntrs[] = {
448 { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
449 SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
450 { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
451 SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
454 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
456 struct a3xx_gpu *a3xx_gpu = NULL;
457 struct adreno_gpu *adreno_gpu;
458 struct msm_gpu *gpu;
459 struct msm_drm_private *priv = dev->dev_private;
460 struct platform_device *pdev = priv->gpu_pdev;
461 int ret;
463 if (!pdev) {
464 DRM_DEV_ERROR(dev->dev, "no a3xx device\n");
465 ret = -ENXIO;
466 goto fail;
469 a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
470 if (!a3xx_gpu) {
471 ret = -ENOMEM;
472 goto fail;
475 adreno_gpu = &a3xx_gpu->base;
476 gpu = &adreno_gpu->base;
478 gpu->perfcntrs = perfcntrs;
479 gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
481 adreno_gpu->registers = a3xx_registers;
482 adreno_gpu->reg_offsets = a3xx_register_offsets;
484 ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
485 if (ret)
486 goto fail;
488 /* if needed, allocate gmem: */
489 if (adreno_is_a330(adreno_gpu)) {
490 ret = adreno_gpu_ocmem_init(&adreno_gpu->base.pdev->dev,
491 adreno_gpu, &a3xx_gpu->ocmem);
492 if (ret)
493 goto fail;
496 if (!gpu->aspace) {
497 /* TODO we think it is possible to configure the GPU to
498 * restrict access to VRAM carveout. But the required
499 * registers are unknown. For now just bail out and
500 * limp along with just modesetting. If it turns out
501 * to not be possible to restrict access, then we must
502 * implement a cmdstream validator.
504 DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");
505 ret = -ENXIO;
506 goto fail;
510 * Set the ICC path to maximum speed for now by multiplying the fastest
511 * frequency by the bus width (8). We'll want to scale this later on to
512 * improve battery life.
514 icc_set_bw(gpu->icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
515 icc_set_bw(gpu->ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
517 return gpu;
519 fail:
520 if (a3xx_gpu)
521 a3xx_destroy(&a3xx_gpu->base.base);
523 return ERR_PTR(ret);