xref: /linux/drivers/gpu/drm/msm/adreno/a3xx_gpu.c (revision 3bcefb0497f9fcad19be286b14d286784d584c5b)
17198e6b0SRob Clark /*
27198e6b0SRob Clark  * Copyright (C) 2013 Red Hat
37198e6b0SRob Clark  * Author: Rob Clark <robdclark@gmail.com>
47198e6b0SRob Clark  *
57198e6b0SRob Clark  * This program is free software; you can redistribute it and/or modify it
67198e6b0SRob Clark  * under the terms of the GNU General Public License version 2 as published by
77198e6b0SRob Clark  * the Free Software Foundation.
87198e6b0SRob Clark  *
97198e6b0SRob Clark  * This program is distributed in the hope that it will be useful, but WITHOUT
107198e6b0SRob Clark  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
117198e6b0SRob Clark  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
127198e6b0SRob Clark  * more details.
137198e6b0SRob Clark  *
147198e6b0SRob Clark  * You should have received a copy of the GNU General Public License along with
157198e6b0SRob Clark  * this program.  If not, see <http://www.gnu.org/licenses/>.
167198e6b0SRob Clark  */
177198e6b0SRob Clark 
1855459968SRob Clark #ifdef CONFIG_MSM_OCMEM
1955459968SRob Clark #  include <mach/ocmem.h>
2055459968SRob Clark #endif
2155459968SRob Clark 
227198e6b0SRob Clark #include "a3xx_gpu.h"
237198e6b0SRob Clark 
247198e6b0SRob Clark #define A3XX_INT0_MASK \
257198e6b0SRob Clark 	(A3XX_INT0_RBBM_AHB_ERROR |        \
267198e6b0SRob Clark 	 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
277198e6b0SRob Clark 	 A3XX_INT0_CP_T0_PACKET_IN_IB |    \
287198e6b0SRob Clark 	 A3XX_INT0_CP_OPCODE_ERROR |       \
297198e6b0SRob Clark 	 A3XX_INT0_CP_RESERVED_BIT_ERROR | \
307198e6b0SRob Clark 	 A3XX_INT0_CP_HW_FAULT |           \
317198e6b0SRob Clark 	 A3XX_INT0_CP_IB1_INT |            \
327198e6b0SRob Clark 	 A3XX_INT0_CP_IB2_INT |            \
337198e6b0SRob Clark 	 A3XX_INT0_CP_RB_INT |             \
347198e6b0SRob Clark 	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \
357198e6b0SRob Clark 	 A3XX_INT0_CP_AHB_ERROR_HALT |     \
367198e6b0SRob Clark 	 A3XX_INT0_UCHE_OOB_ACCESS)
377198e6b0SRob Clark 
383526e9fbSRob Clark extern bool hang_debug;
395b6ef08eSRob Clark 
405b6ef08eSRob Clark static void a3xx_dump(struct msm_gpu *gpu);
415b6ef08eSRob Clark 
427198e6b0SRob Clark static void a3xx_me_init(struct msm_gpu *gpu)
437198e6b0SRob Clark {
447198e6b0SRob Clark 	struct msm_ringbuffer *ring = gpu->rb;
457198e6b0SRob Clark 
467198e6b0SRob Clark 	OUT_PKT3(ring, CP_ME_INIT, 17);
477198e6b0SRob Clark 	OUT_RING(ring, 0x000003f7);
487198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
497198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
507198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
517198e6b0SRob Clark 	OUT_RING(ring, 0x00000080);
527198e6b0SRob Clark 	OUT_RING(ring, 0x00000100);
537198e6b0SRob Clark 	OUT_RING(ring, 0x00000180);
547198e6b0SRob Clark 	OUT_RING(ring, 0x00006600);
557198e6b0SRob Clark 	OUT_RING(ring, 0x00000150);
567198e6b0SRob Clark 	OUT_RING(ring, 0x0000014e);
577198e6b0SRob Clark 	OUT_RING(ring, 0x00000154);
587198e6b0SRob Clark 	OUT_RING(ring, 0x00000001);
597198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
607198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
617198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
627198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
637198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
647198e6b0SRob Clark 
657198e6b0SRob Clark 	gpu->funcs->flush(gpu);
667198e6b0SRob Clark 	gpu->funcs->idle(gpu);
677198e6b0SRob Clark }
687198e6b0SRob Clark 
697198e6b0SRob Clark static int a3xx_hw_init(struct msm_gpu *gpu)
707198e6b0SRob Clark {
717198e6b0SRob Clark 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
7255459968SRob Clark 	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
737198e6b0SRob Clark 	uint32_t *ptr, len;
747198e6b0SRob Clark 	int i, ret;
757198e6b0SRob Clark 
767198e6b0SRob Clark 	DBG("%s", gpu->name);
777198e6b0SRob Clark 
787198e6b0SRob Clark 	if (adreno_is_a305(adreno_gpu)) {
797198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
807198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
817198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
827198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
837198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
847198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
857198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
867198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
877198e6b0SRob Clark 		/* Enable WR-REQ: */
887198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
897198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
907198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
917198e6b0SRob Clark 		/* Set up AOOO: */
927198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
937198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
947198e6b0SRob Clark 
957198e6b0SRob Clark 	} else if (adreno_is_a320(adreno_gpu)) {
967198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
977198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
987198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
997198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
1007198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
1017198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
1027198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
1037198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
1047198e6b0SRob Clark 		/* Enable WR-REQ: */
1057198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
1067198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
1077198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
1087198e6b0SRob Clark 		/* Set up AOOO: */
1097198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
1107198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
1117198e6b0SRob Clark 		/* Enable 1K sort: */
1127198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);
1137198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
1147198e6b0SRob Clark 
11555459968SRob Clark 	} else if (adreno_is_a330v2(adreno_gpu)) {
11655459968SRob Clark 		/*
11755459968SRob Clark 		 * Most of the VBIF registers on 8974v2 have the correct
11855459968SRob Clark 		 * values at power on, so we won't modify those if we don't
11955459968SRob Clark 		 * need to
12055459968SRob Clark 		 */
12155459968SRob Clark 		/* Enable 1k sort: */
12255459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
12355459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
12455459968SRob Clark 		/* Enable WR-REQ: */
12555459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
12655459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
12755459968SRob Clark 		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
12855459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
12955459968SRob Clark 
1307198e6b0SRob Clark 	} else if (adreno_is_a330(adreno_gpu)) {
1317198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
1327198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
1337198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
1347198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
1357198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
1367198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
1377198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
1387198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
1397198e6b0SRob Clark 		/* Enable WR-REQ: */
1407198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
1417198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
1427198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
1437198e6b0SRob Clark 		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
1447198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
1457198e6b0SRob Clark 		/* Set up AOOO: */
14655459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f);
14755459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f);
1487198e6b0SRob Clark 		/* Enable 1K sort: */
14955459968SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
1507198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
1517198e6b0SRob Clark 		/* Disable VBIF clock gating. This is to enable AXI running
1527198e6b0SRob Clark 		 * higher frequency than GPU:
1537198e6b0SRob Clark 		 */
1547198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001);
1557198e6b0SRob Clark 
1567198e6b0SRob Clark 	} else {
1577198e6b0SRob Clark 		BUG();
1587198e6b0SRob Clark 	}
1597198e6b0SRob Clark 
1607198e6b0SRob Clark 	/* Make all blocks contribute to the GPU BUSY perf counter: */
1617198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
1627198e6b0SRob Clark 
1637198e6b0SRob Clark 	/* Tune the hystersis counters for SP and CP idle detection: */
1647198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10);
1657198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
1667198e6b0SRob Clark 
1677198e6b0SRob Clark 	/* Enable the RBBM error reporting bits.  This lets us get
1687198e6b0SRob Clark 	 * useful information on failure:
1697198e6b0SRob Clark 	 */
1707198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001);
1717198e6b0SRob Clark 
1727198e6b0SRob Clark 	/* Enable AHB error reporting: */
1737198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff);
1747198e6b0SRob Clark 
1757198e6b0SRob Clark 	/* Turn on the power counters: */
1767198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000);
1777198e6b0SRob Clark 
1787198e6b0SRob Clark 	/* Turn on hang detection - this spews a lot of useful information
1797198e6b0SRob Clark 	 * into the RBBM registers on a hang:
1807198e6b0SRob Clark 	 */
1817198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff);
1827198e6b0SRob Clark 
1837198e6b0SRob Clark 	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */
1847198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
1857198e6b0SRob Clark 
1867198e6b0SRob Clark 	/* Enable Clock gating: */
18755459968SRob Clark 	if (adreno_is_a320(adreno_gpu))
1887198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
18955459968SRob Clark 	else if (adreno_is_a330v2(adreno_gpu))
19055459968SRob Clark 		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
19155459968SRob Clark 	else if (adreno_is_a330(adreno_gpu))
19255459968SRob Clark 		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff);
1937198e6b0SRob Clark 
19455459968SRob Clark 	if (adreno_is_a330v2(adreno_gpu))
19555459968SRob Clark 		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455);
19655459968SRob Clark 	else if (adreno_is_a330(adreno_gpu))
19755459968SRob Clark 		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000);
19855459968SRob Clark 
19955459968SRob Clark 	/* Set the OCMEM base address for A330, etc */
20055459968SRob Clark 	if (a3xx_gpu->ocmem_hdl) {
20155459968SRob Clark 		gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
20255459968SRob Clark 			(unsigned int)(a3xx_gpu->ocmem_base >> 14));
20355459968SRob Clark 	}
2047198e6b0SRob Clark 
2057198e6b0SRob Clark 	/* Turn on performance counters: */
2067198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
2077198e6b0SRob Clark 
20870c70f09SRob Clark 	/* Enable the perfcntrs that we use.. */
20970c70f09SRob Clark 	for (i = 0; i < gpu->num_perfcntrs; i++) {
21070c70f09SRob Clark 		const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
21170c70f09SRob Clark 		gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
21270c70f09SRob Clark 	}
2137198e6b0SRob Clark 
2147198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
2157198e6b0SRob Clark 
2167198e6b0SRob Clark 	ret = adreno_hw_init(gpu);
2177198e6b0SRob Clark 	if (ret)
2187198e6b0SRob Clark 		return ret;
2197198e6b0SRob Clark 
2207198e6b0SRob Clark 	/* setup access protection: */
2217198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
2227198e6b0SRob Clark 
2237198e6b0SRob Clark 	/* RBBM registers */
2247198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040);
2257198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080);
2267198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc);
2277198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108);
2287198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140);
2297198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400);
2307198e6b0SRob Clark 
2317198e6b0SRob Clark 	/* CP registers */
2327198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700);
2337198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8);
2347198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0);
2357198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178);
2367198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180);
2377198e6b0SRob Clark 
2387198e6b0SRob Clark 	/* RB registers */
2397198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300);
2407198e6b0SRob Clark 
2417198e6b0SRob Clark 	/* VBIF registers */
2427198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000);
2437198e6b0SRob Clark 
2447198e6b0SRob Clark 	/* NOTE: PM4/micro-engine firmware registers look to be the same
2457198e6b0SRob Clark 	 * for a2xx and a3xx.. we could possibly push that part down to
2467198e6b0SRob Clark 	 * adreno_gpu base class.  Or push both PM4 and PFP but
2477198e6b0SRob Clark 	 * parameterize the pfp ucode addr/data registers..
2487198e6b0SRob Clark 	 */
2497198e6b0SRob Clark 
2507198e6b0SRob Clark 	/* Load PM4: */
2517198e6b0SRob Clark 	ptr = (uint32_t *)(adreno_gpu->pm4->data);
2527198e6b0SRob Clark 	len = adreno_gpu->pm4->size / 4;
253e529c7e6SRob Clark 	DBG("loading PM4 ucode version: %x", ptr[1]);
2547198e6b0SRob Clark 
2557198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_DEBUG,
2567198e6b0SRob Clark 			AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |
2577198e6b0SRob Clark 			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
2587198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
2597198e6b0SRob Clark 	for (i = 1; i < len; i++)
2607198e6b0SRob Clark 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
2617198e6b0SRob Clark 
2627198e6b0SRob Clark 	/* Load PFP: */
2637198e6b0SRob Clark 	ptr = (uint32_t *)(adreno_gpu->pfp->data);
2647198e6b0SRob Clark 	len = adreno_gpu->pfp->size / 4;
265e529c7e6SRob Clark 	DBG("loading PFP ucode version: %x", ptr[5]);
2667198e6b0SRob Clark 
2677198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
2687198e6b0SRob Clark 	for (i = 1; i < len; i++)
2697198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);
2707198e6b0SRob Clark 
2717198e6b0SRob Clark 	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
27255459968SRob Clark 	if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) {
2737198e6b0SRob Clark 		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,
2747198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |
2757198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |
2767198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));
27755459968SRob Clark 	} else if (adreno_is_a330(adreno_gpu)) {
27855459968SRob Clark 		/* NOTE: this (value take from downstream android driver)
27955459968SRob Clark 		 * includes some bits outside of the known bitfields.  But
28055459968SRob Clark 		 * A330 has this "MERCIU queue" thing too, which might
28155459968SRob Clark 		 * explain a new bitfield or reshuffling:
28255459968SRob Clark 		 */
28355459968SRob Clark 		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008);
28455459968SRob Clark 	}
2857198e6b0SRob Clark 
2867198e6b0SRob Clark 	/* clear ME_HALT to start micro engine */
2877198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
2887198e6b0SRob Clark 
2897198e6b0SRob Clark 	a3xx_me_init(gpu);
2907198e6b0SRob Clark 
2917198e6b0SRob Clark 	return 0;
2927198e6b0SRob Clark }
2937198e6b0SRob Clark 
29455459968SRob Clark static void a3xx_recover(struct msm_gpu *gpu)
29555459968SRob Clark {
2965b6ef08eSRob Clark 	/* dump registers before resetting gpu, if enabled: */
2975b6ef08eSRob Clark 	if (hang_debug)
2985b6ef08eSRob Clark 		a3xx_dump(gpu);
29955459968SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
30055459968SRob Clark 	gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
30155459968SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
30255459968SRob Clark 	adreno_recover(gpu);
30355459968SRob Clark }
30455459968SRob Clark 
3057198e6b0SRob Clark static void a3xx_destroy(struct msm_gpu *gpu)
3067198e6b0SRob Clark {
3077198e6b0SRob Clark 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
3087198e6b0SRob Clark 	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
3097198e6b0SRob Clark 
3107198e6b0SRob Clark 	DBG("%s", gpu->name);
3117198e6b0SRob Clark 
3127198e6b0SRob Clark 	adreno_gpu_cleanup(adreno_gpu);
31355459968SRob Clark 
31455459968SRob Clark #ifdef CONFIG_MSM_OCMEM
31555459968SRob Clark 	if (a3xx_gpu->ocmem_base)
31655459968SRob Clark 		ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl);
31755459968SRob Clark #endif
31855459968SRob Clark 
3197198e6b0SRob Clark 	kfree(a3xx_gpu);
3207198e6b0SRob Clark }
3217198e6b0SRob Clark 
3227198e6b0SRob Clark static void a3xx_idle(struct msm_gpu *gpu)
3237198e6b0SRob Clark {
3247198e6b0SRob Clark 	/* wait for ringbuffer to drain: */
3257198e6b0SRob Clark 	adreno_idle(gpu);
3267198e6b0SRob Clark 
3277198e6b0SRob Clark 	/* then wait for GPU to finish: */
3280963756fSRob Clark 	if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
3290963756fSRob Clark 			A3XX_RBBM_STATUS_GPU_BUSY)))
3300963756fSRob Clark 		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
3317198e6b0SRob Clark 
3327198e6b0SRob Clark 	/* TODO maybe we need to reset GPU here to recover from hang? */
3337198e6b0SRob Clark }
3347198e6b0SRob Clark 
3357198e6b0SRob Clark static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
3367198e6b0SRob Clark {
3377198e6b0SRob Clark 	uint32_t status;
3387198e6b0SRob Clark 
3397198e6b0SRob Clark 	status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS);
3407198e6b0SRob Clark 	DBG("%s: %08x", gpu->name, status);
3417198e6b0SRob Clark 
3427198e6b0SRob Clark 	// TODO
3437198e6b0SRob Clark 
3447198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status);
3457198e6b0SRob Clark 
3467198e6b0SRob Clark 	msm_gpu_retire(gpu);
3477198e6b0SRob Clark 
3487198e6b0SRob Clark 	return IRQ_HANDLED;
3497198e6b0SRob Clark }
3507198e6b0SRob Clark 
3517198e6b0SRob Clark static const unsigned int a3xx_registers[] = {
3527198e6b0SRob Clark 	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
3537198e6b0SRob Clark 	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
3547198e6b0SRob Clark 	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,
3557198e6b0SRob Clark 	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,
3567198e6b0SRob Clark 	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,
3577198e6b0SRob Clark 	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,
3587198e6b0SRob Clark 	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,
3597198e6b0SRob Clark 	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,
3607198e6b0SRob Clark 	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
3617198e6b0SRob Clark 	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
3627198e6b0SRob Clark 	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
3637198e6b0SRob Clark 	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
3647198e6b0SRob Clark 	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
3657198e6b0SRob Clark 	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
3667198e6b0SRob Clark 	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
3677198e6b0SRob Clark 	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
3687198e6b0SRob Clark 	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,
3697198e6b0SRob Clark 	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
3707198e6b0SRob Clark 	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
3717198e6b0SRob Clark 	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
3727198e6b0SRob Clark 	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
3737198e6b0SRob Clark 	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
3747198e6b0SRob Clark 	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
3757198e6b0SRob Clark 	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
3767198e6b0SRob Clark 	0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
3777198e6b0SRob Clark 	0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
3787198e6b0SRob Clark 	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
3797198e6b0SRob Clark 	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
3807198e6b0SRob Clark 	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
3817198e6b0SRob Clark 	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
3827198e6b0SRob Clark 	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
3837198e6b0SRob Clark 	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
3847198e6b0SRob Clark 	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
3857198e6b0SRob Clark 	0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
3867198e6b0SRob Clark 	0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
3877198e6b0SRob Clark 	0x303c, 0x303c, 0x305e, 0x305f,
388*3bcefb04SRob Clark 	~0   /* sentinel */
3897198e6b0SRob Clark };
3907198e6b0SRob Clark 
3915b6ef08eSRob Clark #ifdef CONFIG_DEBUG_FS
3927198e6b0SRob Clark static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
3937198e6b0SRob Clark {
39437d77c3aSRob Clark 	gpu->funcs->pm_resume(gpu);
3957198e6b0SRob Clark 	seq_printf(m, "status:   %08x\n",
3967198e6b0SRob Clark 			gpu_read(gpu, REG_A3XX_RBBM_STATUS));
39737d77c3aSRob Clark 	gpu->funcs->pm_suspend(gpu);
398*3bcefb04SRob Clark 	adreno_show(gpu, m);
3997198e6b0SRob Clark }
4007198e6b0SRob Clark #endif
4017198e6b0SRob Clark 
4025b6ef08eSRob Clark /* would be nice to not have to duplicate the _show() stuff with printk(): */
4035b6ef08eSRob Clark static void a3xx_dump(struct msm_gpu *gpu)
4045b6ef08eSRob Clark {
4055b6ef08eSRob Clark 	printk("status:   %08x\n",
4065b6ef08eSRob Clark 			gpu_read(gpu, REG_A3XX_RBBM_STATUS));
407*3bcefb04SRob Clark 	adreno_dump(gpu);
4085b6ef08eSRob Clark }
4095b6ef08eSRob Clark 
4107198e6b0SRob Clark static const struct adreno_gpu_funcs funcs = {
4117198e6b0SRob Clark 	.base = {
4127198e6b0SRob Clark 		.get_param = adreno_get_param,
4137198e6b0SRob Clark 		.hw_init = a3xx_hw_init,
4147198e6b0SRob Clark 		.pm_suspend = msm_gpu_pm_suspend,
4157198e6b0SRob Clark 		.pm_resume = msm_gpu_pm_resume,
41655459968SRob Clark 		.recover = a3xx_recover,
4177198e6b0SRob Clark 		.last_fence = adreno_last_fence,
4187198e6b0SRob Clark 		.submit = adreno_submit,
4197198e6b0SRob Clark 		.flush = adreno_flush,
4207198e6b0SRob Clark 		.idle = a3xx_idle,
4217198e6b0SRob Clark 		.irq = a3xx_irq,
4227198e6b0SRob Clark 		.destroy = a3xx_destroy,
4237198e6b0SRob Clark #ifdef CONFIG_DEBUG_FS
4247198e6b0SRob Clark 		.show = a3xx_show,
4257198e6b0SRob Clark #endif
4267198e6b0SRob Clark 	},
4277198e6b0SRob Clark };
4287198e6b0SRob Clark 
42970c70f09SRob Clark static const struct msm_gpu_perfcntr perfcntrs[] = {
43070c70f09SRob Clark 	{ REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
43170c70f09SRob Clark 			SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
43270c70f09SRob Clark 	{ REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
43370c70f09SRob Clark 			SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
43470c70f09SRob Clark };
43570c70f09SRob Clark 
4367198e6b0SRob Clark struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
4377198e6b0SRob Clark {
4387198e6b0SRob Clark 	struct a3xx_gpu *a3xx_gpu = NULL;
43955459968SRob Clark 	struct adreno_gpu *adreno_gpu;
4407198e6b0SRob Clark 	struct msm_gpu *gpu;
441060530f1SRob Clark 	struct msm_drm_private *priv = dev->dev_private;
442060530f1SRob Clark 	struct platform_device *pdev = priv->gpu_pdev;
4437198e6b0SRob Clark 	int ret;
4447198e6b0SRob Clark 
4457198e6b0SRob Clark 	if (!pdev) {
4467198e6b0SRob Clark 		dev_err(dev->dev, "no a3xx device\n");
4477198e6b0SRob Clark 		ret = -ENXIO;
4487198e6b0SRob Clark 		goto fail;
4497198e6b0SRob Clark 	}
4507198e6b0SRob Clark 
4517198e6b0SRob Clark 	a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
4527198e6b0SRob Clark 	if (!a3xx_gpu) {
4537198e6b0SRob Clark 		ret = -ENOMEM;
4547198e6b0SRob Clark 		goto fail;
4557198e6b0SRob Clark 	}
4567198e6b0SRob Clark 
45755459968SRob Clark 	adreno_gpu = &a3xx_gpu->base;
45855459968SRob Clark 	gpu = &adreno_gpu->base;
4597198e6b0SRob Clark 
4607198e6b0SRob Clark 	a3xx_gpu->pdev = pdev;
4617198e6b0SRob Clark 
46270c70f09SRob Clark 	gpu->perfcntrs = perfcntrs;
46370c70f09SRob Clark 	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
46470c70f09SRob Clark 
465*3bcefb04SRob Clark 	adreno_gpu->registers = a3xx_registers;
466*3bcefb04SRob Clark 
4673526e9fbSRob Clark 	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
4687198e6b0SRob Clark 	if (ret)
4697198e6b0SRob Clark 		goto fail;
4707198e6b0SRob Clark 
47155459968SRob Clark 	/* if needed, allocate gmem: */
47255459968SRob Clark 	if (adreno_is_a330(adreno_gpu)) {
47355459968SRob Clark #ifdef CONFIG_MSM_OCMEM
47455459968SRob Clark 		/* TODO this is different/missing upstream: */
47555459968SRob Clark 		struct ocmem_buf *ocmem_hdl =
47655459968SRob Clark 				ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem);
47755459968SRob Clark 
47855459968SRob Clark 		a3xx_gpu->ocmem_hdl = ocmem_hdl;
47955459968SRob Clark 		a3xx_gpu->ocmem_base = ocmem_hdl->addr;
48055459968SRob Clark 		adreno_gpu->gmem = ocmem_hdl->len;
48155459968SRob Clark 		DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024,
48255459968SRob Clark 				a3xx_gpu->ocmem_base);
48355459968SRob Clark #endif
48455459968SRob Clark 	}
48555459968SRob Clark 
486871d812aSRob Clark 	if (!gpu->mmu) {
487871d812aSRob Clark 		/* TODO we think it is possible to configure the GPU to
488871d812aSRob Clark 		 * restrict access to VRAM carveout.  But the required
489871d812aSRob Clark 		 * registers are unknown.  For now just bail out and
490871d812aSRob Clark 		 * limp along with just modesetting.  If it turns out
491871d812aSRob Clark 		 * to not be possible to restrict access, then we must
492871d812aSRob Clark 		 * implement a cmdstream validator.
493871d812aSRob Clark 		 */
494871d812aSRob Clark 		dev_err(dev->dev, "No memory protection without IOMMU\n");
495871d812aSRob Clark 		ret = -ENXIO;
496871d812aSRob Clark 		goto fail;
497871d812aSRob Clark 	}
498871d812aSRob Clark 
499871d812aSRob Clark 	return gpu;
5007198e6b0SRob Clark 
5017198e6b0SRob Clark fail:
5027198e6b0SRob Clark 	if (a3xx_gpu)
5037198e6b0SRob Clark 		a3xx_destroy(&a3xx_gpu->base.base);
5047198e6b0SRob Clark 
5057198e6b0SRob Clark 	return ERR_PTR(ret);
5067198e6b0SRob Clark }
507