xref: /linux/drivers/gpu/drm/imagination/pvr_device.h (revision cc1aeedb98ad347c06ff59e991b2f94dfb4c565d)
14babef07SSarah Walker /* SPDX-License-Identifier: GPL-2.0-only OR MIT */
24babef07SSarah Walker /* Copyright (c) 2023 Imagination Technologies Ltd. */
34babef07SSarah Walker 
44babef07SSarah Walker #ifndef PVR_DEVICE_H
54babef07SSarah Walker #define PVR_DEVICE_H
64babef07SSarah Walker 
7*cc1aeedbSSarah Walker #include "pvr_ccb.h"
8f99f5f3eSSarah Walker #include "pvr_device_info.h"
9f99f5f3eSSarah Walker #include "pvr_fw.h"
10f99f5f3eSSarah Walker 
114babef07SSarah Walker #include <drm/drm_device.h>
124babef07SSarah Walker #include <drm/drm_file.h>
134babef07SSarah Walker #include <drm/drm_mm.h>
144babef07SSarah Walker 
154babef07SSarah Walker #include <linux/bits.h>
164babef07SSarah Walker #include <linux/compiler_attributes.h>
174babef07SSarah Walker #include <linux/compiler_types.h>
181f88f017SSarah Walker #include <linux/io.h>
191f88f017SSarah Walker #include <linux/iopoll.h>
204babef07SSarah Walker #include <linux/kernel.h>
211f88f017SSarah Walker #include <linux/math.h>
221f88f017SSarah Walker #include <linux/mutex.h>
231f88f017SSarah Walker #include <linux/timer.h>
244babef07SSarah Walker #include <linux/types.h>
254babef07SSarah Walker #include <linux/wait.h>
261f88f017SSarah Walker #include <linux/workqueue.h>
271f88f017SSarah Walker #include <linux/xarray.h>
281f88f017SSarah Walker 
291f88f017SSarah Walker /* Forward declaration from <linux/clk.h>. */
301f88f017SSarah Walker struct clk;
311f88f017SSarah Walker 
321f88f017SSarah Walker /* Forward declaration from <linux/firmware.h>. */
331f88f017SSarah Walker struct firmware;
344babef07SSarah Walker 
354babef07SSarah Walker /**
36f99f5f3eSSarah Walker  * struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device
37f99f5f3eSSarah Walker  * @b: Branch ID.
38f99f5f3eSSarah Walker  * @v: Version ID.
39f99f5f3eSSarah Walker  * @n: Number of scalable units.
40f99f5f3eSSarah Walker  * @c: Config ID.
41f99f5f3eSSarah Walker  */
42f99f5f3eSSarah Walker struct pvr_gpu_id {
43f99f5f3eSSarah Walker 	u16 b, v, n, c;
44f99f5f3eSSarah Walker };
45f99f5f3eSSarah Walker 
46f99f5f3eSSarah Walker /**
47f99f5f3eSSarah Walker  * struct pvr_fw_version - Firmware version information
48f99f5f3eSSarah Walker  * @major: Major version number.
49f99f5f3eSSarah Walker  * @minor: Minor version number.
50f99f5f3eSSarah Walker  */
51f99f5f3eSSarah Walker struct pvr_fw_version {
52f99f5f3eSSarah Walker 	u16 major, minor;
53f99f5f3eSSarah Walker };
54f99f5f3eSSarah Walker 
55f99f5f3eSSarah Walker /**
564babef07SSarah Walker  * struct pvr_device - powervr-specific wrapper for &struct drm_device
574babef07SSarah Walker  */
584babef07SSarah Walker struct pvr_device {
594babef07SSarah Walker 	/**
604babef07SSarah Walker 	 * @base: The underlying &struct drm_device.
614babef07SSarah Walker 	 *
624babef07SSarah Walker 	 * Do not access this member directly, instead call
634babef07SSarah Walker 	 * from_pvr_device().
644babef07SSarah Walker 	 */
654babef07SSarah Walker 	struct drm_device base;
661f88f017SSarah Walker 
67f99f5f3eSSarah Walker 	/** @gpu_id: GPU ID detected at runtime. */
68f99f5f3eSSarah Walker 	struct pvr_gpu_id gpu_id;
69f99f5f3eSSarah Walker 
70f99f5f3eSSarah Walker 	/**
71f99f5f3eSSarah Walker 	 * @features: Hardware feature information.
72f99f5f3eSSarah Walker 	 *
73f99f5f3eSSarah Walker 	 * Do not access this member directly, instead use PVR_HAS_FEATURE()
74f99f5f3eSSarah Walker 	 * or PVR_FEATURE_VALUE() macros.
75f99f5f3eSSarah Walker 	 */
76f99f5f3eSSarah Walker 	struct pvr_device_features features;
77f99f5f3eSSarah Walker 
78f99f5f3eSSarah Walker 	/**
79f99f5f3eSSarah Walker 	 * @quirks: Hardware quirk information.
80f99f5f3eSSarah Walker 	 *
81f99f5f3eSSarah Walker 	 * Do not access this member directly, instead use PVR_HAS_QUIRK().
82f99f5f3eSSarah Walker 	 */
83f99f5f3eSSarah Walker 	struct pvr_device_quirks quirks;
84f99f5f3eSSarah Walker 
85f99f5f3eSSarah Walker 	/**
86f99f5f3eSSarah Walker 	 * @enhancements: Hardware enhancement information.
87f99f5f3eSSarah Walker 	 *
88f99f5f3eSSarah Walker 	 * Do not access this member directly, instead use
89f99f5f3eSSarah Walker 	 * PVR_HAS_ENHANCEMENT().
90f99f5f3eSSarah Walker 	 */
91f99f5f3eSSarah Walker 	struct pvr_device_enhancements enhancements;
92f99f5f3eSSarah Walker 
93f99f5f3eSSarah Walker 	/** @fw_version: Firmware version detected at runtime. */
94f99f5f3eSSarah Walker 	struct pvr_fw_version fw_version;
95f99f5f3eSSarah Walker 
961f88f017SSarah Walker 	/**
971f88f017SSarah Walker 	 * @regs: Device control registers.
981f88f017SSarah Walker 	 *
991f88f017SSarah Walker 	 * These are mapped into memory when the device is initialized; that
1001f88f017SSarah Walker 	 * location is where this pointer points.
1011f88f017SSarah Walker 	 */
1021f88f017SSarah Walker 	void __iomem *regs;
1031f88f017SSarah Walker 
1041f88f017SSarah Walker 	/**
1051f88f017SSarah Walker 	 * @core_clk: General core clock.
1061f88f017SSarah Walker 	 *
1071f88f017SSarah Walker 	 * This is the primary clock used by the entire GPU core.
1081f88f017SSarah Walker 	 */
1091f88f017SSarah Walker 	struct clk *core_clk;
1101f88f017SSarah Walker 
1111f88f017SSarah Walker 	/**
1121f88f017SSarah Walker 	 * @sys_clk: Optional system bus clock.
1131f88f017SSarah Walker 	 *
1141f88f017SSarah Walker 	 * This may be used on some platforms to provide an independent clock to the SoC Interface
1151f88f017SSarah Walker 	 * (SOCIF). If present, this needs to be enabled/disabled together with @core_clk.
1161f88f017SSarah Walker 	 */
1171f88f017SSarah Walker 	struct clk *sys_clk;
1181f88f017SSarah Walker 
1191f88f017SSarah Walker 	/**
1201f88f017SSarah Walker 	 * @mem_clk: Optional memory clock.
1211f88f017SSarah Walker 	 *
1221f88f017SSarah Walker 	 * This may be used on some platforms to provide an independent clock to the Memory
1231f88f017SSarah Walker 	 * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk.
1241f88f017SSarah Walker 	 */
1251f88f017SSarah Walker 	struct clk *mem_clk;
126f99f5f3eSSarah Walker 
127*cc1aeedbSSarah Walker 	/** @irq: IRQ number. */
128*cc1aeedbSSarah Walker 	int irq;
129*cc1aeedbSSarah Walker 
130*cc1aeedbSSarah Walker 	/** @fwccb: Firmware CCB. */
131*cc1aeedbSSarah Walker 	struct pvr_ccb fwccb;
132*cc1aeedbSSarah Walker 
133ff5f643dSDonald Robson 	/**
134ff5f643dSDonald Robson 	 * @kernel_vm_ctx: Virtual memory context used for kernel mappings.
135ff5f643dSDonald Robson 	 *
136ff5f643dSDonald Robson 	 * This is used for mappings in the firmware address region when a META firmware processor
137ff5f643dSDonald Robson 	 * is in use.
138ff5f643dSDonald Robson 	 *
139ff5f643dSDonald Robson 	 * When a MIPS firmware processor is in use, this will be %NULL.
140ff5f643dSDonald Robson 	 */
141ff5f643dSDonald Robson 	struct pvr_vm_context *kernel_vm_ctx;
142ff5f643dSDonald Robson 
143f99f5f3eSSarah Walker 	/** @fw_dev: Firmware related data. */
144f99f5f3eSSarah Walker 	struct pvr_fw_device fw_dev;
145ff5f643dSDonald Robson 
146ff5f643dSDonald Robson 	/**
147ff5f643dSDonald Robson 	 * @mmu_flush_cache_flags: Records which MMU caches require flushing
148ff5f643dSDonald Robson 	 * before submitting the next job.
149ff5f643dSDonald Robson 	 */
150ff5f643dSDonald Robson 	atomic_t mmu_flush_cache_flags;
151727538a4SSarah Walker 
152727538a4SSarah Walker 	struct {
153727538a4SSarah Walker 		/** @work: Work item for watchdog callback. */
154727538a4SSarah Walker 		struct delayed_work work;
155727538a4SSarah Walker 
156727538a4SSarah Walker 		/** @old_kccb_cmds_executed: KCCB command execution count at last watchdog poll. */
157727538a4SSarah Walker 		u32 old_kccb_cmds_executed;
158727538a4SSarah Walker 
159727538a4SSarah Walker 		/** @kccb_stall_count: Number of watchdog polls KCCB has been stalled for. */
160727538a4SSarah Walker 		u32 kccb_stall_count;
161727538a4SSarah Walker 	} watchdog;
162727538a4SSarah Walker 
163*cc1aeedbSSarah Walker 	struct {
164*cc1aeedbSSarah Walker 		/** @ccb: Kernel CCB. */
165*cc1aeedbSSarah Walker 		struct pvr_ccb ccb;
166*cc1aeedbSSarah Walker 
167*cc1aeedbSSarah Walker 		/** @rtn_q: Waitqueue for KCCB command return waiters. */
168*cc1aeedbSSarah Walker 		wait_queue_head_t rtn_q;
169*cc1aeedbSSarah Walker 
170*cc1aeedbSSarah Walker 		/** @rtn_obj: Object representing KCCB return slots. */
171*cc1aeedbSSarah Walker 		struct pvr_fw_object *rtn_obj;
172*cc1aeedbSSarah Walker 
173*cc1aeedbSSarah Walker 		/**
174*cc1aeedbSSarah Walker 		 * @rtn: Pointer to CPU mapping of KCCB return slots. Must be accessed by
175*cc1aeedbSSarah Walker 		 *       READ_ONCE()/WRITE_ONCE().
176*cc1aeedbSSarah Walker 		 */
177*cc1aeedbSSarah Walker 		u32 *rtn;
178*cc1aeedbSSarah Walker 
179*cc1aeedbSSarah Walker 		/** @slot_count: Total number of KCCB slots available. */
180*cc1aeedbSSarah Walker 		u32 slot_count;
181*cc1aeedbSSarah Walker 
182*cc1aeedbSSarah Walker 		/** @reserved_count: Number of KCCB slots reserved for future use. */
183*cc1aeedbSSarah Walker 		u32 reserved_count;
184*cc1aeedbSSarah Walker 
185*cc1aeedbSSarah Walker 		/**
186*cc1aeedbSSarah Walker 		 * @waiters: List of KCCB slot waiters.
187*cc1aeedbSSarah Walker 		 */
188*cc1aeedbSSarah Walker 		struct list_head waiters;
189*cc1aeedbSSarah Walker 
190*cc1aeedbSSarah Walker 		/** @fence_ctx: KCCB fence context. */
191*cc1aeedbSSarah Walker 		struct {
192*cc1aeedbSSarah Walker 			/** @id: KCCB fence context ID allocated with dma_fence_context_alloc(). */
193*cc1aeedbSSarah Walker 			u64 id;
194*cc1aeedbSSarah Walker 
195*cc1aeedbSSarah Walker 			/** @seqno: Sequence number incremented each time a fence is created. */
196*cc1aeedbSSarah Walker 			atomic_t seqno;
197*cc1aeedbSSarah Walker 
198*cc1aeedbSSarah Walker 			/**
199*cc1aeedbSSarah Walker 			 * @lock: Lock used to synchronize access to fences allocated by this
200*cc1aeedbSSarah Walker 			 * context.
201*cc1aeedbSSarah Walker 			 */
202*cc1aeedbSSarah Walker 			spinlock_t lock;
203*cc1aeedbSSarah Walker 		} fence_ctx;
204*cc1aeedbSSarah Walker 	} kccb;
205*cc1aeedbSSarah Walker 
206727538a4SSarah Walker 	/**
207727538a4SSarah Walker 	 * @lost: %true if the device has been lost.
208727538a4SSarah Walker 	 *
209727538a4SSarah Walker 	 * This variable is set if the device has become irretrievably unavailable, e.g. if the
210727538a4SSarah Walker 	 * firmware processor has stopped responding and can not be revived via a hard reset.
211727538a4SSarah Walker 	 */
212727538a4SSarah Walker 	bool lost;
213727538a4SSarah Walker 
214*cc1aeedbSSarah Walker 	/**
215*cc1aeedbSSarah Walker 	 * @reset_sem: Reset semaphore.
216*cc1aeedbSSarah Walker 	 *
217*cc1aeedbSSarah Walker 	 * GPU reset code will lock this for writing. Any code that submits commands to the firmware
218*cc1aeedbSSarah Walker 	 * that isn't in an IRQ handler or on the scheduler workqueue must lock this for reading.
219*cc1aeedbSSarah Walker 	 * Once this has been successfully locked, &pvr_dev->lost _must_ be checked, and -%EIO must
220*cc1aeedbSSarah Walker 	 * be returned if it is set.
221*cc1aeedbSSarah Walker 	 */
222*cc1aeedbSSarah Walker 	struct rw_semaphore reset_sem;
223*cc1aeedbSSarah Walker 
224727538a4SSarah Walker 	/** @sched_wq: Workqueue for schedulers. */
225727538a4SSarah Walker 	struct workqueue_struct *sched_wq;
2264babef07SSarah Walker };
2274babef07SSarah Walker 
2284babef07SSarah Walker /**
2294babef07SSarah Walker  * struct pvr_file - powervr-specific data to be assigned to &struct
2304babef07SSarah Walker  * drm_file.driver_priv
2314babef07SSarah Walker  */
2324babef07SSarah Walker struct pvr_file {
2334babef07SSarah Walker 	/**
2344babef07SSarah Walker 	 * @file: A reference to the parent &struct drm_file.
2354babef07SSarah Walker 	 *
2364babef07SSarah Walker 	 * Do not access this member directly, instead call from_pvr_file().
2374babef07SSarah Walker 	 */
2384babef07SSarah Walker 	struct drm_file *file;
2394babef07SSarah Walker 
2404babef07SSarah Walker 	/**
2414babef07SSarah Walker 	 * @pvr_dev: A reference to the powervr-specific wrapper for the
2424babef07SSarah Walker 	 *           associated device. Saves on repeated calls to
2434babef07SSarah Walker 	 *           to_pvr_device().
2444babef07SSarah Walker 	 */
2454babef07SSarah Walker 	struct pvr_device *pvr_dev;
246ff5f643dSDonald Robson 
247ff5f643dSDonald Robson 	/**
248ff5f643dSDonald Robson 	 * @vm_ctx_handles: Array of VM contexts belonging to this file. Array
249ff5f643dSDonald Robson 	 * members are of type "struct pvr_vm_context *".
250ff5f643dSDonald Robson 	 *
251ff5f643dSDonald Robson 	 * This array is used to allocate handles returned to userspace.
252ff5f643dSDonald Robson 	 */
253ff5f643dSDonald Robson 	struct xarray vm_ctx_handles;
2544babef07SSarah Walker };
2554babef07SSarah Walker 
256f99f5f3eSSarah Walker /**
257f99f5f3eSSarah Walker  * PVR_HAS_FEATURE() - Tests whether a PowerVR device has a given feature
258f99f5f3eSSarah Walker  * @pvr_dev: [IN] Target PowerVR device.
259f99f5f3eSSarah Walker  * @feature: [IN] Hardware feature name.
260f99f5f3eSSarah Walker  *
261f99f5f3eSSarah Walker  * Feature names are derived from those found in &struct pvr_device_features by
262f99f5f3eSSarah Walker  * dropping the 'has_' prefix, which is applied by this macro.
263f99f5f3eSSarah Walker  *
264f99f5f3eSSarah Walker  * Return:
265f99f5f3eSSarah Walker  *  * true if the named feature is present in the hardware
266f99f5f3eSSarah Walker  *  * false if the named feature is not present in the hardware
267f99f5f3eSSarah Walker  */
268f99f5f3eSSarah Walker #define PVR_HAS_FEATURE(pvr_dev, feature) ((pvr_dev)->features.has_##feature)
269f99f5f3eSSarah Walker 
270f99f5f3eSSarah Walker /**
271f99f5f3eSSarah Walker  * PVR_FEATURE_VALUE() - Gets a PowerVR device feature value
272f99f5f3eSSarah Walker  * @pvr_dev: [IN] Target PowerVR device.
273f99f5f3eSSarah Walker  * @feature: [IN] Feature name.
274f99f5f3eSSarah Walker  * @value_out: [OUT] Feature value.
275f99f5f3eSSarah Walker  *
276f99f5f3eSSarah Walker  * This macro will get a feature value for those features that have values.
277f99f5f3eSSarah Walker  * If the feature is not present, nothing will be stored to @value_out.
278f99f5f3eSSarah Walker  *
279f99f5f3eSSarah Walker  * Feature names are derived from those found in &struct pvr_device_features by
280f99f5f3eSSarah Walker  * dropping the 'has_' prefix.
281f99f5f3eSSarah Walker  *
282f99f5f3eSSarah Walker  * Return:
283f99f5f3eSSarah Walker  *  * 0 on success, or
284f99f5f3eSSarah Walker  *  * -%EINVAL if the named feature is not present in the hardware
285f99f5f3eSSarah Walker  */
286f99f5f3eSSarah Walker #define PVR_FEATURE_VALUE(pvr_dev, feature, value_out)             \
287f99f5f3eSSarah Walker 	({                                                         \
288f99f5f3eSSarah Walker 		struct pvr_device *_pvr_dev = pvr_dev;             \
289f99f5f3eSSarah Walker 		int _ret = -EINVAL;                                \
290f99f5f3eSSarah Walker 		if (_pvr_dev->features.has_##feature) {            \
291f99f5f3eSSarah Walker 			*(value_out) = _pvr_dev->features.feature; \
292f99f5f3eSSarah Walker 			_ret = 0;                                  \
293f99f5f3eSSarah Walker 		}                                                  \
294f99f5f3eSSarah Walker 		_ret;                                              \
295f99f5f3eSSarah Walker 	})
296f99f5f3eSSarah Walker 
297f99f5f3eSSarah Walker /**
298f99f5f3eSSarah Walker  * PVR_HAS_QUIRK() - Tests whether a physical device has a given quirk
299f99f5f3eSSarah Walker  * @pvr_dev: [IN] Target PowerVR device.
300f99f5f3eSSarah Walker  * @quirk: [IN] Hardware quirk name.
301f99f5f3eSSarah Walker  *
302f99f5f3eSSarah Walker  * Quirk numbers are derived from those found in #pvr_device_quirks by
303f99f5f3eSSarah Walker  * dropping the 'has_brn' prefix, which is applied by this macro.
304f99f5f3eSSarah Walker  *
305f99f5f3eSSarah Walker  * Returns
306f99f5f3eSSarah Walker  *  * true if the quirk is present in the hardware, or
307f99f5f3eSSarah Walker  *  * false if the quirk is not present in the hardware.
308f99f5f3eSSarah Walker  */
309f99f5f3eSSarah Walker #define PVR_HAS_QUIRK(pvr_dev, quirk) ((pvr_dev)->quirks.has_brn##quirk)
310f99f5f3eSSarah Walker 
311f99f5f3eSSarah Walker /**
312f99f5f3eSSarah Walker  * PVR_HAS_ENHANCEMENT() - Tests whether a physical device has a given
313f99f5f3eSSarah Walker  *                         enhancement
314f99f5f3eSSarah Walker  * @pvr_dev: [IN] Target PowerVR device.
315f99f5f3eSSarah Walker  * @enhancement: [IN] Hardware enhancement name.
316f99f5f3eSSarah Walker  *
317f99f5f3eSSarah Walker  * Enhancement numbers are derived from those found in #pvr_device_enhancements
318f99f5f3eSSarah Walker  * by dropping the 'has_ern' prefix, which is applied by this macro.
319f99f5f3eSSarah Walker  *
320f99f5f3eSSarah Walker  * Returns
321f99f5f3eSSarah Walker  *  * true if the enhancement is present in the hardware, or
322f99f5f3eSSarah Walker  *  * false if the enhancement is not present in the hardware.
323f99f5f3eSSarah Walker  */
324f99f5f3eSSarah Walker #define PVR_HAS_ENHANCEMENT(pvr_dev, enhancement) ((pvr_dev)->enhancements.has_ern##enhancement)
325f99f5f3eSSarah Walker 
3264babef07SSarah Walker #define from_pvr_device(pvr_dev) (&(pvr_dev)->base)
3274babef07SSarah Walker 
3284babef07SSarah Walker #define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base)
3294babef07SSarah Walker 
3304babef07SSarah Walker #define from_pvr_file(pvr_file) ((pvr_file)->file)
3314babef07SSarah Walker 
3324babef07SSarah Walker #define to_pvr_file(file) ((file)->driver_priv)
3334babef07SSarah Walker 
334f99f5f3eSSarah Walker /**
335f99f5f3eSSarah Walker  * PVR_PACKED_BVNC() - Packs B, V, N and C values into a 64-bit unsigned integer
336f99f5f3eSSarah Walker  * @b: Branch ID.
337f99f5f3eSSarah Walker  * @v: Version ID.
338f99f5f3eSSarah Walker  * @n: Number of scalable units.
339f99f5f3eSSarah Walker  * @c: Config ID.
340f99f5f3eSSarah Walker  *
341f99f5f3eSSarah Walker  * The packed layout is as follows:
342f99f5f3eSSarah Walker  *
343f99f5f3eSSarah Walker  *    +--------+--------+--------+-------+
344f99f5f3eSSarah Walker  *    | 63..48 | 47..32 | 31..16 | 15..0 |
345f99f5f3eSSarah Walker  *    +========+========+========+=======+
346f99f5f3eSSarah Walker  *    | B      | V      | N      | C     |
347f99f5f3eSSarah Walker  *    +--------+--------+--------+-------+
348f99f5f3eSSarah Walker  *
349f99f5f3eSSarah Walker  * pvr_gpu_id_to_packed_bvnc() should be used instead of this macro when a
350f99f5f3eSSarah Walker  * &struct pvr_gpu_id is available in order to ensure proper type checking.
351f99f5f3eSSarah Walker  *
352f99f5f3eSSarah Walker  * Return: Packed BVNC.
353f99f5f3eSSarah Walker  */
354f99f5f3eSSarah Walker /* clang-format off */
355f99f5f3eSSarah Walker #define PVR_PACKED_BVNC(b, v, n, c) \
356f99f5f3eSSarah Walker 	((((u64)(b) & GENMASK_ULL(15, 0)) << 48) | \
357f99f5f3eSSarah Walker 	 (((u64)(v) & GENMASK_ULL(15, 0)) << 32) | \
358f99f5f3eSSarah Walker 	 (((u64)(n) & GENMASK_ULL(15, 0)) << 16) | \
359f99f5f3eSSarah Walker 	 (((u64)(c) & GENMASK_ULL(15, 0)) <<  0))
360f99f5f3eSSarah Walker /* clang-format on */
361f99f5f3eSSarah Walker 
362f99f5f3eSSarah Walker /**
363f99f5f3eSSarah Walker  * pvr_gpu_id_to_packed_bvnc() - Packs B, V, N and C values into a 64-bit
364f99f5f3eSSarah Walker  * unsigned integer
365f99f5f3eSSarah Walker  * @gpu_id: GPU ID.
366f99f5f3eSSarah Walker  *
367f99f5f3eSSarah Walker  * The packed layout is as follows:
368f99f5f3eSSarah Walker  *
369f99f5f3eSSarah Walker  *    +--------+--------+--------+-------+
370f99f5f3eSSarah Walker  *    | 63..48 | 47..32 | 31..16 | 15..0 |
371f99f5f3eSSarah Walker  *    +========+========+========+=======+
372f99f5f3eSSarah Walker  *    | B      | V      | N      | C     |
373f99f5f3eSSarah Walker  *    +--------+--------+--------+-------+
374f99f5f3eSSarah Walker  *
375f99f5f3eSSarah Walker  * This should be used in preference to PVR_PACKED_BVNC() when a &struct
376f99f5f3eSSarah Walker  * pvr_gpu_id is available in order to ensure proper type checking.
377f99f5f3eSSarah Walker  *
378f99f5f3eSSarah Walker  * Return: Packed BVNC.
379f99f5f3eSSarah Walker  */
380f99f5f3eSSarah Walker static __always_inline u64
381f99f5f3eSSarah Walker pvr_gpu_id_to_packed_bvnc(struct pvr_gpu_id *gpu_id)
382f99f5f3eSSarah Walker {
383f99f5f3eSSarah Walker 	return PVR_PACKED_BVNC(gpu_id->b, gpu_id->v, gpu_id->n, gpu_id->c);
384f99f5f3eSSarah Walker }
385f99f5f3eSSarah Walker 
386f99f5f3eSSarah Walker static __always_inline void
387f99f5f3eSSarah Walker packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id)
388f99f5f3eSSarah Walker {
389f99f5f3eSSarah Walker 	gpu_id->b = (bvnc & GENMASK_ULL(63, 48)) >> 48;
390f99f5f3eSSarah Walker 	gpu_id->v = (bvnc & GENMASK_ULL(47, 32)) >> 32;
391f99f5f3eSSarah Walker 	gpu_id->n = (bvnc & GENMASK_ULL(31, 16)) >> 16;
392f99f5f3eSSarah Walker 	gpu_id->c = bvnc & GENMASK_ULL(15, 0);
393f99f5f3eSSarah Walker }
394f99f5f3eSSarah Walker 
3951f88f017SSarah Walker int pvr_device_init(struct pvr_device *pvr_dev);
3961f88f017SSarah Walker void pvr_device_fini(struct pvr_device *pvr_dev);
3971f88f017SSarah Walker 
398f99f5f3eSSarah Walker bool
399f99f5f3eSSarah Walker pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk);
400f99f5f3eSSarah Walker bool
401f99f5f3eSSarah Walker pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement);
402f99f5f3eSSarah Walker bool
403f99f5f3eSSarah Walker pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature);
404f99f5f3eSSarah Walker 
4051f88f017SSarah Walker /**
4061f88f017SSarah Walker  * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register
4071f88f017SSarah Walker  * @val: Value of the target register.
4081f88f017SSarah Walker  * @field: Field specifier, as defined in "pvr_rogue_cr_defs.h".
4091f88f017SSarah Walker  *
4101f88f017SSarah Walker  * Return: The extracted field.
4111f88f017SSarah Walker  */
4121f88f017SSarah Walker #define PVR_CR_FIELD_GET(val, field) FIELD_GET(~ROGUE_CR_##field##_CLRMSK, val)
4131f88f017SSarah Walker 
4141f88f017SSarah Walker /**
4151f88f017SSarah Walker  * pvr_cr_read32() - Read a 32-bit register from a PowerVR device
4161f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4171f88f017SSarah Walker  * @reg: Target register.
4181f88f017SSarah Walker  *
4191f88f017SSarah Walker  * Return: The value of the requested register.
4201f88f017SSarah Walker  */
4211f88f017SSarah Walker static __always_inline u32
4221f88f017SSarah Walker pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg)
4231f88f017SSarah Walker {
4241f88f017SSarah Walker 	return ioread32(pvr_dev->regs + reg);
4251f88f017SSarah Walker }
4261f88f017SSarah Walker 
4271f88f017SSarah Walker /**
4281f88f017SSarah Walker  * pvr_cr_read64() - Read a 64-bit register from a PowerVR device
4291f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4301f88f017SSarah Walker  * @reg: Target register.
4311f88f017SSarah Walker  *
4321f88f017SSarah Walker  * Return: The value of the requested register.
4331f88f017SSarah Walker  */
4341f88f017SSarah Walker static __always_inline u64
4351f88f017SSarah Walker pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg)
4361f88f017SSarah Walker {
4371f88f017SSarah Walker 	return ioread64(pvr_dev->regs + reg);
4381f88f017SSarah Walker }
4391f88f017SSarah Walker 
4401f88f017SSarah Walker /**
4411f88f017SSarah Walker  * pvr_cr_write32() - Write to a 32-bit register in a PowerVR device
4421f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4431f88f017SSarah Walker  * @reg: Target register.
4441f88f017SSarah Walker  * @val: Value to write.
4451f88f017SSarah Walker  */
4461f88f017SSarah Walker static __always_inline void
4471f88f017SSarah Walker pvr_cr_write32(struct pvr_device *pvr_dev, u32 reg, u32 val)
4481f88f017SSarah Walker {
4491f88f017SSarah Walker 	iowrite32(val, pvr_dev->regs + reg);
4501f88f017SSarah Walker }
4511f88f017SSarah Walker 
4521f88f017SSarah Walker /**
4531f88f017SSarah Walker  * pvr_cr_write64() - Write to a 64-bit register in a PowerVR device
4541f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4551f88f017SSarah Walker  * @reg: Target register.
4561f88f017SSarah Walker  * @val: Value to write.
4571f88f017SSarah Walker  */
4581f88f017SSarah Walker static __always_inline void
4591f88f017SSarah Walker pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val)
4601f88f017SSarah Walker {
4611f88f017SSarah Walker 	iowrite64(val, pvr_dev->regs + reg);
4621f88f017SSarah Walker }
4631f88f017SSarah Walker 
4641f88f017SSarah Walker /**
4651f88f017SSarah Walker  * pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by
4661f88f017SSarah Walker  *                       polling
4671f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4681f88f017SSarah Walker  * @reg_addr: Address of register.
4691f88f017SSarah Walker  * @reg_value: Expected register value (after masking).
4701f88f017SSarah Walker  * @reg_mask: Mask of bits valid for comparison with @reg_value.
4711f88f017SSarah Walker  * @timeout_usec: Timeout length, in us.
4721f88f017SSarah Walker  *
4731f88f017SSarah Walker  * Returns:
4741f88f017SSarah Walker  *  * 0 on success, or
4751f88f017SSarah Walker  *  * -%ETIMEDOUT on timeout.
4761f88f017SSarah Walker  */
4771f88f017SSarah Walker static __always_inline int
4781f88f017SSarah Walker pvr_cr_poll_reg32(struct pvr_device *pvr_dev, u32 reg_addr, u32 reg_value,
4791f88f017SSarah Walker 		  u32 reg_mask, u64 timeout_usec)
4801f88f017SSarah Walker {
4811f88f017SSarah Walker 	u32 value;
4821f88f017SSarah Walker 
4831f88f017SSarah Walker 	return readl_poll_timeout(pvr_dev->regs + reg_addr, value,
4841f88f017SSarah Walker 		(value & reg_mask) == reg_value, 0, timeout_usec);
4851f88f017SSarah Walker }
4861f88f017SSarah Walker 
4871f88f017SSarah Walker /**
4881f88f017SSarah Walker  * pvr_cr_poll_reg64() - Wait for a 64-bit register to match a given value by
4891f88f017SSarah Walker  *                       polling
4901f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
4911f88f017SSarah Walker  * @reg_addr: Address of register.
4921f88f017SSarah Walker  * @reg_value: Expected register value (after masking).
4931f88f017SSarah Walker  * @reg_mask: Mask of bits valid for comparison with @reg_value.
4941f88f017SSarah Walker  * @timeout_usec: Timeout length, in us.
4951f88f017SSarah Walker  *
4961f88f017SSarah Walker  * Returns:
4971f88f017SSarah Walker  *  * 0 on success, or
4981f88f017SSarah Walker  *  * -%ETIMEDOUT on timeout.
4991f88f017SSarah Walker  */
5001f88f017SSarah Walker static __always_inline int
5011f88f017SSarah Walker pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value,
5021f88f017SSarah Walker 		  u64 reg_mask, u64 timeout_usec)
5031f88f017SSarah Walker {
5041f88f017SSarah Walker 	u64 value;
5051f88f017SSarah Walker 
5061f88f017SSarah Walker 	return readq_poll_timeout(pvr_dev->regs + reg_addr, value,
5071f88f017SSarah Walker 		(value & reg_mask) == reg_value, 0, timeout_usec);
5081f88f017SSarah Walker }
5091f88f017SSarah Walker 
5104babef07SSarah Walker /**
511f99f5f3eSSarah Walker  * pvr_round_up_to_cacheline_size() - Round up a provided size to be cacheline
512f99f5f3eSSarah Walker  *                                    aligned
513f99f5f3eSSarah Walker  * @pvr_dev: Target PowerVR device.
514f99f5f3eSSarah Walker  * @size: Initial size, in bytes.
515f99f5f3eSSarah Walker  *
516f99f5f3eSSarah Walker  * Returns:
517f99f5f3eSSarah Walker  *  * Size aligned to cacheline size.
518f99f5f3eSSarah Walker  */
519f99f5f3eSSarah Walker static __always_inline size_t
520f99f5f3eSSarah Walker pvr_round_up_to_cacheline_size(struct pvr_device *pvr_dev, size_t size)
521f99f5f3eSSarah Walker {
522f99f5f3eSSarah Walker 	u16 slc_cacheline_size_bits = 0;
523f99f5f3eSSarah Walker 	u16 slc_cacheline_size_bytes;
524f99f5f3eSSarah Walker 
525f99f5f3eSSarah Walker 	WARN_ON(!PVR_HAS_FEATURE(pvr_dev, slc_cache_line_size_bits));
526f99f5f3eSSarah Walker 	PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits,
527f99f5f3eSSarah Walker 			  &slc_cacheline_size_bits);
528f99f5f3eSSarah Walker 	slc_cacheline_size_bytes = slc_cacheline_size_bits / 8;
529f99f5f3eSSarah Walker 
530f99f5f3eSSarah Walker 	return round_up(size, slc_cacheline_size_bytes);
531f99f5f3eSSarah Walker }
532f99f5f3eSSarah Walker 
533f99f5f3eSSarah Walker /**
5344babef07SSarah Walker  * DOC: IOCTL validation helpers
5354babef07SSarah Walker  *
5364babef07SSarah Walker  * To validate the constraints imposed on IOCTL argument structs, a collection
5374babef07SSarah Walker  * of macros and helper functions exist in ``pvr_device.h``.
5384babef07SSarah Walker  *
5394babef07SSarah Walker  * Of the current helpers, it should only be necessary to call
5404babef07SSarah Walker  * PVR_IOCTL_UNION_PADDING_CHECK() directly. This macro should be used once in
5414babef07SSarah Walker  * every code path which extracts a union member from a struct passed from
5424babef07SSarah Walker  * userspace.
5434babef07SSarah Walker  */
5444babef07SSarah Walker 
5454babef07SSarah Walker /**
5464babef07SSarah Walker  * pvr_ioctl_union_padding_check() - Validate that the implicit padding between
5474babef07SSarah Walker  * the end of a union member and the end of the union itself is zeroed.
5484babef07SSarah Walker  * @instance: Pointer to the instance of the struct to validate.
5494babef07SSarah Walker  * @union_offset: Offset into the type of @instance of the target union. Must
5504babef07SSarah Walker  * be 64-bit aligned.
5514babef07SSarah Walker  * @union_size: Size of the target union in the type of @instance. Must be
5524babef07SSarah Walker  * 64-bit aligned.
5534babef07SSarah Walker  * @member_size: Size of the target member in the target union specified by
5544babef07SSarah Walker  * @union_offset and @union_size. It is assumed that the offset of the target
5554babef07SSarah Walker  * member is zero relative to @union_offset. Must be 64-bit aligned.
5564babef07SSarah Walker  *
5574babef07SSarah Walker  * You probably want to use PVR_IOCTL_UNION_PADDING_CHECK() instead of calling
5584babef07SSarah Walker  * this function directly, since that macro abstracts away much of the setup,
5594babef07SSarah Walker  * and also provides some static validation. See its docs for details.
5604babef07SSarah Walker  *
5614babef07SSarah Walker  * Return:
5624babef07SSarah Walker  *  * %true if every byte between the end of the used member of the union and
5634babef07SSarah Walker  *    the end of that union is zeroed, or
5644babef07SSarah Walker  *  * %false otherwise.
5654babef07SSarah Walker  */
5664babef07SSarah Walker static __always_inline bool
5674babef07SSarah Walker pvr_ioctl_union_padding_check(void *instance, size_t union_offset,
5684babef07SSarah Walker 			      size_t union_size, size_t member_size)
5694babef07SSarah Walker {
5704babef07SSarah Walker 	/*
5714babef07SSarah Walker 	 * void pointer arithmetic is technically illegal - cast to a byte
5724babef07SSarah Walker 	 * pointer so this addition works safely.
5734babef07SSarah Walker 	 */
5744babef07SSarah Walker 	void *padding_start = ((u8 *)instance) + union_offset + member_size;
5754babef07SSarah Walker 	size_t padding_size = union_size - member_size;
5764babef07SSarah Walker 
5774babef07SSarah Walker 	return !memchr_inv(padding_start, 0, padding_size);
5784babef07SSarah Walker }
5794babef07SSarah Walker 
5804babef07SSarah Walker /**
5814babef07SSarah Walker  * PVR_STATIC_ASSERT_64BIT_ALIGNED() - Inline assertion for 64-bit alignment.
5824babef07SSarah Walker  * @static_expr_: Target expression to evaluate.
5834babef07SSarah Walker  *
5844babef07SSarah Walker  * If @static_expr_ does not evaluate to a constant integer which would be a
5854babef07SSarah Walker  * 64-bit aligned address (i.e. a multiple of 8), compilation will fail.
5864babef07SSarah Walker  *
5874babef07SSarah Walker  * Return:
5884babef07SSarah Walker  * The value of @static_expr_.
5894babef07SSarah Walker  */
5904babef07SSarah Walker #define PVR_STATIC_ASSERT_64BIT_ALIGNED(static_expr_)                     \
5914babef07SSarah Walker 	({                                                                \
5924babef07SSarah Walker 		static_assert(((static_expr_) & (sizeof(u64) - 1)) == 0); \
5934babef07SSarah Walker 		(static_expr_);                                           \
5944babef07SSarah Walker 	})
5954babef07SSarah Walker 
5964babef07SSarah Walker /**
5974babef07SSarah Walker  * PVR_IOCTL_UNION_PADDING_CHECK() - Validate that the implicit padding between
5984babef07SSarah Walker  * the end of a union member and the end of the union itself is zeroed.
5994babef07SSarah Walker  * @struct_instance_: An expression which evaluates to a pointer to a UAPI data
6004babef07SSarah Walker  * struct.
6014babef07SSarah Walker  * @union_: The name of the union member of @struct_instance_ to check. If the
6024babef07SSarah Walker  * union member is nested within the type of @struct_instance_, this may
6034babef07SSarah Walker  * contain the member access operator (".").
6044babef07SSarah Walker  * @member_: The name of the member of @union_ to assess.
6054babef07SSarah Walker  *
6064babef07SSarah Walker  * This is a wrapper around pvr_ioctl_union_padding_check() which performs
6074babef07SSarah Walker  * alignment checks and simplifies things for the caller.
6084babef07SSarah Walker  *
6094babef07SSarah Walker  * Return:
6104babef07SSarah Walker  *  * %true if every byte in @struct_instance_ between the end of @member_ and
6114babef07SSarah Walker  *    the end of @union_ is zeroed, or
6124babef07SSarah Walker  *  * %false otherwise.
6134babef07SSarah Walker  */
6144babef07SSarah Walker #define PVR_IOCTL_UNION_PADDING_CHECK(struct_instance_, union_, member_)     \
6154babef07SSarah Walker 	({                                                                   \
6164babef07SSarah Walker 		typeof(struct_instance_) __instance = (struct_instance_);    \
6174babef07SSarah Walker 		size_t __union_offset = PVR_STATIC_ASSERT_64BIT_ALIGNED(     \
6184babef07SSarah Walker 			offsetof(typeof(*__instance), union_));              \
6194babef07SSarah Walker 		size_t __union_size = PVR_STATIC_ASSERT_64BIT_ALIGNED(       \
6204babef07SSarah Walker 			sizeof(__instance->union_));                         \
6214babef07SSarah Walker 		size_t __member_size = PVR_STATIC_ASSERT_64BIT_ALIGNED(      \
6224babef07SSarah Walker 			sizeof(__instance->union_.member_));                 \
6234babef07SSarah Walker 		pvr_ioctl_union_padding_check(__instance, __union_offset,    \
6244babef07SSarah Walker 					      __union_size, __member_size);  \
6254babef07SSarah Walker 	})
6264babef07SSarah Walker 
627f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_META  0
628f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_MIPS  1
629f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_RISCV 2
630f99f5f3eSSarah Walker 
6314babef07SSarah Walker #endif /* PVR_DEVICE_H */
632