18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci#ifndef __A5XX_GPU_H__
58c2ecf20Sopenharmony_ci#define __A5XX_GPU_H__
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "adreno_gpu.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* Bringing over the hack from the previous targets */
108c2ecf20Sopenharmony_ci#undef ROP_COPY
118c2ecf20Sopenharmony_ci#undef ROP_XOR
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "a5xx.xml.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistruct a5xx_gpu {
168c2ecf20Sopenharmony_ci	struct adreno_gpu base;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	struct drm_gem_object *pm4_bo;
198c2ecf20Sopenharmony_ci	uint64_t pm4_iova;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	struct drm_gem_object *pfp_bo;
228c2ecf20Sopenharmony_ci	uint64_t pfp_iova;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	struct drm_gem_object *gpmu_bo;
258c2ecf20Sopenharmony_ci	uint64_t gpmu_iova;
268c2ecf20Sopenharmony_ci	uint32_t gpmu_dwords;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	uint32_t lm_leakage;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	struct msm_ringbuffer *cur_ring;
318c2ecf20Sopenharmony_ci	struct msm_ringbuffer *next_ring;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS];
348c2ecf20Sopenharmony_ci	struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS];
358c2ecf20Sopenharmony_ci	struct a5xx_preempt_record *preempt[MSM_GPU_MAX_RINGS];
368c2ecf20Sopenharmony_ci	uint64_t preempt_iova[MSM_GPU_MAX_RINGS];
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	atomic_t preempt_state;
398c2ecf20Sopenharmony_ci	struct timer_list preempt_timer;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	struct drm_gem_object *shadow_bo;
428c2ecf20Sopenharmony_ci	uint64_t shadow_iova;
438c2ecf20Sopenharmony_ci	uint32_t *shadow;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* True if the microcode supports the WHERE_AM_I opcode */
468c2ecf20Sopenharmony_ci	bool has_whereami;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
528c2ecf20Sopenharmony_civoid a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor);
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * In order to do lockless preemption we use a simple state machine to progress
578c2ecf20Sopenharmony_ci * through the process.
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * PREEMPT_NONE - no preemption in progress.  Next state START.
608c2ecf20Sopenharmony_ci * PREEMPT_START - The trigger is evaulating if preemption is possible. Next
618c2ecf20Sopenharmony_ci * states: TRIGGERED, NONE
628c2ecf20Sopenharmony_ci * PREEMPT_ABORT - An intermediate state before moving back to NONE. Next
638c2ecf20Sopenharmony_ci * state: NONE.
648c2ecf20Sopenharmony_ci * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next
658c2ecf20Sopenharmony_ci * states: FAULTED, PENDING
668c2ecf20Sopenharmony_ci * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger
678c2ecf20Sopenharmony_ci * recovery.  Next state: N/A
688c2ecf20Sopenharmony_ci * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is
698c2ecf20Sopenharmony_ci * checking the success of the operation. Next state: FAULTED, NONE.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cienum preempt_state {
738c2ecf20Sopenharmony_ci	PREEMPT_NONE = 0,
748c2ecf20Sopenharmony_ci	PREEMPT_START,
758c2ecf20Sopenharmony_ci	PREEMPT_ABORT,
768c2ecf20Sopenharmony_ci	PREEMPT_TRIGGERED,
778c2ecf20Sopenharmony_ci	PREEMPT_FAULTED,
788c2ecf20Sopenharmony_ci	PREEMPT_PENDING,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * struct a5xx_preempt_record is a shared buffer between the microcode and the
838c2ecf20Sopenharmony_ci * CPU to store the state for preemption. The record itself is much larger
848c2ecf20Sopenharmony_ci * (64k) but most of that is used by the CP for storage.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * There is a preemption record assigned per ringbuffer. When the CPU triggers a
878c2ecf20Sopenharmony_ci * preemption, it fills out the record with the useful information (wptr, ring
888c2ecf20Sopenharmony_ci * base, etc) and the microcode uses that information to set up the CP following
898c2ecf20Sopenharmony_ci * the preemption.  When a ring is switched out, the CP will save the ringbuffer
908c2ecf20Sopenharmony_ci * state back to the record. In this way, once the records are properly set up
918c2ecf20Sopenharmony_ci * the CPU can quickly switch back and forth between ringbuffers by only
928c2ecf20Sopenharmony_ci * updating a few registers (often only the wptr).
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * These are the CPU aware registers in the record:
958c2ecf20Sopenharmony_ci * @magic: Must always be 0x27C4BAFC
968c2ecf20Sopenharmony_ci * @info: Type of the record - written 0 by the CPU, updated by the CP
978c2ecf20Sopenharmony_ci * @data: Data field from SET_RENDER_MODE or a checkpoint. Written and used by
988c2ecf20Sopenharmony_ci * the CP
998c2ecf20Sopenharmony_ci * @cntl: Value of RB_CNTL written by CPU, save/restored by CP
1008c2ecf20Sopenharmony_ci * @rptr: Value of RB_RPTR written by CPU, save/restored by CP
1018c2ecf20Sopenharmony_ci * @wptr: Value of RB_WPTR written by CPU, save/restored by CP
1028c2ecf20Sopenharmony_ci * @rptr_addr: Value of RB_RPTR_ADDR written by CPU, save/restored by CP
1038c2ecf20Sopenharmony_ci * @rbase: Value of RB_BASE written by CPU, save/restored by CP
1048c2ecf20Sopenharmony_ci * @counter: GPU address of the storage area for the performance counters
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cistruct a5xx_preempt_record {
1078c2ecf20Sopenharmony_ci	uint32_t magic;
1088c2ecf20Sopenharmony_ci	uint32_t info;
1098c2ecf20Sopenharmony_ci	uint32_t data;
1108c2ecf20Sopenharmony_ci	uint32_t cntl;
1118c2ecf20Sopenharmony_ci	uint32_t rptr;
1128c2ecf20Sopenharmony_ci	uint32_t wptr;
1138c2ecf20Sopenharmony_ci	uint64_t rptr_addr;
1148c2ecf20Sopenharmony_ci	uint64_t rbase;
1158c2ecf20Sopenharmony_ci	uint64_t counter;
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* Magic identifier for the preemption record */
1198c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_RECORD_MAGIC 0x27C4BAFCUL
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/*
1228c2ecf20Sopenharmony_ci * Even though the structure above is only a few bytes, we need a full 64k to
1238c2ecf20Sopenharmony_ci * store the entire preemption record from the CP
1248c2ecf20Sopenharmony_ci */
1258c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_RECORD_SIZE (64 * 1024)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * The preemption counter block is a storage area for the value of the
1298c2ecf20Sopenharmony_ci * preemption counters that are saved immediately before context switch. We
1308c2ecf20Sopenharmony_ci * append it on to the end of the allocation for the preemption record.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ci#define A5XX_PREEMPT_COUNTER_SIZE (16 * 4)
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ciint a5xx_power_init(struct msm_gpu *gpu);
1368c2ecf20Sopenharmony_civoid a5xx_gpmu_ucode_init(struct msm_gpu *gpu);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic inline int spin_usecs(struct msm_gpu *gpu, uint32_t usecs,
1398c2ecf20Sopenharmony_ci		uint32_t reg, uint32_t mask, uint32_t value)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	while (usecs--) {
1428c2ecf20Sopenharmony_ci		udelay(1);
1438c2ecf20Sopenharmony_ci		if ((gpu_read(gpu, reg) & mask) == value)
1448c2ecf20Sopenharmony_ci			return 0;
1458c2ecf20Sopenharmony_ci		cpu_relax();
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define shadowptr(a5xx_gpu, ring) ((a5xx_gpu)->shadow_iova + \
1528c2ecf20Sopenharmony_ci		((ring)->id * sizeof(uint32_t)))
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cibool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
1558c2ecf20Sopenharmony_civoid a5xx_set_hwcg(struct msm_gpu *gpu, bool state);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_civoid a5xx_preempt_init(struct msm_gpu *gpu);
1588c2ecf20Sopenharmony_civoid a5xx_preempt_hw_init(struct msm_gpu *gpu);
1598c2ecf20Sopenharmony_civoid a5xx_preempt_trigger(struct msm_gpu *gpu);
1608c2ecf20Sopenharmony_civoid a5xx_preempt_irq(struct msm_gpu *gpu);
1618c2ecf20Sopenharmony_civoid a5xx_preempt_fini(struct msm_gpu *gpu);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_civoid a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, bool sync);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* Return true if we are in a preempt state */
1668c2ecf20Sopenharmony_cistatic inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	int preempt_state = atomic_read(&a5xx_gpu->preempt_state);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return !(preempt_state == PREEMPT_NONE ||
1718c2ecf20Sopenharmony_ci			preempt_state == PREEMPT_ABORT);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#endif /* __A5XX_GPU_H__ */
175