162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (c) 2014 The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci#include "a4xx_gpu.h"
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define A4XX_INT0_MASK \
762306a36Sopenharmony_ci	(A4XX_INT0_RBBM_AHB_ERROR |        \
862306a36Sopenharmony_ci	 A4XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
962306a36Sopenharmony_ci	 A4XX_INT0_CP_T0_PACKET_IN_IB |    \
1062306a36Sopenharmony_ci	 A4XX_INT0_CP_OPCODE_ERROR |       \
1162306a36Sopenharmony_ci	 A4XX_INT0_CP_RESERVED_BIT_ERROR | \
1262306a36Sopenharmony_ci	 A4XX_INT0_CP_HW_FAULT |           \
1362306a36Sopenharmony_ci	 A4XX_INT0_CP_IB1_INT |            \
1462306a36Sopenharmony_ci	 A4XX_INT0_CP_IB2_INT |            \
1562306a36Sopenharmony_ci	 A4XX_INT0_CP_RB_INT |             \
1662306a36Sopenharmony_ci	 A4XX_INT0_CP_REG_PROTECT_FAULT |  \
1762306a36Sopenharmony_ci	 A4XX_INT0_CP_AHB_ERROR_HALT |     \
1862306a36Sopenharmony_ci	 A4XX_INT0_CACHE_FLUSH_TS |        \
1962306a36Sopenharmony_ci	 A4XX_INT0_UCHE_OOB_ACCESS)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciextern bool hang_debug;
2262306a36Sopenharmony_cistatic void a4xx_dump(struct msm_gpu *gpu);
2362306a36Sopenharmony_cistatic bool a4xx_idle(struct msm_gpu *gpu);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic void a4xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct msm_ringbuffer *ring = submit->ring;
2862306a36Sopenharmony_ci	unsigned int i;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	for (i = 0; i < submit->nr_cmds; i++) {
3162306a36Sopenharmony_ci		switch (submit->cmd[i].type) {
3262306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_IB_TARGET_BUF:
3362306a36Sopenharmony_ci			/* ignore IB-targets */
3462306a36Sopenharmony_ci			break;
3562306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
3662306a36Sopenharmony_ci			/* ignore if there has not been a ctx switch: */
3762306a36Sopenharmony_ci			if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno)
3862306a36Sopenharmony_ci				break;
3962306a36Sopenharmony_ci			fallthrough;
4062306a36Sopenharmony_ci		case MSM_SUBMIT_CMD_BUF:
4162306a36Sopenharmony_ci			OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFE, 2);
4262306a36Sopenharmony_ci			OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
4362306a36Sopenharmony_ci			OUT_RING(ring, submit->cmd[i].size);
4462306a36Sopenharmony_ci			OUT_PKT2(ring);
4562306a36Sopenharmony_ci			break;
4662306a36Sopenharmony_ci		}
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);
5062306a36Sopenharmony_ci	OUT_RING(ring, submit->seqno);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* Flush HLSQ lazy updates to make sure there is nothing
5362306a36Sopenharmony_ci	 * pending for indirect loads after the timestamp has
5462306a36Sopenharmony_ci	 * passed:
5562306a36Sopenharmony_ci	 */
5662306a36Sopenharmony_ci	OUT_PKT3(ring, CP_EVENT_WRITE, 1);
5762306a36Sopenharmony_ci	OUT_RING(ring, HLSQ_FLUSH);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* wait for idle before cache flush/interrupt */
6062306a36Sopenharmony_ci	OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
6162306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* BIT(31) of CACHE_FLUSH_TS triggers CACHE_FLUSH_TS IRQ from GPU */
6462306a36Sopenharmony_ci	OUT_PKT3(ring, CP_EVENT_WRITE, 3);
6562306a36Sopenharmony_ci	OUT_RING(ring, CACHE_FLUSH_TS | CP_EVENT_WRITE_0_IRQ);
6662306a36Sopenharmony_ci	OUT_RING(ring, rbmemptr(ring, fence));
6762306a36Sopenharmony_ci	OUT_RING(ring, submit->seqno);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	adreno_flush(gpu, ring, REG_A4XX_CP_RB_WPTR);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/*
7362306a36Sopenharmony_ci * a4xx_enable_hwcg() - Program the clock control registers
7462306a36Sopenharmony_ci * @device: The adreno device pointer
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic void a4xx_enable_hwcg(struct msm_gpu *gpu)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
7962306a36Sopenharmony_ci	unsigned int i;
8062306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
8162306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TP(i), 0x02222202);
8262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
8362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_TP(i), 0x00002222);
8462306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
8562306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TP(i), 0x0E739CE7);
8662306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
8762306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TP(i), 0x00111111);
8862306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
8962306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_SP(i), 0x22222222);
9062306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
9162306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_SP(i), 0x00222222);
9262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
9362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_SP(i), 0x00000104);
9462306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
9562306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_SP(i), 0x00000081);
9662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_UCHE, 0x22222222);
9762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_UCHE, 0x02222222);
9862306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL3_UCHE, 0x00000000);
9962306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL4_UCHE, 0x00000000);
10062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_UCHE, 0x00004444);
10162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_UCHE, 0x00001112);
10262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
10362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_RB(i), 0x22222222);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Disable L1 clocking in A420 due to CCU issues with it */
10662306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
10762306a36Sopenharmony_ci		if (adreno_is_a420(adreno_gpu)) {
10862306a36Sopenharmony_ci			gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i),
10962306a36Sopenharmony_ci					0x00002020);
11062306a36Sopenharmony_ci		} else {
11162306a36Sopenharmony_ci			gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i),
11262306a36Sopenharmony_ci					0x00022020);
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* No CCU for A405 */
11762306a36Sopenharmony_ci	if (!adreno_is_a405(adreno_gpu)) {
11862306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
11962306a36Sopenharmony_ci			gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i),
12062306a36Sopenharmony_ci					0x00000922);
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
12462306a36Sopenharmony_ci			gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i),
12562306a36Sopenharmony_ci					0x00000000);
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
12962306a36Sopenharmony_ci			gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i),
13062306a36Sopenharmony_ci					0x00000001);
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_MODE_GPC, 0x02222222);
13562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_GPC, 0x04100104);
13662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_GPC, 0x00022222);
13762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_COM_DCOM, 0x00000022);
13862306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_COM_DCOM, 0x0000010F);
13962306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_COM_DCOM, 0x00000022);
14062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TSE_RAS_RBBM, 0x00222222);
14162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00004104);
14262306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00000222);
14362306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_HLSQ , 0x00000000);
14462306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_HLSQ, 0x00000000);
14562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, 0x00220000);
14662306a36Sopenharmony_ci	/* Early A430's have a timing issue with SP/TP power collapse;
14762306a36Sopenharmony_ci	   disabling HW clock gating prevents it. */
14862306a36Sopenharmony_ci	if (adreno_is_a430(adreno_gpu) && adreno_patchid(adreno_gpu) < 2)
14962306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL, 0);
15062306a36Sopenharmony_ci	else
15162306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL, 0xAAAAAAAA);
15262306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2, 0);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic bool a4xx_me_init(struct msm_gpu *gpu)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct msm_ringbuffer *ring = gpu->rb[0];
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	OUT_PKT3(ring, CP_ME_INIT, 17);
16162306a36Sopenharmony_ci	OUT_RING(ring, 0x000003f7);
16262306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
16362306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
16462306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
16562306a36Sopenharmony_ci	OUT_RING(ring, 0x00000080);
16662306a36Sopenharmony_ci	OUT_RING(ring, 0x00000100);
16762306a36Sopenharmony_ci	OUT_RING(ring, 0x00000180);
16862306a36Sopenharmony_ci	OUT_RING(ring, 0x00006600);
16962306a36Sopenharmony_ci	OUT_RING(ring, 0x00000150);
17062306a36Sopenharmony_ci	OUT_RING(ring, 0x0000014e);
17162306a36Sopenharmony_ci	OUT_RING(ring, 0x00000154);
17262306a36Sopenharmony_ci	OUT_RING(ring, 0x00000001);
17362306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
17462306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
17562306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
17662306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
17762306a36Sopenharmony_ci	OUT_RING(ring, 0x00000000);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	adreno_flush(gpu, ring, REG_A4XX_CP_RB_WPTR);
18062306a36Sopenharmony_ci	return a4xx_idle(gpu);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int a4xx_hw_init(struct msm_gpu *gpu)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
18662306a36Sopenharmony_ci	struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu);
18762306a36Sopenharmony_ci	uint32_t *ptr, len;
18862306a36Sopenharmony_ci	int i, ret;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (adreno_is_a405(adreno_gpu)) {
19162306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003);
19262306a36Sopenharmony_ci	} else if (adreno_is_a420(adreno_gpu)) {
19362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F);
19462306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
19562306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001);
19662306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
19762306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF1, 0x00000018);
19862306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
19962306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF1, 0x00000018);
20062306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003);
20162306a36Sopenharmony_ci	} else if (adreno_is_a430(adreno_gpu)) {
20262306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001);
20362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
20462306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF1, 0x00000018);
20562306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
20662306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF1, 0x00000018);
20762306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003);
20862306a36Sopenharmony_ci	} else {
20962306a36Sopenharmony_ci		BUG();
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* Make all blocks contribute to the GPU BUSY perf counter */
21362306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* Tune the hystersis counters for SP and CP idle detection */
21662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_SP_HYST_CNT, 0x10);
21762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (adreno_is_a430(adreno_gpu)) {
22062306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL2, 0x30);
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	 /* Enable the RBBM error reporting bits */
22462306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL0, 0x00000001);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* Enable AHB error reporting*/
22762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL1, 0xa6ffffff);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Enable power counters*/
23062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_RBBM_CTL, 0x00000030);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/*
23362306a36Sopenharmony_ci	 * Turn on hang detection - this spews a lot of useful information
23462306a36Sopenharmony_ci	 * into the RBBM registers on a hang:
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_INTERFACE_HANG_INT_CTL,
23762306a36Sopenharmony_ci			(1 << 30) | 0xFFFF);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RB_GMEM_BASE_ADDR,
24062306a36Sopenharmony_ci			(unsigned int)(a4xx_gpu->ocmem.base >> 14));
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* Turn on performance counters: */
24362306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_PERFCTR_CTL, 0x01);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* use the first CP counter for timestamp queries.. userspace may set
24662306a36Sopenharmony_ci	 * this as well but it selects the same counter/countable:
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PERFCTR_CP_SEL_0, CP_ALWAYS_COUNT);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (adreno_is_a430(adreno_gpu))
25162306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_UCHE_CACHE_WAYS_VFD, 0x07);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Disable L2 bypass to avoid UCHE out of bounds errors */
25462306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_LO, 0xffff0000);
25562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_HI, 0xffff0000);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_DEBUG, (1 << 25) |
25862306a36Sopenharmony_ci			(adreno_is_a420(adreno_gpu) ? (1 << 29) : 0));
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* On A430 enable SP regfile sleep for power savings */
26162306a36Sopenharmony_ci	/* TODO downstream does this for !420, so maybe applies for 405 too? */
26262306a36Sopenharmony_ci	if (!adreno_is_a420(adreno_gpu)) {
26362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_SP_REGFILE_SLEEP_CNTL_0,
26462306a36Sopenharmony_ci			0x00000441);
26562306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_SP_REGFILE_SLEEP_CNTL_1,
26662306a36Sopenharmony_ci			0x00000441);
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	a4xx_enable_hwcg(gpu);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/*
27262306a36Sopenharmony_ci	 * For A420 set RBBM_CLOCK_DELAY_HLSQ.CGC_HLSQ_TP_EARLY_CYC >= 2
27362306a36Sopenharmony_ci	 * due to timing issue with HLSQ_TP_CLK_EN
27462306a36Sopenharmony_ci	 */
27562306a36Sopenharmony_ci	if (adreno_is_a420(adreno_gpu)) {
27662306a36Sopenharmony_ci		unsigned int val;
27762306a36Sopenharmony_ci		val = gpu_read(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ);
27862306a36Sopenharmony_ci		val &= ~A4XX_CGC_HLSQ_EARLY_CYC__MASK;
27962306a36Sopenharmony_ci		val |= 2 << A4XX_CGC_HLSQ_EARLY_CYC__SHIFT;
28062306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, val);
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* setup access protection: */
28462306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT_CTRL, 0x00000007);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* RBBM registers */
28762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(0), 0x62000010);
28862306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(1), 0x63000020);
28962306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(2), 0x64000040);
29062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(3), 0x65000080);
29162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(4), 0x66000100);
29262306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(5), 0x64000200);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* CP registers */
29562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(6), 0x67000800);
29662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(7), 0x64001600);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* RB registers */
30062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(8), 0x60003300);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* HLSQ registers */
30362306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(9), 0x60003800);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* VPC registers */
30662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(10), 0x61003980);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* SMMU registers */
30962306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PROTECT(11), 0x6e010000);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_INT_0_MASK, A4XX_INT0_MASK);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ret = adreno_hw_init(gpu);
31462306a36Sopenharmony_ci	if (ret)
31562306a36Sopenharmony_ci		return ret;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/*
31862306a36Sopenharmony_ci	 * Use the default ringbuffer size and block size but disable the RPTR
31962306a36Sopenharmony_ci	 * shadow
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_RB_CNTL,
32262306a36Sopenharmony_ci		MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Set the ringbuffer address */
32562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* Load PM4: */
32862306a36Sopenharmony_ci	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
32962306a36Sopenharmony_ci	len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
33062306a36Sopenharmony_ci	DBG("loading PM4 ucode version: %u", ptr[0]);
33162306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0);
33262306a36Sopenharmony_ci	for (i = 1; i < len; i++)
33362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* Load PFP: */
33662306a36Sopenharmony_ci	ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
33762306a36Sopenharmony_ci	len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
33862306a36Sopenharmony_ci	DBG("loading PFP ucode version: %u", ptr[0]);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0);
34162306a36Sopenharmony_ci	for (i = 1; i < len; i++)
34262306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_DATA, ptr[i]);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* clear ME_HALT to start micro engine */
34562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return a4xx_me_init(gpu) ? 0 : -EINVAL;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void a4xx_recover(struct msm_gpu *gpu)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	int i;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	adreno_dump_info(gpu);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
35762306a36Sopenharmony_ci		printk("CP_SCRATCH_REG%d: %u\n", i,
35862306a36Sopenharmony_ci			gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* dump registers before resetting gpu, if enabled: */
36262306a36Sopenharmony_ci	if (hang_debug)
36362306a36Sopenharmony_ci		a4xx_dump(gpu);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 1);
36662306a36Sopenharmony_ci	gpu_read(gpu, REG_A4XX_RBBM_SW_RESET_CMD);
36762306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 0);
36862306a36Sopenharmony_ci	adreno_recover(gpu);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic void a4xx_destroy(struct msm_gpu *gpu)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
37462306a36Sopenharmony_ci	struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	DBG("%s", gpu->name);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	adreno_gpu_cleanup(adreno_gpu);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	adreno_gpu_ocmem_cleanup(&a4xx_gpu->ocmem);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	kfree(a4xx_gpu);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic bool a4xx_idle(struct msm_gpu *gpu)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	/* wait for ringbuffer to drain: */
38862306a36Sopenharmony_ci	if (!adreno_idle(gpu, gpu->rb[0]))
38962306a36Sopenharmony_ci		return false;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* then wait for GPU to finish: */
39262306a36Sopenharmony_ci	if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) &
39362306a36Sopenharmony_ci					A4XX_RBBM_STATUS_GPU_BUSY))) {
39462306a36Sopenharmony_ci		DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
39562306a36Sopenharmony_ci		/* TODO maybe we need to reset GPU here to recover from hang? */
39662306a36Sopenharmony_ci		return false;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return true;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic irqreturn_t a4xx_irq(struct msm_gpu *gpu)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	uint32_t status;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	status = gpu_read(gpu, REG_A4XX_RBBM_INT_0_STATUS);
40762306a36Sopenharmony_ci	DBG("%s: Int status %08x", gpu->name, status);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (status & A4XX_INT0_CP_REG_PROTECT_FAULT) {
41062306a36Sopenharmony_ci		uint32_t reg = gpu_read(gpu, REG_A4XX_CP_PROTECT_STATUS);
41162306a36Sopenharmony_ci		printk("CP | Protected mode error| %s | addr=%x\n",
41262306a36Sopenharmony_ci			reg & (1 << 24) ? "WRITE" : "READ",
41362306a36Sopenharmony_ci			(reg & 0xFFFFF) >> 2);
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	gpu_write(gpu, REG_A4XX_RBBM_INT_CLEAR_CMD, status);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	msm_gpu_retire(gpu);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return IRQ_HANDLED;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic const unsigned int a4xx_registers[] = {
42462306a36Sopenharmony_ci	/* RBBM */
42562306a36Sopenharmony_ci	0x0000, 0x0002, 0x0004, 0x0021, 0x0023, 0x0024, 0x0026, 0x0026,
42662306a36Sopenharmony_ci	0x0028, 0x002B, 0x002E, 0x0034, 0x0037, 0x0044, 0x0047, 0x0066,
42762306a36Sopenharmony_ci	0x0068, 0x0095, 0x009C, 0x0170, 0x0174, 0x01AF,
42862306a36Sopenharmony_ci	/* CP */
42962306a36Sopenharmony_ci	0x0200, 0x0233, 0x0240, 0x0250, 0x04C0, 0x04DD, 0x0500, 0x050B,
43062306a36Sopenharmony_ci	0x0578, 0x058F,
43162306a36Sopenharmony_ci	/* VSC */
43262306a36Sopenharmony_ci	0x0C00, 0x0C03, 0x0C08, 0x0C41, 0x0C50, 0x0C51,
43362306a36Sopenharmony_ci	/* GRAS */
43462306a36Sopenharmony_ci	0x0C80, 0x0C81, 0x0C88, 0x0C8F,
43562306a36Sopenharmony_ci	/* RB */
43662306a36Sopenharmony_ci	0x0CC0, 0x0CC0, 0x0CC4, 0x0CD2,
43762306a36Sopenharmony_ci	/* PC */
43862306a36Sopenharmony_ci	0x0D00, 0x0D0C, 0x0D10, 0x0D17, 0x0D20, 0x0D23,
43962306a36Sopenharmony_ci	/* VFD */
44062306a36Sopenharmony_ci	0x0E40, 0x0E4A,
44162306a36Sopenharmony_ci	/* VPC */
44262306a36Sopenharmony_ci	0x0E60, 0x0E61, 0x0E63, 0x0E68,
44362306a36Sopenharmony_ci	/* UCHE */
44462306a36Sopenharmony_ci	0x0E80, 0x0E84, 0x0E88, 0x0E95,
44562306a36Sopenharmony_ci	/* VMIDMT */
44662306a36Sopenharmony_ci	0x1000, 0x1000, 0x1002, 0x1002, 0x1004, 0x1004, 0x1008, 0x100A,
44762306a36Sopenharmony_ci	0x100C, 0x100D, 0x100F, 0x1010, 0x1012, 0x1016, 0x1024, 0x1024,
44862306a36Sopenharmony_ci	0x1027, 0x1027, 0x1100, 0x1100, 0x1102, 0x1102, 0x1104, 0x1104,
44962306a36Sopenharmony_ci	0x1110, 0x1110, 0x1112, 0x1116, 0x1124, 0x1124, 0x1300, 0x1300,
45062306a36Sopenharmony_ci	0x1380, 0x1380,
45162306a36Sopenharmony_ci	/* GRAS CTX 0 */
45262306a36Sopenharmony_ci	0x2000, 0x2004, 0x2008, 0x2067, 0x2070, 0x2078, 0x207B, 0x216E,
45362306a36Sopenharmony_ci	/* PC CTX 0 */
45462306a36Sopenharmony_ci	0x21C0, 0x21C6, 0x21D0, 0x21D0, 0x21D9, 0x21D9, 0x21E5, 0x21E7,
45562306a36Sopenharmony_ci	/* VFD CTX 0 */
45662306a36Sopenharmony_ci	0x2200, 0x2204, 0x2208, 0x22A9,
45762306a36Sopenharmony_ci	/* GRAS CTX 1 */
45862306a36Sopenharmony_ci	0x2400, 0x2404, 0x2408, 0x2467, 0x2470, 0x2478, 0x247B, 0x256E,
45962306a36Sopenharmony_ci	/* PC CTX 1 */
46062306a36Sopenharmony_ci	0x25C0, 0x25C6, 0x25D0, 0x25D0, 0x25D9, 0x25D9, 0x25E5, 0x25E7,
46162306a36Sopenharmony_ci	/* VFD CTX 1 */
46262306a36Sopenharmony_ci	0x2600, 0x2604, 0x2608, 0x26A9,
46362306a36Sopenharmony_ci	/* XPU */
46462306a36Sopenharmony_ci	0x2C00, 0x2C01, 0x2C10, 0x2C10, 0x2C12, 0x2C16, 0x2C1D, 0x2C20,
46562306a36Sopenharmony_ci	0x2C28, 0x2C28, 0x2C30, 0x2C30, 0x2C32, 0x2C36, 0x2C40, 0x2C40,
46662306a36Sopenharmony_ci	0x2C50, 0x2C50, 0x2C52, 0x2C56, 0x2C80, 0x2C80, 0x2C94, 0x2C95,
46762306a36Sopenharmony_ci	/* VBIF */
46862306a36Sopenharmony_ci	0x3000, 0x3007, 0x300C, 0x3014, 0x3018, 0x301D, 0x3020, 0x3022,
46962306a36Sopenharmony_ci	0x3024, 0x3026, 0x3028, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031,
47062306a36Sopenharmony_ci	0x3034, 0x3036, 0x3038, 0x3038, 0x303C, 0x303D, 0x3040, 0x3040,
47162306a36Sopenharmony_ci	0x3049, 0x3049, 0x3058, 0x3058, 0x305B, 0x3061, 0x3064, 0x3068,
47262306a36Sopenharmony_ci	0x306C, 0x306D, 0x3080, 0x3088, 0x308B, 0x308C, 0x3090, 0x3094,
47362306a36Sopenharmony_ci	0x3098, 0x3098, 0x309C, 0x309C, 0x30C0, 0x30C0, 0x30C8, 0x30C8,
47462306a36Sopenharmony_ci	0x30D0, 0x30D0, 0x30D8, 0x30D8, 0x30E0, 0x30E0, 0x3100, 0x3100,
47562306a36Sopenharmony_ci	0x3108, 0x3108, 0x3110, 0x3110, 0x3118, 0x3118, 0x3120, 0x3120,
47662306a36Sopenharmony_ci	0x3124, 0x3125, 0x3129, 0x3129, 0x3131, 0x3131, 0x330C, 0x330C,
47762306a36Sopenharmony_ci	0x3310, 0x3310, 0x3400, 0x3401, 0x3410, 0x3410, 0x3412, 0x3416,
47862306a36Sopenharmony_ci	0x341D, 0x3420, 0x3428, 0x3428, 0x3430, 0x3430, 0x3432, 0x3436,
47962306a36Sopenharmony_ci	0x3440, 0x3440, 0x3450, 0x3450, 0x3452, 0x3456, 0x3480, 0x3480,
48062306a36Sopenharmony_ci	0x3494, 0x3495, 0x4000, 0x4000, 0x4002, 0x4002, 0x4004, 0x4004,
48162306a36Sopenharmony_ci	0x4008, 0x400A, 0x400C, 0x400D, 0x400F, 0x4012, 0x4014, 0x4016,
48262306a36Sopenharmony_ci	0x401D, 0x401D, 0x4020, 0x4027, 0x4060, 0x4062, 0x4200, 0x4200,
48362306a36Sopenharmony_ci	0x4300, 0x4300, 0x4400, 0x4400, 0x4500, 0x4500, 0x4800, 0x4802,
48462306a36Sopenharmony_ci	0x480F, 0x480F, 0x4811, 0x4811, 0x4813, 0x4813, 0x4815, 0x4816,
48562306a36Sopenharmony_ci	0x482B, 0x482B, 0x4857, 0x4857, 0x4883, 0x4883, 0x48AF, 0x48AF,
48662306a36Sopenharmony_ci	0x48C5, 0x48C5, 0x48E5, 0x48E5, 0x4905, 0x4905, 0x4925, 0x4925,
48762306a36Sopenharmony_ci	0x4945, 0x4945, 0x4950, 0x4950, 0x495B, 0x495B, 0x4980, 0x498E,
48862306a36Sopenharmony_ci	0x4B00, 0x4B00, 0x4C00, 0x4C00, 0x4D00, 0x4D00, 0x4E00, 0x4E00,
48962306a36Sopenharmony_ci	0x4E80, 0x4E80, 0x4F00, 0x4F00, 0x4F08, 0x4F08, 0x4F10, 0x4F10,
49062306a36Sopenharmony_ci	0x4F18, 0x4F18, 0x4F20, 0x4F20, 0x4F30, 0x4F30, 0x4F60, 0x4F60,
49162306a36Sopenharmony_ci	0x4F80, 0x4F81, 0x4F88, 0x4F89, 0x4FEE, 0x4FEE, 0x4FF3, 0x4FF3,
49262306a36Sopenharmony_ci	0x6000, 0x6001, 0x6008, 0x600F, 0x6014, 0x6016, 0x6018, 0x601B,
49362306a36Sopenharmony_ci	0x61FD, 0x61FD, 0x623C, 0x623C, 0x6380, 0x6380, 0x63A0, 0x63A0,
49462306a36Sopenharmony_ci	0x63C0, 0x63C1, 0x63C8, 0x63C9, 0x63D0, 0x63D4, 0x63D6, 0x63D6,
49562306a36Sopenharmony_ci	0x63EE, 0x63EE, 0x6400, 0x6401, 0x6408, 0x640F, 0x6414, 0x6416,
49662306a36Sopenharmony_ci	0x6418, 0x641B, 0x65FD, 0x65FD, 0x663C, 0x663C, 0x6780, 0x6780,
49762306a36Sopenharmony_ci	0x67A0, 0x67A0, 0x67C0, 0x67C1, 0x67C8, 0x67C9, 0x67D0, 0x67D4,
49862306a36Sopenharmony_ci	0x67D6, 0x67D6, 0x67EE, 0x67EE, 0x6800, 0x6801, 0x6808, 0x680F,
49962306a36Sopenharmony_ci	0x6814, 0x6816, 0x6818, 0x681B, 0x69FD, 0x69FD, 0x6A3C, 0x6A3C,
50062306a36Sopenharmony_ci	0x6B80, 0x6B80, 0x6BA0, 0x6BA0, 0x6BC0, 0x6BC1, 0x6BC8, 0x6BC9,
50162306a36Sopenharmony_ci	0x6BD0, 0x6BD4, 0x6BD6, 0x6BD6, 0x6BEE, 0x6BEE,
50262306a36Sopenharmony_ci	~0 /* sentinel */
50362306a36Sopenharmony_ci};
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic const unsigned int a405_registers[] = {
50662306a36Sopenharmony_ci	/* RBBM */
50762306a36Sopenharmony_ci	0x0000, 0x0002, 0x0004, 0x0021, 0x0023, 0x0024, 0x0026, 0x0026,
50862306a36Sopenharmony_ci	0x0028, 0x002B, 0x002E, 0x0034, 0x0037, 0x0044, 0x0047, 0x0066,
50962306a36Sopenharmony_ci	0x0068, 0x0095, 0x009C, 0x0170, 0x0174, 0x01AF,
51062306a36Sopenharmony_ci	/* CP */
51162306a36Sopenharmony_ci	0x0200, 0x0233, 0x0240, 0x0250, 0x04C0, 0x04DD, 0x0500, 0x050B,
51262306a36Sopenharmony_ci	0x0578, 0x058F,
51362306a36Sopenharmony_ci	/* VSC */
51462306a36Sopenharmony_ci	0x0C00, 0x0C03, 0x0C08, 0x0C41, 0x0C50, 0x0C51,
51562306a36Sopenharmony_ci	/* GRAS */
51662306a36Sopenharmony_ci	0x0C80, 0x0C81, 0x0C88, 0x0C8F,
51762306a36Sopenharmony_ci	/* RB */
51862306a36Sopenharmony_ci	0x0CC0, 0x0CC0, 0x0CC4, 0x0CD2,
51962306a36Sopenharmony_ci	/* PC */
52062306a36Sopenharmony_ci	0x0D00, 0x0D0C, 0x0D10, 0x0D17, 0x0D20, 0x0D23,
52162306a36Sopenharmony_ci	/* VFD */
52262306a36Sopenharmony_ci	0x0E40, 0x0E4A,
52362306a36Sopenharmony_ci	/* VPC */
52462306a36Sopenharmony_ci	0x0E60, 0x0E61, 0x0E63, 0x0E68,
52562306a36Sopenharmony_ci	/* UCHE */
52662306a36Sopenharmony_ci	0x0E80, 0x0E84, 0x0E88, 0x0E95,
52762306a36Sopenharmony_ci	/* GRAS CTX 0 */
52862306a36Sopenharmony_ci	0x2000, 0x2004, 0x2008, 0x2067, 0x2070, 0x2078, 0x207B, 0x216E,
52962306a36Sopenharmony_ci	/* PC CTX 0 */
53062306a36Sopenharmony_ci	0x21C0, 0x21C6, 0x21D0, 0x21D0, 0x21D9, 0x21D9, 0x21E5, 0x21E7,
53162306a36Sopenharmony_ci	/* VFD CTX 0 */
53262306a36Sopenharmony_ci	0x2200, 0x2204, 0x2208, 0x22A9,
53362306a36Sopenharmony_ci	/* GRAS CTX 1 */
53462306a36Sopenharmony_ci	0x2400, 0x2404, 0x2408, 0x2467, 0x2470, 0x2478, 0x247B, 0x256E,
53562306a36Sopenharmony_ci	/* PC CTX 1 */
53662306a36Sopenharmony_ci	0x25C0, 0x25C6, 0x25D0, 0x25D0, 0x25D9, 0x25D9, 0x25E5, 0x25E7,
53762306a36Sopenharmony_ci	/* VFD CTX 1 */
53862306a36Sopenharmony_ci	0x2600, 0x2604, 0x2608, 0x26A9,
53962306a36Sopenharmony_ci	/* VBIF version 0x20050000*/
54062306a36Sopenharmony_ci	0x3000, 0x3007, 0x302C, 0x302C, 0x3030, 0x3030, 0x3034, 0x3036,
54162306a36Sopenharmony_ci	0x3038, 0x3038, 0x303C, 0x303D, 0x3040, 0x3040, 0x3049, 0x3049,
54262306a36Sopenharmony_ci	0x3058, 0x3058, 0x305B, 0x3061, 0x3064, 0x3068, 0x306C, 0x306D,
54362306a36Sopenharmony_ci	0x3080, 0x3088, 0x308B, 0x308C, 0x3090, 0x3094, 0x3098, 0x3098,
54462306a36Sopenharmony_ci	0x309C, 0x309C, 0x30C0, 0x30C0, 0x30C8, 0x30C8, 0x30D0, 0x30D0,
54562306a36Sopenharmony_ci	0x30D8, 0x30D8, 0x30E0, 0x30E0, 0x3100, 0x3100, 0x3108, 0x3108,
54662306a36Sopenharmony_ci	0x3110, 0x3110, 0x3118, 0x3118, 0x3120, 0x3120, 0x3124, 0x3125,
54762306a36Sopenharmony_ci	0x3129, 0x3129, 0x340C, 0x340C, 0x3410, 0x3410,
54862306a36Sopenharmony_ci	~0 /* sentinel */
54962306a36Sopenharmony_ci};
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (!state)
55662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	adreno_gpu_state_get(gpu, state);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return state;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void a4xx_dump(struct msm_gpu *gpu)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	printk("status:   %08x\n",
56862306a36Sopenharmony_ci			gpu_read(gpu, REG_A4XX_RBBM_STATUS));
56962306a36Sopenharmony_ci	adreno_dump(gpu);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic int a4xx_pm_resume(struct msm_gpu *gpu) {
57362306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
57462306a36Sopenharmony_ci	int ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ret = msm_gpu_pm_resume(gpu);
57762306a36Sopenharmony_ci	if (ret)
57862306a36Sopenharmony_ci		return ret;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (adreno_is_a430(adreno_gpu)) {
58162306a36Sopenharmony_ci		unsigned int reg;
58262306a36Sopenharmony_ci		/* Set the default register values; set SW_COLLAPSE to 0 */
58362306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_POWER_CNTL_IP, 0x778000);
58462306a36Sopenharmony_ci		do {
58562306a36Sopenharmony_ci			udelay(5);
58662306a36Sopenharmony_ci			reg = gpu_read(gpu, REG_A4XX_RBBM_POWER_STATUS);
58762306a36Sopenharmony_ci		} while (!(reg & A4XX_RBBM_POWER_CNTL_IP_SP_TP_PWR_ON));
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic int a4xx_pm_suspend(struct msm_gpu *gpu) {
59362306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
59462306a36Sopenharmony_ci	int ret;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ret = msm_gpu_pm_suspend(gpu);
59762306a36Sopenharmony_ci	if (ret)
59862306a36Sopenharmony_ci		return ret;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (adreno_is_a430(adreno_gpu)) {
60162306a36Sopenharmony_ci		/* Set the default register values; set SW_COLLAPSE to 1 */
60262306a36Sopenharmony_ci		gpu_write(gpu, REG_A4XX_RBBM_POWER_CNTL_IP, 0x778001);
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	*value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	return 0;
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic u64 a4xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	u64 busy_cycles;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	busy_cycles = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_RBBM_1_LO);
61962306a36Sopenharmony_ci	*out_sample_rate = clk_get_rate(gpu->core_clk);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	return busy_cycles;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic u32 a4xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	ring->memptrs->rptr = gpu_read(gpu, REG_A4XX_CP_RB_RPTR);
62762306a36Sopenharmony_ci	return ring->memptrs->rptr;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic const struct adreno_gpu_funcs funcs = {
63162306a36Sopenharmony_ci	.base = {
63262306a36Sopenharmony_ci		.get_param = adreno_get_param,
63362306a36Sopenharmony_ci		.set_param = adreno_set_param,
63462306a36Sopenharmony_ci		.hw_init = a4xx_hw_init,
63562306a36Sopenharmony_ci		.pm_suspend = a4xx_pm_suspend,
63662306a36Sopenharmony_ci		.pm_resume = a4xx_pm_resume,
63762306a36Sopenharmony_ci		.recover = a4xx_recover,
63862306a36Sopenharmony_ci		.submit = a4xx_submit,
63962306a36Sopenharmony_ci		.active_ring = adreno_active_ring,
64062306a36Sopenharmony_ci		.irq = a4xx_irq,
64162306a36Sopenharmony_ci		.destroy = a4xx_destroy,
64262306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
64362306a36Sopenharmony_ci		.show = adreno_show,
64462306a36Sopenharmony_ci#endif
64562306a36Sopenharmony_ci		.gpu_busy = a4xx_gpu_busy,
64662306a36Sopenharmony_ci		.gpu_state_get = a4xx_gpu_state_get,
64762306a36Sopenharmony_ci		.gpu_state_put = adreno_gpu_state_put,
64862306a36Sopenharmony_ci		.create_address_space = adreno_create_address_space,
64962306a36Sopenharmony_ci		.get_rptr = a4xx_get_rptr,
65062306a36Sopenharmony_ci	},
65162306a36Sopenharmony_ci	.get_timestamp = a4xx_get_timestamp,
65262306a36Sopenharmony_ci};
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistruct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct a4xx_gpu *a4xx_gpu = NULL;
65762306a36Sopenharmony_ci	struct adreno_gpu *adreno_gpu;
65862306a36Sopenharmony_ci	struct msm_gpu *gpu;
65962306a36Sopenharmony_ci	struct msm_drm_private *priv = dev->dev_private;
66062306a36Sopenharmony_ci	struct platform_device *pdev = priv->gpu_pdev;
66162306a36Sopenharmony_ci	struct icc_path *ocmem_icc_path;
66262306a36Sopenharmony_ci	struct icc_path *icc_path;
66362306a36Sopenharmony_ci	int ret;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (!pdev) {
66662306a36Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "no a4xx device\n");
66762306a36Sopenharmony_ci		ret = -ENXIO;
66862306a36Sopenharmony_ci		goto fail;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	a4xx_gpu = kzalloc(sizeof(*a4xx_gpu), GFP_KERNEL);
67262306a36Sopenharmony_ci	if (!a4xx_gpu) {
67362306a36Sopenharmony_ci		ret = -ENOMEM;
67462306a36Sopenharmony_ci		goto fail;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	adreno_gpu = &a4xx_gpu->base;
67862306a36Sopenharmony_ci	gpu = &adreno_gpu->base;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	gpu->perfcntrs = NULL;
68162306a36Sopenharmony_ci	gpu->num_perfcntrs = 0;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
68462306a36Sopenharmony_ci	if (ret)
68562306a36Sopenharmony_ci		goto fail;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	adreno_gpu->registers = adreno_is_a405(adreno_gpu) ? a405_registers :
68862306a36Sopenharmony_ci							     a4xx_registers;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/* if needed, allocate gmem: */
69162306a36Sopenharmony_ci	ret = adreno_gpu_ocmem_init(dev->dev, adreno_gpu,
69262306a36Sopenharmony_ci				    &a4xx_gpu->ocmem);
69362306a36Sopenharmony_ci	if (ret)
69462306a36Sopenharmony_ci		goto fail;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (!gpu->aspace) {
69762306a36Sopenharmony_ci		/* TODO we think it is possible to configure the GPU to
69862306a36Sopenharmony_ci		 * restrict access to VRAM carveout.  But the required
69962306a36Sopenharmony_ci		 * registers are unknown.  For now just bail out and
70062306a36Sopenharmony_ci		 * limp along with just modesetting.  If it turns out
70162306a36Sopenharmony_ci		 * to not be possible to restrict access, then we must
70262306a36Sopenharmony_ci		 * implement a cmdstream validator.
70362306a36Sopenharmony_ci		 */
70462306a36Sopenharmony_ci		DRM_DEV_ERROR(dev->dev, "No memory protection without IOMMU\n");
70562306a36Sopenharmony_ci		if (!allow_vram_carveout) {
70662306a36Sopenharmony_ci			ret = -ENXIO;
70762306a36Sopenharmony_ci			goto fail;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	icc_path = devm_of_icc_get(&pdev->dev, "gfx-mem");
71262306a36Sopenharmony_ci	if (IS_ERR(icc_path)) {
71362306a36Sopenharmony_ci		ret = PTR_ERR(icc_path);
71462306a36Sopenharmony_ci		goto fail;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	ocmem_icc_path = devm_of_icc_get(&pdev->dev, "ocmem");
71862306a36Sopenharmony_ci	if (IS_ERR(ocmem_icc_path)) {
71962306a36Sopenharmony_ci		ret = PTR_ERR(ocmem_icc_path);
72062306a36Sopenharmony_ci		/* allow -ENODATA, ocmem icc is optional */
72162306a36Sopenharmony_ci		if (ret != -ENODATA)
72262306a36Sopenharmony_ci			goto fail;
72362306a36Sopenharmony_ci		ocmem_icc_path = NULL;
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/*
72762306a36Sopenharmony_ci	 * Set the ICC path to maximum speed for now by multiplying the fastest
72862306a36Sopenharmony_ci	 * frequency by the bus width (8). We'll want to scale this later on to
72962306a36Sopenharmony_ci	 * improve battery life.
73062306a36Sopenharmony_ci	 */
73162306a36Sopenharmony_ci	icc_set_bw(icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
73262306a36Sopenharmony_ci	icc_set_bw(ocmem_icc_path, 0, Bps_to_icc(gpu->fast_rate) * 8);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return gpu;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cifail:
73762306a36Sopenharmony_ci	if (a4xx_gpu)
73862306a36Sopenharmony_ci		a4xx_destroy(&a4xx_gpu->base.base);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	return ERR_PTR(ret);
74162306a36Sopenharmony_ci}
742