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