xref: /linux/drivers/gpu/drm/imagination/pvr_device.h (revision 1f88f017e6499261f46d3468befac7b1cdc96e52)
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 
74babef07SSarah Walker #include <drm/drm_device.h>
84babef07SSarah Walker #include <drm/drm_file.h>
94babef07SSarah Walker #include <drm/drm_mm.h>
104babef07SSarah Walker 
114babef07SSarah Walker #include <linux/bits.h>
124babef07SSarah Walker #include <linux/compiler_attributes.h>
134babef07SSarah Walker #include <linux/compiler_types.h>
14*1f88f017SSarah Walker #include <linux/io.h>
15*1f88f017SSarah Walker #include <linux/iopoll.h>
164babef07SSarah Walker #include <linux/kernel.h>
17*1f88f017SSarah Walker #include <linux/math.h>
18*1f88f017SSarah Walker #include <linux/mutex.h>
19*1f88f017SSarah Walker #include <linux/timer.h>
204babef07SSarah Walker #include <linux/types.h>
214babef07SSarah Walker #include <linux/wait.h>
22*1f88f017SSarah Walker #include <linux/workqueue.h>
23*1f88f017SSarah Walker #include <linux/xarray.h>
24*1f88f017SSarah Walker 
25*1f88f017SSarah Walker /* Forward declaration from <linux/clk.h>. */
26*1f88f017SSarah Walker struct clk;
27*1f88f017SSarah Walker 
28*1f88f017SSarah Walker /* Forward declaration from <linux/firmware.h>. */
29*1f88f017SSarah Walker struct firmware;
304babef07SSarah Walker 
314babef07SSarah Walker /**
324babef07SSarah Walker  * struct pvr_device - powervr-specific wrapper for &struct drm_device
334babef07SSarah Walker  */
344babef07SSarah Walker struct pvr_device {
354babef07SSarah Walker 	/**
364babef07SSarah Walker 	 * @base: The underlying &struct drm_device.
374babef07SSarah Walker 	 *
384babef07SSarah Walker 	 * Do not access this member directly, instead call
394babef07SSarah Walker 	 * from_pvr_device().
404babef07SSarah Walker 	 */
414babef07SSarah Walker 	struct drm_device base;
42*1f88f017SSarah Walker 
43*1f88f017SSarah Walker 	/**
44*1f88f017SSarah Walker 	 * @regs: Device control registers.
45*1f88f017SSarah Walker 	 *
46*1f88f017SSarah Walker 	 * These are mapped into memory when the device is initialized; that
47*1f88f017SSarah Walker 	 * location is where this pointer points.
48*1f88f017SSarah Walker 	 */
49*1f88f017SSarah Walker 	void __iomem *regs;
50*1f88f017SSarah Walker 
51*1f88f017SSarah Walker 	/**
52*1f88f017SSarah Walker 	 * @core_clk: General core clock.
53*1f88f017SSarah Walker 	 *
54*1f88f017SSarah Walker 	 * This is the primary clock used by the entire GPU core.
55*1f88f017SSarah Walker 	 */
56*1f88f017SSarah Walker 	struct clk *core_clk;
57*1f88f017SSarah Walker 
58*1f88f017SSarah Walker 	/**
59*1f88f017SSarah Walker 	 * @sys_clk: Optional system bus clock.
60*1f88f017SSarah Walker 	 *
61*1f88f017SSarah Walker 	 * This may be used on some platforms to provide an independent clock to the SoC Interface
62*1f88f017SSarah Walker 	 * (SOCIF). If present, this needs to be enabled/disabled together with @core_clk.
63*1f88f017SSarah Walker 	 */
64*1f88f017SSarah Walker 	struct clk *sys_clk;
65*1f88f017SSarah Walker 
66*1f88f017SSarah Walker 	/**
67*1f88f017SSarah Walker 	 * @mem_clk: Optional memory clock.
68*1f88f017SSarah Walker 	 *
69*1f88f017SSarah Walker 	 * This may be used on some platforms to provide an independent clock to the Memory
70*1f88f017SSarah Walker 	 * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk.
71*1f88f017SSarah Walker 	 */
72*1f88f017SSarah Walker 	struct clk *mem_clk;
734babef07SSarah Walker };
744babef07SSarah Walker 
754babef07SSarah Walker /**
764babef07SSarah Walker  * struct pvr_file - powervr-specific data to be assigned to &struct
774babef07SSarah Walker  * drm_file.driver_priv
784babef07SSarah Walker  */
794babef07SSarah Walker struct pvr_file {
804babef07SSarah Walker 	/**
814babef07SSarah Walker 	 * @file: A reference to the parent &struct drm_file.
824babef07SSarah Walker 	 *
834babef07SSarah Walker 	 * Do not access this member directly, instead call from_pvr_file().
844babef07SSarah Walker 	 */
854babef07SSarah Walker 	struct drm_file *file;
864babef07SSarah Walker 
874babef07SSarah Walker 	/**
884babef07SSarah Walker 	 * @pvr_dev: A reference to the powervr-specific wrapper for the
894babef07SSarah Walker 	 *           associated device. Saves on repeated calls to
904babef07SSarah Walker 	 *           to_pvr_device().
914babef07SSarah Walker 	 */
924babef07SSarah Walker 	struct pvr_device *pvr_dev;
934babef07SSarah Walker };
944babef07SSarah Walker 
954babef07SSarah Walker #define from_pvr_device(pvr_dev) (&(pvr_dev)->base)
964babef07SSarah Walker 
974babef07SSarah Walker #define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base)
984babef07SSarah Walker 
994babef07SSarah Walker #define from_pvr_file(pvr_file) ((pvr_file)->file)
1004babef07SSarah Walker 
1014babef07SSarah Walker #define to_pvr_file(file) ((file)->driver_priv)
1024babef07SSarah Walker 
103*1f88f017SSarah Walker int pvr_device_init(struct pvr_device *pvr_dev);
104*1f88f017SSarah Walker void pvr_device_fini(struct pvr_device *pvr_dev);
105*1f88f017SSarah Walker 
106*1f88f017SSarah Walker /**
107*1f88f017SSarah Walker  * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register
108*1f88f017SSarah Walker  * @val: Value of the target register.
109*1f88f017SSarah Walker  * @field: Field specifier, as defined in "pvr_rogue_cr_defs.h".
110*1f88f017SSarah Walker  *
111*1f88f017SSarah Walker  * Return: The extracted field.
112*1f88f017SSarah Walker  */
113*1f88f017SSarah Walker #define PVR_CR_FIELD_GET(val, field) FIELD_GET(~ROGUE_CR_##field##_CLRMSK, val)
114*1f88f017SSarah Walker 
115*1f88f017SSarah Walker /**
116*1f88f017SSarah Walker  * pvr_cr_read32() - Read a 32-bit register from a PowerVR device
117*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
118*1f88f017SSarah Walker  * @reg: Target register.
119*1f88f017SSarah Walker  *
120*1f88f017SSarah Walker  * Return: The value of the requested register.
121*1f88f017SSarah Walker  */
122*1f88f017SSarah Walker static __always_inline u32
123*1f88f017SSarah Walker pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg)
124*1f88f017SSarah Walker {
125*1f88f017SSarah Walker 	return ioread32(pvr_dev->regs + reg);
126*1f88f017SSarah Walker }
127*1f88f017SSarah Walker 
128*1f88f017SSarah Walker /**
129*1f88f017SSarah Walker  * pvr_cr_read64() - Read a 64-bit register from a PowerVR device
130*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
131*1f88f017SSarah Walker  * @reg: Target register.
132*1f88f017SSarah Walker  *
133*1f88f017SSarah Walker  * Return: The value of the requested register.
134*1f88f017SSarah Walker  */
135*1f88f017SSarah Walker static __always_inline u64
136*1f88f017SSarah Walker pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg)
137*1f88f017SSarah Walker {
138*1f88f017SSarah Walker 	return ioread64(pvr_dev->regs + reg);
139*1f88f017SSarah Walker }
140*1f88f017SSarah Walker 
141*1f88f017SSarah Walker /**
142*1f88f017SSarah Walker  * pvr_cr_write32() - Write to a 32-bit register in a PowerVR device
143*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
144*1f88f017SSarah Walker  * @reg: Target register.
145*1f88f017SSarah Walker  * @val: Value to write.
146*1f88f017SSarah Walker  */
147*1f88f017SSarah Walker static __always_inline void
148*1f88f017SSarah Walker pvr_cr_write32(struct pvr_device *pvr_dev, u32 reg, u32 val)
149*1f88f017SSarah Walker {
150*1f88f017SSarah Walker 	iowrite32(val, pvr_dev->regs + reg);
151*1f88f017SSarah Walker }
152*1f88f017SSarah Walker 
153*1f88f017SSarah Walker /**
154*1f88f017SSarah Walker  * pvr_cr_write64() - Write to a 64-bit register in a PowerVR device
155*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
156*1f88f017SSarah Walker  * @reg: Target register.
157*1f88f017SSarah Walker  * @val: Value to write.
158*1f88f017SSarah Walker  */
159*1f88f017SSarah Walker static __always_inline void
160*1f88f017SSarah Walker pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val)
161*1f88f017SSarah Walker {
162*1f88f017SSarah Walker 	iowrite64(val, pvr_dev->regs + reg);
163*1f88f017SSarah Walker }
164*1f88f017SSarah Walker 
165*1f88f017SSarah Walker /**
166*1f88f017SSarah Walker  * pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by
167*1f88f017SSarah Walker  *                       polling
168*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
169*1f88f017SSarah Walker  * @reg_addr: Address of register.
170*1f88f017SSarah Walker  * @reg_value: Expected register value (after masking).
171*1f88f017SSarah Walker  * @reg_mask: Mask of bits valid for comparison with @reg_value.
172*1f88f017SSarah Walker  * @timeout_usec: Timeout length, in us.
173*1f88f017SSarah Walker  *
174*1f88f017SSarah Walker  * Returns:
175*1f88f017SSarah Walker  *  * 0 on success, or
176*1f88f017SSarah Walker  *  * -%ETIMEDOUT on timeout.
177*1f88f017SSarah Walker  */
178*1f88f017SSarah Walker static __always_inline int
179*1f88f017SSarah Walker pvr_cr_poll_reg32(struct pvr_device *pvr_dev, u32 reg_addr, u32 reg_value,
180*1f88f017SSarah Walker 		  u32 reg_mask, u64 timeout_usec)
181*1f88f017SSarah Walker {
182*1f88f017SSarah Walker 	u32 value;
183*1f88f017SSarah Walker 
184*1f88f017SSarah Walker 	return readl_poll_timeout(pvr_dev->regs + reg_addr, value,
185*1f88f017SSarah Walker 		(value & reg_mask) == reg_value, 0, timeout_usec);
186*1f88f017SSarah Walker }
187*1f88f017SSarah Walker 
188*1f88f017SSarah Walker /**
189*1f88f017SSarah Walker  * pvr_cr_poll_reg64() - Wait for a 64-bit register to match a given value by
190*1f88f017SSarah Walker  *                       polling
191*1f88f017SSarah Walker  * @pvr_dev: Target PowerVR device.
192*1f88f017SSarah Walker  * @reg_addr: Address of register.
193*1f88f017SSarah Walker  * @reg_value: Expected register value (after masking).
194*1f88f017SSarah Walker  * @reg_mask: Mask of bits valid for comparison with @reg_value.
195*1f88f017SSarah Walker  * @timeout_usec: Timeout length, in us.
196*1f88f017SSarah Walker  *
197*1f88f017SSarah Walker  * Returns:
198*1f88f017SSarah Walker  *  * 0 on success, or
199*1f88f017SSarah Walker  *  * -%ETIMEDOUT on timeout.
200*1f88f017SSarah Walker  */
201*1f88f017SSarah Walker static __always_inline int
202*1f88f017SSarah Walker pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value,
203*1f88f017SSarah Walker 		  u64 reg_mask, u64 timeout_usec)
204*1f88f017SSarah Walker {
205*1f88f017SSarah Walker 	u64 value;
206*1f88f017SSarah Walker 
207*1f88f017SSarah Walker 	return readq_poll_timeout(pvr_dev->regs + reg_addr, value,
208*1f88f017SSarah Walker 		(value & reg_mask) == reg_value, 0, timeout_usec);
209*1f88f017SSarah Walker }
210*1f88f017SSarah Walker 
2114babef07SSarah Walker /**
2124babef07SSarah Walker  * DOC: IOCTL validation helpers
2134babef07SSarah Walker  *
2144babef07SSarah Walker  * To validate the constraints imposed on IOCTL argument structs, a collection
2154babef07SSarah Walker  * of macros and helper functions exist in ``pvr_device.h``.
2164babef07SSarah Walker  *
2174babef07SSarah Walker  * Of the current helpers, it should only be necessary to call
2184babef07SSarah Walker  * PVR_IOCTL_UNION_PADDING_CHECK() directly. This macro should be used once in
2194babef07SSarah Walker  * every code path which extracts a union member from a struct passed from
2204babef07SSarah Walker  * userspace.
2214babef07SSarah Walker  */
2224babef07SSarah Walker 
2234babef07SSarah Walker /**
2244babef07SSarah Walker  * pvr_ioctl_union_padding_check() - Validate that the implicit padding between
2254babef07SSarah Walker  * the end of a union member and the end of the union itself is zeroed.
2264babef07SSarah Walker  * @instance: Pointer to the instance of the struct to validate.
2274babef07SSarah Walker  * @union_offset: Offset into the type of @instance of the target union. Must
2284babef07SSarah Walker  * be 64-bit aligned.
2294babef07SSarah Walker  * @union_size: Size of the target union in the type of @instance. Must be
2304babef07SSarah Walker  * 64-bit aligned.
2314babef07SSarah Walker  * @member_size: Size of the target member in the target union specified by
2324babef07SSarah Walker  * @union_offset and @union_size. It is assumed that the offset of the target
2334babef07SSarah Walker  * member is zero relative to @union_offset. Must be 64-bit aligned.
2344babef07SSarah Walker  *
2354babef07SSarah Walker  * You probably want to use PVR_IOCTL_UNION_PADDING_CHECK() instead of calling
2364babef07SSarah Walker  * this function directly, since that macro abstracts away much of the setup,
2374babef07SSarah Walker  * and also provides some static validation. See its docs for details.
2384babef07SSarah Walker  *
2394babef07SSarah Walker  * Return:
2404babef07SSarah Walker  *  * %true if every byte between the end of the used member of the union and
2414babef07SSarah Walker  *    the end of that union is zeroed, or
2424babef07SSarah Walker  *  * %false otherwise.
2434babef07SSarah Walker  */
2444babef07SSarah Walker static __always_inline bool
2454babef07SSarah Walker pvr_ioctl_union_padding_check(void *instance, size_t union_offset,
2464babef07SSarah Walker 			      size_t union_size, size_t member_size)
2474babef07SSarah Walker {
2484babef07SSarah Walker 	/*
2494babef07SSarah Walker 	 * void pointer arithmetic is technically illegal - cast to a byte
2504babef07SSarah Walker 	 * pointer so this addition works safely.
2514babef07SSarah Walker 	 */
2524babef07SSarah Walker 	void *padding_start = ((u8 *)instance) + union_offset + member_size;
2534babef07SSarah Walker 	size_t padding_size = union_size - member_size;
2544babef07SSarah Walker 
2554babef07SSarah Walker 	return !memchr_inv(padding_start, 0, padding_size);
2564babef07SSarah Walker }
2574babef07SSarah Walker 
2584babef07SSarah Walker /**
2594babef07SSarah Walker  * PVR_STATIC_ASSERT_64BIT_ALIGNED() - Inline assertion for 64-bit alignment.
2604babef07SSarah Walker  * @static_expr_: Target expression to evaluate.
2614babef07SSarah Walker  *
2624babef07SSarah Walker  * If @static_expr_ does not evaluate to a constant integer which would be a
2634babef07SSarah Walker  * 64-bit aligned address (i.e. a multiple of 8), compilation will fail.
2644babef07SSarah Walker  *
2654babef07SSarah Walker  * Return:
2664babef07SSarah Walker  * The value of @static_expr_.
2674babef07SSarah Walker  */
2684babef07SSarah Walker #define PVR_STATIC_ASSERT_64BIT_ALIGNED(static_expr_)                     \
2694babef07SSarah Walker 	({                                                                \
2704babef07SSarah Walker 		static_assert(((static_expr_) & (sizeof(u64) - 1)) == 0); \
2714babef07SSarah Walker 		(static_expr_);                                           \
2724babef07SSarah Walker 	})
2734babef07SSarah Walker 
2744babef07SSarah Walker /**
2754babef07SSarah Walker  * PVR_IOCTL_UNION_PADDING_CHECK() - Validate that the implicit padding between
2764babef07SSarah Walker  * the end of a union member and the end of the union itself is zeroed.
2774babef07SSarah Walker  * @struct_instance_: An expression which evaluates to a pointer to a UAPI data
2784babef07SSarah Walker  * struct.
2794babef07SSarah Walker  * @union_: The name of the union member of @struct_instance_ to check. If the
2804babef07SSarah Walker  * union member is nested within the type of @struct_instance_, this may
2814babef07SSarah Walker  * contain the member access operator (".").
2824babef07SSarah Walker  * @member_: The name of the member of @union_ to assess.
2834babef07SSarah Walker  *
2844babef07SSarah Walker  * This is a wrapper around pvr_ioctl_union_padding_check() which performs
2854babef07SSarah Walker  * alignment checks and simplifies things for the caller.
2864babef07SSarah Walker  *
2874babef07SSarah Walker  * Return:
2884babef07SSarah Walker  *  * %true if every byte in @struct_instance_ between the end of @member_ and
2894babef07SSarah Walker  *    the end of @union_ is zeroed, or
2904babef07SSarah Walker  *  * %false otherwise.
2914babef07SSarah Walker  */
2924babef07SSarah Walker #define PVR_IOCTL_UNION_PADDING_CHECK(struct_instance_, union_, member_)     \
2934babef07SSarah Walker 	({                                                                   \
2944babef07SSarah Walker 		typeof(struct_instance_) __instance = (struct_instance_);    \
2954babef07SSarah Walker 		size_t __union_offset = PVR_STATIC_ASSERT_64BIT_ALIGNED(     \
2964babef07SSarah Walker 			offsetof(typeof(*__instance), union_));              \
2974babef07SSarah Walker 		size_t __union_size = PVR_STATIC_ASSERT_64BIT_ALIGNED(       \
2984babef07SSarah Walker 			sizeof(__instance->union_));                         \
2994babef07SSarah Walker 		size_t __member_size = PVR_STATIC_ASSERT_64BIT_ALIGNED(      \
3004babef07SSarah Walker 			sizeof(__instance->union_.member_));                 \
3014babef07SSarah Walker 		pvr_ioctl_union_padding_check(__instance, __union_offset,    \
3024babef07SSarah Walker 					      __union_size, __member_size);  \
3034babef07SSarah Walker 	})
3044babef07SSarah Walker 
3054babef07SSarah Walker #endif /* PVR_DEVICE_H */
306