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