162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2013 Red Hat
462306a36Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2014 The Linux Foundation. All rights reserved.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "a3xx_gpu.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define A3XX_INT0_MASK \
1262306a36Sopenharmony_ci	(A3XX_INT0_RBBM_AHB_ERROR |        \
1362306a36Sopenharmony_ci	 A3XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
1462306a36Sopenharmony_ci	 A3XX_INT0_CP_T0_PACKET_IN_IB |    \
1562306a36Sopenharmony_ci	 A3XX_INT0_CP_OPCODE_ERROR |       \
1662306a36Sopenharmony_ci	 A3XX_INT0_CP_RESERVED_BIT_ERROR | \
1762306a36Sopenharmony_ci	 A3XX_INT0_CP_HW_FAULT |           \
1862306a36Sopenharmony_ci	 A3XX_INT0_CP_IB1_INT |            \
1962306a36Sopenharmony_ci	 A3XX_INT0_CP_IB2_INT |            \
2062306a36Sopenharmony_ci	 A3XX_INT0_CP_RB_INT |             \
2162306a36Sopenharmony_ci	 A3XX_INT0_CP_REG_PROTECT_FAULT |  \
2262306a36Sopenharmony_ci	 A3XX_INT0_CP_AHB_ERROR_HALT |     \
2362306a36Sopenharmony_ci	 A3XX_INT0_CACHE_FLUSH_TS |        \
2462306a36Sopenharmony_ci	 A3XX_INT0_UCHE_OOB_ACCESS)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciextern bool hang_debug;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void a3xx_dump(struct msm_gpu *gpu);
2962306a36Sopenharmony_cistatic bool a3xx_idle(struct msm_gpu *gpu);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct msm_ringbuffer *ring = submit->ring;
3462306a36Sopenharmony_ci	unsigned int i;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	for (i = 0; i < submit->nr_cmds; i++) {
3762306a36Sopenharmony_ci		switch (submit->cmd[i].type) {
3862306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
3962306a36Sopenharmony_ci			/* ignore IB-targets */
4062306a36Sopenharmony_ci			break;
4162306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
4262306a36Sopenharmony_ci			/* ignore if there has not been a ctx switch: */
4362306a36Sopenharmony_ci			if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno)
4462306a36Sopenharmony_ci				break;
4562306a36Sopenharmony_ci			fallthrough;
4662306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_BUF:
4762306a36Sopenharmony_ci			OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2);
4862306a36Sopenharmony_ci			OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
4962306a36Sopenharmony_ci			OUT_RING(ring, submit->cmd[i].size);
5062306a36Sopenharmony_ci			OUT_PKT2(ring);
5162306a36Sopenharmony_ci			break;
5262306a36Sopenharmony_ci		}
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);
5662306a36Sopenharmony_ci	OUT_RING(ring, submit->seqno);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Flush HLSQ lazy updates to make sure there is nothing
5962306a36Sopenharmony_ci	 * pending for indirect loads after the timestamp has
6062306a36Sopenharmony_ci	 * passed:
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	OUT_PKT3(ring, CP_EVENT_WRITE, 1);
6362306a36Sopenharmony_ci	OUT_RING(ring, HLSQ_FLUSH);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/* wait for idle before cache flush/interrupt */
6662306a36Sopenharmony_ci	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
6762306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
7062306a36Sopenharmony_ci	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
7162306a36Sopenharmony_ci	OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ);
7262306a36Sopenharmony_ci	OUT_RING(ring, rbmemptr(ring, fence));
7362306a36Sopenharmony_ci	OUT_RING(ring, submit->seqno);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#if 0
7662306a36Sopenharmony_ci	/* Dummy set-constant to trigger context rollover */
7762306a36Sopenharmony_ci	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
7862306a36Sopenharmony_ci	OUT_RING(ring, CP_REG(REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG));
7962306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
8062306a36Sopenharmony_ci#endif
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic bool a3xx_me_init(struct msm_gpu *gpu)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct msm_ringbuffer *ring = gpu->rb[0];
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	OUT_PKT3(ring, CP_ME_INIT, 17);
9062306a36Sopenharmony_ci	OUT_RING(ring, 0x000003f7);
9162306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
9262306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
9362306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
9462306a36Sopenharmony_ci	OUT_RING(ring, 0x00000080);
9562306a36Sopenharmony_ci	OUT_RING(ring, 0x00000100);
9662306a36Sopenharmony_ci	OUT_RING(ring, 0x00000180);
9762306a36Sopenharmony_ci	OUT_RING(ring, 0x00006600);
9862306a36Sopenharmony_ci	OUT_RING(ring, 0x00000150);
9962306a36Sopenharmony_ci	OUT_RING(ring, 0x0000014e);
10062306a36Sopenharmony_ci	OUT_RING(ring, 0x00000154);
10162306a36Sopenharmony_ci	OUT_RING(ring, 0x00000001);
10262306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
10362306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
10462306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
10562306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
10662306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
10962306a36Sopenharmony_ci	return a3xx_idle(gpu);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int a3xx_hw_init(struct msm_gpu *gpu)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
11562306a36Sopenharmony_ci	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
11662306a36Sopenharmony_ci	uint32_t *ptr, len;
11762306a36Sopenharmony_ci	int i, ret;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	DBG("%s", gpu->name);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (adreno_is_a305(adreno_gpu)) {
12262306a36Sopenharmony_ci		/* Set up 16 deep read/write request queues: */
12362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
12462306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
12562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
12662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
12762306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
12862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
12962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
13062306a36Sopenharmony_ci		/* Enable WR-REQ: */
13162306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
13262306a36Sopenharmony_ci		/* Set up round robin arbitration between both AXI ports: */
13362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
13462306a36Sopenharmony_ci		/* Set up AOOO: */
13562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
13662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
13762306a36Sopenharmony_ci	} else if (adreno_is_a306(adreno_gpu)) {
13862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
13962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x0000000a);
14062306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x0000000a);
14162306a36Sopenharmony_ci	} else if (adreno_is_a320(adreno_gpu)) {
14262306a36Sopenharmony_ci		/* Set up 16 deep read/write request queues: */
14362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
14462306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
14562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
14662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
14762306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
14862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
14962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
15062306a36Sopenharmony_ci		/* Enable WR-REQ: */
15162306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff);
15262306a36Sopenharmony_ci		/* Set up round robin arbitration between both AXI ports: */
15362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
15462306a36Sopenharmony_ci		/* Set up AOOO: */
15562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c);
15662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c);
15762306a36Sopenharmony_ci		/* Enable 1K sort: */
15862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);
15962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	} else if (adreno_is_a330v2(adreno_gpu)) {
16262306a36Sopenharmony_ci		/*
16362306a36Sopenharmony_ci		 * Most of the VBIF registers on 8974v2 have the correct
16462306a36Sopenharmony_ci		 * values at power on, so we won't modify those if we don't
16562306a36Sopenharmony_ci		 * need to
16662306a36Sopenharmony_ci		 */
16762306a36Sopenharmony_ci		/* Enable 1k sort: */
16862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
16962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
17062306a36Sopenharmony_ci		/* Enable WR-REQ: */
17162306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
17262306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
17362306a36Sopenharmony_ci		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
17462306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	} else if (adreno_is_a330(adreno_gpu)) {
17762306a36Sopenharmony_ci		/* Set up 16 deep read/write request queues: */
17862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
17962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
18062306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
18162306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
18262306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
18362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
18462306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
18562306a36Sopenharmony_ci		/* Enable WR-REQ: */
18662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
18762306a36Sopenharmony_ci		/* Set up round robin arbitration between both AXI ports: */
18862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030);
18962306a36Sopenharmony_ci		/* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
19062306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
19162306a36Sopenharmony_ci		/* Set up AOOO: */
19262306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f);
19362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f);
19462306a36Sopenharmony_ci		/* Enable 1K sort: */
19562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
19662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
19762306a36Sopenharmony_ci		/* Disable VBIF clock gating. This is to enable AXI running
19862306a36Sopenharmony_ci		 * higher frequency than GPU:
19962306a36Sopenharmony_ci		 */
20062306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	} else {
20362306a36Sopenharmony_ci		BUG();
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Make all blocks contribute to the GPU BUSY perf counter: */
20762306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* Tune the hystersis counters for SP and CP idle detection: */
21062306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10);
21162306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* Enable the RBBM error reporting bits.  This lets us get
21462306a36Sopenharmony_ci	 * useful information on failure:
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* Enable AHB error reporting: */
21962306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Turn on the power counters: */
22262306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Turn on hang detection - this spews a lot of useful information
22562306a36Sopenharmony_ci	 * into the RBBM registers on a hang:
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */
23062306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* Enable Clock gating: */
23362306a36Sopenharmony_ci	if (adreno_is_a306(adreno_gpu))
23462306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
23562306a36Sopenharmony_ci	else if (adreno_is_a320(adreno_gpu))
23662306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
23762306a36Sopenharmony_ci	else if (adreno_is_a330v2(adreno_gpu))
23862306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
23962306a36Sopenharmony_ci	else if (adreno_is_a330(adreno_gpu))
24062306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (adreno_is_a330v2(adreno_gpu))
24362306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455);
24462306a36Sopenharmony_ci	else if (adreno_is_a330(adreno_gpu))
24562306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* Set the OCMEM base address for A330, etc */
24862306a36Sopenharmony_ci	if (a3xx_gpu->ocmem.hdl) {
24962306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
25062306a36Sopenharmony_ci			(unsigned int)(a3xx_gpu->ocmem.base >> 14));
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Turn on performance counters: */
25462306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* Enable the perfcntrs that we use.. */
25762306a36Sopenharmony_ci	for (i = 0; i < gpu->num_perfcntrs; i++) {
25862306a36Sopenharmony_ci		const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
25962306a36Sopenharmony_ci		gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	ret = adreno_hw_init(gpu);
26562306a36Sopenharmony_ci	if (ret)
26662306a36Sopenharmony_ci		return ret;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/*
26962306a36Sopenharmony_ci	 * Use the default ringbuffer size and block size but disable the RPTR
27062306a36Sopenharmony_ci	 * shadow
27162306a36Sopenharmony_ci	 */
27262306a36Sopenharmony_ci	gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
27362306a36Sopenharmony_ci		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Set the ringbuffer address */
27662306a36Sopenharmony_ci	gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* setup access protection: */
27962306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT_CTRL, 0x00000007);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* RBBM registers */
28262306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(0), 0x63000040);
28362306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(1), 0x62000080);
28462306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(2), 0x600000cc);
28562306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(3), 0x60000108);
28662306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(4), 0x64000140);
28762306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(5), 0x66000400);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* CP registers */
29062306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(6), 0x65000700);
29162306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(7), 0x610007d8);
29262306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(8), 0x620007e0);
29362306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(9), 0x61001178);
29462306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(10), 0x64001180);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* RB registers */
29762306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(11), 0x60003300);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* VBIF registers */
30062306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PROTECT(12), 0x6b00c000);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* NOTE: PM4/micro-engine firmware registers look to be the same
30362306a36Sopenharmony_ci	 * for a2xx and a3xx.. we could possibly push that part down to
30462306a36Sopenharmony_ci	 * adreno_gpu base class.  Or push both PM4 and PFP but
30562306a36Sopenharmony_ci	 * parameterize the pfp ucode addr/data registers..
30662306a36Sopenharmony_ci	 */
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Load PM4: */
30962306a36Sopenharmony_ci	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
31062306a36Sopenharmony_ci	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
31162306a36Sopenharmony_ci	DBG("loading PM4 ucode version: %x", ptr[1]);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	gpu_write(gpu, REG_AXXX_CP_DEBUG,
31462306a36Sopenharmony_ci			AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |
31562306a36Sopenharmony_ci			AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
31662306a36Sopenharmony_ci	gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
31762306a36Sopenharmony_ci	for (i = 1; i < len; i++)
31862306a36Sopenharmony_ci		gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Load PFP: */
32162306a36Sopenharmony_ci	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
32262306a36Sopenharmony_ci	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
32362306a36Sopenharmony_ci	DBG("loading PFP ucode version: %x", ptr[5]);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
32662306a36Sopenharmony_ci	for (i = 1; i < len; i++)
32762306a36Sopenharmony_ci		gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
33062306a36Sopenharmony_ci	if (adreno_is_a305(adreno_gpu) || adreno_is_a306(adreno_gpu) ||
33162306a36Sopenharmony_ci			adreno_is_a320(adreno_gpu)) {
33262306a36Sopenharmony_ci		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,
33362306a36Sopenharmony_ci				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |
33462306a36Sopenharmony_ci				AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |
33562306a36Sopenharmony_ci				AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));
33662306a36Sopenharmony_ci	} else if (adreno_is_a330(adreno_gpu)) {
33762306a36Sopenharmony_ci		/* NOTE: this (value take from downstream android driver)
33862306a36Sopenharmony_ci		 * includes some bits outside of the known bitfields.  But
33962306a36Sopenharmony_ci		 * A330 has this "MERCIU queue" thing too, which might
34062306a36Sopenharmony_ci		 * explain a new bitfield or reshuffling:
34162306a36Sopenharmony_ci		 */
34262306a36Sopenharmony_ci		gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* clear ME_HALT to start micro engine */
34662306a36Sopenharmony_ci	gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return a3xx_me_init(gpu) ? 0 : -EINVAL;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void a3xx_recover(struct msm_gpu *gpu)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	int i;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	adreno_dump_info(gpu);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
35862306a36Sopenharmony_ci		printk("CP_SCRATCH_REG%d: %u\n", i,
35962306a36Sopenharmony_ci			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* dump registers before resetting gpu, if enabled: */
36362306a36Sopenharmony_ci	if (hang_debug)
36462306a36Sopenharmony_ci		a3xx_dump(gpu);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
36762306a36Sopenharmony_ci	gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
36862306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
36962306a36Sopenharmony_ci	adreno_recover(gpu);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void a3xx_destroy(struct msm_gpu *gpu)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
37562306a36Sopenharmony_ci	struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	DBG("%s", gpu->name);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	adreno_gpu_cleanup(adreno_gpu);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	adreno_gpu_ocmem_cleanup(&a3xx_gpu->ocmem);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	kfree(a3xx_gpu);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic bool a3xx_idle(struct msm_gpu *gpu)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	/* wait for ringbuffer to drain: */
38962306a36Sopenharmony_ci	if (!adreno_idle(gpu, gpu->rb[0]))
39062306a36Sopenharmony_ci		return false;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* then wait for GPU to finish: */
39362306a36Sopenharmony_ci	if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
39462306a36Sopenharmony_ci			A3XX_RBBM_STATUS_GPU_BUSY))) {
39562306a36Sopenharmony_ci		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		/* TODO maybe we need to reset GPU here to recover from hang? */
39862306a36Sopenharmony_ci		return false;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return true;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic irqreturn_t a3xx_irq(struct msm_gpu *gpu)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	uint32_t status;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	status = gpu_read(gpu, REG_A3XX_RBBM_INT_0_STATUS);
40962306a36Sopenharmony_ci	DBG("%s: %08x", gpu->name, status);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	// TODO
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	gpu_write(gpu, REG_A3XX_RBBM_INT_CLEAR_CMD, status);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	msm_gpu_retire(gpu);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return IRQ_HANDLED;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const unsigned int a3xx_registers[] = {
42162306a36Sopenharmony_ci	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
42262306a36Sopenharmony_ci	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
42362306a36Sopenharmony_ci	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,
42462306a36Sopenharmony_ci	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,
42562306a36Sopenharmony_ci	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,
42662306a36Sopenharmony_ci	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,
42762306a36Sopenharmony_ci	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,
42862306a36Sopenharmony_ci	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,
42962306a36Sopenharmony_ci	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
43062306a36Sopenharmony_ci	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
43162306a36Sopenharmony_ci	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
43262306a36Sopenharmony_ci	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
43362306a36Sopenharmony_ci	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
43462306a36Sopenharmony_ci	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
43562306a36Sopenharmony_ci	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
43662306a36Sopenharmony_ci	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
43762306a36Sopenharmony_ci	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,
43862306a36Sopenharmony_ci	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
43962306a36Sopenharmony_ci	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
44062306a36Sopenharmony_ci	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
44162306a36Sopenharmony_ci	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
44262306a36Sopenharmony_ci	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
44362306a36Sopenharmony_ci	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
44462306a36Sopenharmony_ci	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444,
44562306a36Sopenharmony_ci	0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470,
44662306a36Sopenharmony_ci	0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3,
44762306a36Sopenharmony_ci	0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e,
44862306a36Sopenharmony_ci	0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea,
44962306a36Sopenharmony_ci	0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617,
45062306a36Sopenharmony_ci	0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0,
45162306a36Sopenharmony_ci	0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9,
45262306a36Sopenharmony_ci	0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743,
45362306a36Sopenharmony_ci	0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d,
45462306a36Sopenharmony_ci	0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f,
45562306a36Sopenharmony_ci	~0   /* sentinel */
45662306a36Sopenharmony_ci};
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/* would be nice to not have to duplicate the _show() stuff with printk(): */
45962306a36Sopenharmony_cistatic void a3xx_dump(struct msm_gpu *gpu)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	printk("status:   %08x\n",
46262306a36Sopenharmony_ci			gpu_read(gpu, REG_A3XX_RBBM_STATUS));
46362306a36Sopenharmony_ci	adreno_dump(gpu);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (!state)
47162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	adreno_gpu_state_get(gpu, state);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return state;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	u64 busy_cycles;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	busy_cycles = gpu_read64(gpu, REG_A3XX_RBBM_PERFCTR_RBBM_1_LO);
48562306a36Sopenharmony_ci	*out_sample_rate = clk_get_rate(gpu->core_clk);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return busy_cycles;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
49362306a36Sopenharmony_ci	return ring->memptrs->rptr;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic const struct adreno_gpu_funcs funcs = {
49762306a36Sopenharmony_ci	.base = {
49862306a36Sopenharmony_ci		.get_param = adreno_get_param,
49962306a36Sopenharmony_ci		.set_param = adreno_set_param,
50062306a36Sopenharmony_ci		.hw_init = a3xx_hw_init,
50162306a36Sopenharmony_ci		.pm_suspend = msm_gpu_pm_suspend,
50262306a36Sopenharmony_ci		.pm_resume = msm_gpu_pm_resume,
50362306a36Sopenharmony_ci		.recover = a3xx_recover,
50462306a36Sopenharmony_ci		.submit = a3xx_submit,
50562306a36Sopenharmony_ci		.active_ring = adreno_active_ring,
50662306a36Sopenharmony_ci		.irq = a3xx_irq,
50762306a36Sopenharmony_ci		.destroy = a3xx_destroy,
50862306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
50962306a36Sopenharmony_ci		.show = adreno_show,
51062306a36Sopenharmony_ci#endif
51162306a36Sopenharmony_ci		.gpu_busy = a3xx_gpu_busy,
51262306a36Sopenharmony_ci		.gpu_state_get = a3xx_gpu_state_get,
51362306a36Sopenharmony_ci		.gpu_state_put = adreno_gpu_state_put,
51462306a36Sopenharmony_ci		.create_address_space = adreno_create_address_space,
51562306a36Sopenharmony_ci		.get_rptr = a3xx_get_rptr,
51662306a36Sopenharmony_ci	},
51762306a36Sopenharmony_ci};
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic const struct msm_gpu_perfcntr perfcntrs[] = {
52062306a36Sopenharmony_ci	{ REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
52162306a36Sopenharmony_ci			SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
52262306a36Sopenharmony_ci	{ REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
52362306a36Sopenharmony_ci			SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
52462306a36Sopenharmony_ci};
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistruct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct a3xx_gpu *a3xx_gpu = NULL;
52962306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu;
53062306a36Sopenharmony_ci	struct msm_gpu *gpu;
53162306a36Sopenharmony_ci	struct msm_drm_private *priv = dev->dev_private;
53262306a36Sopenharmony_ci	struct platform_device *pdev = priv->gpu_pdev;
53362306a36Sopenharmony_ci	struct icc_path *ocmem_icc_path;
53462306a36Sopenharmony_ci	struct icc_path *icc_path;
53562306a36Sopenharmony_ci	int ret;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!pdev) {
53862306a36Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "no a3xx device\n");
53962306a36Sopenharmony_ci		ret = -ENXIO;
54062306a36Sopenharmony_ci		goto fail;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
54462306a36Sopenharmony_ci	if (!a3xx_gpu) {
54562306a36Sopenharmony_ci		ret = -ENOMEM;
54662306a36Sopenharmony_ci		goto fail;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	adreno_gpu = &a3xx_gpu->base;
55062306a36Sopenharmony_ci	gpu = &adreno_gpu->base;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	gpu->perfcntrs = perfcntrs;
55362306a36Sopenharmony_ci	gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	adreno_gpu->registers = a3xx_registers;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
55862306a36Sopenharmony_ci	if (ret)
55962306a36Sopenharmony_ci		goto fail;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/* if needed, allocate gmem: */
56262306a36Sopenharmony_ci	if (adreno_is_a330(adreno_gpu)) {
56362306a36Sopenharmony_ci		ret = adreno_gpu_ocmem_init(&adreno_gpu->base.pdev->dev,
56462306a36Sopenharmony_ci					    adreno_gpu, &a3xx_gpu->ocmem);
56562306a36Sopenharmony_ci		if (ret)
56662306a36Sopenharmony_ci			goto fail;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (!gpu->aspace) {
57062306a36Sopenharmony_ci		/* TODO we think it is possible to configure the GPU to
57162306a36Sopenharmony_ci		 * restrict access to VRAM carveout.  But the required
57262306a36Sopenharmony_ci		 * registers are unknown.  For now just bail out and
57362306a36Sopenharmony_ci		 * limp along with just modesetting.  If it turns out
57462306a36Sopenharmony_ci		 * to not be possible to restrict access, then we must
57562306a36Sopenharmony_ci		 * implement a cmdstream validator.
57662306a36Sopenharmony_ci		 */
57762306a36Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");
57862306a36Sopenharmony_ci		if (!allow_vram_carveout) {
57962306a36Sopenharmony_ci			ret = -ENXIO;
58062306a36Sopenharmony_ci			goto fail;
58162306a36Sopenharmony_ci		}
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem");
58562306a36Sopenharmony_ci	if (IS_ERR(icc_path)) {
58662306a36Sopenharmony_ci		ret = PTR_ERR(icc_path);
58762306a36Sopenharmony_ci		goto fail;
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem");
59162306a36Sopenharmony_ci	if (IS_ERR(ocmem_icc_path)) {
59262306a36Sopenharmony_ci		ret = PTR_ERR(ocmem_icc_path);
59362306a36Sopenharmony_ci		/* allow -ENODATA, ocmem icc is optional */
59462306a36Sopenharmony_ci		if (ret != -ENODATA)
59562306a36Sopenharmony_ci			goto fail;
59662306a36Sopenharmony_ci		ocmem_icc_path = NULL;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * Set the ICC path to maximum speed for now by multiplying the fastest
60262306a36Sopenharmony_ci	 * frequency by the bus width (8). We'll want to scale this later on to
60362306a36Sopenharmony_ci	 * improve battery life.
60462306a36Sopenharmony_ci	 */
60562306a36Sopenharmony_ci	icc_set_bw(icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
60662306a36Sopenharmony_ci	icc_set_bw(ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return gpu;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cifail:
61162306a36Sopenharmony_ci	if (a3xx_gpu)
61262306a36Sopenharmony_ci		a3xx_destroy(&a3xx_gpu->base.base);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return ERR_PTR(ret);
61562306a36Sopenharmony_ci}
616