xref: /openbmc/linux/drivers/gpu/drm/msm/adreno/a2xx_gpu.c (revision 911b8eac)
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 	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
168 		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
169 
170 	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
171 
172 	/* NOTE: PM4/micro-engine firmware registers look to be the same
173 	 * for a2xx and a3xx.. we could possibly push that part down to
174 	 * adreno_gpu base class.  Or push both PM4 and PFP but
175 	 * parameterize the pfp ucode addr/data registers..
176 	 */
177 
178 	/* Load PM4: */
179 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
180 	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
181 	DBG("loading PM4 ucode version: %x", ptr[1]);
182 
183 	gpu_write(gpu, REG_AXXX_CP_DEBUG,
184 			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
185 	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
186 	for (i = 1; i < len; i++)
187 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
188 
189 	/* Load PFP: */
190 	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
191 	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
192 	DBG("loading PFP ucode version: %x", ptr[5]);
193 
194 	gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
195 	for (i = 1; i < len; i++)
196 		gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
197 
198 	gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
199 
200 	/* clear ME_HALT to start micro engine */
201 	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
202 
203 	return a2xx_me_init(gpu) ? 0 : -EINVAL;
204 }
205 
206 static void a2xx_recover(struct msm_gpu *gpu)
207 {
208 	int i;
209 
210 	adreno_dump_info(gpu);
211 
212 	for (i = 0; i < 8; i++) {
213 		printk("CP_SCRATCH_REG%d: %u\n", i,
214 			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
215 	}
216 
217 	/* dump registers before resetting gpu, if enabled: */
218 	if (hang_debug)
219 		a2xx_dump(gpu);
220 
221 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
222 	gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
223 	gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
224 	adreno_recover(gpu);
225 }
226 
227 static void a2xx_destroy(struct msm_gpu *gpu)
228 {
229 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
230 	struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
231 
232 	DBG("%s", gpu->name);
233 
234 	adreno_gpu_cleanup(adreno_gpu);
235 
236 	kfree(a2xx_gpu);
237 }
238 
239 static bool a2xx_idle(struct msm_gpu *gpu)
240 {
241 	/* wait for ringbuffer to drain: */
242 	if (!adreno_idle(gpu, gpu->rb[0]))
243 		return false;
244 
245 	/* then wait for GPU to finish: */
246 	if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
247 			A2XX_RBBM_STATUS_GUI_ACTIVE))) {
248 		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
249 
250 		/* TODO maybe we need to reset GPU here to recover from hang? */
251 		return false;
252 	}
253 
254 	return true;
255 }
256 
257 static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
258 {
259 	uint32_t mstatus, status;
260 
261 	mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
262 
263 	if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
264 		status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
265 
266 		dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
267 		dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
268 			gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
269 
270 		gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
271 	}
272 
273 	if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
274 		status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
275 
276 		/* only RB_INT is expected */
277 		if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
278 			dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
279 
280 		gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
281 	}
282 
283 	if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
284 		status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
285 
286 		dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
287 
288 		gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
289 	}
290 
291 	msm_gpu_retire(gpu);
292 
293 	return IRQ_HANDLED;
294 }
295 
296 static const unsigned int a200_registers[] = {
297 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
298 	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
299 	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
300 	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
301 	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
302 	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
303 	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
304 	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
305 	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
306 	0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
307 	0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
308 	0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
309 	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
310 	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
311 	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
312 	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
313 	0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
314 	0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
315 	0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
316 	0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
317 	0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
318 	0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
319 	0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
320 	0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
321 	0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
322 	~0   /* sentinel */
323 };
324 
325 static const unsigned int a220_registers[] = {
326 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
327 	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
328 	0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
329 	0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
330 	0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
331 	0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
332 	0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
333 	0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
334 	0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
335 	0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
336 	0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
337 	0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
338 	0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
339 	0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
340 	0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
341 	0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
342 	0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
343 	0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
344 	0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
345 	0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
346 	0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
347 	0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
348 	0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
349 	0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
350 	0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
351 	0x4900, 0x4900, 0x4908, 0x4908,
352 	~0   /* sentinel */
353 };
354 
355 static const unsigned int a225_registers[] = {
356 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
357 	0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
358 	0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
359 	0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
360 	0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
361 	0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
362 	0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
363 	0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
364 	0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
365 	0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
366 	0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
367 	0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
368 	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
369 	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
370 	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
371 	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
372 	0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
373 	0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
374 	0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
375 	0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
376 	0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
377 	0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
378 	0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
379 	0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
380 	0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
381 	0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
382 	0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
383 	0x4908, 0x4908,
384 	~0   /* sentinel */
385 };
386 
387 /* would be nice to not have to duplicate the _show() stuff with printk(): */
388 static void a2xx_dump(struct msm_gpu *gpu)
389 {
390 	printk("status:   %08x\n",
391 			gpu_read(gpu, REG_A2XX_RBBM_STATUS));
392 	adreno_dump(gpu);
393 }
394 
395 static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
396 {
397 	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
398 
399 	if (!state)
400 		return ERR_PTR(-ENOMEM);
401 
402 	adreno_gpu_state_get(gpu, state);
403 
404 	state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
405 
406 	return state;
407 }
408 
409 static struct msm_gem_address_space *
410 a2xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev)
411 {
412 	struct msm_mmu *mmu = msm_gpummu_new(&pdev->dev, gpu);
413 	struct msm_gem_address_space *aspace;
414 
415 	aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M,
416 		0xfff * SZ_64K);
417 
418 	if (IS_ERR(aspace) && !IS_ERR(mmu))
419 		mmu->funcs->destroy(mmu);
420 
421 	return aspace;
422 }
423 
424 /* Register offset defines for A2XX - copy of A3XX */
425 static const unsigned int a2xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
426 	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
427 	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_BASE_HI),
428 	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
429 	REG_ADRENO_SKIP(REG_ADRENO_CP_RB_RPTR_ADDR_HI),
430 	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
431 	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
432 	REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
433 };
434 
435 static const struct adreno_gpu_funcs funcs = {
436 	.base = {
437 		.get_param = adreno_get_param,
438 		.hw_init = a2xx_hw_init,
439 		.pm_suspend = msm_gpu_pm_suspend,
440 		.pm_resume = msm_gpu_pm_resume,
441 		.recover = a2xx_recover,
442 		.submit = adreno_submit,
443 		.flush = adreno_flush,
444 		.active_ring = adreno_active_ring,
445 		.irq = a2xx_irq,
446 		.destroy = a2xx_destroy,
447 #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
448 		.show = adreno_show,
449 #endif
450 		.gpu_state_get = a2xx_gpu_state_get,
451 		.gpu_state_put = adreno_gpu_state_put,
452 		.create_address_space = a2xx_create_address_space,
453 	},
454 };
455 
456 static const struct msm_gpu_perfcntr perfcntrs[] = {
457 /* TODO */
458 };
459 
460 struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
461 {
462 	struct a2xx_gpu *a2xx_gpu = NULL;
463 	struct adreno_gpu *adreno_gpu;
464 	struct msm_gpu *gpu;
465 	struct msm_drm_private *priv = dev->dev_private;
466 	struct platform_device *pdev = priv->gpu_pdev;
467 	int ret;
468 
469 	if (!pdev) {
470 		dev_err(dev->dev, "no a2xx device\n");
471 		ret = -ENXIO;
472 		goto fail;
473 	}
474 
475 	a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
476 	if (!a2xx_gpu) {
477 		ret = -ENOMEM;
478 		goto fail;
479 	}
480 
481 	adreno_gpu = &a2xx_gpu->base;
482 	gpu = &adreno_gpu->base;
483 
484 	gpu->perfcntrs = perfcntrs;
485 	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
486 
487 	if (adreno_is_a20x(adreno_gpu))
488 		adreno_gpu->registers = a200_registers;
489 	else if (adreno_is_a225(adreno_gpu))
490 		adreno_gpu->registers = a225_registers;
491 	else
492 		adreno_gpu->registers = a220_registers;
493 
494 	adreno_gpu->reg_offsets = a2xx_register_offsets;
495 
496 	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
497 	if (ret)
498 		goto fail;
499 
500 	if (!gpu->aspace) {
501 		dev_err(dev->dev, "No memory protection without MMU\n");
502 		ret = -ENXIO;
503 		goto fail;
504 	}
505 
506 	return gpu;
507 
508 fail:
509 	if (a2xx_gpu)
510 		a2xx_destroy(&a2xx_gpu->base.base);
511 
512 	return ERR_PTR(ret);
513 }
514