xref: /linux/drivers/gpu/drm/msm/adreno/a2xx_gpu.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
3 
4 #include "a2xx_gpu.h"
5 #include "msm_gem.h"
6 #include "msm_mmu.h"
7 
8 extern bool hang_debug;
9 
10 static void a2xx_dump(struct msm_gpu *gpu);
11 static bool a2xx_idle(struct msm_gpu *gpu);
12 
13 static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
14 {
15 	struct msm_ringbuffer *ring = submit->ring;
16 	unsigned int i;
17 
18 	for (i = 0; i < submit->nr_cmds; i++) {
19 		switch (submit->cmd[i].type) {
20 		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
21 			/* ignore IB-targets */
22 			break;
23 		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
24 			/* ignore if there has not been a ctx switch: */
25 			if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno)
26 				break;
27 			fallthrough;
28 		case MSM_SUBMIT_CMD_BUF:
29 			OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2);
30 			OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
31 			OUT_RING(ring, submit->cmd[i].size);
32 			OUT_PKT2(ring);
33 			break;
34 		}
35 	}
36 
37 	OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);
38 	OUT_RING(ring, submit->seqno);
39 
40 	/* wait for idle before cache flush/interrupt */
41 	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
42 	OUT_RING(ring, 0x00000000);
43 
44 	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
45 	OUT_RING(ring, CACHE_FLUSH_TS);
46 	OUT_RING(ring, rbmemptr(ring, fence));
47 	OUT_RING(ring, submit->seqno);
48 	OUT_PKT3(ring, CP_INTERRUPT, 1);
49 	OUT_RING(ring, 0x80000000);
50 
51 	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
52 }
53 
54 static bool a2xx_me_init(struct msm_gpu *gpu)
55 {
56 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
57 	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
58 	struct msm_ringbuffer *ring = gpu->rb[0];
59 
60 	OUT_PKT3(ring, CP_ME_INIT, 18);
61 
62 	/* All fields present (bits 9:0) */
63 	OUT_RING(ring, 0x000003ff);
64 	/* Disable/Enable Real-Time Stream processing (present but ignored) */
65 	OUT_RING(ring, 0x00000000);
66 	/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
67 	OUT_RING(ring, 0x00000000);
68 
69 	OUT_RING(ring, REG_A2XX_RB_SURFACE_INFO - 0x2000);
70 	OUT_RING(ring, REG_A2XX_PA_SC_WINDOW_OFFSET - 0x2000);
71 	OUT_RING(ring, REG_A2XX_VGT_MAX_VTX_INDX - 0x2000);
72 	OUT_RING(ring, REG_A2XX_SQ_PROGRAM_CNTL - 0x2000);
73 	OUT_RING(ring, REG_A2XX_RB_DEPTHCONTROL - 0x2000);
74 	OUT_RING(ring, REG_A2XX_PA_SU_POINT_SIZE - 0x2000);
75 	OUT_RING(ring, REG_A2XX_PA_SC_LINE_CNTL - 0x2000);
76 	OUT_RING(ring, REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE - 0x2000);
77 
78 	/* Vertex and Pixel Shader Start Addresses in instructions
79 	 * (3 DWORDS per instruction) */
80 	OUT_RING(ring, 0x80000180);
81 	/* Maximum Contexts */
82 	OUT_RING(ring, 0x00000001);
83 	/* Write Confirm Interval and The CP will wait the
84 	 * wait_interval * 16 clocks between polling  */
85 	OUT_RING(ring, 0x00000000);
86 	/* NQ and External Memory Swap */
87 	OUT_RING(ring, 0x00000000);
88 	/* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
89 	if (a2xx_gpu->protection_disabled)
90 		OUT_RING(ring, 0x00000000);
91 	else
92 		OUT_RING(ring, 0x200001f2);
93 	/* Disable header dumping and Header dump address */
94 	OUT_RING(ring, 0x00000000);
95 	/* Header dump size */
96 	OUT_RING(ring, 0x00000000);
97 
98 	if (!a2xx_gpu->protection_disabled) {
99 		/* enable protected mode */
100 		OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
101 		OUT_RING(ring, 1);
102 	}
103 
104 	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
105 	return a2xx_idle(gpu);
106 }
107 
108 static int a2xx_hw_init(struct msm_gpu *gpu)
109 {
110 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
111 	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
112 	dma_addr_t pt_base, tran_error;
113 	uint32_t *ptr, len;
114 	int i, ret;
115 
116 	a2xx_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error);
117 
118 	DBG("%s", gpu->name);
119 
120 	/* halt ME to avoid ucode upload issues on a20x */
121 	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, AXXX_CP_ME_CNTL_HALT);
122 
123 	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
124 	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0xffffffff);
125 
126 	/* note: kgsl uses 0x00000001 after first reset on a22x */
127 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0xffffffff);
128 	msleep(30);
129 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0x00000000);
130 
131 	if (adreno_is_a225(adreno_gpu))
132 		gpu_write(gpu, REG_A2XX_SQ_FLOW_CONTROL, 0x18000000);
133 
134 	/* note: kgsl uses 0x0000ffff for a20x */
135 	gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
136 
137 	/* MPU: physical range */
138 	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000);
139 	gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
140 
141 	gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE |
142 		A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
143 		A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
144 		A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
145 		A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
146 		A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
147 		A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
148 		A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
149 		A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
150 		A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
151 		A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
152 		A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG));
153 
154 	/* same as parameters in adreno_gpu */
155 	gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M |
156 		A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff));
157 
158 	gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base);
159 	gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error);
160 
161 	gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE,
162 		A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
163 		A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
164 
165 	gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
166 		A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
167 		A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
168 		A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE |
169 		A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(1) |
170 		A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE |
171 		A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE |
172 		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE |
173 		A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(8) |
174 		A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE |
175 		A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE |
176 		A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE |
177 		A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE |
178 		A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE);
179 	if (!adreno_is_a20x(adreno_gpu))
180 		gpu_write(gpu, REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1, 0x00032f07);
181 
182 	gpu_write(gpu, REG_A2XX_SQ_VS_PROGRAM, 0x00000000);
183 	gpu_write(gpu, REG_A2XX_SQ_PS_PROGRAM, 0x00000000);
184 
185 	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0); /* 0x200 for msm8960? */
186 	gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0); /* 0x80/0x1a0 for a22x? */
187 
188 	/* note: gsl doesn't set this */
189 	gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
190 
191 	gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL,
192 		A2XX_RBBM_INT_CNTL_RDERR_INT_MASK);
193 	gpu_write(gpu, REG_AXXX_CP_INT_CNTL,
194 		AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK |
195 		AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK |
196 		AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK |
197 		AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK |
198 		AXXX_CP_INT_CNTL_IB_ERROR_MASK |
199 		AXXX_CP_INT_CNTL_IB1_INT_MASK |
200 		AXXX_CP_INT_CNTL_RB_INT_MASK);
201 	gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
202 	gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK,
203 		A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR |
204 		A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR |
205 		A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT);
206 
207 	for (i = 3; i <= 5; i++)
208 		if ((SZ_16K << i) == adreno_gpu->info->gmem)
209 			break;
210 	gpu_write(gpu, REG_A2XX_RB_EDRAM_INFO, i);
211 
212 	ret = adreno_hw_init(gpu);
213 	if (ret)
214 		return ret;
215 
216 	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
217 		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
218 
219 	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
220 
221 	/* NOTE: PM4/micro-engine firmware registers look to be the same
222 	 * for a2xx and a3xx.. we could possibly push that part down to
223 	 * adreno_gpu base class.  Or push both PM4 and PFP but
224 	 * parameterize the pfp ucode addr/data registers..
225 	 */
226 
227 	/* Load PM4: */
228 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
229 	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
230 	DBG("loading PM4 ucode version: %x", ptr[1]);
231 
232 	/*
233 	 * New firmware files seem to have GPU and firmware version in this
234 	 * word (0x20xxxx for A200, 0x220xxx for A220, 0x225xxx for A225).
235 	 * Older firmware files, which lack protection support, have 0 instead.
236 	 */
237 	if (ptr[1] == 0) {
238 		dev_warn(gpu->dev->dev,
239 			 "Legacy firmware detected, disabling protection support\n");
240 		a2xx_gpu->protection_disabled = true;
241 	}
242 
243 	gpu_write(gpu, REG_AXXX_CP_DEBUG,
244 			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
245 	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
246 	for (i = 1; i < len; i++)
247 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
248 
249 	/* Load PFP: */
250 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
251 	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
252 	DBG("loading PFP ucode version: %x", ptr[5]);
253 
254 	gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
255 	for (i = 1; i < len; i++)
256 		gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
257 
258 	gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
259 
260 	/* clear ME_HALT to start micro engine */
261 	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
262 
263 	return a2xx_me_init(gpu) ? 0 : -EINVAL;
264 }
265 
266 static void a2xx_recover(struct msm_gpu *gpu)
267 {
268 	int i;
269 
270 	adreno_dump_info(gpu);
271 
272 	for (i = 0; i < 8; i++) {
273 		printk("CP_SCRATCH_REG%d: %u\n", i,
274 			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
275 	}
276 
277 	/* dump registers before resetting gpu, if enabled: */
278 	if (hang_debug)
279 		a2xx_dump(gpu);
280 
281 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
282 	gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
283 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
284 	adreno_recover(gpu);
285 }
286 
287 static void a2xx_destroy(struct msm_gpu *gpu)
288 {
289 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
290 	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
291 
292 	DBG("%s", gpu->name);
293 
294 	adreno_gpu_cleanup(adreno_gpu);
295 
296 	kfree(a2xx_gpu);
297 }
298 
299 static bool a2xx_idle(struct msm_gpu *gpu)
300 {
301 	/* wait for ringbuffer to drain: */
302 	if (!adreno_idle(gpu, gpu->rb[0]))
303 		return false;
304 
305 	/* then wait for GPU to finish: */
306 	if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
307 			A2XX_RBBM_STATUS_GUI_ACTIVE))) {
308 		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
309 
310 		/* TODO maybe we need to reset GPU here to recover from hang? */
311 		return false;
312 	}
313 
314 	return true;
315 }
316 
317 static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
318 {
319 	uint32_t mstatus, status;
320 
321 	mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
322 
323 	if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
324 		status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
325 
326 		dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
327 		dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
328 			gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
329 
330 		gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
331 	}
332 
333 	if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
334 		status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
335 
336 		/* only RB_INT is expected */
337 		if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
338 			dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
339 
340 		gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
341 	}
342 
343 	if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
344 		status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
345 
346 		dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
347 
348 		gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
349 	}
350 
351 	msm_gpu_retire(gpu);
352 
353 	return IRQ_HANDLED;
354 }
355 
356 static const unsigned int a200_registers[] = {
357 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
358 	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
359 	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
360 	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
361 	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
362 	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
363 	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
364 	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
365 	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
366 	0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
367 	0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
368 	0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
369 	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
370 	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
371 	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
372 	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
373 	0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
374 	0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
375 	0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
376 	0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
377 	0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
378 	0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
379 	0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
380 	0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
381 	0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
382 	~0   /* sentinel */
383 };
384 
385 static const unsigned int a220_registers[] = {
386 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
387 	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
388 	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
389 	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
390 	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
391 	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
392 	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
393 	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
394 	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
395 	0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
396 	0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
397 	0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
398 	0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
399 	0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
400 	0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
401 	0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
402 	0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
403 	0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
404 	0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
405 	0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
406 	0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
407 	0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
408 	0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
409 	0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
410 	0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
411 	0x4900, 0x4900, 0x4908, 0x4908,
412 	~0   /* sentinel */
413 };
414 
415 static const unsigned int a225_registers[] = {
416 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
417 	0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
418 	0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
419 	0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
420 	0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
421 	0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
422 	0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
423 	0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
424 	0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
425 	0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
426 	0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
427 	0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
428 	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
429 	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
430 	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
431 	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
432 	0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
433 	0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
434 	0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
435 	0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
436 	0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
437 	0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
438 	0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
439 	0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
440 	0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
441 	0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
442 	0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
443 	0x4908, 0x4908,
444 	~0   /* sentinel */
445 };
446 
447 /* would be nice to not have to duplicate the _show() stuff with printk(): */
448 static void a2xx_dump(struct msm_gpu *gpu)
449 {
450 	printk("status:   %08x\n",
451 			gpu_read(gpu, REG_A2XX_RBBM_STATUS));
452 	adreno_dump(gpu);
453 }
454 
455 static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
456 {
457 	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
458 
459 	if (!state)
460 		return ERR_PTR(-ENOMEM);
461 
462 	adreno_gpu_state_get(gpu, state);
463 
464 	state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
465 
466 	return state;
467 }
468 
469 static struct msm_gem_address_space *
470 a2xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev)
471 {
472 	struct msm_mmu *mmu = a2xx_gpummu_new(&pdev->dev, gpu);
473 	struct msm_gem_address_space *aspace;
474 
475 	aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M,
476 		0xfff * SZ_64K);
477 
478 	if (IS_ERR(aspace) && !IS_ERR(mmu))
479 		mmu->funcs->destroy(mmu);
480 
481 	return aspace;
482 }
483 
484 static u32 a2xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
485 {
486 	ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
487 	return ring->memptrs->rptr;
488 }
489 
490 static const struct adreno_gpu_funcs funcs = {
491 	.base = {
492 		.get_param = adreno_get_param,
493 		.set_param = adreno_set_param,
494 		.hw_init = a2xx_hw_init,
495 		.pm_suspend = msm_gpu_pm_suspend,
496 		.pm_resume = msm_gpu_pm_resume,
497 		.recover = a2xx_recover,
498 		.submit = a2xx_submit,
499 		.active_ring = adreno_active_ring,
500 		.irq = a2xx_irq,
501 		.destroy = a2xx_destroy,
502 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
503 		.show = adreno_show,
504 #endif
505 		.gpu_state_get = a2xx_gpu_state_get,
506 		.gpu_state_put = adreno_gpu_state_put,
507 		.create_address_space = a2xx_create_address_space,
508 		.get_rptr = a2xx_get_rptr,
509 	},
510 };
511 
512 static const struct msm_gpu_perfcntr perfcntrs[] = {
513 /* TODO */
514 };
515 
516 struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
517 {
518 	struct a2xx_gpu *a2xx_gpu = NULL;
519 	struct adreno_gpu *adreno_gpu;
520 	struct msm_gpu *gpu;
521 	struct msm_drm_private *priv = dev->dev_private;
522 	struct platform_device *pdev = priv->gpu_pdev;
523 	int ret;
524 
525 	if (!pdev) {
526 		dev_err(dev->dev, "no a2xx device\n");
527 		ret = -ENXIO;
528 		goto fail;
529 	}
530 
531 	a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
532 	if (!a2xx_gpu) {
533 		ret = -ENOMEM;
534 		goto fail;
535 	}
536 
537 	adreno_gpu = &a2xx_gpu->base;
538 	gpu = &adreno_gpu->base;
539 
540 	gpu->perfcntrs = perfcntrs;
541 	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
542 
543 	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
544 	if (ret)
545 		goto fail;
546 
547 	if (adreno_is_a20x(adreno_gpu))
548 		adreno_gpu->registers = a200_registers;
549 	else if (adreno_is_a225(adreno_gpu))
550 		adreno_gpu->registers = a225_registers;
551 	else
552 		adreno_gpu->registers = a220_registers;
553 
554 	if (!gpu->aspace) {
555 		dev_err(dev->dev, "No memory protection without MMU\n");
556 		if (!allow_vram_carveout) {
557 			ret = -ENXIO;
558 			goto fail;
559 		}
560 	}
561 
562 	return gpu;
563 
564 fail:
565 	if (a2xx_gpu)
566 		a2xx_destroy(&a2xx_gpu->base.base);
567 
568 	return ERR_PTR(ret);
569 }
570