xref: /linux/drivers/gpu/drm/msm/adreno/a3xx_gpu.c (revision 871d812aa43e6350a4edf41bf7cb0879675255f1)
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 
187198e6b0SRob Clark #include "a3xx_gpu.h"
197198e6b0SRob Clark 
207198e6b0SRob Clark #define A3XX_INT0_MASK \
217198e6b0SRob Clark 	(A3XX_INT0_RBBM_AHB_ERROR |        \
227198e6b0SRob Clark 	 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
237198e6b0SRob Clark 	 A3XX_INT0_CP_T0_PACKET_IN_IB |    \
247198e6b0SRob Clark 	 A3XX_INT0_CP_OPCODE_ERROR |       \
257198e6b0SRob Clark 	 A3XX_INT0_CP_RESERVED_BIT_ERROR | \
267198e6b0SRob Clark 	 A3XX_INT0_CP_HW_FAULT |           \
277198e6b0SRob Clark 	 A3XX_INT0_CP_IB1_INT |            \
287198e6b0SRob Clark 	 A3XX_INT0_CP_IB2_INT |            \
297198e6b0SRob Clark 	 A3XX_INT0_CP_RB_INT |             \
307198e6b0SRob Clark 	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \
317198e6b0SRob Clark 	 A3XX_INT0_CP_AHB_ERROR_HALT |     \
327198e6b0SRob Clark 	 A3XX_INT0_UCHE_OOB_ACCESS)
337198e6b0SRob Clark 
347198e6b0SRob Clark static struct platform_device *a3xx_pdev;
357198e6b0SRob Clark 
367198e6b0SRob Clark static void a3xx_me_init(struct msm_gpu *gpu)
377198e6b0SRob Clark {
387198e6b0SRob Clark 	struct msm_ringbuffer *ring = gpu->rb;
397198e6b0SRob Clark 
407198e6b0SRob Clark 	OUT_PKT3(ring, CP_ME_INIT, 17);
417198e6b0SRob Clark 	OUT_RING(ring, 0x000003f7);
427198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
437198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
447198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
457198e6b0SRob Clark 	OUT_RING(ring, 0x00000080);
467198e6b0SRob Clark 	OUT_RING(ring, 0x00000100);
477198e6b0SRob Clark 	OUT_RING(ring, 0x00000180);
487198e6b0SRob Clark 	OUT_RING(ring, 0x00006600);
497198e6b0SRob Clark 	OUT_RING(ring, 0x00000150);
507198e6b0SRob Clark 	OUT_RING(ring, 0x0000014e);
517198e6b0SRob Clark 	OUT_RING(ring, 0x00000154);
527198e6b0SRob Clark 	OUT_RING(ring, 0x00000001);
537198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
547198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
557198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
567198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
577198e6b0SRob Clark 	OUT_RING(ring, 0x00000000);
587198e6b0SRob Clark 
597198e6b0SRob Clark 	gpu->funcs->flush(gpu);
607198e6b0SRob Clark 	gpu->funcs->idle(gpu);
617198e6b0SRob Clark }
627198e6b0SRob Clark 
637198e6b0SRob Clark static int a3xx_hw_init(struct msm_gpu *gpu)
647198e6b0SRob Clark {
657198e6b0SRob Clark 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
667198e6b0SRob Clark 	uint32_t *ptr, len;
677198e6b0SRob Clark 	int i, ret;
687198e6b0SRob Clark 
697198e6b0SRob Clark 	DBG("%s", gpu->name);
707198e6b0SRob Clark 
717198e6b0SRob Clark 	if (adreno_is_a305(adreno_gpu)) {
727198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
737198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
747198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
757198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
767198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
777198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
787198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
797198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
807198e6b0SRob Clark 		/* Enable WR-REQ: */
817198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
827198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
837198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
847198e6b0SRob Clark 		/* Set up AOOO: */
857198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
867198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
877198e6b0SRob Clark 
887198e6b0SRob Clark 	} else if (adreno_is_a320(adreno_gpu)) {
897198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
907198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
917198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
927198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
937198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
947198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
957198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
967198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
977198e6b0SRob Clark 		/* Enable WR-REQ: */
987198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
997198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
1007198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
1017198e6b0SRob Clark 		/* Set up AOOO: */
1027198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
1037198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
1047198e6b0SRob Clark 		/* Enable 1K sort: */
1057198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);
1067198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
1077198e6b0SRob Clark 
1087198e6b0SRob Clark 	} else if (adreno_is_a330(adreno_gpu)) {
1097198e6b0SRob Clark 		/* Set up 16 deep read/write request queues: */
1107198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
1117198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
1127198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
1137198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
1147198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
1157198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
1167198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
1177198e6b0SRob Clark 		/* Enable WR-REQ: */
1187198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
1197198e6b0SRob Clark 		/* Set up round robin arbitration between both AXI ports: */
1207198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
1217198e6b0SRob Clark 		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
1227198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
1237198e6b0SRob Clark 		/* Set up AOOO: */
1247198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000ffff);
1257198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0xffffffff);
1267198e6b0SRob Clark 		/* Enable 1K sort: */
1277198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001ffff);
1287198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
1297198e6b0SRob Clark 		/* Disable VBIF clock gating. This is to enable AXI running
1307198e6b0SRob Clark 		 * higher frequency than GPU:
1317198e6b0SRob Clark 		 */
1327198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001);
1337198e6b0SRob Clark 
1347198e6b0SRob Clark 	} else {
1357198e6b0SRob Clark 		BUG();
1367198e6b0SRob Clark 	}
1377198e6b0SRob Clark 
1387198e6b0SRob Clark 	/* Make all blocks contribute to the GPU BUSY perf counter: */
1397198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
1407198e6b0SRob Clark 
1417198e6b0SRob Clark 	/* Tune the hystersis counters for SP and CP idle detection: */
1427198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10);
1437198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
1447198e6b0SRob Clark 
1457198e6b0SRob Clark 	/* Enable the RBBM error reporting bits.  This lets us get
1467198e6b0SRob Clark 	 * useful information on failure:
1477198e6b0SRob Clark 	 */
1487198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001);
1497198e6b0SRob Clark 
1507198e6b0SRob Clark 	/* Enable AHB error reporting: */
1517198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff);
1527198e6b0SRob Clark 
1537198e6b0SRob Clark 	/* Turn on the power counters: */
1547198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000);
1557198e6b0SRob Clark 
1567198e6b0SRob Clark 	/* Turn on hang detection - this spews a lot of useful information
1577198e6b0SRob Clark 	 * into the RBBM registers on a hang:
1587198e6b0SRob Clark 	 */
1597198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff);
1607198e6b0SRob Clark 
1617198e6b0SRob Clark 	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */
1627198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
1637198e6b0SRob Clark 
1647198e6b0SRob Clark 	/* Enable Clock gating: */
1657198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
1667198e6b0SRob Clark 
1677198e6b0SRob Clark 	/* Set the OCMEM base address for A330 */
1687198e6b0SRob Clark //TODO:
1697198e6b0SRob Clark //	if (adreno_is_a330(adreno_gpu)) {
1707198e6b0SRob Clark //		gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
1717198e6b0SRob Clark //			(unsigned int)(a3xx_gpu->ocmem_base >> 14));
1727198e6b0SRob Clark //	}
1737198e6b0SRob Clark 
1747198e6b0SRob Clark 	/* Turn on performance counters: */
1757198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
1767198e6b0SRob Clark 
1777198e6b0SRob Clark 	/* Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
1787198e6b0SRob Clark 	 * we will use this to augment our hang detection:
1797198e6b0SRob Clark 	 */
1807198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_SP_PERFCOUNTER7_SELECT,
1817198e6b0SRob Clark 			SP_FS_FULL_ALU_INSTRUCTIONS);
1827198e6b0SRob Clark 
1837198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
1847198e6b0SRob Clark 
1857198e6b0SRob Clark 	ret = adreno_hw_init(gpu);
1867198e6b0SRob Clark 	if (ret)
1877198e6b0SRob Clark 		return ret;
1887198e6b0SRob Clark 
1897198e6b0SRob Clark 	/* setup access protection: */
1907198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
1917198e6b0SRob Clark 
1927198e6b0SRob Clark 	/* RBBM registers */
1937198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040);
1947198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080);
1957198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc);
1967198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108);
1977198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140);
1987198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400);
1997198e6b0SRob Clark 
2007198e6b0SRob Clark 	/* CP registers */
2017198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700);
2027198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8);
2037198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0);
2047198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178);
2057198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180);
2067198e6b0SRob Clark 
2077198e6b0SRob Clark 	/* RB registers */
2087198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300);
2097198e6b0SRob Clark 
2107198e6b0SRob Clark 	/* VBIF registers */
2117198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000);
2127198e6b0SRob Clark 
2137198e6b0SRob Clark 	/* NOTE: PM4/micro-engine firmware registers look to be the same
2147198e6b0SRob Clark 	 * for a2xx and a3xx.. we could possibly push that part down to
2157198e6b0SRob Clark 	 * adreno_gpu base class.  Or push both PM4 and PFP but
2167198e6b0SRob Clark 	 * parameterize the pfp ucode addr/data registers..
2177198e6b0SRob Clark 	 */
2187198e6b0SRob Clark 
2197198e6b0SRob Clark 	/* Load PM4: */
2207198e6b0SRob Clark 	ptr = (uint32_t *)(adreno_gpu->pm4->data);
2217198e6b0SRob Clark 	len = adreno_gpu->pm4->size / 4;
2227198e6b0SRob Clark 	DBG("loading PM4 ucode version: %u", ptr[0]);
2237198e6b0SRob Clark 
2247198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_DEBUG,
2257198e6b0SRob Clark 			AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |
2267198e6b0SRob Clark 			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
2277198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
2287198e6b0SRob Clark 	for (i = 1; i < len; i++)
2297198e6b0SRob Clark 		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
2307198e6b0SRob Clark 
2317198e6b0SRob Clark 	/* Load PFP: */
2327198e6b0SRob Clark 	ptr = (uint32_t *)(adreno_gpu->pfp->data);
2337198e6b0SRob Clark 	len = adreno_gpu->pfp->size / 4;
2347198e6b0SRob Clark 	DBG("loading PFP ucode version: %u", ptr[0]);
2357198e6b0SRob Clark 
2367198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
2377198e6b0SRob Clark 	for (i = 1; i < len; i++)
2387198e6b0SRob Clark 		gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);
2397198e6b0SRob Clark 
2407198e6b0SRob Clark 	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
2417198e6b0SRob Clark 	if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu))
2427198e6b0SRob Clark 		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,
2437198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |
2447198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |
2457198e6b0SRob Clark 				AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));
2467198e6b0SRob Clark 
2477198e6b0SRob Clark 
2487198e6b0SRob Clark 	/* clear ME_HALT to start micro engine */
2497198e6b0SRob Clark 	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
2507198e6b0SRob Clark 
2517198e6b0SRob Clark 	a3xx_me_init(gpu);
2527198e6b0SRob Clark 
2537198e6b0SRob Clark 	return 0;
2547198e6b0SRob Clark }
2557198e6b0SRob Clark 
2567198e6b0SRob Clark static void a3xx_destroy(struct msm_gpu *gpu)
2577198e6b0SRob Clark {
2587198e6b0SRob Clark 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
2597198e6b0SRob Clark 	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
2607198e6b0SRob Clark 
2617198e6b0SRob Clark 	DBG("%s", gpu->name);
2627198e6b0SRob Clark 
2637198e6b0SRob Clark 	adreno_gpu_cleanup(adreno_gpu);
2647198e6b0SRob Clark 	put_device(&a3xx_gpu->pdev->dev);
2657198e6b0SRob Clark 	kfree(a3xx_gpu);
2667198e6b0SRob Clark }
2677198e6b0SRob Clark 
2687198e6b0SRob Clark static void a3xx_idle(struct msm_gpu *gpu)
2697198e6b0SRob Clark {
2707198e6b0SRob Clark 	unsigned long t;
2717198e6b0SRob Clark 
2727198e6b0SRob Clark 	/* wait for ringbuffer to drain: */
2737198e6b0SRob Clark 	adreno_idle(gpu);
2747198e6b0SRob Clark 
2757198e6b0SRob Clark 	t = jiffies + ADRENO_IDLE_TIMEOUT;
2767198e6b0SRob Clark 
2777198e6b0SRob Clark 	/* then wait for GPU to finish: */
2787198e6b0SRob Clark 	do {
2797198e6b0SRob Clark 		uint32_t rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
2807198e6b0SRob Clark 		if (!(rbbm_status & A3XX_RBBM_STATUS_GPU_BUSY))
2817198e6b0SRob Clark 			return;
2827198e6b0SRob Clark 	} while(time_before(jiffies, t));
2837198e6b0SRob Clark 
2847198e6b0SRob Clark 	DRM_ERROR("timeout waiting for %s to idle!\n", gpu->name);
2857198e6b0SRob Clark 
2867198e6b0SRob Clark 	/* TODO maybe we need to reset GPU here to recover from hang? */
2877198e6b0SRob Clark }
2887198e6b0SRob Clark 
2897198e6b0SRob Clark static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
2907198e6b0SRob Clark {
2917198e6b0SRob Clark 	uint32_t status;
2927198e6b0SRob Clark 
2937198e6b0SRob Clark 	status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS);
2947198e6b0SRob Clark 	DBG("%s: %08x", gpu->name, status);
2957198e6b0SRob Clark 
2967198e6b0SRob Clark 	// TODO
2977198e6b0SRob Clark 
2987198e6b0SRob Clark 	gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status);
2997198e6b0SRob Clark 
3007198e6b0SRob Clark 	msm_gpu_retire(gpu);
3017198e6b0SRob Clark 
3027198e6b0SRob Clark 	return IRQ_HANDLED;
3037198e6b0SRob Clark }
3047198e6b0SRob Clark 
3057198e6b0SRob Clark #ifdef CONFIG_DEBUG_FS
3067198e6b0SRob Clark static const unsigned int a3xx_registers[] = {
3077198e6b0SRob Clark 	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
3087198e6b0SRob Clark 	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
3097198e6b0SRob Clark 	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,
3107198e6b0SRob Clark 	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,
3117198e6b0SRob Clark 	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,
3127198e6b0SRob Clark 	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,
3137198e6b0SRob Clark 	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,
3147198e6b0SRob Clark 	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,
3157198e6b0SRob Clark 	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
3167198e6b0SRob Clark 	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
3177198e6b0SRob Clark 	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
3187198e6b0SRob Clark 	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
3197198e6b0SRob Clark 	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
3207198e6b0SRob Clark 	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
3217198e6b0SRob Clark 	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
3227198e6b0SRob Clark 	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
3237198e6b0SRob Clark 	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,
3247198e6b0SRob Clark 	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
3257198e6b0SRob Clark 	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
3267198e6b0SRob Clark 	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
3277198e6b0SRob Clark 	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
3287198e6b0SRob Clark 	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
3297198e6b0SRob Clark 	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
3307198e6b0SRob Clark 	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
3317198e6b0SRob Clark 	0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
3327198e6b0SRob Clark 	0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
3337198e6b0SRob Clark 	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
3347198e6b0SRob Clark 	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
3357198e6b0SRob Clark 	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
3367198e6b0SRob Clark 	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
3377198e6b0SRob Clark 	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
3387198e6b0SRob Clark 	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
3397198e6b0SRob Clark 	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
3407198e6b0SRob Clark 	0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
3417198e6b0SRob Clark 	0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
3427198e6b0SRob Clark 	0x303c, 0x303c, 0x305e, 0x305f,
3437198e6b0SRob Clark };
3447198e6b0SRob Clark 
3457198e6b0SRob Clark static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
3467198e6b0SRob Clark {
3477198e6b0SRob Clark 	int i;
3487198e6b0SRob Clark 
3497198e6b0SRob Clark 	adreno_show(gpu, m);
3507198e6b0SRob Clark 	seq_printf(m, "status:   %08x\n",
3517198e6b0SRob Clark 			gpu_read(gpu, REG_A3XX_RBBM_STATUS));
3527198e6b0SRob Clark 
3537198e6b0SRob Clark 	/* dump these out in a form that can be parsed by demsm: */
3547198e6b0SRob Clark 	seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
3557198e6b0SRob Clark 	for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
3567198e6b0SRob Clark 		uint32_t start = a3xx_registers[i];
3577198e6b0SRob Clark 		uint32_t end   = a3xx_registers[i+1];
3587198e6b0SRob Clark 		uint32_t addr;
3597198e6b0SRob Clark 
3607198e6b0SRob Clark 		for (addr = start; addr <= end; addr++) {
3617198e6b0SRob Clark 			uint32_t val = gpu_read(gpu, addr);
3627198e6b0SRob Clark 			seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
3637198e6b0SRob Clark 		}
3647198e6b0SRob Clark 	}
3657198e6b0SRob Clark }
3667198e6b0SRob Clark #endif
3677198e6b0SRob Clark 
3687198e6b0SRob Clark static const struct adreno_gpu_funcs funcs = {
3697198e6b0SRob Clark 	.base = {
3707198e6b0SRob Clark 		.get_param = adreno_get_param,
3717198e6b0SRob Clark 		.hw_init = a3xx_hw_init,
3727198e6b0SRob Clark 		.pm_suspend = msm_gpu_pm_suspend,
3737198e6b0SRob Clark 		.pm_resume = msm_gpu_pm_resume,
374bd6f82d8SRob Clark 		.recover = adreno_recover,
3757198e6b0SRob Clark 		.last_fence = adreno_last_fence,
3767198e6b0SRob Clark 		.submit = adreno_submit,
3777198e6b0SRob Clark 		.flush = adreno_flush,
3787198e6b0SRob Clark 		.idle = a3xx_idle,
3797198e6b0SRob Clark 		.irq = a3xx_irq,
3807198e6b0SRob Clark 		.destroy = a3xx_destroy,
3817198e6b0SRob Clark #ifdef CONFIG_DEBUG_FS
3827198e6b0SRob Clark 		.show = a3xx_show,
3837198e6b0SRob Clark #endif
3847198e6b0SRob Clark 	},
3857198e6b0SRob Clark };
3867198e6b0SRob Clark 
3877198e6b0SRob Clark struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
3887198e6b0SRob Clark {
3897198e6b0SRob Clark 	struct a3xx_gpu *a3xx_gpu = NULL;
3907198e6b0SRob Clark 	struct msm_gpu *gpu;
3917198e6b0SRob Clark 	struct platform_device *pdev = a3xx_pdev;
3927198e6b0SRob Clark 	struct adreno_platform_config *config;
3937198e6b0SRob Clark 	int ret;
3947198e6b0SRob Clark 
3957198e6b0SRob Clark 	if (!pdev) {
3967198e6b0SRob Clark 		dev_err(dev->dev, "no a3xx device\n");
3977198e6b0SRob Clark 		ret = -ENXIO;
3987198e6b0SRob Clark 		goto fail;
3997198e6b0SRob Clark 	}
4007198e6b0SRob Clark 
4017198e6b0SRob Clark 	config = pdev->dev.platform_data;
4027198e6b0SRob Clark 
4037198e6b0SRob Clark 	a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
4047198e6b0SRob Clark 	if (!a3xx_gpu) {
4057198e6b0SRob Clark 		ret = -ENOMEM;
4067198e6b0SRob Clark 		goto fail;
4077198e6b0SRob Clark 	}
4087198e6b0SRob Clark 
4097198e6b0SRob Clark 	gpu = &a3xx_gpu->base.base;
4107198e6b0SRob Clark 
4117198e6b0SRob Clark 	get_device(&pdev->dev);
4127198e6b0SRob Clark 	a3xx_gpu->pdev = pdev;
4137198e6b0SRob Clark 
4147198e6b0SRob Clark 	gpu->fast_rate = config->fast_rate;
4157198e6b0SRob Clark 	gpu->slow_rate = config->slow_rate;
4167198e6b0SRob Clark 	gpu->bus_freq  = config->bus_freq;
417bf2b33afSRob Clark #ifdef CONFIG_MSM_BUS_SCALING
418bf2b33afSRob Clark 	gpu->bus_scale_table = config->bus_scale_table;
419bf2b33afSRob Clark #endif
4207198e6b0SRob Clark 
4217198e6b0SRob Clark 	DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
4227198e6b0SRob Clark 			gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
4237198e6b0SRob Clark 
4247198e6b0SRob Clark 	ret = adreno_gpu_init(dev, pdev, &a3xx_gpu->base,
4257198e6b0SRob Clark 			&funcs, config->rev);
4267198e6b0SRob Clark 	if (ret)
4277198e6b0SRob Clark 		goto fail;
4287198e6b0SRob Clark 
429*871d812aSRob Clark 	if (!gpu->mmu) {
430*871d812aSRob Clark 		/* TODO we think it is possible to configure the GPU to
431*871d812aSRob Clark 		 * restrict access to VRAM carveout.  But the required
432*871d812aSRob Clark 		 * registers are unknown.  For now just bail out and
433*871d812aSRob Clark 		 * limp along with just modesetting.  If it turns out
434*871d812aSRob Clark 		 * to not be possible to restrict access, then we must
435*871d812aSRob Clark 		 * implement a cmdstream validator.
436*871d812aSRob Clark 		 */
437*871d812aSRob Clark 		dev_err(dev->dev, "No memory protection without IOMMU\n");
438*871d812aSRob Clark 		ret = -ENXIO;
439*871d812aSRob Clark 		goto fail;
440*871d812aSRob Clark 	}
441*871d812aSRob Clark 
442*871d812aSRob Clark 	return gpu;
4437198e6b0SRob Clark 
4447198e6b0SRob Clark fail:
4457198e6b0SRob Clark 	if (a3xx_gpu)
4467198e6b0SRob Clark 		a3xx_destroy(&a3xx_gpu->base.base);
4477198e6b0SRob Clark 
4487198e6b0SRob Clark 	return ERR_PTR(ret);
4497198e6b0SRob Clark }
4507198e6b0SRob Clark 
4517198e6b0SRob Clark /*
4527198e6b0SRob Clark  * The a3xx device:
4537198e6b0SRob Clark  */
4547198e6b0SRob Clark 
455bf2b33afSRob Clark #if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
456bf2b33afSRob Clark #  include <mach/kgsl.h>
457bf2b33afSRob Clark #endif
458bf2b33afSRob Clark 
4597198e6b0SRob Clark static int a3xx_probe(struct platform_device *pdev)
4607198e6b0SRob Clark {
4617198e6b0SRob Clark 	static struct adreno_platform_config config = {};
4627198e6b0SRob Clark #ifdef CONFIG_OF
4637198e6b0SRob Clark 	/* TODO */
4647198e6b0SRob Clark #else
465bf2b33afSRob Clark 	struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
4667198e6b0SRob Clark 	uint32_t version = socinfo_get_version();
4677198e6b0SRob Clark 	if (cpu_is_apq8064ab()) {
4687198e6b0SRob Clark 		config.fast_rate = 450000000;
4697198e6b0SRob Clark 		config.slow_rate = 27000000;
4707198e6b0SRob Clark 		config.bus_freq  = 4;
4717198e6b0SRob Clark 		config.rev = ADRENO_REV(3, 2, 1, 0);
4727198e6b0SRob Clark 	} else if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
4737198e6b0SRob Clark 		config.fast_rate = 400000000;
4747198e6b0SRob Clark 		config.slow_rate = 27000000;
4757198e6b0SRob Clark 		config.bus_freq  = 4;
4767198e6b0SRob Clark 
4777198e6b0SRob Clark 		if (SOCINFO_VERSION_MAJOR(version) == 2)
4787198e6b0SRob Clark 			config.rev = ADRENO_REV(3, 2, 0, 2);
4797198e6b0SRob Clark 		else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
4807198e6b0SRob Clark 				(SOCINFO_VERSION_MINOR(version) == 1))
4817198e6b0SRob Clark 			config.rev = ADRENO_REV(3, 2, 0, 1);
4827198e6b0SRob Clark 		else
4837198e6b0SRob Clark 			config.rev = ADRENO_REV(3, 2, 0, 0);
4847198e6b0SRob Clark 
4857198e6b0SRob Clark 	} else if (cpu_is_msm8930()) {
4867198e6b0SRob Clark 		config.fast_rate = 400000000;
4877198e6b0SRob Clark 		config.slow_rate = 27000000;
4887198e6b0SRob Clark 		config.bus_freq  = 3;
4897198e6b0SRob Clark 
4907198e6b0SRob Clark 		if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
4917198e6b0SRob Clark 			(SOCINFO_VERSION_MINOR(version) == 2))
4927198e6b0SRob Clark 			config.rev = ADRENO_REV(3, 0, 5, 2);
4937198e6b0SRob Clark 		else
4947198e6b0SRob Clark 			config.rev = ADRENO_REV(3, 0, 5, 0);
4957198e6b0SRob Clark 
4967198e6b0SRob Clark 	}
497bf2b33afSRob Clark #  ifdef CONFIG_MSM_BUS_SCALING
498bf2b33afSRob Clark 	config.bus_scale_table = pdata->bus_scale_table;
499bf2b33afSRob Clark #  endif
5007198e6b0SRob Clark #endif
5017198e6b0SRob Clark 	pdev->dev.platform_data = &config;
5027198e6b0SRob Clark 	a3xx_pdev = pdev;
5037198e6b0SRob Clark 	return 0;
5047198e6b0SRob Clark }
5057198e6b0SRob Clark 
5067198e6b0SRob Clark static int a3xx_remove(struct platform_device *pdev)
5077198e6b0SRob Clark {
5087198e6b0SRob Clark 	a3xx_pdev = NULL;
5097198e6b0SRob Clark 	return 0;
5107198e6b0SRob Clark }
5117198e6b0SRob Clark 
5127198e6b0SRob Clark static struct platform_driver a3xx_driver = {
5137198e6b0SRob Clark 	.probe = a3xx_probe,
5147198e6b0SRob Clark 	.remove = a3xx_remove,
5157198e6b0SRob Clark 	.driver.name = "kgsl-3d0",
5167198e6b0SRob Clark };
5177198e6b0SRob Clark 
5187198e6b0SRob Clark void __init a3xx_register(void)
5197198e6b0SRob Clark {
5207198e6b0SRob Clark 	platform_driver_register(&a3xx_driver);
5217198e6b0SRob Clark }
5227198e6b0SRob Clark 
5237198e6b0SRob Clark void __exit a3xx_unregister(void)
5247198e6b0SRob Clark {
5257198e6b0SRob Clark 	platform_driver_unregister(&a3xx_driver);
5267198e6b0SRob Clark }
527