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 7cc1aeedbSSarah Walker #include "pvr_ccb.h" 8f99f5f3eSSarah Walker #include "pvr_device_info.h" 9f99f5f3eSSarah Walker #include "pvr_fw.h" 10cb56cd61SSarah Walker #include "pvr_params.h" 11d2d79d29SSarah Walker #include "pvr_rogue_fwif_stream.h" 12d2d79d29SSarah Walker #include "pvr_stream.h" 13f99f5f3eSSarah Walker 144babef07SSarah Walker #include <drm/drm_device.h> 154babef07SSarah Walker #include <drm/drm_file.h> 164babef07SSarah Walker #include <drm/drm_mm.h> 174babef07SSarah Walker 184babef07SSarah Walker #include <linux/bits.h> 194babef07SSarah Walker #include <linux/compiler_attributes.h> 204babef07SSarah Walker #include <linux/compiler_types.h> 211f88f017SSarah Walker #include <linux/io.h> 221f88f017SSarah Walker #include <linux/iopoll.h> 234babef07SSarah Walker #include <linux/kernel.h> 241f88f017SSarah Walker #include <linux/math.h> 251f88f017SSarah Walker #include <linux/mutex.h> 26*b0ef514bSBrendan King #include <linux/spinlock_types.h> 271f88f017SSarah Walker #include <linux/timer.h> 284babef07SSarah Walker #include <linux/types.h> 294babef07SSarah Walker #include <linux/wait.h> 301f88f017SSarah Walker #include <linux/workqueue.h> 311f88f017SSarah Walker #include <linux/xarray.h> 321f88f017SSarah Walker 331f88f017SSarah Walker /* Forward declaration from <linux/clk.h>. */ 341f88f017SSarah Walker struct clk; 351f88f017SSarah Walker 361f88f017SSarah Walker /* Forward declaration from <linux/firmware.h>. */ 371f88f017SSarah Walker struct firmware; 384babef07SSarah Walker 394babef07SSarah Walker /** 40f99f5f3eSSarah Walker * struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device 41f99f5f3eSSarah Walker * @b: Branch ID. 42f99f5f3eSSarah Walker * @v: Version ID. 43f99f5f3eSSarah Walker * @n: Number of scalable units. 44f99f5f3eSSarah Walker * @c: Config ID. 45f99f5f3eSSarah Walker */ 46f99f5f3eSSarah Walker struct pvr_gpu_id { 47f99f5f3eSSarah Walker u16 b, v, n, c; 48f99f5f3eSSarah Walker }; 49f99f5f3eSSarah Walker 50f99f5f3eSSarah Walker /** 51f99f5f3eSSarah Walker * struct pvr_fw_version - Firmware version information 52f99f5f3eSSarah Walker * @major: Major version number. 53f99f5f3eSSarah Walker * @minor: Minor version number. 54f99f5f3eSSarah Walker */ 55f99f5f3eSSarah Walker struct pvr_fw_version { 56f99f5f3eSSarah Walker u16 major, minor; 57f99f5f3eSSarah Walker }; 58f99f5f3eSSarah Walker 59f99f5f3eSSarah Walker /** 604babef07SSarah Walker * struct pvr_device - powervr-specific wrapper for &struct drm_device 614babef07SSarah Walker */ 624babef07SSarah Walker struct pvr_device { 634babef07SSarah Walker /** 644babef07SSarah Walker * @base: The underlying &struct drm_device. 654babef07SSarah Walker * 664babef07SSarah Walker * Do not access this member directly, instead call 674babef07SSarah Walker * from_pvr_device(). 684babef07SSarah Walker */ 694babef07SSarah Walker struct drm_device base; 701f88f017SSarah Walker 71f99f5f3eSSarah Walker /** @gpu_id: GPU ID detected at runtime. */ 72f99f5f3eSSarah Walker struct pvr_gpu_id gpu_id; 73f99f5f3eSSarah Walker 74f99f5f3eSSarah Walker /** 75f99f5f3eSSarah Walker * @features: Hardware feature information. 76f99f5f3eSSarah Walker * 77f99f5f3eSSarah Walker * Do not access this member directly, instead use PVR_HAS_FEATURE() 78f99f5f3eSSarah Walker * or PVR_FEATURE_VALUE() macros. 79f99f5f3eSSarah Walker */ 80f99f5f3eSSarah Walker struct pvr_device_features features; 81f99f5f3eSSarah Walker 82f99f5f3eSSarah Walker /** 83f99f5f3eSSarah Walker * @quirks: Hardware quirk information. 84f99f5f3eSSarah Walker * 85f99f5f3eSSarah Walker * Do not access this member directly, instead use PVR_HAS_QUIRK(). 86f99f5f3eSSarah Walker */ 87f99f5f3eSSarah Walker struct pvr_device_quirks quirks; 88f99f5f3eSSarah Walker 89f99f5f3eSSarah Walker /** 90f99f5f3eSSarah Walker * @enhancements: Hardware enhancement information. 91f99f5f3eSSarah Walker * 92f99f5f3eSSarah Walker * Do not access this member directly, instead use 93f99f5f3eSSarah Walker * PVR_HAS_ENHANCEMENT(). 94f99f5f3eSSarah Walker */ 95f99f5f3eSSarah Walker struct pvr_device_enhancements enhancements; 96f99f5f3eSSarah Walker 97f99f5f3eSSarah Walker /** @fw_version: Firmware version detected at runtime. */ 98f99f5f3eSSarah Walker struct pvr_fw_version fw_version; 99f99f5f3eSSarah Walker 100927f3e02SSarah Walker /** @regs_resource: Resource representing device control registers. */ 101927f3e02SSarah Walker struct resource *regs_resource; 102927f3e02SSarah Walker 1031f88f017SSarah Walker /** 1041f88f017SSarah Walker * @regs: Device control registers. 1051f88f017SSarah Walker * 1061f88f017SSarah Walker * These are mapped into memory when the device is initialized; that 1071f88f017SSarah Walker * location is where this pointer points. 1081f88f017SSarah Walker */ 1091f88f017SSarah Walker void __iomem *regs; 1101f88f017SSarah Walker 1111f88f017SSarah Walker /** 1121f88f017SSarah Walker * @core_clk: General core clock. 1131f88f017SSarah Walker * 1141f88f017SSarah Walker * This is the primary clock used by the entire GPU core. 1151f88f017SSarah Walker */ 1161f88f017SSarah Walker struct clk *core_clk; 1171f88f017SSarah Walker 1181f88f017SSarah Walker /** 1191f88f017SSarah Walker * @sys_clk: Optional system bus clock. 1201f88f017SSarah Walker * 1211f88f017SSarah Walker * This may be used on some platforms to provide an independent clock to the SoC Interface 1221f88f017SSarah Walker * (SOCIF). If present, this needs to be enabled/disabled together with @core_clk. 1231f88f017SSarah Walker */ 1241f88f017SSarah Walker struct clk *sys_clk; 1251f88f017SSarah Walker 1261f88f017SSarah Walker /** 1271f88f017SSarah Walker * @mem_clk: Optional memory clock. 1281f88f017SSarah Walker * 1291f88f017SSarah Walker * This may be used on some platforms to provide an independent clock to the Memory 1301f88f017SSarah Walker * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk. 1311f88f017SSarah Walker */ 1321f88f017SSarah Walker struct clk *mem_clk; 133f99f5f3eSSarah Walker 134cc1aeedbSSarah Walker /** @irq: IRQ number. */ 135cc1aeedbSSarah Walker int irq; 136cc1aeedbSSarah Walker 137cc1aeedbSSarah Walker /** @fwccb: Firmware CCB. */ 138cc1aeedbSSarah Walker struct pvr_ccb fwccb; 139cc1aeedbSSarah Walker 140ff5f643dSDonald Robson /** 141ff5f643dSDonald Robson * @kernel_vm_ctx: Virtual memory context used for kernel mappings. 142ff5f643dSDonald Robson * 143ff5f643dSDonald Robson * This is used for mappings in the firmware address region when a META firmware processor 144ff5f643dSDonald Robson * is in use. 145ff5f643dSDonald Robson * 146ff5f643dSDonald Robson * When a MIPS firmware processor is in use, this will be %NULL. 147ff5f643dSDonald Robson */ 148ff5f643dSDonald Robson struct pvr_vm_context *kernel_vm_ctx; 149ff5f643dSDonald Robson 150f99f5f3eSSarah Walker /** @fw_dev: Firmware related data. */ 151f99f5f3eSSarah Walker struct pvr_fw_device fw_dev; 152ff5f643dSDonald Robson 153cb56cd61SSarah Walker /** 154cb56cd61SSarah Walker * @params: Device-specific parameters. 155cb56cd61SSarah Walker * 156cb56cd61SSarah Walker * The values of these parameters are initialized from the 157cb56cd61SSarah Walker * defaults specified as module parameters. They may be 158cb56cd61SSarah Walker * modified at runtime via debugfs (if enabled). 159cb56cd61SSarah Walker */ 160cb56cd61SSarah Walker struct pvr_device_params params; 161cb56cd61SSarah Walker 162d2d79d29SSarah Walker /** @stream_musthave_quirks: Bit array of "must-have" quirks for stream commands. */ 163d2d79d29SSarah Walker u32 stream_musthave_quirks[PVR_STREAM_TYPE_MAX][PVR_STREAM_EXTHDR_TYPE_MAX]; 164d2d79d29SSarah Walker 165ff5f643dSDonald Robson /** 166ff5f643dSDonald Robson * @mmu_flush_cache_flags: Records which MMU caches require flushing 167ff5f643dSDonald Robson * before submitting the next job. 168ff5f643dSDonald Robson */ 169ff5f643dSDonald Robson atomic_t mmu_flush_cache_flags; 170727538a4SSarah Walker 1716eedddabSSarah Walker /** 172d2d79d29SSarah Walker * @ctx_ids: Array of contexts belonging to this device. Array members 173d2d79d29SSarah Walker * are of type "struct pvr_context *". 174d2d79d29SSarah Walker * 175d2d79d29SSarah Walker * This array is used to allocate IDs used by the firmware. 176d2d79d29SSarah Walker */ 177d2d79d29SSarah Walker struct xarray ctx_ids; 178d2d79d29SSarah Walker 179d2d79d29SSarah Walker /** 1806eedddabSSarah Walker * @free_list_ids: Array of free lists belonging to this device. Array members 1816eedddabSSarah Walker * are of type "struct pvr_free_list *". 1826eedddabSSarah Walker * 1836eedddabSSarah Walker * This array is used to allocate IDs used by the firmware. 1846eedddabSSarah Walker */ 1856eedddabSSarah Walker struct xarray free_list_ids; 1866eedddabSSarah Walker 187eaf01ee5SSarah Walker /** 188eaf01ee5SSarah Walker * @job_ids: Array of jobs belonging to this device. Array members 189eaf01ee5SSarah Walker * are of type "struct pvr_job *". 190eaf01ee5SSarah Walker */ 191eaf01ee5SSarah Walker struct xarray job_ids; 192eaf01ee5SSarah Walker 193eaf01ee5SSarah Walker /** 194eaf01ee5SSarah Walker * @queues: Queue-related fields. 195eaf01ee5SSarah Walker */ 196eaf01ee5SSarah Walker struct { 197eee70683SRandy Dunlap /** @queues.active: Active queue list. */ 198eaf01ee5SSarah Walker struct list_head active; 199eaf01ee5SSarah Walker 200eee70683SRandy Dunlap /** @queues.idle: Idle queue list. */ 201eaf01ee5SSarah Walker struct list_head idle; 202eaf01ee5SSarah Walker 203eee70683SRandy Dunlap /** @queues.lock: Lock protecting access to the active/idle 204eee70683SRandy Dunlap * lists. */ 205eaf01ee5SSarah Walker struct mutex lock; 206eaf01ee5SSarah Walker } queues; 207eaf01ee5SSarah Walker 2083cc808e3SDonald Robson /** 2093cc808e3SDonald Robson * @watchdog: Watchdog for communications with firmware. 2103cc808e3SDonald Robson */ 211727538a4SSarah Walker struct { 212eee70683SRandy Dunlap /** @watchdog.work: Work item for watchdog callback. */ 213727538a4SSarah Walker struct delayed_work work; 214727538a4SSarah Walker 2153cc808e3SDonald Robson /** 216eee70683SRandy Dunlap * @watchdog.old_kccb_cmds_executed: KCCB command execution 217eee70683SRandy Dunlap * count at last watchdog poll. 2183cc808e3SDonald Robson */ 219727538a4SSarah Walker u32 old_kccb_cmds_executed; 220727538a4SSarah Walker 2213cc808e3SDonald Robson /** 222eee70683SRandy Dunlap * @watchdog.kccb_stall_count: Number of watchdog polls 223eee70683SRandy Dunlap * KCCB has been stalled for. 2243cc808e3SDonald Robson */ 225727538a4SSarah Walker u32 kccb_stall_count; 226727538a4SSarah Walker } watchdog; 227727538a4SSarah Walker 2283cc808e3SDonald Robson /** 2293cc808e3SDonald Robson * @kccb: Circular buffer for communications with firmware. 2303cc808e3SDonald Robson */ 231cc1aeedbSSarah Walker struct { 232eee70683SRandy Dunlap /** @kccb.ccb: Kernel CCB. */ 233cc1aeedbSSarah Walker struct pvr_ccb ccb; 234cc1aeedbSSarah Walker 235eee70683SRandy Dunlap /** @kccb.rtn_q: Waitqueue for KCCB command return waiters. */ 236cc1aeedbSSarah Walker wait_queue_head_t rtn_q; 237cc1aeedbSSarah Walker 238eee70683SRandy Dunlap /** @kccb.rtn_obj: Object representing KCCB return slots. */ 239cc1aeedbSSarah Walker struct pvr_fw_object *rtn_obj; 240cc1aeedbSSarah Walker 241cc1aeedbSSarah Walker /** 242eee70683SRandy Dunlap * @kccb.rtn: Pointer to CPU mapping of KCCB return slots. 243eee70683SRandy Dunlap * Must be accessed by READ_ONCE()/WRITE_ONCE(). 244cc1aeedbSSarah Walker */ 245cc1aeedbSSarah Walker u32 *rtn; 246cc1aeedbSSarah Walker 247eee70683SRandy Dunlap /** @kccb.slot_count: Total number of KCCB slots available. */ 248cc1aeedbSSarah Walker u32 slot_count; 249cc1aeedbSSarah Walker 250eee70683SRandy Dunlap /** @kccb.reserved_count: Number of KCCB slots reserved for 251eee70683SRandy Dunlap * future use. */ 252cc1aeedbSSarah Walker u32 reserved_count; 253cc1aeedbSSarah Walker 254cc1aeedbSSarah Walker /** 255eee70683SRandy Dunlap * @kccb.waiters: List of KCCB slot waiters. 256cc1aeedbSSarah Walker */ 257cc1aeedbSSarah Walker struct list_head waiters; 258cc1aeedbSSarah Walker 259eee70683SRandy Dunlap /** @kccb.fence_ctx: KCCB fence context. */ 260cc1aeedbSSarah Walker struct { 261eee70683SRandy Dunlap /** @kccb.fence_ctx.id: KCCB fence context ID 262eee70683SRandy Dunlap * allocated with dma_fence_context_alloc(). */ 263cc1aeedbSSarah Walker u64 id; 264cc1aeedbSSarah Walker 265eee70683SRandy Dunlap /** @kccb.fence_ctx.seqno: Sequence number incremented 266eee70683SRandy Dunlap * each time a fence is created. */ 267cc1aeedbSSarah Walker atomic_t seqno; 268cc1aeedbSSarah Walker 269cc1aeedbSSarah Walker /** 270eee70683SRandy Dunlap * @kccb.fence_ctx.lock: Lock used to synchronize 271eee70683SRandy Dunlap * access to fences allocated by this context. 272cc1aeedbSSarah Walker */ 273cc1aeedbSSarah Walker spinlock_t lock; 274cc1aeedbSSarah Walker } fence_ctx; 275cc1aeedbSSarah Walker } kccb; 276cc1aeedbSSarah Walker 277727538a4SSarah Walker /** 278727538a4SSarah Walker * @lost: %true if the device has been lost. 279727538a4SSarah Walker * 280727538a4SSarah Walker * This variable is set if the device has become irretrievably unavailable, e.g. if the 281727538a4SSarah Walker * firmware processor has stopped responding and can not be revived via a hard reset. 282727538a4SSarah Walker */ 283727538a4SSarah Walker bool lost; 284727538a4SSarah Walker 285cc1aeedbSSarah Walker /** 286cc1aeedbSSarah Walker * @reset_sem: Reset semaphore. 287cc1aeedbSSarah Walker * 288cc1aeedbSSarah Walker * GPU reset code will lock this for writing. Any code that submits commands to the firmware 289cc1aeedbSSarah Walker * that isn't in an IRQ handler or on the scheduler workqueue must lock this for reading. 290cc1aeedbSSarah Walker * Once this has been successfully locked, &pvr_dev->lost _must_ be checked, and -%EIO must 291cc1aeedbSSarah Walker * be returned if it is set. 292cc1aeedbSSarah Walker */ 293cc1aeedbSSarah Walker struct rw_semaphore reset_sem; 294cc1aeedbSSarah Walker 295727538a4SSarah Walker /** @sched_wq: Workqueue for schedulers. */ 296727538a4SSarah Walker struct workqueue_struct *sched_wq; 297*b0ef514bSBrendan King 298*b0ef514bSBrendan King /** 299*b0ef514bSBrendan King * @ctx_list_lock: Lock to be held when accessing the context list in 300*b0ef514bSBrendan King * struct pvr_file. 301*b0ef514bSBrendan King */ 302*b0ef514bSBrendan King spinlock_t ctx_list_lock; 3034babef07SSarah Walker }; 3044babef07SSarah Walker 3054babef07SSarah Walker /** 3064babef07SSarah Walker * struct pvr_file - powervr-specific data to be assigned to &struct 3074babef07SSarah Walker * drm_file.driver_priv 3084babef07SSarah Walker */ 3094babef07SSarah Walker struct pvr_file { 3104babef07SSarah Walker /** 3114babef07SSarah Walker * @file: A reference to the parent &struct drm_file. 3124babef07SSarah Walker * 3134babef07SSarah Walker * Do not access this member directly, instead call from_pvr_file(). 3144babef07SSarah Walker */ 3154babef07SSarah Walker struct drm_file *file; 3164babef07SSarah Walker 3174babef07SSarah Walker /** 3184babef07SSarah Walker * @pvr_dev: A reference to the powervr-specific wrapper for the 3193cc808e3SDonald Robson * associated device. Saves on repeated calls to to_pvr_device(). 3204babef07SSarah Walker */ 3214babef07SSarah Walker struct pvr_device *pvr_dev; 322ff5f643dSDonald Robson 323ff5f643dSDonald Robson /** 324d2d79d29SSarah Walker * @ctx_handles: Array of contexts belonging to this file. Array members 325d2d79d29SSarah Walker * are of type "struct pvr_context *". 326d2d79d29SSarah Walker * 327d2d79d29SSarah Walker * This array is used to allocate handles returned to userspace. 328d2d79d29SSarah Walker */ 329d2d79d29SSarah Walker struct xarray ctx_handles; 330d2d79d29SSarah Walker 331d2d79d29SSarah Walker /** 3326eedddabSSarah Walker * @free_list_handles: Array of free lists belonging to this file. Array 3336eedddabSSarah Walker * members are of type "struct pvr_free_list *". 3346eedddabSSarah Walker * 3356eedddabSSarah Walker * This array is used to allocate handles returned to userspace. 3366eedddabSSarah Walker */ 3376eedddabSSarah Walker struct xarray free_list_handles; 3386eedddabSSarah Walker 3396eedddabSSarah Walker /** 3406eedddabSSarah Walker * @hwrt_handles: Array of HWRT datasets belonging to this file. Array 3416eedddabSSarah Walker * members are of type "struct pvr_hwrt_dataset *". 3426eedddabSSarah Walker * 3436eedddabSSarah Walker * This array is used to allocate handles returned to userspace. 3446eedddabSSarah Walker */ 3456eedddabSSarah Walker struct xarray hwrt_handles; 3466eedddabSSarah Walker 3476eedddabSSarah Walker /** 348ff5f643dSDonald Robson * @vm_ctx_handles: Array of VM contexts belonging to this file. Array 349ff5f643dSDonald Robson * members are of type "struct pvr_vm_context *". 350ff5f643dSDonald Robson * 351ff5f643dSDonald Robson * This array is used to allocate handles returned to userspace. 352ff5f643dSDonald Robson */ 353ff5f643dSDonald Robson struct xarray vm_ctx_handles; 354*b0ef514bSBrendan King 355*b0ef514bSBrendan King /** @contexts: PVR context list. */ 356*b0ef514bSBrendan King struct list_head contexts; 3574babef07SSarah Walker }; 3584babef07SSarah Walker 359f99f5f3eSSarah Walker /** 360f99f5f3eSSarah Walker * PVR_HAS_FEATURE() - Tests whether a PowerVR device has a given feature 361f99f5f3eSSarah Walker * @pvr_dev: [IN] Target PowerVR device. 362f99f5f3eSSarah Walker * @feature: [IN] Hardware feature name. 363f99f5f3eSSarah Walker * 364f99f5f3eSSarah Walker * Feature names are derived from those found in &struct pvr_device_features by 365f99f5f3eSSarah Walker * dropping the 'has_' prefix, which is applied by this macro. 366f99f5f3eSSarah Walker * 367f99f5f3eSSarah Walker * Return: 368f99f5f3eSSarah Walker * * true if the named feature is present in the hardware 369f99f5f3eSSarah Walker * * false if the named feature is not present in the hardware 370f99f5f3eSSarah Walker */ 371f99f5f3eSSarah Walker #define PVR_HAS_FEATURE(pvr_dev, feature) ((pvr_dev)->features.has_##feature) 372f99f5f3eSSarah Walker 373f99f5f3eSSarah Walker /** 374f99f5f3eSSarah Walker * PVR_FEATURE_VALUE() - Gets a PowerVR device feature value 375f99f5f3eSSarah Walker * @pvr_dev: [IN] Target PowerVR device. 376f99f5f3eSSarah Walker * @feature: [IN] Feature name. 377f99f5f3eSSarah Walker * @value_out: [OUT] Feature value. 378f99f5f3eSSarah Walker * 379f99f5f3eSSarah Walker * This macro will get a feature value for those features that have values. 380f99f5f3eSSarah Walker * If the feature is not present, nothing will be stored to @value_out. 381f99f5f3eSSarah Walker * 382f99f5f3eSSarah Walker * Feature names are derived from those found in &struct pvr_device_features by 383f99f5f3eSSarah Walker * dropping the 'has_' prefix. 384f99f5f3eSSarah Walker * 385f99f5f3eSSarah Walker * Return: 386f99f5f3eSSarah Walker * * 0 on success, or 387f99f5f3eSSarah Walker * * -%EINVAL if the named feature is not present in the hardware 388f99f5f3eSSarah Walker */ 389f99f5f3eSSarah Walker #define PVR_FEATURE_VALUE(pvr_dev, feature, value_out) \ 390f99f5f3eSSarah Walker ({ \ 391f99f5f3eSSarah Walker struct pvr_device *_pvr_dev = pvr_dev; \ 392f99f5f3eSSarah Walker int _ret = -EINVAL; \ 393f99f5f3eSSarah Walker if (_pvr_dev->features.has_##feature) { \ 394f99f5f3eSSarah Walker *(value_out) = _pvr_dev->features.feature; \ 395f99f5f3eSSarah Walker _ret = 0; \ 396f99f5f3eSSarah Walker } \ 397f99f5f3eSSarah Walker _ret; \ 398f99f5f3eSSarah Walker }) 399f99f5f3eSSarah Walker 400f99f5f3eSSarah Walker /** 401f99f5f3eSSarah Walker * PVR_HAS_QUIRK() - Tests whether a physical device has a given quirk 402f99f5f3eSSarah Walker * @pvr_dev: [IN] Target PowerVR device. 403f99f5f3eSSarah Walker * @quirk: [IN] Hardware quirk name. 404f99f5f3eSSarah Walker * 405f99f5f3eSSarah Walker * Quirk numbers are derived from those found in #pvr_device_quirks by 406f99f5f3eSSarah Walker * dropping the 'has_brn' prefix, which is applied by this macro. 407f99f5f3eSSarah Walker * 408f99f5f3eSSarah Walker * Returns 409f99f5f3eSSarah Walker * * true if the quirk is present in the hardware, or 410f99f5f3eSSarah Walker * * false if the quirk is not present in the hardware. 411f99f5f3eSSarah Walker */ 412f99f5f3eSSarah Walker #define PVR_HAS_QUIRK(pvr_dev, quirk) ((pvr_dev)->quirks.has_brn##quirk) 413f99f5f3eSSarah Walker 414f99f5f3eSSarah Walker /** 415f99f5f3eSSarah Walker * PVR_HAS_ENHANCEMENT() - Tests whether a physical device has a given 416f99f5f3eSSarah Walker * enhancement 417f99f5f3eSSarah Walker * @pvr_dev: [IN] Target PowerVR device. 418f99f5f3eSSarah Walker * @enhancement: [IN] Hardware enhancement name. 419f99f5f3eSSarah Walker * 420f99f5f3eSSarah Walker * Enhancement numbers are derived from those found in #pvr_device_enhancements 421f99f5f3eSSarah Walker * by dropping the 'has_ern' prefix, which is applied by this macro. 422f99f5f3eSSarah Walker * 423f99f5f3eSSarah Walker * Returns 424f99f5f3eSSarah Walker * * true if the enhancement is present in the hardware, or 425f99f5f3eSSarah Walker * * false if the enhancement is not present in the hardware. 426f99f5f3eSSarah Walker */ 427f99f5f3eSSarah Walker #define PVR_HAS_ENHANCEMENT(pvr_dev, enhancement) ((pvr_dev)->enhancements.has_ern##enhancement) 428f99f5f3eSSarah Walker 4294babef07SSarah Walker #define from_pvr_device(pvr_dev) (&(pvr_dev)->base) 4304babef07SSarah Walker 4314babef07SSarah Walker #define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base) 4324babef07SSarah Walker 4334babef07SSarah Walker #define from_pvr_file(pvr_file) ((pvr_file)->file) 4344babef07SSarah Walker 4354babef07SSarah Walker #define to_pvr_file(file) ((file)->driver_priv) 4364babef07SSarah Walker 437f99f5f3eSSarah Walker /** 438f99f5f3eSSarah Walker * PVR_PACKED_BVNC() - Packs B, V, N and C values into a 64-bit unsigned integer 439f99f5f3eSSarah Walker * @b: Branch ID. 440f99f5f3eSSarah Walker * @v: Version ID. 441f99f5f3eSSarah Walker * @n: Number of scalable units. 442f99f5f3eSSarah Walker * @c: Config ID. 443f99f5f3eSSarah Walker * 444f99f5f3eSSarah Walker * The packed layout is as follows: 445f99f5f3eSSarah Walker * 446f99f5f3eSSarah Walker * +--------+--------+--------+-------+ 447f99f5f3eSSarah Walker * | 63..48 | 47..32 | 31..16 | 15..0 | 448f99f5f3eSSarah Walker * +========+========+========+=======+ 449f99f5f3eSSarah Walker * | B | V | N | C | 450f99f5f3eSSarah Walker * +--------+--------+--------+-------+ 451f99f5f3eSSarah Walker * 452f99f5f3eSSarah Walker * pvr_gpu_id_to_packed_bvnc() should be used instead of this macro when a 453f99f5f3eSSarah Walker * &struct pvr_gpu_id is available in order to ensure proper type checking. 454f99f5f3eSSarah Walker * 455f99f5f3eSSarah Walker * Return: Packed BVNC. 456f99f5f3eSSarah Walker */ 457f99f5f3eSSarah Walker /* clang-format off */ 458f99f5f3eSSarah Walker #define PVR_PACKED_BVNC(b, v, n, c) \ 459f99f5f3eSSarah Walker ((((u64)(b) & GENMASK_ULL(15, 0)) << 48) | \ 460f99f5f3eSSarah Walker (((u64)(v) & GENMASK_ULL(15, 0)) << 32) | \ 461f99f5f3eSSarah Walker (((u64)(n) & GENMASK_ULL(15, 0)) << 16) | \ 462f99f5f3eSSarah Walker (((u64)(c) & GENMASK_ULL(15, 0)) << 0)) 463f99f5f3eSSarah Walker /* clang-format on */ 464f99f5f3eSSarah Walker 465f99f5f3eSSarah Walker /** 466f99f5f3eSSarah Walker * pvr_gpu_id_to_packed_bvnc() - Packs B, V, N and C values into a 64-bit 467f99f5f3eSSarah Walker * unsigned integer 468f99f5f3eSSarah Walker * @gpu_id: GPU ID. 469f99f5f3eSSarah Walker * 470f99f5f3eSSarah Walker * The packed layout is as follows: 471f99f5f3eSSarah Walker * 472f99f5f3eSSarah Walker * +--------+--------+--------+-------+ 473f99f5f3eSSarah Walker * | 63..48 | 47..32 | 31..16 | 15..0 | 474f99f5f3eSSarah Walker * +========+========+========+=======+ 475f99f5f3eSSarah Walker * | B | V | N | C | 476f99f5f3eSSarah Walker * +--------+--------+--------+-------+ 477f99f5f3eSSarah Walker * 478f99f5f3eSSarah Walker * This should be used in preference to PVR_PACKED_BVNC() when a &struct 479f99f5f3eSSarah Walker * pvr_gpu_id is available in order to ensure proper type checking. 480f99f5f3eSSarah Walker * 481f99f5f3eSSarah Walker * Return: Packed BVNC. 482f99f5f3eSSarah Walker */ 483f99f5f3eSSarah Walker static __always_inline u64 484f99f5f3eSSarah Walker pvr_gpu_id_to_packed_bvnc(struct pvr_gpu_id *gpu_id) 485f99f5f3eSSarah Walker { 486f99f5f3eSSarah Walker return PVR_PACKED_BVNC(gpu_id->b, gpu_id->v, gpu_id->n, gpu_id->c); 487f99f5f3eSSarah Walker } 488f99f5f3eSSarah Walker 489f99f5f3eSSarah Walker static __always_inline void 490f99f5f3eSSarah Walker packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id) 491f99f5f3eSSarah Walker { 492f99f5f3eSSarah Walker gpu_id->b = (bvnc & GENMASK_ULL(63, 48)) >> 48; 493f99f5f3eSSarah Walker gpu_id->v = (bvnc & GENMASK_ULL(47, 32)) >> 32; 494f99f5f3eSSarah Walker gpu_id->n = (bvnc & GENMASK_ULL(31, 16)) >> 16; 495f99f5f3eSSarah Walker gpu_id->c = bvnc & GENMASK_ULL(15, 0); 496f99f5f3eSSarah Walker } 497f99f5f3eSSarah Walker 4981f88f017SSarah Walker int pvr_device_init(struct pvr_device *pvr_dev); 4991f88f017SSarah Walker void pvr_device_fini(struct pvr_device *pvr_dev); 500eaf01ee5SSarah Walker void pvr_device_reset(struct pvr_device *pvr_dev); 5011f88f017SSarah Walker 502f99f5f3eSSarah Walker bool 503f99f5f3eSSarah Walker pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk); 504f99f5f3eSSarah Walker bool 505f99f5f3eSSarah Walker pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement); 506f99f5f3eSSarah Walker bool 507f99f5f3eSSarah Walker pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature); 508f99f5f3eSSarah Walker 5091f88f017SSarah Walker /** 5101f88f017SSarah Walker * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register 5111f88f017SSarah Walker * @val: Value of the target register. 5121f88f017SSarah Walker * @field: Field specifier, as defined in "pvr_rogue_cr_defs.h". 5131f88f017SSarah Walker * 5141f88f017SSarah Walker * Return: The extracted field. 5151f88f017SSarah Walker */ 5161f88f017SSarah Walker #define PVR_CR_FIELD_GET(val, field) FIELD_GET(~ROGUE_CR_##field##_CLRMSK, val) 5171f88f017SSarah Walker 5181f88f017SSarah Walker /** 5191f88f017SSarah Walker * pvr_cr_read32() - Read a 32-bit register from a PowerVR device 5201f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5211f88f017SSarah Walker * @reg: Target register. 5221f88f017SSarah Walker * 5231f88f017SSarah Walker * Return: The value of the requested register. 5241f88f017SSarah Walker */ 5251f88f017SSarah Walker static __always_inline u32 5261f88f017SSarah Walker pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg) 5271f88f017SSarah Walker { 5281f88f017SSarah Walker return ioread32(pvr_dev->regs + reg); 5291f88f017SSarah Walker } 5301f88f017SSarah Walker 5311f88f017SSarah Walker /** 5321f88f017SSarah Walker * pvr_cr_read64() - Read a 64-bit register from a PowerVR device 5331f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5341f88f017SSarah Walker * @reg: Target register. 5351f88f017SSarah Walker * 5361f88f017SSarah Walker * Return: The value of the requested register. 5371f88f017SSarah Walker */ 5381f88f017SSarah Walker static __always_inline u64 5391f88f017SSarah Walker pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg) 5401f88f017SSarah Walker { 5411f88f017SSarah Walker return ioread64(pvr_dev->regs + reg); 5421f88f017SSarah Walker } 5431f88f017SSarah Walker 5441f88f017SSarah Walker /** 5451f88f017SSarah Walker * pvr_cr_write32() - Write to a 32-bit register in a PowerVR device 5461f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5471f88f017SSarah Walker * @reg: Target register. 5481f88f017SSarah Walker * @val: Value to write. 5491f88f017SSarah Walker */ 5501f88f017SSarah Walker static __always_inline void 5511f88f017SSarah Walker pvr_cr_write32(struct pvr_device *pvr_dev, u32 reg, u32 val) 5521f88f017SSarah Walker { 5531f88f017SSarah Walker iowrite32(val, pvr_dev->regs + reg); 5541f88f017SSarah Walker } 5551f88f017SSarah Walker 5561f88f017SSarah Walker /** 5571f88f017SSarah Walker * pvr_cr_write64() - Write to a 64-bit register in a PowerVR device 5581f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5591f88f017SSarah Walker * @reg: Target register. 5601f88f017SSarah Walker * @val: Value to write. 5611f88f017SSarah Walker */ 5621f88f017SSarah Walker static __always_inline void 5631f88f017SSarah Walker pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val) 5641f88f017SSarah Walker { 5651f88f017SSarah Walker iowrite64(val, pvr_dev->regs + reg); 5661f88f017SSarah Walker } 5671f88f017SSarah Walker 5681f88f017SSarah Walker /** 5691f88f017SSarah Walker * pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by 5701f88f017SSarah Walker * polling 5711f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5721f88f017SSarah Walker * @reg_addr: Address of register. 5731f88f017SSarah Walker * @reg_value: Expected register value (after masking). 5741f88f017SSarah Walker * @reg_mask: Mask of bits valid for comparison with @reg_value. 5751f88f017SSarah Walker * @timeout_usec: Timeout length, in us. 5761f88f017SSarah Walker * 5771f88f017SSarah Walker * Returns: 5781f88f017SSarah Walker * * 0 on success, or 5791f88f017SSarah Walker * * -%ETIMEDOUT on timeout. 5801f88f017SSarah Walker */ 5811f88f017SSarah Walker static __always_inline int 5821f88f017SSarah Walker pvr_cr_poll_reg32(struct pvr_device *pvr_dev, u32 reg_addr, u32 reg_value, 5831f88f017SSarah Walker u32 reg_mask, u64 timeout_usec) 5841f88f017SSarah Walker { 5851f88f017SSarah Walker u32 value; 5861f88f017SSarah Walker 5871f88f017SSarah Walker return readl_poll_timeout(pvr_dev->regs + reg_addr, value, 5881f88f017SSarah Walker (value & reg_mask) == reg_value, 0, timeout_usec); 5891f88f017SSarah Walker } 5901f88f017SSarah Walker 5911f88f017SSarah Walker /** 5921f88f017SSarah Walker * pvr_cr_poll_reg64() - Wait for a 64-bit register to match a given value by 5931f88f017SSarah Walker * polling 5941f88f017SSarah Walker * @pvr_dev: Target PowerVR device. 5951f88f017SSarah Walker * @reg_addr: Address of register. 5961f88f017SSarah Walker * @reg_value: Expected register value (after masking). 5971f88f017SSarah Walker * @reg_mask: Mask of bits valid for comparison with @reg_value. 5981f88f017SSarah Walker * @timeout_usec: Timeout length, in us. 5991f88f017SSarah Walker * 6001f88f017SSarah Walker * Returns: 6011f88f017SSarah Walker * * 0 on success, or 6021f88f017SSarah Walker * * -%ETIMEDOUT on timeout. 6031f88f017SSarah Walker */ 6041f88f017SSarah Walker static __always_inline int 6051f88f017SSarah Walker pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value, 6061f88f017SSarah Walker u64 reg_mask, u64 timeout_usec) 6071f88f017SSarah Walker { 6081f88f017SSarah Walker u64 value; 6091f88f017SSarah Walker 6101f88f017SSarah Walker return readq_poll_timeout(pvr_dev->regs + reg_addr, value, 6111f88f017SSarah Walker (value & reg_mask) == reg_value, 0, timeout_usec); 6121f88f017SSarah Walker } 6131f88f017SSarah Walker 6144babef07SSarah Walker /** 615f99f5f3eSSarah Walker * pvr_round_up_to_cacheline_size() - Round up a provided size to be cacheline 616f99f5f3eSSarah Walker * aligned 617f99f5f3eSSarah Walker * @pvr_dev: Target PowerVR device. 618f99f5f3eSSarah Walker * @size: Initial size, in bytes. 619f99f5f3eSSarah Walker * 620f99f5f3eSSarah Walker * Returns: 621f99f5f3eSSarah Walker * * Size aligned to cacheline size. 622f99f5f3eSSarah Walker */ 623f99f5f3eSSarah Walker static __always_inline size_t 624f99f5f3eSSarah Walker pvr_round_up_to_cacheline_size(struct pvr_device *pvr_dev, size_t size) 625f99f5f3eSSarah Walker { 626f99f5f3eSSarah Walker u16 slc_cacheline_size_bits = 0; 627f99f5f3eSSarah Walker u16 slc_cacheline_size_bytes; 628f99f5f3eSSarah Walker 629f99f5f3eSSarah Walker WARN_ON(!PVR_HAS_FEATURE(pvr_dev, slc_cache_line_size_bits)); 630f99f5f3eSSarah Walker PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, 631f99f5f3eSSarah Walker &slc_cacheline_size_bits); 632f99f5f3eSSarah Walker slc_cacheline_size_bytes = slc_cacheline_size_bits / 8; 633f99f5f3eSSarah Walker 634f99f5f3eSSarah Walker return round_up(size, slc_cacheline_size_bytes); 635f99f5f3eSSarah Walker } 636f99f5f3eSSarah Walker 637f99f5f3eSSarah Walker /** 6384babef07SSarah Walker * DOC: IOCTL validation helpers 6394babef07SSarah Walker * 6404babef07SSarah Walker * To validate the constraints imposed on IOCTL argument structs, a collection 6414babef07SSarah Walker * of macros and helper functions exist in ``pvr_device.h``. 6424babef07SSarah Walker * 6434babef07SSarah Walker * Of the current helpers, it should only be necessary to call 6444babef07SSarah Walker * PVR_IOCTL_UNION_PADDING_CHECK() directly. This macro should be used once in 6454babef07SSarah Walker * every code path which extracts a union member from a struct passed from 6464babef07SSarah Walker * userspace. 6474babef07SSarah Walker */ 6484babef07SSarah Walker 6494babef07SSarah Walker /** 6504babef07SSarah Walker * pvr_ioctl_union_padding_check() - Validate that the implicit padding between 6514babef07SSarah Walker * the end of a union member and the end of the union itself is zeroed. 6524babef07SSarah Walker * @instance: Pointer to the instance of the struct to validate. 6534babef07SSarah Walker * @union_offset: Offset into the type of @instance of the target union. Must 6544babef07SSarah Walker * be 64-bit aligned. 6554babef07SSarah Walker * @union_size: Size of the target union in the type of @instance. Must be 6564babef07SSarah Walker * 64-bit aligned. 6574babef07SSarah Walker * @member_size: Size of the target member in the target union specified by 6584babef07SSarah Walker * @union_offset and @union_size. It is assumed that the offset of the target 6594babef07SSarah Walker * member is zero relative to @union_offset. Must be 64-bit aligned. 6604babef07SSarah Walker * 6614babef07SSarah Walker * You probably want to use PVR_IOCTL_UNION_PADDING_CHECK() instead of calling 6624babef07SSarah Walker * this function directly, since that macro abstracts away much of the setup, 6634babef07SSarah Walker * and also provides some static validation. See its docs for details. 6644babef07SSarah Walker * 6654babef07SSarah Walker * Return: 6664babef07SSarah Walker * * %true if every byte between the end of the used member of the union and 6674babef07SSarah Walker * the end of that union is zeroed, or 6684babef07SSarah Walker * * %false otherwise. 6694babef07SSarah Walker */ 6704babef07SSarah Walker static __always_inline bool 6714babef07SSarah Walker pvr_ioctl_union_padding_check(void *instance, size_t union_offset, 6724babef07SSarah Walker size_t union_size, size_t member_size) 6734babef07SSarah Walker { 6744babef07SSarah Walker /* 6754babef07SSarah Walker * void pointer arithmetic is technically illegal - cast to a byte 6764babef07SSarah Walker * pointer so this addition works safely. 6774babef07SSarah Walker */ 6784babef07SSarah Walker void *padding_start = ((u8 *)instance) + union_offset + member_size; 6794babef07SSarah Walker size_t padding_size = union_size - member_size; 6804babef07SSarah Walker 681f7650635SJani Nikula return mem_is_zero(padding_start, padding_size); 6824babef07SSarah Walker } 6834babef07SSarah Walker 6844babef07SSarah Walker /** 6854babef07SSarah Walker * PVR_STATIC_ASSERT_64BIT_ALIGNED() - Inline assertion for 64-bit alignment. 6864babef07SSarah Walker * @static_expr_: Target expression to evaluate. 6874babef07SSarah Walker * 6884babef07SSarah Walker * If @static_expr_ does not evaluate to a constant integer which would be a 6894babef07SSarah Walker * 64-bit aligned address (i.e. a multiple of 8), compilation will fail. 6904babef07SSarah Walker * 6914babef07SSarah Walker * Return: 6924babef07SSarah Walker * The value of @static_expr_. 6934babef07SSarah Walker */ 6944babef07SSarah Walker #define PVR_STATIC_ASSERT_64BIT_ALIGNED(static_expr_) \ 6954babef07SSarah Walker ({ \ 6964babef07SSarah Walker static_assert(((static_expr_) & (sizeof(u64) - 1)) == 0); \ 6974babef07SSarah Walker (static_expr_); \ 6984babef07SSarah Walker }) 6994babef07SSarah Walker 7004babef07SSarah Walker /** 7014babef07SSarah Walker * PVR_IOCTL_UNION_PADDING_CHECK() - Validate that the implicit padding between 7024babef07SSarah Walker * the end of a union member and the end of the union itself is zeroed. 7034babef07SSarah Walker * @struct_instance_: An expression which evaluates to a pointer to a UAPI data 7044babef07SSarah Walker * struct. 7054babef07SSarah Walker * @union_: The name of the union member of @struct_instance_ to check. If the 7064babef07SSarah Walker * union member is nested within the type of @struct_instance_, this may 7074babef07SSarah Walker * contain the member access operator ("."). 7084babef07SSarah Walker * @member_: The name of the member of @union_ to assess. 7094babef07SSarah Walker * 7104babef07SSarah Walker * This is a wrapper around pvr_ioctl_union_padding_check() which performs 7114babef07SSarah Walker * alignment checks and simplifies things for the caller. 7124babef07SSarah Walker * 7134babef07SSarah Walker * Return: 7144babef07SSarah Walker * * %true if every byte in @struct_instance_ between the end of @member_ and 7154babef07SSarah Walker * the end of @union_ is zeroed, or 7164babef07SSarah Walker * * %false otherwise. 7174babef07SSarah Walker */ 7184babef07SSarah Walker #define PVR_IOCTL_UNION_PADDING_CHECK(struct_instance_, union_, member_) \ 7194babef07SSarah Walker ({ \ 7204babef07SSarah Walker typeof(struct_instance_) __instance = (struct_instance_); \ 7214babef07SSarah Walker size_t __union_offset = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ 7224babef07SSarah Walker offsetof(typeof(*__instance), union_)); \ 7234babef07SSarah Walker size_t __union_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ 7244babef07SSarah Walker sizeof(__instance->union_)); \ 7254babef07SSarah Walker size_t __member_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ 7264babef07SSarah Walker sizeof(__instance->union_.member_)); \ 7274babef07SSarah Walker pvr_ioctl_union_padding_check(__instance, __union_offset, \ 7284babef07SSarah Walker __union_size, __member_size); \ 7294babef07SSarah Walker }) 7304babef07SSarah Walker 731f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_META 0 732f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_MIPS 1 733f99f5f3eSSarah Walker #define PVR_FW_PROCESSOR_TYPE_RISCV 2 734f99f5f3eSSarah Walker 7354babef07SSarah Walker #endif /* PVR_DEVICE_H */ 736