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