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