brintos

brintos / linux-shallow public Read only

0
0
Text · 20.4 KiB · b46ff49 Raw
631 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Red Hat4 * Author: Rob Clark <robdclark@gmail.com>5 *6 * Copyright (c) 2014 The Linux Foundation. All rights reserved.7 */8 9#include "a3xx_gpu.h"10 11#define A3XX_INT0_MASK \12	(A3XX_INT0_RBBM_AHB_ERROR |        \13	 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \14	 A3XX_INT0_CP_T0_PACKET_IN_IB |    \15	 A3XX_INT0_CP_OPCODE_ERROR |       \16	 A3XX_INT0_CP_RESERVED_BIT_ERROR | \17	 A3XX_INT0_CP_HW_FAULT |           \18	 A3XX_INT0_CP_IB1_INT |            \19	 A3XX_INT0_CP_IB2_INT |            \20	 A3XX_INT0_CP_RB_INT |             \21	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \22	 A3XX_INT0_CP_AHB_ERROR_HALT |     \23	 A3XX_INT0_CACHE_FLUSH_TS |        \24	 A3XX_INT0_UCHE_OOB_ACCESS)25 26extern bool hang_debug;27 28static void a3xx_dump(struct msm_gpu *gpu);29static bool a3xx_idle(struct msm_gpu *gpu);30 31static void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)32{33	struct msm_ringbuffer *ring = submit->ring;34	unsigned int i;35 36	for (i = 0; i < submit->nr_cmds; i++) {37		switch (submit->cmd[i].type) {38		case MSM_SUBMIT_CMD_IB_TARGET_BUF:39			/* ignore IB-targets */40			break;41		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:42			/* ignore if there has not been a ctx switch: */43			if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno)44				break;45			fallthrough;46		case MSM_SUBMIT_CMD_BUF:47			OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2);48			OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));49			OUT_RING(ring, submit->cmd[i].size);50			OUT_PKT2(ring);51			break;52		}53	}54 55	OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);56	OUT_RING(ring, submit->seqno);57 58	/* Flush HLSQ lazy updates to make sure there is nothing59	 * pending for indirect loads after the timestamp has60	 * passed:61	 */62	OUT_PKT3(ring, CP_EVENT_WRITE, 1);63	OUT_RING(ring, HLSQ_FLUSH);64 65	/* wait for idle before cache flush/interrupt */66	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);67	OUT_RING(ring, 0x00000000);68 69	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */70	OUT_PKT3(ring, CP_EVENT_WRITE, 3);71	OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ);72	OUT_RING(ring, rbmemptr(ring, fence));73	OUT_RING(ring, submit->seqno);74 75#if 076	/* Dummy set-constant to trigger context rollover */77	OUT_PKT3(ring, CP_SET_CONSTANT, 2);78	OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG));79	OUT_RING(ring, 0x00000000);80#endif81 82	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);83}84 85static bool a3xx_me_init(struct msm_gpu *gpu)86{87	struct msm_ringbuffer *ring = gpu->rb[0];88 89	OUT_PKT3(ring, CP_ME_INIT, 17);90	OUT_RING(ring, 0x000003f7);91	OUT_RING(ring, 0x00000000);92	OUT_RING(ring, 0x00000000);93	OUT_RING(ring, 0x00000000);94	OUT_RING(ring, 0x00000080);95	OUT_RING(ring, 0x00000100);96	OUT_RING(ring, 0x00000180);97	OUT_RING(ring, 0x00006600);98	OUT_RING(ring, 0x00000150);99	OUT_RING(ring, 0x0000014e);100	OUT_RING(ring, 0x00000154);101	OUT_RING(ring, 0x00000001);102	OUT_RING(ring, 0x00000000);103	OUT_RING(ring, 0x00000000);104	OUT_RING(ring, 0x00000000);105	OUT_RING(ring, 0x00000000);106	OUT_RING(ring, 0x00000000);107 108	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);109	return a3xx_idle(gpu);110}111 112static int a3xx_hw_init(struct msm_gpu *gpu)113{114	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);115	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);116	uint32_t *ptr, len;117	int i, ret;118 119	DBG("%s", gpu->name);120 121	if (adreno_is_a305(adreno_gpu)) {122		/* Set up 16 deep read/write request queues: */123		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);124		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);125		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);126		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);127		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);128		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);129		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);130		/* Enable WR-REQ: */131		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);132		/* Set up round robin arbitration between both AXI ports: */133		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);134		/* Set up AOOO: */135		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);136		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);137	} else if (adreno_is_a305b(adreno_gpu)) {138		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x00181818);139		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x00181818);140		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000018);141		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000018);142		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303);143		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);144	} else if (adreno_is_a306(adreno_gpu)) {145		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);146		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x0000000a);147		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x0000000a);148	} else if (adreno_is_a306a(adreno_gpu)) {149		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);150		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000010);151		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000010);152	} else if (adreno_is_a320(adreno_gpu)) {153		/* Set up 16 deep read/write request queues: */154		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);155		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);156		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);157		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);158		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);159		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);160		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);161		/* Enable WR-REQ: */162		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);163		/* Set up round robin arbitration between both AXI ports: */164		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);165		/* Set up AOOO: */166		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);167		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);168		/* Enable 1K sort: */169		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);170		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);171 172	} else if (adreno_is_a330v2(adreno_gpu)) {173		/*174		 * Most of the VBIF registers on 8974v2 have the correct175		 * values at power on, so we won't modify those if we don't176		 * need to177		 */178		/* Enable 1k sort: */179		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);180		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);181		/* Enable WR-REQ: */182		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);183		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);184		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */185		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);186 187	} else if (adreno_is_a330(adreno_gpu)) {188		/* Set up 16 deep read/write request queues: */189		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);190		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);191		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);192		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);193		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);194		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);195		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);196		/* Enable WR-REQ: */197		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);198		/* Set up round robin arbitration between both AXI ports: */199		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);200		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */201		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);202		/* Set up AOOO: */203		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f);204		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f);205		/* Enable 1K sort: */206		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);207		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);208		/* Disable VBIF clock gating. This is to enable AXI running209		 * higher frequency than GPU:210		 */211		gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001);212 213	} else {214		BUG();215	}216 217	/* Make all blocks contribute to the GPU BUSY perf counter: */218	gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);219 220	/* Tune the hystersis counters for SP and CP idle detection: */221	gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10);222	gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);223 224	/* Enable the RBBM error reporting bits.  This lets us get225	 * useful information on failure:226	 */227	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001);228 229	/* Enable AHB error reporting: */230	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff);231 232	/* Turn on the power counters: */233	gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000);234 235	/* Turn on hang detection - this spews a lot of useful information236	 * into the RBBM registers on a hang:237	 */238	gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff);239 240	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */241	gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);242 243	/* Enable Clock gating: */244	if (adreno_is_a305b(adreno_gpu) ||245	    adreno_is_a306(adreno_gpu) ||246	    adreno_is_a306a(adreno_gpu))247		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);248	else if (adreno_is_a320(adreno_gpu))249		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);250	else if (adreno_is_a330v2(adreno_gpu))251		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);252	else if (adreno_is_a330(adreno_gpu))253		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff);254 255	if (adreno_is_a330v2(adreno_gpu))256		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455);257	else if (adreno_is_a330(adreno_gpu))258		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000);259 260	/* Set the OCMEM base address for A330, etc */261	if (a3xx_gpu->ocmem.hdl) {262		gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,263			(unsigned int)(a3xx_gpu->ocmem.base >> 14));264	}265 266	/* Turn on performance counters: */267	gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);268 269	/* Enable the perfcntrs that we use.. */270	for (i = 0; i < gpu->num_perfcntrs; i++) {271		const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];272		gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);273	}274 275	gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);276 277	ret = adreno_hw_init(gpu);278	if (ret)279		return ret;280 281	/*282	 * Use the default ringbuffer size and block size but disable the RPTR283	 * shadow284	 */285	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,286		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);287 288	/* Set the ringbuffer address */289	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));290 291	/* setup access protection: */292	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);293 294	/* RBBM registers */295	gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040);296	gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080);297	gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc);298	gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108);299	gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140);300	gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400);301 302	/* CP registers */303	gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700);304	gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8);305	gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0);306	gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178);307	gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180);308 309	/* RB registers */310	gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300);311 312	/* VBIF registers */313	gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000);314 315	/* NOTE: PM4/micro-engine firmware registers look to be the same316	 * for a2xx and a3xx.. we could possibly push that part down to317	 * adreno_gpu base class.  Or push both PM4 and PFP but318	 * parameterize the pfp ucode addr/data registers..319	 */320 321	/* Load PM4: */322	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);323	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;324	DBG("loading PM4 ucode version: %x", ptr[1]);325 326	gpu_write(gpu, REG_AXXX_CP_DEBUG,327			AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |328			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);329	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);330	for (i = 1; i < len; i++)331		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);332 333	/* Load PFP: */334	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);335	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;336	DBG("loading PFP ucode version: %x", ptr[5]);337 338	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);339	for (i = 1; i < len; i++)340		gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);341 342	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */343	if (adreno_is_a305(adreno_gpu) ||344	    adreno_is_a306(adreno_gpu) ||345	    adreno_is_a306a(adreno_gpu) ||346	    adreno_is_a320(adreno_gpu)) {347		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,348				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |349				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |350				AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));351	} else if (adreno_is_a330(adreno_gpu) || adreno_is_a305b(adreno_gpu)) {352		/* NOTE: this (value take from downstream android driver)353		 * includes some bits outside of the known bitfields.  But354		 * A330 has this "MERCIU queue" thing too, which might355		 * explain a new bitfield or reshuffling:356		 */357		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008);358	}359 360	/* clear ME_HALT to start micro engine */361	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);362 363	return a3xx_me_init(gpu) ? 0 : -EINVAL;364}365 366static void a3xx_recover(struct msm_gpu *gpu)367{368	int i;369 370	adreno_dump_info(gpu);371 372	for (i = 0; i < 8; i++) {373		printk("CP_SCRATCH_REG%d: %u\n", i,374			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));375	}376 377	/* dump registers before resetting gpu, if enabled: */378	if (hang_debug)379		a3xx_dump(gpu);380 381	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);382	gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);383	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);384	adreno_recover(gpu);385}386 387static void a3xx_destroy(struct msm_gpu *gpu)388{389	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);390	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);391 392	DBG("%s", gpu->name);393 394	adreno_gpu_cleanup(adreno_gpu);395 396	adreno_gpu_ocmem_cleanup(&a3xx_gpu->ocmem);397 398	kfree(a3xx_gpu);399}400 401static bool a3xx_idle(struct msm_gpu *gpu)402{403	/* wait for ringbuffer to drain: */404	if (!adreno_idle(gpu, gpu->rb[0]))405		return false;406 407	/* then wait for GPU to finish: */408	if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &409			A3XX_RBBM_STATUS_GPU_BUSY))) {410		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);411 412		/* TODO maybe we need to reset GPU here to recover from hang? */413		return false;414	}415 416	return true;417}418 419static irqreturn_t a3xx_irq(struct msm_gpu *gpu)420{421	uint32_t status;422 423	status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS);424	DBG("%s: %08x", gpu->name, status);425 426	// TODO427 428	gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status);429 430	msm_gpu_retire(gpu);431 432	return IRQ_HANDLED;433}434 435static const unsigned int a3xx_registers[] = {436	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,437	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,438	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,439	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,440	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,441	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,442	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,443	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,444	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,445	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,446	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,447	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,448	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,449	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,450	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,451	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,452	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,453	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,454	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,455	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,456	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,457	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,458	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,459	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444,460	0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470,461	0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3,462	0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e,463	0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea,464	0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617,465	0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0,466	0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9,467	0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,468	0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d,469	0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f,470	~0   /* sentinel */471};472 473/* would be nice to not have to duplicate the _show() stuff with printk(): */474static void a3xx_dump(struct msm_gpu *gpu)475{476	printk("status:   %08x\n",477			gpu_read(gpu, REG_A3XX_RBBM_STATUS));478	adreno_dump(gpu);479}480 481static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu)482{483	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);484 485	if (!state)486		return ERR_PTR(-ENOMEM);487 488	adreno_gpu_state_get(gpu, state);489 490	state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);491 492	return state;493}494 495static u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)496{497	u64 busy_cycles;498 499	busy_cycles = gpu_read64(gpu, REG_A3XX_RBBM_PERFCTR_RBBM_1_LO);500	*out_sample_rate = clk_get_rate(gpu->core_clk);501 502	return busy_cycles;503}504 505static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)506{507	ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);508	return ring->memptrs->rptr;509}510 511static const struct adreno_gpu_funcs funcs = {512	.base = {513		.get_param = adreno_get_param,514		.set_param = adreno_set_param,515		.hw_init = a3xx_hw_init,516		.pm_suspend = msm_gpu_pm_suspend,517		.pm_resume = msm_gpu_pm_resume,518		.recover = a3xx_recover,519		.submit = a3xx_submit,520		.active_ring = adreno_active_ring,521		.irq = a3xx_irq,522		.destroy = a3xx_destroy,523#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)524		.show = adreno_show,525#endif526		.gpu_busy = a3xx_gpu_busy,527		.gpu_state_get = a3xx_gpu_state_get,528		.gpu_state_put = adreno_gpu_state_put,529		.create_address_space = adreno_create_address_space,530		.get_rptr = a3xx_get_rptr,531	},532};533 534static const struct msm_gpu_perfcntr perfcntrs[] = {535	{ REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,536			SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },537	{ REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,538			SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },539};540 541struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)542{543	struct a3xx_gpu *a3xx_gpu = NULL;544	struct adreno_gpu *adreno_gpu;545	struct msm_gpu *gpu;546	struct msm_drm_private *priv = dev->dev_private;547	struct platform_device *pdev = priv->gpu_pdev;548	struct icc_path *ocmem_icc_path;549	struct icc_path *icc_path;550	int ret;551 552	if (!pdev) {553		DRM_DEV_ERROR(dev->dev, "no a3xx device\n");554		ret = -ENXIO;555		goto fail;556	}557 558	a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);559	if (!a3xx_gpu) {560		ret = -ENOMEM;561		goto fail;562	}563 564	adreno_gpu = &a3xx_gpu->base;565	gpu = &adreno_gpu->base;566 567	gpu->perfcntrs = perfcntrs;568	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);569 570	adreno_gpu->registers = a3xx_registers;571 572	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);573	if (ret)574		goto fail;575 576	/* if needed, allocate gmem: */577	if (adreno_is_a330(adreno_gpu) || adreno_is_a305b(adreno_gpu)) {578		ret = adreno_gpu_ocmem_init(&adreno_gpu->base.pdev->dev,579					    adreno_gpu, &a3xx_gpu->ocmem);580		if (ret)581			goto fail;582	}583 584	if (!gpu->aspace) {585		/* TODO we think it is possible to configure the GPU to586		 * restrict access to VRAM carveout.  But the required587		 * registers are unknown.  For now just bail out and588		 * limp along with just modesetting.  If it turns out589		 * to not be possible to restrict access, then we must590		 * implement a cmdstream validator.591		 */592		DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");593		if (!allow_vram_carveout) {594			ret = -ENXIO;595			goto fail;596		}597	}598 599	icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem");600	if (IS_ERR(icc_path)) {601		ret = PTR_ERR(icc_path);602		goto fail;603	}604 605	ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem");606	if (IS_ERR(ocmem_icc_path)) {607		ret = PTR_ERR(ocmem_icc_path);608		/* allow -ENODATA, ocmem icc is optional */609		if (ret != -ENODATA)610			goto fail;611		ocmem_icc_path = NULL;612	}613 614 615	/*616	 * Set the ICC path to maximum speed for now by multiplying the fastest617	 * frequency by the bus width (8). We'll want to scale this later on to618	 * improve battery life.619	 */620	icc_set_bw(icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);621	icc_set_bw(ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);622 623	return gpu;624 625fail:626	if (a3xx_gpu)627		a3xx_destroy(&a3xx_gpu->base.base);628 629	return ERR_PTR(ret);630}631