xref: /openbmc/linux/drivers/gpu/drm/v3d/v3d_drv.h (revision 220989e7097a5cc083624dc1c925c1c255247574)
157692c94SEric Anholt // SPDX-License-Identifier: GPL-2.0+
257692c94SEric Anholt /* Copyright (C) 2015-2018 Broadcom */
357692c94SEric Anholt 
4*220989e7SSam Ravnborg #include <linux/delay.h>
5*220989e7SSam Ravnborg #include <linux/mutex.h>
6*220989e7SSam Ravnborg #include <linux/spinlock_types.h>
7*220989e7SSam Ravnborg #include <linux/workqueue.h>
8*220989e7SSam Ravnborg 
957692c94SEric Anholt #include <drm/drm_encoder.h>
1057692c94SEric Anholt #include <drm/drm_gem.h>
1140609d48SEric Anholt #include <drm/drm_gem_shmem_helper.h>
1257692c94SEric Anholt #include <drm/gpu_scheduler.h>
13*220989e7SSam Ravnborg 
141584f16cSEric Anholt #include "uapi/drm/v3d_drm.h"
1557692c94SEric Anholt 
16*220989e7SSam Ravnborg struct clk;
17*220989e7SSam Ravnborg struct device;
18*220989e7SSam Ravnborg struct platform_device;
19*220989e7SSam Ravnborg struct reset_control;
20*220989e7SSam Ravnborg 
2157692c94SEric Anholt #define GMP_GRANULARITY (128 * 1024)
2257692c94SEric Anholt 
231584f16cSEric Anholt /* Enum for each of the V3D queues. */
2457692c94SEric Anholt enum v3d_queue {
2557692c94SEric Anholt 	V3D_BIN,
2657692c94SEric Anholt 	V3D_RENDER,
271584f16cSEric Anholt 	V3D_TFU,
28d223f98fSEric Anholt 	V3D_CSD,
29d223f98fSEric Anholt 	V3D_CACHE_CLEAN,
3057692c94SEric Anholt };
3157692c94SEric Anholt 
32d223f98fSEric Anholt #define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1)
3357692c94SEric Anholt 
3457692c94SEric Anholt struct v3d_queue_state {
3557692c94SEric Anholt 	struct drm_gpu_scheduler sched;
3657692c94SEric Anholt 
3757692c94SEric Anholt 	u64 fence_context;
3857692c94SEric Anholt 	u64 emit_seqno;
3957692c94SEric Anholt };
4057692c94SEric Anholt 
4157692c94SEric Anholt struct v3d_dev {
4257692c94SEric Anholt 	struct drm_device drm;
4357692c94SEric Anholt 
4457692c94SEric Anholt 	/* Short representation (e.g. 33, 41) of the V3D tech version
4557692c94SEric Anholt 	 * and revision.
4657692c94SEric Anholt 	 */
4757692c94SEric Anholt 	int ver;
48eea9b97bSEric Anholt 	bool single_irq_line;
4957692c94SEric Anholt 
5057692c94SEric Anholt 	struct device *dev;
5157692c94SEric Anholt 	struct platform_device *pdev;
5257692c94SEric Anholt 	void __iomem *hub_regs;
5357692c94SEric Anholt 	void __iomem *core_regs[3];
5457692c94SEric Anholt 	void __iomem *bridge_regs;
5557692c94SEric Anholt 	void __iomem *gca_regs;
5657692c94SEric Anholt 	struct clk *clk;
57eea9b97bSEric Anholt 	struct reset_control *reset;
5857692c94SEric Anholt 
5957692c94SEric Anholt 	/* Virtual and DMA addresses of the single shared page table. */
6057692c94SEric Anholt 	volatile u32 *pt;
6157692c94SEric Anholt 	dma_addr_t pt_paddr;
6257692c94SEric Anholt 
6357692c94SEric Anholt 	/* Virtual and DMA addresses of the MMU's scratch page.  When
6457692c94SEric Anholt 	 * a read or write is invalid in the MMU, it will be
6557692c94SEric Anholt 	 * redirected here.
6657692c94SEric Anholt 	 */
6757692c94SEric Anholt 	void *mmu_scratch;
6857692c94SEric Anholt 	dma_addr_t mmu_scratch_paddr;
6938c2c791SEric Anholt 	/* virtual address bits from V3D to the MMU. */
7038c2c791SEric Anholt 	int va_width;
7157692c94SEric Anholt 
7257692c94SEric Anholt 	/* Number of V3D cores. */
7357692c94SEric Anholt 	u32 cores;
7457692c94SEric Anholt 
7557692c94SEric Anholt 	/* Allocator managing the address space.  All units are in
7657692c94SEric Anholt 	 * number of pages.
7757692c94SEric Anholt 	 */
7857692c94SEric Anholt 	struct drm_mm mm;
7957692c94SEric Anholt 	spinlock_t mm_lock;
8057692c94SEric Anholt 
8157692c94SEric Anholt 	struct work_struct overflow_mem_work;
8257692c94SEric Anholt 
83a783a09eSEric Anholt 	struct v3d_bin_job *bin_job;
84a783a09eSEric Anholt 	struct v3d_render_job *render_job;
851584f16cSEric Anholt 	struct v3d_tfu_job *tfu_job;
86d223f98fSEric Anholt 	struct v3d_csd_job *csd_job;
8757692c94SEric Anholt 
8857692c94SEric Anholt 	struct v3d_queue_state queue[V3D_MAX_QUEUES];
8957692c94SEric Anholt 
9057692c94SEric Anholt 	/* Spinlock used to synchronize the overflow memory
9157692c94SEric Anholt 	 * management against bin job submission.
9257692c94SEric Anholt 	 */
9357692c94SEric Anholt 	spinlock_t job_lock;
9457692c94SEric Anholt 
9557692c94SEric Anholt 	/* Protects bo_stats */
9657692c94SEric Anholt 	struct mutex bo_lock;
9757692c94SEric Anholt 
9857692c94SEric Anholt 	/* Lock taken when resetting the GPU, to keep multiple
9957692c94SEric Anholt 	 * processes from trying to park the scheduler threads and
10057692c94SEric Anholt 	 * reset at once.
10157692c94SEric Anholt 	 */
10257692c94SEric Anholt 	struct mutex reset_lock;
10357692c94SEric Anholt 
1047122b68bSEric Anholt 	/* Lock taken when creating and pushing the GPU scheduler
1057122b68bSEric Anholt 	 * jobs, to keep the sched-fence seqnos in order.
1067122b68bSEric Anholt 	 */
1077122b68bSEric Anholt 	struct mutex sched_lock;
1087122b68bSEric Anholt 
109d223f98fSEric Anholt 	/* Lock taken during a cache clean and when initiating an L2
110d223f98fSEric Anholt 	 * flush, to keep L2 flushes from interfering with the
111d223f98fSEric Anholt 	 * synchronous L2 cleans.
112d223f98fSEric Anholt 	 */
113d223f98fSEric Anholt 	struct mutex cache_clean_lock;
114d223f98fSEric Anholt 
11557692c94SEric Anholt 	struct {
11657692c94SEric Anholt 		u32 num_allocated;
11757692c94SEric Anholt 		u32 pages_allocated;
11857692c94SEric Anholt 	} bo_stats;
11957692c94SEric Anholt };
12057692c94SEric Anholt 
12157692c94SEric Anholt static inline struct v3d_dev *
12257692c94SEric Anholt to_v3d_dev(struct drm_device *dev)
12357692c94SEric Anholt {
12457692c94SEric Anholt 	return (struct v3d_dev *)dev->dev_private;
12557692c94SEric Anholt }
12657692c94SEric Anholt 
127d223f98fSEric Anholt static inline bool
128d223f98fSEric Anholt v3d_has_csd(struct v3d_dev *v3d)
129d223f98fSEric Anholt {
130d223f98fSEric Anholt 	return v3d->ver >= 41;
131d223f98fSEric Anholt }
132d223f98fSEric Anholt 
13357692c94SEric Anholt /* The per-fd struct, which tracks the MMU mappings. */
13457692c94SEric Anholt struct v3d_file_priv {
13557692c94SEric Anholt 	struct v3d_dev *v3d;
13657692c94SEric Anholt 
13757692c94SEric Anholt 	struct drm_sched_entity sched_entity[V3D_MAX_QUEUES];
13857692c94SEric Anholt };
13957692c94SEric Anholt 
14057692c94SEric Anholt struct v3d_bo {
14140609d48SEric Anholt 	struct drm_gem_shmem_object base;
14257692c94SEric Anholt 
14357692c94SEric Anholt 	struct drm_mm_node node;
14457692c94SEric Anholt 
14557692c94SEric Anholt 	/* List entry for the BO's position in
146a783a09eSEric Anholt 	 * v3d_render_job->unref_list
14757692c94SEric Anholt 	 */
14857692c94SEric Anholt 	struct list_head unref_head;
14957692c94SEric Anholt };
15057692c94SEric Anholt 
15157692c94SEric Anholt static inline struct v3d_bo *
15257692c94SEric Anholt to_v3d_bo(struct drm_gem_object *bo)
15357692c94SEric Anholt {
15457692c94SEric Anholt 	return (struct v3d_bo *)bo;
15557692c94SEric Anholt }
15657692c94SEric Anholt 
15757692c94SEric Anholt struct v3d_fence {
15857692c94SEric Anholt 	struct dma_fence base;
15957692c94SEric Anholt 	struct drm_device *dev;
16057692c94SEric Anholt 	/* v3d seqno for signaled() test */
16157692c94SEric Anholt 	u64 seqno;
16257692c94SEric Anholt 	enum v3d_queue queue;
16357692c94SEric Anholt };
16457692c94SEric Anholt 
16557692c94SEric Anholt static inline struct v3d_fence *
16657692c94SEric Anholt to_v3d_fence(struct dma_fence *fence)
16757692c94SEric Anholt {
16857692c94SEric Anholt 	return (struct v3d_fence *)fence;
16957692c94SEric Anholt }
17057692c94SEric Anholt 
17157692c94SEric Anholt #define V3D_READ(offset) readl(v3d->hub_regs + offset)
17257692c94SEric Anholt #define V3D_WRITE(offset, val) writel(val, v3d->hub_regs + offset)
17357692c94SEric Anholt 
17457692c94SEric Anholt #define V3D_BRIDGE_READ(offset) readl(v3d->bridge_regs + offset)
17557692c94SEric Anholt #define V3D_BRIDGE_WRITE(offset, val) writel(val, v3d->bridge_regs + offset)
17657692c94SEric Anholt 
17757692c94SEric Anholt #define V3D_GCA_READ(offset) readl(v3d->gca_regs + offset)
17857692c94SEric Anholt #define V3D_GCA_WRITE(offset, val) writel(val, v3d->gca_regs + offset)
17957692c94SEric Anholt 
18057692c94SEric Anholt #define V3D_CORE_READ(core, offset) readl(v3d->core_regs[core] + offset)
18157692c94SEric Anholt #define V3D_CORE_WRITE(core, offset, val) writel(val, v3d->core_regs[core] + offset)
18257692c94SEric Anholt 
18357692c94SEric Anholt struct v3d_job {
18457692c94SEric Anholt 	struct drm_sched_job base;
18557692c94SEric Anholt 
186a783a09eSEric Anholt 	struct kref refcount;
187a783a09eSEric Anholt 
188a783a09eSEric Anholt 	struct v3d_dev *v3d;
189a783a09eSEric Anholt 
190a783a09eSEric Anholt 	/* This is the array of BOs that were looked up at the start
191a783a09eSEric Anholt 	 * of submission.
192a783a09eSEric Anholt 	 */
193a783a09eSEric Anholt 	struct drm_gem_object **bo;
194a783a09eSEric Anholt 	u32 bo_count;
19557692c94SEric Anholt 
196dffa9b7aSEric Anholt 	/* Array of struct dma_fence * to block on before submitting this job.
197dffa9b7aSEric Anholt 	 */
198dffa9b7aSEric Anholt 	struct xarray deps;
199dffa9b7aSEric Anholt 	unsigned long last_dep;
20057692c94SEric Anholt 
20157692c94SEric Anholt 	/* v3d fence to be signaled by IRQ handler when the job is complete. */
2023f0b646eSEric Anholt 	struct dma_fence *irq_fence;
20357692c94SEric Anholt 
204a783a09eSEric Anholt 	/* scheduler fence for when the job is considered complete and
205a783a09eSEric Anholt 	 * the BO reservations can be released.
206a783a09eSEric Anholt 	 */
207a783a09eSEric Anholt 	struct dma_fence *done_fence;
208a783a09eSEric Anholt 
209a783a09eSEric Anholt 	/* Callback for the freeing of the job on refcount going to 0. */
210a783a09eSEric Anholt 	void (*free)(struct kref *ref);
211a783a09eSEric Anholt };
212a783a09eSEric Anholt 
213a783a09eSEric Anholt struct v3d_bin_job {
214a783a09eSEric Anholt 	struct v3d_job base;
215a783a09eSEric Anholt 
21657692c94SEric Anholt 	/* GPU virtual addresses of the start/end of the CL job. */
21757692c94SEric Anholt 	u32 start, end;
218624bb0c0SEric Anholt 
219624bb0c0SEric Anholt 	u32 timedout_ctca, timedout_ctra;
22057692c94SEric Anholt 
221a783a09eSEric Anholt 	/* Corresponding render job, for attaching our overflow memory. */
222a783a09eSEric Anholt 	struct v3d_render_job *render;
22357692c94SEric Anholt 
22457692c94SEric Anholt 	/* Submitted tile memory allocation start/size, tile state. */
22557692c94SEric Anholt 	u32 qma, qms, qts;
22657692c94SEric Anholt };
22757692c94SEric Anholt 
228a783a09eSEric Anholt struct v3d_render_job {
229a783a09eSEric Anholt 	struct v3d_job base;
230a783a09eSEric Anholt 
231a783a09eSEric Anholt 	/* GPU virtual addresses of the start/end of the CL job. */
232a783a09eSEric Anholt 	u32 start, end;
233a783a09eSEric Anholt 
234a783a09eSEric Anholt 	u32 timedout_ctca, timedout_ctra;
235a783a09eSEric Anholt 
236a783a09eSEric Anholt 	/* List of overflow BOs used in the job that need to be
237a783a09eSEric Anholt 	 * released once the job is complete.
238a783a09eSEric Anholt 	 */
239a783a09eSEric Anholt 	struct list_head unref_list;
240a783a09eSEric Anholt };
241a783a09eSEric Anholt 
2421584f16cSEric Anholt struct v3d_tfu_job {
243a783a09eSEric Anholt 	struct v3d_job base;
2441584f16cSEric Anholt 
2451584f16cSEric Anholt 	struct drm_v3d_submit_tfu args;
2461584f16cSEric Anholt };
2471584f16cSEric Anholt 
248d223f98fSEric Anholt struct v3d_csd_job {
249d223f98fSEric Anholt 	struct v3d_job base;
250d223f98fSEric Anholt 
251d223f98fSEric Anholt 	u32 timedout_batches;
252d223f98fSEric Anholt 
253d223f98fSEric Anholt 	struct drm_v3d_submit_csd args;
254d223f98fSEric Anholt };
255d223f98fSEric Anholt 
25657692c94SEric Anholt /**
25757692c94SEric Anholt  * _wait_for - magic (register) wait macro
25857692c94SEric Anholt  *
25957692c94SEric Anholt  * Does the right thing for modeset paths when run under kdgb or similar atomic
26057692c94SEric Anholt  * contexts. Note that it's important that we check the condition again after
26157692c94SEric Anholt  * having timed out, since the timeout could be due to preemption or similar and
26257692c94SEric Anholt  * we've never had a chance to check the condition before the timeout.
26357692c94SEric Anholt  */
26457692c94SEric Anholt #define wait_for(COND, MS) ({ \
26557692c94SEric Anholt 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1;	\
26657692c94SEric Anholt 	int ret__ = 0;							\
26757692c94SEric Anholt 	while (!(COND)) {						\
26857692c94SEric Anholt 		if (time_after(jiffies, timeout__)) {			\
26957692c94SEric Anholt 			if (!(COND))					\
27057692c94SEric Anholt 				ret__ = -ETIMEDOUT;			\
27157692c94SEric Anholt 			break;						\
27257692c94SEric Anholt 		}							\
27357692c94SEric Anholt 		msleep(1);					\
27457692c94SEric Anholt 	}								\
27557692c94SEric Anholt 	ret__;								\
27657692c94SEric Anholt })
27757692c94SEric Anholt 
27857692c94SEric Anholt static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
27957692c94SEric Anholt {
28057692c94SEric Anholt 	/* nsecs_to_jiffies64() does not guard against overflow */
28157692c94SEric Anholt 	if (NSEC_PER_SEC % HZ &&
28257692c94SEric Anholt 	    div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
28357692c94SEric Anholt 		return MAX_JIFFY_OFFSET;
28457692c94SEric Anholt 
28557692c94SEric Anholt 	return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
28657692c94SEric Anholt }
28757692c94SEric Anholt 
28857692c94SEric Anholt /* v3d_bo.c */
28940609d48SEric Anholt struct drm_gem_object *v3d_create_object(struct drm_device *dev, size_t size);
29057692c94SEric Anholt void v3d_free_object(struct drm_gem_object *gem_obj);
29157692c94SEric Anholt struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
29257692c94SEric Anholt 			     size_t size);
29357692c94SEric Anholt int v3d_create_bo_ioctl(struct drm_device *dev, void *data,
29457692c94SEric Anholt 			struct drm_file *file_priv);
29557692c94SEric Anholt int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data,
29657692c94SEric Anholt 		      struct drm_file *file_priv);
29757692c94SEric Anholt int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data,
29857692c94SEric Anholt 			    struct drm_file *file_priv);
29957692c94SEric Anholt struct drm_gem_object *v3d_prime_import_sg_table(struct drm_device *dev,
30057692c94SEric Anholt 						 struct dma_buf_attachment *attach,
30157692c94SEric Anholt 						 struct sg_table *sgt);
30257692c94SEric Anholt 
30357692c94SEric Anholt /* v3d_debugfs.c */
30457692c94SEric Anholt int v3d_debugfs_init(struct drm_minor *minor);
30557692c94SEric Anholt 
30657692c94SEric Anholt /* v3d_fence.c */
30757692c94SEric Anholt extern const struct dma_fence_ops v3d_fence_ops;
30857692c94SEric Anholt struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue queue);
30957692c94SEric Anholt 
31057692c94SEric Anholt /* v3d_gem.c */
31157692c94SEric Anholt int v3d_gem_init(struct drm_device *dev);
31257692c94SEric Anholt void v3d_gem_destroy(struct drm_device *dev);
31357692c94SEric Anholt int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
31457692c94SEric Anholt 			struct drm_file *file_priv);
3151584f16cSEric Anholt int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
3161584f16cSEric Anholt 			 struct drm_file *file_priv);
317d223f98fSEric Anholt int v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
318d223f98fSEric Anholt 			 struct drm_file *file_priv);
31957692c94SEric Anholt int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
32057692c94SEric Anholt 		      struct drm_file *file_priv);
321a783a09eSEric Anholt void v3d_job_put(struct v3d_job *job);
32257692c94SEric Anholt void v3d_reset(struct v3d_dev *v3d);
32357692c94SEric Anholt void v3d_invalidate_caches(struct v3d_dev *v3d);
324d223f98fSEric Anholt void v3d_clean_caches(struct v3d_dev *v3d);
32557692c94SEric Anholt 
32657692c94SEric Anholt /* v3d_irq.c */
327fc227715SEric Anholt int v3d_irq_init(struct v3d_dev *v3d);
32857692c94SEric Anholt void v3d_irq_enable(struct v3d_dev *v3d);
32957692c94SEric Anholt void v3d_irq_disable(struct v3d_dev *v3d);
33057692c94SEric Anholt void v3d_irq_reset(struct v3d_dev *v3d);
33157692c94SEric Anholt 
33257692c94SEric Anholt /* v3d_mmu.c */
33357692c94SEric Anholt int v3d_mmu_get_offset(struct drm_file *file_priv, struct v3d_bo *bo,
33457692c94SEric Anholt 		       u32 *offset);
33557692c94SEric Anholt int v3d_mmu_set_page_table(struct v3d_dev *v3d);
33657692c94SEric Anholt void v3d_mmu_insert_ptes(struct v3d_bo *bo);
33757692c94SEric Anholt void v3d_mmu_remove_ptes(struct v3d_bo *bo);
33857692c94SEric Anholt 
33957692c94SEric Anholt /* v3d_sched.c */
34057692c94SEric Anholt int v3d_sched_init(struct v3d_dev *v3d);
34157692c94SEric Anholt void v3d_sched_fini(struct v3d_dev *v3d);
342