diff options
Diffstat (limited to 'sys/dev/pci/drm/include')
230 files changed, 11134 insertions, 2409 deletions
diff --git a/sys/dev/pci/drm/include/acpi/acpi_bus.h b/sys/dev/pci/drm/include/acpi/acpi_bus.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/acpi/acpi_bus.h diff --git a/sys/dev/pci/drm/include/asm/byteorder.h b/sys/dev/pci/drm/include/asm/byteorder.h index 75f771e2cd9..d2726354179 100644 --- a/sys/dev/pci/drm/include/asm/byteorder.h +++ b/sys/dev/pci/drm/include/asm/byteorder.h @@ -4,19 +4,28 @@ #define _ASM_BYTEORDER_H #include <sys/endian.h> +#include <linux/types.h> #define le16_to_cpu(x) letoh16(x) #define le32_to_cpu(x) letoh32(x) +#define le64_to_cpu(x) letoh64(x) #define be16_to_cpu(x) betoh16(x) #define be32_to_cpu(x) betoh32(x) +#define be64_to_cpu(x) betoh64(x) #define le16_to_cpup(x) lemtoh16(x) #define le32_to_cpup(x) lemtoh32(x) +#define le64_to_cpup(x) lemtoh64(x) #define be16_to_cpup(x) bemtoh16(x) #define be32_to_cpup(x) bemtoh32(x) +#define be64_to_cpup(x) bemtoh64(x) #define get_unaligned_le32(x) lemtoh32(x) #define cpu_to_le16(x) htole16(x) #define cpu_to_le32(x) htole32(x) +#define cpu_to_le64(x) htole64(x) #define cpu_to_be16(x) htobe16(x) #define cpu_to_be32(x) htobe32(x) +#define cpu_to_be64(x) htobe64(x) + +#define swab16(x) swap16(x) #endif diff --git a/sys/dev/pci/drm/include/asm/cpufeature.h b/sys/dev/pci/drm/include/asm/cpufeature.h new file mode 100644 index 00000000000..bdeb54044aa --- /dev/null +++ b/sys/dev/pci/drm/include/asm/cpufeature.h @@ -0,0 +1,34 @@ +/* Public domain. */ + +#ifndef _ASM_CPUFEATURE_H +#define _ASM_CPUFEATURE_H + +#if defined(__amd64__) || defined(__i386__) + +#define X86_FEATURE_CLFLUSH 1 +#define X86_FEATURE_XMM4_1 2 +#define X86_FEATURE_PAT 3 +#define X86_FEATURE_HYPERVISOR 4 + +static inline bool +static_cpu_has(uint16_t f) +{ + switch (f) { + case X86_FEATURE_CLFLUSH: + return curcpu()->ci_cflushsz != 0; + case X86_FEATURE_XMM4_1: + return (cpu_ecxfeature & CPUIDECX_SSE41) != 0; + case X86_FEATURE_PAT: + return (curcpu()->ci_feature_flags & CPUID_PAT) != 0; + case X86_FEATURE_HYPERVISOR: + return (cpu_ecxfeature & CPUIDECX_HV) != 0; + default: + return false; + } +} + +#define boot_cpu_has(x) static_cpu_has(x) + +#endif + +#endif diff --git a/sys/dev/pci/drm/include/asm/current.h b/sys/dev/pci/drm/include/asm/current.h new file mode 100644 index 00000000000..30263918de8 --- /dev/null +++ b/sys/dev/pci/drm/include/asm/current.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _ASM_CURRENT_H +#define _ASM_CURRENT_H + +#define current curproc + +#endif diff --git a/sys/dev/pci/drm/include/asm/fpu/api.h b/sys/dev/pci/drm/include/asm/fpu/api.h index 882ea6f5ec8..8caad859860 100644 --- a/sys/dev/pci/drm/include/asm/fpu/api.h +++ b/sys/dev/pci/drm/include/asm/fpu/api.h @@ -3,6 +3,8 @@ #ifndef _ASM_FPU_API_H #define _ASM_FPU_API_H +#include <linux/bottom_half.h> + #ifdef __i386__ #include <machine/npx.h> #endif diff --git a/sys/dev/pci/drm/include/asm/ioctl.h b/sys/dev/pci/drm/include/asm/ioctl.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/asm/ioctl.h diff --git a/sys/dev/pci/drm/include/asm/preempt.h b/sys/dev/pci/drm/include/asm/preempt.h new file mode 100644 index 00000000000..5a55e454af1 --- /dev/null +++ b/sys/dev/pci/drm/include/asm/preempt.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _ASM_PREEMPT_H +#define _ASM_PREEMPT_H + +#include <linux/thread_info.h> + +#endif diff --git a/sys/dev/pci/drm/include/asm/set_memory.h b/sys/dev/pci/drm/include/asm/set_memory.h index e78088fd66e..5fced579566 100644 --- a/sys/dev/pci/drm/include/asm/set_memory.h +++ b/sys/dev/pci/drm/include/asm/set_memory.h @@ -1,4 +1,4 @@ -/* $OpenBSD: set_memory.h,v 1.1 2019/04/14 10:14:52 jsg Exp $ */ +/* $OpenBSD: set_memory.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -19,6 +19,10 @@ #define _ASM_SET_MEMORY_H #include <sys/atomic.h> + +#include <sys/param.h> /* for PAGE_SIZE on i386 */ +#include <uvm/uvm_extern.h> + #include <machine/pmap.h> #if defined(__amd64__) || defined(__i386__) diff --git a/sys/dev/pci/drm/include/asm/smp.h b/sys/dev/pci/drm/include/asm/smp.h new file mode 100644 index 00000000000..a50485db7f5 --- /dev/null +++ b/sys/dev/pci/drm/include/asm/smp.h @@ -0,0 +1,20 @@ +/* Public domain. */ + +#ifndef _ASM_SMP_H +#define _ASM_SMP_H + +#if defined(__i386__) || defined(__amd64__) + +#include <machine/cpu.h> + +static inline int +wbinvd_on_all_cpus(void) +{ + /* XXX single cpu only */ + wbinvd(); + return 0; +} + +#endif + +#endif diff --git a/sys/dev/pci/drm/include/asm/thread_info.h b/sys/dev/pci/drm/include/asm/thread_info.h new file mode 100644 index 00000000000..e8c24b4ef61 --- /dev/null +++ b/sys/dev/pci/drm/include/asm/thread_info.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#include <asm/cpufeature.h> + +#endif diff --git a/sys/dev/pci/drm/include/drm/amd_asic_type.h b/sys/dev/pci/drm/include/drm/amd_asic_type.h index dd63d08cc54..b1230e33d50 100644 --- a/sys/dev/pci/drm/include/drm/amd_asic_type.h +++ b/sys/dev/pci/drm/include/drm/amd_asic_type.h @@ -27,29 +27,36 @@ */ enum amd_asic_type { CHIP_TAHITI = 0, - CHIP_PITCAIRN, - CHIP_VERDE, - CHIP_OLAND, - CHIP_HAINAN, - CHIP_BONAIRE, - CHIP_KAVERI, - CHIP_KABINI, - CHIP_HAWAII, - CHIP_MULLINS, - CHIP_TOPAZ, - CHIP_TONGA, - CHIP_FIJI, - CHIP_CARRIZO, - CHIP_STONEY, - CHIP_POLARIS10, - CHIP_POLARIS11, - CHIP_POLARIS12, - CHIP_VEGAM, - CHIP_VEGA10, - CHIP_VEGA12, - CHIP_VEGA20, - CHIP_RAVEN, + CHIP_PITCAIRN, /* 1 */ + CHIP_VERDE, /* 2 */ + CHIP_OLAND, /* 3 */ + CHIP_HAINAN, /* 4 */ + CHIP_BONAIRE, /* 5 */ + CHIP_KAVERI, /* 6 */ + CHIP_KABINI, /* 7 */ + CHIP_HAWAII, /* 8 */ + CHIP_MULLINS, /* 9 */ + CHIP_TOPAZ, /* 10 */ + CHIP_TONGA, /* 11 */ + CHIP_FIJI, /* 12 */ + CHIP_CARRIZO, /* 13 */ + CHIP_STONEY, /* 14 */ + CHIP_POLARIS10, /* 15 */ + CHIP_POLARIS11, /* 16 */ + CHIP_POLARIS12, /* 17 */ + CHIP_VEGAM, /* 18 */ + CHIP_VEGA10, /* 19 */ + CHIP_VEGA12, /* 20 */ + CHIP_VEGA20, /* 21 */ + CHIP_RAVEN, /* 22 */ + CHIP_ARCTURUS, /* 23 */ + CHIP_RENOIR, /* 24 */ + CHIP_NAVI10, /* 25 */ + CHIP_NAVI14, /* 26 */ + CHIP_NAVI12, /* 27 */ CHIP_LAST, }; +extern const char *amdgpu_asic_name[]; + #endif /*__AMD_ASIC_TYPE_H__ */ diff --git a/sys/dev/pci/drm/include/drm/drmP.h b/sys/dev/pci/drm/include/drm/drmP.h deleted file mode 100644 index 832d016032b..00000000000 --- a/sys/dev/pci/drm/include/drm/drmP.h +++ /dev/null @@ -1,324 +0,0 @@ -/* $OpenBSD: drmP.h,v 1.8 2020/03/04 21:19:15 kettenis Exp $ */ -/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- - * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - */ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * - */ - -#ifndef _DRM_P_H_ -#define _DRM_P_H_ - -#if defined(_KERNEL) || defined(__KERNEL__) - -//#define DRMDEBUG - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/malloc.h> -#include <sys/pool.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/mutex.h> -#include <sys/tree.h> -#include <sys/endian.h> -#include <sys/stdint.h> -#include <sys/memrange.h> -#include <sys/extent.h> -#include <sys/rwlock.h> - -#ifdef DDB -#include <ddb/db_var.h> -#endif - -#include <uvm/uvm_extern.h> -#include <uvm/uvm_object.h> - -#include <dev/pci/pcidevs.h> -#include <dev/pci/pcivar.h> -#include <dev/pci/agpvar.h> -#include <machine/bus.h> - -#include <linux/agp_backend.h> -#include <linux/cdev.h> -#include <linux/dma-mapping.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/highmem.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/kref.h> -#include <linux/miscdevice.h> -#include <linux/mm.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/poll.h> -#include <linux/ratelimit.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/workqueue.h> -#include <linux/dma-fence.h> -#include <linux/module.h> - -#include <dev/pci/drm/drm_linux.h> -#include <linux/list.h> -#include <linux/pci.h> -/* these match drm_os_linux.h includes */ -#include <linux/interrupt.h> -#include <linux/sched/signal.h> -#include <linux/delay.h> - -#include <uapi/drm/drm.h> -#include <uapi/drm/drm_mode.h> - -#include <drm/drm_crtc.h> -#include <drm/drm_fourcc.h> -#include <drm/drm_global.h> -#include <drm/drm_hashtab.h> -#include <drm/drm_mm.h> -#include <drm/drm_drv.h> -#include <drm/drm_prime.h> -#include <drm/drm_print.h> -#include <drm/drm_file.h> -#include <drm/drm_ioctl.h> -#include <drm/drm_vblank.h> -#include <drm/drm_irq.h> -#include <drm/drm_device.h> - -struct fb_cmap; -struct fb_fillrect; -struct fb_copyarea; -struct fb_image; - - /* Internal types and structures */ -#define DRM_IF_VERSION(maj, min) (maj << 16 | min) - -#define DRM_CURRENTPID curproc->p_p->ps_pid - -/* DRM_SUSER returns true if the user is superuser */ -#define DRM_SUSER(p) (suser(p) == 0) -#define DRM_MTRR_WC MDF_WRITECOMBINE - -#define drm_msleep(x) mdelay(x) - -extern struct cfdriver drm_cd; - -/* freebsd compat */ -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - } \ -} while (0) - -#define DRM_COPY_TO_USER(user, kern, size) copyout(kern, user, size) - -#define DRM_UDELAY(udelay) DELAY(udelay) - -static inline bool -drm_can_sleep(void) -{ -#if defined(__i386__) || defined(__amd64__) - if (pagefault_disabled() || in_dbg_master() || irqs_disabled()) -#else - if (in_dbg_master() || irqs_disabled()) -#endif - return false; - return true; -} - -#define DRM_WAIT_ON(ret, wq, timo, condition) do { \ - ret = wait_event_interruptible_timeout(wq, condition, timo); \ - if (ret == 0) \ - ret = -EBUSY; \ - if (ret > 0) \ - ret = 0; \ -} while (0) - -struct drm_pcidev { - uint16_t vendor; - uint16_t device; - uint16_t subvendor; - uint16_t subdevice; - uint32_t class; - uint32_t class_mask; - unsigned long driver_data; -}; - -struct drm_dmamem { - bus_dmamap_t map; - caddr_t kva; - bus_size_t size; - int nsegs; - bus_dma_segment_t segs[1]; -}; - -typedef struct drm_dma_handle { - struct drm_dmamem *mem; - dma_addr_t busaddr; - void *vaddr; - size_t size; -} drm_dma_handle_t; - -struct drm_agp_head { - struct agp_softc *agpdev; - const char *chipset; - TAILQ_HEAD(agp_memlist, drm_agp_mem) memory; - struct agp_info info; - unsigned long base; - unsigned long mode; - unsigned long page_mask; - int acquired; - int cant_use_aperture; - int enabled; - int mtrr; -}; - -/* Flags and return codes for get_vblank_timestamp() driver function. */ -#define DRM_CALLED_FROM_VBLIRQ 1 - -/* get_scanout_position() return flags */ -#define DRM_SCANOUTPOS_VALID (1 << 0) -#define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) -#define DRM_SCANOUTPOS_ACCURATE (1 << 2) - -struct drm_attach_args { - struct drm_device *drm; - struct drm_driver *driver; - char *busid; - bus_dma_tag_t dmat; - bus_space_tag_t bst; - size_t busid_len; - int is_agp; - struct pci_attach_args *pa; - int primary; -}; - -#define DRMDEVCF_PRIMARY 0 -#define drmdevcf_primary cf_loc[DRMDEVCF_PRIMARY] /* spec'd as primary? */ -#define DRMDEVCF_PRIMARY_UNK -1 - -void drm_linux_init(void); -int drm_linux_acpi_notify(struct aml_node *, int, void *); - -/* Device setup support (drm_drv.c) */ -int drm_pciprobe(struct pci_attach_args *, const struct drm_pcidev * ); -struct drm_device *drm_attach_pci(struct drm_driver *, - struct pci_attach_args *, int, int, struct device *, struct drm_device *); -int drmprint(void *, const char *); -int drmsubmatch(struct device *, void *, void *); -dev_type_ioctl(drmioctl); -dev_type_read(drmread); -dev_type_poll(drmpoll); -dev_type_open(drmopen); -dev_type_close(drmclose); -dev_type_mmap(drmmmap); -struct drm_dmamem *drm_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, - int, bus_size_t, int, int); -void drm_dmamem_free(bus_dma_tag_t, struct drm_dmamem *); - -extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, - size_t align); -extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); - -const struct drm_pcidev *drm_find_description(int , int , - const struct drm_pcidev *); -int drm_order(unsigned long); - -/* File operations helpers (drm_fops.c) */ -struct drm_file *drm_find_file_by_minor(struct drm_device *, int); -struct drm_device *drm_get_device_from_kdev(dev_t); - -int drm_mtrr_add(unsigned long, size_t, int); -int drm_mtrr_del(int, unsigned long, size_t, int); - -/* Cache management (drm_cache.c) */ -void drm_clflush_pages(struct vm_page *pages[], unsigned long num_pages); -void drm_clflush_sg(struct sg_table *st); -void drm_clflush_virt_range(void *addr, unsigned long length); - -/* AGP/PCI Express/GART support (drm_agpsupport.c) */ -struct drm_agp_head *drm_agp_init(void); -void drm_agp_takedown(struct drm_device *); -int drm_agp_acquire(struct drm_device *); -int drm_agp_release(struct drm_device *); -int drm_agp_info(struct drm_device *, struct drm_agp_info *); -int drm_agp_enable(struct drm_device *, struct drm_agp_mode); -void *drm_agp_allocate_memory(size_t, u32); -int drm_agp_free_memory(void *); -int drm_agp_bind_memory(void *, off_t); -int drm_agp_unbind_memory(void *); -int drm_agp_alloc(struct drm_device *, struct drm_agp_buffer *); -int drm_agp_free(struct drm_device *, struct drm_agp_buffer *); -int drm_agp_bind(struct drm_device *, struct drm_agp_binding *); -int drm_agp_unbind(struct drm_device *, struct drm_agp_binding *); - -/* AGP/GART support (drm_agpsupport.c) */ -int drm_agp_acquire_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_release_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_enable_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_info_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_alloc_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_free_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_unbind_ioctl(struct drm_device *, void *, struct drm_file *); -int drm_agp_bind_ioctl(struct drm_device *, void *, struct drm_file *); - -/* hotplug support */ -void drm_sysfs_hotplug_event(struct drm_device *); - -static inline int -drm_sysfs_connector_add(struct drm_connector *connector) -{ - return 0; -} - -static inline void -drm_sysfs_connector_remove(struct drm_connector *connector) -{ -} - -/* helper for handling conditionals in various for_each macros */ -#define for_each_if(condition) if (!(condition)) {} else - -static inline bool -drm_is_current_master(struct drm_file *file_priv) -{ - return (file_priv->is_master == 1); -} - -#endif /* __KERNEL__ */ -#endif /* _DRM_P_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_agpsupport.h b/sys/dev/pci/drm/include/drm/drm_agpsupport.h new file mode 100644 index 00000000000..77b2a58ae8f --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_agpsupport.h @@ -0,0 +1,47 @@ +/* Public domain. */ + +#ifndef _DRM_AGPSUPPORT_H_ +#define _DRM_AGPSUPPORT_H_ + +#include <dev/pci/pcivar.h> +#include <dev/pci/agpvar.h> +#include <uapi/drm/drm.h> + +struct drm_device; +struct drm_file; + +struct drm_agp_head { + struct agp_softc *agpdev; + const char *chipset; + TAILQ_HEAD(agp_memlist, drm_agp_mem) memory; + struct agp_info info; + unsigned long base; + unsigned long mode; + unsigned long page_mask; + int acquired; + int cant_use_aperture; + int enabled; + int mtrr; +}; + +struct drm_agp_head *drm_agp_init(void); +void drm_agp_takedown(struct drm_device *); +int drm_agp_acquire(struct drm_device *); +int drm_agp_release(struct drm_device *); +int drm_agp_info(struct drm_device *, struct drm_agp_info *); +int drm_agp_enable(struct drm_device *, struct drm_agp_mode); +int drm_agp_alloc(struct drm_device *, struct drm_agp_buffer *); +int drm_agp_free(struct drm_device *, struct drm_agp_buffer *); +int drm_agp_bind(struct drm_device *, struct drm_agp_binding *); +int drm_agp_unbind(struct drm_device *, struct drm_agp_binding *); + +int drm_agp_acquire_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_release_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_enable_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_info_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_alloc_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_free_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_unbind_ioctl(struct drm_device *, void *, struct drm_file *); +int drm_agp_bind_ioctl(struct drm_device *, void *, struct drm_file *); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_atomic.h b/sys/dev/pci/drm/include/drm/drm_atomic.h index 1e713154f00..7b6cb4774e7 100644 --- a/sys/dev/pci/drm/include/drm/drm_atomic.h +++ b/sys/dev/pci/drm/include/drm/drm_atomic.h @@ -29,12 +29,13 @@ #define DRM_ATOMIC_H_ #include <drm/drm_crtc.h> +#include <drm/drm_util.h> /** * struct drm_crtc_commit - track modeset commits on a CRTC * * This structure is used to track pending modeset changes and atomic commit on - * a per-CRTC basis. Since updating the list should never block this structure + * a per-CRTC basis. Since updating the list should never block, this structure * is reference counted to allow waiters to safely wait on an event to complete, * without holding any locks. * @@ -59,8 +60,8 @@ * wait for flip_done <---- * clean up atomic state * - * The important bit to know is that cleanup_done is the terminal event, but the - * ordering between flip_done and hw_done is entirely up to the specific driver + * The important bit to know is that &cleanup_done is the terminal event, but the + * ordering between &flip_done and &hw_done is entirely up to the specific driver * and modeset state change. * * For an implementation of how to use this look at @@ -91,6 +92,9 @@ struct drm_crtc_commit { * commit is sent to userspace, or when an out-fence is singalled. Note * that for most hardware, in most cases this happens after @hw_done is * signalled. + * + * Completion of this stage is signalled implicitly by calling + * drm_crtc_send_vblank_event() on &drm_crtc_state.event. */ struct completion flip_done; @@ -106,6 +110,9 @@ struct drm_crtc_commit { * Note that this does not need to include separately reference-counted * resources like backing storage buffer pinning, or runtime pm * management. + * + * Drivers should call drm_atomic_helper_commit_hw_done() to signal + * completion of this stage. */ struct completion hw_done; @@ -117,6 +124,9 @@ struct drm_crtc_commit { * a vblank wait completed it might be a bit later. This completion is * useful to throttle updates and avoid hardware updates getting ahead * of the buffer cleanup too much. + * + * Drivers should call drm_atomic_helper_commit_cleanup_done() to signal + * completion of this stage. */ struct completion cleanup_done; @@ -138,9 +148,9 @@ struct drm_crtc_commit { /** * @abort_completion: * - * A flag that's set after drm_atomic_helper_setup_commit takes a second - * reference for the completion of $drm_crtc_state.event. It's used by - * the free code to remove the second reference if commit fails. + * A flag that's set after drm_atomic_helper_setup_commit() takes a + * second reference for the completion of $drm_crtc_state.event. It's + * used by the free code to remove the second reference if commit fails. */ bool abort_completion; }; @@ -191,7 +201,7 @@ struct drm_private_state; * private objects. The structure itself is used as a vtable to identify the * associated private object type. Each private object type that needs to be * added to the atomic states is expected to have an implementation of these - * hooks and pass a pointer to it's drm_private_state_funcs struct to + * hooks and pass a pointer to its drm_private_state_funcs struct to * drm_atomic_get_private_obj_state(). */ struct drm_private_state_funcs { @@ -227,9 +237,31 @@ struct drm_private_state_funcs { * Currently only tracks the state update functions and the opaque driver * private state itself, but in the future might also track which * &drm_modeset_lock is required to duplicate and update this object's state. + * + * All private objects must be initialized before the DRM device they are + * attached to is registered to the DRM subsystem (call to drm_dev_register()) + * and should stay around until this DRM device is unregistered (call to + * drm_dev_unregister()). In other words, private objects lifetime is tied + * to the DRM device lifetime. This implies that: + * + * 1/ all calls to drm_atomic_private_obj_init() must be done before calling + * drm_dev_register() + * 2/ all calls to drm_atomic_private_obj_fini() must be done after calling + * drm_dev_unregister() */ struct drm_private_obj { /** + * @head: List entry used to attach a private object to a &drm_device + * (queued to &drm_mode_config.privobj_list). + */ + struct list_head head; + + /** + * @lock: Modeset lock to protect the state object. + */ + struct drm_modeset_lock lock; + + /** * @state: Current atomic state for this driver private object. */ struct drm_private_state *state; @@ -244,6 +276,18 @@ struct drm_private_obj { }; /** + * drm_for_each_privobj() - private object iterator + * + * @privobj: pointer to the current private object. Updated after each + * iteration + * @dev: the DRM device we want get private objects from + * + * Allows one to iterate over all private objects attached to @dev + */ +#define drm_for_each_privobj(privobj, dev) \ + list_for_each_entry(privobj, &(dev)->mode_config.privobj_list, head) + +/** * struct drm_private_state - base struct for driver private object state * @state: backpointer to global drm_atomic_state * @@ -264,7 +308,6 @@ struct __drm_private_objs_state { * struct drm_atomic_state - the global state object for atomic updates * @ref: count of all references to this state (will not be freed until zero) * @dev: parent DRM device - * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics * @async_update: hint for asynchronous plane update * @planes: pointer to array of structures with per-plane data @@ -283,9 +326,27 @@ struct drm_atomic_state { struct kref ref; struct drm_device *dev; + + /** + * @allow_modeset: + * + * Allow full modeset. This is used by the ATOMIC IOCTL handler to + * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should + * never consult this flag, instead looking at the output of + * drm_atomic_crtc_needs_modeset(). + */ bool allow_modeset : 1; bool legacy_cursor_update : 1; bool async_update : 1; + /** + * @duplicated: + * + * Indicates whether or not this atomic state was duplicated using + * drm_atomic_helper_duplicate_state(). Drivers and atomic helpers + * should use this to fixup normal inconsistencies in duplicated + * states. + */ + bool duplicated : 1; struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; @@ -302,7 +363,7 @@ struct drm_atomic_state { * When a connector or plane is not bound to any CRTC, it's still important * to preserve linearity to prevent the atomic states from being freed to early. * - * This commit (if set) is not bound to any crtc, but will be completed when + * This commit (if set) is not bound to any CRTC, but will be completed when * drm_atomic_helper_commit_hw_done() is called. */ struct drm_crtc_commit *fake_commit; @@ -384,9 +445,6 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state); struct drm_crtc_state * __must_check drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc); -int drm_atomic_crtc_set_property(struct drm_crtc *crtc, - struct drm_crtc_state *state, struct drm_property *property, - uint64_t val); struct drm_plane_state * __must_check drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane); @@ -394,7 +452,8 @@ struct drm_connector_state * __must_check drm_atomic_get_connector_state(struct drm_atomic_state *state, struct drm_connector *connector); -void drm_atomic_private_obj_init(struct drm_private_obj *obj, +void drm_atomic_private_obj_init(struct drm_device *dev, + struct drm_private_obj *obj, struct drm_private_state *state, const struct drm_private_state_funcs *funcs); void drm_atomic_private_obj_fini(struct drm_private_obj *obj); @@ -402,14 +461,27 @@ void drm_atomic_private_obj_fini(struct drm_private_obj *obj); struct drm_private_state * __must_check drm_atomic_get_private_obj_state(struct drm_atomic_state *state, struct drm_private_obj *obj); +struct drm_private_state * +drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state, + struct drm_private_obj *obj); +struct drm_private_state * +drm_atomic_get_new_private_obj_state(struct drm_atomic_state *state, + struct drm_private_obj *obj); + +struct drm_connector * +drm_atomic_get_old_connector_for_encoder(struct drm_atomic_state *state, + struct drm_encoder *encoder); +struct drm_connector * +drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state, + struct drm_encoder *encoder); /** - * drm_atomic_get_existing_crtc_state - get crtc state, if it exists + * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the crtc state for the given crtc, or NULL - * if the crtc is not part of the global atomic state. + * This function returns the CRTC state for the given CRTC, or NULL + * if the CRTC is not part of the global atomic state. * * This function is deprecated, @drm_atomic_get_old_crtc_state or * @drm_atomic_get_new_crtc_state should be used instead. @@ -422,12 +494,12 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state, } /** - * drm_atomic_get_old_crtc_state - get old crtc state, if it exists + * drm_atomic_get_old_crtc_state - get old CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the old crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the old CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, @@ -436,12 +508,12 @@ drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, return state->crtcs[drm_crtc_index(crtc)].old_state; } /** - * drm_atomic_get_new_crtc_state - get new crtc state, if it exists + * drm_atomic_get_new_crtc_state - get new CRTC state, if it exists * @state: global atomic state object - * @crtc: crtc to grab + * @crtc: CRTC to grab * - * This function returns the new crtc state for the given crtc, or - * NULL if the crtc is not part of the global atomic state. + * This function returns the new CRTC state for the given CRTC, or + * NULL if the CRTC is not part of the global atomic state. */ static inline struct drm_crtc_state * drm_atomic_get_new_crtc_state(struct drm_atomic_state *state, @@ -598,24 +670,8 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, } int __must_check -drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, - const struct drm_display_mode *mode); -int __must_check -drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, - struct drm_property_blob *blob); -int __must_check -drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, - struct drm_crtc *crtc); -void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, - struct drm_framebuffer *fb); -void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, - struct dma_fence *fence); -int __must_check -drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, - struct drm_crtc *crtc); -int drm_atomic_set_writeback_fb_for_connector( - struct drm_connector_state *conn_state, - struct drm_framebuffer *fb); +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); @@ -649,6 +705,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ (old_connector_state) = (__state)->connectors[__i].old_state, \ (new_connector_state) = (__state)->connectors[__i].new_state, 1)) @@ -670,6 +727,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ (old_connector_state) = (__state)->connectors[__i].old_state, 1)) /** @@ -690,7 +748,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->connectors[__i].ptr && \ ((connector) = (__state)->connectors[__i].ptr, \ - (new_connector_state) = (__state)->connectors[__i].new_state, 1)) + (void)(connector) /* Only to avoid unused-but-set-variable warning */, \ + (new_connector_state) = (__state)->connectors[__i].new_state, \ + (void)(new_connector_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update @@ -710,7 +770,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->crtcs[__i].ptr && \ ((crtc) = (__state)->crtcs[__i].ptr, \ + (void)(crtc) /* Only to avoid unused-but-set-variable warning */, \ (old_crtc_state) = (__state)->crtcs[__i].old_state, \ + (void)(old_crtc_state) /* Only to avoid unused-but-set-variable warning */, \ (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) /** @@ -749,7 +811,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->crtcs[__i].ptr && \ ((crtc) = (__state)->crtcs[__i].ptr, \ - (new_crtc_state) = (__state)->crtcs[__i].new_state, 1)) + (void)(crtc) /* Only to avoid unused-but-set-variable warning */, \ + (new_crtc_state) = (__state)->crtcs[__i].new_state, \ + (void)(new_crtc_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update @@ -769,6 +833,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->planes[__i].ptr && \ ((plane) = (__state)->planes[__i].ptr, \ + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \ (old_plane_state) = (__state)->planes[__i].old_state,\ (new_plane_state) = (__state)->planes[__i].new_state, 1)) @@ -829,7 +894,9 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if ((__state)->planes[__i].ptr && \ ((plane) = (__state)->planes[__i].ptr, \ - (new_plane_state) = (__state)->planes[__i].new_state, 1)) + (void)(plane) /* Only to avoid unused-but-set-variable warning */, \ + (new_plane_state) = (__state)->planes[__i].new_state, \ + (void)(new_plane_state) /* Only to avoid unused-but-set-variable warning */, 1)) /** * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update @@ -913,4 +980,92 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) state->connectors_changed; } +/** + * drm_atomic_crtc_effectively_active - compute whether CRTC is actually active + * @state: &drm_crtc_state for the CRTC + * + * When in self refresh mode, the crtc_state->active value will be false, since + * the CRTC is off. However in some cases we're interested in whether the CRTC + * is active, or effectively active (ie: it's connected to an active display). + * In these cases, use this function instead of just checking active. + */ +static inline bool +drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state) +{ + return state->active || state->self_refresh_active; +} + +/** + * struct drm_bus_cfg - bus configuration + * + * This structure stores the configuration of a physical bus between two + * components in an output pipeline, usually between two bridges, an encoder + * and a bridge, or a bridge and a connector. + * + * The bus configuration is stored in &drm_bridge_state separately for the + * input and output buses, as seen from the point of view of each bridge. The + * bus configuration of a bridge output is usually identical to the + * configuration of the next bridge's input, but may differ if the signals are + * modified between the two bridges, for instance by an inverter on the board. + * The input and output configurations of a bridge may differ if the bridge + * modifies the signals internally, for instance by performing format + * conversion, or modifying signals polarities. + */ +struct drm_bus_cfg { + /** + * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format) + * + * This field should not be directly modified by drivers + * (drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus + * format negotiation). + */ + u32 format; + + /** + * @flags: DRM_BUS_* flags used on this bus + */ + u32 flags; +}; + +/** + * struct drm_bridge_state - Atomic bridge state object + */ +struct drm_bridge_state { + /** + * @base: inherit from &drm_private_state + */ + struct drm_private_state base; + + /** + * @bridge: the bridge this state refers to + */ + struct drm_bridge *bridge; + + /** + * @input_bus_cfg: input bus configuration + */ + struct drm_bus_cfg input_bus_cfg; + + /** + * @output_bus_cfg: input bus configuration + */ + struct drm_bus_cfg output_bus_cfg; +}; + +static inline struct drm_bridge_state * +drm_priv_to_bridge_state(struct drm_private_state *priv) +{ + return container_of(priv, struct drm_bridge_state, base); +} + +struct drm_bridge_state * +drm_atomic_get_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge); +struct drm_bridge_state * +drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge); +struct drm_bridge_state * +drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge); + #endif /* DRM_ATOMIC_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_atomic_helper.h b/sys/dev/pci/drm/include/drm/drm_atomic_helper.h index 99e2a5297c6..b268180c97e 100644 --- a/sys/dev/pci/drm/include/drm/drm_atomic_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_atomic_helper.h @@ -31,6 +31,8 @@ #include <drm/drm_crtc.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_modeset_helper.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_util.h> struct drm_atomic_state; struct drm_private_obj; @@ -115,16 +117,15 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); -int __drm_atomic_helper_disable_plane(struct drm_plane *plane, - struct drm_plane_state *plane_state); int drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx); -int __drm_atomic_helper_set_config(struct drm_mode_set *set, - struct drm_atomic_state *state); int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); void drm_atomic_helper_shutdown(struct drm_device *dev); +struct drm_atomic_state * +drm_atomic_helper_duplicate_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); @@ -143,54 +144,15 @@ int drm_atomic_helper_page_flip_target( uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx); -struct drm_encoder * -drm_atomic_helper_best_encoder(struct drm_connector *connector); - -/* default implementations for state handling */ -void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); -void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, - struct drm_crtc_state *state); -struct drm_crtc_state * -drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); -void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); -void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state); - -void drm_atomic_helper_plane_reset(struct drm_plane *plane); -void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, - struct drm_plane_state *state); -struct drm_plane_state * -drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); -void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); -void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state); - -void __drm_atomic_helper_connector_reset(struct drm_connector *connector, - struct drm_connector_state *conn_state); -void drm_atomic_helper_connector_reset(struct drm_connector *connector); -void -__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, - struct drm_connector_state *state); -struct drm_connector_state * -drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); -struct drm_atomic_state * -drm_atomic_helper_duplicate_state(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx); -void -__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); -void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, - struct drm_connector_state *state); int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size, struct drm_modeset_acquire_ctx *ctx); -void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, - struct drm_private_state *state); /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * @plane: the loop cursor - * @crtc: the crtc whose planes are iterated + * @crtc: the CRTC whose planes are iterated * * This iterates over the current state, useful (for example) when applying * atomic state after it has been checked and swapped. To iterate over the @@ -204,7 +166,7 @@ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj /** * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state * @plane: the loop cursor - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -218,7 +180,7 @@ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj * drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state * @plane: the loop cursor * @plane_state: loop cursor for the plane's state, must be const - * @crtc_state: the incoming crtc-state + * @crtc_state: the incoming CRTC state * * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * attached if the specified state is applied. Useful during for example @@ -227,7 +189,7 @@ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj * * Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a * const plane_state. This is useful when a driver just wants to peek at other - * active planes on this crtc, but does not need to change it. + * active planes on this CRTC, but does not need to change it. */ #define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \ drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \ @@ -262,4 +224,12 @@ drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state, return old_plane_state->crtc && !new_plane_state->crtc; } +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + #endif /* DRM_ATOMIC_HELPER_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_atomic_state_helper.h b/sys/dev/pci/drm/include/drm/drm_atomic_state_helper.h new file mode 100644 index 00000000000..3f8f1d627f7 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_atomic_state_helper.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Rob Clark <robdclark@gmail.com> + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#include <linux/types.h> + +struct drm_bridge; +struct drm_bridge_state; +struct drm_crtc; +struct drm_crtc_state; +struct drm_plane; +struct drm_plane_state; +struct drm_connector; +struct drm_connector_state; +struct drm_private_obj; +struct drm_private_state; +struct drm_modeset_acquire_ctx; +struct drm_device; + +void __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *state, + struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, + struct drm_crtc_state *state); +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); +struct drm_crtc_state * +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); + +void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *state, + struct drm_plane *plane); +void __drm_atomic_helper_plane_reset(struct drm_plane *plane, + struct drm_plane_state *state); +void drm_atomic_helper_plane_reset(struct drm_plane *plane); +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state); +struct drm_plane_state * +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); +void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); + +void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state, + struct drm_connector *connector); +void __drm_atomic_helper_connector_reset(struct drm_connector *connector, + struct drm_connector_state *conn_state); +void drm_atomic_helper_connector_reset(struct drm_connector *connector); +void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector); +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state); +struct drm_connector_state * +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); +void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state); +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *state); + +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *state); +struct drm_bridge_state * +drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge); +void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state); +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state); +struct drm_bridge_state * +drm_atomic_helper_bridge_reset(struct drm_bridge *bridge); diff --git a/sys/dev/pci/drm/include/drm/drm_atomic_uapi.h b/sys/dev/pci/drm/include/drm/drm_atomic_uapi.h new file mode 100644 index 00000000000..8cec52ad127 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_atomic_uapi.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Red Hat + * Copyright (C) 2014 Intel Corp. + * Copyright (C) 2018 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Rob Clark <robdclark@gmail.com> + * Daniel Vetter <daniel.vetter@ffwll.ch> + */ + +#ifndef DRM_ATOMIC_UAPI_H_ +#define DRM_ATOMIC_UAPI_H_ + +struct drm_crtc_state; +struct drm_display_mode; +struct drm_property_blob; +struct drm_plane_state; +struct drm_crtc; +struct drm_connector_state; +struct dma_fence; +struct drm_framebuffer; + +int __must_check +drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + const struct drm_display_mode *mode); +int __must_check +drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, + struct drm_property_blob *blob); +int __must_check +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, + struct drm_crtc *crtc); +void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, + struct drm_framebuffer *fb); +void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct dma_fence *fence); +int __must_check +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, + struct drm_crtc *crtc); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_audio_component.h b/sys/dev/pci/drm/include/drm/drm_audio_component.h index 4923b00328c..a45f9348703 100644 --- a/sys/dev/pci/drm/include/drm/drm_audio_component.h +++ b/sys/dev/pci/drm/include/drm/drm_audio_component.h @@ -5,6 +5,7 @@ #define _DRM_AUDIO_COMPONENT_H_ struct drm_audio_component; +struct device; /** * struct drm_audio_component_ops - Ops implemented by DRM driver, called by hda driver @@ -18,14 +19,17 @@ struct drm_audio_component_ops { * @get_power: get the POWER_DOMAIN_AUDIO power well * * Request the power well to be turned on. + * + * Returns a wakeref cookie to be passed back to the corresponding + * call to @put_power. */ - void (*get_power)(struct device *); + unsigned long (*get_power)(struct device *); /** * @put_power: put the POWER_DOMAIN_AUDIO power well * * Allow the power well to be turned off. */ - void (*put_power)(struct device *); + void (*put_power)(struct device *, unsigned long); /** * @codec_wake_override: Enable/disable codec wake signal */ diff --git a/sys/dev/pci/drm/include/drm/drm_auth.h b/sys/dev/pci/drm/include/drm/drm_auth.h new file mode 100644 index 00000000000..6bf8b2b7899 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_auth.h @@ -0,0 +1,115 @@ +#ifndef _DRM_AUTH_H_ +#define _DRM_AUTH_H_ + +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 2016 Intel Corporation + * + * Author: Daniel Vetter <daniel.vetter@ffwll.ch> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <linux/idr.h> +#include <linux/kref.h> +#include <linux/wait.h> + +struct drm_file; +struct drm_hw_lock; + +/* + * Legacy DRI1 locking data structure. Only here instead of in drm_legacy.h for + * include ordering reasons. + * + * DO NOT USE. + */ +struct drm_lock_data { + struct drm_hw_lock *hw_lock; + struct drm_file *file_priv; + wait_queue_head_t lock_queue; + unsigned long lock_time; + spinlock_t spinlock; + uint32_t kernel_waiters; + uint32_t user_waiters; + int idle_has_lock; +}; + +/** + * struct drm_master - drm master structure + * + * @refcount: Refcount for this master object. + * @dev: Link back to the DRM device + * @driver_priv: Pointer to driver-private information. + * @lessor: Lease holder + * @lessee_id: id for lessees. Owners always have id 0 + * @lessee_list: other lessees of the same master + * @lessees: drm_masters leasing from this one + * @leases: Objects leased to this drm_master. + * @lessee_idr: All lessees under this owner (only used where lessor == NULL) + * + * Note that master structures are only relevant for the legacy/primary device + * nodes, hence there can only be one per device, not one per drm_minor. + */ +struct drm_master { + struct kref refcount; + struct drm_device *dev; + /** + * @unique: Unique identifier: e.g. busid. Protected by + * &drm_device.master_mutex. + */ + char *unique; + /** + * @unique_len: Length of unique field. Protected by + * &drm_device.master_mutex. + */ + int unique_len; + /** + * @magic_map: Map of used authentication tokens. Protected by + * &drm_device.master_mutex. + */ + struct idr magic_map; + void *driver_priv; + + /* Tree of display resource leases, each of which is a drm_master struct + * All of these get activated simultaneously, so drm_device master points + * at the top of the tree (for which lessor is NULL). Protected by + * &drm_device.mode_config.idr_mutex. + */ + + struct drm_master *lessor; + int lessee_id; + struct list_head lessee_list; + struct list_head lessees; + struct idr leases; + struct idr lessee_idr; + /* private: */ +#if IS_ENABLED(CONFIG_DRM_LEGACY) + struct drm_lock_data lock; +#endif +}; + +struct drm_master *drm_master_get(struct drm_master *master); +void drm_master_put(struct drm_master **master); +bool drm_is_current_master(struct drm_file *fpriv); + +struct drm_master *drm_master_create(struct drm_device *dev); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_blend.h b/sys/dev/pci/drm/include/drm/drm_blend.h index 330c561c4c1..88bdfec3bd8 100644 --- a/sys/dev/pci/drm/include/drm/drm_blend.h +++ b/sys/dev/pci/drm/include/drm/drm_blend.h @@ -27,6 +27,10 @@ #include <linux/ctype.h> #include <drm/drm_mode.h> +#define DRM_MODE_BLEND_PREMULTI 0 +#define DRM_MODE_BLEND_COVERAGE 1 +#define DRM_MODE_BLEND_PIXEL_NONE 2 + struct drm_device; struct drm_atomic_state; struct drm_plane; @@ -52,4 +56,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, unsigned int zpos); int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); +int drm_plane_create_blend_mode_property(struct drm_plane *plane, + unsigned int supported_modes); #endif diff --git a/sys/dev/pci/drm/include/drm/drm_bridge.h b/sys/dev/pci/drm/include/drm/drm_bridge.h index bd850747ce5..20e0a0d6d7c 100644 --- a/sys/dev/pci/drm/include/drm/drm_bridge.h +++ b/sys/dev/pci/drm/include/drm/drm_bridge.h @@ -23,14 +23,32 @@ #ifndef __DRM_BRIDGE_H__ #define __DRM_BRIDGE_H__ -#include <linux/list.h> #include <linux/ctype.h> +#include <linux/list.h> +#include <linux/mutex.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_encoder.h> #include <drm/drm_mode_object.h> #include <drm/drm_modes.h> struct drm_bridge; struct drm_bridge_timings; +struct drm_connector; struct drm_panel; +struct edid; +struct i2c_adapter; + +/** + * enum drm_bridge_attach_flags - Flags for &drm_bridge_funcs.attach + */ +enum drm_bridge_attach_flags { + /** + * @DRM_BRIDGE_ATTACH_NO_CONNECTOR: When this flag is set the bridge + * shall not create a drm_connector. + */ + DRM_BRIDGE_ATTACH_NO_CONNECTOR = BIT(0), +}; /** * struct drm_bridge_funcs - drm_bridge control functions @@ -40,15 +58,17 @@ struct drm_bridge_funcs { * @attach: * * This callback is invoked whenever our bridge is being attached to a - * &drm_encoder. + * &drm_encoder. The flags argument tunes the behaviour of the attach + * operation (see DRM_BRIDGE_ATTACH_*). * - * The attach callback is optional. + * The @attach callback is optional. * * RETURNS: * * Zero on success, error code on failure. */ - int (*attach)(struct drm_bridge *bridge); + int (*attach)(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags); /** * @detach: @@ -56,7 +76,7 @@ struct drm_bridge_funcs { * This callback is invoked whenever our bridge is being detached from a * &drm_encoder. * - * The detach callback is optional. + * The @detach callback is optional. */ void (*detach)(struct drm_bridge *bridge); @@ -76,7 +96,7 @@ struct drm_bridge_funcs { * atomic helpers to validate modes supplied by userspace in * drm_atomic_helper_check_modeset(). * - * This function is optional. + * The @mode_valid callback is optional. * * NOTE: * @@ -108,7 +128,9 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The mode_fixup callback is optional. + * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() + * is not called when &drm_bridge_funcs.atomic_check() is implemented, + * so only one of them should be provided. * * NOTE: * @@ -146,7 +168,7 @@ struct drm_bridge_funcs { * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. * - * The disable callback is optional. + * The @disable callback is optional. */ void (*disable)(struct drm_bridge *bridge); @@ -165,7 +187,7 @@ struct drm_bridge_funcs { * singals) feeding it is no longer running when this callback is * called. * - * The post_disable callback is optional. + * The @post_disable callback is optional. */ void (*post_disable)(struct drm_bridge *bridge); @@ -196,8 +218,8 @@ struct drm_bridge_funcs { * the DRM framework will have to be extended with DRM bridge states. */ void (*mode_set)(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); /** * @pre_enable: * @@ -214,7 +236,7 @@ struct drm_bridge_funcs { * not enable the display link feeding the next bridge in the chain (if * there is one) when this callback is called. * - * The pre_enable callback is optional. + * The @pre_enable callback is optional. */ void (*pre_enable)(struct drm_bridge *bridge); @@ -234,9 +256,377 @@ struct drm_bridge_funcs { * callback must enable the display link feeding the next bridge in the * chain if there is one. * - * The enable callback is optional. + * The @enable callback is optional. */ void (*enable)(struct drm_bridge *bridge); + + /** + * @atomic_pre_enable: + * + * This callback should enable the bridge. It is called right before + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @atomic_pre_enable or @pre_enable function. If the preceding + * element is a &drm_encoder it's called right before the encoder's + * &drm_encoder_helper_funcs.atomic_enable hook. + * + * The display pipe (i.e. clocks and timing signals) feeding this bridge + * will not yet be running when this callback is called. The bridge must + * not enable the display link feeding the next bridge in the chain (if + * there is one) when this callback is called. + * + * Note that this function will only be invoked in the context of an + * atomic commit. It will not be invoked from + * &drm_bridge_chain_pre_enable. It would be prudent to also provide an + * implementation of @pre_enable if you are expecting driver calls into + * &drm_bridge_chain_pre_enable. + * + * The @atomic_pre_enable callback is optional. + */ + void (*atomic_pre_enable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + + /** + * @atomic_enable: + * + * This callback should enable the bridge. It is called right after + * the preceding element in the display pipe is enabled. If the + * preceding element is a bridge this means it's called after that + * bridge's @atomic_enable or @enable function. If the preceding element + * is a &drm_encoder it's called right after the encoder's + * &drm_encoder_helper_funcs.atomic_enable hook. + * + * The bridge can assume that the display pipe (i.e. clocks and timing + * signals) feeding it is running when this callback is called. This + * callback must enable the display link feeding the next bridge in the + * chain if there is one. + * + * Note that this function will only be invoked in the context of an + * atomic commit. It will not be invoked from &drm_bridge_chain_enable. + * It would be prudent to also provide an implementation of @enable if + * you are expecting driver calls into &drm_bridge_chain_enable. + * + * The @atomic_enable callback is optional. + */ + void (*atomic_enable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + /** + * @atomic_disable: + * + * This callback should disable the bridge. It is called right before + * the preceding element in the display pipe is disabled. If the + * preceding element is a bridge this means it's called before that + * bridge's @atomic_disable or @disable vfunc. If the preceding element + * is a &drm_encoder it's called right before the + * &drm_encoder_helper_funcs.atomic_disable hook. + * + * The bridge can assume that the display pipe (i.e. clocks and timing + * signals) feeding it is still running when this callback is called. + * + * Note that this function will only be invoked in the context of an + * atomic commit. It will not be invoked from + * &drm_bridge_chain_disable. It would be prudent to also provide an + * implementation of @disable if you are expecting driver calls into + * &drm_bridge_chain_disable. + * + * The @atomic_disable callback is optional. + */ + void (*atomic_disable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + + /** + * @atomic_post_disable: + * + * This callback should disable the bridge. It is called right after the + * preceding element in the display pipe is disabled. If the preceding + * element is a bridge this means it's called after that bridge's + * @atomic_post_disable or @post_disable function. If the preceding + * element is a &drm_encoder it's called right after the encoder's + * &drm_encoder_helper_funcs.atomic_disable hook. + * + * The bridge must assume that the display pipe (i.e. clocks and timing + * signals) feeding it is no longer running when this callback is + * called. + * + * Note that this function will only be invoked in the context of an + * atomic commit. It will not be invoked from + * &drm_bridge_chain_post_disable. + * It would be prudent to also provide an implementation of + * @post_disable if you are expecting driver calls into + * &drm_bridge_chain_post_disable. + * + * The @atomic_post_disable callback is optional. + */ + void (*atomic_post_disable)(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state); + + /** + * @atomic_duplicate_state: + * + * Duplicate the current bridge state object (which is guaranteed to be + * non-NULL). + * + * The atomic_duplicate_state hook is mandatory if the bridge + * implements any of the atomic hooks, and should be left unassigned + * otherwise. For bridges that don't subclass &drm_bridge_state, the + * drm_atomic_helper_bridge_duplicate_state() helper function shall be + * used to implement this hook. + * + * RETURNS: + * A valid drm_bridge_state object or NULL if the allocation fails. + */ + struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); + + /** + * @atomic_destroy_state: + * + * Destroy a bridge state object previously allocated by + * &drm_bridge_funcs.atomic_duplicate_state(). + * + * The atomic_destroy_state hook is mandatory if the bridge implements + * any of the atomic hooks, and should be left unassigned otherwise. + * For bridges that don't subclass &drm_bridge_state, the + * drm_atomic_helper_bridge_destroy_state() helper function shall be + * used to implement this hook. + */ + void (*atomic_destroy_state)(struct drm_bridge *bridge, + struct drm_bridge_state *state); + + /** + * @atomic_get_output_bus_fmts: + * + * Return the supported bus formats on the output end of a bridge. + * The returned array must be allocated with kmalloc() and will be + * freed by the caller. If the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). + * + * This method is only called on the last element of the bridge chain + * as part of the bus format negotiation process that happens in + * &drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will + * fall back to &drm_connector.display_info.bus_formats[0] if + * &drm_connector.display_info.num_bus_formats > 0, + * or to MEDIA_BUS_FMT_FIXED otherwise. + */ + u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts); + + /** + * @atomic_get_input_bus_fmts: + * + * Return the supported bus formats on the input end of a bridge for + * a specific output bus format. + * + * The returned array must be allocated with kmalloc() and will be + * freed by the caller. If the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). When the format is not supported NULL should be + * returned and num_output_fmts should be set to 0. + * + * This method is called on all elements of the bridge chain as part of + * the bus format negotiation process that happens in + * drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will bypass + * bus format negotiation on this element of the bridge without + * failing, and the previous element in the chain will be passed + * MEDIA_BUS_FMT_FIXED as its output bus format. + * + * Bridge drivers that need to support being linked to bridges that are + * not supporting bus format negotiation should handle the + * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a + * sensible default value or extracting this information from somewhere + * else (FW property, &drm_display_mode, &drm_display_info, ...) + * + * Note: Even if input format selection on the first bridge has no + * impact on the negotiation process (bus format negotiation stops once + * we reach the first element of the chain), drivers are expected to + * return accurate input formats as the input format may be used to + * configure the CRTC output appropriately. + */ + u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + + /** + * @atomic_check: + * + * This method is responsible for checking bridge state correctness. + * It can also check the state of the surrounding components in chain + * to make sure the whole pipeline can work properly. + * + * &drm_bridge_funcs.atomic_check() hooks are called in reverse + * order (from the last to the first bridge). + * + * This method is optional. &drm_bridge_funcs.mode_fixup() is not + * called when &drm_bridge_funcs.atomic_check() is implemented, so only + * one of them should be provided. + * + * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or + * &drm_bridge_state.output_bus_cfg.flags it should should happen in + * this function. By default the &drm_bridge_state.output_bus_cfg.flags + * field is set to the next bridge + * &drm_bridge_state.input_bus_cfg.flags value or + * &drm_connector.display_info.bus_flags if the bridge is the last + * element in the chain. + * + * RETURNS: + * zero if the check passed, a negative error code otherwise. + */ + int (*atomic_check)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + + /** + * @atomic_reset: + * + * Reset the bridge to a predefined state (or retrieve its current + * state) and return a &drm_bridge_state object matching this state. + * This function is called at attach time. + * + * The atomic_reset hook is mandatory if the bridge implements any of + * the atomic hooks, and should be left unassigned otherwise. For + * bridges that don't subclass &drm_bridge_state, the + * drm_atomic_helper_bridge_reset() helper function shall be used to + * implement this hook. + * + * Note that the atomic_reset() semantics is not exactly matching the + * reset() semantics found on other components (connector, plane, ...). + * + * 1. The reset operation happens when the bridge is attached, not when + * drm_mode_config_reset() is called + * 2. It's meant to be used exclusively on bridges that have been + * converted to the ATOMIC API + * + * RETURNS: + * A valid drm_bridge_state object in case of success, an ERR_PTR() + * giving the reason of the failure otherwise. + */ + struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); + + /** + * @detect: + * + * Check if anything is attached to the bridge output. + * + * This callback is optional, if not implemented the bridge will be + * considered as always having a component attached to its output. + * Bridges that implement this callback shall set the + * DRM_BRIDGE_OP_DETECT flag in their &drm_bridge->ops. + * + * RETURNS: + * + * drm_connector_status indicating the bridge output status. + */ + enum drm_connector_status (*detect)(struct drm_bridge *bridge); + + /** + * @get_modes: + * + * Fill all modes currently valid for the sink into the &drm_connector + * with drm_mode_probed_add(). + * + * The @get_modes callback is mostly intended to support non-probeable + * displays such as many fixed panels. Bridges that support reading + * EDID shall leave @get_modes unimplemented and implement the + * &drm_bridge_funcs->get_edid callback instead. + * + * This callback is optional. Bridges that implement it shall set the + * DRM_BRIDGE_OP_MODES flag in their &drm_bridge->ops. + * + * The connector parameter shall be used for the sole purpose of + * filling modes, and shall not be stored internally by bridge drivers + * for future usage. + * + * RETURNS: + * + * The number of modes added by calling drm_mode_probed_add(). + */ + int (*get_modes)(struct drm_bridge *bridge, + struct drm_connector *connector); + + /** + * @get_edid: + * + * Read and parse the EDID data of the connected display. + * + * The @get_edid callback is the preferred way of reporting mode + * information for a display connected to the bridge output. Bridges + * that support reading EDID shall implement this callback and leave + * the @get_modes callback unimplemented. + * + * The caller of this operation shall first verify the output + * connection status and refrain from reading EDID from a disconnected + * output. + * + * This callback is optional. Bridges that implement it shall set the + * DRM_BRIDGE_OP_EDID flag in their &drm_bridge->ops. + * + * The connector parameter shall be used for the sole purpose of EDID + * retrieval and parsing, and shall not be stored internally by bridge + * drivers for future usage. + * + * RETURNS: + * + * An edid structure newly allocated with kmalloc() (or similar) on + * success, or NULL otherwise. The caller is responsible for freeing + * the returned edid structure with kfree(). + */ + struct edid *(*get_edid)(struct drm_bridge *bridge, + struct drm_connector *connector); + + /** + * @hpd_notify: + * + * Notify the bridge of hot plug detection. + * + * This callback is optional, it may be implemented by bridges that + * need to be notified of display connection or disconnection for + * internal reasons. One use case is to reset the internal state of CEC + * controllers for HDMI bridges. + */ + void (*hpd_notify)(struct drm_bridge *bridge, + enum drm_connector_status status); + + /** + * @hpd_enable: + * + * Enable hot plug detection. From now on the bridge shall call + * drm_bridge_hpd_notify() each time a change is detected in the output + * connection status, until hot plug detection gets disabled with + * @hpd_disable. + * + * This callback is optional and shall only be implemented by bridges + * that support hot-plug notification without polling. Bridges that + * implement it shall also implement the @hpd_disable callback and set + * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops. + */ + void (*hpd_enable)(struct drm_bridge *bridge); + + /** + * @hpd_disable: + * + * Disable hot plug detection. Once this function returns the bridge + * shall not call drm_bridge_hpd_notify() when a change in the output + * connection status occurs. + * + * This callback is optional and shall only be implemented by bridges + * that support hot-plug notification without polling. Bridges that + * implement it shall also implement the @hpd_enable callback and set + * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops. + */ + void (*hpd_disable)(struct drm_bridge *bridge); }; /** @@ -244,14 +634,13 @@ struct drm_bridge_funcs { */ struct drm_bridge_timings { /** - * @sampling_edge: + * @input_bus_flags: * - * Tells whether the bridge samples the digital input signal - * from the display engine on the positive or negative edge of the - * clock, this should reuse the DRM_BUS_FLAG_PIXDATA_[POS|NEG]EDGE - * bitwise flags from the DRM connector (bit 2 and 3 valid). + * Tells what additional settings for the pixel data on the bus + * this bridge requires (like pixel signal polarity). See also + * &drm_display_info->bus_flags. */ - u32 sampling_edge; + u32 input_bus_flags; /** * @setup_time_ps: * @@ -266,18 +655,61 @@ struct drm_bridge_timings { * input signal after the clock edge. */ u32 hold_time_ps; + /** + * @dual_link: + * + * True if the bus operates in dual-link mode. The exact meaning is + * dependent on the bus type. For LVDS buses, this indicates that even- + * and odd-numbered pixels are received on separate links. + */ + bool dual_link; +}; + +/** + * enum drm_bridge_ops - Bitmask of operations supported by the bridge + */ +enum drm_bridge_ops { + /** + * @DRM_BRIDGE_OP_DETECT: The bridge can detect displays connected to + * its output. Bridges that set this flag shall implement the + * &drm_bridge_funcs->detect callback. + */ + DRM_BRIDGE_OP_DETECT = BIT(0), + /** + * @DRM_BRIDGE_OP_EDID: The bridge can retrieve the EDID of the display + * connected to its output. Bridges that set this flag shall implement + * the &drm_bridge_funcs->get_edid callback. + */ + DRM_BRIDGE_OP_EDID = BIT(1), + /** + * @DRM_BRIDGE_OP_HPD: The bridge can detect hot-plug and hot-unplug + * without requiring polling. Bridges that set this flag shall + * implement the &drm_bridge_funcs->hpd_enable and + * &drm_bridge_funcs->hpd_disable callbacks if they support enabling + * and disabling hot-plug detection dynamically. + */ + DRM_BRIDGE_OP_HPD = BIT(2), + /** + * @DRM_BRIDGE_OP_MODES: The bridge can retrieve the modes supported + * by the display at its output. This does not include reading EDID + * which is separately covered by @DRM_BRIDGE_OP_EDID. Bridges that set + * this flag shall implement the &drm_bridge_funcs->get_modes callback. + */ + DRM_BRIDGE_OP_MODES = BIT(3), }; /** * struct drm_bridge - central DRM bridge control structure */ struct drm_bridge { + /** @base: inherit from &drm_private_object */ + struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; - /** @next: the next bridge in the encoder chain */ - struct drm_bridge *next; + /** @chain_node: used to form a bridge chain */ + struct list_head chain_node; #ifdef CONFIG_OF /** @of_node: device node pointer to the bridge */ struct device_node *of_node; @@ -294,34 +726,169 @@ struct drm_bridge { const struct drm_bridge_funcs *funcs; /** @driver_private: pointer to the bridge driver's internal context */ void *driver_private; + /** @ops: bitmask of operations supported by the bridge */ + enum drm_bridge_ops ops; + /** + * @type: Type of the connection at the bridge output + * (DRM_MODE_CONNECTOR_*). For bridges at the end of this chain this + * identifies the type of connected display. + */ + int type; + /** + * @interlace_allowed: Indicate that the bridge can handle interlaced + * modes. + */ + bool interlace_allowed; + /** + * @ddc: Associated I2C adapter for DDC access, if any. + */ + struct i2c_adapter *ddc; + /** private: */ + /** + * @hpd_mutex: Protects the @hpd_cb and @hpd_data fields. + */ + struct rwlock hpd_mutex; + /** + * @hpd_cb: Hot plug detection callback, registered with + * drm_bridge_hpd_enable(). + */ + void (*hpd_cb)(void *data, enum drm_connector_status status); + /** + * @hpd_data: Private data passed to the Hot plug detection callback + * @hpd_cb. + */ + void *hpd_data; }; +static inline struct drm_bridge * +drm_priv_to_bridge(struct drm_private_obj *priv) +{ + return container_of(priv, struct drm_bridge, base); +} + void drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *of_drm_find_bridge(struct device_node *np); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, - struct drm_bridge *previous); + struct drm_bridge *previous, + enum drm_bridge_attach_flags flags); -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_mode *mode); -void drm_bridge_disable(struct drm_bridge *bridge); -void drm_bridge_post_disable(struct drm_bridge *bridge); -void drm_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -void drm_bridge_pre_enable(struct drm_bridge *bridge); -void drm_bridge_enable(struct drm_bridge *bridge); +/** + * drm_bridge_get_next_bridge() - Get the next bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the next bridge in the chain after @bridge, or NULL if @bridge is the last. + */ +static inline struct drm_bridge * +drm_bridge_get_next_bridge(struct drm_bridge *bridge) +{ + if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_next_entry(bridge, chain_node); +} + +/** + * drm_bridge_get_prev_bridge() - Get the previous bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the previous bridge in the chain, or NULL if @bridge is the first. + */ +static inline struct drm_bridge * +drm_bridge_get_prev_bridge(struct drm_bridge *bridge) +{ + if (list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_prev_entry(bridge, chain_node); +} + +/** + * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain + * @encoder: encoder object + * + * RETURNS: + * the first bridge in the chain, or NULL if @encoder has no bridge attached + * to it. + */ +static inline struct drm_bridge * +drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) +{ + return list_first_entry_or_null(&encoder->bridge_chain, + struct drm_bridge, chain_node); +} + +/** + * drm_for_each_bridge_in_chain() - Iterate over all bridges present in a chain + * @encoder: the encoder to iterate bridges on + * @bridge: a bridge pointer updated to point to the current bridge at each + * iteration + * + * Iterate over all bridges present in the bridge chain attached to @encoder. + */ +#define drm_for_each_bridge_in_chain(encoder, bridge) \ + list_for_each_entry(bridge, &(encoder)->bridge_chain, chain_node) + +bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +enum drm_mode_status +drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode); +void drm_bridge_chain_disable(struct drm_bridge *bridge); +void drm_bridge_chain_post_disable(struct drm_bridge *bridge); +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); +void drm_bridge_chain_enable(struct drm_bridge *bridge); + +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state); + +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + +enum drm_connector_status drm_bridge_detect(struct drm_bridge *bridge); +int drm_bridge_get_modes(struct drm_bridge *bridge, + struct drm_connector *connector); +struct edid *drm_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector); +void drm_bridge_hpd_enable(struct drm_bridge *bridge, + void (*cb)(void *data, + enum drm_connector_status status), + void *data); +void drm_bridge_hpd_disable(struct drm_bridge *bridge); +void drm_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status); #ifdef CONFIG_DRM_PANEL_BRIDGE -struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel, - u32 connector_type); +struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); +struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, + u32 connector_type); void drm_panel_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, - struct drm_panel *panel, - u32 connector_type); + struct drm_panel *panel); +struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, + struct drm_panel *panel, + u32 connector_type); +struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge); #endif #endif diff --git a/sys/dev/pci/drm/include/drm/drm_cache.h b/sys/dev/pci/drm/include/drm/drm_cache.h index 820ebb32bad..3b4081572ba 100644 --- a/sys/dev/pci/drm/include/drm/drm_cache.h +++ b/sys/dev/pci/drm/include/drm/drm_cache.h @@ -1,4 +1,3 @@ -/* $OpenBSD: drm_cache.h,v 1.1 2019/04/14 10:14:52 jsg Exp $ */ /************************************************************************** * * Copyright 2009 Red Hat Inc. @@ -35,17 +34,20 @@ #define _DRM_CACHE_H_ #include <linux/scatterlist.h> -#include <uvm/uvm_extern.h> void drm_clflush_pages(struct vm_page *pages[], unsigned long num_pages); +void drm_clflush_sg(struct sg_table *st); +void drm_clflush_virt_range(void *addr, unsigned long length); +bool drm_need_swiotlb(int dma_bits); + static inline bool drm_arch_can_wc_memory(void) { -#if defined(__powerpc__) +#if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) return false; -#elif defined(__mips__) +#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON64) return false; -#elif defined(__arm__) || defined(__arm64__) +#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) /* * The DRM driver stack is designed to work with cache coherent devices * only, but permits an optimization to be enabled in some cases, where diff --git a/sys/dev/pci/drm/include/drm/drm_client.h b/sys/dev/pci/drm/include/drm/drm_client.h new file mode 100644 index 00000000000..19375f8cd15 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_client.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ + +#ifndef _DRM_CLIENT_H_ +#define _DRM_CLIENT_H_ + +#include <linux/lockdep.h> +#include <linux/mutex.h> +#include <linux/types.h> + +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> + +struct drm_client_dev; +struct drm_device; +struct drm_file; +struct drm_framebuffer; +struct drm_gem_object; +struct drm_minor; +struct module; + +/** + * struct drm_client_funcs - DRM client callbacks + */ +struct drm_client_funcs { + /** + * @owner: The module owner + */ + struct module *owner; + + /** + * @unregister: + * + * Called when &drm_device is unregistered. The client should respond by + * releasing its resources using drm_client_release(). + * + * This callback is optional. + */ + void (*unregister)(struct drm_client_dev *client); + + /** + * @restore: + * + * Called on drm_lastclose(). The first client instance in the list that + * returns zero gets the privilege to restore and no more clients are + * called. This callback is not called after @unregister has been called. + * + * Note that the core does not guarantee exclusion against concurrent + * drm_open(). Clients need to ensure this themselves, for example by + * using drm_master_internal_acquire() and + * drm_master_internal_release(). + * + * This callback is optional. + */ + int (*restore)(struct drm_client_dev *client); + + /** + * @hotplug: + * + * Called on drm_kms_helper_hotplug_event(). + * This callback is not called after @unregister has been called. + * + * This callback is optional. + */ + int (*hotplug)(struct drm_client_dev *client); +}; + +/** + * struct drm_client_dev - DRM client instance + */ +struct drm_client_dev { + /** + * @dev: DRM device + */ + struct drm_device *dev; + + /** + * @name: Name of the client. + */ + const char *name; + + /** + * @list: + * + * List of all clients of a DRM device, linked into + * &drm_device.clientlist. Protected by &drm_device.clientlist_mutex. + */ + struct list_head list; + + /** + * @funcs: DRM client functions (optional) + */ + const struct drm_client_funcs *funcs; + + /** + * @file: DRM file + */ + struct drm_file *file; + + /** + * @modeset_mutex: Protects @modesets. + */ + struct rwlock modeset_mutex; + + /** + * @modesets: CRTC configurations + */ + struct drm_mode_set *modesets; +}; + +int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, + const char *name, const struct drm_client_funcs *funcs); +void drm_client_release(struct drm_client_dev *client); +void drm_client_register(struct drm_client_dev *client); + +void drm_client_dev_unregister(struct drm_device *dev); +void drm_client_dev_hotplug(struct drm_device *dev); +void drm_client_dev_restore(struct drm_device *dev); + +/** + * struct drm_client_buffer - DRM client buffer + */ +struct drm_client_buffer { + /** + * @client: DRM client + */ + struct drm_client_dev *client; + + /** + * @handle: Buffer handle + */ + u32 handle; + + /** + * @pitch: Buffer pitch + */ + u32 pitch; + + /** + * @gem: GEM object backing this buffer + */ + struct drm_gem_object *gem; + + /** + * @vaddr: Virtual address for the buffer + */ + void *vaddr; + + /** + * @fb: DRM framebuffer + */ + struct drm_framebuffer *fb; +}; + +struct drm_client_buffer * +drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); +void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); +void *drm_client_buffer_vmap(struct drm_client_buffer *buffer); +void drm_client_buffer_vunmap(struct drm_client_buffer *buffer); + +int drm_client_modeset_create(struct drm_client_dev *client); +void drm_client_modeset_free(struct drm_client_dev *client); +int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height); +bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation); +int drm_client_modeset_commit_locked(struct drm_client_dev *client); +int drm_client_modeset_commit(struct drm_client_dev *client); +int drm_client_modeset_dpms(struct drm_client_dev *client, int mode); + +/** + * drm_client_for_each_modeset() - Iterate over client modesets + * @modeset: &drm_mode_set loop cursor + * @client: DRM client + */ +#define drm_client_for_each_modeset(modeset, client) \ + for (({ lockdep_assert_held(&(client)->modeset_mutex); }), \ + modeset = (client)->modesets; modeset->crtc; modeset++) + +/** + * drm_client_for_each_connector_iter - connector_list iterator macro + * @connector: &struct drm_connector pointer used as cursor + * @iter: &struct drm_connector_list_iter + * + * This iterates the connectors that are useable for internal clients (excludes + * writeback connectors). + * + * For more info see drm_for_each_connector_iter(). + */ +#define drm_client_for_each_connector_iter(connector, iter) \ + drm_for_each_connector_iter(connector, iter) \ + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + +int drm_client_debugfs_init(struct drm_minor *minor); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_color_mgmt.h b/sys/dev/pci/drm/include/drm/drm_color_mgmt.h index 44f04233e3d..81c298488b0 100644 --- a/sys/dev/pci/drm/include/drm/drm_color_mgmt.h +++ b/sys/dev/pci/drm/include/drm/drm_color_mgmt.h @@ -24,11 +24,35 @@ #define __DRM_COLOR_MGMT_H__ #include <linux/ctype.h> +#include <drm/drm_property.h> struct drm_crtc; struct drm_plane; -uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision); +/** + * drm_color_lut_extract - clamp and round LUT entries + * @user_input: input value + * @bit_precision: number of bits the hw LUT supports + * + * Extract a degamma/gamma LUT value provided by user (in the form of + * &drm_color_lut entries) and round it to the precision supported by the + * hardware. + */ +static inline u32 drm_color_lut_extract(u32 user_input, int bit_precision) +{ + u32 val = user_input; + u32 max = 0xffff >> (16 - bit_precision); + + /* Round only if we're not using full precision. */ + if (bit_precision < 16) { + val += 1UL << (16 - bit_precision - 1); + val >>= 16 - bit_precision; + } + + return clamp_val(val, 0, max); +} + +u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n); void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, uint degamma_lut_size, @@ -68,4 +92,32 @@ int drm_plane_create_color_properties(struct drm_plane *plane, u32 supported_ranges, enum drm_color_encoding default_encoding, enum drm_color_range default_range); + +/** + * enum drm_color_lut_tests - hw-specific LUT tests to perform + * + * The drm_color_lut_check() function takes a bitmask of the values here to + * determine which tests to apply to a userspace-provided LUT. + */ +enum drm_color_lut_tests { + /** + * @DRM_COLOR_LUT_EQUAL_CHANNELS: + * + * Checks whether the entries of a LUT all have equal values for the + * red, green, and blue channels. Intended for hardware that only + * accepts a single value per LUT entry and assumes that value applies + * to all three color components. + */ + DRM_COLOR_LUT_EQUAL_CHANNELS = BIT(0), + + /** + * @DRM_COLOR_LUT_NON_DECREASING: + * + * Checks whether the entries of a LUT are always flat or increasing + * (never decreasing). + */ + DRM_COLOR_LUT_NON_DECREASING = BIT(1), +}; + +int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests); #endif diff --git a/sys/dev/pci/drm/include/drm/drm_connector.h b/sys/dev/pci/drm/include/drm/drm_connector.h index 8b7da93d13e..f5d6c6b72f3 100644 --- a/sys/dev/pci/drm/include/drm/drm_connector.h +++ b/sys/dev/pci/drm/include/drm/drm_connector.h @@ -28,6 +28,7 @@ #include <linux/ctype.h> #include <linux/hdmi.h> #include <drm/drm_mode_object.h> +#include <drm/drm_util.h> #include <uapi/drm/drm_mode.h> @@ -40,6 +41,7 @@ struct drm_property; struct drm_property_blob; struct drm_printer; struct edid; +struct i2c_adapter; enum drm_connector_force { DRM_FORCE_UNSPECIFIED, @@ -81,6 +83,53 @@ enum drm_connector_status { connector_status_unknown = 3, }; +/** + * enum drm_connector_registration_status - userspace registration status for + * a &drm_connector + * + * This enum is used to track the status of initializing a connector and + * registering it with userspace, so that DRM can prevent bogus modesets on + * connectors that no longer exist. + */ +enum drm_connector_registration_state { + /** + * @DRM_CONNECTOR_INITIALIZING: The connector has just been created, + * but has yet to be exposed to userspace. There should be no + * additional restrictions to how the state of this connector may be + * modified. + */ + DRM_CONNECTOR_INITIALIZING = 0, + + /** + * @DRM_CONNECTOR_REGISTERED: The connector has been fully initialized + * and registered with sysfs, as such it has been exposed to + * userspace. There should be no additional restrictions to how the + * state of this connector may be modified. + */ + DRM_CONNECTOR_REGISTERED = 1, + + /** + * @DRM_CONNECTOR_UNREGISTERED: The connector has either been exposed + * to userspace and has since been unregistered and removed from + * userspace, or the connector was unregistered before it had a chance + * to be exposed to userspace (e.g. still in the + * @DRM_CONNECTOR_INITIALIZING state). When a connector is + * unregistered, there are additional restrictions to how its state + * may be modified: + * + * - An unregistered connector may only have its DPMS changed from + * On->Off. Once DPMS is changed to Off, it may not be switched back + * to On. + * - Modesets are not allowed on unregistered connectors, unless they + * would result in disabling its assigned CRTCs. This means + * disabling a CRTC on an unregistered connector is OK, but enabling + * one is not. + * - Removing a CRTC from an unregistered connector is OK, but new + * CRTCs may never be assigned to an unregistered connector. + */ + DRM_CONNECTOR_UNREGISTERED = 2, +}; + enum subpixel_order { SubPixelUnknown = 0, SubPixelHorizontalRGB, @@ -139,19 +188,19 @@ struct drm_hdmi_info { /** * @y420_vdb_modes: bitmap of modes which can support ycbcr420 - * output only (not normal RGB/YCBCR444/422 outputs). There are total - * 107 VICs defined by CEA-861-F spec, so the size is 128 bits to map - * upto 128 VICs; + * output only (not normal RGB/YCBCR444/422 outputs). The max VIC + * defined by the CEA-861-G spec is 219, so the size is 256 bits to map + * up to 256 VICs. */ - unsigned long y420_vdb_modes[BITS_TO_LONGS(128)]; + unsigned long y420_vdb_modes[BITS_TO_LONGS(256)]; /** * @y420_cmdb_modes: bitmap of modes which can support ycbcr420 - * output also, along with normal HDMI outputs. There are total 107 - * VICs defined by CEA-861-F spec, so the size is 128 bits to map upto - * 128 VICs; + * output also, along with normal HDMI outputs. The max VIC defined by + * the CEA-861-G spec is 219, so the size is 256 bits to map up to 256 + * VICs. */ - unsigned long y420_cmdb_modes[BITS_TO_LONGS(128)]; + unsigned long y420_cmdb_modes[BITS_TO_LONGS(256)]; /** @y420_cmdb_map: bitmap of SVD index, to extraxt vcb modes */ u64 y420_cmdb_map; @@ -206,6 +255,120 @@ enum drm_panel_orientation { }; /** + * struct drm_monitor_range_info - Panel's Monitor range in EDID for + * &drm_display_info + * + * This struct is used to store a frequency range supported by panel + * as parsed from EDID's detailed monitor range descriptor block. + * + * @min_vfreq: This is the min supported refresh rate in Hz from + * EDID's detailed monitor range. + * @max_vfreq: This is the max supported refresh rate in Hz from + * EDID's detailed monitor range + */ +struct drm_monitor_range_info { + u8 min_vfreq; + u8 max_vfreq; +}; + +/* + * This is a consolidated colorimetry list supported by HDMI and + * DP protocol standard. The respective connectors will register + * a property with the subset of this list (supported by that + * respective protocol). Userspace will set the colorspace through + * a colorspace property which will be created and exposed to + * userspace. + */ + +/* For Default case, driver will set the colorspace */ +#define DRM_MODE_COLORIMETRY_DEFAULT 0 +/* CEA 861 Normal Colorimetry options */ +#define DRM_MODE_COLORIMETRY_NO_DATA 0 +#define DRM_MODE_COLORIMETRY_SMPTE_170M_YCC 1 +#define DRM_MODE_COLORIMETRY_BT709_YCC 2 +/* CEA 861 Extended Colorimetry Options */ +#define DRM_MODE_COLORIMETRY_XVYCC_601 3 +#define DRM_MODE_COLORIMETRY_XVYCC_709 4 +#define DRM_MODE_COLORIMETRY_SYCC_601 5 +#define DRM_MODE_COLORIMETRY_OPYCC_601 6 +#define DRM_MODE_COLORIMETRY_OPRGB 7 +#define DRM_MODE_COLORIMETRY_BT2020_CYCC 8 +#define DRM_MODE_COLORIMETRY_BT2020_RGB 9 +#define DRM_MODE_COLORIMETRY_BT2020_YCC 10 +/* Additional Colorimetry extension added as part of CTA 861.G */ +#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 11 +#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER 12 +/* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ +#define DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED 13 +#define DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT 14 +#define DRM_MODE_COLORIMETRY_BT601_YCC 15 + +/** + * enum drm_bus_flags - bus_flags info for &drm_display_info + * + * This enum defines signal polarities and clock edge information for signals on + * a bus as bitmask flags. + * + * The clock edge information is conveyed by two sets of symbols, + * DRM_BUS_FLAGS_*_DRIVE_\* and DRM_BUS_FLAGS_*_SAMPLE_\*. When this enum is + * used to describe a bus from the point of view of the transmitter, the + * \*_DRIVE_\* flags should be used. When used from the point of view of the + * receiver, the \*_SAMPLE_\* flags should be used. The \*_DRIVE_\* and + * \*_SAMPLE_\* flags alias each other, with the \*_SAMPLE_POSEDGE and + * \*_SAMPLE_NEGEDGE flags being equal to \*_DRIVE_NEGEDGE and \*_DRIVE_POSEDGE + * respectively. This simplifies code as signals are usually sampled on the + * opposite edge of the driving edge. Transmitters and receivers may however + * need to take other signal timings into account to convert between driving + * and sample edges. + * + * @DRM_BUS_FLAG_DE_LOW: The Data Enable signal is active low + * @DRM_BUS_FLAG_DE_HIGH: The Data Enable signal is active high + * @DRM_BUS_FLAG_PIXDATA_POSEDGE: Legacy value, do not use + * @DRM_BUS_FLAG_PIXDATA_NEGEDGE: Legacy value, do not use + * @DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE: Data is driven on the rising edge of + * the pixel clock + * @DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE: Data is driven on the falling edge of + * the pixel clock + * @DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE: Data is sampled on the rising edge of + * the pixel clock + * @DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE: Data is sampled on the falling edge of + * the pixel clock + * @DRM_BUS_FLAG_DATA_MSB_TO_LSB: Data is transmitted MSB to LSB on the bus + * @DRM_BUS_FLAG_DATA_LSB_TO_MSB: Data is transmitted LSB to MSB on the bus + * @DRM_BUS_FLAG_SYNC_POSEDGE: Legacy value, do not use + * @DRM_BUS_FLAG_SYNC_NEGEDGE: Legacy value, do not use + * @DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE: Sync signals are driven on the rising + * edge of the pixel clock + * @DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE: Sync signals are driven on the falling + * edge of the pixel clock + * @DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE: Sync signals are sampled on the rising + * edge of the pixel clock + * @DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE: Sync signals are sampled on the falling + * edge of the pixel clock + * @DRM_BUS_FLAG_SHARP_SIGNALS: Set if the Sharp-specific signals + * (SPL, CLS, PS, REV) must be used + */ +enum drm_bus_flags { + DRM_BUS_FLAG_DE_LOW = BIT(0), + DRM_BUS_FLAG_DE_HIGH = BIT(1), + DRM_BUS_FLAG_PIXDATA_POSEDGE = BIT(2), + DRM_BUS_FLAG_PIXDATA_NEGEDGE = BIT(3), + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE = DRM_BUS_FLAG_PIXDATA_POSEDGE, + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE = DRM_BUS_FLAG_PIXDATA_POSEDGE, + DRM_BUS_FLAG_DATA_MSB_TO_LSB = BIT(4), + DRM_BUS_FLAG_DATA_LSB_TO_MSB = BIT(5), + DRM_BUS_FLAG_SYNC_POSEDGE = BIT(6), + DRM_BUS_FLAG_SYNC_NEGEDGE = BIT(7), + DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE = DRM_BUS_FLAG_SYNC_POSEDGE, + DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE, + DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE, + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE = DRM_BUS_FLAG_SYNC_POSEDGE, + DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8), +}; + +/** * struct drm_display_info - runtime data about the connected sink * * Describes a given display (e.g. CRT or flat panel) and its limitations. For @@ -218,26 +381,16 @@ enum drm_panel_orientation { */ struct drm_display_info { /** - * @name: Name of the display. - */ - char name[DRM_DISPLAY_INFO_LEN]; - - /** * @width_mm: Physical width in mm. */ - unsigned int width_mm; + unsigned int width_mm; + /** * @height_mm: Physical height in mm. */ unsigned int height_mm; /** - * @pixel_clock: Maximum pixel clock supported by the sink, in units of - * 100Hz. This mismatches the clock in &drm_display_mode (which is in - * kHZ), because that's what the EDID uses as base unit. - */ - unsigned int pixel_clock; - /** * @bpc: Maximum bits per color channel. Used by HDMI and DP outputs. */ unsigned int bpc; @@ -280,24 +433,10 @@ struct drm_display_info { */ unsigned int num_bus_formats; -#define DRM_BUS_FLAG_DE_LOW (1<<0) -#define DRM_BUS_FLAG_DE_HIGH (1<<1) -/* drive data on pos. edge */ -#define DRM_BUS_FLAG_PIXDATA_POSEDGE (1<<2) -/* drive data on neg. edge */ -#define DRM_BUS_FLAG_PIXDATA_NEGEDGE (1<<3) -/* data is transmitted MSB to LSB on the bus */ -#define DRM_BUS_FLAG_DATA_MSB_TO_LSB (1<<4) -/* data is transmitted LSB to MSB on the bus */ -#define DRM_BUS_FLAG_DATA_LSB_TO_MSB (1<<5) -/* drive sync on pos. edge */ -#define DRM_BUS_FLAG_SYNC_POSEDGE (1<<6) -/* drive sync on neg. edge */ -#define DRM_BUS_FLAG_SYNC_NEGEDGE (1<<7) - /** * @bus_flags: Additional information (like pixel signal polarity) for - * the pixel data on the bus, using DRM_BUS_FLAGS\_ defines. + * the pixel data on the bus, using &enum drm_bus_flags values + * DRM_BUS_FLAGS\_. */ u32 bus_flags; @@ -313,11 +452,25 @@ struct drm_display_info { bool dvi_dual; /** + * @is_hdmi: True if the sink is an HDMI device. + * + * This field shall be used instead of calling + * drm_detect_hdmi_monitor() when possible. + */ + bool is_hdmi; + + /** * @has_hdmi_infoframe: Does the sink support the HDMI infoframe? */ bool has_hdmi_infoframe; /** + * @rgb_quant_range_selectable: Does the sink support selecting + * the RGB quantization range? + */ + bool rgb_quant_range_selectable; + + /** * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even * more stuff redundant with @bus_formats. */ @@ -337,6 +490,11 @@ struct drm_display_info { * @non_desktop: Non desktop display (HMD). */ bool non_desktop; + + /** + * @monitor_range: Frequency range supported by monitor range descriptor + */ + struct drm_monitor_range_info monitor_range; }; int drm_display_info_set_bus_formats(struct drm_display_info *info, @@ -344,13 +502,37 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, unsigned int num_formats); /** + * struct drm_connector_tv_margins - TV connector related margins + * + * Describes the margins in pixels to put around the image on TV + * connectors to deal with overscan. + */ +struct drm_connector_tv_margins { + /** + * @bottom: Bottom margin in pixels. + */ + unsigned int bottom; + + /** + * @left: Left margin in pixels. + */ + unsigned int left; + + /** + * @right: Right margin in pixels. + */ + unsigned int right; + + /** + * @top: Top margin in pixels. + */ + unsigned int top; +}; + +/** * struct drm_tv_connector_state - TV connector related states * @subconnector: selected subconnector - * @margins: margins - * @margins.left: left margin - * @margins.right: right margin - * @margins.top: top margin - * @margins.bottom: bottom margin + * @margins: TV margins * @mode: TV mode * @brightness: brightness in percent * @contrast: contrast in percent @@ -361,12 +543,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, */ struct drm_tv_connector_state { enum drm_mode_subconnector subconnector; - struct { - unsigned int left; - unsigned int right; - unsigned int top; - unsigned int bottom; - } margins; + struct drm_connector_tv_margins margins; unsigned int mode; unsigned int brightness; unsigned int contrast; @@ -397,6 +574,15 @@ struct drm_connector_state { * Used by the atomic helpers to select the encoder, through the * &drm_connector_helper_funcs.atomic_best_encoder or * &drm_connector_helper_funcs.best_encoder callbacks. + * + * This is also used in the atomic helpers to map encoders to their + * current and previous connectors, see + * drm_atomic_get_old_connector_for_encoder() and + * drm_atomic_get_new_connector_for_encoder(). + * + * NOTE: Atomic drivers must fill this out (either themselves or through + * helpers), for otherwise the GETCONNECTOR and GETENCODER IOCTLs will + * not return correct data to userspace. */ struct drm_encoder *best_encoder; @@ -420,6 +606,20 @@ struct drm_connector_state { struct drm_tv_connector_state tv; /** + * @self_refresh_aware: + * + * This tracks whether a connector is aware of the self refresh state. + * It should be set to true for those connector implementations which + * understand the self refresh state. This is needed since the crtc + * registers the self refresh helpers and it doesn't know if the + * connectors downstream have implemented self refresh entry/exit. + * + * Drivers should set this to true in atomic_check if they know how to + * handle self_refresh requests. + */ + bool self_refresh_aware; + + /** * @picture_aspect_ratio: Connector property to control the * HDMI infoframe aspect ratio setting. * @@ -437,6 +637,12 @@ struct drm_connector_state { unsigned int content_type; /** + * @hdcp_content_type: Connector property to pass the type of + * protected content. This is most commonly used for HDCP. + */ + unsigned int hdcp_content_type; + + /** * @scaling_mode: Connector property to control the * upscaling, mostly used for built-in panels. */ @@ -449,6 +655,13 @@ struct drm_connector_state { unsigned int content_protection; /** + * @colorspace: State variable for Connector property to request + * colorspace change on Sink. This is most commonly used to switch + * to wider color gamuts like BT2020. + */ + u32 colorspace; + + /** * @writeback_job: Writeback job for writeback connectors * * Holds the framebuffer and out-fence for a writeback connector. As @@ -460,6 +673,24 @@ struct drm_connector_state { * drm_writeback_signal_completion() */ struct drm_writeback_job *writeback_job; + + /** + * @max_requested_bpc: Connector property to limit the maximum bit + * depth of the pixels. + */ + u8 max_requested_bpc; + + /** + * @max_bpc: Connector max_bpc based on the requested max_bpc property + * and the connector bpc limitations obtained from edid. + */ + u8 max_bpc; + + /** + * @hdr_output_metadata: + * DRM blob property for HDR output metadata + */ + struct drm_property_blob *hdr_output_metadata; }; /** @@ -755,19 +986,131 @@ struct drm_connector_funcs { const struct drm_connector_state *state); }; -/* mode specified on the command line */ +/** + * struct drm_cmdline_mode - DRM Mode passed through the kernel command-line + * + * Each connector can have an initial mode with additional options + * passed through the kernel command line. This structure allows to + * express those parameters and will be filled by the command-line + * parser. + */ struct drm_cmdline_mode { + /** + * @name: + * + * Name of the mode. + */ + char name[DRM_DISPLAY_MODE_LEN]; + + /** + * @specified: + * + * Has a mode been read from the command-line? + */ bool specified; + + /** + * @refresh_specified: + * + * Did the mode have a preferred refresh rate? + */ bool refresh_specified; + + /** + * @bpp_specified: + * + * Did the mode have a preferred BPP? + */ bool bpp_specified; - int xres, yres; + + /** + * @xres: + * + * Active resolution on the X axis, in pixels. + */ + int xres; + + /** + * @yres: + * + * Active resolution on the Y axis, in pixels. + */ + int yres; + + /** + * @bpp: + * + * Bits per pixels for the mode. + */ int bpp; + + /** + * @refresh: + * + * Refresh rate, in Hertz. + */ int refresh; + + /** + * @rb: + * + * Do we need to use reduced blanking? + */ bool rb; + + /** + * @interlace: + * + * The mode is interlaced. + */ bool interlace; + + /** + * @cvt: + * + * The timings will be calculated using the VESA Coordinated + * Video Timings instead of looking up the mode from a table. + */ bool cvt; + + /** + * @margins: + * + * Add margins to the mode calculation (1.8% of xres rounded + * down to 8 pixels and 1.8% of yres). + */ bool margins; + + /** + * @force: + * + * Ignore the hotplug state of the connector, and force its + * state to one of the DRM_FORCE_* values. + */ enum drm_connector_force force; + + /** + * @rotation_reflection: + * + * Initial rotation and reflection of the mode setup from the + * command line. See DRM_MODE_ROTATE_* and + * DRM_MODE_REFLECT_*. The only rotations supported are + * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180. + */ + unsigned int rotation_reflection; + + /** + * @panel_orientation: + * + * drm-connector "panel orientation" property override value, + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set. + */ + enum drm_panel_orientation panel_orientation; + + /** + * @tv_margins: TV margins to apply to the mode. + */ + struct drm_connector_tv_margins tv_margins; }; /** @@ -846,16 +1189,18 @@ struct drm_connector { /** * @ycbcr_420_allowed : This bool indicates if this connector is * capable of handling YCBCR 420 output. While parsing the EDID - * blocks, its very helpful to know, if the source is capable of + * blocks it's very helpful to know if the source is capable of * handling YCBCR 420 outputs. */ bool ycbcr_420_allowed; /** - * @registered: Is this connector exposed (registered) with userspace? + * @registration_state: Is this connector initializing, exposed + * (registered) with userspace, or unregistered? + * * Protected by @mutex. */ - bool registered; + enum drm_connector_registration_state registration_state; /** * @modes: @@ -910,10 +1255,21 @@ struct drm_connector { struct drm_property *scaling_mode_property; /** - * @content_protection_property: DRM ENUM property for content - * protection. See drm_connector_attach_content_protection_property(). + * @vrr_capable_property: Optional property to help userspace + * query hardware support for variable refresh rate on a connector. + * connector. Drivers can add the property to a connector by + * calling drm_connector_attach_vrr_capable_property(). + * + * This should be updated only by calling + * drm_connector_set_vrr_capable_property(). */ - struct drm_property *content_protection_property; + struct drm_property *vrr_capable_property; + + /** + * @colorspace_property: Connector property to set the suitable + * colorspace supported by the sink. + */ + struct drm_property *colorspace_property; /** * @path_blob_ptr: @@ -923,6 +1279,12 @@ struct drm_connector { */ struct drm_property_blob *path_blob_ptr; + /** + * @max_bpc_property: Default connector property for the max bpc to be + * driven out of the connector. + */ + struct drm_property *max_bpc_property; + #define DRM_CONNECTOR_POLL_HPD (1 << 0) #define DRM_CONNECTOR_POLL_CONNECT (1 << 1) #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) @@ -968,12 +1330,12 @@ struct drm_connector { /** @override_edid: has the EDID been overwritten through debugfs for testing? */ bool override_edid; -#define DRM_CONNECTOR_MAX_ENCODER 3 /** - * @encoder_ids: Valid encoders for this connector. Please only use - * drm_connector_for_each_possible_encoder() to enumerate these. + * @possible_encoders: Bit mask of encoders that can drive this + * connector, drm_encoder_index() determines the index into the bitfield + * and the bits are set with drm_connector_attach_encoder(). */ - uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + u32 possible_encoders; /** * @encoder: Currently bound encoder driving this connector, if any. @@ -998,6 +1360,18 @@ struct drm_connector { * [0]: progressive, [1]: interlaced */ int audio_latency[2]; + + /** + * @ddc: associated ddc adapter. + * A connector usually has its associated ddc adapter. If a driver uses + * this field, then an appropriate symbolic link is created in connector + * sysfs directory to make it easy for the user to tell which i2c + * adapter is for a particular display. + * + * The field should be set by calling drm_connector_init_with_ddc(). + */ + struct i2c_adapter *ddc; + /** * @null_edid_counter: track sinks that give us all zeros for the EDID. * Needed to workaround some HW bugs where we get all 0s @@ -1013,6 +1387,12 @@ struct drm_connector { * rev1.1 4.2.2.6 */ bool edid_corrupt; + /** + * @real_edid_checksum: real edid checksum for corrupted edid block. + * Required in Displayport 1.4 compliance testing + * rev1.1 4.2.2.6 + */ + u8 real_edid_checksum; /** @debugfs_entry: debugfs directory for this connector */ struct dentry *debugfs_entry; @@ -1080,6 +1460,9 @@ struct drm_connector { * &drm_mode_config.connector_free_work. */ struct llist_node free_node; + + /** @hdr_sink_metadata: HDR Metadata Information read from sink */ + struct hdr_sink_metadata hdr_sink_metadata; }; #define obj_to_connector(x) container_of(x, struct drm_connector, base) @@ -1088,6 +1471,12 @@ int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type); +int drm_connector_init_with_ddc(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type, + struct i2c_adapter *ddc); +void drm_connector_attach_edid_property(struct drm_connector *connector); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); int drm_connector_attach_encoder(struct drm_connector *connector, @@ -1147,29 +1536,24 @@ static inline void drm_connector_put(struct drm_connector *connector) } /** - * drm_connector_reference - acquire a connector reference + * drm_connector_is_unregistered - has the connector been unregistered from + * userspace? * @connector: DRM connector * - * This is a compatibility alias for drm_connector_get() and should not be - * used by new code. - */ -static inline void drm_connector_reference(struct drm_connector *connector) -{ - drm_connector_get(connector); -} - -/** - * drm_connector_unreference - release a connector reference - * @connector: DRM connector + * Checks whether or not @connector has been unregistered from userspace. * - * This is a compatibility alias for drm_connector_put() and should not be - * used by new code. + * Returns: + * True if the connector was unregistered, false if the connector is + * registered or has not yet been registered with userspace. */ -static inline void drm_connector_unreference(struct drm_connector *connector) +static inline bool +drm_connector_is_unregistered(struct drm_connector *connector) { - drm_connector_put(connector); + return READ_ONCE(connector->registration_state) == + DRM_CONNECTOR_UNREGISTERED; } +const char *drm_get_connector_type_name(unsigned int connector_type); const char *drm_get_connector_status_name(enum drm_connector_status status); const char *drm_get_subpixel_order_name(enum subpixel_order order); const char *drm_get_dpms_name(int val); @@ -1178,18 +1562,23 @@ const char *drm_get_dvi_i_select_name(int val); const char *drm_get_tv_subconnector_name(int val); const char *drm_get_tv_select_name(int val); const char *drm_get_content_protection_name(int val); +const char *drm_get_hdcp_content_type_name(int val); int drm_mode_create_dvi_i_properties(struct drm_device *dev); +int drm_mode_create_tv_margin_properties(struct drm_device *dev); int drm_mode_create_tv_properties(struct drm_device *dev, unsigned int num_modes, const char * const modes[]); +void drm_connector_attach_tv_margin_properties(struct drm_connector *conn); int drm_mode_create_scaling_mode_property(struct drm_device *dev); int drm_connector_attach_content_type_property(struct drm_connector *dev); int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, u32 scaling_mode_mask); -int drm_connector_attach_content_protection_property( +int drm_connector_attach_vrr_capable_property( struct drm_connector *connector); int drm_mode_create_aspect_ratio_property(struct drm_device *dev); +int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector); +int drm_mode_create_dp_colorspace_property(struct drm_connector *connector); int drm_mode_create_content_type_property(struct drm_device *dev); void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state); @@ -1203,8 +1592,17 @@ int drm_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); void drm_connector_set_link_status_property(struct drm_connector *connector, uint64_t link_status); -int drm_connector_init_panel_orientation_property( - struct drm_connector *connector, int width, int height); +void drm_connector_set_vrr_capable_property( + struct drm_connector *connector, bool capable); +int drm_connector_set_panel_orientation( + struct drm_connector *connector, + enum drm_panel_orientation panel_orientation); +int drm_connector_set_panel_orientation_with_quirk( + struct drm_connector *connector, + enum drm_panel_orientation panel_orientation, + int width, int height); +int drm_connector_attach_max_bpc_property(struct drm_connector *connector, + int min, int max); /** * struct drm_tile_group - Tile group metadata @@ -1270,13 +1668,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector, * drm_connector_for_each_possible_encoder - iterate connector's possible encoders * @connector: &struct drm_connector pointer * @encoder: &struct drm_encoder pointer used as cursor - * @__i: int iteration cursor, for macro-internal use */ -#define drm_connector_for_each_possible_encoder(connector, encoder, __i) \ - for ((__i) = 0; (__i) < ARRAY_SIZE((connector)->encoder_ids) && \ - (connector)->encoder_ids[(__i)] != 0; (__i)++) \ - for_each_if((encoder) = \ - drm_encoder_find((connector)->dev, NULL, \ - (connector)->encoder_ids[(__i)])) \ +#define drm_connector_for_each_possible_encoder(connector, encoder) \ + drm_for_each_encoder_mask(encoder, (connector)->dev, \ + (connector)->possible_encoders) #endif diff --git a/sys/dev/pci/drm/include/drm/drm_crtc.h b/sys/dev/pci/drm/include/drm/drm_crtc.h index 54879c25d5c..59b51a09cae 100644 --- a/sys/dev/pci/drm/include/drm/drm_crtc.h +++ b/sys/dev/pci/drm/include/drm/drm_crtc.h @@ -31,10 +31,6 @@ #include <linux/fb.h> #include <linux/hdmi.h> #include <linux/media-bus-format.h> - -#include <linux/err.h> -#include <linux/sched.h> - #include <uapi/drm/drm_mode.h> #include <uapi/drm/drm_fourcc.h> #include <drm/drm_modeset_lock.h> @@ -43,8 +39,8 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_modes.h> #include <drm/drm_connector.h> +#include <drm/drm_device.h> #include <drm/drm_property.h> -#include <drm/drm_bridge.h> #include <drm/drm_edid.h> #include <drm/drm_plane.h> #include <drm/drm_blend.h> @@ -57,6 +53,7 @@ struct drm_mode_set; struct drm_file; struct drm_clip_rect; struct drm_printer; +struct drm_self_refresh_data; struct device_node; struct dma_fence; struct edid; @@ -82,7 +79,7 @@ struct drm_plane_helper_funcs; /** * struct drm_crtc_state - mutable CRTC state * - * Note that the distinction between @enable and @active is rather subtile: + * Note that the distinction between @enable and @active is rather subtle: * Flipping @active while @enable is set without changing anything else may * never return in a failure from the &drm_mode_config_funcs.atomic_check * callback. Userspace assumes that a DPMS On will always succeed. In other @@ -177,12 +174,25 @@ struct drm_crtc_state { * @no_vblank: * * Reflects the ability of a CRTC to send VBLANK events. This state - * usually depends on the pipeline configuration, and the main usuage - * is CRTCs feeding a writeback connector operating in oneshot mode. - * In this case the VBLANK event is only generated when a job is queued - * to the writeback connector, and we want the core to fake VBLANK - * events when this part of the pipeline hasn't changed but others had - * or when the CRTC and connectors are being disabled. + * usually depends on the pipeline configuration. If set to true, DRM + * atomic helpers will send out a fake VBLANK event during display + * updates after all hardware changes have been committed. This is + * implemented in drm_atomic_helper_fake_vblank(). + * + * One usage is for drivers and/or hardware without support for VBLANK + * interrupts. Such drivers typically do not initialize vblanking + * (i.e., call drm_vblank_init() with the number of CRTCs). For CRTCs + * without initialized vblanking, this field is set to true in + * drm_atomic_helper_check_modeset(), and a fake VBLANK event will be + * send out on each update of the display pipeline by + * drm_atomic_helper_fake_vblank(). + * + * Another usage is CRTCs feeding a writeback connector operating in + * oneshot mode. In this case the fake VBLANK event is only generated + * when a job is queued to the writeback connector, and we want the + * core to fake VBLANK events when this part of the pipeline hasn't + * changed but others had or when the CRTC and connectors are being + * disabled. * * __drm_atomic_helper_crtc_duplicate_state() will not reset the value * from the current state, the CRTC driver is then responsible for @@ -287,12 +297,32 @@ struct drm_crtc_state { u32 target_vblank; /** - * @pageflip_flags: + * @async_flip: + * + * This is set when DRM_MODE_PAGE_FLIP_ASYNC is set in the legacy + * PAGE_FLIP IOCTL. It's not wired up for the atomic IOCTL itself yet. + */ + bool async_flip; + + /** + * @vrr_enabled: * - * DRM_MODE_PAGE_FLIP_* flags, as passed to the page flip ioctl. - * Zero in any other case. + * Indicates if variable refresh rate should be enabled for the CRTC. + * Support for the requested vrr state will depend on driver and + * hardware capabiltiy - lacking support is not treated as failure. */ - u32 pageflip_flags; + bool vrr_enabled; + + /** + * @self_refresh_active: + * + * Used by the self refresh helpers to denote when a self refresh + * transition is occurring. This will be set on enable/disable callbacks + * when self refresh is being enabled or disabled. In some cases, it may + * not be desirable to fully shut off the crtc during self refresh. + * CRTC's can inspect this flag and determine the best course of action. + */ + bool self_refresh_active; /** * @event: @@ -318,7 +348,14 @@ struct drm_crtc_state { * - Events for disabled CRTCs are not allowed, and drivers can ignore * that case. * - * This can be handled by the drm_crtc_send_vblank_event() function, + * For very simple hardware without VBLANK interrupt, enabling + * &struct drm_crtc_state.no_vblank makes DRM's atomic commit helpers + * send a fake VBLANK event at the end of the display update after all + * hardware changes have been applied. See + * drm_atomic_helper_fake_vblank(). + * + * For more complex hardware this + * can be handled by the drm_crtc_send_vblank_event() function, * which the driver should call on the provided event upon completion of * the atomic commit. Note that if the driver supports vblank signalling * and timestamping the vblank counters and timestamps must agree with @@ -467,7 +504,7 @@ struct drm_crtc_funcs { /** * @destroy: * - * Clean up plane resources. This is only called at driver unload time + * Clean up CRTC resources. This is only called at driver unload time * through drm_mode_config_cleanup() since a CRTC cannot be hotplugged * in DRM. */ @@ -738,6 +775,9 @@ struct drm_crtc_funcs { * provided from the configured source. Drivers must accept an "auto" * source name that will select a default source for this CRTC. * + * This may trigger an atomic modeset commit if necessary, to enable CRC + * generation. + * * Note that "auto" can depend upon the current modeset configuration, * e.g. it could pick an encoder or output specific CRC sampling point. * @@ -748,8 +788,46 @@ struct drm_crtc_funcs { * * 0 on success or a negative error code on failure. */ - int (*set_crc_source)(struct drm_crtc *crtc, const char *source, - size_t *values_cnt); + int (*set_crc_source)(struct drm_crtc *crtc, const char *source); + + /** + * @verify_crc_source: + * + * verifies the source of CRC checksums of frames before setting the + * source for CRC and during crc open. Source parameter can be NULL + * while disabling crc source. + * + * This callback is optional if the driver does not support any CRC + * generation functionality. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*verify_crc_source)(struct drm_crtc *crtc, const char *source, + size_t *values_cnt); + /** + * @get_crc_sources: + * + * Driver callback for getting a list of all the available sources for + * CRC generation. This callback depends upon verify_crc_source, So + * verify_crc_source callback should be implemented before implementing + * this. Driver can pass full list of available crc sources, this + * callback does the verification on each crc-source before passing it + * to userspace. + * + * This callback is optional if the driver does not support exporting of + * possible CRC sources list. + * + * RETURNS: + * + * a constant character pointer to the list of all the available CRC + * sources. On failure driver should return NULL. count should be + * updated with number of sources in list. if zero we don't process any + * source from the list. + */ + const char *const *(*get_crc_sources)(struct drm_crtc *crtc, + size_t *count); /** * @atomic_print_state: @@ -809,6 +887,47 @@ struct drm_crtc_funcs { * new drivers as the replacement of &drm_driver.disable_vblank hook. */ void (*disable_vblank)(struct drm_crtc *crtc); + + /** + * @get_vblank_timestamp: + * + * Called by drm_get_last_vbltimestamp(). Should return a precise + * timestamp when the most recent vblank interval ended or will end. + * + * Specifically, the timestamp in @vblank_time should correspond as + * closely as possible to the time when the first video scanline of + * the video frame after the end of vblank will start scanning out, + * the time immediately after end of the vblank interval. If the + * @crtc is currently inside vblank, this will be a time in the future. + * If the @crtc is currently scanning out a frame, this will be the + * past start time of the current scanout. This is meant to adhere + * to the OpenML OML_sync_control extension specification. + * + * Parameters: + * + * crtc: + * CRTC for which timestamp should be returned. + * max_error: + * Maximum allowable timestamp error in nanoseconds. + * Implementation should strive to provide timestamp + * with an error of at most max_error nanoseconds. + * Returns true upper bound on error for timestamp. + * vblank_time: + * Target location for returned vblank timestamp. + * in_vblank_irq: + * True when called from drm_crtc_handle_vblank(). Some drivers + * need to apply some workarounds for gpu-specific vblank irq quirks + * if flag is set. + * + * Returns: + * + * True on success, false on failure, which means the core should + * fallback to a simple timestamp taken in drm_crtc_handle_vblank(). + */ + bool (*get_vblank_timestamp)(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq); }; /** @@ -916,11 +1035,12 @@ struct drm_crtc { * Programmed mode in hw, after adjustments for encoders, crtc, panel * scaling etc. Should only be used by legacy drivers, for high * precision vblank timestamps in - * drm_calc_vbltimestamp_from_scanoutpos(). + * drm_crtc_vblank_helper_get_vblank_timestamp(). * * Note that atomic drivers should not use this, but instead use * &drm_crtc_state.adjusted_mode. And for high-precision timestamps - * drm_calc_vbltimestamp_from_scanoutpos() used &drm_vblank_crtc.hwmode, + * drm_crtc_vblank_helper_get_vblank_timestamp() used + * &drm_vblank_crtc.hwmode, * which is filled out by calling drm_calc_timestamping_constants(). */ struct drm_display_mode hwmode; @@ -1045,6 +1165,13 @@ struct drm_crtc { * The name of the CRTC's fence timeline. */ char timeline_name[32]; + + /** + * @self_refresh_data: Holds the state for the self refresh helpers + * + * Initialized via drm_self_refresh_helper_init(). + */ + struct drm_self_refresh_data *self_refresh_data; }; /** @@ -1107,9 +1234,6 @@ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -int drm_crtc_force_disable(struct drm_crtc *crtc); -int drm_crtc_force_disable_all(struct drm_device *dev); - int drm_mode_set_config_internal(struct drm_mode_set *set); struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx); diff --git a/sys/dev/pci/drm/include/drm/drm_crtc_helper.h b/sys/dev/pci/drm/include/drm/drm_crtc_helper.h index 6f88d660928..a6d520d5b6c 100644 --- a/sys/dev/pci/drm/include/drm/drm_crtc_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_crtc_helper.h @@ -56,29 +56,6 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder); int drm_helper_connector_dpms(struct drm_connector *connector, int mode); void drm_helper_resume_force_mode(struct drm_device *dev); - -int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb); -int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb); - -/* drm_probe_helper.c */ -int drm_helper_probe_single_connector_modes(struct drm_connector - *connector, uint32_t maxX, - uint32_t maxY); -int drm_helper_probe_detect(struct drm_connector *connector, - struct drm_modeset_acquire_ctx *ctx, - bool force); -void drm_kms_helper_poll_init(struct drm_device *dev); -void drm_kms_helper_poll_fini(struct drm_device *dev); -bool drm_helper_hpd_irq_event(struct drm_device *dev); -void drm_kms_helper_hotplug_event(struct drm_device *dev); - -void drm_kms_helper_poll_disable(struct drm_device *dev); -void drm_kms_helper_poll_enable(struct drm_device *dev); -#ifdef __linux__ -bool drm_kms_helper_is_poll_worker(void); -#endif +int drm_helper_force_disable_all(struct drm_device *dev); #endif diff --git a/sys/dev/pci/drm/include/drm/drm_damage_helper.h b/sys/dev/pci/drm/include/drm/drm_damage_helper.h new file mode 100644 index 00000000000..40c34a5bf14 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_damage_helper.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/************************************************************************** + * + * Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Deepak Rawat <drawat@vmware.com> + * + **************************************************************************/ + +#ifndef DRM_DAMAGE_HELPER_H_ +#define DRM_DAMAGE_HELPER_H_ + +#include <drm/drm_atomic_helper.h> + +/** + * drm_atomic_for_each_plane_damage - Iterator macro for plane damage. + * @iter: The iterator to advance. + * @rect: Return a rectangle in fb coordinate clipped to plane src. + * + * Note that if the first call to iterator macro return false then no need to do + * plane update. Iterator will return full plane src when damage is not passed + * by user-space. + */ +#define drm_atomic_for_each_plane_damage(iter, rect) \ + while (drm_atomic_helper_damage_iter_next(iter, rect)) + +/** + * struct drm_atomic_helper_damage_iter - Closure structure for damage iterator. + * + * This structure tracks state needed to walk the list of plane damage clips. + */ +struct drm_atomic_helper_damage_iter { + /* private: Plane src in whole number. */ + struct drm_rect plane_src; + /* private: Rectangles in plane damage blob. */ + const struct drm_rect *clips; + /* private: Number of rectangles in plane damage blob. */ + uint32_t num_clips; + /* private: Current clip iterator is advancing on. */ + uint32_t curr_clip; + /* private: Whether need full plane update. */ + bool full_update; +}; + +void drm_plane_enable_fb_damage_clips(struct drm_plane *plane); +void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state, + struct drm_plane_state *plane_state); +int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned int flags, + unsigned int color, struct drm_clip_rect *clips, + unsigned int num_clips); +void +drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, + const struct drm_plane_state *old_state, + const struct drm_plane_state *new_state); +bool +drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter, + struct drm_rect *rect); +bool drm_atomic_helper_damage_merged(const struct drm_plane_state *old_state, + struct drm_plane_state *state, + struct drm_rect *rect); + +/** + * drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect. + * @state: Plane state. + * + * Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect + * can be obtained by simply typecasting &drm_mode_rect. This is because both + * are signed 32 and during drm_atomic_check_only() it is verified that damage + * clips are inside fb. + * + * Return: Clips in plane fb_damage_clips blob property. + */ +static inline struct drm_rect * +drm_helper_get_plane_damage_clips(const struct drm_plane_state *state) +{ + return (struct drm_rect *)drm_plane_get_damage_clips(state); +} + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_debugfs.h b/sys/dev/pci/drm/include/drm/drm_debugfs.h new file mode 100644 index 00000000000..7501e323d38 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_debugfs.h @@ -0,0 +1,103 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_DEBUGFS_H_ +#define _DRM_DEBUGFS_H_ + +#include <linux/types.h> +#include <linux/seq_file.h> +/** + * struct drm_info_list - debugfs info list entry + * + * This structure represents a debugfs file to be created by the drm + * core. + */ +struct drm_info_list { + /** @name: file name */ + const char *name; + /** + * @show: + * + * Show callback. &seq_file->private will be set to the &struct + * drm_info_node corresponding to the instance of this info on a given + * &struct drm_minor. + */ + int (*show)(struct seq_file*, void*); + /** @driver_features: Required driver features for this entry */ + u32 driver_features; + /** @data: Driver-private data, should not be device-specific. */ + void *data; +}; + +/** + * struct drm_info_node - Per-minor debugfs node structure + * + * This structure represents a debugfs file, as an instantiation of a &struct + * drm_info_list on a &struct drm_minor. + * + * FIXME: + * + * No it doesn't make a hole lot of sense that we duplicate debugfs entries for + * both the render and the primary nodes, but that's how this has organically + * grown. It should probably be fixed, with a compatibility link, if needed. + */ +struct drm_info_node { + /** @minor: &struct drm_minor for this node. */ + struct drm_minor *minor; + /** @info_ent: template for this node. */ + const struct drm_info_list *info_ent; + /* private: */ + struct list_head list; + struct dentry *dent; +}; + +#if defined(CONFIG_DEBUG_FS) +int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor); +int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor); +#else +static inline int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor) +{ + return 0; +} + +static inline int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor) +{ + return 0; +} +#endif + +#endif /* _DRM_DEBUGFS_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_device.h b/sys/dev/pci/drm/include/drm/drm_device.h index 8e2016b6df7..2d3255c3ced 100644 --- a/sys/dev/pci/drm/include/drm/drm_device.h +++ b/sys/dev/pci/drm/include/drm/drm_device.h @@ -1,112 +1,256 @@ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * - */ - #ifndef _DRM_DEVICE_H_ #define _DRM_DEVICE_H_ +#include <sys/types.h> +#include <sys/selinfo.h> + +#include <linux/list.h> +#include <linux/kref.h> +#include <linux/mutex.h> +#include <linux/idr.h> +#include <linux/pci.h> + #include <drm/drm_hashtab.h> #include <drm/drm_mode_config.h> +#include <sys/pool.h> + struct drm_driver; +struct drm_minor; +struct drm_master; +struct drm_device_dma; struct drm_vblank_crtc; +struct drm_sg_mem; struct drm_local_map; struct drm_vma_offset_manager; +struct drm_vram_mm; struct drm_fb_helper; +struct inode; + struct pci_dev; +struct pci_controller; + + +/** + * enum drm_switch_power - power state of drm device + */ + +enum switch_power_state { + /** @DRM_SWITCH_POWER_ON: Power state is ON */ + DRM_SWITCH_POWER_ON = 0, + + /** @DRM_SWITCH_POWER_OFF: Power state is OFF */ + DRM_SWITCH_POWER_OFF = 1, -/** - * DRM device functions structure + /** @DRM_SWITCH_POWER_CHANGING: Power state is changing */ + DRM_SWITCH_POWER_CHANGING = 2, + + /** @DRM_SWITCH_POWER_DYNAMIC_OFF: Suspended */ + DRM_SWITCH_POWER_DYNAMIC_OFF = 3, +}; + +/** + * struct drm_device - DRM device structure + * + * This structure represent a complete card that + * may contain multiple heads. */ struct drm_device { struct device *dev; - struct drm_driver *driver; + /** + * @legacy_dev_list: + * + * List of devices per driver for stealth attach cleanup + */ + struct list_head legacy_dev_list; - struct klist note; + /** @if_version: Highest interface version set */ + int if_version; - struct pci_dev _pdev; - struct pci_dev *pdev; + /** @ref: Object ref-count */ + struct kref ref; - bus_dma_tag_t dmat; - bus_space_tag_t bst; +#ifdef __linux__ + /** @dev: Device structure of bus-device */ + struct device *dev; +#endif + + /** @driver: DRM driver managing the device */ + struct drm_driver *driver; + + bus_dma_tag_t dmat; + bus_space_tag_t bst; + + struct klist note; + struct pci_dev _pdev; struct mutex quiesce_mtx; int quiesce; int quiesce_count; - char *unique; /* Unique identifier: e.g., busid */ - int unique_len; /* Length of unique field */ - - int if_version; /* Highest interface version set */ - bool registered; - /* Locks */ - struct rwlock struct_mutex; /* protects everything else */ + /** + * @dev_private: + * + * DRM driver private data. Instead of using this pointer it is + * recommended that drivers use drm_dev_init() and embed struct + * &drm_device in their larger per-device structure. + */ + void *dev_private; + + /** @primary: Primary node */ + struct drm_minor *primary; + + /** @render: Render node */ + struct drm_minor *render; + + /** + * @registered: + * + * Internally used by drm_dev_register() and drm_connector_register(). + */ + bool registered; + + /** + * @master: + * + * Currently active master for this device. + * Protected by &master_mutex + */ + struct drm_master *master; + + /** + * @driver_features: per-device driver features + * + * Drivers can clear specific flags here to disallow + * certain features on a per-device basis while still + * sharing a single &struct drm_driver instance across + * all devices. + */ + u32 driver_features; + + /** + * @unplugged: + * + * Flag to tell if the device has been unplugged. + * See drm_dev_enter() and drm_dev_is_unplugged(). + */ + bool unplugged; + + /** @anon_inode: inode for private address-space */ + struct inode *anon_inode; + + /** @unique: Unique name of the device */ + char *unique; + + /** + * @struct_mutex: + * + * Lock for others (not &drm_minor.master and &drm_file.is_master) + */ + struct rwlock struct_mutex; + + /** + * @master_mutex: + * + * Lock for &drm_minor.master and &drm_file.is_master + */ + struct rwlock master_mutex; - /* Usage Counters */ - int open_count; /* Outstanding files open */ + /** + * @open_count: + * + * Usage counter for outstanding files open, + * protected by drm_global_mutex + */ + atomic_t open_count; - /* Authentication */ + /** @filelist_mutex: Protects @filelist. */ + struct rwlock filelist_mutex; + /** + * @filelist: + * + * List of userspace clients, linked through &drm_file.lhead. + */ +#ifdef __linux__ + struct list_head filelist; +#else SPLAY_HEAD(drm_file_tree, drm_file) files; - drm_magic_t magicid; +#endif + + /** + * @filelist_internal: + * + * List of open DRM files for in-kernel clients. + * Protected by &filelist_mutex. + */ + struct list_head filelist_internal; + + /** + * @clientlist_mutex: + * + * Protects &clientlist access. + */ + struct rwlock clientlist_mutex; - /* Context support */ + /** + * @clientlist: + * + * List of in-kernel clients. Protected by &clientlist_mutex. + */ + struct list_head clientlist; - /** \name VBLANK IRQ support */ - /*@{ */ + /** + * @irq_enabled: + * + * Indicates that interrupt handling is enabled, specifically vblank + * handling. Drivers which don't use drm_irq_install() need to set this + * to true manually. + */ bool irq_enabled; - int irq; - /* - * At load time, disabling the vblank interrupt won't be allowed since - * old clients may not call the modeset ioctl and therefore misbehave. - * Once the modeset ioctl *has* been called though, we can safely - * disable them when unused. + /** + * @irq: Used by the drm_irq_install() and drm_irq_unistall() helpers. */ - bool vblank_disable_allowed; + int irq; - /* + /** + * @vblank_disable_immediate: + * * If true, vblank interrupt will be disabled immediately when the * refcount drops to zero, as opposed to via the vblank disable * timer. - * This can be set to true it the hardware has a working vblank - * counter and the driver uses drm_vblank_on() and drm_vblank_off() - * appropriately. + * + * This can be set to true it the hardware has a working vblank counter + * with high-precision timestamping (otherwise there are races) and the + * driver uses drm_crtc_vblank_on() and drm_crtc_vblank_off() + * appropriately. See also @max_vblank_count and + * &drm_crtc_funcs.get_vblank_counter. */ bool vblank_disable_immediate; - /* array of size num_crtcs */ + /** + * @vblank: + * + * Array of vblank tracking structures, one per &struct drm_crtc. For + * historical reasons (vblank support predates kernel modesetting) this + * is free-standing and not part of &struct drm_crtc itself. It must be + * initialized explicitly by calling drm_vblank_init(). + */ struct drm_vblank_crtc *vblank; - struct mutex vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ - struct mutex vbl_lock; + /** + * @vblank_time_lock: + * + * Protects vblank count and time updates during vblank enable/disable + */ + spinlock_t vblank_time_lock; + /** + * @vbl_lock: Top-level vblank references lock, wraps the low-level + * @vblank_time_lock. + */ + spinlock_t vbl_lock; /** * @max_vblank_count: @@ -129,43 +273,117 @@ struct drm_device { * * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set. */ - u32 max_vblank_count; /**< size of vblank counter register */ + u32 max_vblank_count; + + /** @vblank_event_list: List of vblank events */ + struct list_head vblank_event_list; /** - * List of events + * @event_lock: + * + * Protects @vblank_event_list and event delivery in + * general. See drm_send_event() and drm_send_event_locked(). */ - struct list_head vblank_event_list; spinlock_t event_lock; - /*@} */ - - int *vblank_enabled; - int *vblank_inmodeset; - u32 *last_vblank_wait; + /** @agp: AGP data */ + struct drm_agp_head *agp; - int num_crtcs; + /** @pdev: PCI device structure */ + struct pci_dev *pdev; - struct drm_agp_head *agp; - void *dev_private; - struct address_space *dev_mapping; - struct drm_local_map *agp_buffer_map; +#ifdef __alpha__ + /** @hose: PCI hose, only used on ALPHA platforms. */ + struct pci_controller *hose; +#endif + /** @num_crtcs: Number of CRTCs on this device */ + unsigned int num_crtcs; - struct drm_mode_config mode_config; /* Current mode config */ + /** @mode_config: Current mode config */ + struct drm_mode_config mode_config; - /* GEM info */ - atomic_t obj_count; - u_int obj_name; - atomic_t obj_memory; - struct pool objpl; + struct pool objpl; - /** \name GEM information */ - /*@{ */ + /** @object_name_lock: GEM information */ struct rwlock object_name_lock; + + /** @object_name_idr: GEM information */ struct idr object_name_idr; + + /** @vma_offset_manager: GEM information */ struct drm_vma_offset_manager *vma_offset_manager; - /*@} */ + /** @vram_mm: VRAM MM memory manager */ + struct drm_vram_mm *vram_mm; + + /** + * @switch_power_state: + * + * Power state of the client. + * Used by drivers supporting the switcheroo driver. + * The state is maintained in the + * &vga_switcheroo_client_ops.set_gpu_state callback + */ + enum switch_power_state switch_power_state; + + /** + * @fb_helper: + * + * Pointer to the fbdev emulation structure. + * Set by drm_fb_helper_init() and cleared by drm_fb_helper_fini(). + */ struct drm_fb_helper *fb_helper; + + /* Everything below here is for legacy driver, never use! */ + /* private: */ +#if IS_ENABLED(CONFIG_DRM_LEGACY) + /* Context handle management - linked list of context handles */ + struct list_head ctxlist; + + /* Context handle management - mutex for &ctxlist */ + struct rwlock ctxlist_mutex; + + /* Context handle management */ + struct idr ctx_idr; + + /* Memory management - linked list of regions */ + struct list_head maplist; + + /* Memory management - user token hash table for maps */ + struct drm_open_hash map_hash; + + /* Context handle management - list of vmas (for debugging) */ + struct list_head vmalist; + + /* Optional pointer for DMA support */ + struct drm_device_dma *dma; + + /* Context swapping flag */ + __volatile__ long context_flag; + + /* Last current context */ + int last_context; + + /* Lock for &buf_use and a few other things. */ + spinlock_t buf_lock; + + /* Usage counter for buffers in use -- cannot alloc */ + int buf_use; + + /* Buffer allocation in progress */ + atomic_t buf_alloc; + + struct { + int context; + struct drm_hw_lock *lock; + } sigdata; + + struct drm_local_map *agp_buffer_map; + unsigned int agp_buffer_token; + + /* Scatter gather memory */ + struct drm_sg_mem *sg; +#endif }; #endif diff --git a/sys/dev/pci/drm/include/drm/drm_dp_helper.h b/sys/dev/pci/drm/include/drm/drm_dp_helper.h index 47c901faee8..21174aed92b 100644 --- a/sys/dev/pci/drm/include/drm/drm_dp_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_dp_helper.h @@ -23,9 +23,9 @@ #ifndef _DRM_DP_HELPER_H_ #define _DRM_DP_HELPER_H_ -#include <linux/types.h> -#include <linux/i2c.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/types.h> /* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that @@ -42,6 +42,48 @@ * 1.2 formally includes both eDP and DPI definitions. */ +/* MSA (Main Stream Attribute) MISC bits (as MISC1<<8|MISC0) */ +#define DP_MSA_MISC_SYNC_CLOCK (1 << 0) +#define DP_MSA_MISC_INTERLACE_VTOTAL_EVEN (1 << 8) +#define DP_MSA_MISC_STEREO_NO_3D (0 << 9) +#define DP_MSA_MISC_STEREO_PROG_RIGHT_EYE (1 << 9) +#define DP_MSA_MISC_STEREO_PROG_LEFT_EYE (3 << 9) +/* bits per component for non-RAW */ +#define DP_MSA_MISC_6_BPC (0 << 5) +#define DP_MSA_MISC_8_BPC (1 << 5) +#define DP_MSA_MISC_10_BPC (2 << 5) +#define DP_MSA_MISC_12_BPC (3 << 5) +#define DP_MSA_MISC_16_BPC (4 << 5) +/* bits per component for RAW */ +#define DP_MSA_MISC_RAW_6_BPC (1 << 5) +#define DP_MSA_MISC_RAW_7_BPC (2 << 5) +#define DP_MSA_MISC_RAW_8_BPC (3 << 5) +#define DP_MSA_MISC_RAW_10_BPC (4 << 5) +#define DP_MSA_MISC_RAW_12_BPC (5 << 5) +#define DP_MSA_MISC_RAW_14_BPC (6 << 5) +#define DP_MSA_MISC_RAW_16_BPC (7 << 5) +/* pixel encoding/colorimetry format */ +#define _DP_MSA_MISC_COLOR(misc1_7, misc0_21, misc0_3, misc0_4) \ + ((misc1_7) << 15 | (misc0_4) << 4 | (misc0_3) << 3 | ((misc0_21) << 1)) +#define DP_MSA_MISC_COLOR_RGB _DP_MSA_MISC_COLOR(0, 0, 0, 0) +#define DP_MSA_MISC_COLOR_CEA_RGB _DP_MSA_MISC_COLOR(0, 0, 1, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FIXED _DP_MSA_MISC_COLOR(0, 3, 0, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FLOAT _DP_MSA_MISC_COLOR(0, 3, 0, 1) +#define DP_MSA_MISC_COLOR_Y_ONLY _DP_MSA_MISC_COLOR(1, 0, 0, 0) +#define DP_MSA_MISC_COLOR_RAW _DP_MSA_MISC_COLOR(1, 1, 0, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 1, 1) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 1, 1) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 0, 1) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 0, 1) +#define DP_MSA_MISC_COLOR_OPRGB _DP_MSA_MISC_COLOR(0, 0, 1, 1) +#define DP_MSA_MISC_COLOR_DCI_P3 _DP_MSA_MISC_COLOR(0, 3, 1, 0) +#define DP_MSA_MISC_COLOR_COLOR_PROFILE _DP_MSA_MISC_COLOR(0, 3, 1, 1) +#define DP_MSA_MISC_COLOR_VSC_SDP (1 << 14) + #define DP_AUX_MAX_PAYLOAD_BYTES 16 #define DP_AUX_I2C_WRITE 0x0 @@ -95,6 +137,7 @@ # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */ #define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0) #define DP_DOWN_STREAM_PORT_COUNT 0x007 # define DP_PORT_COUNT_MASK 0x0f @@ -123,8 +166,9 @@ # define DP_FRAMING_CHANGE_CAP (1 << 1) # define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ -#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ -# define DP_TRAINING_AUX_RD_MASK 0x7F /* XXX 1.2? */ +#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +# define DP_TRAINING_AUX_RD_MASK 0x7F /* DP 1.3 */ +# define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */ #define DP_ADAPTER_CAP 0x00f /* 1.2 */ # define DP_FORCE_LOAD_SENSE_CAP (1 << 0) @@ -230,6 +274,8 @@ #define DP_DSC_MAX_BITS_PER_PIXEL_LOW 0x067 /* eDP 1.4 */ #define DP_DSC_MAX_BITS_PER_PIXEL_HI 0x068 /* eDP 1.4 */ +# define DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK (0x3 << 0) +# define DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT 8 #define DP_DSC_DEC_COLOR_FORMAT_CAP 0x069 # define DP_DSC_RGB (1 << 0) @@ -246,6 +292,7 @@ #define DP_DSC_PEAK_THROUGHPUT 0x06B # define DP_DSC_THROUGHPUT_MODE_0_MASK (0xf << 0) # define DP_DSC_THROUGHPUT_MODE_0_SHIFT 0 +# define DP_DSC_THROUGHPUT_MODE_0_UPSUPPORTED 0 # define DP_DSC_THROUGHPUT_MODE_0_340 (1 << 0) # define DP_DSC_THROUGHPUT_MODE_0_400 (2 << 0) # define DP_DSC_THROUGHPUT_MODE_0_450 (3 << 0) @@ -260,8 +307,10 @@ # define DP_DSC_THROUGHPUT_MODE_0_900 (12 << 0) # define DP_DSC_THROUGHPUT_MODE_0_950 (13 << 0) # define DP_DSC_THROUGHPUT_MODE_0_1000 (14 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_170 (15 << 0) /* 1.4a */ # define DP_DSC_THROUGHPUT_MODE_1_MASK (0xf << 4) # define DP_DSC_THROUGHPUT_MODE_1_SHIFT 4 +# define DP_DSC_THROUGHPUT_MODE_1_UPSUPPORTED 0 # define DP_DSC_THROUGHPUT_MODE_1_340 (1 << 4) # define DP_DSC_THROUGHPUT_MODE_1_400 (2 << 4) # define DP_DSC_THROUGHPUT_MODE_1_450 (3 << 4) @@ -276,8 +325,11 @@ # define DP_DSC_THROUGHPUT_MODE_1_900 (12 << 4) # define DP_DSC_THROUGHPUT_MODE_1_950 (13 << 4) # define DP_DSC_THROUGHPUT_MODE_1_1000 (14 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_170 (15 << 4) #define DP_DSC_MAX_SLICE_WIDTH 0x06C +#define DP_DSC_MIN_SLICE_WIDTH_VALUE 2560 +#define DP_DSC_SLICE_WIDTH_MULTIPLIER 320 #define DP_DSC_SLICE_CAP_2 0x06D # define DP_DSC_16_PER_DP_DSC_SINK (1 << 0) @@ -309,6 +361,10 @@ # define DP_PSR_SETUP_TIME_SHIFT 1 # define DP_PSR2_SU_Y_COORDINATE_REQUIRED (1 << 4) /* eDP 1.4a */ # define DP_PSR2_SU_GRANULARITY_REQUIRED (1 << 5) /* eDP 1.4b */ + +#define DP_PSR2_SU_X_GRANULARITY 0x072 /* eDP 1.4b */ +#define DP_PSR2_SU_Y_GRANULARITY 0x074 /* eDP 1.4b */ + /* * 0x80-0x8f describe downstream port capabilities, but there are two layouts * based on whether DP_DETAILED_CAP_INFO_AVAILABLE was set. If it was not, @@ -336,6 +392,8 @@ # define DP_DS_12BPC 2 # define DP_DS_16BPC 3 +#define DP_MAX_DOWNSTREAM_PORTS 0x10 + /* DP Forward error Correction Registers */ #define DP_FEC_CAPABILITY 0x090 /* 1.4 */ # define DP_FEC_CAPABLE (1 << 0) @@ -343,6 +401,11 @@ # define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) # define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3) +/* DP Extended DSC Capabilities */ +#define DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 0x0a0 /* DP 1.4a SCR */ +#define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 +#define DP_DSC_BRANCH_MAX_LINE_WIDTH 0x0a2 + /* link configuration */ #define DP_LINK_BW_SET 0x100 # define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ @@ -476,6 +539,7 @@ # define DP_AUX_FRAME_SYNC_VALID (1 << 0) #define DP_DSC_ENABLE 0x160 /* DP 1.4 */ +# define DP_DECOMPRESSION_EN (1 << 0) #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) @@ -543,6 +607,14 @@ # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 #define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +# define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +# define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +# define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +# define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +# define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +# define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +# define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +# define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6 #define DP_TEST_REQUEST 0x218 # define DP_TEST_LINK_TRAINING (1 << 0) @@ -550,6 +622,8 @@ # define DP_TEST_LINK_EDID_READ (1 << 2) # define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ # define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ +# define DP_TEST_LINK_AUDIO_PATTERN (1 << 5) /* DPCD >= 1.2 */ +# define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6) /* DPCD >= 1.2 */ #define DP_TEST_LINK_RATE 0x219 # define DP_LINK_RATE_162 (0x6) @@ -598,6 +672,7 @@ # define DP_COLOR_FORMAT_RGB (0 << 1) # define DP_COLOR_FORMAT_YCbCr422 (1 << 1) # define DP_COLOR_FORMAT_YCbCr444 (2 << 1) +# define DP_TEST_DYNAMIC_RANGE_VESA (0 << 3) # define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3) # define DP_TEST_YCBCR_COEFFICIENTS (1 << 4) # define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4) @@ -647,6 +722,16 @@ #define DP_TEST_SINK 0x270 # define DP_TEST_SINK_START (1 << 0) +#define DP_TEST_AUDIO_MODE 0x271 +#define DP_TEST_AUDIO_PATTERN_TYPE 0x272 +#define DP_TEST_AUDIO_PERIOD_CH1 0x273 +#define DP_TEST_AUDIO_PERIOD_CH2 0x274 +#define DP_TEST_AUDIO_PERIOD_CH3 0x275 +#define DP_TEST_AUDIO_PERIOD_CH4 0x276 +#define DP_TEST_AUDIO_PERIOD_CH5 0x277 +#define DP_TEST_AUDIO_PERIOD_CH6 0x278 +#define DP_TEST_AUDIO_PERIOD_CH7 0x279 +#define DP_TEST_AUDIO_PERIOD_CH8 0x27A #define DP_FEC_STATUS 0x280 /* 1.4 */ # define DP_FEC_DECODE_EN_DETECTED (1 << 0) @@ -684,6 +769,8 @@ # define DP_EDP_12 0x01 # define DP_EDP_13 0x02 # define DP_EDP_14 0x03 +# define DP_EDP_14a 0x04 /* eDP 1.4a */ +# define DP_EDP_14b 0x05 /* eDP 1.4b */ #define DP_EDP_GENERAL_CAP_1 0x701 # define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0) @@ -904,6 +991,89 @@ #define DP_AUX_HDCP_KSV_FIFO 0x6802C #define DP_AUX_HDCP_AINFO 0x6803B +/* DP HDCP2.2 parameter offsets in DPCD address space */ +#define DP_HDCP_2_2_REG_RTX_OFFSET 0x69000 +#define DP_HDCP_2_2_REG_TXCAPS_OFFSET 0x69008 +#define DP_HDCP_2_2_REG_CERT_RX_OFFSET 0x6900B +#define DP_HDCP_2_2_REG_RRX_OFFSET 0x69215 +#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET 0x6921D +#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET 0x69220 +#define DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET 0x692A0 +#define DP_HDCP_2_2_REG_M_OFFSET 0x692B0 +#define DP_HDCP_2_2_REG_HPRIME_OFFSET 0x692C0 +#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET 0x692E0 +#define DP_HDCP_2_2_REG_RN_OFFSET 0x692F0 +#define DP_HDCP_2_2_REG_LPRIME_OFFSET 0x692F8 +#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET 0x69318 +#define DP_HDCP_2_2_REG_RIV_OFFSET 0x69328 +#define DP_HDCP_2_2_REG_RXINFO_OFFSET 0x69330 +#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET 0x69332 +#define DP_HDCP_2_2_REG_VPRIME_OFFSET 0x69335 +#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET 0x69345 +#define DP_HDCP_2_2_REG_V_OFFSET 0x693E0 +#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET 0x693F0 +#define DP_HDCP_2_2_REG_K_OFFSET 0x693F3 +#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5 +#define DP_HDCP_2_2_REG_MPRIME_OFFSET 0x69473 +#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET 0x69493 +#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 +#define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 + +/* Link Training (LT)-tunable PHY Repeaters */ +#define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */ +#define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */ +#define DP_PHY_REPEATER_CNT 0xf0002 /* 1.3 */ +#define DP_PHY_REPEATER_MODE 0xf0003 /* 1.3 */ +#define DP_MAX_LANE_COUNT_PHY_REPEATER 0xf0004 /* 1.4a */ +#define DP_Repeater_FEC_CAPABILITY 0xf0004 /* 1.4 */ +#define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT 0xf0005 /* 1.4a */ +#define DP_TRAINING_PATTERN_SET_PHY_REPEATER1 0xf0010 /* 1.3 */ +#define DP_TRAINING_LANE0_SET_PHY_REPEATER1 0xf0011 /* 1.3 */ +#define DP_TRAINING_LANE1_SET_PHY_REPEATER1 0xf0012 /* 1.3 */ +#define DP_TRAINING_LANE2_SET_PHY_REPEATER1 0xf0013 /* 1.3 */ +#define DP_TRAINING_LANE3_SET_PHY_REPEATER1 0xf0014 /* 1.3 */ +#define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0020 /* 1.4a */ +#define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1 0xf0021 /* 1.4a */ +#define DP_LANE0_1_STATUS_PHY_REPEATER1 0xf0030 /* 1.3 */ +#define DP_LANE2_3_STATUS_PHY_REPEATER1 0xf0031 /* 1.3 */ +#define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1 0xf0032 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 0xf0033 /* 1.3 */ +#define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1 0xf0034 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE0_PHY_REPEATER1 0xf0035 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE1_PHY_REPEATER1 0xf0037 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE2_PHY_REPEATER1 0xf0039 /* 1.3 */ +#define DP_SYMBOL_ERROR_COUNT_LANE3_PHY_REPEATER1 0xf003b /* 1.3 */ +#define DP_FEC_STATUS_PHY_REPEATER1 0xf0290 /* 1.4 */ +#define DP_FEC_ERROR_COUNT_PHY_REPEATER1 0xf0291 /* 1.4 */ +#define DP_FEC_CAPABILITY_PHY_REPEATER1 0xf0294 /* 1.4a */ + +/* Repeater modes */ +#define DP_PHY_REPEATER_MODE_TRANSPARENT 0x55 /* 1.3 */ +#define DP_PHY_REPEATER_MODE_NON_TRANSPARENT 0xaa /* 1.3 */ + +/* DP HDCP message start offsets in DPCD address space */ +#define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET +#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET +#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKPUB_KM_OFFSET +#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKH_KM_WR_OFFSET +#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET DP_HDCP_2_2_REG_HPRIME_OFFSET +#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \ + DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET +#define DP_HDCP_2_2_LC_INIT_OFFSET DP_HDCP_2_2_REG_RN_OFFSET +#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET DP_HDCP_2_2_REG_LPRIME_OFFSET +#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET DP_HDCP_2_2_REG_EDKEY_KS_OFFSET +#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET DP_HDCP_2_2_REG_RXINFO_OFFSET +#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET DP_HDCP_2_2_REG_V_OFFSET +#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET +#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET DP_HDCP_2_2_REG_MPRIME_OFFSET + +#define HDCP_2_2_DP_RXSTATUS_LEN 1 +#define HDCP_2_2_DP_RXSTATUS_READY(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x) ((x) & BIT(1)) +#define HDCP_2_2_DP_RXSTATUS_PAIRING(x) ((x) & BIT(2)) +#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) +#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x) ((x) & BIT(4)) + /* DP 1.2 Sideband message defines */ /* peer device type - DP 1.2a Table 2-92 */ #define DP_PEER_DEVICE_NONE 0x0 @@ -913,6 +1083,7 @@ #define DP_PEER_DEVICE_DP_LEGACY_CONV 0x4 /* DP 1.2 MST sideband request names DP 1.2a Table 2-80 */ +#define DP_GET_MSG_TRANSACTION_VERSION 0x00 /* DP 1.3 */ #define DP_LINK_ADDRESS 0x01 #define DP_CONNECTION_STATUS_NOTIFY 0x02 #define DP_ENUM_PATH_RESOURCES 0x10 @@ -929,6 +1100,10 @@ #define DP_SINK_EVENT_NOTIFY 0x30 #define DP_QUERY_STREAM_ENC_STATUS 0x38 +/* DP 1.2 MST sideband reply types */ +#define DP_SIDEBAND_REPLY_ACK 0x00 +#define DP_SIDEBAND_REPLY_NAK 0x01 + /* DP 1.2 MST sideband nak reasons - table 2.84 */ #define DP_NAK_WRITE_FAILURE 0x01 #define DP_NAK_INVALID_READ 0x02 @@ -959,9 +1134,12 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], int lane); +u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane); #define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf +#define DP_DSC_RECEIVER_CAP_SIZE 0xf #define EDP_PSR_RECEIVER_CAP_SIZE 2 #define EDP_DISPLAY_CTL_CAP_SIZE 3 @@ -983,27 +1161,48 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw); #define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */ /* 0x80+ CEA-861 infoframe types */ +/** + * struct dp_sdp_header - DP secondary data packet header + * @HB0: Secondary Data Packet ID + * @HB1: Secondary Data Packet Type + * @HB2: Secondary Data Packet Specific header, Byte 0 + * @HB3: Secondary Data packet Specific header, Byte 1 + */ struct dp_sdp_header { - u8 HB0; /* Secondary Data Packet ID */ - u8 HB1; /* Secondary Data Packet Type */ - u8 HB2; /* Secondary Data Packet Specific header, Byte 0 */ - u8 HB3; /* Secondary Data packet Specific header, Byte 1 */ + u8 HB0; + u8 HB1; + u8 HB2; + u8 HB3; } __packed; #define EDP_SDP_HEADER_REVISION_MASK 0x1F #define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES 0x1F +#define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F -struct edp_vsc_psr { +/** + * struct dp_sdp - DP secondary data packet + * @sdp_header: DP secondary data packet header + * @db: DP secondaray data packet data blocks + * VSC SDP Payload for PSR + * db[0]: Stereo Interface + * db[1]: 0 - PSR State; 1 - Update RFB; 2 - CRC Valid + * db[2]: CRC value bits 7:0 of the R or Cr component + * db[3]: CRC value bits 15:8 of the R or Cr component + * db[4]: CRC value bits 7:0 of the G or Y component + * db[5]: CRC value bits 15:8 of the G or Y component + * db[6]: CRC value bits 7:0 of the B or Cb component + * db[7]: CRC value bits 15:8 of the B or Cb component + * db[8] - db[31]: Reserved + * VSC SDP Payload for Pixel Encoding/Colorimetry Format + * db[0] - db[15]: Reserved + * db[16]: Pixel Encoding and Colorimetry Formats + * db[17]: Dynamic Range and Component Bit Depth + * db[18]: Content Type + * db[19] - db[31]: Reserved + */ +struct dp_sdp { struct dp_sdp_header sdp_header; - u8 DB0; /* Stereo Interface */ - u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */ - u8 DB2; /* CRC value bits 7:0 of the R or Cr component */ - u8 DB3; /* CRC value bits 15:8 of the R or Cr component */ - u8 DB4; /* CRC value bits 7:0 of the G or Y component */ - u8 DB5; /* CRC value bits 15:8 of the G or Y component */ - u8 DB6; /* CRC value bits 7:0 of the B or Cb component */ - u8 DB7; /* CRC value bits 15:8 of the B or Cb component */ - u8 DB8_31[24]; /* Reserved */ + u8 db[32]; } __packed; #define EDP_VSC_PSR_STATE_ACTIVE (1<<0) @@ -1032,6 +1231,13 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } static inline bool +drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING); +} + +static inline bool drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { return dpcd[DP_DPCD_REV] >= 0x12 && @@ -1058,6 +1264,57 @@ drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT; } +/* DP/eDP DSC support */ +u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp); +u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); +int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpc[DP_DSC_RECEIVER_CAP_SIZE], + u8 dsc_bpc[3]); + +static inline bool +drm_dp_sink_supports_dsc(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) +{ + return dsc_dpcd[DP_DSC_SUPPORT - DP_DSC_SUPPORT] & + DP_DSC_DECOMPRESSION_IS_SUPPORTED; +} + +static inline u16 +drm_edp_dsc_sink_output_bpp(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) +{ + return dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] | + (dsc_dpcd[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] & + DP_DSC_MAX_BITS_PER_PIXEL_HI_MASK << + DP_DSC_MAX_BITS_PER_PIXEL_HI_SHIFT); +} + +static inline u32 +drm_dp_dsc_sink_max_slice_width(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) +{ + /* Max Slicewidth = Number of Pixels * 320 */ + return dsc_dpcd[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] * + DP_DSC_SLICE_WIDTH_MULTIPLIER; +} + +/* Forward Error Correction Support on DP 1.4 */ +static inline bool +drm_dp_sink_supports_fec(const u8 fec_capable) +{ + return fec_capable & DP_FEC_CAPABLE; +} + +static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; +} + +static inline bool +drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_EDP_CONFIGURATION_CAP] & + DP_ALTERNATE_SCRAMBLER_RESET_CAP; +} + /* * DisplayPort AUX channel */ @@ -1080,20 +1337,19 @@ struct drm_dp_aux_msg { struct cec_adapter; struct edid; +struct drm_connector; /** * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX * @lock: mutex protecting this struct * @adap: the CEC adapter for CEC-Tunneling-over-AUX support. - * @name: name of the CEC adapter - * @parent: parent device of the CEC adapter + * @connector: the connector this CEC adapter is associated with * @unregister_work: unregister the CEC adapter */ struct drm_dp_aux_cec { struct rwlock lock; struct cec_adapter *adap; - const char *name; - struct device *parent; + struct drm_connector *connector; struct delayed_work unregister_work; }; @@ -1159,6 +1415,10 @@ struct drm_dp_aux { * @cec: struct containing fields used for CEC-Tunneling-over-AUX. */ struct drm_dp_aux_cec cec; + /** + * @is_remote: Is this AUX CH actually using sideband messaging. + */ + bool is_remote; }; ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, @@ -1199,22 +1459,9 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, u8 status[DP_LINK_STATUS_SIZE]); -/* - * DisplayPort link - */ -#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) - -struct drm_dp_link { - unsigned char revision; - unsigned int rate; - unsigned int num_lanes; - unsigned long capabilities; -}; +bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, + u8 real_edid_checksum); -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], @@ -1223,6 +1470,7 @@ int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], struct drm_dp_aux *aux); +void drm_dp_remote_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux); void drm_dp_aux_unregister(struct drm_dp_aux *aux); @@ -1250,41 +1498,77 @@ struct drm_dp_desc { int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, bool is_branch); +u32 drm_dp_get_edid_quirks(const struct edid *edid); /** * enum drm_dp_quirk - Display Port sink/branch device specific quirks * * Display Port sink and branch devices in the wild have a variety of bugs, try * to collect them here. The quirks are shared, but it's up to the drivers to - * implement workarounds for them. + * implement workarounds for them. Note that because some devices have + * unreliable OUIDs, the EDID of sinks should also be checked for quirks using + * drm_dp_get_edid_quirks(). */ enum drm_dp_quirk { /** - * @DP_DPCD_QUIRK_LIMITED_M_N: + * @DP_DPCD_QUIRK_CONSTANT_N: * * The device requires main link attributes Mvid and Nvid to be limited - * to 16 bits. + * to 16 bits. So will give a constant value (0x8000) for compatability. + */ + DP_DPCD_QUIRK_CONSTANT_N, + /** + * @DP_DPCD_QUIRK_NO_PSR: + * + * The device does not support PSR even if reports that it supports or + * driver still need to implement proper handling for such device. + */ + DP_DPCD_QUIRK_NO_PSR, + /** + * @DP_DPCD_QUIRK_NO_SINK_COUNT: + * + * The device does not set SINK_COUNT to a non-zero value. + * The driver should ignore SINK_COUNT during detection. + */ + DP_DPCD_QUIRK_NO_SINK_COUNT, + /** + * @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD: + * + * The device supports MST DSC despite not supporting Virtual DPCD. + * The DSC caps can be read from the physical aux instead. + */ + DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD, + /** + * @DP_QUIRK_FORCE_DPCD_BACKLIGHT: + * + * The device is telling the truth when it says that it uses DPCD + * backlight controls, even if the system's firmware disagrees. This + * quirk should be checked against both the ident and panel EDID. + * When present, the driver should honor the DPCD backlight + * capabilities advertised. */ - DP_DPCD_QUIRK_LIMITED_M_N, + DP_QUIRK_FORCE_DPCD_BACKLIGHT, }; /** * drm_dp_has_quirk() - does the DP device have a specific quirk * @desc: Device decriptor filled by drm_dp_read_desc() + * @edid_quirks: Optional quirk bitmask filled by drm_dp_get_edid_quirks() * @quirk: Quirk to query for * * Return true if DP device identified by @desc has @quirk. */ static inline bool -drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) +drm_dp_has_quirk(const struct drm_dp_desc *desc, u32 edid_quirks, + enum drm_dp_quirk quirk) { - return desc->quirks & BIT(quirk); + return (desc->quirks | edid_quirks) & BIT(quirk); } #ifdef CONFIG_DRM_DP_CEC void drm_dp_cec_irq(struct drm_dp_aux *aux); -void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, - struct device *parent); +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector); void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux); void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid); void drm_dp_cec_unset_edid(struct drm_dp_aux *aux); @@ -1293,9 +1577,9 @@ static inline void drm_dp_cec_irq(struct drm_dp_aux *aux) { } -static inline void drm_dp_cec_register_connector(struct drm_dp_aux *aux, - const char *name, - struct device *parent) +static inline void +drm_dp_cec_register_connector(struct drm_dp_aux *aux, + struct drm_connector *connector) { } diff --git a/sys/dev/pci/drm/include/drm/drm_dp_mst_helper.h b/sys/dev/pci/drm/include/drm/drm_dp_mst_helper.h index 4070429fb32..cc5cf0649aa 100644 --- a/sys/dev/pci/drm/include/drm/drm_dp_mst_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_dp_mst_helper.h @@ -26,6 +26,26 @@ #include <drm/drm_dp_helper.h> #include <drm/drm_atomic.h> +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) +#include <linux/stackdepot.h> +#include <linux/timekeeping.h> + +enum drm_dp_mst_topology_ref_type { + DRM_DP_MST_TOPOLOGY_REF_GET, + DRM_DP_MST_TOPOLOGY_REF_PUT, +}; + +struct drm_dp_mst_topology_ref_history { + struct drm_dp_mst_topology_ref_entry { + enum drm_dp_mst_topology_ref_type type; + int count; + ktime_t ts_nsec; + depot_stack_handle_t backtrace; + } *entries; + int len; +}; +#endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */ + struct drm_dp_mst_branch; /** @@ -44,30 +64,58 @@ struct drm_dp_vcpi { /** * struct drm_dp_mst_port - MST port - * @kref: reference count for this port. * @port_num: port number - * @input: if this port is an input port. - * @mcs: message capability status - DP 1.2 spec. - * @ddps: DisplayPort Device Plug Status - DP 1.2 - * @pdt: Peer Device Type - * @ldps: Legacy Device Plug Status - * @dpcd_rev: DPCD revision of device on this port - * @num_sdp_streams: Number of simultaneous streams - * @num_sdp_stream_sinks: Number of stream sinks - * @available_pbn: Available bandwidth for this port. + * @input: if this port is an input port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @mcs: message capability status - DP 1.2 spec. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @ddps: DisplayPort Device Plug Status - DP 1.2. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @pdt: Peer Device Type. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @ldps: Legacy Device Plug Status. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @dpcd_rev: DPCD revision of device on this port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @num_sdp_streams: Number of simultaneous streams. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @num_sdp_stream_sinks: Number of stream sinks. Protected by + * &drm_dp_mst_topology_mgr.base.lock. + * @full_pbn: Max possible bandwidth for this port. Protected by + * &drm_dp_mst_topology_mgr.base.lock. * @next: link to next port on this branch device - * @mstb: branch device attach below this port - * @aux: i2c aux transport to talk to device connected to this port. + * @aux: i2c aux transport to talk to device connected to this port, protected + * by &drm_dp_mst_topology_mgr.base.lock. * @parent: branch device parent of this port * @vcpi: Virtual Channel Payload info for this port. - * @connector: DRM connector this port is connected to. + * @connector: DRM connector this port is connected to. Protected by + * &drm_dp_mst_topology_mgr.base.lock. * @mgr: topology manager this port lives under. * * This structure represents an MST port endpoint on a device somewhere * in the MST topology. */ struct drm_dp_mst_port { - struct kref kref; + /** + * @topology_kref: refcount for this port's lifetime in the topology, + * only the DP MST helpers should need to touch this + */ + struct kref topology_kref; + + /** + * @malloc_kref: refcount for the memory allocation containing this + * structure. See drm_dp_mst_get_port_malloc() and + * drm_dp_mst_put_port_malloc(). + */ + struct kref malloc_kref; + +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history: A history of each topology + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. + */ + struct drm_dp_mst_topology_ref_history topology_ref_history; +#endif u8 port_num; bool input; @@ -78,9 +126,19 @@ struct drm_dp_mst_port { u8 dpcd_rev; u8 num_sdp_streams; u8 num_sdp_stream_sinks; - uint16_t available_pbn; + uint16_t full_pbn; struct list_head next; - struct drm_dp_mst_branch *mstb; /* pointer to an mstb if this port has one */ + /** + * @mstb: the branch device connected to this port, if there is one. + * This should be considered protected for reading by + * &drm_dp_mst_topology_mgr.lock. There are two exceptions to this: + * &drm_dp_mst_topology_mgr.up_req_work and + * &drm_dp_mst_topology_mgr.work, which do not grab + * &drm_dp_mst_topology_mgr.lock during reads but are the only + * updaters of this list and are protected from writing concurrently + * by &drm_dp_mst_topology_mgr.probe_lock. + */ + struct drm_dp_mst_branch *mstb; struct drm_dp_aux aux; /* i2c bus for this port? */ struct drm_dp_mst_branch *parent; @@ -98,16 +156,16 @@ struct drm_dp_mst_port { * audio-capable. */ bool has_audio; + + bool fec_capable; }; /** * struct drm_dp_mst_branch - MST branch device. - * @kref: reference count for this port. * @rad: Relative Address to talk to this branch device. * @lct: Link count total to talk to this branch device. * @num_ports: number of ports on the branch. * @msg_slots: one bit per transmitted msg slot. - * @ports: linked list of ports on this branch. * @port_parent: pointer to the port parent, NULL if toplevel. * @mgr: topology manager for this branch device. * @tx_slots: transmission slots for this device. @@ -121,12 +179,48 @@ struct drm_dp_mst_port { * to downstream port of parent branches. */ struct drm_dp_mst_branch { - struct kref kref; + /** + * @topology_kref: refcount for this branch device's lifetime in the + * topology, only the DP MST helpers should need to touch this + */ + struct kref topology_kref; + + /** + * @malloc_kref: refcount for the memory allocation containing this + * structure. See drm_dp_mst_get_mstb_malloc() and + * drm_dp_mst_put_mstb_malloc(). + */ + struct kref malloc_kref; + +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history: A history of each topology + * reference/dereference. See CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. + */ + struct drm_dp_mst_topology_ref_history topology_ref_history; +#endif + + /** + * @destroy_next: linked-list entry used by + * drm_dp_delayed_destroy_work() + */ + struct list_head destroy_next; + u8 rad[8]; u8 lct; int num_ports; int msg_slots; + /** + * @ports: the list of ports on this branch device. This should be + * considered protected for reading by &drm_dp_mst_topology_mgr.lock. + * There are two exceptions to this: + * &drm_dp_mst_topology_mgr.up_req_work and + * &drm_dp_mst_topology_mgr.work, which do not grab + * &drm_dp_mst_topology_mgr.lock during reads but are the only + * updaters of this list and are protected from updating the list + * concurrently by @drm_dp_mst_topology_mgr.probe_lock + */ struct list_head ports; /* list of tx ops queue for this port */ @@ -266,7 +360,7 @@ struct drm_dp_remote_dpcd_write { struct drm_dp_remote_i2c_read { u8 num_transactions; u8 port_number; - struct { + struct drm_dp_remote_i2c_read_tx { u8 i2c_dev_id; u8 num_bytes; u8 *bytes; @@ -291,6 +385,7 @@ struct drm_dp_port_number_req { struct drm_dp_enum_path_resources_ack_reply { u8 port_number; + bool fec_capable; u16 full_payload_bw_number; u16 avail_payload_bw_number; }; @@ -384,11 +479,8 @@ struct drm_dp_mst_topology_mgr; struct drm_dp_mst_topology_cbs { /* create a connector for a port */ struct drm_connector *(*add_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *path); - void (*register_connector)(struct drm_connector *connector); void (*destroy_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector); - void (*hotplug)(struct drm_dp_mst_topology_mgr *mgr); - }; #define DP_MAX_PAYLOAD (sizeof(unsigned long) * 8) @@ -406,10 +498,17 @@ struct drm_dp_payload { #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) +struct drm_dp_vcpi_allocation { + struct drm_dp_mst_port *port; + int vcpi; + int pbn; + bool dsc_enabled; + struct list_head next; +}; + struct drm_dp_mst_topology_state { struct drm_private_state base; - int avail_slots; - struct drm_atomic_state *state; + struct list_head vcpis; struct drm_dp_mst_topology_mgr *mgr; }; @@ -457,28 +556,44 @@ struct drm_dp_mst_topology_mgr { int conn_base_id; /** - * @down_rep_recv: Message receiver state for down replies. This and - * @up_req_recv are only ever access from the work item, which is - * serialised. + * @down_rep_recv: Message receiver state for down replies. */ struct drm_dp_sideband_msg_rx down_rep_recv; /** - * @up_req_recv: Message receiver state for up requests. This and - * @down_rep_recv are only ever access from the work item, which is - * serialised. + * @up_req_recv: Message receiver state for up requests. */ struct drm_dp_sideband_msg_rx up_req_recv; /** - * @lock: protects mst state, primary, dpcd. + * @lock: protects @mst_state, @mst_primary, @dpcd, and + * @payload_id_table_cleared. */ struct rwlock lock; /** + * @probe_lock: Prevents @work and @up_req_work, the only writers of + * &drm_dp_mst_port.mstb and &drm_dp_mst_branch.ports, from racing + * while they update the topology. + */ + struct rwlock probe_lock; + + /** * @mst_state: If this manager is enabled for an MST capable port. False * if no MST sink/branch devices is connected. */ - bool mst_state; + bool mst_state : 1; + + /** + * @payload_id_table_cleared: Whether or not we've cleared the payload + * ID table for @mst_primary. Protected by @lock. + */ + bool payload_id_table_cleared : 1; + + /** + * @is_waiting_for_dwn_reply: whether we're waiting for a down reply. + */ + bool is_waiting_for_dwn_reply : 1; + /** * @mst_primary: Pointer to the primary/first branch device. */ @@ -498,11 +613,6 @@ struct drm_dp_mst_topology_mgr { int pbn_div; /** - * @state: State information for topology manager - */ - struct drm_dp_mst_topology_state *state; - - /** * @funcs: Atomic helper callbacks */ const struct drm_private_state_funcs *funcs; @@ -512,6 +622,7 @@ struct drm_dp_mst_topology_mgr { * &drm_dp_sideband_msg_tx.state once they are queued */ struct rwlock qlock; + /** * @tx_msg_downq: List of pending down replies. */ @@ -523,11 +634,13 @@ struct drm_dp_mst_topology_mgr { struct rwlock payload_lock; /** * @proposed_vcpis: Array of pointers for the new VCPI allocation. The - * VCPI structure itself is &drm_dp_mst_port.vcpi. + * VCPI structure itself is &drm_dp_mst_port.vcpi, and the size of + * this array is determined by @max_payloads. */ struct drm_dp_vcpi **proposed_vcpis; /** - * @payloads: Array of payloads. + * @payloads: Array of payloads. The size of this array is determined + * by @max_payloads. */ struct drm_dp_payload *payloads; /** @@ -556,18 +669,49 @@ struct drm_dp_mst_topology_mgr { struct work_struct tx_work; /** - * @destroy_connector_list: List of to be destroyed connectors. + * @destroy_port_list: List of to be destroyed connectors. + */ + struct list_head destroy_port_list; + /** + * @destroy_branch_device_list: List of to be destroyed branch + * devices. + */ + struct list_head destroy_branch_device_list; + /** + * @delayed_destroy_lock: Protects @destroy_port_list and + * @destroy_branch_device_list. + */ + struct rwlock delayed_destroy_lock; + /** + * @delayed_destroy_work: Work item to destroy MST port and branch + * devices, needed to avoid locking inversion. + */ + struct work_struct delayed_destroy_work; + + /** + * @up_req_list: List of pending up requests from the topology that + * need to be processed, in chronological order. */ - struct list_head destroy_connector_list; + struct list_head up_req_list; /** - * @destroy_connector_lock: Protects @connector_list. + * @up_req_lock: Protects @up_req_list */ - struct rwlock destroy_connector_lock; + struct rwlock up_req_lock; /** - * @destroy_connector_work: Work item to destroy connectors. Needed to - * avoid locking inversion. + * @up_req_work: Work item to process up requests received from the + * topology. Needed to avoid blocking hotplug handling and sideband + * transmissions. */ - struct work_struct destroy_connector_work; + struct work_struct up_req_work; + +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) + /** + * @topology_ref_history_lock: protects + * &drm_dp_mst_port.topology_ref_history and + * &drm_dp_mst_branch.topology_ref_history. + */ + struct rwlock topology_ref_history_lock; +#endif }; int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, @@ -584,15 +728,18 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); -enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); +int +drm_dp_mst_detect_port(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); -int drm_dp_calc_pbn_mode(int clock, int bpp); - +int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc); bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int slots); @@ -622,16 +769,141 @@ void drm_dp_mst_dump_topology(struct seq_file *m, struct drm_dp_mst_topology_mgr *mgr); void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); +int __must_check +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, + bool sync); + +ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); +ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, + unsigned int offset, void *buffer, size_t size); + +int drm_dp_mst_connector_late_register(struct drm_connector *connector, + struct drm_dp_mst_port *port); +void drm_dp_mst_connector_early_unregister(struct drm_connector *connector, + struct drm_dp_mst_port *port); + struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_port *port, int pbn); -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - int slots); +int __must_check +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn, + int pbn_div); +int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, + struct drm_dp_mst_port *port, + int pbn, int pbn_div, + bool enable); +int __must_check +drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); +int __must_check +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up); +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); + +void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port); +void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port); + +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port); + +extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; + +/** + * __drm_dp_mst_state_iter_get - private atomic state iterator function for + * macro-internal use + * @state: &struct drm_atomic_state pointer + * @mgr: pointer to the &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: optional pointer to the old &struct drm_dp_mst_topology_state + * iteration cursor + * @new_state: optional pointer to the new &struct drm_dp_mst_topology_state + * iteration cursor + * @i: int iteration cursor, for macro-internal use + * + * Used by for_each_oldnew_mst_mgr_in_state(), + * for_each_old_mst_mgr_in_state(), and for_each_new_mst_mgr_in_state(). Don't + * call this directly. + * + * Returns: + * True if the current &struct drm_private_obj is a &struct + * drm_dp_mst_topology_mgr, false otherwise. + */ +static inline bool +__drm_dp_mst_state_iter_get(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr **mgr, + struct drm_dp_mst_topology_state **old_state, + struct drm_dp_mst_topology_state **new_state, + int i) +{ + struct __drm_private_objs_state *objs_state = &state->private_objs[i]; + + if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) + return false; + + *mgr = to_dp_mst_topology_mgr(objs_state->ptr); + if (old_state) + *old_state = to_dp_mst_topology_state(objs_state->old_state); + if (new_state) + *new_state = to_dp_mst_topology_state(objs_state->new_state); + + return true; +} + +/** + * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology + * managers in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking both old and new state. This is useful in places where the state + * delta needs to be considered, for example in atomic check functions. + */ +#define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) + +/** + * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the old state. This is useful in disable functions, where we + * need the old state the hardware is still in. + */ +#define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) + +/** + * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the new state. This is useful in enable functions, where we + * need the new state the hardware should be in when the atomic commit + * operation has completed. + */ +#define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) #endif diff --git a/sys/dev/pci/drm/include/drm/drm_drv.h b/sys/dev/pci/drm/include/drm/drm_drv.h index 3d643545b17..7ed43504f2b 100644 --- a/sys/dev/pci/drm/include/drm/drm_drv.h +++ b/sys/dev/pci/drm/include/drm/drm_drv.h @@ -1,7 +1,8 @@ -/*- +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All rights reserved. + * Copyright (c) 2009-2010, Code Aurora Forum. + * Copyright 2016 Intel Corp. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -21,11 +22,6 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #ifndef _DRM_DRV_H_ @@ -36,227 +32,667 @@ #include <drm/drm_device.h> +#include <uvm/uvm_extern.h> + struct drm_file; struct drm_gem_object; +struct drm_master; +struct drm_minor; +struct dma_buf_attachment; struct drm_display_mode; struct drm_mode_create_dumb; struct drm_printer; -/* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_LEGACY 0x2 -#define DRIVER_PCI_DMA 0x8 -#define DRIVER_SG 0x10 -#define DRIVER_HAVE_DMA 0x20 -#define DRIVER_HAVE_IRQ 0x40 -#define DRIVER_IRQ_SHARED 0x80 -#define DRIVER_GEM 0x1000 -#define DRIVER_MODESET 0x2000 -#define DRIVER_PRIME 0x4000 -#define DRIVER_RENDER 0x8000 -#define DRIVER_ATOMIC 0x10000 -#define DRIVER_KMS_LEGACY_CONTEXT 0x20000 -#define DRIVER_SYNCOBJ 0x40000 -#define DRIVER_PREFER_XBGR_30BPP 0x80000 +/** + * enum drm_driver_feature - feature flags + * + * See &drm_driver.driver_features, drm_device.driver_features and + * drm_core_check_feature(). + */ +enum drm_driver_feature { + /** + * @DRIVER_GEM: + * + * Driver use the GEM memory manager. This should be set for all modern + * drivers. + */ + DRIVER_GEM = BIT(0), + /** + * @DRIVER_MODESET: + * + * Driver supports mode setting interfaces (KMS). + */ + DRIVER_MODESET = BIT(1), + /** + * @DRIVER_RENDER: + * + * Driver supports dedicated render nodes. See also the :ref:`section on + * render nodes <drm_render_node>` for details. + */ + DRIVER_RENDER = BIT(3), + /** + * @DRIVER_ATOMIC: + * + * Driver supports the full atomic modesetting userspace API. Drivers + * which only use atomic internally, but do not the support the full + * userspace API (e.g. not all properties converted to atomic, or + * multi-plane updates are not guaranteed to be tear-free) should not + * set this flag. + */ + DRIVER_ATOMIC = BIT(4), + /** + * @DRIVER_SYNCOBJ: + * + * Driver supports &drm_syncobj for explicit synchronization of command + * submission. + */ + DRIVER_SYNCOBJ = BIT(5), + /** + * @DRIVER_SYNCOBJ_TIMELINE: + * + * Driver supports the timeline flavor of &drm_syncobj for explicit + * synchronization of command submission. + */ + DRIVER_SYNCOBJ_TIMELINE = BIT(6), + /* IMPORTANT: Below are all the legacy flags, add new ones above. */ + + /** + * @DRIVER_USE_AGP: + * + * Set up DRM AGP support, see drm_agp_init(), the DRM core will manage + * AGP resources. New drivers don't need this. + */ + DRIVER_USE_AGP = BIT(25), + /** + * @DRIVER_LEGACY: + * + * Denote a legacy driver using shadow attach. Do not use. + */ + DRIVER_LEGACY = BIT(26), + /** + * @DRIVER_PCI_DMA: + * + * Driver is capable of PCI DMA, mapping of PCI DMA buffers to userspace + * will be enabled. Only for legacy drivers. Do not use. + */ + DRIVER_PCI_DMA = BIT(27), + /** + * @DRIVER_SG: + * + * Driver can perform scatter/gather DMA, allocation and mapping of + * scatter/gather buffers will be enabled. Only for legacy drivers. Do + * not use. + */ + DRIVER_SG = BIT(28), + + /** + * @DRIVER_HAVE_DMA: + * + * Driver supports DMA, the userspace DMA API will be supported. Only + * for legacy drivers. Do not use. + */ + DRIVER_HAVE_DMA = BIT(29), + /** + * @DRIVER_HAVE_IRQ: + * + * Legacy irq support. Only for legacy drivers. Do not use. + * + * New drivers can either use the drm_irq_install() and + * drm_irq_uninstall() helper functions, or roll their own irq support + * code by calling request_irq() directly. + */ + DRIVER_HAVE_IRQ = BIT(30), + /** + * @DRIVER_KMS_LEGACY_CONTEXT: + * + * Used only by nouveau for backwards compatibility with existing + * userspace. Do not use. + */ + DRIVER_KMS_LEGACY_CONTEXT = BIT(31), +}; + +/** + * struct drm_driver - DRM driver structure + * + * This structure represent the common code for a family of cards. There will be + * one &struct drm_device for each card present in this family. It contains lots + * of vfunc entries, and a pile of those probably should be moved to more + * appropriate places like &drm_mode_config_funcs or into a new operations + * structure for GEM drivers. + */ struct drm_driver { - int (*firstopen)(struct drm_device *); - int (*open)(struct drm_device *, struct drm_file *); - void (*preclose)(struct drm_device *, struct drm_file *); - void (*postclose)(struct drm_device *, struct drm_file *); - void (*lastclose)(struct drm_device *); - struct uvm_object *(*mmap)(struct drm_device *, voff_t, vsize_t); - int (*dma_ioctl)(struct drm_device *, struct drm_dma *, - struct drm_file *); - int (*irq_handler)(int, void *); - void (*irq_preinstall) (struct drm_device *); - int (*irq_install)(struct drm_device *); - int (*irq_postinstall) (struct drm_device *); - void (*irq_uninstall)(struct drm_device *); - int vblank_pipes; - - /** - * get_vblank_counter - get raw hardware vblank counter - * @dev: DRM device - * @pipe: counter to fetch - * - * Driver callback for fetching a raw hardware vblank counter for @crtc. - * If a device doesn't have a hardware counter, the driver can simply - * return the value of drm_vblank_count. The DRM core will account for - * missed vblank events while interrupts where disabled based on system - * timestamps. - * - * Wraparound handling and loss of events due to modesetting is dealt - * with in the DRM core code. - * - * RETURNS - * Raw vblank counter value. - */ - u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe); + /** + * @load: + * + * Backward-compatible driver callback to complete + * initialization steps after the driver is registered. For + * this reason, may suffer from race conditions and its use is + * deprecated for new drivers. It is therefore only supported + * for existing drivers not yet converted to the new scheme. + * See drm_dev_init() and drm_dev_register() for proper and + * race-free way to set up a &struct drm_device. + * + * This is deprecated, do not use! + * + * Returns: + * + * Zero on success, non-zero value on failure. + */ + int (*load) (struct drm_device *, unsigned long flags); /** - * enable_vblank - enable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable + * @open: + * + * Driver callback when a new &struct drm_file is opened. Useful for + * setting up driver-private data structures like buffer allocators, + * execution contexts or similar things. Such driver-private resources + * must be released again in @postclose. + * + * Since the display/modeset side of DRM can only be owned by exactly + * one &struct drm_file (see &drm_file.is_master and &drm_device.master) + * there should never be a need to set up any modeset related resources + * in this callback. Doing so would be a driver design bug. * - * Enable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, this routine should be a no-op, since - * interrupts will have to stay on to keep the count accurate. + * Returns: * - * RETURNS - * Zero on success, appropriate errno if the given @crtc's vblank - * interrupt cannot be enabled. + * 0 on success, a negative error code on failure, which will be + * promoted to userspace as the result of the open() system call. */ - int (*enable_vblank) (struct drm_device *dev, unsigned int pipe); + int (*open) (struct drm_device *, struct drm_file *); /** - * disable_vblank - disable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable + * @postclose: * - * Disable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, this routine should be a no-op, since - * interrupts will have to stay on to keep the count accurate. + * One of the driver callbacks when a new &struct drm_file is closed. + * Useful for tearing down driver-private data structures allocated in + * @open like buffer allocators, execution contexts or similar things. + * + * Since the display/modeset side of DRM can only be owned by exactly + * one &struct drm_file (see &drm_file.is_master and &drm_device.master) + * there should never be a need to tear down any modeset related + * resources in this callback. Doing so would be a driver design bug. */ - void (*disable_vblank) (struct drm_device *dev, unsigned int pipe); + void (*postclose) (struct drm_device *, struct drm_file *); /** - * Called by vblank timestamping code. + * @lastclose: * - * Return the current display scanout position from a crtc, and an - * optional accurate ktime_get timestamp of when position was measured. + * Called when the last &struct drm_file has been closed and there's + * currently no userspace client for the &struct drm_device. * - * \param dev DRM device. - * \param pipe Id of the crtc to query. - * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). - * \param *vpos Target location for current vertical scanout position. - * \param *hpos Target location for current horizontal scanout position. - * \param *stime Target location for timestamp taken immediately before - * scanout position query. Can be NULL to skip timestamp. - * \param *etime Target location for timestamp taken immediately after - * scanout position query. Can be NULL to skip timestamp. - * \param mode Current display timings. + * Modern drivers should only use this to force-restore the fbdev + * framebuffer using drm_fb_helper_restore_fbdev_mode_unlocked(). + * Anything else would indicate there's something seriously wrong. + * Modern drivers can also use this to execute delayed power switching + * state changes, e.g. in conjunction with the :ref:`vga_switcheroo` + * infrastructure. * - * Returns vpos as a positive number while in active scanout area. - * Returns vpos as a negative number inside vblank, counting the number - * of scanlines to go until end of vblank, e.g., -1 means "one scanline - * until start of active scanout / end of vblank." + * This is called after @postclose hook has been called. * - * \return Flags, or'ed together as follows: + * NOTE: * - * DRM_SCANOUTPOS_VALID = Query successful. - * DRM_SCANOUTPOS_INVBL = Inside vblank. - * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of - * this flag means that returned position may be offset by a constant - * but unknown small number of scanlines wrt. real scanout position. + * All legacy drivers use this callback to de-initialize the hardware. + * This is purely because of the shadow-attach model, where the DRM + * kernel driver does not really own the hardware. Instead ownershipe is + * handled with the help of userspace through an inheritedly racy dance + * to set/unset the VT into raw mode. * + * Legacy drivers initialize the hardware in the @firstopen callback, + * which isn't even called for modern drivers. */ - bool (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, - bool in_vblank_irq, int *vpos, int *hpos, - ktime_t *stime, ktime_t *etime, - const struct drm_display_mode *mode); + void (*lastclose) (struct drm_device *); /** - * Called by \c drm_get_last_vbltimestamp. Should return a precise - * timestamp when the most recent VBLANK interval ended or will end. + * @unload: * - * Specifically, the timestamp in @vblank_time should correspond as - * closely as possible to the time when the first video scanline of - * the video frame after the end of VBLANK will start scanning out, - * the time immediately after end of the VBLANK interval. If the - * @crtc is currently inside VBLANK, this will be a time in the future. - * If the @crtc is currently scanning out a frame, this will be the - * past start time of the current scanout. This is meant to adhere - * to the OpenML OML_sync_control extension specification. + * Reverse the effects of the driver load callback. Ideally, + * the clean up performed by the driver should happen in the + * reverse order of the initialization. Similarly to the load + * hook, this handler is deprecated and its usage should be + * dropped in favor of an open-coded teardown function at the + * driver layer. See drm_dev_unregister() and drm_dev_put() + * for the proper way to remove a &struct drm_device. * - * \param dev dev DRM device handle. - * \param pipe crtc for which timestamp should be returned. - * \param *max_error Maximum allowable timestamp error in nanoseconds. - * Implementation should strive to provide timestamp - * with an error of at most *max_error nanoseconds. - * Returns true upper bound on error for timestamp. - * \param *vblank_time Target location for returned vblank timestamp. - * \param flags 0 = Defaults, no special treatment needed. - * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank - * irq handler. Some drivers need to apply some workarounds - * for gpu-specific vblank irq quirks if flag is set. + * The unload() hook is called right after unregistering + * the device. * - * \returns - * Zero if timestamping isn't supported in current display mode or a - * negative number on failure. A positive status code on success, - * which describes how the vblank_time timestamp was computed. */ - bool (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe, - int *max_error, - ktime_t *vblank_time, - bool in_vblank_irq); + void (*unload) (struct drm_device *); /** - * Driver-specific constructor for drm_gem_objects, to set up - * obj->driver_private. + * @release: * - * Returns 0 on success. + * Optional callback for destroying device data after the final + * reference is released, i.e. the device is being destroyed. Drivers + * using this callback are responsible for calling drm_dev_fini() + * to finalize the device and then freeing the struct themselves. + */ + void (*release) (struct drm_device *); + + /** + * @irq_handler: + * + * Interrupt handler called when using drm_irq_install(). Not used by + * drivers which implement their own interrupt handling. + */ + irqreturn_t(*irq_handler) (int irq, void *arg); + + /** + * @irq_preinstall: + * + * Optional callback used by drm_irq_install() which is called before + * the interrupt handler is registered. This should be used to clear out + * any pending interrupts (from e.g. firmware based drives) and reset + * the interrupt handling registers. + */ + void (*irq_preinstall) (struct drm_device *dev); + + /** + * @irq_postinstall: + * + * Optional callback used by drm_irq_install() which is called after + * the interrupt handler is registered. This should be used to enable + * interrupt generation in the hardware. + */ + int (*irq_postinstall) (struct drm_device *dev); + + /** + * @irq_uninstall: + * + * Optional callback used by drm_irq_uninstall() which is called before + * the interrupt handler is unregistered. This should be used to disable + * interrupt generation in the hardware. + */ + void (*irq_uninstall) (struct drm_device *dev); + + /** + * @master_set: + * + * Called whenever the minor master is set. Only used by vmwgfx. + */ + int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, + bool from_open); + /** + * @master_drop: + * + * Called whenever the minor master is dropped. Only used by vmwgfx. + */ + void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv); + + /** + * @debugfs_init: + * + * Allows drivers to create driver-specific debugfs files. + */ + int (*debugfs_init)(struct drm_minor *minor); + + /** + * @gem_free_object: deconstructor for drm_gem_objects + * + * This is deprecated and should not be used by new drivers. Use + * &drm_gem_object_funcs.free instead. */ void (*gem_free_object) (struct drm_gem_object *obj); + + /** + * @gem_free_object_unlocked: deconstructor for drm_gem_objects + * + * This is deprecated and should not be used by new drivers. Use + * &drm_gem_object_funcs.free instead. + * Compared to @gem_free_object this is not encumbered with + * &drm_device.struct_mutex legacy locking schemes. + */ void (*gem_free_object_unlocked) (struct drm_gem_object *obj); + + /** + * @gem_open_object: + * + * This callback is deprecated in favour of &drm_gem_object_funcs.open. + * + * Driver hook called upon gem handle creation + */ int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); + + /** + * @gem_close_object: + * + * This callback is deprecated in favour of &drm_gem_object_funcs.close. + * + * Driver hook called upon gem handle release + */ void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); - void (*gem_print_info)(struct drm_printer *, unsigned int, - const struct drm_gem_object *); - int (*gem_fault)(struct drm_gem_object *, struct uvm_faultinfo *, - off_t, vaddr_t, vm_page_t *, int, int, vm_prot_t, int); + /** + * @gem_print_info: + * + * This callback is deprecated in favour of + * &drm_gem_object_funcs.print_info. + * + * If driver subclasses struct &drm_gem_object, it can implement this + * optional hook for printing additional driver specific info. + * + * drm_printf_indent() should be used in the callback passing it the + * indent argument. + * + * This callback is called from drm_gem_print_info(). + */ + void (*gem_print_info)(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj); - /* prime: */ - /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + /** + * @gem_create_object: constructor for gem objects + * + * Hook for allocating the GEM object struct, for use by the CMA and + * SHMEM GEM helpers. + */ + struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, + size_t size); + /** + * @prime_handle_to_fd: + * + * Main PRIME export function. Should be implemented with + * drm_gem_prime_handle_to_fd() for GEM based drivers. + * + * For an in-depth discussion see :ref:`PRIME buffer sharing + * documentation <prime_buffer_sharing>`. + */ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); - /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ + /** + * @prime_fd_to_handle: + * + * Main PRIME import function. Should be implemented with + * drm_gem_prime_fd_to_handle() for GEM based drivers. + * + * For an in-depth discussion see :ref:`PRIME buffer sharing + * documentation <prime_buffer_sharing>`. + */ int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle); - /* export GEM -> dmabuf */ - struct dma_buf * (*gem_prime_export)(struct drm_device *dev, - struct drm_gem_object *obj, int flags); - /* import dmabuf -> GEM */ + /** + * @gem_prime_export: + * + * Export hook for GEM drivers. Deprecated in favour of + * &drm_gem_object_funcs.export. + */ + struct dma_buf * (*gem_prime_export)(struct drm_gem_object *obj, + int flags); + /** + * @gem_prime_import: + * + * Import hook for GEM drivers. + * + * This defaults to drm_gem_prime_import() if not set. + */ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf); - struct reservation_object * (*gem_prime_res_obj)( - struct drm_gem_object *obj); - - int (*dumb_create)(struct drm_file *file_priv, - struct drm_device *dev, struct drm_mode_create_dumb *args); - int (*dumb_map_offset)(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, uint64_t *offset); - int (*dumb_destroy)(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle); - - size_t gem_size; - size_t buf_priv_size; - size_t file_priv_size; - - int major; - int minor; - int patchlevel; - const char *name; /* Simple driver name */ - const char *desc; /* Longer driver name */ - const char *date; /* Date of last major changes. */ + /** + * @gem_prime_pin: + * + * Deprecated hook in favour of &drm_gem_object_funcs.pin. + */ + int (*gem_prime_pin)(struct drm_gem_object *obj); + + /** + * @gem_prime_unpin: + * + * Deprecated hook in favour of &drm_gem_object_funcs.unpin. + */ + void (*gem_prime_unpin)(struct drm_gem_object *obj); + + + /** + * @gem_prime_get_sg_table: + * + * Deprecated hook in favour of &drm_gem_object_funcs.get_sg_table. + */ + struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj); + + /** + * @gem_prime_import_sg_table: + * + * Optional hook used by the PRIME helper functions + * drm_gem_prime_import() respectively drm_gem_prime_import_dev(). + */ + struct drm_gem_object *(*gem_prime_import_sg_table)( + struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt); + /** + * @gem_prime_vmap: + * + * Deprecated vmap hook for GEM drivers. Please use + * &drm_gem_object_funcs.vmap instead. + */ + void *(*gem_prime_vmap)(struct drm_gem_object *obj); + + /** + * @gem_prime_vunmap: + * + * Deprecated vunmap hook for GEM drivers. Please use + * &drm_gem_object_funcs.vunmap instead. + */ + void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr); + + /** + * @gem_prime_mmap: + * + * mmap hook for GEM drivers, used to implement dma-buf mmap in the + * PRIME helpers. + * + * FIXME: There's way too much duplication going on here, and also moved + * to &drm_gem_object_funcs. + */ +#ifdef __linux__ + int (*gem_prime_mmap)(struct drm_gem_object *obj, + struct vm_area_struct *vma); +#endif + +#ifdef __OpenBSD__ + struct uvm_object *(*mmap)(struct file *, vm_prot_t, voff_t, vsize_t); + size_t gem_size; + size_t buf_priv_size; + size_t file_priv_size; +#endif + + /** + * @dumb_create: + * + * This creates a new dumb buffer in the driver's backing storage manager (GEM, + * TTM or something else entirely) and returns the resulting buffer handle. This + * handle can then be wrapped up into a framebuffer modeset object. + * + * Note that userspace is not allowed to use such objects for render + * acceleration - drivers must create their own private ioctls for such a use + * case. + * + * Width, height and depth are specified in the &drm_mode_create_dumb + * argument. The callback needs to fill the handle, pitch and size for + * the created buffer. + * + * Called by the user via ioctl. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ + int (*dumb_create)(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + /** + * @dumb_map_offset: + * + * Allocate an offset in the drm device node's address space to be able to + * memory map a dumb buffer. + * + * The default implementation is drm_gem_create_mmap_offset(). GEM based + * drivers must not overwrite this. + * + * Called by the user via ioctl. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ + int (*dumb_map_offset)(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset); + /** + * @dumb_destroy: + * + * This destroys the userspace handle for the given dumb backing storage buffer. + * Since buffer objects must be reference counted in the kernel a buffer object + * won't be immediately freed if a framebuffer modeset object still uses it. + * + * Called by the user via ioctl. + * + * The default implementation is drm_gem_dumb_destroy(). GEM based drivers + * must not overwrite this. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ + int (*dumb_destroy)(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle); + + /** + * @gem_vm_ops: Driver private ops for this object + * + * For GEM drivers this is deprecated in favour of + * &drm_gem_object_funcs.vm_ops. + */ + const struct vm_operations_struct *gem_vm_ops; + +#ifdef __OpenBSD__ + int (*gem_fault)(struct drm_gem_object *, + struct uvm_faultinfo *, off_t, vaddr_t, + vm_page_t *, int, int, vm_prot_t, int); +#endif + + /** @major: driver major number */ + int major; + /** @minor: driver minor number */ + int minor; + /** @patchlevel: driver patch level */ + int patchlevel; + /** @name: driver name */ + char *name; + /** @desc: driver description */ + char *desc; + /** @date: driver date */ + char *date; + + /** + * @driver_features: + * Driver features, see &enum drm_driver_feature. Drivers can disable + * some features on a per-instance basis using + * &drm_device.driver_features. + */ u32 driver_features; + + /** + * @ioctls: + * + * Array of driver-private IOCTL description entries. See the chapter on + * :ref:`IOCTL support in the userland interfaces + * chapter<drm_driver_ioctl>` for the full details. + */ + const struct drm_ioctl_desc *ioctls; + /** @num_ioctls: Number of entries in @ioctls. */ int num_ioctls; + /** + * @fops: + * + * File operations for the DRM device node. See the discussion in + * :ref:`file operations<drm_driver_fops>` for in-depth coverage and + * some examples. + */ + const struct file_operations *fops; + + /* Everything below here is for legacy driver, never use! */ + /* private: */ + + /* List of devices hanging off this driver with stealth attach. */ + struct list_head legacy_dev_list; + int (*firstopen) (struct drm_device *); + void (*preclose) (struct drm_device *, struct drm_file *file_priv); + int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); + int (*dma_quiescent) (struct drm_device *); + int (*context_dtor) (struct drm_device *dev, int context); + u32 (*get_vblank_counter)(struct drm_device *dev, unsigned int pipe); + int (*enable_vblank)(struct drm_device *dev, unsigned int pipe); + void (*disable_vblank)(struct drm_device *dev, unsigned int pipe); + int dev_priv_size; }; -extern unsigned int drm_debug; +int drm_dev_init(struct drm_device *dev, + struct drm_driver *driver, + struct device *parent); +int devm_drm_dev_init(struct device *parent, + struct drm_device *dev, + struct drm_driver *driver); +void drm_dev_fini(struct drm_device *dev); + +struct drm_device *drm_dev_alloc(struct drm_driver *driver, + struct device *parent); +int drm_dev_register(struct drm_device *dev, unsigned long flags); +void drm_dev_unregister(struct drm_device *dev); + +void drm_dev_get(struct drm_device *dev); +void drm_dev_put(struct drm_device *dev); +void drm_put_dev(struct drm_device *dev); +bool drm_dev_enter(struct drm_device *dev, int *idx); +void drm_dev_exit(int idx); +void drm_dev_unplug(struct drm_device *dev); -static inline void -drm_dev_get(struct drm_device *dev) +/** + * drm_dev_is_unplugged - is a DRM device unplugged + * @dev: DRM device + * + * This function can be called to check whether a hotpluggable is unplugged. + * Unplugging itself is singalled through drm_dev_unplug(). If a device is + * unplugged, these two functions guarantee that any store before calling + * drm_dev_unplug() is visible to callers of this function after it completes + * + * WARNING: This function fundamentally races against drm_dev_unplug(). It is + * recommended that drivers instead use the underlying drm_dev_enter() and + * drm_dev_exit() function pairs. + */ +static inline bool drm_dev_is_unplugged(struct drm_device *dev) { + int idx; + + if (drm_dev_enter(dev, &idx)) { + drm_dev_exit(idx); + return false; + } + + return true; } -static inline void -drm_dev_put(struct drm_device *dev) +/** + * drm_core_check_all_features - check driver feature flags mask + * @dev: DRM device to check + * @features: feature flag(s) mask + * + * This checks @dev for driver features, see &drm_driver.driver_features, + * &drm_device.driver_features, and the various &enum drm_driver_feature flags. + * + * Returns true if all features in the @features mask are supported, false + * otherwise. + */ +static inline bool drm_core_check_all_features(const struct drm_device *dev, + u32 features) { + u32 supported = dev->driver->driver_features & dev->driver_features; + + return features && (supported & features) == features; } /** @@ -264,14 +700,15 @@ drm_dev_put(struct drm_device *dev) * @dev: DRM device to check * @feature: feature flag * - * This checks @dev for driver features, see &drm_driver.driver_features and the - * various DRIVER_\* flags. + * This checks @dev for driver features, see &drm_driver.driver_features, + * &drm_device.driver_features, and the various &enum drm_driver_feature flags. * * Returns true if the @feature is supported, false otherwise. */ -static inline bool drm_core_check_feature(struct drm_device *dev, int feature) +static inline bool drm_core_check_feature(const struct drm_device *dev, + enum drm_driver_feature feature) { - return dev->driver->driver_features & feature; + return drm_core_check_all_features(dev, feature); } /** @@ -288,10 +725,25 @@ static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) (dev->mode_config.funcs && dev->mode_config.funcs->atomic_commit != NULL); } -int drm_dev_register(struct drm_device *, unsigned long); -void drm_dev_unregister(struct drm_device *); -int drm_getpciinfo(struct drm_device *, void *, struct drm_file *); -const struct drm_pcidev *drm_find_description(int, int, - const struct drm_pcidev *); + +int drm_dev_set_unique(struct drm_device *dev, const char *name); + +struct drm_file *drm_find_file_by_minor(struct drm_device *, int); +struct drm_device *drm_get_device_from_kdev(dev_t); + +#ifdef __OpenBSD__ + +void drm_attach_platform(struct drm_driver *, bus_space_tag_t, bus_dma_tag_t, + struct device *, struct drm_device *); +struct drm_device *drm_attach_pci(struct drm_driver *, + struct pci_attach_args *, int, int, struct device *, struct drm_device *); + +int drm_pciprobe(struct pci_attach_args *, const struct pci_device_id * ); +const struct pci_device_id *drm_find_description(int, int, + const struct pci_device_id *); + +int drm_getpciinfo(struct drm_device *, void *, struct drm_file *); + +#endif #endif diff --git a/sys/dev/pci/drm/include/drm/drm_dsc.h b/sys/dev/pci/drm/include/drm/drm_dsc.h new file mode 100644 index 00000000000..887954cbfc6 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_dsc.h @@ -0,0 +1,609 @@ +/* SPDX-License-Identifier: MIT + * Copyright (C) 2018 Intel Corp. + * + * Authors: + * Manasi Navare <manasi.d.navare@intel.com> + */ + +#ifndef DRM_DSC_H_ +#define DRM_DSC_H_ + +#include <drm/drm_dp_helper.h> + +/* VESA Display Stream Compression DSC 1.2 constants */ +#define DSC_NUM_BUF_RANGES 15 +#define DSC_MUX_WORD_SIZE_8_10_BPC 48 +#define DSC_MUX_WORD_SIZE_12_BPC 64 +#define DSC_RC_PIXELS_PER_GROUP 3 +#define DSC_SCALE_DECREMENT_INTERVAL_MAX 4095 +#define DSC_RANGE_BPG_OFFSET_MASK 0x3f + +/* DSC Rate Control Constants */ +#define DSC_RC_MODEL_SIZE_CONST 8192 +#define DSC_RC_EDGE_FACTOR_CONST 6 +#define DSC_RC_TGT_OFFSET_HI_CONST 3 +#define DSC_RC_TGT_OFFSET_LO_CONST 3 + +/* DSC PPS constants and macros */ +#define DSC_PPS_VERSION_MAJOR_SHIFT 4 +#define DSC_PPS_BPC_SHIFT 4 +#define DSC_PPS_MSB_SHIFT 8 +#define DSC_PPS_LSB_MASK (0xFF << 0) +#define DSC_PPS_BPP_HIGH_MASK (0x3 << 8) +#define DSC_PPS_VBR_EN_SHIFT 2 +#define DSC_PPS_SIMPLE422_SHIFT 3 +#define DSC_PPS_CONVERT_RGB_SHIFT 4 +#define DSC_PPS_BLOCK_PRED_EN_SHIFT 5 +#define DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK (0x3 << 8) +#define DSC_PPS_SCALE_DEC_INT_HIGH_MASK (0xF << 8) +#define DSC_PPS_RC_TGT_OFFSET_HI_SHIFT 4 +#define DSC_PPS_RC_RANGE_MINQP_SHIFT 11 +#define DSC_PPS_RC_RANGE_MAXQP_SHIFT 6 +#define DSC_PPS_NATIVE_420_SHIFT 1 +#define DSC_1_2_MAX_LINEBUF_DEPTH_BITS 16 +#define DSC_1_2_MAX_LINEBUF_DEPTH_VAL 0 +#define DSC_1_1_MAX_LINEBUF_DEPTH_BITS 13 + +/** + * struct drm_dsc_rc_range_parameters - DSC Rate Control range parameters + * + * This defines different rate control parameters used by the DSC engine + * to compress the frame. + */ +struct drm_dsc_rc_range_parameters { + /** + * @range_min_qp: Min Quantization Parameters allowed for this range + */ + u8 range_min_qp; + /** + * @range_max_qp: Max Quantization Parameters allowed for this range + */ + u8 range_max_qp; + /** + * @range_bpg_offset: + * Bits/group offset to apply to target for this group + */ + u8 range_bpg_offset; +}; + +/** + * struct drm_dsc_config - Parameters required to configure DSC + * + * Driver populates this structure with all the parameters required + * to configure the display stream compression on the source. + */ +struct drm_dsc_config { + /** + * @line_buf_depth: + * Bits per component for previous reconstructed line buffer + */ + u8 line_buf_depth; + /** + * @bits_per_component: Bits per component to code (8/10/12) + */ + u8 bits_per_component; + /** + * @convert_rgb: + * Flag to indicate if RGB - YCoCg conversion is needed + * True if RGB input, False if YCoCg input + */ + bool convert_rgb; + /** + * @slice_count: Number fo slices per line used by the DSC encoder + */ + u8 slice_count; + /** + * @slice_width: Width of each slice in pixels + */ + u16 slice_width; + /** + * @slice_height: Slice height in pixels + */ + u16 slice_height; + /** + * @simple_422: True if simple 4_2_2 mode is enabled else False + */ + bool simple_422; + /** + * @pic_width: Width of the input display frame in pixels + */ + u16 pic_width; + /** + * @pic_height: Vertical height of the input display frame + */ + u16 pic_height; + /** + * @rc_tgt_offset_high: + * Offset to bits/group used by RC to determine QP adjustment + */ + u8 rc_tgt_offset_high; + /** + * @rc_tgt_offset_low: + * Offset to bits/group used by RC to determine QP adjustment + */ + u8 rc_tgt_offset_low; + /** + * @bits_per_pixel: + * Target bits per pixel with 4 fractional bits, bits_per_pixel << 4 + */ + u16 bits_per_pixel; + /** + * @rc_edge_factor: + * Factor to determine if an edge is present based on the bits produced + */ + u8 rc_edge_factor; + /** + * @rc_quant_incr_limit1: + * Slow down incrementing once the range reaches this value + */ + u8 rc_quant_incr_limit1; + /** + * @rc_quant_incr_limit0: + * Slow down incrementing once the range reaches this value + */ + u8 rc_quant_incr_limit0; + /** + * @initial_xmit_delay: + * Number of pixels to delay the initial transmission + */ + u16 initial_xmit_delay; + /** + * @initial_dec_delay: + * Initial decoder delay, number of pixel times that the decoder + * accumulates data in its rate buffer before starting to decode + * and output pixels. + */ + u16 initial_dec_delay; + /** + * @block_pred_enable: + * True if block prediction is used to code any groups within the + * picture. False if BP not used + */ + bool block_pred_enable; + /** + * @first_line_bpg_offset: + * Number of additional bits allocated for each group on the first + * line of slice. + */ + u8 first_line_bpg_offset; + /** + * @initial_offset: Value to use for RC model offset at slice start + */ + u16 initial_offset; + /** + * @rc_buf_thresh: Thresholds defining each of the buffer ranges + */ + u16 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1]; + /** + * @rc_range_params: + * Parameters for each of the RC ranges defined in + * &struct drm_dsc_rc_range_parameters + */ + struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES]; + /** + * @rc_model_size: Total size of RC model + */ + u16 rc_model_size; + /** + * @flatness_min_qp: Minimum QP where flatness information is sent + */ + u8 flatness_min_qp; + /** + * @flatness_max_qp: Maximum QP where flatness information is sent + */ + u8 flatness_max_qp; + /** + * @initial_scale_value: Initial value for the scale factor + */ + u8 initial_scale_value; + /** + * @scale_decrement_interval: + * Specifies number of group times between decrementing the scale factor + * at beginning of a slice. + */ + u16 scale_decrement_interval; + /** + * @scale_increment_interval: + * Number of group times between incrementing the scale factor value + * used at the beginning of a slice. + */ + u16 scale_increment_interval; + /** + * @nfl_bpg_offset: Non first line BPG offset to be used + */ + u16 nfl_bpg_offset; + /** + * @slice_bpg_offset: BPG offset used to enforce slice bit + */ + u16 slice_bpg_offset; + /** + * @final_offset: Final RC linear transformation offset value + */ + u16 final_offset; + /** + * @vbr_enable: True if VBR mode is enabled, false if disabled + */ + bool vbr_enable; + /** + * @mux_word_size: Mux word size (in bits) for SSM mode + */ + u8 mux_word_size; + /** + * @slice_chunk_size: + * The (max) size in bytes of the "chunks" that are used in slice + * multiplexing. + */ + u16 slice_chunk_size; + /** + * @rc_bits: Rate control buffer size in bits + */ + u16 rc_bits; + /** + * @dsc_version_minor: DSC minor version + */ + u8 dsc_version_minor; + /** + * @dsc_version_major: DSC major version + */ + u8 dsc_version_major; + /** + * @native_422: True if Native 4:2:2 supported, else false + */ + bool native_422; + /** + * @native_420: True if Native 4:2:0 supported else false. + */ + bool native_420; + /** + * @second_line_bpg_offset: + * Additional bits/grp for seconnd line of slice for native 4:2:0 + */ + u8 second_line_bpg_offset; + /** + * @nsl_bpg_offset: + * Num of bits deallocated for each grp that is not in second line of + * slice + */ + u16 nsl_bpg_offset; + /** + * @second_line_offset_adj: + * Offset adjustment for second line in Native 4:2:0 mode + */ + u16 second_line_offset_adj; +}; + +/** + * struct picture_parameter_set - Represents 128 bytes of Picture Parameter Set + * + * The VESA DSC standard defines picture parameter set (PPS) which display + * stream compression encoders must communicate to decoders. + * The PPS is encapsulated in 128 bytes (PPS 0 through PPS 127). The fields in + * this structure are as per Table 4.1 in Vesa DSC specification v1.1/v1.2. + * The PPS fields that span over more than a byte should be stored in Big Endian + * format. + */ +struct drm_dsc_picture_parameter_set { + /** + * @dsc_version: + * PPS0[3:0] - dsc_version_minor: Contains Minor version of DSC + * PPS0[7:4] - dsc_version_major: Contains major version of DSC + */ + u8 dsc_version; + /** + * @pps_identifier: + * PPS1[7:0] - Application specific identifier that can be + * used to differentiate between different PPS tables. + */ + u8 pps_identifier; + /** + * @pps_reserved: + * PPS2[7:0]- RESERVED Byte + */ + u8 pps_reserved; + /** + * @pps_3: + * PPS3[3:0] - linebuf_depth: Contains linebuffer bit depth used to + * generate the bitstream. (0x0 - 16 bits for DSC 1.2, 0x8 - 8 bits, + * 0xA - 10 bits, 0xB - 11 bits, 0xC - 12 bits, 0xD - 13 bits, + * 0xE - 14 bits for DSC1.2, 0xF - 14 bits for DSC 1.2. + * PPS3[7:4] - bits_per_component: Bits per component for the original + * pixels of the encoded picture. + * 0x0 = 16bpc (allowed only when dsc_version_minor = 0x2) + * 0x8 = 8bpc, 0xA = 10bpc, 0xC = 12bpc, 0xE = 14bpc (also + * allowed only when dsc_minor_version = 0x2) + */ + u8 pps_3; + /** + * @pps_4: + * PPS4[1:0] -These are the most significant 2 bits of + * compressed BPP bits_per_pixel[9:0] syntax element. + * PPS4[2] - vbr_enable: 0 = VBR disabled, 1 = VBR enabled + * PPS4[3] - simple_422: Indicates if decoder drops samples to + * reconstruct the 4:2:2 picture. + * PPS4[4] - Convert_rgb: Indicates if DSC color space conversion is + * active. + * PPS4[5] - blobk_pred_enable: Indicates if BP is used to code any + * groups in picture + * PPS4[7:6] - Reseved bits + */ + u8 pps_4; + /** + * @bits_per_pixel_low: + * PPS5[7:0] - This indicates the lower significant 8 bits of + * the compressed BPP bits_per_pixel[9:0] element. + */ + u8 bits_per_pixel_low; + /** + * @pic_height: + * PPS6[7:0], PPS7[7:0] -pic_height: Specifies the number of pixel rows + * within the raster. + */ + __be16 pic_height; + /** + * @pic_width: + * PPS8[7:0], PPS9[7:0] - pic_width: Number of pixel columns within + * the raster. + */ + __be16 pic_width; + /** + * @slice_height: + * PPS10[7:0], PPS11[7:0] - Slice height in units of pixels. + */ + __be16 slice_height; + /** + * @slice_width: + * PPS12[7:0], PPS13[7:0] - Slice width in terms of pixels. + */ + __be16 slice_width; + /** + * @chunk_size: + * PPS14[7:0], PPS15[7:0] - Size in units of bytes of the chunks + * that are used for slice multiplexing. + */ + __be16 chunk_size; + /** + * @initial_xmit_delay_high: + * PPS16[1:0] - Most Significant two bits of initial transmission delay. + * It specifies the number of pixel times that the encoder waits before + * transmitting data from its rate buffer. + * PPS16[7:2] - Reserved + */ + u8 initial_xmit_delay_high; + /** + * @initial_xmit_delay_low: + * PPS17[7:0] - Least significant 8 bits of initial transmission delay. + */ + u8 initial_xmit_delay_low; + /** + * @initial_dec_delay: + * + * PPS18[7:0], PPS19[7:0] - Initial decoding delay which is the number + * of pixel times that the decoder accumulates data in its rate buffer + * before starting to decode and output pixels. + */ + __be16 initial_dec_delay; + /** + * @pps20_reserved: + * + * PPS20[7:0] - Reserved + */ + u8 pps20_reserved; + /** + * @initial_scale_value: + * PPS21[5:0] - Initial rcXformScale factor used at beginning + * of a slice. + * PPS21[7:6] - Reserved + */ + u8 initial_scale_value; + /** + * @scale_increment_interval: + * PPS22[7:0], PPS23[7:0] - Number of group times between incrementing + * the rcXformScale factor at end of a slice. + */ + __be16 scale_increment_interval; + /** + * @scale_decrement_interval_high: + * PPS24[3:0] - Higher 4 bits indicating number of group times between + * decrementing the rcXformScale factor at beginning of a slice. + * PPS24[7:4] - Reserved + */ + u8 scale_decrement_interval_high; + /** + * @scale_decrement_interval_low: + * PPS25[7:0] - Lower 8 bits of scale decrement interval + */ + u8 scale_decrement_interval_low; + /** + * @pps26_reserved: + * PPS26[7:0] + */ + u8 pps26_reserved; + /** + * @first_line_bpg_offset: + * PPS27[4:0] - Number of additional bits that are allocated + * for each group on first line of a slice. + * PPS27[7:5] - Reserved + */ + u8 first_line_bpg_offset; + /** + * @nfl_bpg_offset: + * PPS28[7:0], PPS29[7:0] - Number of bits including frac bits + * deallocated for each group for groups after the first line of slice. + */ + __be16 nfl_bpg_offset; + /** + * @slice_bpg_offset: + * PPS30, PPS31[7:0] - Number of bits that are deallocated for each + * group to enforce the slice constraint. + */ + __be16 slice_bpg_offset; + /** + * @initial_offset: + * PPS32,33[7:0] - Initial value for rcXformOffset + */ + __be16 initial_offset; + /** + * @final_offset: + * PPS34,35[7:0] - Maximum end-of-slice value for rcXformOffset + */ + __be16 final_offset; + /** + * @flatness_min_qp: + * PPS36[4:0] - Minimum QP at which flatness is signaled and + * flatness QP adjustment is made. + * PPS36[7:5] - Reserved + */ + u8 flatness_min_qp; + /** + * @flatness_max_qp: + * PPS37[4:0] - Max QP at which flatness is signalled and + * the flatness adjustment is made. + * PPS37[7:5] - Reserved + */ + u8 flatness_max_qp; + /** + * @rc_model_size: + * PPS38,39[7:0] - Number of bits within RC Model. + */ + __be16 rc_model_size; + /** + * @rc_edge_factor: + * PPS40[3:0] - Ratio of current activity vs, previous + * activity to determine presence of edge. + * PPS40[7:4] - Reserved + */ + u8 rc_edge_factor; + /** + * @rc_quant_incr_limit0: + * PPS41[4:0] - QP threshold used in short term RC + * PPS41[7:5] - Reserved + */ + u8 rc_quant_incr_limit0; + /** + * @rc_quant_incr_limit1: + * PPS42[4:0] - QP threshold used in short term RC + * PPS42[7:5] - Reserved + */ + u8 rc_quant_incr_limit1; + /** + * @rc_tgt_offset: + * PPS43[3:0] - Lower end of the variability range around the target + * bits per group that is allowed by short term RC. + * PPS43[7:4]- Upper end of the variability range around the target + * bits per group that i allowed by short term rc. + */ + u8 rc_tgt_offset; + /** + * @rc_buf_thresh: + * PPS44[7:0] - PPS57[7:0] - Specifies the thresholds in RC model for + * the 15 ranges defined by 14 thresholds. + */ + u8 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1]; + /** + * @rc_range_parameters: + * PPS58[7:0] - PPS87[7:0] + * Parameters that correspond to each of the 15 ranges. + */ + __be16 rc_range_parameters[DSC_NUM_BUF_RANGES]; + /** + * @native_422_420: + * PPS88[0] - 0 = Native 4:2:2 not used + * 1 = Native 4:2:2 used + * PPS88[1] - 0 = Native 4:2:0 not use + * 1 = Native 4:2:0 used + * PPS88[7:2] - Reserved 6 bits + */ + u8 native_422_420; + /** + * @second_line_bpg_offset: + * PPS89[4:0] - Additional bits/group budget for the + * second line of a slice in Native 4:2:0 mode. + * Set to 0 if DSC minor version is 1 or native420 is 0. + * PPS89[7:5] - Reserved + */ + u8 second_line_bpg_offset; + /** + * @nsl_bpg_offset: + * PPS90[7:0], PPS91[7:0] - Number of bits that are deallocated + * for each group that is not in the second line of a slice. + */ + __be16 nsl_bpg_offset; + /** + * @second_line_offset_adj: + * PPS92[7:0], PPS93[7:0] - Used as offset adjustment for the second + * line in Native 4:2:0 mode. + */ + __be16 second_line_offset_adj; + /** + * @pps_long_94_reserved: + * PPS 94, 95, 96, 97 - Reserved + */ + u32 pps_long_94_reserved; + /** + * @pps_long_98_reserved: + * PPS 98, 99, 100, 101 - Reserved + */ + u32 pps_long_98_reserved; + /** + * @pps_long_102_reserved: + * PPS 102, 103, 104, 105 - Reserved + */ + u32 pps_long_102_reserved; + /** + * @pps_long_106_reserved: + * PPS 106, 107, 108, 109 - reserved + */ + u32 pps_long_106_reserved; + /** + * @pps_long_110_reserved: + * PPS 110, 111, 112, 113 - reserved + */ + u32 pps_long_110_reserved; + /** + * @pps_long_114_reserved: + * PPS 114 - 117 - reserved + */ + u32 pps_long_114_reserved; + /** + * @pps_long_118_reserved: + * PPS 118 - 121 - reserved + */ + u32 pps_long_118_reserved; + /** + * @pps_long_122_reserved: + * PPS 122- 125 - reserved + */ + u32 pps_long_122_reserved; + /** + * @pps_short_126_reserved: + * PPS 126, 127 - reserved + */ + __be16 pps_short_126_reserved; +} __packed; + +/** + * struct drm_dsc_pps_infoframe - DSC infoframe carrying the Picture Parameter + * Set Metadata + * + * This structure represents the DSC PPS infoframe required to send the Picture + * Parameter Set metadata required before enabling VESA Display Stream + * Compression. This is based on the DP Secondary Data Packet structure and + * comprises of SDP Header as defined &struct struct dp_sdp_header in drm_dp_helper.h + * and PPS payload defined in &struct drm_dsc_picture_parameter_set. + * + * @pps_header: Header for PPS as per DP SDP header format of type + * &struct dp_sdp_header + * @pps_payload: PPS payload fields as per DSC specification Table 4-1 + * as represented in &struct drm_dsc_picture_parameter_set + */ +struct drm_dsc_pps_infoframe { + struct dp_sdp_header pps_header; + struct drm_dsc_picture_parameter_set pps_payload; +} __packed; + +void drm_dsc_dp_pps_header_init(struct dp_sdp_header *pps_header); +void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_sdp, + const struct drm_dsc_config *dsc_cfg); +int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg); + +#endif /* _DRM_DSC_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_edid.h b/sys/dev/pci/drm/include/drm/drm_edid.h index 269249b7f09..34b15e3d070 100644 --- a/sys/dev/pci/drm/include/drm/drm_edid.h +++ b/sys/dev/pci/drm/include/drm/drm_edid.h @@ -25,6 +25,10 @@ #include <linux/types.h> #include <linux/hdmi.h> +#include <drm/drm_mode.h> + +struct drm_device; +struct i2c_adapter; #define EDID_LENGTH 128 #define DDC_ADDR 0x50 @@ -87,6 +91,11 @@ struct detailed_data_string { u8 str[13]; } __attribute__((packed)); +#define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 +#define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 +#define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 +#define DRM_EDID_CVT_SUPPORT_FLAG 0x04 + struct detailed_data_monitor_range { u8 min_vfreq; u8 max_vfreq; @@ -173,21 +182,23 @@ struct detailed_timing { #define DRM_EDID_INPUT_BLANK_TO_BLACK (1 << 4) #define DRM_EDID_INPUT_VIDEO_LEVEL (3 << 5) #define DRM_EDID_INPUT_DIGITAL (1 << 7) -#define DRM_EDID_DIGITAL_DEPTH_MASK (7 << 4) -#define DRM_EDID_DIGITAL_DEPTH_UNDEF (0 << 4) -#define DRM_EDID_DIGITAL_DEPTH_6 (1 << 4) -#define DRM_EDID_DIGITAL_DEPTH_8 (2 << 4) -#define DRM_EDID_DIGITAL_DEPTH_10 (3 << 4) -#define DRM_EDID_DIGITAL_DEPTH_12 (4 << 4) -#define DRM_EDID_DIGITAL_DEPTH_14 (5 << 4) -#define DRM_EDID_DIGITAL_DEPTH_16 (6 << 4) -#define DRM_EDID_DIGITAL_DEPTH_RSVD (7 << 4) -#define DRM_EDID_DIGITAL_TYPE_UNDEF (0) -#define DRM_EDID_DIGITAL_TYPE_DVI (1) -#define DRM_EDID_DIGITAL_TYPE_HDMI_A (2) -#define DRM_EDID_DIGITAL_TYPE_HDMI_B (3) -#define DRM_EDID_DIGITAL_TYPE_MDDI (4) -#define DRM_EDID_DIGITAL_TYPE_DP (5) +#define DRM_EDID_DIGITAL_DEPTH_MASK (7 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_UNDEF (0 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_6 (1 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_8 (2 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_10 (3 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_12 (4 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_14 (5 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_16 (6 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_DEPTH_RSVD (7 << 4) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_MASK (7 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_UNDEF (0 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_DVI (1 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_HDMI_A (2 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_HDMI_B (3 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_MDDI (4 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_TYPE_DP (5 << 0) /* 1.4 */ +#define DRM_EDID_DIGITAL_DFP_1_X (1 << 0) /* 1.3 */ #define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) @@ -328,6 +339,7 @@ struct cea_sad { struct drm_encoder; struct drm_connector; +struct drm_connector_state; struct drm_display_mode; int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); @@ -349,18 +361,30 @@ drm_load_edid_firmware(struct drm_connector *connector) int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, - const struct drm_display_mode *mode, - bool is_hdmi2_sink); + struct drm_connector *connector, + const struct drm_display_mode *mode); int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, struct drm_connector *connector, const struct drm_display_mode *mode); + +void +drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); + +void +drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); + void drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, + struct drm_connector *connector, const struct drm_display_mode *mode, - enum hdmi_quantization_range rgb_quant_range, - bool rgb_quant_range_selectable, - bool is_hdmi2_sink); + enum hdmi_quantization_range rgb_quant_range); + +int +drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, + const struct drm_connector_state *conn_state); /** * drm_eld_mnl - Get ELD monitor name length in bytes. @@ -466,10 +490,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); int drm_add_override_edid_modes(struct drm_connector *connector); u8 drm_match_cea_mode(const struct drm_display_mode *to_match); -enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code); bool drm_detect_hdmi_monitor(struct edid *edid); bool drm_detect_monitor_audio(struct edid *edid); -bool drm_rgb_quant_range_selectable(struct edid *edid); enum hdmi_quantization_range drm_default_rgb_quant_range(const struct drm_display_mode *mode); int drm_add_modes_noedid(struct drm_connector *connector, diff --git a/sys/dev/pci/drm/include/drm/drm_encoder.h b/sys/dev/pci/drm/include/drm/drm_encoder.h index 4f597c0730b..4370e039c01 100644 --- a/sys/dev/pci/drm/include/drm/drm_encoder.h +++ b/sys/dev/pci/drm/include/drm/drm_encoder.h @@ -28,6 +28,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_mode.h> #include <drm/drm_mode_object.h> +#include <drm/drm_util.h> struct drm_encoder; @@ -139,7 +140,7 @@ struct drm_encoder { * @possible_crtcs: Bitmask of potential CRTC bindings, using * drm_crtc_index() as the index into the bitfield. The driver must set * the bits for all &drm_crtc objects this encoder can be connected to - * before calling drm_encoder_init(). + * before calling drm_dev_register(). * * In reality almost every driver gets this wrong. * @@ -153,7 +154,7 @@ struct drm_encoder { * using drm_encoder_index() as the index into the bitfield. The driver * must set the bits for all &drm_encoder objects which can clone a * &drm_crtc together with this encoder before calling - * drm_encoder_init(). Drivers should set the bit representing the + * drm_dev_register(). Drivers should set the bit representing the * encoder itself, too. Cloning bits should be set such that when two * encoders can be used in a cloned configuration, they both should have * each another bits set. @@ -171,7 +172,13 @@ struct drm_encoder { * &drm_connector_state.crtc. */ struct drm_crtc *crtc; - struct drm_bridge *bridge; + + /** + * @bridge_chain: Bridges attached to this encoder. Drivers shall not + * access this field directly. + */ + struct list_head bridge_chain; + const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; }; @@ -197,7 +204,7 @@ static inline unsigned int drm_encoder_index(const struct drm_encoder *encoder) } /** - * drm_encoder_mask - find the mask of a registered ENCODER + * drm_encoder_mask - find the mask of a registered encoder * @encoder: encoder to find mask for * * Given a registered encoder, return the mask bit of that encoder for an diff --git a/sys/dev/pci/drm/include/drm/drm_encoder_slave.h b/sys/dev/pci/drm/include/drm/drm_encoder_slave.h new file mode 100644 index 00000000000..b2f01c11f8e --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_encoder_slave.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __DRM_ENCODER_SLAVE_H__ +#define __DRM_ENCODER_SLAVE_H__ + +#include <drm/drm_crtc.h> +#include <drm/drm_encoder.h> + +/** + * struct drm_encoder_slave_funcs - Entry points exposed by a slave encoder driver + * @set_config: Initialize any encoder-specific modesetting parameters. + * The meaning of the @params parameter is implementation + * dependent. It will usually be a structure with DVO port + * data format settings or timings. It's not required for + * the new parameters to take effect until the next mode + * is set. + * + * Most of its members are analogous to the function pointers in + * &drm_encoder_helper_funcs and they can optionally be used to + * initialize the latter. Connector-like methods (e.g. @get_modes and + * @set_property) will typically be wrapped around and only be called + * if the encoder is the currently selected one for the connector. + */ +struct drm_encoder_slave_funcs { + void (*set_config)(struct drm_encoder *encoder, + void *params); + + void (*destroy)(struct drm_encoder *encoder); + void (*dpms)(struct drm_encoder *encoder, int mode); + void (*save)(struct drm_encoder *encoder); + void (*restore)(struct drm_encoder *encoder); + bool (*mode_fixup)(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + int (*mode_valid)(struct drm_encoder *encoder, + struct drm_display_mode *mode); + void (*mode_set)(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + enum drm_connector_status (*detect)(struct drm_encoder *encoder, + struct drm_connector *connector); + int (*get_modes)(struct drm_encoder *encoder, + struct drm_connector *connector); + int (*create_resources)(struct drm_encoder *encoder, + struct drm_connector *connector); + int (*set_property)(struct drm_encoder *encoder, + struct drm_connector *connector, + struct drm_property *property, + uint64_t val); + +}; + +/** + * struct drm_encoder_slave - Slave encoder struct + * @base: DRM encoder object. + * @slave_funcs: Slave encoder callbacks. + * @slave_priv: Slave encoder private data. + * @bus_priv: Bus specific data. + * + * A &drm_encoder_slave has two sets of callbacks, @slave_funcs and the + * ones in @base. The former are never actually called by the common + * CRTC code, it's just a convenience for splitting the encoder + * functions in an upper, GPU-specific layer and a (hopefully) + * GPU-agnostic lower layer: It's the GPU driver responsibility to + * call the slave methods when appropriate. + * + * drm_i2c_encoder_init() provides a way to get an implementation of + * this. + */ +struct drm_encoder_slave { + struct drm_encoder base; + + const struct drm_encoder_slave_funcs *slave_funcs; + void *slave_priv; + void *bus_priv; +}; +#define to_encoder_slave(x) container_of((x), struct drm_encoder_slave, base) + +#ifdef notyet +int drm_i2c_encoder_init(struct drm_device *dev, + struct drm_encoder_slave *encoder, + struct i2c_adapter *adap, + const struct i2c_board_info *info); +#endif + +/** + * struct drm_i2c_encoder_driver + * + * Describes a device driver for an encoder connected to the GPU + * through an I2C bus. In addition to the entry points in @i2c_driver + * an @encoder_init function should be provided. It will be called to + * give the driver an opportunity to allocate any per-encoder data + * structures and to initialize the @slave_funcs and (optionally) + * @slave_priv members of @encoder. + */ +struct drm_i2c_encoder_driver { +#ifdef notyet + struct i2c_driver i2c_driver; + + int (*encoder_init)(struct i2c_client *client, + struct drm_device *dev, + struct drm_encoder_slave *encoder); +#endif + +}; +#define to_drm_i2c_encoder_driver(x) container_of((x), \ + struct drm_i2c_encoder_driver, \ + i2c_driver) + +/** + * drm_i2c_encoder_get_client - Get the I2C client corresponding to an encoder + */ +static inline struct i2c_client *drm_i2c_encoder_get_client(struct drm_encoder *encoder) +{ + return (struct i2c_client *)to_encoder_slave(encoder)->bus_priv; +} + +/** + * drm_i2c_encoder_register - Register an I2C encoder driver + * @owner: Module containing the driver. + * @driver: Driver to be registered. + */ +static inline int drm_i2c_encoder_register(struct module *owner, + struct drm_i2c_encoder_driver *driver) +{ + STUB(); + return -ENOSYS; +#ifdef notyet + return i2c_register_driver(owner, &driver->i2c_driver); +#endif +} + +/** + * drm_i2c_encoder_unregister - Unregister an I2C encoder driver + * @driver: Driver to be unregistered. + */ +static inline void drm_i2c_encoder_unregister(struct drm_i2c_encoder_driver *driver) +{ + STUB(); +#ifdef notyet + i2c_del_driver(&driver->i2c_driver); +#endif +} + +void drm_i2c_encoder_destroy(struct drm_encoder *encoder); + + +/* + * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: + */ + +void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode); +bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void drm_i2c_encoder_prepare(struct drm_encoder *encoder); +void drm_i2c_encoder_commit(struct drm_encoder *encoder); +void drm_i2c_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector); +void drm_i2c_encoder_save(struct drm_encoder *encoder); +void drm_i2c_encoder_restore(struct drm_encoder *encoder); + + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_fb_helper.h b/sys/dev/pci/drm/include/drm/drm_fb_helper.h index 51e82c7372d..cc41a73707a 100644 --- a/sys/dev/pci/drm/include/drm/drm_fb_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_fb_helper.h @@ -32,29 +32,17 @@ struct drm_fb_helper; -#ifdef notyet #include <drm/drm_client.h> -#endif #include <drm/drm_crtc.h> #include <drm/drm_device.h> #include <linux/kgdb.h> +#include <linux/vgaarb.h> enum mode_set_atomic { LEAVE_ATOMIC_MODE_SET, ENTER_ATOMIC_MODE_SET, }; -struct drm_fb_offset { - int x, y; -}; - -struct drm_fb_helper_crtc { - struct drm_mode_set mode_set; - struct drm_display_mode *desired_mode; - int x, y; - int rotation; -}; - /** * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size * @fb_width: fbdev width @@ -69,10 +57,8 @@ struct drm_fb_helper_crtc { * according to the largest width/height (so it is large enough for all CRTCs * to scanout). But the fbdev width/height is sized to the minimum width/ * height of all the displays. This ensures that fbcon fits on the smallest - * of the attached displays. - * - * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height, - * rather than the surface size. + * of the attached displays. fb_width/fb_height is used by + * drm_fb_helper_fill_info() to fill out the &fb_info.var structure. */ struct drm_fb_helper_surface_size { u32 fb_width; @@ -105,43 +91,12 @@ struct drm_fb_helper_funcs { */ int (*fb_probe)(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); - - /** - * @initial_config: - * - * Driver callback to setup an initial fbdev display configuration. - * Drivers can use this callback to tell the fbdev emulation what the - * preferred initial configuration is. This is useful to implement - * smooth booting where the fbdev (and subsequently all userspace) never - * changes the mode, but always inherits the existing configuration. - * - * This callback is optional. - * - * RETURNS: - * - * The driver should return true if a suitable initial configuration has - * been filled out and false when the fbdev helper should fall back to - * the default probing logic. - */ - bool (*initial_config)(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_crtc **crtcs, - struct drm_display_mode **modes, - struct drm_fb_offset *offsets, - bool *enabled, int width, int height); -}; - -struct drm_fb_helper_connector { - struct drm_connector *connector; }; /** * struct drm_fb_helper - main structure to emulate fbdev on top of KMS * @fb: Scanout framebuffer object * @dev: DRM device - * @crtc_count: number of possible CRTCs - * @crtc_info: per-CRTC helper state (mode, x/y offset, etc) - * @connector_count: number of connected connectors - * @connector_info_alloc_count: size of connector_info * @funcs: driver callbacks for fb helper * @fbdev: emulated fbdev device info struct * @pseudo_palette: fake palette of 16 colors @@ -162,9 +117,7 @@ struct drm_fb_helper { * * DRM client used by the generic fbdev emulation. */ -#ifdef notyet struct drm_client_dev client; -#endif /** * @buffer: @@ -175,24 +128,6 @@ struct drm_fb_helper { struct drm_framebuffer *fb; struct drm_device *dev; - int crtc_count; - struct drm_fb_helper_crtc *crtc_info; - int connector_count; - int connector_info_alloc_count; - /** - * @sw_rotations: - * Bitmask of all rotations requested for panel-orientation which - * could not be handled in hardware. If only one bit is set - * fbdev->fbcon_rotate_hint gets set to the requested rotation. - */ - int sw_rotations; - /** - * @connector_info: - * - * Array of per-connector information. Do not iterate directly, but use - * drm_fb_helper_for_each_connector. - */ - struct drm_fb_helper_connector **connector_info; const struct drm_fb_helper_funcs *funcs; struct fb_info *fbdev; u32 pseudo_palette[17]; @@ -253,13 +188,11 @@ struct drm_fb_helper { int preferred_bpp; }; -#ifdef notyet static inline struct drm_fb_helper * drm_fb_helper_from_client(struct drm_client_dev *client) { return container_of(client, struct drm_fb_helper, client); } -#endif /** * define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers @@ -280,8 +213,7 @@ drm_fb_helper_from_client(struct drm_client_dev *client) #ifdef CONFIG_DRM_FBDEV_EMULATION void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, const struct drm_fb_helper_funcs *funcs); -int drm_fb_helper_init(struct drm_device *dev, - struct drm_fb_helper *helper, int max_conn); +int drm_fb_helper_init(struct drm_device *dev, struct drm_fb_helper *helper); void drm_fb_helper_fini(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, @@ -294,16 +226,12 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper); struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper); void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper); -void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, - uint32_t fb_width, uint32_t fb_height); -void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, - uint32_t depth); - -void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); +void drm_fb_helper_fill_info(struct fb_info *info, + struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes); void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist); -int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper); ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); @@ -335,31 +263,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); -int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); int drm_fb_helper_debug_enter(struct fb_info *info); int drm_fb_helper_debug_leave(struct fb_info *info); -struct drm_display_mode * -drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, - int width, int height); -struct drm_display_mode * -drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn); - -int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); -int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, - struct drm_connector *connector); - -int drm_fb_helper_fbdev_setup(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - const struct drm_fb_helper_funcs *funcs, - unsigned int preferred_bpp, - unsigned int max_conn_count); -void drm_fb_helper_fbdev_teardown(struct drm_device *dev); void drm_fb_helper_lastclose(struct drm_device *dev); void drm_fb_helper_output_poll_changed(struct drm_device *dev); -int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_surface_size *sizes); int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp); #else static inline void drm_fb_helper_prepare(struct drm_device *dev, @@ -369,8 +278,7 @@ static inline void drm_fb_helper_prepare(struct drm_device *dev, } static inline int drm_fb_helper_init(struct drm_device *dev, - struct drm_fb_helper *helper, - int max_conn) + struct drm_fb_helper *helper) { /* So drivers can use it to free the struct */ helper->dev = dev; @@ -423,14 +331,10 @@ static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper) { } -static inline void drm_fb_helper_fill_var(struct fb_info *info, - struct drm_fb_helper *fb_helper, - uint32_t fb_width, uint32_t fb_height) -{ -} - -static inline void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, - uint32_t depth) +static inline void +drm_fb_helper_fill_info(struct fb_info *info, + struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) { } @@ -446,10 +350,6 @@ static inline int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, return 0; } -static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) -{ -} - static inline void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist) { @@ -525,12 +425,6 @@ static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, return 0; } -static inline int -drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) -{ - return 0; -} - static inline int drm_fb_helper_debug_enter(struct fb_info *info) { return 0; @@ -541,52 +435,6 @@ static inline int drm_fb_helper_debug_leave(struct fb_info *info) return 0; } -static inline struct drm_display_mode * -drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, - int width, int height) -{ - return NULL; -} - -static inline struct drm_display_mode * -drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, - int width, int height) -{ - return NULL; -} - -static inline int -drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, - struct drm_connector *connector) -{ - return 0; -} - -static inline int -drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, - struct drm_connector *connector) -{ - return 0; -} - -static inline int -drm_fb_helper_fbdev_setup(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - const struct drm_fb_helper_funcs *funcs, - unsigned int preferred_bpp, - unsigned int max_conn_count) -{ - /* So drivers can use it to free the struct */ - dev->fb_helper = fb_helper; - - return 0; -} - -static inline void drm_fb_helper_fbdev_teardown(struct drm_device *dev) -{ - dev->fb_helper = NULL; -} - static inline void drm_fb_helper_lastclose(struct drm_device *dev) { } @@ -596,13 +444,6 @@ static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev) } static inline int -drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_surface_size *sizes) -{ - return 0; -} - -static inline int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) { return 0; @@ -610,7 +451,16 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) #endif -#ifdef __linux__ +/** + * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers + * @a: memory range, users of which are to be removed + * @name: requesting driver name + * @primary: also kick vga16fb if present + * + * This function removes framebuffer devices (initialized by firmware/bootloader) + * which use memory range described by @a. If @a is NULL all such devices are + * removed. + */ static inline int drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) @@ -621,6 +471,34 @@ drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a, return 0; #endif } -#endif /* __linux__ */ + +/** + * drm_fb_helper_remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices + * @pdev: PCI device + * @name: requesting driver name + * + * This function removes framebuffer devices (eg. initialized by firmware) + * using memory range configured for any of @pdev's memory bars. + * + * The function assumes that PCI device with shadowed ROM drives a primary + * display and so kicks out vga16fb. + */ +static inline int +drm_fb_helper_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, + const char *name) +{ + int ret = 0; + + /* + * WARNING: Apparently we must kick fbdev drivers before vgacon, + * otherwise the vga fbdev driver falls over. + */ +#if IS_REACHABLE(CONFIG_FB) + ret = remove_conflicting_pci_framebuffers(pdev, name); +#endif + if (ret == 0) + ret = vga_remove_vgacon(pdev); + return ret; +} #endif diff --git a/sys/dev/pci/drm/include/drm/drm_file.h b/sys/dev/pci/drm/include/drm/drm_file.h index a2914170635..14017314421 100644 --- a/sys/dev/pci/drm/include/drm/drm_file.h +++ b/sys/dev/pci/drm/include/drm/drm_file.h @@ -30,18 +30,21 @@ #ifndef _DRM_FILE_H_ #define _DRM_FILE_H_ -#include <sys/selinfo.h> #include <linux/types.h> #include <linux/completion.h> +#include <linux/idr.h> #include <uapi/drm/drm.h> #include <drm/drm_prime.h> +#include <sys/selinfo.h> + struct dma_fence; struct drm_file; struct drm_device; struct device; +struct file; /* * FIXME: Not sure we want to have drm_minor here in the end, but to avoid @@ -70,7 +73,9 @@ struct drm_minor { /* private: */ int index; /* Minor device number */ int type; /* Control or render */ +#ifdef __linux__ struct device *kdev; /* Linux device */ +#endif struct drm_device *dev; struct dentry *debugfs_root; @@ -165,14 +170,14 @@ struct drm_file { * See also the :ref:`section on primary nodes and authentication * <drm_primary_node>`. */ - unsigned authenticated :1; + bool authenticated; /** * @stereo_allowed: * * True when the client has asked us to expose stereo 3D mode flags. */ - unsigned stereo_allowed :1; + bool stereo_allowed; /** * @universal_planes: @@ -180,10 +185,10 @@ struct drm_file { * True if client understands CRTC primary planes and cursor planes * in the plane list. Automatically set when @atomic is set. */ - unsigned universal_planes:1; + bool universal_planes; /** @atomic: True if client understands atomic properties. */ - unsigned atomic:1; + bool atomic; /** * @aspect_ratio_allowed: @@ -191,14 +196,14 @@ struct drm_file { * True, if client can handle picture aspect ratios, and has requested * to pass this information along with the mode. */ - unsigned aspect_ratio_allowed:1; + bool aspect_ratio_allowed; /** * @writeback_connectors: * * True if client understands writeback connectors */ - unsigned writeback_connectors:1; + bool writeback_connectors; /** * @is_master: @@ -209,7 +214,7 @@ struct drm_file { * See also the :ref:`section on primary nodes and authentication * <drm_primary_node>`. */ - unsigned is_master:1; + bool is_master; /** * @master: @@ -238,12 +243,9 @@ struct drm_file { struct list_head lhead; /** @minor: &struct drm_minor for this file. */ -#ifdef notyet struct drm_minor *minor; -#else - int minor; - int minor_type; -#endif + + int fminor; /** * @object_idr: @@ -340,7 +342,9 @@ struct drm_file { struct drm_prime_file_private prime; /* private: */ +#if IS_ENABLED(CONFIG_DRM_LEGACY) unsigned long lock_count; /* DRI1 legacy lock count */ +#endif struct selinfo rsel; SPLAY_ENTRY(drm_file) link; @@ -358,11 +362,7 @@ struct drm_file { */ static inline bool drm_is_primary_client(const struct drm_file *file_priv) { -#ifdef __linux__ return file_priv->minor->type == DRM_MINOR_PRIMARY; -#else - return file_priv->minor_type == DRM_MINOR_PRIMARY; -#endif } /** @@ -376,11 +376,7 @@ static inline bool drm_is_primary_client(const struct drm_file *file_priv) */ static inline bool drm_is_render_client(const struct drm_file *file_priv) { -#ifdef __linux__ return file_priv->minor->type == DRM_MINOR_RENDER; -#else - return file_priv->minor_type == DRM_MINOR_RENDER; -#endif } #ifdef __linux__ @@ -388,6 +384,7 @@ int drm_open(struct inode *inode, struct file *filp); ssize_t drm_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset); int drm_release(struct inode *inode, struct file *filp); +int drm_release_noglobal(struct inode *inode, struct file *filp); __poll_t drm_poll(struct file *filp, struct poll_table_struct *wait); #endif int drm_event_reserve_init_locked(struct drm_device *dev, @@ -403,4 +400,15 @@ void drm_event_cancel_free(struct drm_device *dev, void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e); void drm_send_event(struct drm_device *dev, struct drm_pending_event *e); +struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags); + +#ifdef CONFIG_MMU +struct drm_vma_offset_manager; +unsigned long drm_get_unmapped_area(struct file *file, + unsigned long uaddr, unsigned long len, + unsigned long pgoff, unsigned long flags, + struct drm_vma_offset_manager *mgr); +#endif /* CONFIG_MMU */ + + #endif /* _DRM_FILE_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_flip_work.h b/sys/dev/pci/drm/include/drm/drm_flip_work.h new file mode 100644 index 00000000000..21c3d512d25 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_flip_work.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DRM_FLIP_WORK_H +#define DRM_FLIP_WORK_H + +#include <linux/kfifo.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> + +/** + * DOC: flip utils + * + * Util to queue up work to run from work-queue context after flip/vblank. + * Typically this can be used to defer unref of framebuffer's, cursor + * bo's, etc until after vblank. The APIs are all thread-safe. + * Moreover, drm_flip_work_queue_task and drm_flip_work_queue can be called + * in atomic context. + */ + +struct drm_flip_work; + +/* + * drm_flip_func_t - callback function + * + * @work: the flip work + * @val: value queued via drm_flip_work_queue() + * + * Callback function to be called for each of the queue'd work items after + * drm_flip_work_commit() is called. + */ +typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val); + +/** + * struct drm_flip_task - flip work task + * @node: list entry element + * @data: data to pass to &drm_flip_work.func + */ +struct drm_flip_task { + struct list_head node; + void *data; +}; + +/** + * struct drm_flip_work - flip work queue + * @name: debug name + * @func: callback fxn called for each committed item + * @worker: worker which calls @func + * @queued: queued tasks + * @commited: commited tasks + * @lock: lock to access queued and commited lists + */ +struct drm_flip_work { + const char *name; + drm_flip_func_t func; + struct work_struct worker; + struct list_head queued; + struct list_head commited; + spinlock_t lock; +}; + +struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags); +void drm_flip_work_queue_task(struct drm_flip_work *work, + struct drm_flip_task *task); +void drm_flip_work_queue(struct drm_flip_work *work, void *val); +void drm_flip_work_commit(struct drm_flip_work *work, + struct workqueue_struct *wq); +void drm_flip_work_init(struct drm_flip_work *work, + const char *name, drm_flip_func_t func); +void drm_flip_work_cleanup(struct drm_flip_work *work); + +#endif /* DRM_FLIP_WORK_H */ diff --git a/sys/dev/pci/drm/include/drm/drm_format_helper.h b/sys/dev/pci/drm/include/drm/drm_format_helper.h new file mode 100644 index 00000000000..7c5d4ffb2af --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_format_helper.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* + * Copyright (C) 2016 Noralf Trønnes + */ + +#ifndef __LINUX_DRM_FORMAT_HELPER_H +#define __LINUX_DRM_FORMAT_HELPER_H + +struct drm_framebuffer; +struct drm_rect; + +void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip); +void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, + struct drm_framebuffer *fb, + struct drm_rect *clip); +void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip); +void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, + struct drm_framebuffer *fb, + struct drm_rect *clip, bool swab); +void drm_fb_xrgb8888_to_rgb565_dstclip(void __iomem *dst, unsigned int dst_pitch, + void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip, bool swab); +void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch, + void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip); +void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *clip); + +#endif /* __LINUX_DRM_FORMAT_HELPER_H */ diff --git a/sys/dev/pci/drm/include/drm/drm_fourcc.h b/sys/dev/pci/drm/include/drm/drm_fourcc.h index f9c15845f46..156b122c0ad 100644 --- a/sys/dev/pci/drm/include/drm/drm_fourcc.h +++ b/sys/dev/pci/drm/include/drm/drm_fourcc.h @@ -25,30 +25,113 @@ #include <linux/types.h> #include <uapi/drm/drm_fourcc.h> +/* + * DRM formats are little endian. Define host endian variants for the + * most common formats here, to reduce the #ifdefs needed in drivers. + * + * Note that the DRM_FORMAT_BIG_ENDIAN flag should only be used in + * case the format can't be specified otherwise, so we don't end up + * with two values describing the same format. + */ +#ifdef __BIG_ENDIAN +# define DRM_FORMAT_HOST_XRGB1555 (DRM_FORMAT_XRGB1555 | \ + DRM_FORMAT_BIG_ENDIAN) +# define DRM_FORMAT_HOST_RGB565 (DRM_FORMAT_RGB565 | \ + DRM_FORMAT_BIG_ENDIAN) +# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_BGRX8888 +# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_BGRA8888 +#else +# define DRM_FORMAT_HOST_XRGB1555 DRM_FORMAT_XRGB1555 +# define DRM_FORMAT_HOST_RGB565 DRM_FORMAT_RGB565 +# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_XRGB8888 +# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_ARGB8888 +#endif + struct drm_device; struct drm_mode_fb_cmd2; /** * struct drm_format_info - information about a DRM format - * @format: 4CC format identifier (DRM_FORMAT_*) - * @depth: Color depth (number of bits per pixel excluding padding bits), - * valid for a subset of RGB formats only. This is a legacy field, do not - * use in new code and set to 0 for new formats. - * @num_planes: Number of color planes (1 to 3) - * @cpp: Number of bytes per pixel (per plane) - * @hsub: Horizontal chroma subsampling factor - * @vsub: Vertical chroma subsampling factor - * @has_alpha: Does the format embeds an alpha component? - * @is_yuv: Is it a YUV format? */ struct drm_format_info { + /** @format: 4CC format identifier (DRM_FORMAT_*) */ u32 format; + + /** + * @depth: + * + * Color depth (number of bits per pixel excluding padding bits), + * valid for a subset of RGB formats only. This is a legacy field, do + * not use in new code and set to 0 for new formats. + */ u8 depth; + + /** @num_planes: Number of color planes (1 to 3) */ u8 num_planes; - u8 cpp[3]; + + union { + /** + * @cpp: + * + * Number of bytes per pixel (per plane), this is aliased with + * @char_per_block. It is deprecated in favour of using the + * triplet @char_per_block, @block_w, @block_h for better + * describing the pixel format. + */ + u8 cpp[4]; + + /** + * @char_per_block: + * + * Number of bytes per block (per plane), where blocks are + * defined as a rectangle of pixels which are stored next to + * each other in a byte aligned memory region. Together with + * @block_w and @block_h this is used to properly describe tiles + * in tiled formats or to describe groups of pixels in packed + * formats for which the memory needed for a single pixel is not + * byte aligned. + * + * @cpp has been kept for historical reasons because there are + * a lot of places in drivers where it's used. In drm core for + * generic code paths the preferred way is to use + * @char_per_block, drm_format_info_block_width() and + * drm_format_info_block_height() which allows handling both + * block and non-block formats in the same way. + * + * For formats that are intended to be used only with non-linear + * modifiers both @cpp and @char_per_block must be 0 in the + * generic format table. Drivers could supply accurate + * information from their drm_mode_config.get_format_info hook + * if they want the core to be validating the pitch. + */ + u8 char_per_block[4]; + }; + + /** + * @block_w: + * + * Block width in pixels, this is intended to be accessed through + * drm_format_info_block_width() + */ + u8 block_w[4]; + + /** + * @block_h: + * + * Block height in pixels, this is intended to be accessed through + * drm_format_info_block_height() + */ + u8 block_h[4]; + + /** @hsub: Horizontal chroma subsampling factor */ u8 hsub; + /** @vsub: Vertical chroma subsampling factor */ u8 vsub; + + /** @has_alpha: Does the format embeds an alpha component? */ bool has_alpha; + + /** @is_yuv: Is it a YUV format? */ bool is_yuv; }; @@ -60,18 +143,181 @@ struct drm_format_name_buf { char str[32]; }; +/** + * drm_format_info_is_yuv_packed - check that the format info matches a YUV + * format with data laid in a single plane + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a packed YUV format. + */ +static inline bool +drm_format_info_is_yuv_packed(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 1; +} + +/** + * drm_format_info_is_yuv_semiplanar - check that the format info matches a YUV + * format with data laid in two planes (luminance and chrominance) + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a semiplanar YUV format. + */ +static inline bool +drm_format_info_is_yuv_semiplanar(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 2; +} + +/** + * drm_format_info_is_yuv_planar - check that the format info matches a YUV + * format with data laid in three planes (one for each YUV component) + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a planar YUV format. + */ +static inline bool +drm_format_info_is_yuv_planar(const struct drm_format_info *info) +{ + return info->is_yuv && info->num_planes == 3; +} + +/** + * drm_format_info_is_yuv_sampling_410 - check that the format info matches a + * YUV format with 4:1:0 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:1:0 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_410(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 4 && info->vsub == 4; +} + +/** + * drm_format_info_is_yuv_sampling_411 - check that the format info matches a + * YUV format with 4:1:1 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:1:1 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_411(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 4 && info->vsub == 1; +} + +/** + * drm_format_info_is_yuv_sampling_420 - check that the format info matches a + * YUV format with 4:2:0 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:2:0 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_420(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 2 && info->vsub == 2; +} + +/** + * drm_format_info_is_yuv_sampling_422 - check that the format info matches a + * YUV format with 4:2:2 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:2:2 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_422(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 2 && info->vsub == 1; +} + +/** + * drm_format_info_is_yuv_sampling_444 - check that the format info matches a + * YUV format with 4:4:4 sub-sampling + * @info: format info + * + * Returns: + * A boolean indicating whether the format info matches a YUV format with 4:4:4 + * sub-sampling. + */ +static inline bool +drm_format_info_is_yuv_sampling_444(const struct drm_format_info *info) +{ + return info->is_yuv && info->hsub == 1 && info->vsub == 1; +} + +/** + * drm_format_info_plane_width - width of the plane given the first plane + * @info: pixel format info + * @width: width of the first plane + * @plane: plane index + * + * Returns: + * The width of @plane, given that the width of the first plane is @width. + */ +static inline +int drm_format_info_plane_width(const struct drm_format_info *info, int width, + int plane) +{ + if (!info || plane >= info->num_planes) + return 0; + + if (plane == 0) + return width; + + return width / info->hsub; +} + +/** + * drm_format_info_plane_height - height of the plane given the first plane + * @info: pixel format info + * @height: height of the first plane + * @plane: plane index + * + * Returns: + * The height of @plane, given that the height of the first plane is @height. + */ +static inline +int drm_format_info_plane_height(const struct drm_format_info *info, int height, + int plane) +{ + if (!info || plane >= info->num_planes) + return 0; + + if (plane == 0) + return height; + + return height / info->vsub; +} + const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); const struct drm_format_info * drm_get_format_info(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); -int drm_format_num_planes(uint32_t format); -int drm_format_plane_cpp(uint32_t format, int plane); -int drm_format_horz_chroma_subsampling(uint32_t format); -int drm_format_vert_chroma_subsampling(uint32_t format); -int drm_format_plane_width(int width, uint32_t format, int plane); -int drm_format_plane_height(int height, uint32_t format, int plane); +uint32_t drm_driver_legacy_fb_format(struct drm_device *dev, + uint32_t bpp, uint32_t depth); +unsigned int drm_format_info_block_width(const struct drm_format_info *info, + int plane); +unsigned int drm_format_info_block_height(const struct drm_format_info *info, + int plane); +uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, + int plane, unsigned int buffer_width); const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf); #endif /* __DRM_FOURCC_H__ */ diff --git a/sys/dev/pci/drm/include/drm/drm_framebuffer.h b/sys/dev/pci/drm/include/drm/drm_framebuffer.h index c50502c656e..c0e0256e3e9 100644 --- a/sys/dev/pci/drm/include/drm/drm_framebuffer.h +++ b/sys/dev/pci/drm/include/drm/drm_framebuffer.h @@ -23,13 +23,18 @@ #ifndef __DRM_FRAMEBUFFER_H__ #define __DRM_FRAMEBUFFER_H__ -#include <linux/list.h> #include <linux/ctype.h> +#include <linux/list.h> +#include <linux/sched.h> + #include <drm/drm_mode_object.h> -struct drm_framebuffer; -struct drm_file; +struct drm_clip_rect; struct drm_device; +struct drm_file; +struct drm_format_info; +struct drm_framebuffer; +struct drm_gem_object; /** * struct drm_framebuffer_funcs - framebuffer hooks @@ -82,6 +87,9 @@ struct drm_framebuffer_funcs { * for more information as all the semantics and arguments have a one to * one mapping on this function. * + * Atomic drivers should use drm_atomic_helper_dirtyfb() to implement + * this hook. + * * RETURNS: * * 0 on success or a negative error code on failure. @@ -241,30 +249,6 @@ static inline void drm_framebuffer_put(struct drm_framebuffer *fb) } /** - * drm_framebuffer_reference - acquire a framebuffer reference - * @fb: DRM framebuffer - * - * This is a compatibility alias for drm_framebuffer_get() and should not be - * used by new code. - */ -static inline void drm_framebuffer_reference(struct drm_framebuffer *fb) -{ - drm_framebuffer_get(fb); -} - -/** - * drm_framebuffer_unreference - release a framebuffer reference - * @fb: DRM framebuffer - * - * This is a compatibility alias for drm_framebuffer_put() and should not be - * used by new code. - */ -static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb) -{ - drm_framebuffer_put(fb); -} - -/** * drm_framebuffer_read_refcount - read the framebuffer reference count. * @fb: framebuffer * diff --git a/sys/dev/pci/drm/include/drm/drm_gem.h b/sys/dev/pci/drm/include/drm/drm_gem.h index 67997edbd51..5bc32a1d2b5 100644 --- a/sys/dev/pci/drm/include/drm/drm_gem.h +++ b/sys/dev/pci/drm/include/drm/drm_gem.h @@ -35,9 +35,146 @@ */ #include <linux/kref.h> +#include <linux/dma-resv.h> #include <drm/drm_vma_manager.h> +struct drm_gem_object; + +/** + * struct drm_gem_object_funcs - GEM object functions + */ +struct drm_gem_object_funcs { + /** + * @free: + * + * Deconstructor for drm_gem_objects. + * + * This callback is mandatory. + */ + void (*free)(struct drm_gem_object *obj); + + /** + * @open: + * + * Called upon GEM handle creation. + * + * This callback is optional. + */ + int (*open)(struct drm_gem_object *obj, struct drm_file *file); + + /** + * @close: + * + * Called upon GEM handle release. + * + * This callback is optional. + */ + void (*close)(struct drm_gem_object *obj, struct drm_file *file); + + /** + * @print_info: + * + * If driver subclasses struct &drm_gem_object, it can implement this + * optional hook for printing additional driver specific info. + * + * drm_printf_indent() should be used in the callback passing it the + * indent argument. + * + * This callback is called from drm_gem_print_info(). + * + * This callback is optional. + */ + void (*print_info)(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj); + + /** + * @export: + * + * Export backing buffer as a &dma_buf. + * If this is not set drm_gem_prime_export() is used. + * + * This callback is optional. + */ + struct dma_buf *(*export)(struct drm_gem_object *obj, int flags); + + /** + * @pin: + * + * Pin backing buffer in memory. Used by the drm_gem_map_attach() helper. + * + * This callback is optional. + */ + int (*pin)(struct drm_gem_object *obj); + + /** + * @unpin: + * + * Unpin backing buffer. Used by the drm_gem_map_detach() helper. + * + * This callback is optional. + */ + void (*unpin)(struct drm_gem_object *obj); + + /** + * @get_sg_table: + * + * Returns a Scatter-Gather table representation of the buffer. + * Used when exporting a buffer by the drm_gem_map_dma_buf() helper. + * Releasing is done by calling dma_unmap_sg_attrs() and sg_free_table() + * in drm_gem_unmap_buf(), therefore these helpers and this callback + * here cannot be used for sg tables pointing at driver private memory + * ranges. + * + * See also drm_prime_pages_to_sg(). + */ + struct sg_table *(*get_sg_table)(struct drm_gem_object *obj); + + /** + * @vmap: + * + * Returns a virtual address for the buffer. Used by the + * drm_gem_dmabuf_vmap() helper. + * + * This callback is optional. + */ + void *(*vmap)(struct drm_gem_object *obj); + + /** + * @vunmap: + * + * Releases the the address previously returned by @vmap. Used by the + * drm_gem_dmabuf_vunmap() helper. + * + * This callback is optional. + */ + void (*vunmap)(struct drm_gem_object *obj, void *vaddr); + + /** + * @mmap: + * + * Handle mmap() of the gem object, setup vma accordingly. + * + * This callback is optional. + * + * The callback is used by by both drm_gem_mmap_obj() and + * drm_gem_prime_mmap(). When @mmap is present @vm_ops is not + * used, the @mmap callback must set vma->vm_ops instead. + */ +#ifdef __linux__ + int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma); +#endif + + /** + * @vm_ops: + * + * Virtual memory operations used with mmap. + * + * This is optional but necessary for mmap support. + */ + const struct vm_operations_struct *vm_ops; +}; + /** * struct drm_gem_object - GEM buffer object * @@ -47,6 +184,12 @@ * Buffer objects are often abbreviated to BO. */ struct drm_gem_object { + /* + * This must be first as uobj is cast to ttm_buffer_object for + * radeon_ttm_fault() the first member of that struct is drm_gem_object + */ + struct uvm_object uobj; + /** * @refcount: * @@ -147,7 +290,35 @@ struct drm_gem_object { */ struct dma_buf_attachment *import_attach; - struct uvm_object uobj; + /** + * @resv: + * + * Pointer to reservation object associated with the this GEM object. + * + * Normally (@resv == &@_resv) except for imported GEM objects. + */ + struct dma_resv *resv; + + /** + * @_resv: + * + * A reservation object for this GEM object. + * + * This is unused for imported GEM objects. + */ + struct dma_resv _resv; + + /** + * @funcs: + * + * Optional GEM object functions. If this is set, it will be used instead of the + * corresponding &drm_driver GEM callbacks. + * + * New drivers should use this. + * + */ + const struct drm_gem_object_funcs *funcs; + SPLAY_ENTRY(drm_gem_object) entry; struct uvm_object *uao; }; @@ -228,56 +399,6 @@ __drm_gem_object_put(struct drm_gem_object *obj) void drm_gem_object_put_unlocked(struct drm_gem_object *obj); void drm_gem_object_put(struct drm_gem_object *obj); -/** - * drm_gem_object_reference - acquire a GEM buffer object reference - * @obj: GEM buffer object - * - * This is a compatibility alias for drm_gem_object_get() and should not be - * used by new code. - */ -static inline void drm_gem_object_reference(struct drm_gem_object *obj) -{ - drm_gem_object_get(obj); -} - -/** - * __drm_gem_object_unreference - raw function to release a GEM buffer object - * reference - * @obj: GEM buffer object - * - * This is a compatibility alias for __drm_gem_object_put() and should not be - * used by new code. - */ -static inline void __drm_gem_object_unreference(struct drm_gem_object *obj) -{ - __drm_gem_object_put(obj); -} - -/** - * drm_gem_object_unreference_unlocked - release a GEM buffer object reference - * @obj: GEM buffer object - * - * This is a compatibility alias for drm_gem_object_put_unlocked() and should - * not be used by new code. - */ -static inline void -drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) -{ - drm_gem_object_put_unlocked(obj); -} - -/** - * drm_gem_object_unreference - release a GEM buffer object reference - * @obj: GEM buffer object - * - * This is a compatibility alias for drm_gem_object_put() and should not be - * used by new code. - */ -static inline void drm_gem_object_unreference(struct drm_gem_object *obj) -{ - drm_gem_object_put(obj); -} - int drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, u32 *handlep); @@ -288,11 +409,26 @@ void drm_gem_free_mmap_offset(struct drm_gem_object *obj); int drm_gem_create_mmap_offset(struct drm_gem_object *obj); int drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size); -struct page **drm_gem_get_pages(struct drm_gem_object *obj); -void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, +struct vm_page **drm_gem_get_pages(struct drm_gem_object *obj); +void drm_gem_put_pages(struct drm_gem_object *obj, struct vm_page **pages, bool dirty, bool accessed); +int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, + int count, struct drm_gem_object ***objs_out); struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); +long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, + bool wait_all, unsigned long timeout); +int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, + struct ww_acquire_ctx *acquire_ctx); +void drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, + struct ww_acquire_ctx *acquire_ctx); +#ifdef notyet +int drm_gem_fence_array_add(struct xarray *fence_array, + struct dma_fence *fence); +int drm_gem_fence_array_add_implicit(struct xarray *fence_array, + struct drm_gem_object *obj, + bool write); +#endif int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, u32 handle, u64 *offset); int drm_gem_dumb_destroy(struct drm_file *file, diff --git a/sys/dev/pci/drm/include/drm/drm_gem_cma_helper.h b/sys/dev/pci/drm/include/drm/drm_gem_cma_helper.h index b388a0d99c7..d23766028f9 100644 --- a/sys/dev/pci/drm/include/drm/drm_gem_cma_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_gem_cma_helper.h @@ -1,6 +1,5 @@ /* Public Domain */ -#include <drm/drmP.h> #include <drm/drm_gem.h> void drm_gem_cma_free_object(struct drm_gem_object *); diff --git a/sys/dev/pci/drm/include/drm/drm_gem_framebuffer_helper.h b/sys/dev/pci/drm/include/drm/drm_gem_framebuffer_helper.h index 9670130719f..c903667925c 100644 --- a/sys/dev/pci/drm/include/drm/drm_gem_framebuffer_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_gem_framebuffer_helper.h @@ -1,7 +1,7 @@ /* Public domain. */ -#ifndef DRM_GEM_FRAMEBUFFER_HELPER_H -#define DRM_GEM_FRAMEBUFFER_HELPER_H +#ifndef _DRM_GEM_FRAMEBUFFER_HELPER_H +#define _DRM_GEM_FRAMEBUFFER_HELPER_H void drm_gem_fb_destroy(struct drm_framebuffer *); int drm_gem_fb_create_handle(struct drm_framebuffer *, struct drm_file *, diff --git a/sys/dev/pci/drm/include/drm/drm_global.h b/sys/dev/pci/drm/include/drm/drm_global.h deleted file mode 100644 index 3a830602a2e..00000000000 --- a/sys/dev/pci/drm/include/drm/drm_global.h +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************************************** - * - * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ -/* - * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> - */ - -#ifndef _DRM_GLOBAL_H_ -#define _DRM_GLOBAL_H_ -enum drm_global_types { - DRM_GLOBAL_TTM_MEM = 0, - DRM_GLOBAL_TTM_BO, - DRM_GLOBAL_TTM_OBJECT, - DRM_GLOBAL_NUM -}; - -struct drm_global_reference { - enum drm_global_types global_type; - size_t size; - void *object; - int (*init) (struct drm_global_reference *); - void (*release) (struct drm_global_reference *); -}; - -void drm_global_init(void); -void drm_global_release(void); -int drm_global_item_ref(struct drm_global_reference *ref); -void drm_global_item_unref(struct drm_global_reference *ref); - -#endif diff --git a/sys/dev/pci/drm/include/drm/drm_hashtab.h b/sys/dev/pci/drm/include/drm/drm_hashtab.h index d5d00d4c27d..bb95ff011ba 100644 --- a/sys/dev/pci/drm/include/drm/drm_hashtab.h +++ b/sys/dev/pci/drm/include/drm/drm_hashtab.h @@ -1,4 +1,3 @@ -/* $OpenBSD: drm_hashtab.h,v 1.1 2019/04/14 10:14:52 jsg Exp $ */ /************************************************************************** * * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA. @@ -36,32 +35,31 @@ #ifndef DRM_HASHTAB_H #define DRM_HASHTAB_H -#include <sys/types.h> -#include <sys/queue.h> +#include <linux/list.h> #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) struct drm_hash_item { - LIST_ENTRY(drm_hash_item) head; + struct hlist_node head; unsigned long key; }; struct drm_open_hash { - LIST_HEAD(drm_hash_item_list, drm_hash_item) *table; - uint8_t order; + struct hlist_head *table; + u8 order; }; -extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order); -extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); +int drm_ht_create(struct drm_open_hash *ht, unsigned int order); +int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); +int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, + unsigned long seed, int bits, int shift, + unsigned long add); +int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); -extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern void drm_ht_remove(struct drm_open_hash *ht); +void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); +void drm_ht_remove(struct drm_open_hash *ht); /* * RCU-safe interface diff --git a/sys/dev/pci/drm/include/drm/drm_hdcp.h b/sys/dev/pci/drm/include/drm/drm_hdcp.h index 98e63d87013..c6bab4986a6 100644 --- a/sys/dev/pci/drm/include/drm/drm_hdcp.h +++ b/sys/dev/pci/drm/include/drm/drm_hdcp.h @@ -9,8 +9,11 @@ #ifndef _DRM_HDCP_H_INCLUDED_ #define _DRM_HDCP_H_INCLUDED_ +#include <linux/types.h> + /* Period of hdcp checks (to ensure we're still authenticated) */ #define DRM_HDCP_CHECK_PERIOD_MS (128 * 16) +#define DRM_HDCP2_CHECK_PERIOD_MS 500 /* Shared lengths/masks between HDMI/DVI/DisplayPort */ #define DRM_HDCP_AN_LEN 8 @@ -38,4 +41,262 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43 +#define DRM_HDCP_1_4_SRM_ID 0x8 +#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 + +/* Protocol message definition for HDCP2.2 specification */ +/* + * Protected content streams are classified into 2 types: + * - Type0: Can be transmitted with HDCP 1.4+ + * - Type1: Can be transmitted with HDCP 2.2+ + */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01 + +/* HDCP2.2 Msg IDs */ +#define HDCP_2_2_NULL_MSG 1 +#define HDCP_2_2_AKE_INIT 2 +#define HDCP_2_2_AKE_SEND_CERT 3 +#define HDCP_2_2_AKE_NO_STORED_KM 4 +#define HDCP_2_2_AKE_STORED_KM 5 +#define HDCP_2_2_AKE_SEND_HPRIME 7 +#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 +#define HDCP_2_2_LC_INIT 9 +#define HDCP_2_2_LC_SEND_LPRIME 10 +#define HDCP_2_2_SKE_SEND_EKS 11 +#define HDCP_2_2_REP_SEND_RECVID_LIST 12 +#define HDCP_2_2_REP_SEND_ACK 15 +#define HDCP_2_2_REP_STREAM_MANAGE 16 +#define HDCP_2_2_REP_STREAM_READY 17 + +#define HDCP_2_2_RTX_LEN 8 +#define HDCP_2_2_RRX_LEN 8 + +#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 +#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 +#define HDCP_2_2_K_PUB_RX_LEN (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \ + HDCP_2_2_K_PUB_RX_EXP_E_LEN) + +#define HDCP_2_2_DCP_LLC_SIG_LEN 384 + +#define HDCP_2_2_E_KPUB_KM_LEN 128 +#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) +#define HDCP_2_2_H_PRIME_LEN 32 +#define HDCP_2_2_E_KH_KM_LEN 16 +#define HDCP_2_2_RN_LEN 8 +#define HDCP_2_2_L_PRIME_LEN 32 +#define HDCP_2_2_E_DKEY_KS_LEN 16 +#define HDCP_2_2_RIV_LEN 8 +#define HDCP_2_2_SEQ_NUM_LEN 3 +#define HDCP_2_2_V_PRIME_HALF_LEN (HDCP_2_2_L_PRIME_LEN / 2) +#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN +#define HDCP_2_2_MAX_DEVICE_COUNT 31 +#define HDCP_2_2_RECEIVER_IDS_MAX_LEN (HDCP_2_2_RECEIVER_ID_LEN * \ + HDCP_2_2_MAX_DEVICE_COUNT) +#define HDCP_2_2_MPRIME_LEN 32 + +/* Following Macros take a byte at a time for bit(s) masking */ +/* + * TODO: This has to be changed for DP MST, as multiple stream on + * same port is possible. + * For HDCP2.2 on HDMI and DP SST this value is always 1. + */ +#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 1 +#define HDCP_2_2_TXCAP_MASK_LEN 2 +#define HDCP_2_2_RXCAPS_LEN 3 +#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) +#define HDCP_2_2_RXINFO_LEN 2 + +/* HDCP1.x compliant device in downstream */ +#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0)) + +/* HDCP2.0 Compliant repeater in downstream */ +#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) +#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) +#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) +#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) +#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) +#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1) + +struct hdcp2_cert_rx { + u8 receiver_id[HDCP_2_2_RECEIVER_ID_LEN]; + u8 kpub_rx[HDCP_2_2_K_PUB_RX_LEN]; + u8 reserved[2]; + u8 dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN]; +} __packed; + +struct hdcp2_streamid_type { + u8 stream_id; + u8 stream_type; +} __packed; + +/* + * The TxCaps field specified in the HDCP HDMI, DP specs + * This field is big endian as specified in the errata. + */ +struct hdcp2_tx_caps { + /* Transmitter must set this to 0x2 */ + u8 version; + + /* Reserved for HDCP and DP Spec. Read as Zero */ + u8 tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN]; +} __packed; + +/* Main structures for HDCP2.2 protocol communication */ +struct hdcp2_ake_init { + u8 msg_id; + u8 r_tx[HDCP_2_2_RTX_LEN]; + struct hdcp2_tx_caps tx_caps; +} __packed; + +struct hdcp2_ake_send_cert { + u8 msg_id; + struct hdcp2_cert_rx cert_rx; + u8 r_rx[HDCP_2_2_RRX_LEN]; + u8 rx_caps[HDCP_2_2_RXCAPS_LEN]; +} __packed; + +struct hdcp2_ake_no_stored_km { + u8 msg_id; + u8 e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN]; +} __packed; + +struct hdcp2_ake_stored_km { + u8 msg_id; + u8 e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN]; +} __packed; + +struct hdcp2_ake_send_hprime { + u8 msg_id; + u8 h_prime[HDCP_2_2_H_PRIME_LEN]; +} __packed; + +struct hdcp2_ake_send_pairing_info { + u8 msg_id; + u8 e_kh_km[HDCP_2_2_E_KH_KM_LEN]; +} __packed; + +struct hdcp2_lc_init { + u8 msg_id; + u8 r_n[HDCP_2_2_RN_LEN]; +} __packed; + +struct hdcp2_lc_send_lprime { + u8 msg_id; + u8 l_prime[HDCP_2_2_L_PRIME_LEN]; +} __packed; + +struct hdcp2_ske_send_eks { + u8 msg_id; + u8 e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN]; + u8 riv[HDCP_2_2_RIV_LEN]; +} __packed; + +struct hdcp2_rep_send_receiverid_list { + u8 msg_id; + u8 rx_info[HDCP_2_2_RXINFO_LEN]; + u8 seq_num_v[HDCP_2_2_SEQ_NUM_LEN]; + u8 v_prime[HDCP_2_2_V_PRIME_HALF_LEN]; + u8 receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN]; +} __packed; + +struct hdcp2_rep_send_ack { + u8 msg_id; + u8 v[HDCP_2_2_V_PRIME_HALF_LEN]; +} __packed; + +struct hdcp2_rep_stream_manage { + u8 msg_id; + u8 seq_num_m[HDCP_2_2_SEQ_NUM_LEN]; + __be16 k; + struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT]; +} __packed; + +struct hdcp2_rep_stream_ready { + u8 msg_id; + u8 m_prime[HDCP_2_2_MPRIME_LEN]; +} __packed; + +/* HDCP2.2 TIMEOUTs in mSec */ +#define HDCP_2_2_CERT_TIMEOUT_MS 100 +#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS 1000 +#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS 200 +#define HDCP_2_2_PAIRING_TIMEOUT_MS 200 +#define HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS 20 +#define HDCP_2_2_DP_LPRIME_TIMEOUT_MS 7 +#define HDCP_2_2_RECVID_LIST_TIMEOUT_MS 3000 +#define HDCP_2_2_STREAM_READY_TIMEOUT_MS 100 + +/* HDMI HDCP2.2 Register Offsets */ +#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 +#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 +#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 +#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 +#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0 + +#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) +#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 +#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF +#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200 + +/* Below macros take a byte at a time and mask the bit(s) */ +#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 +#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) +#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) +#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) + +/* + * Helper functions to convert 24bit big endian hdcp sequence number to + * host format and back + */ +static inline +u32 drm_hdcp_be24_to_cpu(const u8 seq_num[HDCP_2_2_SEQ_NUM_LEN]) +{ + return (u32)(seq_num[2] | seq_num[1] << 8 | seq_num[0] << 16); +} + +static inline +void drm_hdcp_cpu_to_be24(u8 seq_num[HDCP_2_2_SEQ_NUM_LEN], u32 val) +{ + seq_num[0] = val >> 16; + seq_num[1] = val >> 8; + seq_num[2] = val; +} + +#define DRM_HDCP_SRM_GEN1_MAX_BYTES (5 * 1024) +#define DRM_HDCP_1_4_SRM_ID 0x8 +#define DRM_HDCP_SRM_ID_MASK (0xF << 4) +#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 +#define DRM_HDCP_2_SRM_ID 0x9 +#define DRM_HDCP_2_INDICATOR 0x1 +#define DRM_HDCP_2_INDICATOR_MASK 0xF +#define DRM_HDCP_2_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_2_DCP_SIG_SIZE 384 +#define DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ 4 +#define DRM_HDCP_2_KSV_COUNT_2_LSBITS(byte) (((byte) & 0xC0) >> 6) + +struct hdcp_srm_header { + u8 srm_id; + u8 reserved; + __be16 srm_version; + u8 srm_gen_no; +} __packed; + +struct drm_device; +struct drm_connector; + +int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, + u8 *ksvs, u32 ksv_count); +int drm_connector_attach_content_protection_property( + struct drm_connector *connector, bool hdcp_content_type); +void drm_hdcp_update_content_protection(struct drm_connector *connector, + u64 val); + +/* Content Type classification for HDCP2.2 vs others */ +#define DRM_MODE_HDCP_CONTENT_TYPE0 0 +#define DRM_MODE_HDCP_CONTENT_TYPE1 1 + #endif diff --git a/sys/dev/pci/drm/include/drm/drm_ioctl.h b/sys/dev/pci/drm/include/drm/drm_ioctl.h index a9edb834cd9..ca79b07962c 100644 --- a/sys/dev/pci/drm/include/drm/drm_ioctl.h +++ b/sys/dev/pci/drm/include/drm/drm_ioctl.h @@ -1,8 +1,14 @@ -/*- +/* + * Internal Header for the Direct Rendering Manager + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. * All rights reserved. * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation @@ -21,57 +27,159 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #ifndef _DRM_IOCTL_H_ #define _DRM_IOCTL_H_ +#include <linux/types.h> +#include <linux/bitops.h> + +#include <asm/ioctl.h> + struct drm_device; struct drm_file; struct file; /** - * Ioctl function type. + * drm_ioctl_t - DRM ioctl function type. + * @dev: DRM device inode + * @data: private pointer of the ioctl call + * @file_priv: DRM file this ioctl was made on * - * \param inode device inode. - * \param file_priv DRM file private pointer. - * \param cmd command. - * \param arg argument. + * This is the DRM ioctl typedef. Note that drm_ioctl() has alrady copied @data + * into kernel-space, and will also copy it back, depending upon the read/write + * settings in the ioctl command code. */ typedef int drm_ioctl_t(struct drm_device *dev, void *data, struct drm_file *file_priv); +/** + * drm_ioctl_compat_t - compatibility DRM ioctl function type. + * @filp: file pointer + * @cmd: ioctl command code + * @arg: DRM file this ioctl was made on + * + * Just a typedef to make declaring an array of compatibility handlers easier. + * New drivers shouldn't screw up the structure layout for their ioctl + * structures and hence never need this. + */ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, unsigned long arg); -#define DRM_IOCTL_NR(n) ((n) & 0xff) +#ifdef __linux__ +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_MAJOR 226 +#else +#define DRM_IOCTL_NR(n) ((n) & 0xff) +#endif -#define DRM_AUTH 0x1 -#define DRM_MASTER 0x2 -#define DRM_ROOT_ONLY 0x4 -#define DRM_CONTROL_ALLOW 0x8 -#define DRM_UNLOCKED 0x10 -#define DRM_RENDER_ALLOW 0x20 +/** + * enum drm_ioctl_flags - DRM ioctl flags + * + * Various flags that can be set in &drm_ioctl_desc.flags to control how + * userspace can use a given ioctl. + */ +enum drm_ioctl_flags { + /** + * @DRM_AUTH: + * + * This is for ioctl which are used for rendering, and require that the + * file descriptor is either for a render node, or if it's a + * legacy/primary node, then it must be authenticated. + */ + DRM_AUTH = BIT(0), + /** + * @DRM_MASTER: + * + * This must be set for any ioctl which can change the modeset or + * display state. Userspace must call the ioctl through a primary node, + * while it is the active master. + * + * Note that read-only modeset ioctl can also be called by + * unauthenticated clients, or when a master is not the currently active + * one. + */ + DRM_MASTER = BIT(1), + /** + * @DRM_ROOT_ONLY: + * + * Anything that could potentially wreak a master file descriptor needs + * to have this flag set. Current that's only for the SETMASTER and + * DROPMASTER ioctl, which e.g. logind can call to force a non-behaving + * master (display compositor) into compliance. + * + * This is equivalent to callers with the SYSADMIN capability. + */ + DRM_ROOT_ONLY = BIT(2), + /** + * @DRM_UNLOCKED: + * + * Whether &drm_ioctl_desc.func should be called with the DRM BKL held + * or not. Enforced as the default for all modern drivers, hence there + * should never be a need to set this flag. + * + * Do not use anywhere else than for the VBLANK_WAIT IOCTL, which is the + * only legacy IOCTL which needs this. + */ + DRM_UNLOCKED = BIT(4), + /** + * @DRM_RENDER_ALLOW: + * + * This is used for all ioctl needed for rendering only, for drivers + * which support render nodes. This should be all new render drivers, + * and hence it should be always set for any ioctl with DRM_AUTH set. + * Note though that read-only query ioctl might have this set, but have + * not set DRM_AUTH because they do not require authentication. + */ + DRM_RENDER_ALLOW = BIT(5), +}; +/** + * struct drm_ioctl_desc - DRM driver ioctl entry + * @cmd: ioctl command number, without flags + * @flags: a bitmask of &enum drm_ioctl_flags + * @func: handler for this ioctl + * @name: user-readable name for debug output + * + * For convenience it's easier to create these using the DRM_IOCTL_DEF_DRV() + * macro. + */ struct drm_ioctl_desc { unsigned int cmd; - int flags; + enum drm_ioctl_flags flags; drm_ioctl_t *func; - unsigned int cmd_drv; + const char *name; }; /** - * Creates a driver or general drm_ioctl_desc array entry for the given - * ioctl, for use by drm_ioctl(). + * DRM_IOCTL_DEF_DRV() - helper macro to fill out a &struct drm_ioctl_desc + * @ioctl: ioctl command suffix + * @_func: handler for the ioctl + * @_flags: a bitmask of &enum drm_ioctl_flags + * + * Small helper macro to create a &struct drm_ioctl_desc entry. The ioctl + * command number is constructed by prepending ``DRM_IOCTL\_`` and passing that + * to DRM_IOCTL_NR(). */ +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ + .cmd = DRM_IOCTL_##ioctl, \ + .func = _func, \ + .flags = _flags, \ + .name = #ioctl \ + } -#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} +int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); +long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +long drm_ioctl_kernel(struct file *, drm_ioctl_t, void *, u32); +#ifdef CONFIG_COMPAT +long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ +#define drm_compat_ioctl NULL +#endif +bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/sys/dev/pci/drm/include/drm/drm_lease.h b/sys/dev/pci/drm/include/drm/drm_lease.h index 285c3010133..c4707753f4e 100644 --- a/sys/dev/pci/drm/include/drm/drm_lease.h +++ b/sys/dev/pci/drm/include/drm/drm_lease.h @@ -1,9 +1,21 @@ /* Public domain. */ -#ifndef DRM_LEASE_H -#define DRM_LEASE_H +#ifndef _DRM_LEASE_H +#define _DRM_LEASE_H + +struct drm_master; #define drm_lease_held(f, id) (true) #define drm_lease_filter_crtcs(f, in) (in) +static inline void +drm_lease_revoke(struct drm_master *m) +{ +} + +static inline void +drm_lease_destroy(struct drm_master *m) +{ +} + #endif diff --git a/sys/dev/pci/drm/include/drm/drm_legacy.h b/sys/dev/pci/drm/include/drm/drm_legacy.h new file mode 100644 index 00000000000..0937169deed --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_legacy.h @@ -0,0 +1,235 @@ +#ifndef __DRM_DRM_LEGACY_H__ +#define __DRM_DRM_LEGACY_H__ +/* + * Legacy driver interfaces for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * Copyright © 2014 Intel Corporation + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <drm/drm.h> +#include <drm/drm_auth.h> +#include <drm/drm_hashtab.h> + +struct drm_device; +struct drm_driver; +struct file; +struct pci_driver; + +/* + * Legacy Support for palateontologic DRM drivers + * + * If you add a new driver and it uses any of these functions or structures, + * you're doing it terribly wrong. + */ + +/** + * DMA buffer. + */ +struct drm_buf { + int idx; /**< Index into master buflist */ + int total; /**< Buffer size */ + int order; /**< log-base-2(total) */ + int used; /**< Amount of buffer in use (for DMA) */ + unsigned long offset; /**< Byte offset (used internally) */ + void *address; /**< Address of buffer */ + unsigned long bus_address; /**< Bus address of buffer */ + struct drm_buf *next; /**< Kernel-only: used for free list */ + __volatile__ int waiting; /**< On kernel DMA queue */ + __volatile__ int pending; /**< On hardware DMA queue */ + struct drm_file *file_priv; /**< Private of holding file descr */ + int context; /**< Kernel queue for this buffer */ + int while_locked; /**< Dispatch this buffer while locked */ + enum { + DRM_LIST_NONE = 0, + DRM_LIST_FREE = 1, + DRM_LIST_WAIT = 2, + DRM_LIST_PEND = 3, + DRM_LIST_PRIO = 4, + DRM_LIST_RECLAIM = 5 + } list; /**< Which list we're on */ + + int dev_priv_size; /**< Size of buffer private storage */ + void *dev_private; /**< Per-buffer private storage */ +}; + +struct drm_dmamem { + bus_dmamap_t map; + caddr_t kva; + bus_size_t size; + int nsegs; + bus_dma_segment_t segs[1]; +}; + +typedef struct drm_dma_handle { + struct drm_dmamem *mem; + dma_addr_t busaddr; + void *vaddr; + size_t size; +} drm_dma_handle_t; + +struct drm_dmamem *drm_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, + int, bus_size_t, int, int); +void drm_dmamem_free(bus_dma_tag_t, struct drm_dmamem *); + +/** + * Buffer entry. There is one of this for each buffer size order. + */ +struct drm_buf_entry { + int buf_size; /**< size */ + int buf_count; /**< number of buffers */ + struct drm_buf *buflist; /**< buffer list */ + int seg_count; + int page_order; + struct drm_dma_handle **seglist; + + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ +}; + +/** + * DMA data. + */ +struct drm_device_dma { + + struct drm_buf_entry bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */ + int buf_count; /**< total number of buffers */ + struct drm_buf **buflist; /**< Vector of pointers into drm_device_dma::bufs */ + int seg_count; + int page_count; /**< number of pages */ + unsigned long *pagelist; /**< page list */ + unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02, + _DRM_DMA_USE_FB = 0x04, + _DRM_DMA_USE_PCI_RO = 0x08 + } flags; + +}; + +/** + * Scatter-gather memory. + */ +struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct vm_page **pagelist; + dma_addr_t *busaddr; +}; + +/** + * Kernel side of a mapping + */ +struct drm_local_map { + dma_addr_t offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + enum drm_map_type type; /**< Type of memory to map */ + enum drm_map_flags flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot used */ +}; + +typedef struct drm_local_map drm_local_map_t; + +/** + * Mappings list + */ +struct drm_map_list { + struct list_head head; /**< list head */ + struct drm_hash_item hash; + struct drm_local_map *map; /**< mapping */ + uint64_t user_token; + struct drm_master *master; +}; + +int drm_legacy_addmap(struct drm_device *d, resource_size_t offset, + unsigned int size, enum drm_map_type type, + enum drm_map_flags flags, struct drm_local_map **map_p); +struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, unsigned int token); +void drm_legacy_rmmap(struct drm_device *d, struct drm_local_map *map); +int drm_legacy_rmmap_locked(struct drm_device *d, struct drm_local_map *map); +struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev); +#ifdef __linux__ +int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma); +#endif + +int drm_legacy_addbufs_agp(struct drm_device *d, struct drm_buf_desc *req); +int drm_legacy_addbufs_pci(struct drm_device *d, struct drm_buf_desc *req); + +/** + * Test that the hardware lock is held by the caller, returning otherwise. + * + * \param dev DRM device. + * \param filp file pointer of the caller. + */ +#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \ +do { \ + if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \ + _file_priv->master->lock.file_priv != _file_priv) { \ + DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ + __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\ + _file_priv->master->lock.file_priv, _file_priv); \ + return -EINVAL; \ + } \ +} while (0) + +void drm_legacy_idlelock_take(struct drm_lock_data *lock); +void drm_legacy_idlelock_release(struct drm_lock_data *lock); + +/* drm_pci.c */ + +#ifdef CONFIG_PCI + +int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); +void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); + +#else + +static inline int drm_legacy_pci_init(struct drm_driver *driver, + struct pci_driver *pdriver) +{ + return -EINVAL; +} + +static inline void drm_legacy_pci_exit(struct drm_driver *driver, + struct pci_driver *pdriver) +{ +} + +#endif + +/* drm_memory.c */ +void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev); +void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev); +void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev); + +#endif /* __DRM_DRM_LEGACY_H__ */ diff --git a/sys/dev/pci/drm/include/drm/drm_mipi_dsi.h b/sys/dev/pci/drm/include/drm/drm_mipi_dsi.h index 79f41d0060f..47f34f5dccd 100644 --- a/sys/dev/pci/drm/include/drm/drm_mipi_dsi.h +++ b/sys/dev/pci/drm/include/drm/drm_mipi_dsi.h @@ -1,7 +1,7 @@ /* Public domain. */ -#ifndef _DEV_PCI_DRM_DRM_MIPI_DSI_H_ -#define _DEV_PCI_DRM_DRM_MIPI_DSI_H_ +#ifndef _DRM_MIPI_DSI_H_ +#define _DRM_MIPI_DSI_H_ #include <sys/types.h> #include <linux/errno.h> @@ -10,6 +10,7 @@ struct mipi_dsi_host; struct mipi_dsi_device; struct mipi_dsi_msg; +struct drm_dsc_picture_parameter_set; struct mipi_dsi_host_ops { int (*attach)(struct mipi_dsi_host *, struct mipi_dsi_device *); @@ -33,7 +34,7 @@ struct mipi_dsi_msg { uint8_t channel; uint16_t flags; #define MIPI_DSI_MSG_USE_LPM (1 << 0) - const uint8_t *tx_buf; + const void *tx_buf; size_t tx_len; uint8_t *rx_buf; size_t rx_len; @@ -65,6 +66,12 @@ ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *, const void *, size_t); ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *, u8, void *, size_t); ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *, u8, const void *, size_t); +int mipi_dsi_dcs_nop(struct mipi_dsi_device *); +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *, u16); +bool mipi_dsi_packet_format_is_long(u8); +ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *, bool); +ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *, + const struct drm_dsc_picture_parameter_set *); static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) diff --git a/sys/dev/pci/drm/include/drm/drm_mode_config.h b/sys/dev/pci/drm/include/drm/drm_mode_config.h index 453fcc2c9c0..d22c3f0ac67 100644 --- a/sys/dev/pci/drm/include/drm/drm_mode_config.h +++ b/sys/dev/pci/drm/include/drm/drm_mode_config.h @@ -52,6 +52,12 @@ struct drm_mode_config_funcs { * requested metadata, but most of that is left to the driver. See * &struct drm_mode_fb_cmd2 for details. * + * To validate the pixel format and modifier drivers can use + * drm_any_plane_has_format() to make sure at least one plane supports + * the requested values. Note that the driver must first determine the + * actual modifier used if the request doesn't have it specified, + * ie. when (@mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0. + * * If the parameters are deemed valid and the backing storage objects in * the underlying memory manager all exist, then the driver allocates * a new &drm_framebuffer structure, subclassed to contain @@ -355,7 +361,7 @@ struct drm_mode_config { * * This is the big scary modeset BKL which protects everything that * isn't protect otherwise. Scope is unclear and fuzzy, try to remove - * anything from under it's protection and move it into more well-scoped + * anything from under its protection and move it into more well-scoped * locks. * * The one important thing this protects is the use of @acquire_ctx. @@ -385,18 +391,18 @@ struct drm_mode_config { /** * @idr_mutex: * - * Mutex for KMS ID allocation and management. Protects both @crtc_idr + * Mutex for KMS ID allocation and management. Protects both @object_idr * and @tile_idr. */ struct rwlock idr_mutex; /** - * @crtc_idr: + * @object_idr: * * Main KMS ID tracking object. Use this idr for all IDs, fb, crtc, * connector, modes - just makes life easier to have only one. */ - struct idr crtc_idr; + struct idr object_idr; /** * @tile_idr: @@ -506,6 +512,15 @@ struct drm_mode_config { */ struct list_head property_list; + /** + * @privobj_list: + * + * List of private objects linked with &drm_private_obj.head. This is + * invariant over the lifetime of a device and hence doesn't need any + * locks. + */ + struct list_head privobj_list; + int min_width, min_height; int max_width, max_height; const struct drm_mode_config_funcs *funcs; @@ -628,6 +643,15 @@ struct drm_mode_config { */ struct drm_property *prop_crtc_id; /** + * @prop_fb_damage_clips: Optional plane property to mark damaged + * regions on the plane in framebuffer coordinates of the framebuffer + * attached to the plane. + * + * The layout of blob data is simply an array of &drm_mode_rect. Unlike + * plane src coordinates, damage clips are not in 16.16 fixed point. + */ + struct drm_property *prop_fb_damage_clips; + /** * @prop_active: Default atomic CRTC property to control the active * state, which is the simplified implementation for DPMS in atomic * drivers. @@ -639,6 +663,11 @@ struct drm_mode_config { * connectors must be of and active must be set to disabled, too. */ struct drm_property *prop_mode_id; + /** + * @prop_vrr_enabled: Default atomic CRTC property to indicate + * whether variable refresh rate should be enabled on the CRTC. + */ + struct drm_property *prop_vrr_enabled; /** * @dvi_i_subconnector_property: Optional DVI-I property to @@ -668,22 +697,22 @@ struct drm_mode_config { struct drm_property *tv_mode_property; /** * @tv_left_margin_property: Optional TV property to set the left - * margin. + * margin (expressed in pixels). */ struct drm_property *tv_left_margin_property; /** * @tv_right_margin_property: Optional TV property to set the right - * margin. + * margin (expressed in pixels). */ struct drm_property *tv_right_margin_property; /** * @tv_top_margin_property: Optional TV property to set the right - * margin. + * margin (expressed in pixels). */ struct drm_property *tv_top_margin_property; /** * @tv_bottom_margin_property: Optional TV property to set the right - * margin. + * margin (expressed in pixels). */ struct drm_property *tv_bottom_margin_property; /** @@ -807,10 +836,58 @@ struct drm_mode_config { */ struct drm_property *writeback_out_fence_ptr_property; + /** + * @hdr_output_metadata_property: Connector property containing hdr + * metatada. This will be provided by userspace compositors based + * on HDR content + */ + struct drm_property *hdr_output_metadata_property; + + /** + * @content_protection_property: DRM ENUM property for content + * protection. See drm_connector_attach_content_protection_property(). + */ + struct drm_property *content_protection_property; + + /** + * @hdcp_content_type_property: DRM ENUM property for type of + * Protected Content. + */ + struct drm_property *hdcp_content_type_property; + /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; /** + * @prefer_shadow_fbdev: + * + * Hint to framebuffer emulation to prefer shadow-fb rendering. + */ + bool prefer_shadow_fbdev; + + /** + * @quirk_addfb_prefer_xbgr_30bpp: + * + * Special hack for legacy ADDFB to keep nouveau userspace happy. Should + * only ever be set by the nouveau kernel driver. + */ + bool quirk_addfb_prefer_xbgr_30bpp; + + /** + * @quirk_addfb_prefer_host_byte_order: + * + * When set to true drm_mode_addfb() will pick host byte order + * pixel_format when calling drm_mode_addfb2(). This is how + * drm_mode_addfb() should have worked from day one. It + * didn't though, so we ended up with quirks in both kernel + * and userspace drivers to deal with the broken behavior. + * Simply fixing drm_mode_addfb() unconditionally would break + * these drivers, so add a quirk bit here to allow drivers + * opt-in. + */ + bool quirk_addfb_prefer_host_byte_order; + + /** * @async_page_flip: Does this device support async flips on the primary * plane? */ diff --git a/sys/dev/pci/drm/include/drm/drm_modes.h b/sys/dev/pci/drm/include/drm/drm_modes.h index 8b3d17fa214..320f8112a0f 100644 --- a/sys/dev/pci/drm/include/drm/drm_modes.h +++ b/sys/dev/pci/drm/include/drm/drm_modes.h @@ -27,8 +27,6 @@ #ifndef __DRM_MODES_H__ #define __DRM_MODES_H__ -struct videomode; - #include <linux/hdmi.h> #include <drm/drm_mode_object.h> @@ -50,7 +48,7 @@ struct videomode; * @MODE_HSYNC: hsync out of range * @MODE_VSYNC: vsync out of range * @MODE_H_ILLEGAL: mode has illegal horizontal timings - * @MODE_V_ILLEGAL: mode has illegal horizontal timings + * @MODE_V_ILLEGAL: mode has illegal vertical timings * @MODE_BAD_WIDTH: requires an unsupported linepitch * @MODE_NOMODE: no mode with a matching name * @MODE_NO_INTERLACE: interlaced mode not supported @@ -138,8 +136,24 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f), \ - .base.type = DRM_MODE_OBJECT_MODE + .vscan = (vs), .flags = (f) + +/** + * DRM_SIMPLE_MODE - Simple display mode + * @hd: Horizontal resolution, width + * @vd: Vertical resolution, height + * @hd_mm: Display width in millimeters + * @vd_mm: Display height in millimeters + * + * This macro initializes a &drm_display_mode that only contains info about + * resolution and physical size. + */ +#define DRM_SIMPLE_MODE(hd, vd, hd_mm, vd_mm) \ + .type = DRM_MODE_TYPE_DRIVER, .clock = 1 /* pass validation */, \ + .hdisplay = (hd), .hsync_start = (hd), .hsync_end = (hd), \ + .htotal = (hd), .vdisplay = (vd), .vsync_start = (vd), \ + .vsync_end = (vd), .vtotal = (vd), .width_mm = (hd_mm), \ + .height_mm = (vd_mm) #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ @@ -216,20 +230,6 @@ struct drm_display_mode { struct list_head head; /** - * @base: - * - * A display mode is a normal modeset object, possibly including public - * userspace id. - * - * FIXME: - * - * This can probably be removed since the entire concept of userspace - * managing modes explicitly has never landed in upstream kernel mode - * setting support. - */ - struct drm_mode_object base; - - /** * @name: * * Human-readable name of the mode, filled out with drm_mode_set_name(). @@ -371,20 +371,13 @@ struct drm_display_mode { int crtc_vtotal; /** - * @private: + * @private_flags: * - * Pointer for driver private data. This can only be used for mode + * Driver private flags. private_flags can only be used for mode * objects passed to drivers in modeset operations. It shouldn't be used * by atomic drivers since they can store any additional data by * subclassing state structures. */ - int *private; - - /** - * @private_flags: - * - * Similar to @private, but just an integer. - */ int private_flags; /** @@ -431,14 +424,14 @@ struct drm_display_mode { /** * DRM_MODE_FMT - printf string for &struct drm_display_mode */ -#define DRM_MODE_FMT "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" +#define DRM_MODE_FMT "\"%s\": %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x" /** * DRM_MODE_ARG - printf arguments for &struct drm_display_mode * @m: display mode */ #define DRM_MODE_ARG(m) \ - (m)->base.id, (m)->name, (m)->vrefresh, (m)->clock, \ + (m)->name, (m)->vrefresh, (m)->clock, \ (m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \ (m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \ (m)->type, (m)->flags @@ -537,7 +530,7 @@ void drm_connector_list_update(struct drm_connector *connector); /* parsing cmdline modes */ bool drm_mode_parse_command_line_for_connector(const char *mode_option, - struct drm_connector *connector, + const struct drm_connector *connector, struct drm_cmdline_mode *mode); struct drm_display_mode * drm_mode_create_from_cmdline_mode(struct drm_device *dev, diff --git a/sys/dev/pci/drm/include/drm/drm_modeset_helper.h b/sys/dev/pci/drm/include/drm/drm_modeset_helper.h index efa337f0312..995fd981cab 100644 --- a/sys/dev/pci/drm/include/drm/drm_modeset_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_modeset_helper.h @@ -23,7 +23,11 @@ #ifndef __DRM_KMS_HELPER_H__ #define __DRM_KMS_HELPER_H__ -#include <drm/drmP.h> +struct drm_crtc; +struct drm_crtc_funcs; +struct drm_device; +struct drm_framebuffer; +struct drm_mode_fb_cmd2; void drm_helper_move_panel_connectors_to_head(struct drm_device *); diff --git a/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h b/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h index 0eb3372d031..7c20b1c8b6a 100644 --- a/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h +++ b/sys/dev/pci/drm/include/drm/drm_modeset_helper_vtables.h @@ -49,6 +49,8 @@ */ enum mode_set_atomic; +struct drm_writeback_connector; +struct drm_writeback_job; /** * struct drm_crtc_helper_funcs - helper operations for CRTCs @@ -418,6 +420,8 @@ struct drm_crtc_helper_funcs { * Drivers can use the @old_crtc_state input parameter if the operations * needed to enable the CRTC don't depend solely on the new state but * also on the transition between the old state and the new state. + * + * This function is optional. */ void (*atomic_enable)(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state); @@ -441,9 +445,58 @@ struct drm_crtc_helper_funcs { * parameter @old_crtc_state which could be used to access the old * state. Atomic drivers should consider to use this one instead * of @disable. + * + * This function is optional. */ void (*atomic_disable)(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state); + + /** + * @get_scanout_position: + * + * Called by vblank timestamping code. + * + * Returns the current display scanout position from a CRTC and an + * optional accurate ktime_get() timestamp of when the position was + * measured. Note that this is a helper callback which is only used + * if a driver uses drm_crtc_vblank_helper_get_vblank_timestamp() + * for the @drm_crtc_funcs.get_vblank_timestamp callback. + * + * Parameters: + * + * crtc: + * The CRTC. + * in_vblank_irq: + * True when called from drm_crtc_handle_vblank(). Some drivers + * need to apply some workarounds for gpu-specific vblank irq + * quirks if the flag is set. + * vpos: + * Target location for current vertical scanout position. + * hpos: + * Target location for current horizontal scanout position. + * stime: + * Target location for timestamp taken immediately before + * scanout position query. Can be NULL to skip timestamp. + * etime: + * Target location for timestamp taken immediately after + * scanout position query. Can be NULL to skip timestamp. + * mode: + * Current display timings. + * + * Returns vpos as a positive number while in active scanout area. + * Returns vpos as a negative number inside vblank, counting the number + * of scanlines to go until end of vblank, e.g., -1 means "one scanline + * until start of active scanout / end of vblank." + * + * Returns: + * + * True on success, false if a reliable scanout position counter could + * not be read out. + */ + bool (*get_scanout_position)(struct drm_crtc *crtc, + bool in_vblank_irq, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode); }; /** @@ -640,22 +693,6 @@ struct drm_encoder_helper_funcs { struct drm_connector_state *conn_state); /** - * @get_crtc: - * - * This callback is used by the legacy CRTC helpers to work around - * deficiencies in its own book-keeping. - * - * Do not use, use atomic helpers instead, which get the book keeping - * right. - * - * FIXME: - * - * Currently only nouveau is using this, and as soon as nouveau is - * atomic we can ditch this hook. - */ - struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder); - - /** * @detect: * * This callback can be used by drivers who want to do detection on the @@ -674,6 +711,52 @@ struct drm_encoder_helper_funcs { struct drm_connector *connector); /** + * @atomic_disable: + * + * This callback should be used to disable the encoder. With the atomic + * drivers it is called before this encoder's CRTC has been shut off + * using their own &drm_crtc_helper_funcs.atomic_disable hook. If that + * sequence is too simple drivers can just add their own driver private + * encoder hooks and call them from CRTC's callback by looping over all + * encoders connected to it using for_each_encoder_on_crtc(). + * + * This callback is a variant of @disable that provides the atomic state + * to the driver. If @atomic_disable is implemented, @disable is not + * called by the helpers. + * + * This hook is only used by atomic helpers. Atomic drivers don't need + * to implement it if there's no need to disable anything at the encoder + * level. To ensure that runtime PM handling (using either DPMS or the + * new "ACTIVE" property) works @atomic_disable must be the inverse of + * @atomic_enable. + */ + void (*atomic_disable)(struct drm_encoder *encoder, + struct drm_atomic_state *state); + + /** + * @atomic_enable: + * + * This callback should be used to enable the encoder. It is called + * after this encoder's CRTC has been enabled using their own + * &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is + * too simple drivers can just add their own driver private encoder + * hooks and call them from CRTC's callback by looping over all encoders + * connected to it using for_each_encoder_on_crtc(). + * + * This callback is a variant of @enable that provides the atomic state + * to the driver. If @atomic_enable is implemented, @enable is not + * called by the helpers. + * + * This hook is only used by atomic helpers, it is the opposite of + * @atomic_disable. Atomic drivers don't need to implement it if there's + * no need to enable anything at the encoder level. To ensure that + * runtime PM handling works @atomic_enable must be the inverse of + * @atomic_disable. + */ + void (*atomic_enable)(struct drm_encoder *encoder, + struct drm_atomic_state *state); + + /** * @disable: * * This callback should be used to disable the encoder. With the atomic @@ -689,6 +772,9 @@ struct drm_encoder_helper_funcs { * handling (using either DPMS or the new "ACTIVE" property) works * @disable must be the inverse of @enable for atomic drivers. * + * For atomic drivers also consider @atomic_disable and save yourself + * from having to read the NOTE below! + * * NOTE: * * With legacy CRTC helpers there's a big semantic difference between @@ -713,11 +799,11 @@ struct drm_encoder_helper_funcs { * hooks and call them from CRTC's callback by looping over all encoders * connected to it using for_each_encoder_on_crtc(). * - * This hook is used only by atomic helpers, for symmetry with @disable. - * Atomic drivers don't need to implement it if there's no need to - * enable anything at the encoder level. To ensure that runtime PM handling - * (using either DPMS or the new "ACTIVE" property) works - * @enable must be the inverse of @disable for atomic drivers. + * This hook is only used by atomic helpers, it is the opposite of + * @disable. Atomic drivers don't need to implement it if there's no + * need to enable anything at the encoder level. To ensure that + * runtime PM handling (using either DPMS or the new "ACTIVE" property) + * works @enable must be the inverse of @disable for atomic drivers. */ void (*enable)(struct drm_encoder *encoder); @@ -900,9 +986,8 @@ struct drm_connector_helper_funcs { * @atomic_best_encoder. * * You can leave this function to NULL if the connector is only - * attached to a single encoder and you are using the atomic helpers. - * In this case, the core will call drm_atomic_helper_best_encoder() - * for you. + * attached to a single encoder. In this case, the core will call + * drm_connector_get_single_encoder() for you. * * RETURNS: * @@ -922,7 +1007,7 @@ struct drm_connector_helper_funcs { * * This function is used by drm_atomic_helper_check_modeset(). * If it is not implemented, the core will fallback to @best_encoder - * (or drm_atomic_helper_best_encoder() if @best_encoder is NULL). + * (or drm_connector_get_single_encoder() if @best_encoder is NULL). * * NOTE: * @@ -973,7 +1058,7 @@ struct drm_connector_helper_funcs { * deadlock. */ int (*atomic_check)(struct drm_connector *connector, - struct drm_connector_state *state); + struct drm_atomic_state *state); /** * @atomic_commit: @@ -989,6 +1074,11 @@ struct drm_connector_helper_funcs { */ void (*atomic_commit)(struct drm_connector *connector, struct drm_connector_state *state); + + int (*prepare_writeback_job)(struct drm_writeback_connector *connector, + struct drm_writeback_job *job); + void (*cleanup_writeback_job)(struct drm_writeback_connector *connector, + struct drm_writeback_job *job); }; /** @@ -1013,7 +1103,7 @@ struct drm_plane_helper_funcs { * @prepare_fb: * * This hook is to prepare a framebuffer for scanout by e.g. pinning - * it's backing storage or relocating it into a contiguous block of + * its backing storage or relocating it into a contiguous block of * VRAM. Other possible preparatory work includes flushing caches. * * This function must not block for outstanding rendering, since it is diff --git a/sys/dev/pci/drm/include/drm/drm_modeset_lock.h b/sys/dev/pci/drm/include/drm/drm_modeset_lock.h index a685d1bb21f..4fc9a43ac45 100644 --- a/sys/dev/pci/drm/include/drm/drm_modeset_lock.h +++ b/sys/dev/pci/drm/include/drm/drm_modeset_lock.h @@ -68,7 +68,7 @@ struct drm_modeset_acquire_ctx { /** * struct drm_modeset_lock - used for locking modeset resources. * @mutex: resource locking - * @head: used to hold it's place on &drm_atomi_state.locked list when + * @head: used to hold its place on &drm_atomi_state.locked list when * part of an atomic update * * Used for locking CRTCs and other modeset resources. @@ -114,6 +114,15 @@ static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock) return ww_mutex_is_locked(&lock->mutex); } +/** + * drm_modeset_lock_assert_held - equivalent to lockdep_assert_held() + * @lock: lock to check + */ +static inline void drm_modeset_lock_assert_held(struct drm_modeset_lock *lock) +{ + lockdep_assert_held(&lock->mutex.base); +} + int drm_modeset_lock(struct drm_modeset_lock *lock, struct drm_modeset_acquire_ctx *ctx); int __must_check drm_modeset_lock_single_interruptible(struct drm_modeset_lock *lock); @@ -130,4 +139,63 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); int drm_modeset_lock_all_ctx(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +/** + * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks + * @dev: drm device + * @ctx: local modeset acquire context, will be dereferenced + * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init() + * @ret: local ret/err/etc variable to track error status + * + * Use these macros to simplify grabbing all modeset locks using a local + * context. This has the advantage of reducing boilerplate, but also properly + * checking return values where appropriate. + * + * Any code run between BEGIN and END will be holding the modeset locks. + * + * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and + * forth between the labels on deadlock and error conditions. + * + * Drivers can acquire additional modeset locks. If any lock acquisition + * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with + * the @ret parameter containing the return value of drm_modeset_lock(). + * + * Returns: + * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN() + * is 0, so no error checking is necessary + */ +#define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret) \ + drm_modeset_acquire_init(&ctx, flags); \ +modeset_lock_retry: \ + ret = drm_modeset_lock_all_ctx(dev, &ctx); \ + if (ret) \ + goto modeset_lock_fail; + +/** + * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks + * @ctx: local modeset acquire context, will be dereferenced + * @ret: local ret/err/etc variable to track error status + * + * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN + * if ret is -EDEADLK. + * + * It's important that you use the same ret variable for begin and end so + * deadlock conditions are properly handled. + * + * Returns: + * ret will be untouched unless it is -EDEADLK on entry. That means that if you + * successfully acquire the locks, ret will be whatever your code sets it to. If + * there is a deadlock or other failure with acquire or backoff, ret will be set + * to that failure. In both of these cases the code between BEGIN/END will not + * be run, so the failure will reflect the inability to grab the locks. + */ +#define DRM_MODESET_LOCK_ALL_END(ctx, ret) \ +modeset_lock_fail: \ + if (ret == -EDEADLK) { \ + ret = drm_modeset_backoff(&ctx); \ + if (!ret) \ + goto modeset_lock_retry; \ + } \ + drm_modeset_drop_locks(&ctx); \ + drm_modeset_acquire_fini(&ctx); + #endif /* DRM_MODESET_LOCK_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_panel.h b/sys/dev/pci/drm/include/drm/drm_panel.h index 675aa1e876c..6193cb555ac 100644 --- a/sys/dev/pci/drm/include/drm/drm_panel.h +++ b/sys/dev/pci/drm/include/drm/drm_panel.h @@ -28,6 +28,7 @@ #include <linux/errno.h> #include <linux/list.h> +struct backlight_device; struct device_node; struct drm_connector; struct drm_device; @@ -36,14 +37,6 @@ struct display_timing; /** * struct drm_panel_funcs - perform operations on a given panel - * @disable: disable panel (turn off back light, etc.) - * @unprepare: turn off panel - * @prepare: turn on panel and perform set up - * @enable: enable panel (turn on back light, etc.) - * @get_modes: add modes to the connector that the panel is attached to and - * return the number of modes added - * @get_timings: copy display timings into the provided array and return - * the number of display timings available * * The .prepare() function is typically called before the display controller * starts to transmit video data. Panel drivers can use this to turn the panel @@ -67,133 +60,134 @@ struct display_timing; * * To save power when no video data is transmitted, a driver can power down * the panel. This is the job of the .unprepare() function. + * + * Backlight can be handled automatically if configured using + * drm_panel_of_backlight(). Then the driver does not need to implement the + * functionality to enable/disable backlight. */ struct drm_panel_funcs { - int (*disable)(struct drm_panel *panel); - int (*unprepare)(struct drm_panel *panel); + /** + * @prepare: + * + * Turn on panel and perform set up. + * + * This function is optional. + */ int (*prepare)(struct drm_panel *panel); + + /** + * @enable: + * + * Enable panel (turn on back light, etc.). + * + * This function is optional. + */ int (*enable)(struct drm_panel *panel); - int (*get_modes)(struct drm_panel *panel); + + /** + * @disable: + * + * Disable panel (turn off back light, etc.). + * + * This function is optional. + */ + int (*disable)(struct drm_panel *panel); + + /** + * @unprepare: + * + * Turn off panel. + * + * This function is optional. + */ + int (*unprepare)(struct drm_panel *panel); + + /** + * @get_modes: + * + * Add modes to the connector that the panel is attached to + * and returns the number of modes added. + * + * This function is mandatory. + */ + int (*get_modes)(struct drm_panel *panel, + struct drm_connector *connector); + + /** + * @get_timings: + * + * Copy display timings into the provided array and return + * the number of display timings available. + * + * This function is optional. + */ int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, struct display_timing *timings); }; /** * struct drm_panel - DRM panel object - * @drm: DRM device owning the panel - * @connector: DRM connector that the panel is attached to - * @dev: parent device of the panel - * @funcs: operations that can be performed on the panel - * @list: panel entry in registry */ struct drm_panel { - struct drm_device *drm; - struct drm_connector *connector; + /** + * @dev: + * + * Parent device of the panel. + */ struct device *dev; + /** + * @backlight: + * + * Backlight device, used to turn on backlight after the call + * to enable(), and to turn off backlight before the call to + * disable(). + * backlight is set by drm_panel_of_backlight() and drivers + * shall not assign it. + */ + struct backlight_device *backlight; + + /** + * @funcs: + * + * Operations that can be performed on the panel. + */ const struct drm_panel_funcs *funcs; + /** + * @connector_type: + * + * Type of the panel as a DRM_MODE_CONNECTOR_* value. This is used to + * initialise the drm_connector corresponding to the panel with the + * correct connector type. + */ + int connector_type; + + /** + * @list: + * + * Panel entry in registry. + */ struct list_head list; }; -/** - * drm_disable_unprepare - power off a panel - * @panel: DRM panel - * - * Calling this function will completely power off a panel (assert the panel's - * reset, turn off power supplies, ...). After this function has completed, it - * is usually no longer possible to communicate with the panel until another - * call to drm_panel_prepare(). - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_unprepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->unprepare) - return panel->funcs->unprepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_disable - disable a panel - * @panel: DRM panel - * - * This will typically turn off the panel's backlight or disable the display - * drivers. For smart panels it should still be possible to communicate with - * the integrated circuitry via any command bus after this call. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_disable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->disable) - return panel->funcs->disable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_prepare - power on a panel - * @panel: DRM panel - * - * Calling this function will enable power and deassert any reset signals to - * the panel. After this has completed it is possible to communicate with any - * integrated circuitry via a command bus. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_prepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->prepare) - return panel->funcs->prepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_enable - enable a panel - * @panel: DRM panel - * - * Calling this function will cause the panel display drivers to be turned on - * and the backlight to be enabled. Content will be visible on screen after - * this call completes. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_enable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->enable) - return panel->funcs->enable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_get_modes - probe the available display modes of a panel - * @panel: DRM panel - * - * The modes probed from the panel are automatically added to the connector - * that the panel is attached to. - * - * Return: The number of modes available from the panel on success or a - * negative error code on failure. - */ -static inline int drm_panel_get_modes(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->get_modes) - return panel->funcs->get_modes(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -void drm_panel_init(struct drm_panel *panel); +void drm_panel_init(struct drm_panel *panel, struct device *dev, + const struct drm_panel_funcs *funcs, + int connector_type); int drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); -int drm_panel_detach(struct drm_panel *panel); +void drm_panel_detach(struct drm_panel *panel); + +int drm_panel_prepare(struct drm_panel *panel); +int drm_panel_unprepare(struct drm_panel *panel); + +int drm_panel_enable(struct drm_panel *panel); +int drm_panel_disable(struct drm_panel *panel); + +int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector); #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct drm_panel *of_drm_find_panel(const struct device_node *np); @@ -204,4 +198,14 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) } #endif +#if IS_ENABLED(CONFIG_DRM_PANEL) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ + (IS_MODULE(CONFIG_DRM) && IS_MODULE(CONFIG_BACKLIGHT_CLASS_DEVICE))) +int drm_panel_of_backlight(struct drm_panel *panel); +#else +static inline int drm_panel_of_backlight(struct drm_panel *panel) +{ + return 0; +} +#endif + #endif diff --git a/sys/dev/pci/drm/include/drm/drm_pci.h b/sys/dev/pci/drm/include/drm/drm_pci.h new file mode 100644 index 00000000000..3941b0255ec --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_pci.h @@ -0,0 +1,63 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_PCI_H_ +#define _DRM_PCI_H_ + +#include <linux/pci.h> + +struct drm_dma_handle; +struct drm_device; +struct drm_driver; +struct drm_master; + +#ifdef CONFIG_PCI + +struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, + size_t align); +void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); + +#else + +static inline struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, + size_t size, size_t align) +{ + return NULL; +} + +static inline void drm_pci_free(struct drm_device *dev, + struct drm_dma_handle *dmah) +{ +} + +#endif + +#endif /* _DRM_PCI_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_plane.h b/sys/dev/pci/drm/include/drm/drm_plane.h index 8a152dc16ea..3f396d94afe 100644 --- a/sys/dev/pci/drm/include/drm/drm_plane.h +++ b/sys/dev/pci/drm/include/drm/drm_plane.h @@ -27,6 +27,9 @@ #include <linux/ctype.h> #include <drm/drm_mode_object.h> #include <drm/drm_color_mgmt.h> +#include <drm/drm_rect.h> +#include <drm/drm_modeset_lock.h> +#include <drm/drm_util.h> struct drm_crtc; struct drm_printer; @@ -66,7 +69,7 @@ struct drm_plane_state { * * Optional fence to wait for before scanning out @fb. The core atomic * code will set this when userspace is using explicit fencing. Do not - * write this directly for a driver's implicit fence, use + * write this field directly for a driver's implicit fence, use * drm_atomic_set_fence_for_plane() to ensure that an explicit fence is * preserved. * @@ -119,6 +122,14 @@ struct drm_plane_state { u16 alpha; /** + * @pixel_blend_mode: + * The alpha blending equation selection, describing how the pixels from + * the current plane are composited with the background. Value can be + * one of DRM_MODE_BLEND_* + */ + uint16_t pixel_blend_mode; + + /** * @rotation: * Rotation of the plane. See drm_plane_create_rotation_property() for * more details. @@ -129,10 +140,11 @@ struct drm_plane_state { * @zpos: * Priority of the given plane on crtc (optional). * - * Note that multiple active planes on the same crtc can have an - * identical zpos value. The rule to solving the conflict is to compare - * the plane object IDs; the plane with a higher ID must be stacked on - * top of a plane with a lower ID. + * User-space may set mutable zpos properties so that multiple active + * planes on the same CRTC have identical zpos values. This is a + * user-space bug, but drivers can solve the conflict by comparing the + * plane object IDs; the plane with a higher ID is stacked on top of a + * plane with a lower ID. * * See drm_plane_create_zpos_property() and * drm_plane_create_zpos_immutable_property() for more details. @@ -162,8 +174,36 @@ struct drm_plane_state { */ enum drm_color_range color_range; - /** @src: clipped source coordinates of the plane (in 16.16) */ - /** @dst: clipped destination coordinates of the plane */ + /** + * @fb_damage_clips: + * + * Blob representing damage (area in plane framebuffer that changed + * since last plane update) as an array of &drm_mode_rect in framebuffer + * coodinates of the attached framebuffer. Note that unlike plane src, + * damage clips are not in 16.16 fixed point. + */ + struct drm_property_blob *fb_damage_clips; + + /** + * @src: + * + * source coordinates of the plane (in 16.16). + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ + /** + * @dst: + * + * clipped destination coordinates of the plane. + * + * When using drm_atomic_helper_check_plane_state(), + * the coordinates are clipped, but the driver may choose + * to use unclipped coordinates instead when the hardware + * performs the clipping automatically. + */ struct drm_rect src, dst; /** @@ -659,6 +699,14 @@ struct drm_plane { * drm_plane_create_rotation_property(). */ struct drm_property *rotation_property; + /** + * @blend_mode_property: + * Optional "pixel blend mode" enum property for this plane. + * Blend mode property represents the alpha blending equation selection, + * describing how the pixels from the current plane are composited with + * the background. + */ + struct drm_property *blend_mode_property; /** * @color_encoding_property: @@ -779,5 +827,39 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) +bool drm_any_plane_has_format(struct drm_device *dev, + u32 format, u64 modifier); +/** + * drm_plane_get_damage_clips_count - Returns damage clips count. + * @state: Plane state. + * + * Simple helper to get the number of &drm_mode_rect clips set by user-space + * during plane update. + * + * Return: Number of clips in plane fb_damage_clips blob property. + */ +static inline unsigned int +drm_plane_get_damage_clips_count(const struct drm_plane_state *state) +{ + return (state && state->fb_damage_clips) ? + state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0; +} + +/** + * drm_plane_get_damage_clips - Returns damage clips. + * @state: Plane state. + * + * Note that this function returns uapi type &drm_mode_rect. Drivers might + * instead be interested in internal &drm_rect which can be obtained by calling + * drm_helper_get_plane_damage_clips(). + * + * Return: Damage clips in plane fb_damage_clips blob property. + */ +static inline struct drm_mode_rect * +drm_plane_get_damage_clips(const struct drm_plane_state *state) +{ + return (struct drm_mode_rect *)((state && state->fb_damage_clips) ? + state->fb_damage_clips->data : NULL); +} #endif diff --git a/sys/dev/pci/drm/include/drm/drm_plane_helper.h b/sys/dev/pci/drm/include/drm/drm_plane_helper.h index 26cee293478..331ebd60b3a 100644 --- a/sys/dev/pci/drm/include/drm/drm_plane_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_plane_helper.h @@ -38,42 +38,7 @@ */ #define DRM_PLANE_HELPER_NO_SCALING (1<<16) -int drm_plane_helper_check_update(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_rect *src, - struct drm_rect *dest, - unsigned int rotation, - int min_scale, - int max_scale, - bool can_position, - bool can_update_disabled, - bool *visible); -int drm_primary_helper_update(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx); -int drm_primary_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; -int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx); -int drm_plane_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); - -/* For use by drm_crtc_helper.c */ -int drm_plane_helper_commit(struct drm_plane *plane, - struct drm_plane_state *plane_state, - struct drm_framebuffer *old_fb); #endif diff --git a/sys/dev/pci/drm/include/drm/drm_prime.h b/sys/dev/pci/drm/include/drm/drm_prime.h index 713c133bef3..e9d4af64f32 100644 --- a/sys/dev/pci/drm/include/drm/drm_prime.h +++ b/sys/dev/pci/drm/include/drm/drm_prime.h @@ -42,7 +42,6 @@ * This just contains the internal &struct dma_buf and handle caches for each * &struct drm_file used by the PRIME core code. */ - struct drm_prime_file_private { /* private: */ struct rwlock lock; @@ -62,26 +61,18 @@ struct drm_device; struct drm_gem_object; struct drm_file; -struct device; +/* core prime functions */ +struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, + struct dma_buf_export_info *exp_info); +void drm_gem_dmabuf_release(struct dma_buf *dma_buf); -struct dma_buf *drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags); +int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle); int drm_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); -struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); - -struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, - struct dma_buf *dma_buf, - struct device *attach_dev); -int drm_gem_prime_fd_to_handle(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, uint32_t *handle); -struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, - struct dma_buf_export_info *exp_info); -void drm_gem_dmabuf_release(struct dma_buf *dma_buf); +/* helper functions for exporting */ int drm_gem_map_attach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach); void drm_gem_map_detach(struct dma_buf *dma_buf, @@ -93,19 +84,27 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir); void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf); void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr); -void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num); -void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, - void *addr); + #ifdef __linux__ +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma); #endif -#ifdef notyet -int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, - dma_addr_t *addrs, int max_pages); -struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); -#endif +struct sg_table *drm_prime_pages_to_sg(struct vm_page **pages, unsigned int nr_pages); +struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj, + int flags); + +/* helper functions for importing */ +struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, + struct dma_buf *dma_buf, + struct device *attach_dev); +struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); + void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); +int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct vm_page **pages, + dma_addr_t *addrs, int max_pages); + #endif /* __DRM_PRIME_H__ */ diff --git a/sys/dev/pci/drm/include/drm/drm_print.h b/sys/dev/pci/drm/include/drm/drm_print.h index e37cd6c8f64..ca7cee8e728 100644 --- a/sys/dev/pci/drm/include/drm/drm_print.h +++ b/sys/dev/pci/drm/include/drm/drm_print.h @@ -30,6 +30,12 @@ #include <linux/printk.h> #include <linux/seq_file.h> #include <linux/device.h> +#include <linux/debugfs.h> + +#include <drm/drm.h> + +/* Do *not* use outside of drm_print.[ch]! */ +extern unsigned int __drm_debug; /** * DOC: print @@ -80,10 +86,14 @@ void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); void __drm_puts_seq_file(struct drm_printer *p, const char *str); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); +void __drm_printfn_err(struct drm_printer *p, struct va_format *vaf); __printf(2, 3) void drm_printf(struct drm_printer *p, const char *f, ...); void drm_puts(struct drm_printer *p, const char *str); +void drm_print_regset32(struct drm_printer *p, struct debugfs_regset32 *regset); +void drm_print_bits(struct drm_printer *p, unsigned long value, + const char * const bits[], unsigned int nbits); __printf(2, 0) /** @@ -223,86 +233,106 @@ static inline struct drm_printer drm_debug_printer(const char *prefix) return p; } -/* - * The following categories are defined: +/** + * drm_err_printer - construct a &drm_printer that outputs to pr_err() + * @prefix: debug output prefix * - * CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ... - * This is the category used by the DRM_DEBUG() macro. + * RETURNS: + * The &drm_printer object + */ +static inline struct drm_printer drm_err_printer(const char *prefix) +{ + struct drm_printer p = { + .printfn = __drm_printfn_err, + .prefix = prefix + }; + return p; +} + +/** + * enum drm_debug_category - The DRM debug categories * - * DRIVER: Used in the vendor specific part of the driver: i915, radeon, ... - * This is the category used by the DRM_DEBUG_DRIVER() macro. + * Each of the DRM debug logging macros use a specific category, and the logging + * is filtered by the drm.debug module parameter. This enum specifies the values + * for the interface. * - * KMS: used in the modesetting code. - * This is the category used by the DRM_DEBUG_KMS() macro. + * Each DRM_DEBUG_<CATEGORY> macro logs to DRM_UT_<CATEGORY> category, except + * DRM_DEBUG() logs to DRM_UT_CORE. * - * PRIME: used in the prime code. - * This is the category used by the DRM_DEBUG_PRIME() macro. + * Enabling verbose debug messages is done through the drm.debug parameter, each + * category being enabled by a bit: * - * ATOMIC: used in the atomic code. - * This is the category used by the DRM_DEBUG_ATOMIC() macro. + * - drm.debug=0x1 will enable CORE messages + * - drm.debug=0x2 will enable DRIVER messages + * - drm.debug=0x3 will enable CORE and DRIVER messages + * - ... + * - drm.debug=0x1ff will enable all messages * - * VBL: used for verbose debug message in the vblank code - * This is the category used by the DRM_DEBUG_VBL() macro. + * An interesting feature is that it's possible to enable verbose logging at + * run-time by echoing the debug value in its sysfs node:: * - * Enabling verbose debug messages is done through the drm.debug parameter, - * each category being enabled by a bit. + * # echo 0xf > /sys/module/drm/parameters/debug * - * drm.debug=0x1 will enable CORE messages - * drm.debug=0x2 will enable DRIVER messages - * drm.debug=0x3 will enable CORE and DRIVER messages - * ... - * drm.debug=0x3f will enable all messages + */ +enum drm_debug_category { + /** + * @DRM_UT_CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, + * drm_memory.c, ... + */ + DRM_UT_CORE = 0x01, + /** + * @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915, + * radeon, ... macro. + */ + DRM_UT_DRIVER = 0x02, + /** + * @DRM_UT_KMS: Used in the modesetting code. + */ + DRM_UT_KMS = 0x04, + /** + * @DRM_UT_PRIME: Used in the prime code. + */ + DRM_UT_PRIME = 0x08, + /** + * @DRM_UT_ATOMIC: Used in the atomic code. + */ + DRM_UT_ATOMIC = 0x10, + /** + * @DRM_UT_VBL: Used for verbose debug message in the vblank code. + */ + DRM_UT_VBL = 0x20, + /** + * @DRM_UT_STATE: Used for verbose atomic state debugging. + */ + DRM_UT_STATE = 0x40, + /** + * @DRM_UT_LEASE: Used in the lease code. + */ + DRM_UT_LEASE = 0x80, + /** + * @DRM_UT_DP: Used in the DP code. + */ + DRM_UT_DP = 0x100, +}; + +static inline bool drm_debug_enabled(enum drm_debug_category category) +{ + return unlikely(__drm_debug & category); +} + +/* + * struct device based logging * - * An interesting feature is that it's possible to enable verbose logging at - * run-time by echoing the debug value in its sysfs node: - * # echo 0xf > /sys/module/drm/parameters/debug + * Prefer drm_device based logging over device or prink based logging. */ -#define DRM_UT_NONE 0x00 -#define DRM_UT_CORE 0x01 -#define DRM_UT_DRIVER 0x02 -#define DRM_UT_KMS 0x04 -#define DRM_UT_PRIME 0x08 -#define DRM_UT_ATOMIC 0x10 -#define DRM_UT_VBL 0x20 -#define DRM_UT_STATE 0x40 -#define DRM_UT_LEASE 0x80 -#define DRM_UT_DP 0x100 __printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, const char *format, ...); __printf(3, 4) -void drm_dev_dbg(const struct device *dev, unsigned int category, +void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, const char *format, ...); -__printf(2, 3) -void drm_dbg(unsigned int category, const char *format, ...); -__printf(1, 2) -void drm_err(const char *format, ...); - -/* Macros to make printk easier */ - -#define _DRM_PRINTK(once, level, fmt, ...) \ - printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__) - -#ifdef DRMDEBUG -#define DRM_INFO(fmt, ...) \ - _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__) -#else -#define DRM_INFO(fmt, arg...) do { } while(/* CONSTCOND */ 0) -#endif -#define DRM_NOTE(fmt, ...) \ - _DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__) -#define DRM_WARN(fmt, ...) \ - _DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__) - -#define DRM_INFO_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__) -#define DRM_NOTE_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__) -#define DRM_WARN_ONCE(fmt, ...) \ - _DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__) - /** * Error output. * @@ -311,8 +341,6 @@ void drm_err(const char *format, ...); */ #define DRM_DEV_ERROR(dev, fmt, ...) \ drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__) -#define DRM_ERROR(fmt, ...) \ - drm_err(fmt, ##__VA_ARGS__) /** * Rate limited error output. Like DRM_ERROR() but won't flood the log. @@ -329,10 +357,8 @@ void drm_err(const char *format, ...); if (__ratelimit(&_rs)) \ DRM_DEV_ERROR(dev, fmt, ##__VA_ARGS__); \ }) -#define DRM_ERROR_RATELIMITED(fmt, ...) \ - DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) -#define DRM_DEV_INFO(dev, fmt, ...) \ +#define DRM_DEV_INFO(dev, fmt, ...) \ drm_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__) #define DRM_DEV_INFO_ONCE(dev, fmt, ...) \ @@ -352,91 +378,169 @@ void drm_err(const char *format, ...); */ #define DRM_DEV_DEBUG(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) -#ifdef DRMDEBUG -#define DRM_DEBUG(fmt, ...) \ - drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__) -#else -#define DRM_DEBUG(fmt, arg...) do { } while(/* CONSTCOND */ 0) -#endif - #define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) -#ifdef DRMDEBUG -#define DRM_DEBUG_DRIVER(fmt, ...) \ - drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__) -#else -#define DRM_DEBUG_DRIVER(fmt, arg...) do { } while(/* CONSTCOND */ 0) -#endif - #define DRM_DEV_DEBUG_KMS(dev, fmt, ...) \ drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) -#ifdef DRMDEBUG + +/* + * struct drm_device based logging + * + * Prefer drm_device based logging over device or prink based logging. + */ + +/* Helper for struct drm_device based logging. */ +#define __drm_printk(drm, level, type, fmt, ...) \ + dev_##level##type((drm)->dev, "[drm] " fmt, ##__VA_ARGS__) + + +#define drm_info(drm, fmt, ...) \ + __drm_printk((drm), info,, fmt, ##__VA_ARGS__) + +#define drm_notice(drm, fmt, ...) \ + __drm_printk((drm), notice,, fmt, ##__VA_ARGS__) + +#define drm_warn(drm, fmt, ...) \ + __drm_printk((drm), warn,, fmt, ##__VA_ARGS__) + +#define drm_err(drm, fmt, ...) \ + __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_info_once(drm, fmt, ...) \ + __drm_printk((drm), info, _once, fmt, ##__VA_ARGS__) + +#define drm_notice_once(drm, fmt, ...) \ + __drm_printk((drm), notice, _once, fmt, ##__VA_ARGS__) + +#define drm_warn_once(drm, fmt, ...) \ + __drm_printk((drm), warn, _once, fmt, ##__VA_ARGS__) + +#define drm_err_once(drm, fmt, ...) \ + __drm_printk((drm), err, _once, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_err_ratelimited(drm, fmt, ...) \ + __drm_printk((drm), err, _ratelimited, "*ERROR* " fmt, ##__VA_ARGS__) + + +#define drm_dbg_core(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_CORE, fmt, ##__VA_ARGS__) +#define drm_dbg(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) +#define drm_dbg_kms(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_KMS, fmt, ##__VA_ARGS__) +#define drm_dbg_prime(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) +#define drm_dbg_atomic(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) +#define drm_dbg_vbl(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) +#define drm_dbg_state(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_STATE, fmt, ##__VA_ARGS__) +#define drm_dbg_lease(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_LEASE, fmt, ##__VA_ARGS__) +#define drm_dbg_dp(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DP, fmt, ##__VA_ARGS__) + + +/* + * printk based logging + * + * Prefer drm_device based logging over device or prink based logging. + */ + +__printf(2, 3) +void __drm_dbg(enum drm_debug_category category, const char *format, ...); +__printf(1, 2) +void __drm_err(const char *format, ...); + +/* Macros to make printk easier */ + +#define _DRM_PRINTK(once, level, fmt, ...) \ + printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__) + +#define DRM_INFO(fmt, ...) \ + _DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__) +#define DRM_NOTE(fmt, ...) \ + _DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__) +#define DRM_WARN(fmt, ...) \ + _DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__) + +#define DRM_INFO_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__) +#define DRM_NOTE_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__) +#define DRM_WARN_ONCE(fmt, ...) \ + _DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__) + +#define DRM_ERROR(fmt, ...) \ + __drm_err(fmt, ##__VA_ARGS__) + +#define DRM_ERROR_RATELIMITED(fmt, ...) \ + DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG(fmt, ...) \ + __drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__) + +#define DRM_DEBUG_DRIVER(fmt, ...) \ + __drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__) + #define DRM_DEBUG_KMS(fmt, ...) \ - drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__) -#else -#define DRM_DEBUG_KMS(fmt, arg...) do { } while(/* CONSTCOND */ 0) -#endif + __drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_PRIME(dev, fmt, ...) \ - drm_dev_dbg(dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__) #define DRM_DEBUG_PRIME(fmt, ...) \ - drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__) + __drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, ...) \ - drm_dev_dbg(dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) #define DRM_DEBUG_ATOMIC(fmt, ...) \ - drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) + __drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_VBL(dev, fmt, ...) \ - drm_dev_dbg(dev, DRM_UT_VBL, fmt, ##__VA_ARGS__) #define DRM_DEBUG_VBL(fmt, ...) \ - drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__) + __drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__) #define DRM_DEBUG_LEASE(fmt, ...) \ - drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) + __drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_DP(dev, fmt, ...) \ - drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__) -#define DRM_DEBUG_DP(dev, fmt, ...) \ - drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) +#define DRM_DEBUG_DP(fmt, ...) \ + __drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) -#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ + +#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ + DEFAULT_RATELIMIT_INTERVAL, \ + DEFAULT_RATELIMIT_BURST); \ if (__ratelimit(&_rs)) \ - drm_dev_dbg(dev, category, fmt, ##__VA_ARGS__); \ + drm_dev_dbg(NULL, DRM_UT_KMS, fmt, ##__VA_ARGS__); \ }) -/** - * Rate limited debug output. Like DRM_DEBUG() but won't flood the log. +/* + * struct drm_device based WARNs * - * @dev: device pointer - * @fmt: printf() like format string. + * drm_WARN*() acts like WARN*(), but with the key difference of + * using device specific information so that we know from which device + * warning is originating from. + * + * Prefer drm_device based drm_WARN* over regular WARN* */ -#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, ...) \ - _DEV_DRM_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_CORE, \ - fmt, ##__VA_ARGS__) -#define DRM_DEBUG_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__) - -#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, ...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_DRIVER, \ - fmt, ##__VA_ARGS__) -#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__) - -#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, ...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_KMS, \ - fmt, ##__VA_ARGS__) -#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__) -#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, ...) \ - _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \ - fmt, ##__VA_ARGS__) -#define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...) \ - DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__) +/* Helper for struct drm_device based WARNs */ +#define drm_WARN(drm, condition, format, arg...) \ + WARN(condition, "%s %s: " format, \ + dev_driver_string((drm)->dev), \ + dev_name((drm)->dev), ## arg) + +#define drm_WARN_ONCE(drm, condition, format, arg...) \ + WARN_ONCE(condition, "%s %s: " format, \ + dev_driver_string((drm)->dev), \ + dev_name((drm)->dev), ## arg) + +#define drm_WARN_ON(drm, x) \ + drm_WARN((drm), (x), "%s", \ + "drm_WARN_ON(" __stringify(x) ")") + +#define drm_WARN_ON_ONCE(drm, x) \ + drm_WARN_ONCE((drm), (x), "%s", \ + "drm_WARN_ON_ONCE(" __stringify(x) ")") #endif /* DRM_PRINT_H_ */ diff --git a/sys/dev/pci/drm/include/drm/drm_probe_helper.h b/sys/dev/pci/drm/include/drm/drm_probe_helper.h new file mode 100644 index 00000000000..8d3ed2834d3 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_probe_helper.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +#ifndef __DRM_PROBE_HELPER_H__ +#define __DRM_PROBE_HELPER_H__ + +#include <linux/types.h> + +struct drm_connector; +struct drm_device; +struct drm_modeset_acquire_ctx; + +int drm_helper_probe_single_connector_modes(struct drm_connector + *connector, uint32_t maxX, + uint32_t maxY); +int drm_helper_probe_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force); +void drm_kms_helper_poll_init(struct drm_device *dev); +void drm_kms_helper_poll_fini(struct drm_device *dev); +bool drm_helper_hpd_irq_event(struct drm_device *dev); +void drm_kms_helper_hotplug_event(struct drm_device *dev); + +void drm_kms_helper_poll_disable(struct drm_device *dev); +void drm_kms_helper_poll_enable(struct drm_device *dev); +bool drm_kms_helper_is_poll_worker(void); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_property.h b/sys/dev/pci/drm/include/drm/drm_property.h index c030f6ccab9..4a0a80d658c 100644 --- a/sys/dev/pci/drm/include/drm/drm_property.h +++ b/sys/dev/pci/drm/include/drm/drm_property.h @@ -27,6 +27,8 @@ #include <linux/ctype.h> #include <drm/drm_mode_object.h> +#include <uapi/drm/drm_mode.h> + /** * struct drm_property_enum - symbolic values for enumerations * @value: numeric property value for this enum entry @@ -151,7 +153,8 @@ struct drm_property { * userspace. The kernel is allowed to update the value of these * properties. This is generally used to expose probe state to * userspace, e.g. the EDID, or the connector path property on DP - * MST sinks. + * MST sinks. Kernel can update the value of an immutable property + * by calling drm_object_property_set_value(). */ uint32_t flags; diff --git a/sys/dev/pci/drm/include/drm/drm_rect.h b/sys/dev/pci/drm/include/drm/drm_rect.h index 6c54544a4be..57a3be9e53e 100644 --- a/sys/dev/pci/drm/include/drm/drm_rect.h +++ b/sys/dev/pci/drm/include/drm/drm_rect.h @@ -24,6 +24,8 @@ #ifndef DRM_RECT_H #define DRM_RECT_H +#include <linux/types.h> + /** * DOC: rect utils * @@ -70,6 +72,23 @@ struct drm_rect { (r)->y1 >> 16, (((r)->y1 & 0xffff) * 15625) >> 10 /** + * drm_rect_init - initialize the rectangle from x/y/w/h + * @r: rectangle + * @x: x coordinate + * @y: y coordinate + * @width: width + * @height: height + */ +static inline void drm_rect_init(struct drm_rect *r, int x, int y, + int width, int height) +{ + r->x1 = x; + r->y1 = y; + r->x2 = x + width; + r->y2 = y + height; +} + +/** * drm_rect_adjust_size - adjust the size of the rectangle * @r: rectangle to be adjusted * @dw: horizontal adjustment @@ -107,6 +126,20 @@ static inline void drm_rect_translate(struct drm_rect *r, int dx, int dy) } /** + * drm_rect_translate_to - translate the rectangle to an absolute position + * @r: rectangle to be tranlated + * @x: horizontal position + * @y: vertical position + * + * Move rectangle @r to @x in the horizontal direction, + * and to @y in the vertical direction. + */ +static inline void drm_rect_translate_to(struct drm_rect *r, int x, int y) +{ + drm_rect_translate(r, x - r->x1, y - r->y1); +} + +/** * drm_rect_downscale - downscale a rectangle * @r: rectangle to be downscaled * @horz: horizontal downscale factor @@ -182,12 +215,6 @@ int drm_rect_calc_hscale(const struct drm_rect *src, int drm_rect_calc_vscale(const struct drm_rect *src, const struct drm_rect *dst, int min_vscale, int max_vscale); -int drm_rect_calc_hscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_hscale, int max_hscale); -int drm_rect_calc_vscale_relaxed(struct drm_rect *src, - struct drm_rect *dst, - int min_vscale, int max_vscale); void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point); void drm_rect_rotate(struct drm_rect *r, diff --git a/sys/dev/pci/drm/include/drm/drm_scdc_helper.h b/sys/dev/pci/drm/include/drm/drm_scdc_helper.h index f92eb2094d6..6a483533aae 100644 --- a/sys/dev/pci/drm/include/drm/drm_scdc_helper.h +++ b/sys/dev/pci/drm/include/drm/drm_scdc_helper.h @@ -50,9 +50,9 @@ #define SCDC_READ_REQUEST_ENABLE (1 << 0) #define SCDC_STATUS_FLAGS_0 0x40 -#define SCDC_CH2_LOCK (1 < 3) -#define SCDC_CH1_LOCK (1 < 2) -#define SCDC_CH0_LOCK (1 < 1) +#define SCDC_CH2_LOCK (1 << 3) +#define SCDC_CH1_LOCK (1 << 2) +#define SCDC_CH0_LOCK (1 << 1) #define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) #define SCDC_CLOCK_DETECT (1 << 0) diff --git a/sys/dev/pci/drm/include/drm/drm_self_refresh_helper.h b/sys/dev/pci/drm/include/drm/drm_self_refresh_helper.h new file mode 100644 index 00000000000..520235c2070 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_self_refresh_helper.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2019 Google, Inc. + * + * Authors: + * Sean Paul <seanpaul@chromium.org> + */ +#ifndef DRM_SELF_REFRESH_HELPER_H_ +#define DRM_SELF_REFRESH_HELPER_H_ + +struct drm_atomic_state; +struct drm_crtc; + +void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state); +void drm_self_refresh_helper_update_avg_times(struct drm_atomic_state *state, + unsigned int commit_time_ms, + unsigned int new_self_refresh_mask); + +int drm_self_refresh_helper_init(struct drm_crtc *crtc); +void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc); +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_syncobj.h b/sys/dev/pci/drm/include/drm/drm_syncobj.h index 3980602472c..6cf7243a1dc 100644 --- a/sys/dev/pci/drm/include/drm/drm_syncobj.h +++ b/sys/dev/pci/drm/include/drm/drm_syncobj.h @@ -26,9 +26,10 @@ #ifndef __DRM_SYNCOBJ_H__ #define __DRM_SYNCOBJ_H__ -#include "linux/dma-fence.h" +#include <linux/dma-fence.h> +#include <linux/dma-fence-chain.h> -struct drm_syncobj_cb; +struct drm_file; /** * struct drm_syncobj - sync object. @@ -62,25 +63,6 @@ struct drm_syncobj { struct file *file; }; -typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj, - struct drm_syncobj_cb *cb); - -/** - * struct drm_syncobj_cb - callback for drm_syncobj_add_callback - * @node: used by drm_syncob_add_callback to append this struct to - * &drm_syncobj.cb_list - * @func: drm_syncobj_func_t to call - * - * This struct will be initialized by drm_syncobj_add_callback, additional - * data can be passed along by embedding drm_syncobj_cb in another struct. - * The callback will get called the next time drm_syncobj_replace_fence is - * called. - */ -struct drm_syncobj_cb { - struct list_head node; - drm_syncobj_func_t func; -}; - void drm_syncobj_free(struct kref *kref); /** @@ -131,15 +113,14 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj) struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle); -void drm_syncobj_add_callback(struct drm_syncobj *syncobj, - struct drm_syncobj_cb *cb, - drm_syncobj_func_t func); -void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, - struct drm_syncobj_cb *cb); +void drm_syncobj_add_point(struct drm_syncobj *syncobj, + struct dma_fence_chain *chain, + struct dma_fence *fence, + uint64_t point); void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, struct dma_fence *fence); int drm_syncobj_find_fence(struct drm_file *file_private, - u32 handle, + u32 handle, u64 point, u64 flags, struct dma_fence **fence); void drm_syncobj_free(struct kref *kref); int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, diff --git a/sys/dev/pci/drm/include/drm/drm_sysfs.h b/sys/dev/pci/drm/include/drm/drm_sysfs.h new file mode 100644 index 00000000000..df8af5c4e47 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_sysfs.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef _DRM_SYSFS_H_ +#define _DRM_SYSFS_H_ + +struct drm_device; + +void drm_sysfs_hotplug_event(struct drm_device *); + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_util.h b/sys/dev/pci/drm/include/drm/drm_util.h new file mode 100644 index 00000000000..79952d8c4bb --- /dev/null +++ b/sys/dev/pci/drm/include/drm/drm_util.h @@ -0,0 +1,83 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 2018 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_UTIL_H_ +#define _DRM_UTIL_H_ + +/** + * DOC: drm utils + * + * Macros and inline functions that does not naturally belong in other places + */ + +#include <linux/interrupt.h> +#include <linux/kgdb.h> +#include <linux/preempt.h> +#include <linux/smp.h> + +/* + * Use EXPORT_SYMBOL_FOR_TESTS_ONLY() for functions that shall + * only be visible for drmselftests. + */ +#if defined(CONFIG_DRM_EXPORT_FOR_TESTS) +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) +#else +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) +#endif + +/** + * for_each_if - helper for handling conditionals in various for_each macros + * @condition: The condition to check + * + * Typical use:: + * + * #define for_each_foo_bar(x, y) \' + * list_for_each_entry(x, y->list, head) \' + * for_each_if(x->something == SOMETHING) + * + * The for_each_if() macro makes the use of for_each_foo_bar() less error + * prone. + */ +#define for_each_if(condition) if (!(condition)) {} else + +/** + * drm_can_sleep - returns true if currently okay to sleep + * + * This function shall not be used in new code. + * The check for running in atomic context may not work - see linux/preempt.h. + * + * FIXME: All users of drm_can_sleep should be removed (see todo.rst) + * + * Returns: + * False if kgdb is active, we are in atomic context or irqs are disabled. + */ +static inline bool drm_can_sleep(void) +{ + if (in_atomic() || in_dbg_master() || irqs_disabled()) + return false; + return true; +} + +#endif diff --git a/sys/dev/pci/drm/include/drm/drm_utils.h b/sys/dev/pci/drm/include/drm/drm_utils.h index a803988d857..70775748d24 100644 --- a/sys/dev/pci/drm/include/drm/drm_utils.h +++ b/sys/dev/pci/drm/include/drm/drm_utils.h @@ -10,6 +10,10 @@ #ifndef __DRM_UTILS_H__ #define __DRM_UTILS_H__ +#include <linux/types.h> + int drm_get_panel_orientation_quirk(int width, int height); +signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec); + #endif diff --git a/sys/dev/pci/drm/include/drm/drm_vblank.h b/sys/dev/pci/drm/include/drm/drm_vblank.h index f731cca4447..925332d1865 100644 --- a/sys/dev/pci/drm/include/drm/drm_vblank.h +++ b/sys/dev/pci/drm/include/drm/drm_vblank.h @@ -30,7 +30,6 @@ #include <drm/drm_file.h> #include <drm/drm_modes.h> -#include <uapi/drm/drm.h> struct drm_device; struct drm_crtc; @@ -95,7 +94,7 @@ struct drm_vblank_crtc { /** * @queue: Wait queue for vblank waiters. */ - wait_queue_head_t queue; /**< VBLANK wait queue */ + wait_queue_head_t queue; /** * @disable_timer: Disable timer for the delayed vblank disabling * hysteresis logic. Vblank disabling is controlled through the @@ -107,12 +106,23 @@ struct drm_vblank_crtc { /** * @seqlock: Protect vblank count and time. */ - seqlock_t seqlock; /* protects vblank count and time */ + seqlock_t seqlock; /** - * @count: Current software vblank counter. + * @count: + * + * Current software vblank counter. + * + * Note that for a given vblank counter value drm_crtc_handle_vblank() + * and drm_crtc_vblank_count() or drm_crtc_vblank_count_and_time() + * provide a barrier: Any writes done before calling + * drm_crtc_handle_vblank() will be visible to callers of the later + * functions, iff the vblank count is the same or a later one. + * + * IMPORTANT: This guarantee requires barriers, therefor never access + * this field directly. Use drm_crtc_vblank_count() instead. */ - u64 count; + atomic64_t count; /** * @time: Vblank timestamp corresponding to @count. */ @@ -123,7 +133,7 @@ struct drm_vblank_crtc { * this refcount reaches 0 can the hardware interrupt be disabled using * @disable_timer. */ - atomic_t refcount; /* number of users of vblank interruptsper crtc */ + atomic_t refcount; /** * @last: Protected by &drm_device.vbl_lock, used for wraparound handling. */ @@ -156,7 +166,7 @@ struct drm_vblank_crtc { * call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly * save and restore the vblank count. */ - unsigned int inmodeset; /* Display driver is setting mode */ + unsigned int inmodeset; /** * @pipe: drm_crtc_index() of the &drm_crtc corresponding to this * structure. @@ -164,13 +174,13 @@ struct drm_vblank_crtc { unsigned int pipe; /** * @framedur_ns: Frame/Field duration in ns, used by - * drm_calc_vbltimestamp_from_scanoutpos() and computed by + * drm_crtc_vblank_helper_get_vblank_timestamp() and computed by * drm_calc_timestamping_constants(). */ int framedur_ns; /** * @linedur_ns: Line duration in ns, used by - * drm_calc_vbltimestamp_from_scanoutpos() and computed by + * drm_crtc_vblank_helper_get_vblank_timestamp() and computed by * drm_calc_timestamping_constants(). */ int linedur_ns; @@ -180,8 +190,8 @@ struct drm_vblank_crtc { * * Cache of the current hardware display mode. Only valid when @enabled * is set. This is used by helpers like - * drm_calc_vbltimestamp_from_scanoutpos(). We can't just access the - * hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode, + * drm_crtc_vblank_helper_get_vblank_timestamp(). We can't just access + * the hardware mode by e.g. looking at &drm_crtc_state.adjusted_mode, * because that one is really hard to get from interrupt context. */ struct drm_display_mode hwmode; @@ -196,6 +206,7 @@ struct drm_vblank_crtc { }; int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); +bool drm_dev_has_vblank(const struct drm_device *dev); u64 drm_crtc_vblank_count(struct drm_crtc *crtc); u64 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, ktime_t *vblanktime); @@ -219,13 +230,32 @@ u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc); void drm_vblank_restore(struct drm_device *dev, unsigned int pipe); void drm_crtc_vblank_restore(struct drm_crtc *crtc); -bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, - unsigned int pipe, int *max_error, - ktime_t *vblank_time, - bool in_vblank_irq); void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode); wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc); void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, u32 max_vblank_count); + +/* + * Helpers for struct drm_crtc_funcs + */ + +typedef bool (*drm_vblank_get_scanout_position_func)(struct drm_crtc *crtc, + bool in_vblank_irq, + int *vpos, int *hpos, + ktime_t *stime, + ktime_t *etime, + const struct drm_display_mode *mode); + +bool +drm_crtc_vblank_helper_get_vblank_timestamp_internal(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq, + drm_vblank_get_scanout_position_func get_scanout_position); +bool drm_crtc_vblank_helper_get_vblank_timestamp(struct drm_crtc *crtc, + int *max_error, + ktime_t *vblank_time, + bool in_vblank_irq); + #endif diff --git a/sys/dev/pci/drm/include/drm/drm_vma_manager.h b/sys/dev/pci/drm/include/drm/drm_vma_manager.h index 1872c27f080..0a1812412b4 100644 --- a/sys/dev/pci/drm/include/drm/drm_vma_manager.h +++ b/sys/dev/pci/drm/include/drm/drm_vma_manager.h @@ -1,4 +1,4 @@ -/* $OpenBSD: drm_vma_manager.h,v 1.2 2020/01/22 07:52:31 jsg Exp $ */ +/* $OpenBSD: drm_vma_manager.h,v 1.3 2020/06/08 04:48:14 jsg Exp $ */ #ifndef __DRM_VMA_MANAGER_H__ #define __DRM_VMA_MANAGER_H__ @@ -30,6 +30,20 @@ #include <linux/spinlock.h> #include <linux/types.h> +/* We make up offsets for buffer objects so we can recognize them at + * mmap time. pgoff in mmap is an unsigned long, so we need to make sure + * that the faked up offset will fit + */ +#if BITS_PER_LONG == 64 +#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) +#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 256) +#else +#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1) +#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) +#endif + +struct drm_file; + struct drm_vma_offset_file { struct rb_node vm_rb; struct file *vm_filp; @@ -54,9 +68,6 @@ void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr, unsigned long page_offset, unsigned long size); void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr); -struct drm_vma_offset_node *drm_vma_offset_lookup(struct drm_vma_offset_manager *mgr, - unsigned long start, - unsigned long pages); struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr, unsigned long start, unsigned long pages); @@ -71,25 +82,25 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, struct file *filp); /** - * drm_vma_offset_exact_lookup() - Look up node by exact address + * drm_vma_offset_exact_lookup_locked() - Look up node by exact address * @mgr: Manager object * @start: Start address (page-based, not byte-based) * @pages: Size of object (page-based) * - * Same as drm_vma_offset_lookup() but does not allow any offset into the node. + * Same as drm_vma_offset_lookup_locked() but does not allow any offset into the node. * It only returns the exact object with the given start address. * * RETURNS: * Node at exact start address @start. */ static inline struct drm_vma_offset_node * -drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr, - unsigned long start, - unsigned long pages) +drm_vma_offset_exact_lookup_locked(struct drm_vma_offset_manager *mgr, + unsigned long start, + unsigned long pages) { struct drm_vma_offset_node *node; - node = drm_vma_offset_lookup(mgr, start, pages); + node = drm_vma_offset_lookup_locked(mgr, start, pages); return (node && node->vm_node.start == start) ? node : NULL; } @@ -97,7 +108,7 @@ drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr, * drm_vma_offset_lock_lookup() - Lock lookup for extended private use * @mgr: Manager object * - * Lock VMA manager for extended lookups. Only *_locked() VMA function calls + * Lock VMA manager for extended lookups. Only locked VMA function calls * are allowed while holding this lock. All other contexts are blocked from VMA * until the lock is released via drm_vma_offset_unlock_lookup(). * @@ -108,13 +119,6 @@ drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr, * not call any other VMA helpers while holding this lock. * * Note: You're in atomic-context while holding this lock! - * - * Example: - * drm_vma_offset_lock_lookup(mgr); - * node = drm_vma_offset_lookup_locked(mgr); - * if (node) - * kref_get_unless_zero(container_of(node, sth, entr)); - * drm_vma_offset_unlock_lookup(mgr); */ static inline void drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr) { @@ -186,19 +190,6 @@ static inline unsigned long drm_vma_node_size(struct drm_vma_offset_node *node) } /** - * drm_vma_node_has_offset() - Check whether node is added to offset manager - * @node: Node to be checked - * - * RETURNS: - * true iff the node was previously allocated an offset and added to - * an vma offset manager. - */ -static inline bool drm_vma_node_has_offset(struct drm_vma_offset_node *node) -{ - return drm_mm_node_allocated(&node->vm_node); -} - -/** * drm_vma_node_offset_addr() - Return sanitized offset for user-space mmaps * @node: Linked offset node * @@ -222,8 +213,8 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) * @file_mapping: Address space to unmap @node from * * Unmap all userspace mappings for a given offset node. The mappings must be - * associated with the @file_mapping address-space. If no offset exists or - * the address-space is invalid, nothing is done. + * associated with the @file_mapping address-space. If no offset exists + * nothing is done. * * This call is unlocked. The caller must guarantee that drm_vma_offset_remove() * is not called on this node concurrently. @@ -231,7 +222,7 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, struct address_space *file_mapping) { - if (file_mapping && drm_vma_node_has_offset(node)) + if (drm_mm_node_allocated(&node->vm_node)) unmap_mapping_range(file_mapping, drm_vma_node_offset_addr(node), drm_vma_node_size(node) << PAGE_SHIFT, 1); diff --git a/sys/dev/pci/drm/include/drm/drm_writeback.h b/sys/dev/pci/drm/include/drm/drm_writeback.h index 41e20c57771..64a01ba27ab 100644 --- a/sys/dev/pci/drm/include/drm/drm_writeback.h +++ b/sys/dev/pci/drm/include/drm/drm_writeback.h @@ -1,7 +1,7 @@ /* Public domain. */ -#ifndef DRM_WRITEBACK_H -#define DRM_WRITEBACK_H +#ifndef _DRM_WRITEBACK_H +#define _DRM_WRITEBACK_H #include <drm/drm_connector.h> @@ -26,4 +26,21 @@ drm_writeback_get_out_fence(struct drm_writeback_connector *connector) return NULL; } +static inline void +drm_writeback_cleanup_job(struct drm_writeback_job *j) +{ +} + +static inline int +drm_writeback_prepare_job(struct drm_writeback_job *j) +{ + return 0; +} + +static inline int +drm_writeback_set_fb(struct drm_connector_state *cs, struct drm_framebuffer *fb) +{ + return 0; +} + #endif diff --git a/sys/dev/pci/drm/include/drm/gpu_scheduler.h b/sys/dev/pci/drm/include/drm/gpu_scheduler.h index abbc5481430..2241239cd7a 100644 --- a/sys/dev/pci/drm/include/drm/gpu_scheduler.h +++ b/sys/dev/pci/drm/include/drm/gpu_scheduler.h @@ -26,6 +26,7 @@ #include <drm/spsc_queue.h> #include <linux/dma-fence.h> +#include <linux/completion.h> #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) @@ -50,7 +51,11 @@ enum drm_sched_priority { * * @list: used to append this struct to the list of entities in the * runqueue. - * @rq: runqueue to which this entity belongs. + * @rq: runqueue on which this entity is currently scheduled. + * @sched_list: A list of schedulers (drm_gpu_schedulers). + * Jobs from this entity can be scheduled on any scheduler + * on this list. + * @num_sched_list: number of drm_gpu_schedulers in the sched_list. * @rq_lock: lock to modify the runqueue to which this entity belongs. * @job_queue: the list of jobs of this entity. * @fence_seq: a linearly increasing seqno incremented with each @@ -67,6 +72,8 @@ enum drm_sched_priority { * @fini_status: contains the exit status in case the process was signalled. * @last_scheduled: points to the finished fence of the last scheduled job. * @last_user: last group leader pushing a job into the entity. + * @stopped: Marks the enity as removed from rq and destined for termination. + * @entity_idle: Signals when enityt is not in use * * Entities will emit jobs in order to their corresponding hardware * ring, and the scheduler will alternate between entities based on @@ -75,6 +82,9 @@ enum drm_sched_priority { struct drm_sched_entity { struct list_head list; struct drm_sched_rq *rq; + struct drm_gpu_scheduler **sched_list; + unsigned int num_sched_list; + enum drm_sched_priority priority; spinlock_t rq_lock; struct spsc_queue job_queue; @@ -91,6 +101,8 @@ struct drm_sched_entity { #else struct process *last_user; #endif + bool stopped; + struct completion entity_idle; }; /** @@ -135,10 +147,6 @@ struct drm_sched_fence { struct dma_fence finished; /** - * @cb: the callback for the parent fence below. - */ - struct dma_fence_cb cb; - /** * @parent: the fence returned by &drm_sched_backend_ops.run_job * when scheduling the job on hardware. We signal the * &drm_sched_fence.finished fence once parent is signalled. @@ -168,18 +176,14 @@ struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); * @sched: the scheduler instance on which this job is scheduled. * @s_fence: contains the fences for the scheduling of job. * @finish_cb: the callback for the finished fence. - * @finish_work: schedules the function @drm_sched_job_finish once the job has - * finished to remove the job from the - * @drm_gpu_scheduler.ring_mirror_list. * @node: used to append this struct to the @drm_gpu_scheduler.ring_mirror_list. - * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the timeout - * interval is over. * @id: a unique id assigned to each job scheduled on the scheduler. * @karma: increment on every hang caused by this job. If this exceeds the hang * limit of the scheduler then the job is marked guilty and will not * be scheduled further. * @s_priority: the priority of the job. * @entity: the entity to which this job belongs. + * @cb: the callback for the parent fence in s_fence. * * A job is created by the driver using drm_sched_job_init(), and * should call drm_sched_entity_push_job() once it wants the scheduler @@ -190,13 +194,12 @@ struct drm_sched_job { struct drm_gpu_scheduler *sched; struct drm_sched_fence *s_fence; struct dma_fence_cb finish_cb; - struct work_struct finish_work; struct list_head node; - struct delayed_work work_tdr; uint64_t id; atomic_t karma; enum drm_sched_priority s_priority; struct drm_sched_entity *entity; + struct dma_fence_cb cb; }; static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, @@ -256,11 +259,16 @@ struct drm_sched_backend_ops { * finished. * @hw_rq_count: the number of jobs currently in the hardware queue. * @job_id_count: used to assign unique id to the each job. + * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the + * timeout interval is over. * @thread: the kthread on which the scheduler which run. * @ring_mirror_list: the list of jobs which are currently in the job queue. * @job_list_lock: lock to protect the ring_mirror_list. * @hang_limit: once the hangs by a job crosses this limit then it is marked * guilty and it will be considered for scheduling further. + * @num_jobs: the number of jobs in queue in the scheduler + * @ready: marks if the underlying HW is ready to work + * @free_guilty: A hit to time out handler to free the guilty job. * * One scheduler is implemented for each hardware ring. */ @@ -274,6 +282,7 @@ struct drm_gpu_scheduler { wait_queue_head_t job_scheduled; atomic_t hw_rq_count; atomic64_t job_id_count; + struct delayed_work work_tdr; #ifdef __linux__ struct task_struct *thread; #else @@ -282,38 +291,66 @@ struct drm_gpu_scheduler { struct list_head ring_mirror_list; spinlock_t job_list_lock; int hang_limit; + atomic_t num_jobs; + bool ready; + bool free_guilty; }; int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, uint32_t hw_submission, unsigned hang_limit, long timeout, const char *name); + void drm_sched_fini(struct drm_gpu_scheduler *sched); +int drm_sched_job_init(struct drm_sched_job *job, + struct drm_sched_entity *entity, + void *owner); +void drm_sched_entity_modify_sched(struct drm_sched_entity *entity, + struct drm_gpu_scheduler **sched_list, + unsigned int num_sched_list); + +void drm_sched_job_cleanup(struct drm_sched_job *job); +void drm_sched_wakeup(struct drm_gpu_scheduler *sched); +void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); +void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery); +void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); +void drm_sched_increase_karma(struct drm_sched_job *bad); +bool drm_sched_dependency_optimized(struct dma_fence* fence, + struct drm_sched_entity *entity); +void drm_sched_fault(struct drm_gpu_scheduler *sched); +void drm_sched_job_kickout(struct drm_sched_job *s_job); + +void drm_sched_rq_add_entity(struct drm_sched_rq *rq, + struct drm_sched_entity *entity); +void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, + struct drm_sched_entity *entity); int drm_sched_entity_init(struct drm_sched_entity *entity, - struct drm_sched_rq **rq_list, - unsigned int num_rq_list, + enum drm_sched_priority priority, + struct drm_gpu_scheduler **sched_list, + unsigned int num_sched_list, atomic_t *guilty); long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout); void drm_sched_entity_fini(struct drm_sched_entity *entity); void drm_sched_entity_destroy(struct drm_sched_entity *entity); +void drm_sched_entity_select_rq(struct drm_sched_entity *entity); +struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity); void drm_sched_entity_push_job(struct drm_sched_job *sched_job, struct drm_sched_entity *entity); -void drm_sched_entity_set_rq(struct drm_sched_entity *entity, - struct drm_sched_rq *rq); +void drm_sched_entity_set_priority(struct drm_sched_entity *entity, + enum drm_sched_priority priority); +bool drm_sched_entity_is_ready(struct drm_sched_entity *entity); struct drm_sched_fence *drm_sched_fence_create( struct drm_sched_entity *s_entity, void *owner); void drm_sched_fence_scheduled(struct drm_sched_fence *fence); void drm_sched_fence_finished(struct drm_sched_fence *fence); -int drm_sched_job_init(struct drm_sched_job *job, - struct drm_sched_entity *entity, - void *owner); -void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, - struct drm_sched_job *job); -void drm_sched_job_recovery(struct drm_gpu_scheduler *sched); -bool drm_sched_dependency_optimized(struct dma_fence* fence, - struct drm_sched_entity *entity); -void drm_sched_job_kickout(struct drm_sched_job *s_job); + +unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched); +void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched, + unsigned long remaining); +struct drm_gpu_scheduler * +drm_sched_pick_best(struct drm_gpu_scheduler **sched_list, + unsigned int num_sched_list); #endif diff --git a/sys/dev/pci/drm/include/drm/i2c/ch7006.h b/sys/dev/pci/drm/include/drm/i2c/ch7006.h new file mode 100644 index 00000000000..8390b437a1f --- /dev/null +++ b/sys/dev/pci/drm/include/drm/i2c/ch7006.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __DRM_I2C_CH7006_H__ +#define __DRM_I2C_CH7006_H__ + +/** + * struct ch7006_encoder_params + * + * Describes how the ch7006 is wired up with the GPU. It should be + * used as the @params parameter of its @set_config method. + * + * See "http://www.chrontel.com/pdf/7006.pdf" for their precise + * meaning. + */ +struct ch7006_encoder_params { + enum { + CH7006_FORMAT_RGB16 = 0, + CH7006_FORMAT_YCrCb24m16, + CH7006_FORMAT_RGB24m16, + CH7006_FORMAT_RGB15, + CH7006_FORMAT_RGB24m12C, + CH7006_FORMAT_RGB24m12I, + CH7006_FORMAT_RGB24m8, + CH7006_FORMAT_RGB16m8, + CH7006_FORMAT_RGB15m8, + CH7006_FORMAT_YCrCb24m8, + } input_format; + + enum { + CH7006_CLOCK_SLAVE = 0, + CH7006_CLOCK_MASTER, + } clock_mode; + + enum { + CH7006_CLOCK_EDGE_NEG = 0, + CH7006_CLOCK_EDGE_POS, + } clock_edge; + + int xcm, pcm; + + enum { + CH7006_SYNC_SLAVE = 0, + CH7006_SYNC_MASTER, + } sync_direction; + + enum { + CH7006_SYNC_SEPARATED = 0, + CH7006_SYNC_EMBEDDED, + } sync_encoding; + + enum { + CH7006_POUT_1_8V = 0, + CH7006_POUT_3_3V, + } pout_level; + + enum { + CH7006_ACTIVE_HSYNC = 0, + CH7006_ACTIVE_DSTART, + } active_detect; +}; + +#endif diff --git a/sys/dev/pci/drm/include/drm/i2c/sil164.h b/sys/dev/pci/drm/include/drm/i2c/sil164.h new file mode 100644 index 00000000000..205e27384c8 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/i2c/sil164.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __DRM_I2C_SIL164_H__ +#define __DRM_I2C_SIL164_H__ + +/** + * struct sil164_encoder_params + * + * Describes how the sil164 is connected to the GPU. It should be used + * as the @params parameter of its @set_config method. + * + * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf". + */ +struct sil164_encoder_params { + enum { + SIL164_INPUT_EDGE_FALLING = 0, + SIL164_INPUT_EDGE_RISING + } input_edge; + + enum { + SIL164_INPUT_WIDTH_12BIT = 0, + SIL164_INPUT_WIDTH_24BIT + } input_width; + + enum { + SIL164_INPUT_SINGLE_EDGE = 0, + SIL164_INPUT_DUAL_EDGE + } input_dual; + + enum { + SIL164_PLL_FILTER_ON = 0, + SIL164_PLL_FILTER_OFF, + } pll_filter; + + int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */ + int duallink_skew; /** < Allowed range [-4, 3]. */ +}; + +#endif diff --git a/sys/dev/pci/drm/include/drm/i915_component.h b/sys/dev/pci/drm/include/drm/i915_component.h index fca22d463e1..55c3b123581 100644 --- a/sys/dev/pci/drm/include/drm/i915_component.h +++ b/sys/dev/pci/drm/include/drm/i915_component.h @@ -26,10 +26,15 @@ #include "drm_audio_component.h" +enum i915_component_type { + I915_COMPONENT_AUDIO = 1, + I915_COMPONENT_HDCP, +}; + /* MAX_PORT is the number of port * It must be sync with I915_MAX_PORTS defined i915_drv.h */ -#define MAX_PORTS 6 +#define MAX_PORTS 9 /** * struct i915_audio_component - Used for direct communication between i915 and hda drivers diff --git a/sys/dev/pci/drm/include/drm/i915_drm.h b/sys/dev/pci/drm/include/drm/i915_drm.h index c44703f471b..6722005884d 100644 --- a/sys/dev/pci/drm/include/drm/i915_drm.h +++ b/sys/dev/pci/drm/include/drm/i915_drm.h @@ -30,11 +30,11 @@ #include <uapi/drm/i915_drm.h> /* For use by IPS driver */ -extern unsigned long i915_read_mch_val(void); -extern bool i915_gpu_raise(void); -extern bool i915_gpu_lower(void); -extern bool i915_gpu_busy(void); -extern bool i915_gpu_turbo_disable(void); +unsigned long i915_read_mch_val(void); +bool i915_gpu_raise(void); +bool i915_gpu_lower(void); +bool i915_gpu_busy(void); +bool i915_gpu_turbo_disable(void); /* Exported from arch/x86/kernel/early-quirks.c */ extern struct resource intel_graphics_stolen_res; diff --git a/sys/dev/pci/drm/include/drm/i915_mei_hdcp_interface.h b/sys/dev/pci/drm/include/drm/i915_mei_hdcp_interface.h new file mode 100644 index 00000000000..607fa40b9ae --- /dev/null +++ b/sys/dev/pci/drm/include/drm/i915_mei_hdcp_interface.h @@ -0,0 +1,50 @@ +/* Public domain. */ + +#ifndef _I915_MEI_HDCP_INTERFACE_H_ +#define _I915_MEI_HDCP_INTERFACE_H_ + +#include <drm/drm_hdcp.h> + +enum hdcp_wired_protocol { + HDCP_PROTOCOL_INVALID, + HDCP_PROTOCOL_HDMI, + HDCP_PROTOCOL_DP +}; + +struct hdcp_port_data { + struct hdcp2_streamid_type *streams; + uint32_t seq_num_m; +}; + +struct i915_hdcp_component_ops { + int (*initiate_hdcp2_session)(struct device *, struct hdcp_port_data *, + struct hdcp2_ake_init *); + int (*verify_receiver_cert_prepare_km)(struct device *, + struct hdcp_port_data *, struct hdcp2_ake_send_cert *, bool *, + struct hdcp2_ake_no_stored_km *, size_t *); + int (*verify_hprime)(struct device *, struct hdcp_port_data *, + struct hdcp2_ake_send_hprime *); + int (*store_pairing_info)(struct device *, struct hdcp_port_data *, + struct hdcp2_ake_send_pairing_info *); + int (*initiate_locality_check)(struct device *, struct hdcp_port_data *, + struct hdcp2_lc_init *); + int (*verify_lprime)(struct device *, struct hdcp_port_data *, + struct hdcp2_lc_send_lprime *); + int (*get_session_key)(struct device *, struct hdcp_port_data *, + struct hdcp2_ske_send_eks *); + int (*repeater_check_flow_prepare_ack)(struct device *, + struct hdcp_port_data *, struct hdcp2_rep_send_receiverid_list *, + struct hdcp2_rep_send_ack *); + int (*verify_mprime)(struct device *, struct hdcp_port_data *, + struct hdcp2_rep_stream_ready *); + int (*enable_hdcp_authentication)(struct device *, + struct hdcp_port_data *); + int (*close_hdcp_session)(struct device *, struct hdcp_port_data *); +}; + +struct i915_hdcp_comp_master { + void *mei_dev; + const struct i915_hdcp_component_ops *ops; +}; + +#endif diff --git a/sys/dev/pci/drm/include/drm/i915_pciids.h b/sys/dev/pci/drm/include/drm/i915_pciids.h index ecbde04a68e..1d2c12219f4 100644 --- a/sys/dev/pci/drm/include/drm/i915_pciids.h +++ b/sys/dev/pci/drm/include/drm/i915_pciids.h @@ -108,8 +108,10 @@ INTEL_VGA_DEVICE(0x2e42, info), /* B43_G */ \ INTEL_VGA_DEVICE(0x2e92, info) /* B43_G.1 */ -#define INTEL_PINEVIEW_IDS(info) \ - INTEL_VGA_DEVICE(0xa001, info), \ +#define INTEL_PINEVIEW_G_IDS(info) \ + INTEL_VGA_DEVICE(0xa001, info) + +#define INTEL_PINEVIEW_M_IDS(info) \ INTEL_VGA_DEVICE(0xa011, info) #define INTEL_IRONLAKE_D_IDS(info) \ @@ -166,7 +168,18 @@ #define INTEL_IVB_Q_IDS(info) \ INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */ +#define INTEL_HSW_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \ + INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \ + INTEL_VGA_DEVICE(0x0A0B, info), /* ULT GT1 reserved */ \ + INTEL_VGA_DEVICE(0x0A06, info) /* ULT GT1 mobile */ + +#define INTEL_HSW_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0A0E, info) /* ULX GT1 mobile */ + #define INTEL_HSW_GT1_IDS(info) \ + INTEL_HSW_ULT_GT1_IDS(info), \ + INTEL_HSW_ULX_GT1_IDS(info), \ INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \ INTEL_VGA_DEVICE(0x040a, info), /* GT1 server */ \ INTEL_VGA_DEVICE(0x040B, info), /* GT1 reserved */ \ @@ -175,20 +188,26 @@ INTEL_VGA_DEVICE(0x0C0A, info), /* SDV GT1 server */ \ INTEL_VGA_DEVICE(0x0C0B, info), /* SDV GT1 reserved */ \ INTEL_VGA_DEVICE(0x0C0E, info), /* SDV GT1 reserved */ \ - INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \ - INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \ - INTEL_VGA_DEVICE(0x0A0B, info), /* ULT GT1 reserved */ \ INTEL_VGA_DEVICE(0x0D02, info), /* CRW GT1 desktop */ \ INTEL_VGA_DEVICE(0x0D0A, info), /* CRW GT1 server */ \ INTEL_VGA_DEVICE(0x0D0B, info), /* CRW GT1 reserved */ \ INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \ INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \ INTEL_VGA_DEVICE(0x0C06, info), /* SDV GT1 mobile */ \ - INTEL_VGA_DEVICE(0x0A06, info), /* ULT GT1 mobile */ \ - INTEL_VGA_DEVICE(0x0A0E, info), /* ULX GT1 mobile */ \ INTEL_VGA_DEVICE(0x0D06, info) /* CRW GT1 mobile */ +#define INTEL_HSW_ULT_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \ + INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \ + INTEL_VGA_DEVICE(0x0A1B, info), /* ULT GT2 reserved */ \ + INTEL_VGA_DEVICE(0x0A16, info) /* ULT GT2 mobile */ + +#define INTEL_HSW_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0A1E, info) /* ULX GT2 mobile */ \ + #define INTEL_HSW_GT2_IDS(info) \ + INTEL_HSW_ULT_GT2_IDS(info), \ + INTEL_HSW_ULX_GT2_IDS(info), \ INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \ INTEL_VGA_DEVICE(0x041a, info), /* GT2 server */ \ INTEL_VGA_DEVICE(0x041B, info), /* GT2 reserved */ \ @@ -197,9 +216,6 @@ INTEL_VGA_DEVICE(0x0C1A, info), /* SDV GT2 server */ \ INTEL_VGA_DEVICE(0x0C1B, info), /* SDV GT2 reserved */ \ INTEL_VGA_DEVICE(0x0C1E, info), /* SDV GT2 reserved */ \ - INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \ - INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \ - INTEL_VGA_DEVICE(0x0A1B, info), /* ULT GT2 reserved */ \ INTEL_VGA_DEVICE(0x0D12, info), /* CRW GT2 desktop */ \ INTEL_VGA_DEVICE(0x0D1A, info), /* CRW GT2 server */ \ INTEL_VGA_DEVICE(0x0D1B, info), /* CRW GT2 reserved */ \ @@ -207,11 +223,17 @@ INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \ INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \ INTEL_VGA_DEVICE(0x0C16, info), /* SDV GT2 mobile */ \ - INTEL_VGA_DEVICE(0x0A16, info), /* ULT GT2 mobile */ \ - INTEL_VGA_DEVICE(0x0A1E, info), /* ULX GT2 mobile */ \ INTEL_VGA_DEVICE(0x0D16, info) /* CRW GT2 mobile */ +#define INTEL_HSW_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \ + INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \ + INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \ + INTEL_VGA_DEVICE(0x0A2E, info) /* ULT GT3 reserved */ + #define INTEL_HSW_GT3_IDS(info) \ + INTEL_HSW_ULT_GT3_IDS(info), \ INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \ INTEL_VGA_DEVICE(0x042a, info), /* GT3 server */ \ INTEL_VGA_DEVICE(0x042B, info), /* GT3 reserved */ \ @@ -220,16 +242,11 @@ INTEL_VGA_DEVICE(0x0C2A, info), /* SDV GT3 server */ \ INTEL_VGA_DEVICE(0x0C2B, info), /* SDV GT3 reserved */ \ INTEL_VGA_DEVICE(0x0C2E, info), /* SDV GT3 reserved */ \ - INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \ - INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \ - INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \ INTEL_VGA_DEVICE(0x0D22, info), /* CRW GT3 desktop */ \ INTEL_VGA_DEVICE(0x0D2A, info), /* CRW GT3 server */ \ INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \ INTEL_VGA_DEVICE(0x0D2E, info), /* CRW GT3 reserved */ \ INTEL_VGA_DEVICE(0x0C26, info), /* SDV GT3 mobile */ \ - INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \ - INTEL_VGA_DEVICE(0x0A2E, info), /* ULT GT3 reserved */ \ INTEL_VGA_DEVICE(0x0D26, info) /* CRW GT3 mobile */ #define INTEL_HSW_IDS(info) \ @@ -245,35 +262,59 @@ INTEL_VGA_DEVICE(0x0157, info), \ INTEL_VGA_DEVICE(0x0155, info) -#define INTEL_BDW_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \ +#define INTEL_BDW_ULT_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \ - INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \ - INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \ + INTEL_VGA_DEVICE(0x160B, info) /* GT1 Iris */ + +#define INTEL_BDW_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x160E, info) /* GT1 ULX */ + +#define INTEL_BDW_GT1_IDS(info) \ + INTEL_BDW_ULT_GT1_IDS(info), \ + INTEL_BDW_ULX_GT1_IDS(info), \ + INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \ INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \ INTEL_VGA_DEVICE(0x160D, info) /* GT1 Workstation */ -#define INTEL_BDW_GT2_IDS(info) \ - INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \ +#define INTEL_BDW_ULT_GT2_IDS(info) \ INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \ - INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \ - INTEL_VGA_DEVICE(0x161E, info), /* GT2 ULX */ \ + INTEL_VGA_DEVICE(0x161B, info) /* GT2 ULT */ + +#define INTEL_BDW_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x161E, info) /* GT2 ULX */ + +#define INTEL_BDW_GT2_IDS(info) \ + INTEL_BDW_ULT_GT2_IDS(info), \ + INTEL_BDW_ULX_GT2_IDS(info), \ + INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \ INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \ INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */ +#define INTEL_BDW_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x162B, info) /* Iris */ \ + +#define INTEL_BDW_ULX_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x162E, info) /* ULX */ + #define INTEL_BDW_GT3_IDS(info) \ + INTEL_BDW_ULT_GT3_IDS(info), \ + INTEL_BDW_ULX_GT3_IDS(info), \ INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \ - INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \ - INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \ - INTEL_VGA_DEVICE(0x162E, info), /* ULX */\ INTEL_VGA_DEVICE(0x162A, info), /* Server */ \ INTEL_VGA_DEVICE(0x162D, info) /* Workstation */ +#define INTEL_BDW_ULT_RSVD_IDS(info) \ + INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x163B, info) /* Iris */ + +#define INTEL_BDW_ULX_RSVD_IDS(info) \ + INTEL_VGA_DEVICE(0x163E, info) /* ULX */ + #define INTEL_BDW_RSVD_IDS(info) \ + INTEL_BDW_ULT_RSVD_IDS(info), \ + INTEL_BDW_ULX_RSVD_IDS(info), \ INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \ - INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \ - INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \ - INTEL_VGA_DEVICE(0x163E, info), /* ULX */ \ INTEL_VGA_DEVICE(0x163A, info), /* Server */ \ INTEL_VGA_DEVICE(0x163D, info) /* Workstation */ @@ -289,25 +330,40 @@ INTEL_VGA_DEVICE(0x22b2, info), \ INTEL_VGA_DEVICE(0x22b3, info) +#define INTEL_SKL_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x1906, info) /* ULT GT1 */ + +#define INTEL_SKL_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x190E, info) /* ULX GT1 */ + #define INTEL_SKL_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \ - INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \ + INTEL_SKL_ULT_GT1_IDS(info), \ + INTEL_SKL_ULX_GT1_IDS(info), \ INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */ -#define INTEL_SKL_GT2_IDS(info) \ +#define INTEL_SKL_ULT_GT2_IDS(info) \ INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ - INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \ - INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \ + INTEL_VGA_DEVICE(0x1921, info) /* ULT GT2F */ + +#define INTEL_SKL_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x191E, info) /* ULX GT2 */ + +#define INTEL_SKL_GT2_IDS(info) \ + INTEL_SKL_ULT_GT2_IDS(info), \ + INTEL_SKL_ULX_GT2_IDS(info), \ INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \ INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \ INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \ INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */ +#define INTEL_SKL_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1926, info) /* ULT GT3 */ + #define INTEL_SKL_GT3_IDS(info) \ + INTEL_SKL_ULT_GT3_IDS(info), \ INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \ - INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ INTEL_VGA_DEVICE(0x192D, info) /* SRV GT3 */ @@ -336,29 +392,44 @@ INTEL_VGA_DEVICE(0x3184, info), \ INTEL_VGA_DEVICE(0x3185, info) -#define INTEL_KBL_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \ - INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \ +#define INTEL_KBL_ULT_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \ + INTEL_VGA_DEVICE(0x5913, info) /* ULT GT1.5 */ + +#define INTEL_KBL_ULX_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x5915, info) /* ULX GT1.5 */ + +#define INTEL_KBL_GT1_IDS(info) \ + INTEL_KBL_ULT_GT1_IDS(info), \ + INTEL_KBL_ULX_GT1_IDS(info), \ INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \ INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \ INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \ INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */ -#define INTEL_KBL_GT2_IDS(info) \ +#define INTEL_KBL_ULT_GT2_IDS(info) \ INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x5921, info) /* ULT GT2F */ + +#define INTEL_KBL_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x591E, info) /* ULX GT2 */ + +#define INTEL_KBL_GT2_IDS(info) \ + INTEL_KBL_ULT_GT2_IDS(info), \ + INTEL_KBL_ULX_GT2_IDS(info), \ INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */ \ - INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \ - INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \ INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \ INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \ INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \ INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */ +#define INTEL_KBL_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x5926, info) /* ULT GT3 */ + #define INTEL_KBL_GT3_IDS(info) \ + INTEL_KBL_ULT_GT3_IDS(info), \ INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \ - INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */ #define INTEL_KBL_GT4_IDS(info) \ @@ -375,27 +446,30 @@ /* CML GT1 */ #define INTEL_CML_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x9B21, info), \ - INTEL_VGA_DEVICE(0x9BAA, info), \ - INTEL_VGA_DEVICE(0x9BAB, info), \ - INTEL_VGA_DEVICE(0x9BAC, info), \ - INTEL_VGA_DEVICE(0x9BA0, info), \ INTEL_VGA_DEVICE(0x9BA5, info), \ INTEL_VGA_DEVICE(0x9BA8, info), \ INTEL_VGA_DEVICE(0x9BA4, info), \ INTEL_VGA_DEVICE(0x9BA2, info) +#define INTEL_CML_U_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x9B21, info), \ + INTEL_VGA_DEVICE(0x9BAA, info), \ + INTEL_VGA_DEVICE(0x9BAC, info) + /* CML GT2 */ #define INTEL_CML_GT2_IDS(info) \ - INTEL_VGA_DEVICE(0x9B41, info), \ - INTEL_VGA_DEVICE(0x9BCA, info), \ - INTEL_VGA_DEVICE(0x9BCB, info), \ - INTEL_VGA_DEVICE(0x9BCC, info), \ - INTEL_VGA_DEVICE(0x9BC0, info), \ INTEL_VGA_DEVICE(0x9BC5, info), \ INTEL_VGA_DEVICE(0x9BC8, info), \ INTEL_VGA_DEVICE(0x9BC4, info), \ - INTEL_VGA_DEVICE(0x9BC2, info) + INTEL_VGA_DEVICE(0x9BC2, info), \ + INTEL_VGA_DEVICE(0x9BC6, info), \ + INTEL_VGA_DEVICE(0x9BE6, info), \ + INTEL_VGA_DEVICE(0x9BF6, info) + +#define INTEL_CML_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x9B41, info), \ + INTEL_VGA_DEVICE(0x9BCA, info), \ + INTEL_VGA_DEVICE(0x9BCC, info) #define INTEL_KBL_IDS(info) \ INTEL_KBL_GT1_IDS(info), \ @@ -462,10 +536,19 @@ INTEL_WHL_U_GT3_IDS(info), \ INTEL_AML_CFL_GT2_IDS(info), \ INTEL_CML_GT1_IDS(info), \ - INTEL_CML_GT2_IDS(info) + INTEL_CML_GT2_IDS(info), \ + INTEL_CML_U_GT1_IDS(info), \ + INTEL_CML_U_GT2_IDS(info) /* CNL */ +#define INTEL_CNL_PORT_F_IDS(info) \ + INTEL_VGA_DEVICE(0x5A54, info), \ + INTEL_VGA_DEVICE(0x5A5C, info), \ + INTEL_VGA_DEVICE(0x5A44, info), \ + INTEL_VGA_DEVICE(0x5A4C, info) + #define INTEL_CNL_IDS(info) \ + INTEL_CNL_PORT_F_IDS(info), \ INTEL_VGA_DEVICE(0x5A51, info), \ INTEL_VGA_DEVICE(0x5A59, info), \ INTEL_VGA_DEVICE(0x5A41, info), \ @@ -475,18 +558,12 @@ INTEL_VGA_DEVICE(0x5A42, info), \ INTEL_VGA_DEVICE(0x5A4A, info), \ INTEL_VGA_DEVICE(0x5A50, info), \ - INTEL_VGA_DEVICE(0x5A40, info), \ - INTEL_VGA_DEVICE(0x5A54, info), \ - INTEL_VGA_DEVICE(0x5A5C, info), \ - INTEL_VGA_DEVICE(0x5A44, info), \ - INTEL_VGA_DEVICE(0x5A4C, info) + INTEL_VGA_DEVICE(0x5A40, info) /* ICL */ -#define INTEL_ICL_11_IDS(info) \ +#define INTEL_ICL_PORT_F_IDS(info) \ INTEL_VGA_DEVICE(0x8A50, info), \ - INTEL_VGA_DEVICE(0x8A51, info), \ INTEL_VGA_DEVICE(0x8A5C, info), \ - INTEL_VGA_DEVICE(0x8A5D, info), \ INTEL_VGA_DEVICE(0x8A59, info), \ INTEL_VGA_DEVICE(0x8A58, info), \ INTEL_VGA_DEVICE(0x8A52, info), \ @@ -495,6 +572,33 @@ INTEL_VGA_DEVICE(0x8A57, info), \ INTEL_VGA_DEVICE(0x8A56, info), \ INTEL_VGA_DEVICE(0x8A71, info), \ - INTEL_VGA_DEVICE(0x8A70, info) + INTEL_VGA_DEVICE(0x8A70, info), \ + INTEL_VGA_DEVICE(0x8A53, info), \ + INTEL_VGA_DEVICE(0x8A54, info) + +#define INTEL_ICL_11_IDS(info) \ + INTEL_ICL_PORT_F_IDS(info), \ + INTEL_VGA_DEVICE(0x8A51, info), \ + INTEL_VGA_DEVICE(0x8A5D, info) + +/* EHL/JSL */ +#define INTEL_EHL_IDS(info) \ + INTEL_VGA_DEVICE(0x4500, info), \ + INTEL_VGA_DEVICE(0x4571, info), \ + INTEL_VGA_DEVICE(0x4551, info), \ + INTEL_VGA_DEVICE(0x4541, info), \ + INTEL_VGA_DEVICE(0x4E71, info), \ + INTEL_VGA_DEVICE(0x4E61, info), \ + INTEL_VGA_DEVICE(0x4E51, info) + +/* TGL */ +#define INTEL_TGL_12_IDS(info) \ + INTEL_VGA_DEVICE(0x9A49, info), \ + INTEL_VGA_DEVICE(0x9A40, info), \ + INTEL_VGA_DEVICE(0x9A59, info), \ + INTEL_VGA_DEVICE(0x9A60, info), \ + INTEL_VGA_DEVICE(0x9A68, info), \ + INTEL_VGA_DEVICE(0x9A70, info), \ + INTEL_VGA_DEVICE(0x9A78, info) #endif /* _I915_PCIIDS_H */ diff --git a/sys/dev/pci/drm/include/drm/intel-gtt.h b/sys/dev/pci/drm/include/drm/intel-gtt.h new file mode 100644 index 00000000000..b5bfb1c07f6 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/intel-gtt.h @@ -0,0 +1,21 @@ +/* Public domain. */ + +#ifndef _DRM_INTEL_GTT_H +#define _DRM_INTEL_GTT_H + +#include <linux/agp_backend.h> +#include <linux/kernel.h> + +struct pci_dev; + +int intel_enable_gtt(void); +void intel_gtt_chipset_flush(void); +int intel_gmch_probe(struct pci_dev *, struct pci_dev *, void *); +void intel_gtt_get(u64 *, phys_addr_t *, resource_size_t *); +void intel_gtt_insert_sg_entries(struct sg_table *, unsigned int, + unsigned int); +void intel_gtt_insert_page(dma_addr_t, unsigned int, unsigned int); +void intel_gtt_clear_range(unsigned int, unsigned int); +void intel_gmch_remove(void); + +#endif diff --git a/sys/dev/pci/drm/include/drm/task_barrier.h b/sys/dev/pci/drm/include/drm/task_barrier.h new file mode 100644 index 00000000000..a2edc9a55d4 --- /dev/null +++ b/sys/dev/pci/drm/include/drm/task_barrier.h @@ -0,0 +1,119 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include <linux/semaphore.h> +#include <linux/atomic.h> + +/* + * Reusable 2 PHASE task barrier (randevouz point) implementation for N tasks. + * Based on the Little book of sempahores - https://greenteapress.com/wp/semaphores/ + */ + + + +#ifndef DRM_TASK_BARRIER_H_ +#define DRM_TASK_BARRIER_H_ + +/* + * Represents an instance of a task barrier. + */ +struct task_barrier { + unsigned int n; + atomic_t count; + struct semaphore enter_turnstile; + struct semaphore exit_turnstile; +}; + +static inline void task_barrier_signal_turnstile(struct semaphore *turnstile, + unsigned int n) +{ + STUB(); +#ifdef notyet + int i; + + for (i = 0 ; i < n; i++) + up(turnstile); +#endif +} + +static inline void task_barrier_init(struct task_barrier *tb) +{ + tb->n = 0; + atomic_set(&tb->count, 0); + STUB(); +#ifdef notyet + sema_init(&tb->enter_turnstile, 0); + sema_init(&tb->exit_turnstile, 0); +#endif +} + +static inline void task_barrier_add_task(struct task_barrier *tb) +{ + tb->n++; +} + +static inline void task_barrier_rem_task(struct task_barrier *tb) +{ + tb->n--; +} + +/* + * Lines up all the threads BEFORE the critical point. + * + * When all thread passed this code the entry barrier is back to locked state. + */ +static inline void task_barrier_enter(struct task_barrier *tb) +{ + if (atomic_inc_return(&tb->count) == tb->n) + task_barrier_signal_turnstile(&tb->enter_turnstile, tb->n); + + STUB(); +#ifdef notyet + down(&tb->enter_turnstile); +#endif +} + +/* + * Lines up all the threads AFTER the critical point. + * + * This function is used to avoid any one thread running ahead if the barrier is + * used repeatedly . + */ +static inline void task_barrier_exit(struct task_barrier *tb) +{ + if (atomic_dec_return(&tb->count) == 0) + task_barrier_signal_turnstile(&tb->exit_turnstile, tb->n); + + STUB(); +#ifdef notyet + down(&tb->exit_turnstile); +#endif +} + +/* Convinieince function when nothing to be done in between entry and exit */ +static inline void task_barrier_full(struct task_barrier *tb) +{ + task_barrier_enter(tb); + task_barrier_exit(tb); +} + +#endif diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_bo_api.h b/sys/dev/pci/drm/include/drm/ttm/ttm_bo_api.h index a4004dfca30..675387a2be9 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_bo_api.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_bo_api.h @@ -31,6 +31,7 @@ #ifndef _TTM_BO_API_H_ #define _TTM_BO_API_H_ +#include <drm/drm_gem.h> #include <drm/drm_hashtab.h> #include <drm/drm_vma_manager.h> #include <linux/kref.h> @@ -39,7 +40,9 @@ #include <linux/mutex.h> #include <linux/mm.h> #include <linux/bitmap.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> + +#include <uvm/uvm_extern.h> struct ttm_bo_global; @@ -51,6 +54,8 @@ struct ttm_placement; struct ttm_place; +struct ttm_lru_bulk_move; + /** * struct ttm_bus_placement * @@ -126,34 +131,28 @@ struct ttm_tt; /** * struct ttm_buffer_object * + * @base: drm_gem_object superclass data. * @bdev: Pointer to the buffer object device structure. * @type: The bo type. * @destroy: Destruction function. If NULL, kfree is used. * @num_pages: Actual number of pages. * @acc_size: Accounted size for this object. * @kref: Reference count of this buffer object. When this refcount reaches - * zero, the object is put on the delayed delete list. - * @list_kref: List reference count of this buffer object. This member is - * used to avoid destruction while the buffer object is still on a list. - * Lru lists may keep one refcount, the delayed delete list, and kref != 0 - * keeps one refcount. When this refcount reaches zero, - * the object is destroyed. + * zero, the object is destroyed or put on the delayed delete list. * @mem: structure describing current placement. * @persistent_swap_storage: Usually the swap storage is deleted for buffers * pinned in physical memory. If this behaviour is not desired, this member * holds a pointer to a persistent shmem object. * @ttm: TTM structure holding system pages. * @evicted: Whether the object was evicted without user-space knowing. - * @cpu_writes: For synchronization. Number of cpu writers. + * @deleted: True if the object is only a zombie and already deleted. * @lru: List head for the lru list. * @ddestroy: List head for the delayed destroy list. * @swap: List head for swap LRU list. * @moving: Fence set when BO is moving - * @vma_node: Address space manager node. * @offset: The current GPU offset, which can have different meanings * depending on the memory type. For SYSTEM type memory, it should be 0. * @cur_placement: Hint of current placement. - * @wu_mutex: Wait unreserved mutex. * * Base class for TTM buffer object, that deals with data placement and CPU * mappings. GPU mappings are really up to the driver, but for simpler GPUs @@ -168,7 +167,7 @@ struct ttm_tt; */ struct ttm_buffer_object { - struct uvm_object uobj; + struct drm_gem_object base; /** * Members constant at init. @@ -183,9 +182,7 @@ struct ttm_buffer_object { /** * Members not needing protection. */ - struct kref kref; - struct kref list_kref; /** * Members protected by the bo::resv::reserved lock. @@ -195,12 +192,7 @@ struct ttm_buffer_object { struct uvm_object *persistent_swap_storage; struct ttm_tt *ttm; bool evicted; - - /** - * Members protected by the bo::reserved lock only when written to. - */ - - atomic_t cpu_writers; + bool deleted; /** * Members protected by the bdev::lru_lock. @@ -216,9 +208,6 @@ struct ttm_buffer_object { */ struct dma_fence *moving; - - struct drm_vma_offset_node vma_node; - unsigned priority; /** @@ -230,10 +219,6 @@ struct ttm_buffer_object { uint64_t offset; /* GPU address space is independent of CPU word size */ struct sg_table *sg; - - struct reservation_object *resv; - struct reservation_object ttm_resv; - struct rwlock wu_mutex; }; /** @@ -276,7 +261,7 @@ struct ttm_bo_kmap_obj { struct ttm_operation_ctx { bool interruptible; bool no_wait_gpu; - struct reservation_object *resv; + struct dma_resv *resv; uint64_t bytes_moved; uint32_t flags; }; @@ -297,19 +282,20 @@ static inline void ttm_bo_get(struct ttm_buffer_object *bo) } /** - * ttm_bo_reference - reference a struct ttm_buffer_object - * + * ttm_bo_get_unless_zero - reference a struct ttm_buffer_object unless + * its refcount has already reached zero. * @bo: The buffer object. * - * Returns a refcounted pointer to a buffer object. + * Used to reference a TTM buffer object in lookups where the object is removed + * from the lookup structure during the destructor and for RCU lookups. * - * This function is deprecated. Use @ttm_bo_get instead. + * Returns: @bo if the referencing was successful, NULL otherwise. */ - -static inline struct ttm_buffer_object * -ttm_bo_reference(struct ttm_buffer_object *bo) +static inline __must_check struct ttm_buffer_object * +ttm_bo_get_unless_zero(struct ttm_buffer_object *bo) { - ttm_bo_get(bo); + if (!kref_get_unless_zero(&bo->kref)) + return NULL; return bo; } @@ -370,50 +356,27 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, void ttm_bo_put(struct ttm_buffer_object *bo); /** - * ttm_bo_unref - * - * @bo: The buffer object. - * - * Unreference and clear a pointer to a buffer object. - * - * This function is deprecated. Use @ttm_bo_put instead. - */ -void ttm_bo_unref(struct ttm_buffer_object **bo); - -/** - * ttm_bo_add_to_lru - * - * @bo: The buffer object. - * - * Add this bo to the relevant mem type lru and, if it's backed by - * system pages (ttms) to the swap list. - * This function must be called with struct ttm_bo_global::lru_lock held, and - * is typically called immediately prior to unreserving a bo. - */ -void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); - -/** - * ttm_bo_del_from_lru + * ttm_bo_move_to_lru_tail * * @bo: The buffer object. + * @bulk: optional bulk move structure to remember BO positions * - * Remove this bo from all lru lists used to lookup and reserve an object. - * This function must be called with struct ttm_bo_global::lru_lock held, - * and is usually called just immediately after the bo has been reserved to - * avoid recursive reservation from lru lists. + * Move this BO to the tail of all lru lists used to lookup and reserve an + * object. This function must be called with struct ttm_bo_global::lru_lock + * held, and is used to make a BO less likely to be considered for eviction. */ -void ttm_bo_del_from_lru(struct ttm_buffer_object *bo); +void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo, + struct ttm_lru_bulk_move *bulk); /** - * ttm_bo_move_to_lru_tail + * ttm_bo_bulk_move_lru_tail * - * @bo: The buffer object. + * @bulk: bulk move structure * - * Move this BO to the tail of all lru lists used to lookup and reserve an - * object. This function must be called with struct ttm_bo_global::lru_lock - * held, and is used to make a BO less likely to be considered for eviction. + * Bulk move BOs to the LRU tail, only valid to use when driver makes sure that + * BO order never changes. Should be called with ttm_bo_global::lru_lock held. */ -void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo); +void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk); /** * ttm_bo_lock_delayed_workqueue @@ -443,31 +406,6 @@ bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, const struct ttm_place *place); /** - * ttm_bo_synccpu_write_grab - * - * @bo: The buffer object: - * @no_wait: Return immediately if buffer is busy. - * - * Synchronizes a buffer object for CPU RW access. This means - * command submission that affects the buffer will return -EBUSY - * until ttm_bo_synccpu_write_release is called. - * - * Returns - * -EBUSY if the buffer is busy and no_wait is true. - * -ERESTARTSYS if interrupted by a signal. - */ -int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait); - -/** - * ttm_bo_synccpu_write_release: - * - * @bo : The buffer object. - * - * Releases a synccpu lock. - */ -void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo); - -/** * ttm_bo_acc_size * * @bdev: Pointer to a ttm_bo_device struct. @@ -494,7 +432,7 @@ size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev, * @page_alignment: Data alignment in pages. * @ctx: TTM operation context for memory allocation. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -527,7 +465,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, struct ttm_operation_ctx *ctx, size_t acc_size, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** @@ -546,7 +484,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, * point to the shmem object backing a GEM object if TTM is used to back a * GEM user interface. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -571,7 +509,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, struct ttm_buffer_object *bo, unsigned long size, enum ttm_bo_type type, struct ttm_placement *placement, uint32_t page_alignment, bool interrubtible, size_t acc_size, - struct sg_table *sg, struct reservation_object *resv, + struct sg_table *sg, struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** @@ -712,16 +650,14 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map); #ifdef notyet /** - * ttm_fbdev_mmap - mmap fbdev memory backed by a ttm buffer object. + * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object. * * @vma: vma as input from the fbdev mmap method. - * @bo: The bo backing the address space. The address space will - * have the same size as the bo, and start at offset 0. + * @bo: The bo backing the address space. * - * This function is intended to be called by the fbdev mmap method - * if the fbdev address space is to be backed by a bo. + * Maps a buffer object. */ -int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); +int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo); /** * ttm_bo_mmap - mmap out of the ttm device address space. @@ -735,14 +671,15 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); */ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, struct ttm_bo_device *bdev); +#else +struct uvm_object *ttm_bo_mmap(struct file *, voff_t, vsize_t, + struct ttm_bo_device *); #endif void *ttm_kmap_atomic_prot(struct vm_page *page, pgprot_t prot); void ttm_kunmap_atomic_prot(void *addr, pgprot_t prot); -extern struct uvm_object *ttm_bo_mmap(voff_t, vsize_t, struct ttm_bo_device *); - /** * ttm_bo_io * @@ -770,5 +707,49 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp, int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx); void ttm_bo_swapout_all(struct ttm_bo_device *bdev); -int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo); + +/** + * ttm_bo_uses_embedded_gem_object - check if the given bo uses the + * embedded drm_gem_object. + * + * Most ttm drivers are using gem too, so the embedded + * ttm_buffer_object.base will be initialized by the driver (before + * calling ttm_bo_init). It is also possible to use ttm without gem + * though (vmwgfx does that). + * + * This helper will figure whenever a given ttm bo is a gem object too + * or not. + * + * @bo: The bo to check. + */ +static inline bool ttm_bo_uses_embedded_gem_object(struct ttm_buffer_object *bo) +{ + return bo->base.dev != NULL; +} + +/* Default number of pre-faulted pages in the TTM fault handler */ +#define TTM_BO_VM_NUM_PREFAULT 16 + +#ifdef __linux__ +vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo, + struct vm_fault *vmf); + +vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, + pgprot_t prot, + pgoff_t num_prefault, + pgoff_t fault_page_size); + +vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf); + +void ttm_bo_vm_open(struct vm_area_struct *vma); + +void ttm_bo_vm_close(struct vm_area_struct *vma); + +int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write); +#else +int ttm_bo_vm_fault(struct uvm_faultinfo *, vaddr_t, vm_page_t *, + int, int, vm_fault_t, vm_prot_t, int); +#endif /* !__linux__ */ + #endif diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_bo_driver.h b/sys/dev/pci/drm/include/drm/ttm/ttm_bo_driver.h index dfb60677965..4e4df19a8a9 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_bo_driver.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_bo_driver.h @@ -31,13 +31,11 @@ #define _TTM_BO_DRIVER_H_ #include <drm/drm_mm.h> -#include <drm/drm_global.h> #include <drm/drm_vma_manager.h> -#include <drm/drm_print.h> #include <linux/workqueue.h> #include <linux/fs.h> #include <linux/spinlock.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "ttm_bo_api.h" #include "ttm_memory.h" @@ -212,8 +210,6 @@ struct ttm_mem_type_manager { * struct ttm_bo_driver * * @create_ttm_backend_entry: Callback to create a struct ttm_backend. - * @invalidate_caches: Callback to invalidate read caches when a buffer object - * has been evicted. * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager * structure. * @evict_flags: Callback to obtain placement flags when a buffer is evicted. @@ -258,19 +254,6 @@ struct ttm_bo_driver { */ void (*ttm_tt_unpopulate)(struct ttm_tt *ttm); - /** - * struct ttm_bo_driver member invalidate_caches - * - * @bdev: the buffer object device. - * @flags: new placement of the rebound buffer object. - * - * A previosly evicted buffer has been rebound in a - * potentially new location. Tell the driver that it might - * consider invalidating read (texture) caches on the next command - * submission as a consequence. - */ - - int (*invalidate_caches)(struct ttm_bo_device *bdev, uint32_t flags); int (*init_mem_type)(struct ttm_bo_device *bdev, uint32_t type, struct ttm_mem_type_manager *man); @@ -383,15 +366,25 @@ struct ttm_bo_driver { */ int (*access_memory)(struct ttm_buffer_object *bo, unsigned long offset, void *buf, int len, int write); -}; -/** - * struct ttm_bo_global_ref - Argument to initialize a struct ttm_bo_global. - */ + /** + * struct ttm_bo_driver member del_from_lru_notify + * + * @bo: the buffer object deleted from lru + * + * notify driver that a BO was deleted from LRU. + */ + void (*del_from_lru_notify)(struct ttm_buffer_object *bo); -struct ttm_bo_global_ref { - struct drm_global_reference ref; - struct ttm_mem_global *mem_glob; + /** + * Notify the driver that we're about to release a BO + * + * @bo: BO that is about to be released + * + * Gives the driver a chance to do any cleanup, including + * adding fences that may force a delayed delete + */ + void (*release_notify)(struct ttm_buffer_object *bo); }; /** @@ -408,20 +401,18 @@ struct ttm_bo_global_ref { * @swap_lru: Lru list of buffer objects used for swapping. */ -struct ttm_bo_global { +extern struct ttm_bo_global { /** * Constant after init. */ struct kobject kobj; - struct ttm_mem_global *mem_glob; struct vm_page *dummy_read_page; - struct rwlock device_list_mutex; spinlock_t lru_lock; /** - * Protected by device_list_mutex. + * Protected by ttm_global_mutex. */ struct list_head device_list; @@ -434,7 +425,7 @@ struct ttm_bo_global { * Internal protection. */ atomic_t bo_count; -}; +} ttm_bo_glob; #define TTM_NUM_MEM_TYPES 8 @@ -444,7 +435,7 @@ struct ttm_bo_global { * * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. * @man: An array of mem_type_managers. - * @vma_manager: Address space manager + * @vma_manager: Address space manager (pointer) * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. * @dev_mapping: A pointer to the struct address_space representing the @@ -460,7 +451,6 @@ struct ttm_bo_device { * Constant after bo device init / atomic. */ struct list_head device_list; - struct ttm_bo_global *glob; struct ttm_bo_driver *driver; struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; @@ -471,7 +461,7 @@ struct ttm_bo_device { /* * Protected by internal locks. */ - struct drm_vma_offset_manager vma_manager; + struct drm_vma_offset_manager *vma_manager; /* * Protected by the global:lru lock. @@ -496,6 +486,34 @@ struct ttm_bo_device { }; /** + * struct ttm_lru_bulk_move_pos + * + * @first: first BO in the bulk move range + * @last: last BO in the bulk move range + * + * Positions for a lru bulk move. + */ +struct ttm_lru_bulk_move_pos { + struct ttm_buffer_object *first; + struct ttm_buffer_object *last; +}; + +/** + * struct ttm_lru_bulk_move + * + * @tt: first/last lru entry for BOs in the TT domain + * @vram: first/last lru entry for BOs in the VRAM domain + * @swap: first/last lru entry for BOs on the swap list + * + * Helper structure for bulk moves on the LRU list. + */ +struct ttm_lru_bulk_move { + struct ttm_lru_bulk_move_pos tt[TTM_MAX_BO_PRIORITY]; + struct ttm_lru_bulk_move_pos vram[TTM_MAX_BO_PRIORITY]; + struct ttm_lru_bulk_move_pos swap[TTM_MAX_BO_PRIORITY]; +}; + +/** * ttm_flag_masked * * @old: Pointer to the result and original value. @@ -555,9 +573,6 @@ void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); -void ttm_bo_global_release(struct drm_global_reference *ref); -int ttm_bo_global_init(struct drm_global_reference *ref); - int ttm_bo_device_release(struct ttm_bo_device *bdev); /** @@ -567,6 +582,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev); * @glob: A pointer to an initialized struct ttm_bo_global. * @driver: A pointer to a struct ttm_bo_driver set up by the caller. * @mapping: The address space to use for this bo. + * @vma_manager: A pointer to a vma manager. * @file_page_offset: Offset into the device address space that is available * for buffer data. This ensures compatibility with other users of the * address space. @@ -575,10 +591,11 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev); * Returns: * !0: Failure. */ -int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_global *glob, +int ttm_bo_device_init(struct ttm_bo_device *bdev, struct ttm_bo_driver *driver, struct address_space *mapping, - uint64_t file_page_offset, bool need_dma32); + struct drm_vma_offset_manager *vma_manager, + bool need_dma32); /** * ttm_bo_unmap_virtual @@ -601,9 +618,6 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible); void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); -void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo); -void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); - /** * __ttm_bo_reserve: * @@ -636,14 +650,14 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, if (WARN_ON(ticket)) return -EBUSY; - success = reservation_object_trylock(bo->resv); + success = dma_resv_trylock(bo->base.resv); return success ? 0 : -EBUSY; } if (interruptible) - ret = reservation_object_lock_interruptible(bo->resv, ticket); + ret = dma_resv_lock_interruptible(bo->base.resv, ticket); else - ret = reservation_object_lock(bo->resv, ticket); + ret = dma_resv_lock(bo->base.resv, ticket); if (ret == -EINTR) return -ERESTARTSYS; return ret; @@ -697,15 +711,9 @@ static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, bool interruptible, bool no_wait, struct ww_acquire_ctx *ticket) { - int ret; - WARN_ON(!kref_read(&bo->kref)); - ret = __ttm_bo_reserve(bo, interruptible, no_wait, ticket); - if (likely(ret == 0)) - ttm_bo_del_sub_from_lru(bo); - - return ret; + return __ttm_bo_reserve(bo, interruptible, no_wait, ticket); } /** @@ -727,14 +735,12 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, WARN_ON(!kref_read(&bo->kref)); if (interruptible) - ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, - ticket); + ret = dma_resv_lock_slow_interruptible(bo->base.resv, + ticket); else - ww_mutex_lock_slow(&bo->resv->lock, ticket); + dma_resv_lock_slow(bo->base.resv, ticket); - if (likely(ret == 0)) - ttm_bo_del_sub_from_lru(bo); - else if (ret == -EINTR) + if (ret == -EINTR) ret = -ERESTARTSYS; return ret; @@ -749,12 +755,10 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, */ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) { - if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { - spin_lock(&bo->bdev->glob->lru_lock); - ttm_bo_add_to_lru(bo); - spin_unlock(&bo->bdev->glob->lru_lock); - } - reservation_object_unlock(bo->resv); + spin_lock(&ttm_bo_glob.lru_lock); + ttm_bo_move_to_lru_tail(bo, NULL); + spin_unlock(&ttm_bo_glob.lru_lock); + dma_resv_unlock(bo->base.resv); } /* @@ -857,7 +861,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, * * @bo: A pointer to a struct ttm_buffer_object. * - * Pipelined gutting a BO of it's backing store. + * Pipelined gutting a BO of its backing store. */ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo); diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_execbuf_util.h b/sys/dev/pci/drm/include/drm/ttm/ttm_execbuf_util.h index b0fdd198003..5a19843bb80 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_execbuf_util.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_execbuf_util.h @@ -40,13 +40,13 @@ * * @head: list head for thread-private list. * @bo: refcounted buffer object pointer. - * @shared: should the fence be added shared? + * @num_shared: How many shared fences we want to add. */ struct ttm_validate_buffer { struct list_head head; struct ttm_buffer_object *bo; - bool shared; + unsigned int num_shared; }; /** @@ -70,6 +70,7 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, * @list: thread private list of ttm_validate_buffer structs. * @intr: should the wait be interruptible * @dups: [out] optional list of duplicates. + * @del_lru: true if BOs should be removed from the LRU. * * Tries to reserve bos pointed to by the list entries for validation. * If the function returns 0, all buffers are marked as "unfenced", diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_memory.h b/sys/dev/pci/drm/include/drm/ttm/ttm_memory.h index 43c97fb01fb..3f98db6375e 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_memory.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_memory.h @@ -63,9 +63,8 @@ #define TTM_MEM_MAX_ZONES 2 struct ttm_mem_zone; -struct ttm_mem_global { +extern struct ttm_mem_global { struct kobject kobj; - struct ttm_bo_global *bo_glob; struct workqueue_struct *swap_queue; struct work_struct work; spinlock_t lock; @@ -78,7 +77,7 @@ struct ttm_mem_global { #else struct ttm_mem_zone *zone_dma32; #endif -}; +} ttm_mem_glob; extern int ttm_mem_global_init(struct ttm_mem_global *glob); extern void ttm_mem_global_release(struct ttm_mem_global *glob); diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_page_alloc.h b/sys/dev/pci/drm/include/drm/ttm/ttm_page_alloc.h index 4d9b019d253..a6b6ef5f9bf 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_page_alloc.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_page_alloc.h @@ -74,7 +74,7 @@ void ttm_unmap_and_unpopulate_pages(struct device *dev, struct ttm_dma_tt *tt); */ int ttm_page_alloc_debugfs(struct seq_file *m, void *data); -#if defined(CONFIG_SWIOTLB) || defined(CONFIG_INTEL_IOMMU) +#if defined(CONFIG_DRM_TTM_DMA_PAGE_POOL) /** * Initialize pool allocator. */ diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_set_memory.h b/sys/dev/pci/drm/include/drm/ttm/ttm_set_memory.h index 035fc418152..0209935fdc6 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_set_memory.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_set_memory.h @@ -37,7 +37,6 @@ #include <asm/set_memory.h> - static inline int ttm_set_pages_array_wb(struct vm_page **pages, int addrinarray) { return set_pages_array_wb(pages, addrinarray); diff --git a/sys/dev/pci/drm/include/drm/ttm/ttm_tt.h b/sys/dev/pci/drm/include/drm/ttm/ttm_tt.h index 0aa65fa1a21..adb52b17962 100644 --- a/sys/dev/pci/drm/include/drm/ttm/ttm_tt.h +++ b/sys/dev/pci/drm/include/drm/ttm/ttm_tt.h @@ -28,7 +28,6 @@ #define _TTM_TT_H_ #include <linux/types.h> -#include <drm/drmP.h> struct ttm_tt; struct ttm_mem_reg; @@ -253,6 +252,7 @@ int ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx); void ttm_tt_unpopulate(struct ttm_tt *ttm); #if IS_ENABLED(CONFIG_AGP) +#include <linux/agp_backend.h> /** * ttm_agp_tt_create diff --git a/sys/dev/pci/drm/include/generated/autoconf.h b/sys/dev/pci/drm/include/generated/autoconf.h index be8d046c856..05af433246b 100644 --- a/sys/dev/pci/drm/include/generated/autoconf.h +++ b/sys/dev/pci/drm/include/generated/autoconf.h @@ -4,24 +4,25 @@ #define CONFIG_BACKLIGHT_CLASS_DEVICE 1 #define CONFIG_DRM_FBDEV_EMULATION 1 -#define CONFIG_DRM_FBDEV_OVERALLOC 0 -#define CONFIG_DRM_I915_DEBUG 0 -#define CONFIG_DRM_I915_DEBUG_GEM 0 +#define CONFIG_DRM_PANEL 1 #define CONFIG_DRM_I915_FBDEV 1 -#define CONFIG_DRM_I915_ALPHA_SUPPORT 0 #define CONFIG_DRM_I915_CAPTURE_ERROR 1 -#define CONFIG_DRM_I915_GVT 0 -#define CONFIG_DRM_I915_SW_FENCE_CHECK_DAG 0 -#define CONFIG_PM 0 #define CONFIG_DRM_AMD_DC 1 #if defined(__amd64__) || defined(__i386__) -#define CONFIG_DRM_AMD_DC_DCN1_0 1 +#define CONFIG_DRM_AMD_DC_DCN 1 #endif #if 0 #define CONFIG_DRM_AMDGPU_CIK 1 #define CONFIG_DRM_AMDGPU_SI 1 #endif +#define CONFIG_DRM_I915_PREEMPT_TIMEOUT 640 /* ms */ +#define CONFIG_DRM_I915_TIMESLICE_DURATION 1 /* ms */ +#define CONFIG_DRM_I915_HEARTBEAT_INTERVAL 2500 /* ms */ +#define CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT 8000 /* ns */ +#define CONFIG_DRM_I915_STOP_TIMEOUT 100 /* ms */ +#define CONFIG_DRM_I915_FORCE_PROBE "" + #ifdef __HAVE_ACPI #include "acpi.h" #if NACPI > 0 @@ -29,6 +30,11 @@ #endif #endif +#include "pci.h" +#if NPCI > 0 +#define CONFIG_PCI 1 +#endif + #include "agp.h" #if NAGP > 0 #define CONFIG_AGP 1 @@ -49,3 +55,29 @@ #define CONFIG_X86_32 1 #define CONFIG_X86_PAT 1 #endif + +#ifdef __arm__ +#define CONFIG_ARM 1 +#endif + +#ifdef __arm64__ +#define CONFIG_ARM64 1 +#endif + +#ifdef __macppc__ +#define CONFIG_PPC 1 +#define CONFIG_PPC_PMAC 1 +#endif + +#ifdef __powerpc64__ +#define CONFIG_PPC64 1 +#endif + +#ifdef __loongson__ +#define CONFIG_MIPS 1 +#define CONFIG_CPU_LOONGSON64 1 +#endif + +#ifdef __LP64__ +#define CONFIG_64BIT 1 +#endif diff --git a/sys/dev/pci/drm/include/linux/agp_backend.h b/sys/dev/pci/drm/include/linux/agp_backend.h index 452d8e92834..c3f937853a9 100644 --- a/sys/dev/pci/drm/include/linux/agp_backend.h +++ b/sys/dev/pci/drm/include/linux/agp_backend.h @@ -10,4 +10,6 @@ #define AGP_USER_CACHED_MEMORY BUS_DMA_COHERENT #endif +struct drm_agp_head; + #endif diff --git a/sys/dev/pci/drm/include/linux/ascii85.h b/sys/dev/pci/drm/include/linux/ascii85.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/ascii85.h diff --git a/sys/dev/pci/drm/include/linux/atomic.h b/sys/dev/pci/drm/include/linux/atomic.h index 5e23da1490e..bb43b294c4c 100644 --- a/sys/dev/pci/drm/include/linux/atomic.h +++ b/sys/dev/pci/drm/include/linux/atomic.h @@ -1,4 +1,4 @@ -/* $OpenBSD: atomic.h,v 1.5 2019/08/17 06:07:22 jsg Exp $ */ +/* $OpenBSD: atomic.h,v 1.6 2020/06/08 04:48:14 jsg Exp $ */ /** * \file drm_atomic.h * Atomic operations used in the DRM which may or may not be provided by the OS. @@ -36,8 +36,10 @@ #include <sys/types.h> #include <sys/mutex.h> #include <machine/intr.h> -#include <machine/atomic.h> #include <linux/types.h> +#include <linux/compiler.h> /* via x86/include/asm/atomic.h */ + +#define ATOMIC_INIT(x) (x) #define atomic_set(p, v) (*(p) = (v)) #define atomic_read(p) (*(p)) @@ -45,17 +47,34 @@ #define atomic_dec(p) __sync_fetch_and_sub(p, 1) #define atomic_add(n, p) __sync_fetch_and_add(p, n) #define atomic_sub(n, p) __sync_fetch_and_sub(p, n) +#define atomic_and(n, p) __sync_fetch_and_and(p, n) +#define atomic_or(n, p) atomic_setbits_int(p, n) #define atomic_add_return(n, p) __sync_add_and_fetch(p, n) #define atomic_sub_return(n, p) __sync_sub_and_fetch(p, n) #define atomic_inc_return(v) atomic_add_return(1, (v)) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) -#define atomic_or(n, p) atomic_setbits_int(p, n) #define atomic_cmpxchg(p, o, n) __sync_val_compare_and_swap(p, o, n) #define cmpxchg(p, o, n) __sync_val_compare_and_swap(p, o, n) #define atomic_set_release(p, v) atomic_set((p), (v)) +#define try_cmpxchg(p, op, n) \ +({ \ + __typeof(p) __op = (__typeof((p)))(op); \ + __typeof(*(p)) __o = *__op; \ + __typeof(*(p)) __p = __sync_val_compare_and_swap((p), (__o), (n)); \ + if (__p != __o) \ + *__op = __p; \ + (__p == __o); \ +}) + +static inline bool +atomic_try_cmpxchg(volatile int *p, int *op, int n) +{ + return try_cmpxchg(p, op, n); +} + static inline int atomic_xchg(volatile int *v, int n) { @@ -99,6 +118,8 @@ atomic_dec_if_positive(volatile int *v) #ifdef __LP64__ typedef int64_t atomic64_t; +#define ATOMIC64_INIT(x) (x) + #define atomic64_set(p, v) (*(p) = (v)) #define atomic64_read(p) (*(p)) @@ -122,6 +143,8 @@ typedef struct { struct mutex lock; } atomic64_t; +#define ATOMIC64_INIT(x) { (x), .lock = MUTEX_INITIALIZER(IPL_HIGH) } + static inline void atomic64_set(atomic64_t *v, int64_t i) { @@ -236,6 +259,13 @@ clear_bit(u_int b, volatile void *p) } static inline void +clear_bit_unlock(u_int b, volatile void *p) +{ + membar_enter(); + clear_bit(b, p); +} + +static inline void set_bit(u_int b, volatile void *p) { atomic_set_int(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f)); diff --git a/sys/dev/pci/drm/include/linux/average.h b/sys/dev/pci/drm/include/linux/average.h new file mode 100644 index 00000000000..d78c65b78b4 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/average.h @@ -0,0 +1,38 @@ +/* Public domain. */ + +#ifndef _LINUX_AVERAGE_H +#define _LINUX_AVERAGE_H + +#include <sys/types.h> +#include <lib/libkern/libkern.h> + +#define DECLARE_EWMA(name, precision, recip) \ +struct ewma_##name { \ + u_long value; \ +}; \ + \ +static inline void \ +ewma_##name##_init(struct ewma_##name *p) \ +{ \ + p->value = 0; \ +} \ + \ +static inline void \ +ewma_##name##_add(struct ewma_##name *p, u_long value) \ +{ \ + u_long shift = fls(recip) - 1; \ + \ + if (p->value == 0) \ + p->value = (value << (precision)); \ + else \ + p->value = ((((p->value << shift) - p->value) + \ + (value << (precision))) >> shift); \ +} \ + \ +static inline u_long \ +ewma_##name##_read(struct ewma_##name *p) \ +{ \ + return (p->value >> (precision)); \ +} + +#endif diff --git a/sys/dev/pci/drm/include/linux/backlight.h b/sys/dev/pci/drm/include/linux/backlight.h index fa559dbe047..cfcec3220e9 100644 --- a/sys/dev/pci/drm/include/linux/backlight.h +++ b/sys/dev/pci/drm/include/linux/backlight.h @@ -54,4 +54,9 @@ backlight_force_update(struct backlight_device *bd, int reason) void backlight_schedule_update_status(struct backlight_device *); +int backlight_enable(struct backlight_device *); +int backlight_disable(struct backlight_device *); + +#define devm_of_find_backlight(x) NULL + #endif diff --git a/sys/dev/pci/drm/include/linux/bitfield.h b/sys/dev/pci/drm/include/linux/bitfield.h new file mode 100644 index 00000000000..909ddaa8bac --- /dev/null +++ b/sys/dev/pci/drm/include/linux/bitfield.h @@ -0,0 +1,16 @@ +/* Public domain. */ + +#ifndef _LINUX_BITFIELD_H +#define _LINUX_BITFIELD_H + +#include <asm/byteorder.h> + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define FIELD_GET(_m, _v) \ + ((typeof(_m))(((_v) & (_m)) >> __bf_shf(_m))) + +#define FIELD_PREP(_m, _v) \ + (((typeof(_m))(_v) << __bf_shf(_m)) & (_m)) + +#endif diff --git a/sys/dev/pci/drm/include/linux/bitmap.h b/sys/dev/pci/drm/include/linux/bitmap.h index dc2055db5d2..c3160639a75 100644 --- a/sys/dev/pci/drm/include/linux/bitmap.h +++ b/sys/dev/pci/drm/include/linux/bitmap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bitmap.h,v 1.2 2019/07/11 04:26:37 jsg Exp $ */ +/* $OpenBSD: bitmap.h,v 1.3 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -64,6 +64,18 @@ bitmap_or(void *d, void *s1, void *s2, u_int n) } static inline void +bitmap_andnot(void *d, void *s1, void *s2, u_int n) +{ + u_int *dst = d; + u_int *src1 = s1; + u_int *src2 = s2; + u_int b; + + for (b = 0; b < n; b += 32) + dst[b >> 5] = src1[b >> 5] & ~src2[b >> 5]; +} + +static inline void bitmap_complement(void *d, void *s, u_int n) { u_int *dst = d; @@ -74,6 +86,17 @@ bitmap_complement(void *d, void *s, u_int n) dst[b >> 5] = ~src[b >> 5]; } +static inline void +bitmap_copy(void *d, void *s, u_int n) +{ + u_int *dst = d; + u_int *src = s; + u_int b; + + for (b = 0; b < n; b += 32) + dst[b >> 5] = src[b >> 5]; +} + static inline int bitmap_weight(void *p, u_int n) { @@ -86,4 +109,7 @@ bitmap_weight(void *p, u_int n) return sum; } +void *bitmap_zalloc(u_int, gfp_t); +void bitmap_free(void *); + #endif diff --git a/sys/dev/pci/drm/include/linux/bitops.h b/sys/dev/pci/drm/include/linux/bitops.h index 73317e1791b..72bf3b79590 100644 --- a/sys/dev/pci/drm/include/linux/bitops.h +++ b/sys/dev/pci/drm/include/linux/bitops.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bitops.h,v 1.2 2019/11/24 02:29:43 jsg Exp $ */ +/* $OpenBSD: bitops.h,v 1.3 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -25,13 +25,19 @@ #define BIT(x) (1UL << (x)) #define BIT_ULL(x) (1ULL << (x)) +#define BIT_MASK(x) (1UL << ((x) % BITS_PER_LONG)) #define BITS_PER_BYTE 8 #define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l))) #define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l))) +#define BITS_PER_TYPE(x) (8 * sizeof(x)) #define BITS_TO_LONGS(x) howmany((x), 8 * sizeof(long)) +/* despite the name these are really ctz */ +#define __ffs(x) __builtin_ctzl(x) +#define __ffs64(x) __builtin_ctzll(x) + static inline uint8_t hweight8(uint32_t x) { diff --git a/sys/dev/pci/drm/include/linux/bits.h b/sys/dev/pci/drm/include/linux/bits.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/bits.h diff --git a/sys/dev/pci/drm/include/linux/bottom_half.h b/sys/dev/pci/drm/include/linux/bottom_half.h index 1261bf12fe1..9d13c06ac56 100644 --- a/sys/dev/pci/drm/include/linux/bottom_half.h +++ b/sys/dev/pci/drm/include/linux/bottom_half.h @@ -3,6 +3,8 @@ #ifndef _LINUX_BOTTOM_HALF_H #define _LINUX_BOTTOM_HALF_H +#include <linux/preempt.h> + #define local_bh_disable() #define local_bh_enable() diff --git a/sys/dev/pci/drm/include/linux/build_bug.h b/sys/dev/pci/drm/include/linux/build_bug.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/build_bug.h diff --git a/sys/dev/pci/drm/include/linux/byteorder/generic.h b/sys/dev/pci/drm/include/linux/byteorder/generic.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/byteorder/generic.h diff --git a/sys/dev/pci/drm/include/linux/compiler.h b/sys/dev/pci/drm/include/linux/compiler.h index c2f09e25afe..6e7c02ddb19 100644 --- a/sys/dev/pci/drm/include/linux/compiler.h +++ b/sys/dev/pci/drm/include/linux/compiler.h @@ -4,11 +4,14 @@ #define _LINUX_COMPILER_H #include <linux/kconfig.h> +#include <sys/atomic.h> /* for READ_ONCE() WRITE_ONCE() */ #define unlikely(x) __builtin_expect(!!(x), 0) #define likely(x) __builtin_expect(!!(x), 1) #define __force +#define __acquires(x) +#define __releases(x) #define __always_unused __unused #define __maybe_unused #define __read_mostly @@ -19,6 +22,7 @@ #define __deprecated #define __always_inline inline #define noinline __attribute__((noinline)) +#define fallthrough do {} while (0) #ifndef __user #define __user @@ -30,4 +34,20 @@ #define uninitialized_var(x) x +/* The Linux code doesn't meet our usual standards! */ +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wenum-conversion" +#pragma clang diagnostic ignored "-Winitializer-overrides" +#pragma clang diagnostic ignored "-Wtautological-compare" +#pragma clang diagnostic ignored "-Wunneeded-internal-declaration" +#pragma clang diagnostic ignored "-Wunused-const-variable" +#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wparentheses-equality" +#pragma clang diagnostic ignored "-Wmissing-braces" +#else +#pragma GCC diagnostic ignored "-Wformat-zero-length" +#endif + #endif diff --git a/sys/dev/pci/drm/include/linux/completion.h b/sys/dev/pci/drm/include/linux/completion.h index 0fb61e8c288..f1233514f80 100644 --- a/sys/dev/pci/drm/include/linux/completion.h +++ b/sys/dev/pci/drm/include/linux/completion.h @@ -1,4 +1,4 @@ -/* $OpenBSD: completion.h,v 1.3 2019/12/30 09:30:31 mpi Exp $ */ +/* $OpenBSD: completion.h,v 1.4 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2015, 2018 Mark Kettenis * @@ -35,6 +35,12 @@ init_completion(struct completion *x) mtx_init(&x->wait.lock, IPL_TTY); } +static inline void +reinit_completion(struct completion *x) +{ + x->done = 0; +} + static inline u_long wait_for_completion_timeout(struct completion *x, u_long timo) { @@ -57,6 +63,27 @@ wait_for_completion_timeout(struct completion *x, u_long timo) } static inline u_long +wait_for_completion(struct completion *x) +{ + int ret; + + KASSERT(!cold); + + mtx_enter(&x->wait.lock); + while (x->done == 0) { + ret = msleep_nsec(x, &x->wait.lock, 0, "wfci", INFSLP); + if (ret) { + mtx_leave(&x->wait.lock); + return (ret == EWOULDBLOCK) ? 0 : -ret; + } + } + x->done--; + mtx_leave(&x->wait.lock); + + return 0; +} + +static inline u_long wait_for_completion_interruptible(struct completion *x) { int ret; @@ -99,6 +126,16 @@ wait_for_completion_interruptible_timeout(struct completion *x, u_long timo) } static inline void +complete(struct completion *x) +{ + mtx_enter(&x->wait.lock); + if (x->done != UINT_MAX) + x->done++; + mtx_leave(&x->wait.lock); + wakeup(x); +} + +static inline void complete_all(struct completion *x) { mtx_enter(&x->wait.lock); diff --git a/sys/dev/pci/drm/include/linux/component.h b/sys/dev/pci/drm/include/linux/component.h index e69de29bb2d..c20c085a61d 100644 --- a/sys/dev/pci/drm/include/linux/component.h +++ b/sys/dev/pci/drm/include/linux/component.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_COMPONENT_H +#define _LINUX_COMPONENT_H + +#define component_del(a, b) + +#endif diff --git a/sys/dev/pci/drm/include/linux/debugfs.h b/sys/dev/pci/drm/include/linux/debugfs.h index e69de29bb2d..bd5fc702ee0 100644 --- a/sys/dev/pci/drm/include/linux/debugfs.h +++ b/sys/dev/pci/drm/include/linux/debugfs.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_DEBUGFS_H +#define _LINUX_DEBUGFS_H + +struct debugfs_regset32 { +}; + +#endif diff --git a/sys/dev/pci/drm/include/linux/debugobjects.h b/sys/dev/pci/drm/include/linux/debugobjects.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/debugobjects.h diff --git a/sys/dev/pci/drm/include/linux/delay.h b/sys/dev/pci/drm/include/linux/delay.h index 157ef90c3f3..19f0ef92204 100644 --- a/sys/dev/pci/drm/include/linux/delay.h +++ b/sys/dev/pci/drm/include/linux/delay.h @@ -31,4 +31,6 @@ mdelay(unsigned long msecs) DELAY(1000); } +#define drm_msleep(x) mdelay(x) + #endif diff --git a/sys/dev/pci/drm/include/linux/device.h b/sys/dev/pci/drm/include/linux/device.h index 21bcf29e1ad..14bf41401dc 100644 --- a/sys/dev/pci/drm/include/linux/device.h +++ b/sys/dev/pci/drm/include/linux/device.h @@ -12,6 +12,8 @@ #include <linux/ioport.h> #include <linux/lockdep.h> #include <linux/pm.h> +#include <linux/kobject.h> +#include <linux/ratelimit.h> /* dev_printk.h -> ratelimit.h */ struct device_node; @@ -20,6 +22,8 @@ struct device_driver { }; struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *, struct device_attribute *, char *); }; #define DEVICE_ATTR(_name, _mode, _show, _store) \ @@ -30,7 +34,6 @@ struct device_attribute { #define dev_get_drvdata(x) NULL #define dev_set_drvdata(x, y) -#define dev_name(dev) "" #define dev_pm_set_driver_flags(x, y) @@ -52,6 +55,17 @@ struct device_attribute { printf("drm:pid%d:%s *PRINTK* " fmt, curproc->p_p->ps_pid, \ __func__ , ## arg) +#define dev_warn_ratelimited(dev, fmt, arg...) \ + printf("drm:pid%d:%s *WARNING* " fmt, curproc->p_p->ps_pid, \ + __func__ , ## arg) +#define dev_notice_ratelimited(dev, fmt, arg...) \ + printf("drm:pid%d:%s *NOTICE* " fmt, curproc->p_p->ps_pid, \ + __func__ , ## arg) + +#define dev_err_once(dev, fmt, arg...) \ + printf("drm:pid%d:%s *ERROR* " fmt, curproc->p_p->ps_pid, \ + __func__ , ## arg) + #ifdef DRMDEBUG #define dev_info(dev, fmt, arg...) \ printf("drm: " fmt, ## arg) @@ -65,4 +79,13 @@ struct device_attribute { do { } while(0) #endif +static inline const char * +dev_driver_string(struct device *dev) +{ + return dev->dv_cfdata->cf_driver->cd_name; +} + +/* should be bus id as string, ie 0000:00:02.0 */ +#define dev_name(dev) "" + #endif diff --git a/sys/dev/pci/drm/include/linux/dma-buf.h b/sys/dev/pci/drm/include/linux/dma-buf.h index 69ee26eea33..04fa939f63a 100644 --- a/sys/dev/pci/drm/include/linux/dma-buf.h +++ b/sys/dev/pci/drm/include/linux/dma-buf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dma-buf.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: dma-buf.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -20,7 +20,8 @@ #include <sys/types.h> #include <sys/systm.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> +#include <linux/list.h> struct dma_buf_ops; @@ -29,9 +30,17 @@ struct dma_buf { void *priv; size_t size; struct file *file; + struct list_head attachments; + struct dma_resv *resv; }; -struct dma_buf_attachment; +struct dma_buf_attachment { + void *importer_priv; +}; + +struct dma_buf_attach_ops { + void (*move_notify)(struct dma_buf_attachment *); +}; void get_dma_buf(struct dma_buf *); struct dma_buf *dma_buf_get(int); @@ -47,7 +56,7 @@ struct dma_buf_export_info { size_t size; int flags; void *priv; - struct reservation_object *resv; + struct dma_resv *resv; }; #define DEFINE_DMA_BUF_EXPORT_INFO(x) struct dma_buf_export_info x diff --git a/sys/dev/pci/drm/include/linux/dma-fence-chain.h b/sys/dev/pci/drm/include/linux/dma-fence-chain.h new file mode 100644 index 00000000000..8d1ac5d5337 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/dma-fence-chain.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_DMA_FENCE_CHAIN_H +#define _LINUX_DMA_FENCE_CHAIN_H + +struct dma_fence_chain { +}; + +#endif diff --git a/sys/dev/pci/drm/include/linux/dma-fence.h b/sys/dev/pci/drm/include/linux/dma-fence.h index 5b94d067bb6..5b02546f7f4 100644 --- a/sys/dev/pci/drm/include/linux/dma-fence.h +++ b/sys/dev/pci/drm/include/linux/dma-fence.h @@ -18,16 +18,18 @@ struct dma_fence { struct kref refcount; const struct dma_fence_ops *ops; unsigned long flags; - unsigned int context; - unsigned int seqno; + uint64_t context; + uint64_t seqno; struct mutex *lock; struct list_head cb_list; int error; struct rcu_head rcu; + ktime_t timestamp; }; enum dma_fence_flag_bits { DMA_FENCE_FLAG_SIGNALED_BIT, + DMA_FENCE_FLAG_TIMESTAMP_BIT, DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, DMA_FENCE_FLAG_USER_BITS, }; @@ -49,7 +51,7 @@ struct dma_fence_cb { dma_fence_func_t func; }; -unsigned int dma_fence_context_alloc(unsigned int); +uint64_t dma_fence_context_alloc(unsigned int); static inline struct dma_fence * dma_fence_get(struct dma_fence *fence) @@ -103,45 +105,43 @@ dma_fence_put(struct dma_fence *fence) } static inline int -dma_fence_signal(struct dma_fence *fence) +dma_fence_signal_locked(struct dma_fence *fence) { + struct dma_fence_cb *cur, *tmp; + struct list_head cb_list; + if (fence == NULL) return -EINVAL; if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) return -EINVAL; - if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) { - struct dma_fence_cb *cur, *tmp; + list_replace(&fence->cb_list, &cb_list); - mtx_enter(fence->lock); - list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { - list_del_init(&cur->node); - cur->func(fence, cur); - } - mtx_leave(fence->lock); + fence->timestamp = ktime_get(); + set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); + + list_for_each_entry_safe(cur, tmp, &cb_list, node) { + INIT_LIST_HEAD(&cur->node); + cur->func(fence, cur); } return 0; } static inline int -dma_fence_signal_locked(struct dma_fence *fence) +dma_fence_signal(struct dma_fence *fence) { - struct dma_fence_cb *cur, *tmp; + int r; if (fence == NULL) return -EINVAL; - if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return -EINVAL; - - list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { - list_del_init(&cur->node); - cur->func(fence, cur); - } + mtx_enter(fence->lock); + r = dma_fence_signal_locked(fence); + mtx_leave(fence->lock); - return 0; + return r; } static inline bool @@ -213,7 +213,7 @@ dma_fence_enable_sw_signaling(struct dma_fence *fence) static inline void dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, - struct mutex *lock, unsigned context, unsigned seqno) + struct mutex *lock, uint64_t context, uint64_t seqno) { fence->ops = ops; fence->lock = lock; @@ -294,4 +294,6 @@ dma_fence_set_error(struct dma_fence *fence, int error) long dma_fence_wait_any_timeout(struct dma_fence **, uint32_t, bool, long, uint32_t *); +struct dma_fence *dma_fence_get_stub(void); + #endif diff --git a/sys/dev/pci/drm/include/linux/dma-mapping.h b/sys/dev/pci/drm/include/linux/dma-mapping.h index 5c33c31c5ea..1e06dac6d3e 100644 --- a/sys/dev/pci/drm/include/linux/dma-mapping.h +++ b/sys/dev/pci/drm/include/linux/dma-mapping.h @@ -4,10 +4,13 @@ #define _LINUX_DMA_MAPPING_H #include <linux/sizes.h> +#include <linux/scatterlist.h> #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) -1) #define dma_set_coherent_mask(x, y) 0 #define dma_set_max_seg_size(x, y) 0 +#define dma_set_mask_and_coherent(x, y) 0 +#define dma_addressing_limited(x) false #endif diff --git a/sys/dev/pci/drm/include/linux/reservation.h b/sys/dev/pci/drm/include/linux/dma-resv.h index 02166e815af..ee50d10f052 100644 --- a/sys/dev/pci/drm/include/linux/reservation.h +++ b/sys/dev/pci/drm/include/linux/dma-resv.h @@ -50,102 +50,52 @@ extern struct lock_class_key reservation_seqcount_class; extern const char reservation_seqcount_string[]; /** - * struct reservation_object_list - a list of shared fences + * struct dma_resv_list - a list of shared fences * @rcu: for internal use * @shared_count: table of shared fences * @shared_max: for growing shared fence table * @shared: shared fence table */ -struct reservation_object_list { +struct dma_resv_list { struct rcu_head rcu; u32 shared_count, shared_max; struct dma_fence __rcu *shared[]; }; /** - * struct reservation_object - a reservation object manages fences for a buffer + * struct dma_resv - a reservation object manages fences for a buffer * @lock: update side lock * @seq: sequence count for managing RCU read-side synchronization * @fence_excl: the exclusive fence, if there is one currently * @fence: list of current shared fences - * @staged: staged copy of shared fences for RCU updates */ -struct reservation_object { +struct dma_resv { struct ww_mutex lock; seqcount_t seq; struct dma_fence __rcu *fence_excl; - struct reservation_object_list __rcu *fence; - struct reservation_object_list *staged; + struct dma_resv_list __rcu *fence; }; -#define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base) -#define reservation_object_assert_held(obj) \ - lockdep_assert_held(&(obj)->lock.base) +#define dma_resv_held(obj) lockdep_is_held(&(obj)->lock.base) +#define dma_resv_assert_held(obj) lockdep_assert_held(&(obj)->lock.base) /** - * reservation_object_init - initialize a reservation object - * @obj: the reservation object - */ -static inline void -reservation_object_init(struct reservation_object *obj) -{ - ww_mutex_init(&obj->lock, &reservation_ww_class); - - __seqcount_init(&obj->seq, reservation_seqcount_string, &reservation_seqcount_class); - RCU_INIT_POINTER(obj->fence, NULL); - RCU_INIT_POINTER(obj->fence_excl, NULL); - obj->staged = NULL; -} - -/** - * reservation_object_fini - destroys a reservation object - * @obj: the reservation object - */ -static inline void -reservation_object_fini(struct reservation_object *obj) -{ - int i; - struct reservation_object_list *fobj; - struct dma_fence *excl; - - /* - * This object should be dead and all references must have - * been released to it, so no need to be protected with rcu. - */ - excl = rcu_dereference_protected(obj->fence_excl, 1); - if (excl) - dma_fence_put(excl); - - fobj = rcu_dereference_protected(obj->fence, 1); - if (fobj) { - for (i = 0; i < fobj->shared_count; ++i) - dma_fence_put(rcu_dereference_protected(fobj->shared[i], 1)); - - kfree(fobj); - } - kfree(obj->staged); - - ww_mutex_destroy(&obj->lock); -} - -/** - * reservation_object_get_list - get the reservation object's + * dma_resv_get_list - get the reservation object's * shared fence list, with update-side lock held * @obj: the reservation object * * Returns the shared fence list. Does NOT take references to * the fence. The obj->lock must be held. */ -static inline struct reservation_object_list * -reservation_object_get_list(struct reservation_object *obj) +static inline struct dma_resv_list *dma_resv_get_list(struct dma_resv *obj) { return rcu_dereference_protected(obj->fence, - reservation_object_held(obj)); + dma_resv_held(obj)); } /** - * reservation_object_lock - lock the reservation object + * dma_resv_lock - lock the reservation object * @obj: the reservation object * @ctx: the locking context * @@ -159,15 +109,14 @@ reservation_object_get_list(struct reservation_object *obj) * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. */ -static inline int -reservation_object_lock(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline int dma_resv_lock(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { return ww_mutex_lock(&obj->lock, ctx); } /** - * reservation_object_lock_interruptible - lock the reservation object + * dma_resv_lock_interruptible - lock the reservation object * @obj: the reservation object * @ctx: the locking context * @@ -181,16 +130,45 @@ reservation_object_lock(struct reservation_object *obj, * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. */ -static inline int -reservation_object_lock_interruptible(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline int dma_resv_lock_interruptible(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { return ww_mutex_lock_interruptible(&obj->lock, ctx); } +/** + * dma_resv_lock_slow - slowpath lock the reservation object + * @obj: the reservation object + * @ctx: the locking context + * + * Acquires the reservation object after a die case. This function + * will sleep until the lock becomes available. See dma_resv_lock() as + * well. + */ +static inline void dma_resv_lock_slow(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) +{ + ww_mutex_lock_slow(&obj->lock, ctx); +} /** - * reservation_object_trylock - trylock the reservation object + * dma_resv_lock_slow_interruptible - slowpath lock the reservation + * object, interruptible + * @obj: the reservation object + * @ctx: the locking context + * + * Acquires the reservation object interruptible after a die case. This function + * will sleep until the lock becomes available. See + * dma_resv_lock_interruptible() as well. + */ +static inline int dma_resv_lock_slow_interruptible(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) +{ + return ww_mutex_lock_slow_interruptible(&obj->lock, ctx); +} + +/** + * dma_resv_trylock - trylock the reservation object * @obj: the reservation object * * Tries to lock the reservation object for exclusive access and modification. @@ -203,44 +181,74 @@ reservation_object_lock_interruptible(struct reservation_object *obj, * * Returns true if the lock was acquired, false otherwise. */ -static inline bool __must_check -reservation_object_trylock(struct reservation_object *obj) +static inline bool __must_check dma_resv_trylock(struct dma_resv *obj) { return ww_mutex_trylock(&obj->lock); } /** - * reservation_object_unlock - unlock the reservation object + * dma_resv_is_locked - is the reservation object locked + * @obj: the reservation object + * + * Returns true if the mutex is locked, false if unlocked. + */ +static inline bool dma_resv_is_locked(struct dma_resv *obj) +{ + return ww_mutex_is_locked(&obj->lock); +} + +/** + * dma_resv_locking_ctx - returns the context used to lock the object + * @obj: the reservation object + * + * Returns the context used to lock a reservation object or NULL if no context + * was used or the object is not locked at all. + */ +static inline struct ww_acquire_ctx *dma_resv_locking_ctx(struct dma_resv *obj) +{ + return READ_ONCE(obj->lock.ctx); +} + +/** + * dma_resv_unlock - unlock the reservation object * @obj: the reservation object * * Unlocks the reservation object following exclusive access. */ -static inline void -reservation_object_unlock(struct reservation_object *obj) +static inline void dma_resv_unlock(struct dma_resv *obj) { +#ifdef CONFIG_DEBUG_MUTEXES + /* Test shared fence slot reservation */ + if (rcu_access_pointer(obj->fence)) { + struct dma_resv_list *fence = dma_resv_get_list(obj); + + fence->shared_max = fence->shared_count; + } +#endif ww_mutex_unlock(&obj->lock); } /** - * reservation_object_get_excl - get the reservation object's + * dma_resv_get_excl - get the reservation object's * exclusive fence, with update-side lock held * @obj: the reservation object * * Returns the exclusive fence (if any). Does NOT take a - * reference. The obj->lock must be held. + * reference. Writers must hold obj->lock, readers may only + * hold a RCU read side lock. * * RETURNS * The exclusive fence or NULL */ static inline struct dma_fence * -reservation_object_get_excl(struct reservation_object *obj) +dma_resv_get_excl(struct dma_resv *obj) { return rcu_dereference_protected(obj->fence_excl, - reservation_object_held(obj)); + dma_resv_held(obj)); } /** - * reservation_object_get_excl_rcu - get the reservation object's + * dma_resv_get_excl_rcu - get the reservation object's * exclusive fence, without lock held. * @obj: the reservation object * @@ -251,7 +259,7 @@ reservation_object_get_excl(struct reservation_object *obj) * The exclusive fence or NULL if none */ static inline struct dma_fence * -reservation_object_get_excl_rcu(struct reservation_object *obj) +dma_resv_get_excl_rcu(struct dma_resv *obj) { struct dma_fence *fence; @@ -265,26 +273,23 @@ reservation_object_get_excl_rcu(struct reservation_object *obj) return fence; } -int reservation_object_reserve_shared(struct reservation_object *obj); -void reservation_object_add_shared_fence(struct reservation_object *obj, - struct dma_fence *fence); +void dma_resv_init(struct dma_resv *obj); +void dma_resv_fini(struct dma_resv *obj); +int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences); +void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence); -void reservation_object_add_excl_fence(struct reservation_object *obj, - struct dma_fence *fence); +void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); -int reservation_object_get_fences_rcu(struct reservation_object *obj, - struct dma_fence **pfence_excl, - unsigned *pshared_count, - struct dma_fence ***pshared); +int dma_resv_get_fences_rcu(struct dma_resv *obj, + struct dma_fence **pfence_excl, + unsigned *pshared_count, + struct dma_fence ***pshared); -int reservation_object_copy_fences(struct reservation_object *dst, - struct reservation_object *src); +int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); -long reservation_object_wait_timeout_rcu(struct reservation_object *obj, - bool wait_all, bool intr, - unsigned long timeout); +long dma_resv_wait_timeout_rcu(struct dma_resv *obj, bool wait_all, bool intr, + unsigned long timeout); -bool reservation_object_test_signaled_rcu(struct reservation_object *obj, - bool test_all); +bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all); #endif /* _LINUX_RESERVATION_H */ diff --git a/sys/dev/pci/drm/include/linux/errno.h b/sys/dev/pci/drm/include/linux/errno.h index 99c6d662fcf..2a85ac1e7cc 100644 --- a/sys/dev/pci/drm/include/linux/errno.h +++ b/sys/dev/pci/drm/include/linux/errno.h @@ -11,5 +11,6 @@ #define ENOTSUPP ENOTSUP #define ENODATA ENOTSUP #define ECHRNG EINVAL +#define EHWPOISON EIO #endif diff --git a/sys/dev/pci/drm/include/linux/fb.h b/sys/dev/pci/drm/include/linux/fb.h index 463de7f2cf7..70170be0b69 100644 --- a/sys/dev/pci/drm/include/linux/fb.h +++ b/sys/dev/pci/drm/include/linux/fb.h @@ -8,6 +8,14 @@ #include <linux/notifier.h> #include <linux/backlight.h> #include <linux/kgdb.h> +#include <linux/fs.h> + +struct fb_cmap; +struct fb_fillrect; +struct fb_copyarea; +struct fb_image; + +struct apertures_struct; struct fb_var_screeninfo { int pixclock; @@ -21,8 +29,11 @@ struct fb_info { void *par; int fbcon_rotate_hint; bool skip_vt_switch; + int flags; }; +#define KHZ2PICOS(a) (1000000000UL/(a)) + #define FB_BLANK_UNBLANK 0 #define FB_BLANK_NORMAL 1 #define FB_BLANK_HSYNC_SUSPEND 2 @@ -32,14 +43,45 @@ struct fb_info { #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 +#define FBINFO_HIDE_SMEM_START 0 + #define FB_ROTATE_UR 0 #define FB_ROTATE_CW 1 #define FB_ROTATE_UD 2 #define FB_ROTATE_CCW 3 -#define framebuffer_alloc(flags, device) \ - kzalloc(sizeof(struct fb_info), GFP_KERNEL) +static inline struct fb_info * +framebuffer_alloc(size_t size, void *dev) +{ + return kzalloc(sizeof(struct fb_info) + size, GFP_KERNEL); +} + +static inline void +fb_set_suspend(struct fb_info *fbi, int s) +{ +} + +static inline void +framebuffer_release(struct fb_info *fbi) +{ + kfree(fbi); +} + +static inline int +fb_get_options(const char *name, char **opt) +{ + return 0; +} + +static inline int +register_framebuffer(struct fb_info *fbi) +{ + return 0; +} -#define fb_set_suspend(x, y) +static inline void +unregister_framebuffer(struct fb_info *fbi) +{ +} #endif diff --git a/sys/dev/pci/drm/include/linux/firmware.h b/sys/dev/pci/drm/include/linux/firmware.h index 4e24fc963ca..e3406bf6787 100644 --- a/sys/dev/pci/drm/include/linux/firmware.h +++ b/sys/dev/pci/drm/include/linux/firmware.h @@ -7,6 +7,7 @@ #include <sys/malloc.h> #include <sys/device.h> #include <linux/types.h> +#include <linux/gfp.h> #ifndef __DECONST #define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var)) diff --git a/sys/dev/pci/drm/include/linux/fs.h b/sys/dev/pci/drm/include/linux/fs.h index 19ca23adc33..be033dc5d11 100644 --- a/sys/dev/pci/drm/include/linux/fs.h +++ b/sys/dev/pci/drm/include/linux/fs.h @@ -12,6 +12,8 @@ #include <linux/pid.h> #include <linux/radix-tree.h> #include <linux/wait_bit.h> +#include <linux/err.h> +#include <linux/sched/signal.h> /* via percpu-rwsem.h -> rcuwait.h */ struct address_space; diff --git a/sys/dev/pci/drm/include/linux/ftrace.h b/sys/dev/pci/drm/include/linux/ftrace.h new file mode 100644 index 00000000000..2754e2477b9 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/ftrace.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_FTRACE_H +#define _LINUX_FTRACE_H + +#include <linux/kallsyms.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/gfp.h b/sys/dev/pci/drm/include/linux/gfp.h index dcffa2ef49d..d1c8d60162d 100644 --- a/sys/dev/pci/drm/include/linux/gfp.h +++ b/sys/dev/pci/drm/include/linux/gfp.h @@ -7,6 +7,8 @@ #include <sys/malloc.h> #include <uvm/uvm_extern.h> +#include <linux/mmzone.h> + #define __GFP_ZERO M_ZERO #define __GFP_DMA32 0x00010000 #define __GFP_NOWARN 0 diff --git a/sys/dev/pci/drm/include/linux/hashtable.h b/sys/dev/pci/drm/include/linux/hashtable.h index 26660bf65bf..ccc72458351 100644 --- a/sys/dev/pci/drm/include/linux/hashtable.h +++ b/sys/dev/pci/drm/include/linux/hashtable.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hashtable.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: hashtable.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -19,6 +19,7 @@ #define _LINUX_HASHTABLE_H #include <linux/list.h> +#include <linux/hash.h> #define DECLARE_HASHTABLE(name, bits) struct hlist_head name[1 << (bits)] diff --git a/sys/dev/pci/drm/include/linux/hdmi.h b/sys/dev/pci/drm/include/linux/hdmi.h index 4f3febc0f97..9613d796cfb 100644 --- a/sys/dev/pci/drm/include/linux/hdmi.h +++ b/sys/dev/pci/drm/include/linux/hdmi.h @@ -27,11 +27,27 @@ #include <linux/types.h> #include <linux/device.h> +enum hdmi_packet_type { + HDMI_PACKET_TYPE_NULL = 0x00, + HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01, + HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02, + HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03, + HDMI_PACKET_TYPE_ACP = 0x04, + HDMI_PACKET_TYPE_ISRC1 = 0x05, + HDMI_PACKET_TYPE_ISRC2 = 0x06, + HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07, + HDMI_PACKET_TYPE_DST_AUDIO = 0x08, + HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09, + HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a, + /* + enum hdmi_infoframe_type */ +}; + enum hdmi_infoframe_type { HDMI_INFOFRAME_TYPE_VENDOR = 0x81, HDMI_INFOFRAME_TYPE_AVI = 0x82, HDMI_INFOFRAME_TYPE_SPD = 0x83, HDMI_INFOFRAME_TYPE_AUDIO = 0x84, + HDMI_INFOFRAME_TYPE_DRM = 0x87, }; #define HDMI_IEEE_OUI 0x000c03 @@ -40,6 +56,7 @@ enum hdmi_infoframe_type { #define HDMI_AVI_INFOFRAME_SIZE 13 #define HDMI_SPD_INFOFRAME_SIZE 25 #define HDMI_AUDIO_INFOFRAME_SIZE 10 +#define HDMI_DRM_INFOFRAME_SIZE 26 #define HDMI_INFOFRAME_SIZE(type) \ (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) @@ -137,6 +154,17 @@ enum hdmi_content_type { HDMI_CONTENT_TYPE_GAME, }; +enum hdmi_metadata_type { + HDMI_STATIC_METADATA_TYPE1 = 1, +}; + +enum hdmi_eotf { + HDMI_EOTF_TRADITIONAL_GAMMA_SDR, + HDMI_EOTF_TRADITIONAL_GAMMA_HDR, + HDMI_EOTF_SMPTE_ST2084, + HDMI_EOTF_BT_2100_HLG, +}; + struct hdmi_avi_infoframe { enum hdmi_infoframe_type type; unsigned char version; @@ -160,9 +188,37 @@ struct hdmi_avi_infoframe { unsigned short right_bar; }; -int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); +/* DRM Infoframe as per CTA 861.G spec */ +struct hdmi_drm_infoframe { + enum hdmi_infoframe_type type; + unsigned char version; + unsigned char length; + enum hdmi_eotf eotf; + enum hdmi_metadata_type metadata_type; + struct { + u16 x, y; + } display_primaries[3]; + struct { + u16 x, y; + } white_point; + u16 max_display_mastering_luminance; + u16 min_display_mastering_luminance; + u16 max_cll; + u16 max_fall; +}; + +void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, size_t size); +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, + void *buffer, size_t size); +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame); +int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame); +ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer, + size_t size); +ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame, + void *buffer, size_t size); +int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame); enum hdmi_spd_sdi { HDMI_SPD_SDI_UNKNOWN, @@ -194,6 +250,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, const char *vendor, const char *product); ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, size_t size); +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame, + void *buffer, size_t size); +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame); enum hdmi_audio_coding_type { HDMI_AUDIO_CODING_TYPE_STREAM, @@ -272,6 +331,9 @@ struct hdmi_audio_infoframe { int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame); ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, void *buffer, size_t size); +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame, + void *buffer, size_t size); +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame); enum hdmi_3d_structure { HDMI_3D_STRUCTURE_INVALID = -1, @@ -296,9 +358,39 @@ struct hdmi_vendor_infoframe { unsigned int s3d_ext_data; }; +/* HDR Metadata as per 861.G spec */ +struct hdr_static_metadata { + __u8 eotf; + __u8 metadata_type; + __u16 max_cll; + __u16 max_fall; + __u16 min_cll; +}; + +/** + * struct hdr_sink_metadata - HDR sink metadata + * + * Metadata Information read from Sink's EDID + */ +struct hdr_sink_metadata { + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u32 metadata_type; + /** + * @hdmi_type1: HDR Metadata Infoframe. + */ + union { + struct hdr_static_metadata hdmi_type1; + }; +}; + int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame); ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, void *buffer, size_t size); +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame, + void *buffer, size_t size); +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame); union hdmi_vendor_any_infoframe { struct { @@ -317,6 +409,7 @@ union hdmi_vendor_any_infoframe { * @spd: spd infoframe * @vendor: union of all vendor infoframes * @audio: audio infoframe + * @drm: Dynamic Range and Mastering infoframe * * This is used by the generic pack function. This works since all infoframes * have the same header which also indicates which type of infoframe should be @@ -328,12 +421,17 @@ union hdmi_infoframe { struct hdmi_spd_infoframe spd; union hdmi_vendor_any_infoframe vendor; struct hdmi_audio_infoframe audio; + struct hdmi_drm_infoframe drm; }; -ssize_t -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size); -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer); +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, + size_t size); +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, + void *buffer, size_t size); +int hdmi_infoframe_check(union hdmi_infoframe *frame); +int hdmi_infoframe_unpack(union hdmi_infoframe *frame, + const void *buffer, size_t size); void hdmi_infoframe_log(const char *level, struct device *dev, - union hdmi_infoframe *frame); + const union hdmi_infoframe *frame); #endif /* _DRM_HDMI_H */ diff --git a/sys/dev/pci/drm/include/linux/highmem.h b/sys/dev/pci/drm/include/linux/highmem.h index 39385671748..36405597f9e 100644 --- a/sys/dev/pci/drm/include/linux/highmem.h +++ b/sys/dev/pci/drm/include/linux/highmem.h @@ -1,4 +1,4 @@ -/* $OpenBSD: highmem.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: highmem.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -18,6 +18,7 @@ #ifndef _LINUX_HIGHMEM_H #define _LINUX_HIGHMEM_H +#include <sys/param.h> #include <uvm/uvm_extern.h> #include <linux/uaccess.h> diff --git a/sys/dev/pci/drm/include/linux/hmm.h b/sys/dev/pci/drm/include/linux/hmm.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/hmm.h diff --git a/sys/dev/pci/drm/include/linux/i2c.h b/sys/dev/pci/drm/include/linux/i2c.h index 3a91dc8dcd3..0d0ff3f44be 100644 --- a/sys/dev/pci/drm/include/linux/i2c.h +++ b/sys/dev/pci/drm/include/linux/i2c.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i2c.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: i2c.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -33,6 +33,8 @@ struct i2c_algorithm; #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0 #define I2C_FUNC_10BIT_ADDR 0 +struct i2c_lock_operations; + struct i2c_adapter { struct i2c_controller ic; @@ -40,10 +42,17 @@ struct i2c_adapter { const struct i2c_algorithm *algo; void *algo_data; int retries; + const struct i2c_lock_operations *lock_ops; void *data; }; +struct i2c_lock_operations { + void (*lock_bus)(struct i2c_adapter *, unsigned int); + int (*trylock_bus)(struct i2c_adapter *, unsigned int); + void (*unlock_bus)(struct i2c_adapter *, unsigned int); +}; + #define I2C_NAME_SIZE 20 struct i2c_msg { diff --git a/sys/dev/pci/drm/include/linux/idr.h b/sys/dev/pci/drm/include/linux/idr.h index 501a89577fa..b327fa9e4a4 100644 --- a/sys/dev/pci/drm/include/linux/idr.h +++ b/sys/dev/pci/drm/include/linux/idr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: idr.h,v 1.2 2019/05/13 16:23:15 jsg Exp $ */ +/* $OpenBSD: idr.h,v 1.3 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -18,8 +18,11 @@ #ifndef _LINUX_IDR_H #define _LINUX_IDR_H +#include <sys/types.h> #include <sys/tree.h> +#include <linux/radix-tree.h> + struct idr_entry { SPLAY_ENTRY(idr_entry) entry; int id; diff --git a/sys/dev/pci/drm/include/linux/init.h b/sys/dev/pci/drm/include/linux/init.h index e69de29bb2d..4f0355101f7 100644 --- a/sys/dev/pci/drm/include/linux/init.h +++ b/sys/dev/pci/drm/include/linux/init.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_INIT_H +#define _LINUX_INIT_H + +#define __initconst + +#endif diff --git a/sys/dev/pci/drm/include/linux/intel-iommu.h b/sys/dev/pci/drm/include/linux/intel-iommu.h index e69de29bb2d..9cab2c2a0e8 100644 --- a/sys/dev/pci/drm/include/linux/intel-iommu.h +++ b/sys/dev/pci/drm/include/linux/intel-iommu.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _INTEL_IOMMU_H_ +#define _INTEL_IOMMU_H_ + +#include <linux/dma-mapping.h> /* via linux/iova.h */ + +#endif diff --git a/sys/dev/pci/drm/include/linux/interrupt.h b/sys/dev/pci/drm/include/linux/interrupt.h index 8390fbdf3ca..459fe3341d4 100644 --- a/sys/dev/pci/drm/include/linux/interrupt.h +++ b/sys/dev/pci/drm/include/linux/interrupt.h @@ -10,6 +10,7 @@ #include <linux/irqflags.h> #include <linux/atomic.h> #include <linux/compiler.h> +#include <linux/irqreturn.h> #define IRQF_SHARED 0 @@ -19,6 +20,8 @@ #define request_irq(irq, hdlr, flags, name, dev) (0) #define free_irq(irq, dev) +typedef irqreturn_t (*irq_handler_t)(int, void *); + struct tasklet_struct { void (*func)(unsigned long); unsigned long data; @@ -86,4 +89,18 @@ tasklet_hi_schedule(struct tasklet_struct *ts) task_add(taskletq, &ts->task); } +static inline void +tasklet_disable_nosync(struct tasklet_struct *ts) +{ + atomic_inc(&ts->count); + smp_mb__after_atomic(); +} + +static inline void +tasklet_enable(struct tasklet_struct *ts) +{ + smp_mb__before_atomic(); + atomic_dec(&ts->count); +} + #endif diff --git a/sys/dev/pci/drm/include/linux/io-64-nonatomic-lo-hi.h b/sys/dev/pci/drm/include/linux/io-64-nonatomic-lo-hi.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/io-64-nonatomic-lo-hi.h diff --git a/sys/dev/pci/drm/include/linux/io.h b/sys/dev/pci/drm/include/linux/io.h index 2b9e956c3fc..b88352f733a 100644 --- a/sys/dev/pci/drm/include/linux/io.h +++ b/sys/dev/pci/drm/include/linux/io.h @@ -3,9 +3,13 @@ #ifndef _LINUX_IO_H #define _LINUX_IO_H +#include <sys/types.h> #include <sys/systm.h> +#include <sys/memrange.h> /* for MDF_WRITECOMBINE */ + #include <linux/types.h> #include <linux/compiler.h> +#include <linux/vmalloc.h> #define memcpy_toio(d, s, n) memcpy(d, s, n) #define memcpy_fromio(d, s, n) memcpy(d, s, n) @@ -68,4 +72,9 @@ iowrite64(u64 val, volatile void __iomem *addr) #define readq(p) ioread64(p) #define writeq(v, p) iowrite64(v, p) +int drm_mtrr_add(unsigned long, size_t, int); +int drm_mtrr_del(int, unsigned long, size_t, int); + +#define DRM_MTRR_WC MDF_WRITECOMBINE + #endif diff --git a/sys/dev/pci/drm/include/linux/ipc.h b/sys/dev/pci/drm/include/linux/ipc.h new file mode 100644 index 00000000000..e738818c92e --- /dev/null +++ b/sys/dev/pci/drm/include/linux/ipc.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_IPC_H +#define _LINUX_IPC_H + +#include <linux/workqueue.h> /* via linux/rhashtable-types.h */ + +#endif diff --git a/sys/dev/pci/drm/include/linux/kallsyms.h b/sys/dev/pci/drm/include/linux/kallsyms.h new file mode 100644 index 00000000000..4dc9fabd0d1 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/kallsyms.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_KALLSYMS_H +#define _LINUX_KALLSYMS_H + +#include <linux/module.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/kconfig.h b/sys/dev/pci/drm/include/linux/kconfig.h index 86aa9464a9c..586553e40e9 100644 --- a/sys/dev/pci/drm/include/linux/kconfig.h +++ b/sys/dev/pci/drm/include/linux/kconfig.h @@ -7,8 +7,16 @@ #include <generated/autoconf.h> -#define IS_ENABLED(x) x - 0 -#define IS_BUILTIN(x) 1 +#define __NEWARG1 __newarg, +#define __is_defined(x) __is_defined2(x) +#define __is_defined2(x) __is_defined3(__NEWARG##x) +#define __is_defined3(x) __is_defined4(x 1, 0) +#define __is_defined4(a, b, ...) b + +#define IS_ENABLED(x) __is_defined(x) +#define IS_REACHABLE(x) __is_defined(x) +#define IS_BUILTIN(x) __is_defined(x) +#define IS_MODULE(x) 0 #if BYTE_ORDER == BIG_ENDIAN #define __BIG_ENDIAN diff --git a/sys/dev/pci/drm/include/linux/kernel.h b/sys/dev/pci/drm/include/linux/kernel.h index 99fa7b4bb8b..059680589db 100644 --- a/sys/dev/pci/drm/include/linux/kernel.h +++ b/sys/dev/pci/drm/include/linux/kernel.h @@ -36,8 +36,6 @@ #define U64_C(x) UINT64_C(x) #define U64_MAX UINT64_MAX -#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0) - #define ARRAY_SIZE nitems #define lower_32_bits(n) ((u32)(n)) @@ -66,6 +64,7 @@ #define mult_frac(x, n, d) (((x) * (n)) / (d)) +#define roundup2(x, y) (((x) + ((y) - 1)) & (~((__typeof(x))(y) - 1))) #define round_up(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define round_down(x, y) (((x) / (y)) * (y)) /* y is power of two */ #define rounddown(x, y) (((x) / (y)) * (y)) /* arbitary y */ @@ -76,6 +75,9 @@ #define DIV_ROUND_CLOSEST(x, y) (((x) + ((y) / 2)) / (y)) #define DIV_ROUND_CLOSEST_ULL(x, y) DIV_ROUND_CLOSEST(x, y) +#define IS_ALIGNED(x, y) (((x) & ((y) - 1)) == 0) +#define PTR_ALIGN(x, y) ((__typeof(x))roundup2((unsigned long)(x), (y))) + static inline char * kasprintf(int flags, const char *fmt, ...) { @@ -114,6 +116,18 @@ kvasprintf(int flags, const char *fmt, va_list ap) } static inline int +vscnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int nc; + + nc = vsnprintf(buf, size, fmt, ap); + if (nc > (size - 1)) + return (size - 1); + else + return nc; +} + +static inline int _in_dbg_master(void) { #ifdef DDB @@ -129,8 +143,13 @@ _in_dbg_master(void) #define add_taint(x, y) #define TAINT_MACHINE_CHECK 0 +#define TAINT_WARN 1 #define LOCKDEP_STILL_OK 0 #define u64_to_user_ptr(x) ((void *)(uintptr_t)(x)) +#define _RET_IP_ __builtin_return_address(0) + +#define STUB() do { printf("%s: stub\n", __func__); } while(0) + #endif diff --git a/sys/dev/pci/drm/include/linux/kernfs.h b/sys/dev/pci/drm/include/linux/kernfs.h new file mode 100644 index 00000000000..3d24789dfee --- /dev/null +++ b/sys/dev/pci/drm/include/linux/kernfs.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_KERNFS_H +#define _LINUX_KERNFS_H + +#include <linux/err.h> +#include <linux/idr.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/kgdb.h b/sys/dev/pci/drm/include/linux/kgdb.h index 874a0ebe0be..86dee85a2f0 100644 --- a/sys/dev/pci/drm/include/linux/kgdb.h +++ b/sys/dev/pci/drm/include/linux/kgdb.h @@ -3,6 +3,7 @@ #ifndef _LINUX_KGDB_H #define _LINUX_KGDB_H +#include <sys/types.h> #include <sys/systm.h> static inline int diff --git a/sys/dev/pci/drm/include/linux/kmemleak.h b/sys/dev/pci/drm/include/linux/kmemleak.h new file mode 100644 index 00000000000..30857919af2 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/kmemleak.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_KMEMLEAK_H +#define _LINUX_KMEMLEAK_H + +#define kmemleak_update_trace(x) + +#endif diff --git a/sys/dev/pci/drm/include/linux/kref.h b/sys/dev/pci/drm/include/linux/kref.h index 1fbf37133cf..4d16577e749 100644 --- a/sys/dev/pci/drm/include/linux/kref.h +++ b/sys/dev/pci/drm/include/linux/kref.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kref.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: kref.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2015 Mark Kettenis * @@ -92,4 +92,21 @@ kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref), return 0; } +static inline int +kref_put_lock(struct kref *kref, void (*release)(struct kref *kref), + struct mutex *lock) +{ + if (!atomic_add_unless(&kref->refcount, -1, 1)) { + mtx_enter(lock); + if (likely(atomic_dec_and_test(&kref->refcount))) { + release(kref); + return 1; + } + mtx_leave(lock); + return 0; + } + + return 0; +} + #endif diff --git a/sys/dev/pci/drm/include/linux/ktime.h b/sys/dev/pci/drm/include/linux/ktime.h index c4e78551b10..7e5ccf322da 100644 --- a/sys/dev/pci/drm/include/linux/ktime.h +++ b/sys/dev/pci/drm/include/linux/ktime.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ktime.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: ktime.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -101,6 +101,12 @@ ktime_add(struct timeval a, struct timeval b) } static inline struct timeval +ktime_add_us(struct timeval tv, int64_t us) +{ + return ns_to_timeval(timeval_to_ns(&tv) + (us * NSEC_PER_USEC)); +} + +static inline struct timeval ktime_add_ns(struct timeval tv, int64_t ns) { return ns_to_timeval(timeval_to_ns(&tv) + ns); diff --git a/sys/dev/pci/drm/include/linux/list.h b/sys/dev/pci/drm/include/linux/list.h index cf05e6f7ad7..115580dbc0d 100644 --- a/sys/dev/pci/drm/include/linux/list.h +++ b/sys/dev/pci/drm/include/linux/list.h @@ -1,4 +1,4 @@ -/* $OpenBSD: list.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: list.h,v 1.2 2020/06/08 04:48:14 jsg Exp $ */ /* drm_linux_list.h -- linux list functions for the BSDs. * Created: Mon Apr 7 14:30:16 1999 by anholt@FreeBSD.org */ @@ -36,6 +36,7 @@ #include <sys/param.h> #include <linux/kernel.h> #include <linux/types.h> +#include <linux/poison.h> #define list_entry(ptr, type, member) container_of(ptr, type, member) @@ -61,6 +62,13 @@ list_is_singular(const struct list_head *head) { } static inline int +list_is_first(const struct list_head *list, + const struct list_head *head) +{ + return list->prev == head; +} + +static inline int list_is_last(const struct list_head *list, const struct list_head *head) { @@ -121,6 +129,18 @@ static inline void list_move_tail(struct list_head *list, } static inline void +list_bulk_move_tail(struct list_head *head, struct list_head *first, + struct list_head *last) +{ + first->prev->next = last->next; + last->next->prev = first->prev; + head->prev->next = first; + first->prev = head->prev; + last->next = head; + head->prev = last; +} + +static inline void list_del_init(struct list_head *entry) { (entry)->next->prev = (entry)->prev; (entry)->prev->next = (entry)->next; @@ -133,6 +153,9 @@ list_del_init(struct list_head *entry) { #define list_prev_entry(pos, member) \ list_entry(((pos)->member.prev), typeof(*(pos)), member) +#define list_safe_reset_next(pos, n, member) \ + n = list_next_entry(pos, member) + #define list_for_each(entry, head) \ for (entry = (head)->next; entry != head; entry = (entry)->next) diff --git a/sys/dev/pci/drm/include/linux/llist.h b/sys/dev/pci/drm/include/linux/llist.h index aea86b4faff..8c0b37da123 100644 --- a/sys/dev/pci/drm/include/linux/llist.h +++ b/sys/dev/pci/drm/include/linux/llist.h @@ -49,6 +49,19 @@ llist_add(struct llist_node *new, struct llist_head *head) return (first == NULL); } +static inline bool +llist_add_batch(struct llist_node *new_first, struct llist_node *new_last, + struct llist_head *head) +{ + struct llist_node *first; + + do { + new_last->next = first = head->first; + } while (atomic_cas_ptr(&head->first, first, new_first) != first); + + return (first == NULL); +} + static inline void init_llist_head(struct llist_head *head) { @@ -61,10 +74,21 @@ llist_empty(struct llist_head *head) return (head->first == NULL); } +#define llist_for_each_safe(pos, n, node) \ + for ((pos) = (node); \ + (pos) != NULL && \ + ((n) = (pos)->next, pos); \ + (pos) = (n)) + #define llist_for_each_entry_safe(pos, n, node, member) \ for (pos = llist_entry((node), __typeof(*pos), member); \ pos != NULL && \ (n = llist_entry(pos->member.next, __typeof(*pos), member), pos); \ pos = n) +#define llist_for_each_entry(pos, node, member) \ + for ((pos) = llist_entry((node), __typeof(*(pos)), member); \ + (pos) != NULL; \ + (pos) = llist_entry((pos)->member.next, __typeof(*(pos)), member)) + #endif diff --git a/sys/dev/pci/drm/include/linux/lockdep.h b/sys/dev/pci/drm/include/linux/lockdep.h index a6407a1d645..afdb6216b3d 100644 --- a/sys/dev/pci/drm/include/linux/lockdep.h +++ b/sys/dev/pci/drm/include/linux/lockdep.h @@ -6,11 +6,30 @@ struct lock_class_key { }; +struct pin_cookie { +}; + #define might_lock(lock) +#define might_lock_nested(lock, subc) #define lockdep_assert_held(lock) do { (void)(lock); } while(0) +#define lockdep_assert_held_once(lock) do { (void)(lock); } while(0) #define lock_acquire(lock, a, b, c, d, e, f) -#define lock_release(lock, a, b) +#define lock_release(lock, a) #define lock_acquire_shared_recursive(lock, a, b, c, d) #define lockdep_set_subclass(a, b) +#define lockdep_unpin_lock(a, b) +#define lockdep_set_class(a, b) +#define lockdep_init_map(a, b, c, d) + +#define mutex_acquire(a, b, c, d) +#define mutex_release(a, b) + +#define SINGLE_DEPTH_NESTING 0 + +#define lockdep_pin_lock(lock) \ +({ \ + struct pin_cookie pc = {}; \ + pc; \ +}) #endif diff --git a/sys/dev/pci/drm/include/linux/log2.h b/sys/dev/pci/drm/include/linux/log2.h index 8351b473b1f..5dc08372cac 100644 --- a/sys/dev/pci/drm/include/linux/log2.h +++ b/sys/dev/pci/drm/include/linux/log2.h @@ -8,6 +8,8 @@ #define ilog2(x) ((sizeof(x) <= 4) ? (fls(x) - 1) : (flsl(x) - 1)) +int drm_order(unsigned long); + #define is_power_of_2(x) (((x) != 0) && (((x) - 1) & (x)) == 0) #define order_base_2(x) drm_order(x) diff --git a/sys/dev/pci/drm/include/linux/math64.h b/sys/dev/pci/drm/include/linux/math64.h index 7ca4f3b5808..8cf96571e94 100644 --- a/sys/dev/pci/drm/include/linux/math64.h +++ b/sys/dev/pci/drm/include/linux/math64.h @@ -56,4 +56,21 @@ mul_u64_u32_div(uint64_t x, uint32_t y, uint32_t div) return (x * y) / div; } +#define DIV64_U64_ROUND_UP(x, y) \ +({ \ + uint64_t _t = (y); \ + div64_u64((x) + _t - 1, _t); \ +}) + +static inline uint64_t +mul_u64_u32_shr(uint64_t x, uint32_t y, unsigned int shift) +{ + uint32_t hi, lo; + hi = x >> 32; + lo = x & 0xffffffff; + + return (mul_u32_u32(lo, y) >> shift) + + (mul_u32_u32(hi, y) << (32 - shift)); +} + #endif diff --git a/sys/dev/pci/drm/include/linux/media-bus-format.h b/sys/dev/pci/drm/include/linux/media-bus-format.h index e69de29bb2d..7ef55e928e4 100644 --- a/sys/dev/pci/drm/include/linux/media-bus-format.h +++ b/sys/dev/pci/drm/include/linux/media-bus-format.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_MEDIA_BUS_FORMAT_H +#define _LINUX_MEDIA_BUS_FORMAT_H + +#define MEDIA_BUS_FMT_FIXED 1 + +#endif diff --git a/sys/dev/pci/drm/include/linux/mempolicy.h b/sys/dev/pci/drm/include/linux/mempolicy.h index e69de29bb2d..b987c99da44 100644 --- a/sys/dev/pci/drm/include/linux/mempolicy.h +++ b/sys/dev/pci/drm/include/linux/mempolicy.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_MEMPOLICY_H +#define _LINUX_MEMPOLICY_H + +#include <linux/pagemap.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/mm.h b/sys/dev/pci/drm/include/linux/mm.h index 59b269ae815..fbf230c309d 100644 --- a/sys/dev/pci/drm/include/linux/mm.h +++ b/sys/dev/pci/drm/include/linux/mm.h @@ -12,6 +12,7 @@ #include <uvm/uvm_extern.h> #include <linux/fs.h> #include <linux/shrinker.h> +#include <linux/overflow.h> #include <asm/pgtable.h> #define PageHighMem(x) 0 @@ -21,13 +22,14 @@ #define page_to_pfn(pp) (VM_PAGE_TO_PHYS(pp) / PAGE_SIZE) #define pfn_to_page(pfn) (PHYS_TO_VM_PAGE(ptoa(pfn))) #define nth_page(page, n) (&(page)[(n)]) -#define offset_in_page(off) ((off) & PAGE_MASK) +#define offset_in_page(off) ((vaddr_t)(off) & PAGE_MASK) #define set_page_dirty(page) atomic_clearbits_int(&page->pg_flags, PG_CLEAN) #define PAGE_ALIGN(addr) (((addr) + PAGE_MASK) & ~PAGE_MASK) #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) #define is_vmalloc_addr(ptr) true diff --git a/sys/dev/pci/drm/include/linux/mm_types.h b/sys/dev/pci/drm/include/linux/mm_types.h index e69de29bb2d..1fdd4c1b088 100644 --- a/sys/dev/pci/drm/include/linux/mm_types.h +++ b/sys/dev/pci/drm/include/linux/mm_types.h @@ -0,0 +1,11 @@ +/* Public domain. */ + +#ifndef _LINUX_MM_TYPES_H +#define _LINUX_MM_TYPES_H + +#include <linux/workqueue.h> +#include <linux/completion.h> + +#include <uvm/uvm_extern.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/mmzone.h b/sys/dev/pci/drm/include/linux/mmzone.h new file mode 100644 index 00000000000..f373e2e5896 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/mmzone.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_MMZONE_H +#define _LINUX_MMZONE_H + +#include <linux/mm_types.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/mod_devicetable.h b/sys/dev/pci/drm/include/linux/mod_devicetable.h index 173f3107763..847aaa85cf8 100644 --- a/sys/dev/pci/drm/include/linux/mod_devicetable.h +++ b/sys/dev/pci/drm/include/linux/mod_devicetable.h @@ -40,4 +40,14 @@ struct dmi_system_id { #define DMI_MATCH(a, b) {(a), (b)} #define DMI_EXACT_MATCH(a, b) {(a), (b)} +struct pci_device_id { + uint16_t vendor; + uint16_t device; + uint16_t subvendor; + uint16_t subdevice; + uint32_t class; + uint32_t class_mask; + unsigned long driver_data; +}; + #endif diff --git a/sys/dev/pci/drm/include/linux/module.h b/sys/dev/pci/drm/include/linux/module.h index 416077c072c..d976306e3de 100644 --- a/sys/dev/pci/drm/include/linux/module.h +++ b/sys/dev/pci/drm/include/linux/module.h @@ -5,6 +5,7 @@ #include <linux/export.h> #include <linux/moduleparam.h> +#include <linux/kobject.h> struct module; @@ -17,4 +18,15 @@ struct module; #define module_exit(x) #define symbol_put(x) +static inline bool +try_module_get(struct module *m) +{ + return true; +} + +static inline void +module_put(struct module *m) +{ +} + #endif diff --git a/sys/dev/pci/drm/include/linux/moduleparam.h b/sys/dev/pci/drm/include/linux/moduleparam.h index c94fe7b45ad..7785f976fce 100644 --- a/sys/dev/pci/drm/include/linux/moduleparam.h +++ b/sys/dev/pci/drm/include/linux/moduleparam.h @@ -8,5 +8,6 @@ #define module_param_named(name, value, type, perm) #define module_param_named_unsafe(name, value, type, perm) #define module_param_unsafe(name, type, perm) +#define module_param_string(name, string, len, perm) #endif diff --git a/sys/dev/pci/drm/include/linux/mutex.h b/sys/dev/pci/drm/include/linux/mutex.h index a1436f82228..5910b9743c0 100644 --- a/sys/dev/pci/drm/include/linux/mutex.h +++ b/sys/dev/pci/drm/include/linux/mutex.h @@ -11,6 +11,8 @@ #define DEFINE_MUTEX(x) struct rwlock x #define mutex_lock_interruptible(rwl) -rw_enter(rwl, RW_WRITE | RW_INTR) +#define mutex_lock_interruptible_nested(rwl, subc) \ + -rw_enter(rwl, RW_WRITE | RW_INTR) #define mutex_lock(rwl) rw_enter_write(rwl) #define mutex_lock_nest_lock(rwl, sub) rw_enter_write(rwl) #define mutex_lock_nested(rwl, sub) rw_enter_write(rwl) @@ -35,4 +37,6 @@ mutex_trylock_recursive(struct rwlock *rwl) return MUTEX_TRYLOCK_FAILED; } +int atomic_dec_and_mutex_lock(volatile int *, struct rwlock *); + #endif diff --git a/sys/dev/pci/drm/include/linux/nmi.h b/sys/dev/pci/drm/include/linux/nmi.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/nmi.h diff --git a/sys/dev/pci/drm/include/linux/of.h b/sys/dev/pci/drm/include/linux/of.h new file mode 100644 index 00000000000..cbac3f60606 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/of.h @@ -0,0 +1,15 @@ +/* Public domain. */ + +#ifndef _LINUX_OF_H +#define _LINUX_OF_H + +#ifdef __macppc__ +static inline int +of_machine_is_compatible(const char *model) +{ + extern char *hw_prod; + return (strcmp(model, hw_prod) == 0); +} +#endif + +#endif diff --git a/sys/dev/pci/drm/include/linux/overflow.h b/sys/dev/pci/drm/include/linux/overflow.h index ea8fa45e399..93615be569b 100644 --- a/sys/dev/pci/drm/include/linux/overflow.h +++ b/sys/dev/pci/drm/include/linux/overflow.h @@ -5,4 +5,7 @@ #define array_size(x, y) ((x) * (y)) +#define struct_size(p, member, n) \ + (sizeof(*(p)) + ((n) * (sizeof(*(p)->member)))) + #endif diff --git a/sys/dev/pci/drm/include/linux/pagemap.h b/sys/dev/pci/drm/include/linux/pagemap.h index e69de29bb2d..92474a244f6 100644 --- a/sys/dev/pci/drm/include/linux/pagemap.h +++ b/sys/dev/pci/drm/include/linux/pagemap.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_PAGEMAP_H +#define _LINUX_PAGEMAP_H + +#include <linux/uaccess.h> +#include <linux/highmem.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/pci.h b/sys/dev/pci/drm/include/linux/pci.h index 4ec8881f8ca..40348ececc0 100644 --- a/sys/dev/pci/drm/include/linux/pci.h +++ b/sys/dev/pci/drm/include/linux/pci.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pci.h,v 1.4 2019/08/28 10:17:59 kettenis Exp $ */ +/* $OpenBSD: pci.h,v 1.5 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2015 Mark Kettenis * @@ -19,22 +19,27 @@ #define _LINUX_PCI_H #include <sys/types.h> -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> /* sparc64 cpu.h needs time.h and siginfo.h (indirect via param.h) */ #include <sys/param.h> #include <machine/cpu.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> #include <uvm/uvm_extern.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/kobject.h> +#include <linux/dma-mapping.h> /* pci-dma-compat.h -> dma-mapping.h */ +#include <linux/mod_devicetable.h> struct pci_dev; struct pci_bus { pci_chipset_tag_t pc; unsigned char number; + int domain_nr; pcitag_t *bridgetag; struct pci_dev *self; }; @@ -66,6 +71,18 @@ struct pci_dev { }; #define PCI_ANY_ID (uint16_t) (~0U) +#ifndef PCI_MEM_START +#define PCI_MEM_START 0 +#endif + +#ifndef PCI_MEM_END +#define PCI_MEM_END 0xffffffff +#endif + +#ifndef PCI_MEM64_END +#define PCI_MEM64_END 0xffffffffffffffff +#endif + #define PCI_VENDOR_ID_APPLE PCI_VENDOR_APPLE #define PCI_VENDOR_ID_ASUSTEK PCI_VENDOR_ASUSTEK #define PCI_VENDOR_ID_ATI PCI_VENDOR_ATI @@ -95,6 +112,12 @@ struct pci_dev { #define PCI_EXP_LNKCTL 0x10 #define PCI_EXP_LNKCTL_HAWD 0x0200 #define PCI_EXP_LNKCTL2 0x30 +#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 +#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 +#define PCI_EXP_LNKCTL2_TLS PCI_PCIE_LCSR2_TLS +#define PCI_EXP_LNKCTL2_TLS_2_5GT PCI_PCIE_LCSR2_TLS_2_5 +#define PCI_EXP_LNKCTL2_TLS_5_0GT PCI_PCIE_LCSR2_TLS_5 +#define PCI_EXP_LNKCTL2_TLS_8_0GT PCI_PCIE_LCSR2_TLS_8 #define PCI_COMMAND PCI_COMMAND_STATUS_REG #define PCI_COMMAND_MEMORY PCI_COMMAND_MEM_ENABLE @@ -209,6 +232,12 @@ pci_pcie_cap(struct pci_dev *pdev) } static inline bool +pci_is_pcie(struct pci_dev *pdev) +{ + return (pci_pcie_cap(pdev) > 0); +} + +static inline bool pci_is_root_bus(struct pci_bus *pbus) { return (pbus->bridgetag == NULL); @@ -227,6 +256,51 @@ pcie_capability_read_dword(struct pci_dev *pdev, int off, u32 *val) return 0; } +static inline int +pcie_capability_read_word(struct pci_dev *pdev, int off, u16 *val) +{ + int pos; + if (!pci_get_capability(pdev->pc, pdev->tag, PCI_CAP_PCIEXPRESS, + &pos, NULL)) { + *val = 0; + return -EINVAL; + } + pci_read_config_word(pdev, pos + off, val); + return 0; +} + +static inline int +pcie_capability_write_word(struct pci_dev *pdev, int off, u16 val) +{ + int pos; + if (!pci_get_capability(pdev->pc, pdev->tag, PCI_CAP_PCIEXPRESS, + &pos, NULL)) + return -EINVAL; + pci_write_config_word(pdev, pos + off, val); + return 0; +} + +static inline int +pcie_get_readrq(struct pci_dev *pdev) +{ + uint16_t val; + + pcie_capability_read_word(pdev, PCI_PCIE_DCSR, &val); + + return 128 << ((val & PCI_PCIE_DCSR_MPS) >> 12); +} + +static inline int +pcie_set_readrq(struct pci_dev *pdev, int rrq) +{ + uint16_t val; + + pcie_capability_read_word(pdev, PCI_PCIE_DCSR, &val); + val &= ~PCI_PCIE_DCSR_MPS; + val |= (ffs(rrq) - 8) << 12; + return pcie_capability_write_word(pdev, PCI_PCIE_DCSR, val); +} + #define pci_set_master(x) #define pci_clear_master(x) @@ -267,6 +341,20 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *); enum pcie_link_width pcie_get_width_cap(struct pci_dev *); int pci_resize_resource(struct pci_dev *, int, int); +static inline void +pcie_bandwidth_available(struct pci_dev *pdev, struct pci_dev **ldev, + enum pci_bus_speed *speed, enum pcie_link_width *width) +{ + struct pci_dev *bdev = pdev->bus->self; + if (bdev == NULL) + return; + + if (speed) + *speed = pcie_get_speed_cap(bdev); + if (width) + *width = pcie_get_width_cap(bdev); +} + #define pci_save_state(x) #define pci_enable_device(x) 0 #define pci_disable_device(x) @@ -274,6 +362,23 @@ int pci_resize_resource(struct pci_dev *, int, int); #define pci_set_drvdata(x, y) static inline int +pci_domain_nr(struct pci_bus *pbus) +{ + return pbus->domain_nr; +} + +static inline int +pci_irq_vector(struct pci_dev *pdev, unsigned int num) +{ + return pdev->irq; +} + +static inline void +pci_free_irq_vectors(struct pci_dev *pdev) +{ +} + +static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; diff --git a/sys/dev/pci/drm/include/linux/perf_event.h b/sys/dev/pci/drm/include/linux/perf_event.h index 935fd59b5fb..0f2e67e6542 100644 --- a/sys/dev/pci/drm/include/linux/perf_event.h +++ b/sys/dev/pci/drm/include/linux/perf_event.h @@ -3,6 +3,8 @@ #ifndef _LINUX_PERF_EVENT_H #define _LINUX_PERF_EVENT_H +#include <linux/ftrace.h> + struct pmu { }; diff --git a/sys/dev/pci/drm/include/linux/pfn.h b/sys/dev/pci/drm/include/linux/pfn.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/pfn.h diff --git a/sys/dev/pci/drm/include/linux/pid.h b/sys/dev/pci/drm/include/linux/pid.h index 5aa09ef5322..8534accfad3 100644 --- a/sys/dev/pci/drm/include/linux/pid.h +++ b/sys/dev/pci/drm/include/linux/pid.h @@ -3,6 +3,8 @@ #ifndef _LINUX_PID_H #define _LINUX_PID_H +#include <linux/rculist.h> + #define put_pid(x) #endif diff --git a/sys/dev/pci/drm/include/linux/pm.h b/sys/dev/pci/drm/include/linux/pm.h index 35c166bf79f..ac202674c7b 100644 --- a/sys/dev/pci/drm/include/linux/pm.h +++ b/sys/dev/pci/drm/include/linux/pm.h @@ -8,4 +8,7 @@ struct dev_pm_domain { }; +typedef struct { +} pm_message_t; + #endif diff --git a/sys/dev/pci/drm/include/linux/pm_qos.h b/sys/dev/pci/drm/include/linux/pm_qos.h index 2a4e938b757..e4bc138a903 100644 --- a/sys/dev/pci/drm/include/linux/pm_qos.h +++ b/sys/dev/pci/drm/include/linux/pm_qos.h @@ -14,4 +14,8 @@ struct pm_qos_request { #define pm_qos_add_request(a, b, c) #define pm_qos_remove_request(a) +#define cpu_latency_qos_update_request(a, b) +#define cpu_latency_qos_add_request(a, b) +#define cpu_latency_qos_remove_request(a) + #endif diff --git a/sys/dev/pci/drm/include/linux/pm_runtime.h b/sys/dev/pci/drm/include/linux/pm_runtime.h index efbcfaa86bb..c692fcec1b3 100644 --- a/sys/dev/pci/drm/include/linux/pm_runtime.h +++ b/sys/dev/pci/drm/include/linux/pm_runtime.h @@ -9,6 +9,7 @@ #define pm_runtime_mark_last_busy(x) #define pm_runtime_use_autosuspend(x) +#define pm_runtime_dont_use_autosuspend(x) #define pm_runtime_put_autosuspend(x) #define pm_runtime_set_autosuspend_delay(x, y) #define pm_runtime_set_active(x) @@ -16,6 +17,7 @@ #define pm_runtime_put_noidle(x) #define pm_runtime_forbid(x) #define pm_runtime_get_noresume(x) +#define pm_runtime_put(x) static inline int pm_runtime_get_sync(struct device *dev) @@ -23,4 +25,10 @@ pm_runtime_get_sync(struct device *dev) return 0; } +static inline int +pm_runtime_get_if_in_use(struct device *dev) +{ + return -EINVAL; +} + #endif diff --git a/sys/dev/pci/drm/include/linux/poison.h b/sys/dev/pci/drm/include/linux/poison.h new file mode 100644 index 00000000000..35ccb5b5499 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/poison.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_POISON_H +#define _LINUX_POISON_H + +#define POISON_INUSE 0xdb +#define POISON_FREE 0xdf + +#endif diff --git a/sys/dev/pci/drm/include/linux/poll.h b/sys/dev/pci/drm/include/linux/poll.h index 1ba9509bba9..4998990d29c 100644 --- a/sys/dev/pci/drm/include/linux/poll.h +++ b/sys/dev/pci/drm/include/linux/poll.h @@ -4,5 +4,6 @@ #define _LINUX_POLL_H #include <linux/ktime.h> +#include <linux/uaccess.h> #endif diff --git a/sys/dev/pci/drm/include/linux/preempt.h b/sys/dev/pci/drm/include/linux/preempt.h index c0d8bf6b95d..fdcaf207999 100644 --- a/sys/dev/pci/drm/include/linux/preempt.h +++ b/sys/dev/pci/drm/include/linux/preempt.h @@ -3,6 +3,8 @@ #ifndef _LINUX_PREEMPT_H #define _LINUX_PREEMPT_H +#include <asm/preempt.h> + #define preempt_enable() #define preempt_disable() @@ -19,5 +21,6 @@ in_irq(void) #define in_interrupt() in_irq() #define in_task() (!in_irq()) +#define in_atomic() 0 #endif diff --git a/sys/dev/pci/drm/include/linux/prime_numbers.h b/sys/dev/pci/drm/include/linux/prime_numbers.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/prime_numbers.h diff --git a/sys/dev/pci/drm/include/linux/printk.h b/sys/dev/pci/drm/include/linux/printk.h index 854cdfb6598..e7fc370f11e 100644 --- a/sys/dev/pci/drm/include/linux/printk.h +++ b/sys/dev/pci/drm/include/linux/printk.h @@ -7,12 +7,16 @@ #include <sys/systm.h> #include <sys/stdarg.h> -#define KERN_INFO "" -#define KERN_WARNING "" -#define KERN_NOTICE "" -#define KERN_DEBUG "" -#define KERN_CRIT "" -#define KERN_ERR "" +#include <linux/init.h> + +#define KERN_CRIT "\0012" +#define KERN_ERR "\0013" +#define KERN_WARNING "\0014" +#define KERN_NOTICE "\0015" +#define KERN_INFO "\0016" +#define KERN_DEBUG "\0017" + +#define KERN_CONT "\001c" #ifndef pr_fmt #define pr_fmt(fmt) fmt @@ -21,25 +25,32 @@ #define printk_once(fmt, arg...) ({ \ static int __warned; \ if (!__warned) { \ - printf(fmt, ## arg); \ + printk(fmt, ## arg); \ __warned = 1; \ } \ }) -#define printk(fmt, arg...) printf(fmt, ## arg) -#define pr_warn(fmt, arg...) printf(pr_fmt(fmt), ## arg) -#define pr_warn_once(fmt, arg...) printk_once(pr_fmt(fmt), ## arg) -#define pr_notice(fmt, arg...) printf(pr_fmt(fmt), ## arg) -#define pr_crit(fmt, arg...) printf(pr_fmt(fmt), ## arg) -#define pr_err(fmt, arg...) printf(pr_fmt(fmt), ## arg) -#define pr_cont(fmt, arg...) printf(pr_fmt(fmt), ## arg) +#define printk_ratelimit() 1 + +int printk(const char *fmt, ...); + +#define pr_warn(fmt, arg...) printk(KERN_WARNING pr_fmt(fmt), ## arg) +#define pr_warn_ratelimited(fmt, arg...) printk(KERN_WARNING pr_fmt(fmt), ## arg) +#define pr_warn_once(fmt, arg...) printk_once(KERN_WARNING pr_fmt(fmt), ## arg) +#define pr_notice(fmt, arg...) printk(KERN_NOTICE pr_fmt(fmt), ## arg) +#define pr_crit(fmt, arg...) printk(KERN_CRIT pr_fmt(fmt), ## arg) +#define pr_err(fmt, arg...) printk(KERN_ERR pr_fmt(fmt), ## arg) +#define pr_err_once(fmt, arg...) printk_once(KERN_ERR pr_fmt(fmt), ## arg) +#define pr_cont(fmt, arg...) printk(KERN_CONT pr_fmt(fmt), ## arg) #ifdef DRMDEBUG -#define pr_info(fmt, arg...) printf(pr_fmt(fmt), ## arg) -#define pr_info_once(fmt, arg...) printk_once(pr_fmt(fmt), ## arg) -#define pr_debug(fmt, arg...) printf(pr_fmt(fmt), ## arg) +#define pr_info(fmt, arg...) printk(KERN_INFO pr_fmt(fmt), ## arg) +#define pr_info_ratelimited(fmt, arg...) printk(KERN_INFO pr_fmt(fmt), ## arg) +#define pr_info_once(fmt, arg...) printk_once(KERN_INFO pr_fmt(fmt), ## arg) +#define pr_debug(fmt, arg...) printk(KERN_DEBUG pr_fmt(fmt), ## arg) #else #define pr_info(fmt, arg...) do { } while(0) +#define pr_info_ratelimited(fmt, arg...) do { } while(0) #define pr_info_once(fmt, arg...) do { } while(0) #define pr_debug(fmt, arg...) do { } while(0) #endif diff --git a/sys/dev/pci/drm/include/linux/pseudo_fs.h b/sys/dev/pci/drm/include/linux/pseudo_fs.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/pseudo_fs.h diff --git a/sys/dev/pci/drm/include/linux/radix-tree.h b/sys/dev/pci/drm/include/linux/radix-tree.h index 104ebafbe9f..e656a7711c9 100644 --- a/sys/dev/pci/drm/include/linux/radix-tree.h +++ b/sys/dev/pci/drm/include/linux/radix-tree.h @@ -32,6 +32,7 @@ #define _LINUX_RADIX_TREE_H_ #include <linux/types.h> +#include <linux/xarray.h> #define RADIX_TREE_MAP_SHIFT 6 #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) diff --git a/sys/dev/pci/drm/include/linux/random.h b/sys/dev/pci/drm/include/linux/random.h index 17d3611c862..23286b18fdb 100644 --- a/sys/dev/pci/drm/include/linux/random.h +++ b/sys/dev/pci/drm/include/linux/random.h @@ -27,4 +27,10 @@ get_random_long(void) #endif } +static inline uint32_t +prandom_u32_max(uint32_t x) +{ + return arc4random_uniform(x + 1); +} + #endif diff --git a/sys/dev/pci/drm/include/linux/rbtree.h b/sys/dev/pci/drm/include/linux/rbtree.h index b221ac7a56d..fe45a4eeeb1 100644 --- a/sys/dev/pci/drm/include/linux/rbtree.h +++ b/sys/dev/pci/drm/include/linux/rbtree.h @@ -50,7 +50,7 @@ struct rb_root { }; struct rb_root_cached { - struct rb_node *rb_node; + struct rb_root rb_root; }; /* @@ -77,18 +77,19 @@ RB_PROTOTYPE(linux_root, rb_node, __entry, panic_cmp); #define rb_insert_color(node, root) \ linux_root_RB_INSERT_COLOR((struct linux_root *)(root), (node)) -#define rb_insert_color_cached(node, root, leftmost) \ - linux_root_RB_INSERT_COLOR((struct linux_root *)(root), (node)) #define rb_erase(node, root) \ linux_root_RB_REMOVE((struct linux_root *)(root), (node)) -#define rb_erase_cached(node, root) \ - linux_root_RB_REMOVE((struct linux_root *)(root), (node)) #define rb_next(node) RB_NEXT(linux_root, NULL, (node)) #define rb_prev(node) RB_PREV(linux_root, NULL, (node)) #define rb_first(root) RB_MIN(linux_root, (struct linux_root *)(root)) -#define rb_first_cached(root) RB_MIN(linux_root, (struct linux_root *)(root)) #define rb_last(root) RB_MAX(linux_root, (struct linux_root *)(root)) +#define rb_insert_color_cached(node, root, leftmost) \ + linux_root_RB_INSERT_COLOR((struct linux_root *)(&(root)->rb_root), (node)) +#define rb_erase_cached(node, root) \ + linux_root_RB_REMOVE((struct linux_root *)(&(root)->rb_root), (node)) +#define rb_first_cached(root) RB_MIN(linux_root, (struct linux_root *)(&(root)->rb_root)) + static inline struct rb_node * __rb_deepest_left(struct rb_node *node) { @@ -156,7 +157,11 @@ rb_replace_node(struct rb_node *victim, struct rb_node *new, #undef RB_ROOT #define RB_ROOT (struct rb_root) { NULL } +#ifdef __clang__ #define RB_ROOT_CACHED (struct rb_root_cached) { NULL } +#else +#define RB_ROOT_CACHED (struct rb_root_cached) { { NULL } } +#endif struct interval_tree_node { struct rb_node rb; @@ -165,7 +170,7 @@ struct interval_tree_node { }; static inline struct interval_tree_node * -interval_tree_iter_first(struct rb_root *root, +interval_tree_iter_first(struct rb_root_cached *root, unsigned long start, unsigned long last) { #ifdef DRMDEBUG @@ -175,7 +180,7 @@ interval_tree_iter_first(struct rb_root *root, } static inline void -interval_tree_insert(struct interval_tree_node *node, struct rb_root *root) +interval_tree_insert(struct interval_tree_node *node, struct rb_root_cached *root) { #ifdef DRMDEBUG printf("%s: stub start: 0x%lx last: 0x%lx\n", __func__, node->start, node->last); @@ -183,7 +188,7 @@ interval_tree_insert(struct interval_tree_node *node, struct rb_root *root) } static inline void -interval_tree_remove(struct interval_tree_node *node, struct rb_root *root) +interval_tree_remove(struct interval_tree_node *node, struct rb_root_cached *root) { #ifdef DRMDEBUG printf("%s: stub start: 0x%lx last: 0x%lx\n", __func__, node->start, node->last); diff --git a/sys/dev/pci/drm/include/linux/rculist.h b/sys/dev/pci/drm/include/linux/rculist.h new file mode 100644 index 00000000000..537d6dbf9f9 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/rculist.h @@ -0,0 +1,15 @@ +/* Public domain. */ + +#ifndef _LINUX_RCULIST_H +#define _LINUX_RCULIST_H + +#include <linux/list.h> +#include <linux/rcupdate.h> + +#define list_add_rcu(a, b) list_add(a, b) +#define list_add_tail_rcu(a, b) list_add_tail(a, b) +#define list_del_rcu(a) list_del(a) +#define list_for_each_entry_rcu list_for_each_entry +#define list_for_each_entry_lockless(a, b, c) list_for_each_entry(a, b, c) + +#endif diff --git a/sys/dev/pci/drm/include/linux/rcupdate.h b/sys/dev/pci/drm/include/linux/rcupdate.h index 3bb821befcf..346c87e862a 100644 --- a/sys/dev/pci/drm/include/linux/rcupdate.h +++ b/sys/dev/pci/drm/include/linux/rcupdate.h @@ -18,6 +18,15 @@ struct rcu_head { #define rcu_read_lock() #define rcu_read_unlock() #define rcu_pointer_handoff(p) (p) +#define init_rcu_head(h) +#define destroy_rcu_head(h) + +#define rcu_replace_pointer(rp, p, c) \ +({ \ + __typeof(rp) __r = rp; \ + rp = p; \ + __r; \ +}) #define kfree_rcu(objp, name) do { free((void *)objp, M_DRM, 0); } while(0) @@ -32,5 +41,8 @@ call_rcu(struct rcu_head *head, void (*fn)(struct rcu_head *)) } #define synchronize_rcu() +#define synchronize_rcu_expedited() +#define cond_synchronize_rcu(x) +#define get_state_synchronize_rcu() 0 #endif diff --git a/sys/dev/pci/drm/include/linux/refcount.h b/sys/dev/pci/drm/include/linux/refcount.h index 402a985406e..fea109c5f06 100644 --- a/sys/dev/pci/drm/include/linux/refcount.h +++ b/sys/dev/pci/drm/include/linux/refcount.h @@ -6,10 +6,38 @@ #include <sys/types.h> #include <linux/atomic.h> +typedef atomic_t refcount_t; + static inline bool refcount_dec_and_test(uint32_t *p) { return atomic_dec_and_test(p); } +static inline bool +refcount_inc_not_zero(uint32_t *p) +{ + return atomic_inc_not_zero(p); +} + +static inline void +refcount_set(uint32_t *p, int v) +{ + atomic_set(p, v); +} + +static inline bool +refcount_dec_and_lock_irqsave(volatile int *v, struct mutex *lock, + unsigned long *flags) +{ + if (atomic_add_unless(v, -1, 1)) + return false; + + mtx_enter(lock); + if (atomic_dec_return(v) == 0) + return true; + mtx_leave(lock); + return false; +} + #endif diff --git a/sys/dev/pci/drm/include/linux/rwsem.h b/sys/dev/pci/drm/include/linux/rwsem.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/rwsem.h diff --git a/sys/dev/pci/drm/include/linux/scatterlist.h b/sys/dev/pci/drm/include/linux/scatterlist.h index 4ec58c80de0..effe1ce499b 100644 --- a/sys/dev/pci/drm/include/linux/scatterlist.h +++ b/sys/dev/pci/drm/include/linux/scatterlist.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scatterlist.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: scatterlist.h,v 1.2 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -22,7 +22,10 @@ #include <sys/param.h> #include <uvm/uvm_extern.h> +#include <linux/mm.h> + struct scatterlist { + struct vm_page *__page; dma_addr_t dma_address; unsigned int offset; unsigned int length; @@ -98,13 +101,20 @@ sg_page_iter_page(struct sg_page_iter *iter) static inline struct vm_page * sg_page(struct scatterlist *sgl) { - return PHYS_TO_VM_PAGE(sgl->dma_address); + return sgl->__page; +} + +static inline void +sg_assign_page(struct scatterlist *sgl, struct vm_page *page) +{ + sgl->__page = page; } static inline void sg_set_page(struct scatterlist *sgl, struct vm_page *page, unsigned int length, unsigned int offset) { + sgl->__page = page; sgl->dma_address = VM_PAGE_TO_PHYS(page); sgl->offset = offset; sgl->length = length; diff --git a/sys/dev/pci/drm/include/linux/sched.h b/sys/dev/pci/drm/include/linux/sched.h index 9def4c4be27..95f074795b1 100644 --- a/sys/dev/pci/drm/include/linux/sched.h +++ b/sys/dev/pci/drm/include/linux/sched.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sched.h,v 1.2 2020/02/18 12:13:40 mpi Exp $ */ +/* $OpenBSD: sched.h,v 1.3 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -25,6 +25,7 @@ #include <sys/mutex.h> #include <linux/wait.h> #include <linux/hrtimer.h> +#include <linux/sem.h> #define TASK_NORMAL 1 #define TASK_UNINTERRUPTIBLE 0 @@ -43,6 +44,7 @@ void set_current_state(int); void __set_current_state(int); void schedule(void); long schedule_timeout(long); +long schedule_timeout_uninterruptible(long); #define io_schedule_timeout(x) schedule_timeout(x) diff --git a/sys/dev/pci/drm/include/linux/sched/clock.h b/sys/dev/pci/drm/include/linux/sched/clock.h index 3604ee1ac17..efb3fc2bd00 100644 --- a/sys/dev/pci/drm/include/linux/sched/clock.h +++ b/sys/dev/pci/drm/include/linux/sched/clock.h @@ -4,8 +4,8 @@ #define _LINUX_SCHED_CLOCK_H #include <sys/types.h> -#include <sys/time.h> +#include <linux/time.h> #include <linux/smp.h> static inline uint64_t diff --git a/sys/dev/pci/drm/include/linux/sched/signal.h b/sys/dev/pci/drm/include/linux/sched/signal.h index c201146f159..a405933671d 100644 --- a/sys/dev/pci/drm/include/linux/sched/signal.h +++ b/sys/dev/pci/drm/include/linux/sched/signal.h @@ -3,6 +3,7 @@ #ifndef _LINUX_SCHED_SIGNAL_H #define _LINUX_SCHED_SIGNAL_H +#include <sys/param.h> #include <sys/systm.h> #include <sys/signalvar.h> diff --git a/sys/dev/pci/drm/include/linux/sched/task.h b/sys/dev/pci/drm/include/linux/sched/task.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/sched/task.h diff --git a/sys/dev/pci/drm/include/linux/sem.h b/sys/dev/pci/drm/include/linux/sem.h new file mode 100644 index 00000000000..6cca4ccef8d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/sem.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_SEM_H +#define _LINUX_SEM_H + +#include <linux/ipc.h> /* via uapi/linux/sem.h */ + +#endif diff --git a/sys/dev/pci/drm/include/linux/semaphore.h b/sys/dev/pci/drm/include/linux/semaphore.h new file mode 100644 index 00000000000..f89bbb34443 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/semaphore.h @@ -0,0 +1,9 @@ +/* Public domain. */ + +#ifndef _LINUX_SEMAPHORE_H +#define _LINUX_SEMAPHORE_H + +struct semaphore { +}; + +#endif diff --git a/sys/dev/pci/drm/include/linux/shmem_fs.h b/sys/dev/pci/drm/include/linux/shmem_fs.h index e69de29bb2d..c728c6d8489 100644 --- a/sys/dev/pci/drm/include/linux/shmem_fs.h +++ b/sys/dev/pci/drm/include/linux/shmem_fs.h @@ -0,0 +1,10 @@ +/* Public domain. */ + +#ifndef _LINUX_SHMEM_FS_H +#define _LINUX_SHMEM_FS_H + +#include <linux/mempolicy.h> +#include <linux/swap.h> +#include <linux/file.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/sizes.h b/sys/dev/pci/drm/include/linux/sizes.h index 01a1dc4a269..4d43eec763b 100644 --- a/sys/dev/pci/drm/include/linux/sizes.h +++ b/sys/dev/pci/drm/include/linux/sizes.h @@ -3,11 +3,17 @@ #ifndef _LINUX_SIZES_H #define _LINUX_SIZES_H +#define SZ_1K (1024 * 1) #define SZ_4K (1024 * 4) #define SZ_8K (1024 * 8) +#define SZ_16K (1024 * 16) #define SZ_32K (1024 * 32) +#define SZ_64K (1024 * 64) #define SZ_128K (1024 * 128) -#define SZ_1M (1024 * 1024) -#define SZ_16M (16 * 1024 * 1024) +#define SZ_256K (1024 * 256) +#define SZ_1M (1024 * 1024 * 1) +#define SZ_2M (1024 * 1024 * 2) +#define SZ_8M (1024 * 1024 * 8) +#define SZ_16M (1024 * 1024 * 16) #endif diff --git a/sys/dev/pci/drm/include/linux/smp.h b/sys/dev/pci/drm/include/linux/smp.h index 354bf92be3c..4db0fee69be 100644 --- a/sys/dev/pci/drm/include/linux/smp.h +++ b/sys/dev/pci/drm/include/linux/smp.h @@ -9,4 +9,7 @@ #define smp_processor_id() (curcpu()->ci_cpuid) +#define get_cpu() cpu_number() +#define put_cpu() + #endif diff --git a/sys/dev/pci/drm/include/linux/spinlock.h b/sys/dev/pci/drm/include/linux/spinlock.h index e40d2872d00..8b1a437e9ae 100644 --- a/sys/dev/pci/drm/include/linux/spinlock.h +++ b/sys/dev/pci/drm/include/linux/spinlock.h @@ -7,6 +7,7 @@ #include <linux/spinlock_types.h> #include <linux/preempt.h> #include <linux/bottom_half.h> +#include <linux/atomic.h> #define spin_lock_irqsave(_mtxp, _flags) do { \ _flags = 0; \ @@ -24,6 +25,28 @@ mtx_leave(_mtxp); \ } while (0) +#define spin_trylock_irqsave(_mtxp, _flags) \ +({ \ + (void)(_flags); \ + mtx_enter_try(_mtxp) ? 1 : 0; \ +}) + +static inline int +atomic_dec_and_lock(volatile int *v, struct mutex *mtxp) +{ + if (*v != 1) { + atomic_dec(v); + return 0; + } + + mtx_enter(mtxp); + atomic_dec(v); + return 1; +} + +#define atomic_dec_and_lock_irqsave(_a, _mtxp, _flags) \ + atomic_dec_and_lock(_a, _mtxp) + #define spin_lock(mtxp) mtx_enter(mtxp) #define spin_lock_nested(mtxp, l) mtx_enter(mtxp) #define spin_unlock(mtxp) mtx_leave(mtxp) diff --git a/sys/dev/pci/drm/include/linux/srcu.h b/sys/dev/pci/drm/include/linux/srcu.h new file mode 100644 index 00000000000..dbabe2f8d6d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/srcu.h @@ -0,0 +1,14 @@ +/* Public domain. */ + +#ifndef _LINUX_SRCU_H +#define _LINUX_SRCU_H + +#define init_srcu_struct(x) +#define cleanup_srcu_struct(x) + +#define srcu_read_lock(x) 0 +#define srcu_read_unlock(x, y) + +#define synchronize_srcu_expedited(x) + +#endif diff --git a/sys/dev/pci/drm/include/linux/stackdepot.h b/sys/dev/pci/drm/include/linux/stackdepot.h new file mode 100644 index 00000000000..2ae1c9b8d31 --- /dev/null +++ b/sys/dev/pci/drm/include/linux/stackdepot.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_STACKDEPOT_H +#define _LINUX_STACKDEPOT_H + +typedef uint32_t depot_stack_handle_t; + +#endif diff --git a/sys/dev/pci/drm/include/linux/stacktrace.h b/sys/dev/pci/drm/include/linux/stacktrace.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/stacktrace.h diff --git a/sys/dev/pci/drm/include/linux/stat.h b/sys/dev/pci/drm/include/linux/stat.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/stat.h diff --git a/sys/dev/pci/drm/include/linux/string.h b/sys/dev/pci/drm/include/linux/string.h index b77067b1bcc..dc45a038546 100644 --- a/sys/dev/pci/drm/include/linux/string.h +++ b/sys/dev/pci/drm/include/linux/string.h @@ -54,6 +54,9 @@ kstrdup(const char *str, int flags) size_t len; char *p; + if (str == NULL) + return NULL; + len = strlen(str) + 1; p = malloc(len, M_DRM, flags); if (p) diff --git a/sys/dev/pci/drm/include/linux/suspend.h b/sys/dev/pci/drm/include/linux/suspend.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/suspend.h diff --git a/sys/dev/pci/drm/include/linux/swap.h b/sys/dev/pci/drm/include/linux/swap.h index ce2f8ad9378..d6c8202a5a5 100644 --- a/sys/dev/pci/drm/include/linux/swap.h +++ b/sys/dev/pci/drm/include/linux/swap.h @@ -3,6 +3,18 @@ #ifndef _LINUX_SWAP_H #define _LINUX_SWAP_H +/* + * normally clock.h would be indirectly included via + * + * linux/swap.h + * linux/memcontrol.h + * linux/writeback.h + * linux/blk-cgroup.h + * linux/blkdev.h + * linux/sched/clock.h + */ +#include <linux/sched/clock.h> + #include <uvm/uvm_extern.h> static inline long diff --git a/sys/dev/pci/drm/include/linux/syscalls.h b/sys/dev/pci/drm/include/linux/syscalls.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/syscalls.h diff --git a/sys/dev/pci/drm/include/linux/sysfs.h b/sys/dev/pci/drm/include/linux/sysfs.h index c9be9a48fba..409373609b0 100644 --- a/sys/dev/pci/drm/include/linux/sysfs.h +++ b/sys/dev/pci/drm/include/linux/sysfs.h @@ -3,9 +3,27 @@ #ifndef _LINUX_SYSFS_H #define _LINUX_SYSFS_H +#include <linux/kernfs.h> + +struct attribute { + const char *name; + int mode; +}; + +struct bin_attribute { +}; + +struct attribute_group { + const char *name; + struct attribute **attrs; + struct bin_attribute **bin_attrs; +}; + #define sysfs_create_link(x, y, z) 0 #define sysfs_remove_link(x, y) #define sysfs_create_group(x, y) 0 #define sysfs_remove_group(x, y) +#define sysfs_remove_file(x, y) +#define sysfs_remove_file_from_group(x, y, z) #endif diff --git a/sys/dev/pci/drm/include/linux/sysrq.h b/sys/dev/pci/drm/include/linux/sysrq.h index 1805e30387a..7cc51b6db6c 100644 --- a/sys/dev/pci/drm/include/linux/sysrq.h +++ b/sys/dev/pci/drm/include/linux/sysrq.h @@ -3,6 +3,19 @@ #ifndef _LINUX_SYSRQ_H #define _LINUX_SYSRQ_H -#define register_sysrq_key(x, y) +struct sysrq_key_op { +}; + +static inline int +register_sysrq_key(int k, struct sysrq_key_op *op) +{ + return 0; +} + +static inline int +unregister_sysrq_key(int k, struct sysrq_key_op *op) +{ + return 0; +} #endif diff --git a/sys/dev/pci/drm/include/linux/thread_info.h b/sys/dev/pci/drm/include/linux/thread_info.h new file mode 100644 index 00000000000..c64eb4ea1bd --- /dev/null +++ b/sys/dev/pci/drm/include/linux/thread_info.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef _LINUX_THREAD_INFO_H +#define _LINUX_THREAD_INFO_H + +#include <asm/thread_info.h> + +#endif diff --git a/sys/dev/pci/drm/include/linux/time.h b/sys/dev/pci/drm/include/linux/time.h index c8a97b94b1a..0719b8fce65 100644 --- a/sys/dev/pci/drm/include/linux/time.h +++ b/sys/dev/pci/drm/include/linux/time.h @@ -1,4 +1,4 @@ -/* $OpenBSD: time.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: time.h,v 1.2 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -20,11 +20,15 @@ #include <sys/time.h> #include <linux/math64.h> +#include <linux/seqlock.h> #define NSEC_PER_USEC 1000L #define NSEC_PER_MSEC 1000000L #define NSEC_PER_SEC 1000000000L +#define USEC_PER_MSEC 1000L +#define USEC_PER_SEC 1000000L + extern struct timespec ns_to_timespec(const int64_t); extern int64_t timeval_to_ms(const struct timeval *); extern int64_t timeval_to_ns(const struct timeval *); diff --git a/sys/dev/pci/drm/include/linux/timekeeping.h b/sys/dev/pci/drm/include/linux/timekeeping.h index fc27e921cd5..c6aa77583c7 100644 --- a/sys/dev/pci/drm/include/linux/timekeeping.h +++ b/sys/dev/pci/drm/include/linux/timekeeping.h @@ -18,4 +18,11 @@ ktime_get_real_seconds(void) return ktime_get().tv_sec; } +static inline uint64_t +ktime_get_ns(void) +{ + struct timeval tv = ktime_get(); + return timeval_to_ns(&tv); +} + #endif diff --git a/sys/dev/pci/drm/include/linux/timer.h b/sys/dev/pci/drm/include/linux/timer.h index b1f11a2c916..a475ee10adb 100644 --- a/sys/dev/pci/drm/include/linux/timer.h +++ b/sys/dev/pci/drm/include/linux/timer.h @@ -1,4 +1,4 @@ -/* $OpenBSD: timer.h,v 1.1 2019/04/14 10:14:53 jsg Exp $ */ +/* $OpenBSD: timer.h,v 1.2 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * @@ -28,6 +28,7 @@ #define mod_timer(x, y) timeout_add((x), (y - jiffies)) #define mod_timer_pinned(x, y) timeout_add((x), (y - jiffies)) #define del_timer_sync(x) timeout_del((x)) +#define del_timer(x) timeout_del((x)) #define timer_pending(x) timeout_pending((x)) static inline unsigned long diff --git a/sys/dev/pci/drm/include/linux/tracepoint.h b/sys/dev/pci/drm/include/linux/tracepoint.h index a28216f65ac..750a63afc6b 100644 --- a/sys/dev/pci/drm/include/linux/tracepoint.h +++ b/sys/dev/pci/drm/include/linux/tracepoint.h @@ -3,6 +3,8 @@ #ifndef _LINUX_TRACEPOINT_H #define _LINUX_TRACEPOINT_H +#include <linux/types.h> + #define TP_PROTO(x...) x #define DEFINE_EVENT(template, name, proto, args) \ diff --git a/sys/dev/pci/drm/include/linux/types.h b/sys/dev/pci/drm/include/linux/types.h index 5ec2b85b594..bc9222ca2ee 100644 --- a/sys/dev/pci/drm/include/linux/types.h +++ b/sys/dev/pci/drm/include/linux/types.h @@ -34,6 +34,8 @@ typedef uint16_t __le16; typedef uint16_t __be16; typedef uint32_t __le32; typedef uint32_t __be32; +typedef uint64_t __le64; +typedef uint64_t __be64; typedef bus_addr_t dma_addr_t; typedef bus_addr_t phys_addr_t; diff --git a/sys/dev/pci/drm/include/linux/uaccess.h b/sys/dev/pci/drm/include/linux/uaccess.h index 1a0325f7f78..459eadf0b21 100644 --- a/sys/dev/pci/drm/include/linux/uaccess.h +++ b/sys/dev/pci/drm/include/linux/uaccess.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uaccess.h,v 1.2 2019/12/18 08:56:19 kettenis Exp $ */ +/* $OpenBSD: uaccess.h,v 1.3 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2015 Mark Kettenis * @@ -22,9 +22,6 @@ #include <sys/systm.h> #include <linux/sched.h> -#define user_access_begin() -#define user_access_end() - static inline unsigned long __copy_to_user(void *to, const void *from, unsigned len) { @@ -70,11 +67,14 @@ copy_from_user(void *to, const void *from, unsigned len) #define VERIFY_READ 0x1 #define VERIFY_WRITE 0x2 static inline int -access_ok(int type, const void *addr, unsigned long size) +access_ok(const void *addr, unsigned long size) { - return true; + return 1; } +#define user_access_begin(addr, size) access_ok(addr, size) +#define user_access_end() + #if defined(__i386__) || defined(__amd64__) static inline void diff --git a/sys/dev/pci/drm/include/linux/uio.h b/sys/dev/pci/drm/include/linux/uio.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/uio.h diff --git a/sys/dev/pci/drm/include/linux/utsname.h b/sys/dev/pci/drm/include/linux/utsname.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/linux/utsname.h diff --git a/sys/dev/pci/drm/include/linux/vga_switcheroo.h b/sys/dev/pci/drm/include/linux/vga_switcheroo.h index ccdb11c5a97..30518e24cbb 100644 --- a/sys/dev/pci/drm/include/linux/vga_switcheroo.h +++ b/sys/dev/pci/drm/include/linux/vga_switcheroo.h @@ -3,15 +3,30 @@ #ifndef _LINUX_VGA_SWITCHEROO_H #define _LINUX_VGA_SWITCHEROO_H +#include <linux/fb.h> + +struct pci_dev; + #define vga_switcheroo_register_client(a, b, c) 0 #define vga_switcheroo_unregister_client(a) #define vga_switcheroo_process_delayed_switch() #define vga_switcheroo_fini_domain_pm_ops(x) -#define vga_switcheroo_lock_ddc(x) -#define vga_switcheroo_unlock_ddc(x) #define vga_switcheroo_handler_flags() 0 #define vga_switcheroo_client_fb_set(a, b) +#define vga_switcheroo_init_domain_pm_ops(a, b) #define VGA_SWITCHEROO_CAN_SWITCH_DDC 1 +static inline int +vga_switcheroo_lock_ddc(struct pci_dev *pdev) +{ + return -ENOSYS; +} + +static inline int +vga_switcheroo_unlock_ddc(struct pci_dev *pdev) +{ + return -ENOSYS; +} + #endif diff --git a/sys/dev/pci/drm/include/linux/vgaarb.h b/sys/dev/pci/drm/include/linux/vgaarb.h index 8a5721af5da..9f8ce34c1d4 100644 --- a/sys/dev/pci/drm/include/linux/vgaarb.h +++ b/sys/dev/pci/drm/include/linux/vgaarb.h @@ -18,4 +18,10 @@ vga_client_register(struct pci_dev *a, void *b, void *c, void *d) return -ENODEV; } +static inline int +vga_remove_vgacon(struct pci_dev *a) +{ + return 0; +} + #endif diff --git a/sys/dev/pci/drm/include/linux/wait.h b/sys/dev/pci/drm/include/linux/wait.h index 5860e906a5c..68a6e07ab7f 100644 --- a/sys/dev/pci/drm/include/linux/wait.h +++ b/sys/dev/pci/drm/include/linux/wait.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wait.h,v 1.4 2019/05/08 23:35:23 jsg Exp $ */ +/* $OpenBSD: wait.h,v 1.5 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2013, 2014, 2015 Mark Kettenis * Copyright (c) 2017 Martin Pieuchot @@ -147,10 +147,12 @@ do { \ } while (0) #define wait_event_killable(wq, condition) \ -do { \ +({ \ + int __ret = 0; \ if (!(condition)) \ - __wait_event_intr_timeout(wq, condition, 0, PCATCH); \ -} while (0) + __ret = __wait_event_intr_timeout(wq, condition, 0, PCATCH); \ + __ret; \ +}) #define wait_event_interruptible(wq, condition) \ ({ \ diff --git a/sys/dev/pci/drm/include/linux/wait_bit.h b/sys/dev/pci/drm/include/linux/wait_bit.h index 6f30fdc1ede..2d91c8841b6 100644 --- a/sys/dev/pci/drm/include/linux/wait_bit.h +++ b/sys/dev/pci/drm/include/linux/wait_bit.h @@ -3,8 +3,27 @@ #ifndef _LINUX_WAIT_BIT_H #define _LINUX_WAIT_BIT_H +#include <linux/wait.h> + int wait_on_bit(unsigned long *, int, unsigned); int wait_on_bit_timeout(unsigned long *, int, unsigned, int); void wake_up_bit(void *, int); +void clear_and_wake_up_bit(int, void *); + +wait_queue_head_t *bit_waitqueue(void *, int); + +extern wait_queue_head_t var_waitq; + +static inline void +wake_up_var(void *var) +{ + wake_up(&var_waitq); +} + +#define wait_var_event_interruptible(var, condition) \ + wait_event_interruptible(var_waitq, condition) + +#define wait_var_event_killable(var, condition) \ + wait_event_killable(var_waitq, condition) #endif diff --git a/sys/dev/pci/drm/include/linux/workqueue.h b/sys/dev/pci/drm/include/linux/workqueue.h index 039a0ab9d2a..e2a877d2ab3 100644 --- a/sys/dev/pci/drm/include/linux/workqueue.h +++ b/sys/dev/pci/drm/include/linux/workqueue.h @@ -1,4 +1,4 @@ -/* $OpenBSD: workqueue.h,v 1.2 2019/05/11 14:39:13 jsg Exp $ */ +/* $OpenBSD: workqueue.h,v 1.3 2020/06/08 04:48:15 jsg Exp $ */ /* * Copyright (c) 2015 Mark Kettenis * @@ -32,6 +32,7 @@ struct workqueue_struct; extern struct workqueue_struct *system_wq; +extern struct workqueue_struct *system_highpri_wq; extern struct workqueue_struct *system_unbound_wq; extern struct workqueue_struct *system_long_wq; @@ -39,6 +40,8 @@ extern struct workqueue_struct *system_long_wq; #define WQ_FREEZABLE 2 #define WQ_UNBOUND 4 +#define WQ_UNBOUND_MAX_ACTIVE 4 /* matches nthreads in drm_linux.c */ + static inline struct workqueue_struct * alloc_workqueue(const char *name, int flags, int max_active) { @@ -195,4 +198,21 @@ bool flush_delayed_work(struct delayed_work *); #define destroy_work_on_stack(x) #define destroy_delayed_work_on_stack(x) +struct rcu_work { + struct work_struct work; + struct rcu_head rcu; +}; + +static inline void +INIT_RCU_WORK(struct rcu_work *work, work_func_t func) +{ + INIT_WORK(&work->work, func); +} + +static inline bool +queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *work) +{ + return queue_work(wq, &work->work); +} + #endif diff --git a/sys/dev/pci/drm/include/linux/ww_mutex.h b/sys/dev/pci/drm/include/linux/ww_mutex.h index a38780b8bd5..82018493a67 100644 --- a/sys/dev/pci/drm/include/linux/ww_mutex.h +++ b/sys/dev/pci/drm/include/linux/ww_mutex.h @@ -55,7 +55,7 @@ struct ww_acquire_ctx { struct ww_mutex { struct mutex base; volatile int acquired; - volatile struct ww_acquire_ctx *ctx; + struct ww_acquire_ctx *ctx; volatile struct proc *owner; }; diff --git a/sys/dev/pci/drm/include/linux/xarray.h b/sys/dev/pci/drm/include/linux/xarray.h new file mode 100644 index 00000000000..6aa486be54b --- /dev/null +++ b/sys/dev/pci/drm/include/linux/xarray.h @@ -0,0 +1,58 @@ +/* Public domain. */ + +#ifndef _LINUX_XARRAY_H +#define _LINUX_XARRAY_H + +#include <linux/gfp.h> + +#include <sys/tree.h> +#include <sys/pool.h> + +#define XA_FLAGS_ALLOC 1 +#define XA_FLAGS_ALLOC1 2 + +struct xarray_entry { + SPLAY_ENTRY(xarray_entry) entry; + int id; + void *ptr; +}; + +struct xarray { + gfp_t xa_flags; + SPLAY_HEAD(xarray_tree, xarray_entry) xa_tree; +}; + +void xa_init_flags(struct xarray *, gfp_t); +void xa_destroy(struct xarray *); +int xa_alloc(struct xarray *, u32 *, void *, int, gfp_t); +void *xa_load(struct xarray *, unsigned long); +void *xa_erase(struct xarray *, unsigned long); +void *xa_get_next(struct xarray *, unsigned long *); + +#define xa_for_each(xa, index, entry) \ + for (index = 0; ((entry) = xa_get_next(xa, &(index))) != NULL; index++) + +#define xa_limit_32b 0 + +static inline void * +xa_mk_value(unsigned long v) +{ + unsigned long r = (v << 1) | 1; + return (void *)r; +} + +static inline bool +xa_is_value(const void *e) +{ + unsigned long v = (unsigned long)e; + return v & 1; +} + +static inline unsigned long +xa_to_value(const void *e) +{ + unsigned long v = (unsigned long)e; + return v >> 1; +} + +#endif diff --git a/sys/dev/pci/drm/include/media/cec-notifier.h b/sys/dev/pci/drm/include/media/cec-notifier.h index 6e0dca87875..8a1434606bb 100644 --- a/sys/dev/pci/drm/include/media/cec-notifier.h +++ b/sys/dev/pci/drm/include/media/cec-notifier.h @@ -3,9 +3,15 @@ #ifndef _MEDIA_CEC_NOTIFIER_H #define _MEDIA_CEC_NOTIFIER_H +struct cec_connector_info { +}; + #define cec_notifier_set_phys_addr_from_edid(x, y) #define cec_notifier_phys_addr_invalidate(x) #define cec_notifier_put(x) #define cec_notifier_get_conn(x, y) NULL +#define cec_fill_conn_info_from_drm(x, y) +#define cec_notifier_conn_register(x, y, z) (void *)1 +#define cec_notifier_conn_unregister(x) #endif diff --git a/sys/dev/pci/drm/include/trace/define_trace.h b/sys/dev/pci/drm/include/trace/define_trace.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/trace/define_trace.h diff --git a/sys/dev/pci/drm/include/trace/events/dma_fence.h b/sys/dev/pci/drm/include/trace/events/dma_fence.h new file mode 100644 index 00000000000..da32d160f3e --- /dev/null +++ b/sys/dev/pci/drm/include/trace/events/dma_fence.h @@ -0,0 +1,14 @@ +/* Public domain. */ + +#ifndef _TRACE_EVENTS_DMA_FENCE_H +#define _TRACE_EVENTS_DMA_FENCE_H + +#define trace_dma_fence_destroy(a) +#define trace_dma_fence_emit(a) +#define trace_dma_fence_enable_signal(a) +#define trace_dma_fence_init(a) +#define trace_dma_fence_signaled(a) +#define trace_dma_fence_wait_end(a) +#define trace_dma_fence_wait_start(a) + +#endif diff --git a/sys/dev/pci/drm/include/uapi/drm/amdgpu_drm.h b/sys/dev/pci/drm/include/uapi/drm/amdgpu_drm.h index 1ceec56de01..d28b4ce744d 100644 --- a/sys/dev/pci/drm/include/uapi/drm/amdgpu_drm.h +++ b/sys/dev/pci/drm/include/uapi/drm/amdgpu_drm.h @@ -125,9 +125,14 @@ extern "C" { /* Flag that BO sharing will be explicitly synchronized */ #define AMDGPU_GEM_CREATE_EXPLICIT_SYNC (1 << 7) /* Flag that indicates allocating MQD gart on GFX9, where the mtype - * for the second page onward should be set to NC. + * for the second page onward should be set to NC. It should never + * be used by user space applications. */ -#define AMDGPU_GEM_CREATE_MQD_GFX9 (1 << 8) +#define AMDGPU_GEM_CREATE_CP_MQD_GFX9 (1 << 8) +/* Flag that BO may contain sensitive data that must be wiped before + * releasing the memory + */ +#define AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE (1 << 9) struct drm_amdgpu_gem_create_in { /** the requested memory size */ @@ -210,13 +215,19 @@ union drm_amdgpu_bo_list { #define AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST (1<<1) /* indicate some job from this context once cause gpu hang */ #define AMDGPU_CTX_QUERY2_FLAGS_GUILTY (1<<2) +/* indicate some errors are detected by RAS */ +#define AMDGPU_CTX_QUERY2_FLAGS_RAS_CE (1<<3) +#define AMDGPU_CTX_QUERY2_FLAGS_RAS_UE (1<<4) /* Context priority level */ #define AMDGPU_CTX_PRIORITY_UNSET -2048 #define AMDGPU_CTX_PRIORITY_VERY_LOW -1023 #define AMDGPU_CTX_PRIORITY_LOW -512 #define AMDGPU_CTX_PRIORITY_NORMAL 0 -/* Selecting a priority above NORMAL requires CAP_SYS_NICE or DRM_MASTER */ +/* + * When used in struct drm_amdgpu_ctx_in, a priority above NORMAL requires + * CAP_SYS_NICE or DRM_MASTER +*/ #define AMDGPU_CTX_PRIORITY_HIGH 512 #define AMDGPU_CTX_PRIORITY_VERY_HIGH 1023 @@ -226,6 +237,7 @@ struct drm_amdgpu_ctx_in { /** For future use, no flags defined so far */ __u32 flags; __u32 ctx_id; + /** AMDGPU_CTX_PRIORITY_* */ __s32 priority; }; @@ -272,13 +284,15 @@ union drm_amdgpu_vm { /* sched ioctl */ #define AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE 1 +#define AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE 2 struct drm_amdgpu_sched_in { /* AMDGPU_SCHED_OP_* */ __u32 op; __u32 fd; + /** AMDGPU_CTX_PRIORITY_* */ __s32 priority; - __u32 flags; + __u32 ctx_id; }; union drm_amdgpu_sched { @@ -326,6 +340,16 @@ struct drm_amdgpu_gem_userptr { /* GFX9 and later: */ #define AMDGPU_TILING_SWIZZLE_MODE_SHIFT 0 #define AMDGPU_TILING_SWIZZLE_MODE_MASK 0x1f +#define AMDGPU_TILING_DCC_OFFSET_256B_SHIFT 5 +#define AMDGPU_TILING_DCC_OFFSET_256B_MASK 0xFFFFFF +#define AMDGPU_TILING_DCC_PITCH_MAX_SHIFT 29 +#define AMDGPU_TILING_DCC_PITCH_MAX_MASK 0x3FFF +#define AMDGPU_TILING_DCC_INDEPENDENT_64B_SHIFT 43 +#define AMDGPU_TILING_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_SHIFT 44 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMDGPU_TILING_SCANOUT_SHIFT 63 +#define AMDGPU_TILING_SCANOUT_MASK 0x1 /* Set/Get helpers for tiling flags. */ #define AMDGPU_TILING_SET(field, value) \ @@ -481,6 +505,8 @@ struct drm_amdgpu_gem_op { #define AMDGPU_VM_MTYPE_CC (3 << 5) /* Use UC MTYPE instead of default MTYPE */ #define AMDGPU_VM_MTYPE_UC (4 << 5) +/* Use RW MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_RW (5 << 5) struct drm_amdgpu_gem_va { /** GEM object handle */ @@ -517,6 +543,9 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_SYNCOBJ_IN 0x04 #define AMDGPU_CHUNK_ID_SYNCOBJ_OUT 0x05 #define AMDGPU_CHUNK_ID_BO_HANDLES 0x06 +#define AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES 0x07 +#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT 0x08 +#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL 0x09 struct drm_amdgpu_cs_chunk { __u32 chunk_id; @@ -559,6 +588,11 @@ union drm_amdgpu_cs { * caches (L2/vL1/sL1/I$). */ #define AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE (1 << 3) +/* Set GDS_COMPUTE_MAX_WAVE_ID = DEFAULT before PACKET3_INDIRECT_BUFFER. + * This will reset wave ID counters for the IB. + */ +#define AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID (1 << 4) + struct drm_amdgpu_cs_chunk_ib { __u32 _pad; /** AMDGPU_IB_FLAG_* */ @@ -592,6 +626,12 @@ struct drm_amdgpu_cs_chunk_sem { __u32 handle; }; +struct drm_amdgpu_cs_chunk_syncobj { + __u32 handle; + __u32 flags; + __u64 point; +}; + #define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ 0 #define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ_FD 1 #define AMDGPU_FENCE_TO_HANDLE_GET_SYNC_FILE_FD 2 @@ -665,6 +705,12 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_GPM_MEM 0x10 /* Subquery id: Query GFX RLC SRLS firmware version */ #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_SRM_MEM 0x11 + /* Subquery id: Query DMCU firmware version */ + #define AMDGPU_INFO_FW_DMCU 0x12 + #define AMDGPU_INFO_FW_TA 0x13 + /* Subquery id: Query DMCUB firmware version */ + #define AMDGPU_INFO_FW_DMCUB 0x14 + /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f /* the used VRAM size */ @@ -718,6 +764,37 @@ struct drm_amdgpu_cs_chunk_data { /* Number of VRAM page faults on CPU access. */ #define AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS 0x1E #define AMDGPU_INFO_VRAM_LOST_COUNTER 0x1F +/* query ras mask of enabled features*/ +#define AMDGPU_INFO_RAS_ENABLED_FEATURES 0x20 + +/* RAS MASK: UMC (VRAM) */ +#define AMDGPU_INFO_RAS_ENABLED_UMC (1 << 0) +/* RAS MASK: SDMA */ +#define AMDGPU_INFO_RAS_ENABLED_SDMA (1 << 1) +/* RAS MASK: GFX */ +#define AMDGPU_INFO_RAS_ENABLED_GFX (1 << 2) +/* RAS MASK: MMHUB */ +#define AMDGPU_INFO_RAS_ENABLED_MMHUB (1 << 3) +/* RAS MASK: ATHUB */ +#define AMDGPU_INFO_RAS_ENABLED_ATHUB (1 << 4) +/* RAS MASK: PCIE */ +#define AMDGPU_INFO_RAS_ENABLED_PCIE (1 << 5) +/* RAS MASK: HDP */ +#define AMDGPU_INFO_RAS_ENABLED_HDP (1 << 6) +/* RAS MASK: XGMI */ +#define AMDGPU_INFO_RAS_ENABLED_XGMI (1 << 7) +/* RAS MASK: DF */ +#define AMDGPU_INFO_RAS_ENABLED_DF (1 << 8) +/* RAS MASK: SMN */ +#define AMDGPU_INFO_RAS_ENABLED_SMN (1 << 9) +/* RAS MASK: SEM */ +#define AMDGPU_INFO_RAS_ENABLED_SEM (1 << 10) +/* RAS MASK: MP0 */ +#define AMDGPU_INFO_RAS_ENABLED_MP0 (1 << 11) +/* RAS MASK: MP1 */ +#define AMDGPU_INFO_RAS_ENABLED_MP1 (1 << 12) +/* RAS MASK: FUSE */ +#define AMDGPU_INFO_RAS_ENABLED_FUSE (1 << 13) #define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 #define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff @@ -854,6 +931,7 @@ struct drm_amdgpu_info_firmware { #define AMDGPU_VRAM_TYPE_HBM 6 #define AMDGPU_VRAM_TYPE_DDR3 7 #define AMDGPU_VRAM_TYPE_DDR4 8 +#define AMDGPU_VRAM_TYPE_GDDR6 9 struct drm_amdgpu_info_device { /** PCI Device ID */ @@ -933,6 +1011,10 @@ struct drm_amdgpu_info_device { __u64 high_va_offset; /** The maximum high virtual address */ __u64 high_va_max; + /* gfx10 pa_sc_tile_steering_override */ + __u32 pa_sc_tile_steering_override; + /* disabled TCCs */ + __u64 tcc_disabled_mask; }; struct drm_amdgpu_info_hw_ip { @@ -986,6 +1068,7 @@ struct drm_amdgpu_info_vce_clock_table { #define AMDGPU_FAMILY_CZ 135 /* Carrizo, Stoney */ #define AMDGPU_FAMILY_AI 141 /* Vega10 */ #define AMDGPU_FAMILY_RV 142 /* Raven */ +#define AMDGPU_FAMILY_NV 143 /* Navi10 */ #if defined(__cplusplus) } diff --git a/sys/dev/pci/drm/include/uapi/drm/drm.h b/sys/dev/pci/drm/include/uapi/drm/drm.h index 97b43504e88..58bb4254250 100644 --- a/sys/dev/pci/drm/include/uapi/drm/drm.h +++ b/sys/dev/pci/drm/include/uapi/drm/drm.h @@ -653,6 +653,7 @@ struct drm_gem_open { #define DRM_CAP_PAGE_FLIP_TARGET 0x11 #define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12 #define DRM_CAP_SYNCOBJ 0x13 +#define DRM_CAP_SYNCOBJ_TIMELINE 0x14 /** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { @@ -739,8 +740,18 @@ struct drm_syncobj_handle { __u32 pad; }; +struct drm_syncobj_transfer { + __u32 src_handle; + __u32 dst_handle; + __u64 src_point; + __u64 dst_point; + __u32 flags; + __u32 pad; +}; + #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ struct drm_syncobj_wait { __u64 handles; /* absolute timeout */ @@ -751,12 +762,34 @@ struct drm_syncobj_wait { __u32 pad; }; +struct drm_syncobj_timeline_wait { + __u64 handles; + /* wait on specific timeline point for every handles*/ + __u64 points; + /* absolute timeout */ + __s64 timeout_nsec; + __u32 count_handles; + __u32 flags; + __u32 first_signaled; /* only valid when not waiting all */ + __u32 pad; +}; + + struct drm_syncobj_array { __u64 handles; __u32 count_handles; __u32 pad; }; +#define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */ +struct drm_syncobj_timeline_array { + __u64 handles; + __u64 points; + __u32 count_handles; + __u32 flags; +}; + + /* Query current scanout sequence number */ struct drm_crtc_get_sequence { __u32 crtc_id; /* requested crtc_id */ @@ -917,6 +950,13 @@ extern "C" { #define DRM_IOCTL_MODE_GET_LEASE DRM_IOWR(0xC8, struct drm_mode_get_lease) #define DRM_IOCTL_MODE_REVOKE_LEASE DRM_IOWR(0xC9, struct drm_mode_revoke_lease) +#define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait) +#define DRM_IOCTL_SYNCOBJ_QUERY DRM_IOWR(0xCB, struct drm_syncobj_timeline_array) +#define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer) +#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array) + +#define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) + /** * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. diff --git a/sys/dev/pci/drm/include/uapi/drm/drm_fourcc.h b/sys/dev/pci/drm/include/uapi/drm/drm_fourcc.h index 721ab7e54d9..8bc0b31597d 100644 --- a/sys/dev/pci/drm/include/uapi/drm/drm_fourcc.h +++ b/sys/dev/pci/drm/include/uapi/drm/drm_fourcc.h @@ -30,10 +30,49 @@ extern "C" { #endif +/** + * DOC: overview + * + * In the DRM subsystem, framebuffer pixel formats are described using the + * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the + * fourcc code, a Format Modifier may optionally be provided, in order to + * further describe the buffer's format - for example tiling or compression. + * + * Format Modifiers + * ---------------- + * + * Format modifiers are used in conjunction with a fourcc code, forming a + * unique fourcc:modifier pair. This format:modifier pair must fully define the + * format and data layout of the buffer, and should be the only way to describe + * that particular buffer. + * + * Having multiple fourcc:modifier pairs which describe the same layout should + * be avoided, as such aliases run the risk of different drivers exposing + * different names for the same data format, forcing userspace to understand + * that they are aliases. + * + * Format modifiers may change any property of the buffer, including the number + * of planes and/or the required allocation size. Format modifiers are + * vendor-namespaced, and as such the relationship between a fourcc code and a + * modifier is specific to the modifer being used. For example, some modifiers + * may preserve meaning - such as number of planes - from the fourcc code, + * whereas others may not. + * + * Vendors should document their modifier usage in as much detail as + * possible, to ensure maximum compatibility across devices, drivers and + * applications. + * + * The authoritative list of format modifier codes is found in + * `include/uapi/drm/drm_fourcc.h` + */ + #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ((__u32)(c) << 16) | ((__u32)(d) << 24)) -#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ +#define DRM_FORMAT_BIG_ENDIAN (1U<<31) /* format is big endian instead of little endian */ + +/* Reserve 0 for the invalid format specifier */ +#define DRM_FORMAT_INVALID 0 /* color index */ #define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ @@ -105,6 +144,17 @@ extern "C" { #define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ #define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ +/* + * Floating point 64bpp RGB + * IEEE 754-2008 binary16 half-precision float + * [15:0] sign:exponent:mantissa 1:5:10 + */ +#define DRM_FORMAT_XRGB16161616F fourcc_code('X', 'R', '4', 'H') /* [63:0] x:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_XBGR16161616F fourcc_code('X', 'B', '4', 'H') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + /* packed YCbCr */ #define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ #define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ @@ -112,6 +162,52 @@ extern "C" { #define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ #define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ +#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ + +/* + * packed Y2xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb + */ +#define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y212 fourcc_code('Y', '2', '1', '2') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y216 fourcc_code('Y', '2', '1', '6') /* [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels */ + +/* + * packed Y4xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb except Y410 + */ +#define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_Y412 fourcc_code('Y', '4', '1', '2') /* [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_Y416 fourcc_code('Y', '4', '1', '6') /* [63:0] A:Cr:Y:Cb 16:16:16:16 little endian */ + +#define DRM_FORMAT_XVYU2101010 fourcc_code('X', 'V', '3', '0') /* [31:0] X:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_XVYU12_16161616 fourcc_code('X', 'V', '3', '6') /* [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_XVYU16161616 fourcc_code('X', 'V', '4', '8') /* [63:0] X:Cr:Y:Cb 16:16:16:16 little endian */ + +/* + * packed YCbCr420 2x2 tiled formats + * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile + */ +/* [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_Y0L0 fourcc_code('Y', '0', 'L', '0') +/* [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_X0L0 fourcc_code('X', '0', 'L', '0') + +/* [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_Y0L2 fourcc_code('Y', '0', 'L', '2') +/* [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_X0L2 fourcc_code('X', '0', 'L', '2') + +/* + * 1-plane YUV 4:2:0 + * In these formats, the component ordering is specified (Y, followed by U + * then V), but the exact Linear layout is undefined. + * These formats can only be used with a non-Linear modifier. + */ +#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8') +#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0') /* * 2 plane RGB + A @@ -142,6 +238,34 @@ extern "C" { #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ /* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0') /* 2x1 subsampled Cr:Cb plane, 10 bit per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [12:4] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian + */ +#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane 12 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y little endian + * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian + */ +#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + +/* * 3 plane YCbCr * index 0: Y plane, [7:0] Y * index 1: Cb plane, [7:0] Cb @@ -184,6 +308,8 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 +#define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 + /* add more to the end as needed */ #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) @@ -285,6 +411,30 @@ extern "C" { #define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) /* + * Intel color control surfaces (CCS) for Gen-12 render compression. + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6) + +/* + * Intel color control surfaces (CCS) for Gen-12 media compression + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7) + +/* * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks * * Macroblocks are laid in a Z-shape, and each pixel data is following the @@ -300,6 +450,15 @@ extern "C" { #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) /* + * Tiled, 16 (pixels) x 16 (lines) - sized macroblocks + * + * This is a simple tiled layout using tiles of 16x16 pixels in a row-major + * layout. For YCbCr formats Cb/Cr components are taken in such a way that + * they correspond to their 16x16 luma block. + */ +#define DRM_FORMAT_MOD_SAMSUNG_16_16_TILE fourcc_mod_code(SAMSUNG, 2) + +/* * Qualcomm Compressed Format * * Refers to a compressed variant of the base format that is compressed. @@ -509,8 +668,25 @@ extern "C" { * AFBC has several features which may be supported and/or used, which are * represented using bits in the modifier. Not all combinations are valid, * and different devices or use-cases may support different combinations. + * + * Further information on the use of AFBC modifiers can be found in + * Documentation/gpu/afbc.rst */ -#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) + +/* + * The top 4 bits (out of the 56 bits alloted for specifying vendor specific + * modifiers) denote the category for modifiers. Currently we have only two + * categories of modifiers ie AFBC and MISC. We can have a maximum of sixteen + * different categories. + */ +#define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ + fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) + +#define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00 +#define DRM_FORMAT_MOD_ARM_TYPE_MISC 0x01 + +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFBC, __afbc_mode) /* * AFBC superblock size @@ -518,10 +694,18 @@ extern "C" { * Indicates the superblock size(s) used for the AFBC buffer. The buffer * size (in pixels) must be aligned to a multiple of the superblock size. * Four lowest significant bits(LSBs) are reserved for block size. + * + * Where one superblock size is specified, it applies to all planes of the + * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, + * the first applies to the Luma plane and the second applies to the Chroma + * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). + * Multiple superblock sizes are only valid for multi-plane YCbCr formats. */ #define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf #define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) /* * AFBC lossless colorspace transform @@ -581,6 +765,45 @@ extern "C" { */ #define AFBC_FORMAT_MOD_SC (1ULL << 9) +/* + * AFBC double-buffer + * + * Indicates that the buffer is allocated in a layout safe for front-buffer + * rendering. + */ +#define AFBC_FORMAT_MOD_DB (1ULL << 10) + +/* + * AFBC buffer content hints + * + * Indicates that the buffer includes per-superblock content hints. + */ +#define AFBC_FORMAT_MOD_BCH (1ULL << 11) + +/* + * Arm 16x16 Block U-Interleaved modifier + * + * This is used by Arm Mali Utgard and Midgard GPUs. It divides the image + * into 16x16 pixel blocks. Blocks are stored linearly in order, but pixels + * in the block are reordered. + */ +#define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 1ULL) + +/* + * Allwinner tiled modifier + * + * This tiling mode is implemented by the VPU found on all Allwinner platforms, + * codenamed sunxi. It is associated with a YUV format that uses either 2 or 3 + * planes. + * + * With this tiling, the luminance samples are disposed in tiles representing + * 32x32 pixels and the chrominance samples in tiles representing 32x64 pixels. + * The pixel order in each tile is linear and the tiles are disposed linearly, + * both in row-major order. + */ +#define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + #if defined(__cplusplus) } #endif diff --git a/sys/dev/pci/drm/include/uapi/drm/drm_mode.h b/sys/dev/pci/drm/include/uapi/drm/drm_mode.h index 8d67243952f..735c8cfdaaa 100644 --- a/sys/dev/pci/drm/include/uapi/drm/drm_mode.h +++ b/sys/dev/pci/drm/include/uapi/drm/drm_mode.h @@ -33,7 +33,15 @@ extern "C" { #endif -#define DRM_DISPLAY_INFO_LEN 32 +/** + * DOC: overview + * + * DRM exposes many UAPI and structure definition to have a consistent + * and standardized interface with user. + * Userspace can refer to these structure definitions and UAPI formats + * to communicate to driver + */ + #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 #define DRM_PROP_NAME_LEN 32 @@ -186,8 +194,9 @@ extern "C" { /* * DRM_MODE_REFLECT_<axis> * - * Signals that the contents of a drm plane is reflected in the <axis> axis, + * Signals that the contents of a drm plane is reflected along the <axis> axis, * in the same way as mirroring. + * See kerneldoc chapter "Plane Composition Properties" for more details. * * This define is provided as a convenience, looking up the property id * using the name->prop id lookup is the preferred method. @@ -352,6 +361,7 @@ enum drm_mode_subconnector { #define DRM_MODE_CONNECTOR_DSI 16 #define DRM_MODE_CONNECTOR_DPI 17 #define DRM_MODE_CONNECTOR_WRITEBACK 18 +#define DRM_MODE_CONNECTOR_SPI 19 struct drm_mode_get_connector { @@ -621,7 +631,8 @@ struct drm_color_ctm { struct drm_color_lut { /* - * Data is U0.16 fixed point format. + * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and + * 0xffff == 1.0. */ __u16 red; __u16 green; @@ -629,6 +640,92 @@ struct drm_color_lut { __u16 reserved; }; +/** + * struct hdr_metadata_infoframe - HDR Metadata Infoframe Data. + * + * HDR Metadata Infoframe as per CTA 861.G spec. This is expected + * to match exactly with the spec. + * + * Userspace is expected to pass the metadata information as per + * the format described in this structure. + */ +struct hdr_metadata_infoframe { + /** + * @eotf: Electro-Optical Transfer Function (EOTF) + * used in the stream. + */ + __u8 eotf; + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u8 metadata_type; + /** + * @display_primaries: Color Primaries of the Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @display_primaries.x: X cordinate of color primary. + * @display_primaries.y: Y cordinate of color primary. + */ + struct { + __u16 x, y; + } display_primaries[3]; + /** + * @white_point: White Point of Colorspace Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @white_point.x: X cordinate of whitepoint of color primary. + * @white_point.y: Y cordinate of whitepoint of color primary. + */ + struct { + __u16 x, y; + } white_point; + /** + * @max_display_mastering_luminance: Max Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_display_mastering_luminance; + /** + * @min_display_mastering_luminance: Min Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of + * 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + * represents 6.5535 cd/m2. + */ + __u16 min_display_mastering_luminance; + /** + * @max_cll: Max Content Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_cll; + /** + * @max_fall: Max Frame Average Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_fall; +}; + +/** + * struct hdr_output_metadata - HDR output metadata + * + * Metadata Information to be passed from userspace + */ +struct hdr_output_metadata { + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u32 metadata_type; + /** + * @hdmi_metadata_type1: HDR Metadata Infoframe. + */ + union { + struct hdr_metadata_infoframe hdmi_metadata_type1; + }; +}; + #define DRM_MODE_PAGE_FLIP_EVENT 0x01 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 @@ -802,6 +899,10 @@ struct drm_format_modifier { }; /** + * struct drm_mode_create_blob - Create New block property + * @data: Pointer to data to copy. + * @length: Length of data to copy. + * @blob_id: new property ID. * Create a new 'blob' data property, copying length bytes from data pointer, * and returning new blob ID. */ @@ -815,6 +916,8 @@ struct drm_mode_create_blob { }; /** + * struct drm_mode_destroy_blob - Destroy user blob + * @blob_id: blob_id to destroy * Destroy a user-created blob property. */ struct drm_mode_destroy_blob { @@ -822,6 +925,12 @@ struct drm_mode_destroy_blob { }; /** + * struct drm_mode_create_lease - Create lease + * @object_ids: Pointer to array of object ids. + * @object_count: Number of object ids. + * @flags: flags for new FD. + * @lessee_id: unique identifier for lessee. + * @fd: file descriptor to new drm_master file. * Lease mode resources, creating another drm_master. */ struct drm_mode_create_lease { @@ -839,6 +948,10 @@ struct drm_mode_create_lease { }; /** + * struct drm_mode_list_lessees - List lessees + * @count_lessees: Number of lessees. + * @pad: pad. + * @lessees_ptr: Pointer to lessess. * List lesses from a drm_master */ struct drm_mode_list_lessees { @@ -859,6 +972,10 @@ struct drm_mode_list_lessees { }; /** + * struct drm_mode_get_lease - Get Lease + * @count_objects: Number of leased objects. + * @pad: pad. + * @objects_ptr: Pointer to objects. * Get leased objects */ struct drm_mode_get_lease { @@ -879,6 +996,8 @@ struct drm_mode_get_lease { }; /** + * struct drm_mode_revoke_lease - Revoke lease + * @lessee_id: Unique ID of lessee. * Revoke lease */ struct drm_mode_revoke_lease { @@ -887,6 +1006,25 @@ struct drm_mode_revoke_lease { __u32 lessee_id; }; +/** + * struct drm_mode_rect - Two dimensional rectangle. + * @x1: Horizontal starting coordinate (inclusive). + * @y1: Vertical starting coordinate (inclusive). + * @x2: Horizontal ending coordinate (exclusive). + * @y2: Vertical ending coordinate (exclusive). + * + * With drm subsystem using struct drm_rect to manage rectangular area this + * export it to user-space. + * + * Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS. + */ +struct drm_mode_rect { + __s32 x1; + __s32 y1; + __s32 x2; + __s32 y2; +}; + #if defined(__cplusplus) } #endif diff --git a/sys/dev/pci/drm/include/uapi/drm/i915_drm.h b/sys/dev/pci/drm/include/uapi/drm/i915_drm.h index 4671c9150d4..2813e579b48 100644 --- a/sys/dev/pci/drm/include/uapi/drm/i915_drm.h +++ b/sys/dev/pci/drm/include/uapi/drm/i915_drm.h @@ -63,6 +63,28 @@ extern "C" { #define I915_RESET_UEVENT "RESET" /* + * i915_user_extension: Base class for defining a chain of extensions + * + * Many interfaces need to grow over time. In most cases we can simply + * extend the struct and have userspace pass in more data. Another option, + * as demonstrated by Vulkan's approach to providing extensions for forward + * and backward compatibility, is to use a list of optional structs to + * provide those extra details. + * + * The key advantage to using an extension chain is that it allows us to + * redefine the interface more easily than an ever growing struct of + * increasing complexity, and for large parts of that interface to be + * entirely optional. The downside is more pointer chasing; chasing across + * the __user boundary with pointers encapsulated inside u64. + */ +struct i915_user_extension { + __u64 next_extension; + __u32 name; + __u32 flags; /* All undefined bits must be zero. */ + __u32 rsvd[4]; /* Reserved for future use; must be zero. */ +}; + +/* * MOCS indexes used for GPU surfaces, defining the cacheability of the * surface data and the coherency for this data wrt. CPU vs. GPU accesses. */ @@ -99,9 +121,25 @@ enum drm_i915_gem_engine_class { I915_ENGINE_CLASS_VIDEO = 2, I915_ENGINE_CLASS_VIDEO_ENHANCE = 3, + /* should be kept compact */ + I915_ENGINE_CLASS_INVALID = -1 }; +/* + * There may be more than one engine fulfilling any role within the system. + * Each engine of a class is given a unique instance number and therefore + * any engine can be specified by its class:instance tuplet. APIs that allow + * access to any engine in the system will use struct i915_engine_class_instance + * for this identification. + */ +struct i915_engine_class_instance { + __u16 engine_class; /* see enum drm_i915_gem_engine_class */ + __u16 engine_instance; +#define I915_ENGINE_CLASS_INVALID_NONE -1 +#define I915_ENGINE_CLASS_INVALID_VIRTUAL -2 +}; + /** * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915 * @@ -319,6 +357,9 @@ typedef struct _drm_i915_sarea { #define DRM_I915_PERF_ADD_CONFIG 0x37 #define DRM_I915_PERF_REMOVE_CONFIG 0x38 #define DRM_I915_QUERY 0x39 +#define DRM_I915_GEM_VM_CREATE 0x3a +#define DRM_I915_GEM_VM_DESTROY 0x3b +/* Must be kept compact -- no holes */ #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -354,6 +395,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) #define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) #define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt) +#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_offset) #define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) #define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) #define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling) @@ -367,6 +409,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) #define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create_ext) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) #define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) #define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) @@ -377,6 +420,8 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) #define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) +#define DRM_IOCTL_I915_GEM_VM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control) +#define DRM_IOCTL_I915_GEM_VM_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -412,6 +457,14 @@ typedef struct drm_i915_irq_wait { int irq_seq; } drm_i915_irq_wait_t; +/* + * Different modes of per-process Graphics Translation Table, + * see I915_PARAM_HAS_ALIASING_PPGTT + */ +#define I915_GEM_PPGTT_NONE 0 +#define I915_GEM_PPGTT_ALIASING 1 +#define I915_GEM_PPGTT_FULL 2 + /* Ioctl to query kernel params: */ #define I915_PARAM_IRQ_ACTIVE 1 @@ -468,6 +521,8 @@ typedef struct drm_i915_irq_wait { #define I915_SCHEDULER_CAP_ENABLED (1ul << 0) #define I915_SCHEDULER_CAP_PRIORITY (1ul << 1) #define I915_SCHEDULER_CAP_PREEMPTION (1ul << 2) +#define I915_SCHEDULER_CAP_SEMAPHORES (1ul << 3) +#define I915_SCHEDULER_CAP_ENGINE_BUSY_STATS (1ul << 4) #define I915_PARAM_HUC_STATUS 42 @@ -529,6 +584,43 @@ typedef struct drm_i915_irq_wait { */ #define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51 +/* + * Once upon a time we supposed that writes through the GGTT would be + * immediately in physical memory (once flushed out of the CPU path). However, + * on a few different processors and chipsets, this is not necessarily the case + * as the writes appear to be buffered internally. Thus a read of the backing + * storage (physical memory) via a different path (with different physical tags + * to the indirect write via the GGTT) will see stale values from before + * the GGTT write. Inside the kernel, we can for the most part keep track of + * the different read/write domains in use (e.g. set-domain), but the assumption + * of coherency is baked into the ABI, hence reporting its true state in this + * parameter. + * + * Reports true when writes via mmap_gtt are immediately visible following an + * lfence to flush the WCB. + * + * Reports false when writes via mmap_gtt are indeterminately delayed in an in + * internal buffer and are _not_ immediately visible to third parties accessing + * directly via mmap_cpu/mmap_wc. Use of mmap_gtt as part of an IPC + * communications channel when reporting false is strongly disadvised. + */ +#define I915_PARAM_MMAP_GTT_COHERENT 52 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports coordination of parallel + * execution through use of explicit fence support. + * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT. + */ +#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53 + +/* + * Revision of the i915-perf uAPI. The value returned helps determine what + * i915-perf features are available. See drm_i915_perf_property_id. + */ +#define I915_PARAM_PERF_REVISION 54 + +/* Must be kept compact -- no holes and well documented */ + typedef struct drm_i915_getparam { __s32 param; /* @@ -544,6 +636,7 @@ typedef struct drm_i915_getparam { #define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 #define I915_SETPARAM_ALLOW_BATCHBUFFER 3 #define I915_SETPARAM_NUM_USED_FENCES 4 +/* Must be kept compact -- no holes */ typedef struct drm_i915_setparam { int param; @@ -701,6 +794,37 @@ struct drm_i915_gem_mmap_gtt { __u64 offset; }; +struct drm_i915_gem_mmap_offset { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; + + /** + * Flags for extended behaviour. + * + * It is mandatory that one of the MMAP_OFFSET types + * (GTT, WC, WB, UC, etc) should be included. + */ + __u64 flags; +#define I915_MMAP_OFFSET_GTT 0 +#define I915_MMAP_OFFSET_WC 1 +#define I915_MMAP_OFFSET_WB 2 +#define I915_MMAP_OFFSET_UC 3 + + /* + * Zero-terminated chain of extensions. + * + * No current extensions defined; mbz. + */ + __u64 extensions; +}; + struct drm_i915_gem_set_domain { /** Handle for the object */ __u32 handle; @@ -1048,7 +1172,16 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_FENCE_ARRAY (1<<19) -#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1)) +/* + * Setting I915_EXEC_FENCE_SUBMIT implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_SUBMIT (1 << 20) + +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1)) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ @@ -1090,32 +1223,34 @@ struct drm_i915_gem_busy { * as busy may become idle before the ioctl is completed. * * Furthermore, if the object is busy, which engine is busy is only - * provided as a guide. There are race conditions which prevent the - * report of which engines are busy from being always accurate. - * However, the converse is not true. If the object is idle, the - * result of the ioctl, that all engines are idle, is accurate. + * provided as a guide and only indirectly by reporting its class + * (there may be more than one engine in each class). There are race + * conditions which prevent the report of which engines are busy from + * being always accurate. However, the converse is not true. If the + * object is idle, the result of the ioctl, that all engines are idle, + * is accurate. * * The returned dword is split into two fields to indicate both - * the engines on which the object is being read, and the - * engine on which it is currently being written (if any). + * the engine classess on which the object is being read, and the + * engine class on which it is currently being written (if any). * * The low word (bits 0:15) indicate if the object is being written * to by any engine (there can only be one, as the GEM implicit * synchronisation rules force writes to be serialised). Only the - * engine for the last write is reported. + * engine class (offset by 1, I915_ENGINE_CLASS_RENDER is reported as + * 1 not 0 etc) for the last write is reported. * - * The high word (bits 16:31) are a bitmask of which engines are - * currently reading from the object. Multiple engines may be + * The high word (bits 16:31) are a bitmask of which engines classes + * are currently reading from the object. Multiple engines may be * reading from the object simultaneously. * - * The value of each engine is the same as specified in the - * EXECBUFFER2 ioctl, i.e. I915_EXEC_RENDER, I915_EXEC_BSD etc. - * Note I915_EXEC_DEFAULT is a symbolic value and is mapped to - * the I915_EXEC_RENDER engine for execution, and so it is never + * The value of each engine class is the same as specified in the + * I915_CONTEXT_SET_ENGINES parameter and via perf, i.e. + * I915_ENGINE_CLASS_RENDER, I915_ENGINE_CLASS_COPY, etc. * reported as active itself. Some hardware may have parallel * execution engines, e.g. multiple media engines, which are - * mapped to the same identifier in the EXECBUFFER2 ioctl and - * so are not separately reported for busyness. + * mapped to the same class identifier and so are not separately + * reported for busyness. * * Caveat emptor: * Only the boolean result of this query is reliable; that is whether @@ -1382,16 +1517,334 @@ struct drm_i915_gem_wait { }; struct drm_i915_gem_context_create { - /* output: id of new context*/ - __u32 ctx_id; + __u32 ctx_id; /* output: id of new context*/ __u32 pad; }; +struct drm_i915_gem_context_create_ext { + __u32 ctx_id; /* output: id of new context*/ + __u32 flags; +#define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS (1u << 0) +#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE (1u << 1) +#define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \ + (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1)) + __u64 extensions; +}; + +struct drm_i915_gem_context_param { + __u32 ctx_id; + __u32 size; + __u64 param; +#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 +#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 +#define I915_CONTEXT_PARAM_GTT_SIZE 0x3 +#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4 +#define I915_CONTEXT_PARAM_BANNABLE 0x5 +#define I915_CONTEXT_PARAM_PRIORITY 0x6 +#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */ +#define I915_CONTEXT_DEFAULT_PRIORITY 0 +#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */ + /* + * When using the following param, value should be a pointer to + * drm_i915_gem_context_param_sseu. + */ +#define I915_CONTEXT_PARAM_SSEU 0x7 + +/* + * Not all clients may want to attempt automatic recover of a context after + * a hang (for example, some clients may only submit very small incremental + * batches relying on known logical state of previous batches which will never + * recover correctly and each attempt will hang), and so would prefer that + * the context is forever banned instead. + * + * If set to false (0), after a reset, subsequent (and in flight) rendering + * from this context is discarded, and the client will need to create a new + * context to use instead. + * + * If set to true (1), the kernel will automatically attempt to recover the + * context by skipping the hanging batch and executing the next batch starting + * from the default context state (discarding the incomplete logical context + * state lost due to the reset). + * + * On creation, all new contexts are marked as recoverable. + */ +#define I915_CONTEXT_PARAM_RECOVERABLE 0x8 + + /* + * The id of the associated virtual memory address space (ppGTT) of + * this context. Can be retrieved and passed to another context + * (on the same fd) for both to use the same ppGTT and so share + * address layouts, and avoid reloading the page tables on context + * switches between themselves. + * + * See DRM_I915_GEM_VM_CREATE and DRM_I915_GEM_VM_DESTROY. + */ +#define I915_CONTEXT_PARAM_VM 0x9 + +/* + * I915_CONTEXT_PARAM_ENGINES: + * + * Bind this context to operate on this subset of available engines. Henceforth, + * the I915_EXEC_RING selector for DRM_IOCTL_I915_GEM_EXECBUFFER2 operates as + * an index into this array of engines; I915_EXEC_DEFAULT selecting engine[0] + * and upwards. Slots 0...N are filled in using the specified (class, instance). + * Use + * engine_class: I915_ENGINE_CLASS_INVALID, + * engine_instance: I915_ENGINE_CLASS_INVALID_NONE + * to specify a gap in the array that can be filled in later, e.g. by a + * virtual engine used for load balancing. + * + * Setting the number of engines bound to the context to 0, by passing a zero + * sized argument, will revert back to default settings. + * + * See struct i915_context_param_engines. + * + * Extensions: + * i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE) + * i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND) + */ +#define I915_CONTEXT_PARAM_ENGINES 0xa + +/* + * I915_CONTEXT_PARAM_PERSISTENCE: + * + * Allow the context and active rendering to survive the process until + * completion. Persistence allows fire-and-forget clients to queue up a + * bunch of work, hand the output over to a display server and then quit. + * If the context is marked as not persistent, upon closing (either via + * an explicit DRM_I915_GEM_CONTEXT_DESTROY or implicitly from file closure + * or process termination), the context and any outstanding requests will be + * cancelled (and exported fences for cancelled requests marked as -EIO). + * + * By default, new contexts allow persistence. + */ +#define I915_CONTEXT_PARAM_PERSISTENCE 0xb + +/* + * I915_CONTEXT_PARAM_RINGSIZE: + * + * Sets the size of the CS ringbuffer to use for logical ring contexts. This + * applies a limit of how many batches can be queued to HW before the caller + * is blocked due to lack of space for more commands. + * + * Only reliably possible to be set prior to first use, i.e. during + * construction. At any later point, the current execution must be flushed as + * the ring can only be changed while the context is idle. Note, the ringsize + * can be specified as a constructor property, see + * I915_CONTEXT_CREATE_EXT_SETPARAM, but can also be set later if required. + * + * Only applies to the current set of engine and lost when those engines + * are replaced by a new mapping (see I915_CONTEXT_PARAM_ENGINES). + * + * Must be between 4 - 512 KiB, in intervals of page size [4 KiB]. + * Default is 16 KiB. + */ +#define I915_CONTEXT_PARAM_RINGSIZE 0xc +/* Must be kept compact -- no holes and well documented */ + + __u64 value; +}; + +/** + * Context SSEU programming + * + * It may be necessary for either functional or performance reason to configure + * a context to run with a reduced number of SSEU (where SSEU stands for Slice/ + * Sub-slice/EU). + * + * This is done by configuring SSEU configuration using the below + * @struct drm_i915_gem_context_param_sseu for every supported engine which + * userspace intends to use. + * + * Not all GPUs or engines support this functionality in which case an error + * code -ENODEV will be returned. + * + * Also, flexibility of possible SSEU configuration permutations varies between + * GPU generations and software imposed limitations. Requesting such a + * combination will return an error code of -EINVAL. + * + * NOTE: When perf/OA is active the context's SSEU configuration is ignored in + * favour of a single global setting. + */ +struct drm_i915_gem_context_param_sseu { + /* + * Engine class & instance to be configured or queried. + */ + struct i915_engine_class_instance engine; + + /* + * Unknown flags must be cleared to zero. + */ + __u32 flags; +#define I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX (1u << 0) + + /* + * Mask of slices to enable for the context. Valid values are a subset + * of the bitmask value returned for I915_PARAM_SLICE_MASK. + */ + __u64 slice_mask; + + /* + * Mask of subslices to enable for the context. Valid values are a + * subset of the bitmask value return by I915_PARAM_SUBSLICE_MASK. + */ + __u64 subslice_mask; + + /* + * Minimum/Maximum number of EUs to enable per subslice for the + * context. min_eus_per_subslice must be inferior or equal to + * max_eus_per_subslice. + */ + __u16 min_eus_per_subslice; + __u16 max_eus_per_subslice; + + /* + * Unused for now. Must be cleared to zero. + */ + __u32 rsvd; +}; + +/* + * i915_context_engines_load_balance: + * + * Enable load balancing across this set of engines. + * + * Into the I915_EXEC_DEFAULT slot [0], a virtual engine is created that when + * used will proxy the execbuffer request onto one of the set of engines + * in such a way as to distribute the load evenly across the set. + * + * The set of engines must be compatible (e.g. the same HW class) as they + * will share the same logical GPU context and ring. + * + * To intermix rendering with the virtual engine and direct rendering onto + * the backing engines (bypassing the load balancing proxy), the context must + * be defined to use a single timeline for all engines. + */ +struct i915_context_engines_load_balance { + struct i915_user_extension base; + + __u16 engine_index; + __u16 num_siblings; + __u32 flags; /* all undefined flags must be zero */ + + __u64 mbz64; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 num_siblings; \ + __u32 flags; \ + __u64 mbz64; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/* + * i915_context_engines_bond: + * + * Constructed bonded pairs for execution within a virtual engine. + * + * All engines are equal, but some are more equal than others. Given + * the distribution of resources in the HW, it may be preferable to run + * a request on a given subset of engines in parallel to a request on a + * specific engine. We enable this selection of engines within a virtual + * engine by specifying bonding pairs, for any given master engine we will + * only execute on one of the corresponding siblings within the virtual engine. + * + * To execute a request in parallel on the master engine and a sibling requires + * coordination with a I915_EXEC_FENCE_SUBMIT. + */ +struct i915_context_engines_bond { + struct i915_user_extension base; + + struct i915_engine_class_instance master; + + __u16 virtual_index; /* index of virtual engine in ctx->engines[] */ + __u16 num_bonds; + + __u64 flags; /* all undefined flags must be zero */ + __u64 mbz64[4]; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \ + struct i915_user_extension base; \ + struct i915_engine_class_instance master; \ + __u16 virtual_index; \ + __u16 num_bonds; \ + __u64 flags; \ + __u64 mbz64[4]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +struct i915_context_param_engines { + __u64 extensions; /* linked chain of extension blocks, 0 terminates */ +#define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ +#define I915_CONTEXT_ENGINES_EXT_BOND 1 /* see i915_context_engines_bond */ + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_PARAM_ENGINES(name__, N__) struct { \ + __u64 extensions; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +struct drm_i915_gem_context_create_ext_setparam { +#define I915_CONTEXT_CREATE_EXT_SETPARAM 0 + struct i915_user_extension base; + struct drm_i915_gem_context_param param; +}; + +struct drm_i915_gem_context_create_ext_clone { +#define I915_CONTEXT_CREATE_EXT_CLONE 1 + struct i915_user_extension base; + __u32 clone_id; + __u32 flags; +#define I915_CONTEXT_CLONE_ENGINES (1u << 0) +#define I915_CONTEXT_CLONE_FLAGS (1u << 1) +#define I915_CONTEXT_CLONE_SCHEDATTR (1u << 2) +#define I915_CONTEXT_CLONE_SSEU (1u << 3) +#define I915_CONTEXT_CLONE_TIMELINE (1u << 4) +#define I915_CONTEXT_CLONE_VM (1u << 5) +#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1) + __u64 rsvd; +}; + struct drm_i915_gem_context_destroy { __u32 ctx_id; __u32 pad; }; +/* + * DRM_I915_GEM_VM_CREATE - + * + * Create a new virtual memory address space (ppGTT) for use within a context + * on the same file. Extensions can be provided to configure exactly how the + * address space is setup upon creation. + * + * The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is + * returned in the outparam @id. + * + * No flags are defined, with all bits reserved and must be zero. + * + * An extension chain maybe provided, starting with @extensions, and terminated + * by the @next_extension being 0. Currently, no extensions are defined. + * + * DRM_I915_GEM_VM_DESTROY - + * + * Destroys a previously created VM id, specified in @id. + * + * No extensions or flags are allowed currently, and so must be zero. + */ +struct drm_i915_gem_vm_control { + __u64 extensions; + __u32 flags; + __u32 vm_id; +}; + struct drm_i915_reg_read { /* * Register offset. @@ -1404,6 +1857,7 @@ struct drm_i915_reg_read { __u64 val; /* Return value */ }; + /* Known registers: * * Render engine timestamp - 0x2358 + 64bit - gen7+ @@ -1443,22 +1897,6 @@ struct drm_i915_gem_userptr { __u32 handle; }; -struct drm_i915_gem_context_param { - __u32 ctx_id; - __u32 size; - __u64 param; -#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 -#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 -#define I915_CONTEXT_PARAM_GTT_SIZE 0x3 -#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4 -#define I915_CONTEXT_PARAM_BANNABLE 0x5 -#define I915_CONTEXT_PARAM_PRIORITY 0x6 -#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */ -#define I915_CONTEXT_DEFAULT_PRIORITY 0 -#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */ - __u64 value; -}; - enum drm_i915_oa_format { I915_OA_FORMAT_A13 = 1, /* HSW only */ I915_OA_FORMAT_A29, /* HSW only */ @@ -1481,23 +1919,31 @@ enum drm_i915_perf_property_id { * Open the stream for a specific context handle (as used with * execbuffer2). A stream opened for a specific context this way * won't typically require root privileges. + * + * This property is available in perf revision 1. */ DRM_I915_PERF_PROP_CTX_HANDLE = 1, /** * A value of 1 requests the inclusion of raw OA unit reports as * part of stream samples. + * + * This property is available in perf revision 1. */ DRM_I915_PERF_PROP_SAMPLE_OA, /** * The value specifies which set of OA unit metrics should be * be configured, defining the contents of any OA unit reports. + * + * This property is available in perf revision 1. */ DRM_I915_PERF_PROP_OA_METRICS_SET, /** * The value specifies the size and layout of OA unit reports. + * + * This property is available in perf revision 1. */ DRM_I915_PERF_PROP_OA_FORMAT, @@ -1507,9 +1953,22 @@ enum drm_i915_perf_property_id { * from this exponent as follows: * * 80ns * 2^(period_exponent + 1) + * + * This property is available in perf revision 1. */ DRM_I915_PERF_PROP_OA_EXPONENT, + /** + * Specifying this property is only valid when specify a context to + * filter with DRM_I915_PERF_PROP_CTX_HANDLE. Specifying this property + * will hold preemption of the particular context we want to gather + * performance data about. The execbuf2 submissions must include a + * drm_i915_gem_execbuffer_ext_perf parameter for this to apply. + * + * This property is available in perf revision 3. + */ + DRM_I915_PERF_PROP_HOLD_PREEMPTION, + DRM_I915_PERF_PROP_MAX /* non-ABI */ }; @@ -1538,6 +1997,8 @@ struct drm_i915_perf_open_param { * to close and re-open a stream with the same configuration. * * It's undefined whether any pending data for the stream will be lost. + * + * This ioctl is available in perf revision 1. */ #define I915_PERF_IOCTL_ENABLE _IO('i', 0x0) @@ -1545,10 +2006,25 @@ struct drm_i915_perf_open_param { * Disable data capture for a stream. * * It is an error to try and read a stream that is disabled. + * + * This ioctl is available in perf revision 1. */ #define I915_PERF_IOCTL_DISABLE _IO('i', 0x1) /** + * Change metrics_set captured by a stream. + * + * If the stream is bound to a specific context, the configuration change + * will performed inline with that context such that it takes effect before + * the next execbuf submission. + * + * Returns the previously bound metrics set id, or a negative error code. + * + * This ioctl is available in perf revision 2. + */ +#define I915_PERF_IOCTL_CONFIG _IO('i', 0x2) + +/** * Common to all i915 perf records */ struct drm_i915_perf_record_header { @@ -1620,6 +2096,9 @@ struct drm_i915_perf_oa_config { struct drm_i915_query_item { __u64 query_id; #define DRM_I915_QUERY_TOPOLOGY_INFO 1 +#define DRM_I915_QUERY_ENGINE_INFO 2 +#define DRM_I915_QUERY_PERF_CONFIG 3 +/* Must be kept compact -- no holes and well documented */ /* * When set to zero by userspace, this is filled with the size of the @@ -1630,9 +2109,18 @@ struct drm_i915_query_item { __s32 length; /* - * Unused for now. Must be cleared to zero. + * When query_id == DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. + * + * When query_id == DRM_I915_QUERY_PERF_CONFIG, must be one of the + * following : + * - DRM_I915_QUERY_PERF_CONFIG_LIST + * - DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID + * - DRM_I915_QUERY_PERF_CONFIG_FOR_UUID */ __u32 flags; +#define DRM_I915_QUERY_PERF_CONFIG_LIST 1 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID 2 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID 3 /* * Data will be written at the location pointed by data_ptr when the @@ -1668,8 +2156,10 @@ struct drm_i915_query { * (data[X / 8] >> (X % 8)) & 1 * * - the subslice mask for each slice with one bit per subslice telling - * whether a subslice is available. The availability of subslice Y in slice - * X can be queried with the following formula : + * whether a subslice is available. Gen12 has dual-subslices, which are + * similar to two gen11 subslices. For gen12, this array represents dual- + * subslices. The availability of subslice Y in slice X can be queried + * with the following formula : * * (data[subslice_offset + * X * subslice_stride + @@ -1717,6 +2207,97 @@ struct drm_i915_query_topology_info { __u8 data[]; }; +/** + * struct drm_i915_engine_info + * + * Describes one engine and it's capabilities as known to the driver. + */ +struct drm_i915_engine_info { + /** Engine class and instance. */ + struct i915_engine_class_instance engine; + + /** Reserved field. */ + __u32 rsvd0; + + /** Engine flags. */ + __u64 flags; + + /** Capabilities of this engine. */ + __u64 capabilities; +#define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) +#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) + + /** Reserved fields. */ + __u64 rsvd1[4]; +}; + +/** + * struct drm_i915_query_engine_info + * + * Engine info query enumerates all engines known to the driver by filling in + * an array of struct drm_i915_engine_info structures. + */ +struct drm_i915_query_engine_info { + /** Number of struct drm_i915_engine_info structs following. */ + __u32 num_engines; + + /** MBZ */ + __u32 rsvd[3]; + + /** Marker for drm_i915_engine_info structures. */ + struct drm_i915_engine_info engines[]; +}; + +/* + * Data written by the kernel with query DRM_I915_QUERY_PERF_CONFIG. + */ +struct drm_i915_query_perf_config { + union { + /* + * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets + * this fields to the number of configurations available. + */ + __u64 n_configs; + + /* + * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, + * i915 will use the value in this field as configuration + * identifier to decide what data to write into config_ptr. + */ + __u64 config; + + /* + * When query_id == DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, + * i915 will use the value in this field as configuration + * identifier to decide what data to write into config_ptr. + * + * String formatted like "%08x-%04x-%04x-%04x-%012x" + */ + char uuid[36]; + }; + + /* + * Unused for now. Must be cleared to zero. + */ + __u32 flags; + + /* + * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_LIST, i915 will + * write an array of __u64 of configuration identifiers. + * + * When query_item.flags == DRM_I915_QUERY_PERF_CONFIG_DATA, i915 will + * write a struct drm_i915_perf_oa_config. If the following fields of + * drm_i915_perf_oa_config are set not set to 0, i915 will write into + * the associated pointers the values of submitted when the + * configuration was created : + * + * - n_mux_regs + * - n_boolean_regs + * - n_flex_regs + */ + __u8 data[]; +}; + #if defined(__cplusplus) } #endif diff --git a/sys/dev/pci/drm/include/uapi/drm/radeon_drm.h b/sys/dev/pci/drm/include/uapi/drm/radeon_drm.h index ddc8f23b730..490a59cc453 100644 --- a/sys/dev/pci/drm/include/uapi/drm/radeon_drm.h +++ b/sys/dev/pci/drm/include/uapi/drm/radeon_drm.h @@ -765,7 +765,7 @@ typedef struct drm_radeon_irq_wait { typedef struct drm_radeon_setparam { unsigned int param; - int64_t value; + __s64 value; } drm_radeon_setparam_t; #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ diff --git a/sys/dev/pci/drm/include/uapi/linux/ioctl.h b/sys/dev/pci/drm/include/uapi/linux/ioctl.h new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/sys/dev/pci/drm/include/uapi/linux/ioctl.h diff --git a/sys/dev/pci/drm/include/uapi/linux/kfd_ioctl.h b/sys/dev/pci/drm/include/uapi/linux/kfd_ioctl.h new file mode 100644 index 00000000000..20917c59f39 --- /dev/null +++ b/sys/dev/pci/drm/include/uapi/linux/kfd_ioctl.h @@ -0,0 +1,535 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef KFD_IOCTL_H_INCLUDED +#define KFD_IOCTL_H_INCLUDED + +#include <drm/drm.h> +#include <linux/ioctl.h> + +#define KFD_IOCTL_MAJOR_VERSION 1 +#define KFD_IOCTL_MINOR_VERSION 1 + +struct kfd_ioctl_get_version_args { + __u32 major_version; /* from KFD */ + __u32 minor_version; /* from KFD */ +}; + +/* For kfd_ioctl_create_queue_args.queue_type. */ +#define KFD_IOC_QUEUE_TYPE_COMPUTE 0x0 +#define KFD_IOC_QUEUE_TYPE_SDMA 0x1 +#define KFD_IOC_QUEUE_TYPE_COMPUTE_AQL 0x2 +#define KFD_IOC_QUEUE_TYPE_SDMA_XGMI 0x3 + +#define KFD_MAX_QUEUE_PERCENTAGE 100 +#define KFD_MAX_QUEUE_PRIORITY 15 + +struct kfd_ioctl_create_queue_args { + __u64 ring_base_address; /* to KFD */ + __u64 write_pointer_address; /* from KFD */ + __u64 read_pointer_address; /* from KFD */ + __u64 doorbell_offset; /* from KFD */ + + __u32 ring_size; /* to KFD */ + __u32 gpu_id; /* to KFD */ + __u32 queue_type; /* to KFD */ + __u32 queue_percentage; /* to KFD */ + __u32 queue_priority; /* to KFD */ + __u32 queue_id; /* from KFD */ + + __u64 eop_buffer_address; /* to KFD */ + __u64 eop_buffer_size; /* to KFD */ + __u64 ctx_save_restore_address; /* to KFD */ + __u32 ctx_save_restore_size; /* to KFD */ + __u32 ctl_stack_size; /* to KFD */ +}; + +struct kfd_ioctl_destroy_queue_args { + __u32 queue_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_update_queue_args { + __u64 ring_base_address; /* to KFD */ + + __u32 queue_id; /* to KFD */ + __u32 ring_size; /* to KFD */ + __u32 queue_percentage; /* to KFD */ + __u32 queue_priority; /* to KFD */ +}; + +struct kfd_ioctl_set_cu_mask_args { + __u32 queue_id; /* to KFD */ + __u32 num_cu_mask; /* to KFD */ + __u64 cu_mask_ptr; /* to KFD */ +}; + +struct kfd_ioctl_get_queue_wave_state_args { + __u64 ctl_stack_address; /* to KFD */ + __u32 ctl_stack_used_size; /* from KFD */ + __u32 save_area_used_size; /* from KFD */ + __u32 queue_id; /* to KFD */ + __u32 pad; +}; + +/* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */ +#define KFD_IOC_CACHE_POLICY_COHERENT 0 +#define KFD_IOC_CACHE_POLICY_NONCOHERENT 1 + +struct kfd_ioctl_set_memory_policy_args { + __u64 alternate_aperture_base; /* to KFD */ + __u64 alternate_aperture_size; /* to KFD */ + + __u32 gpu_id; /* to KFD */ + __u32 default_policy; /* to KFD */ + __u32 alternate_policy; /* to KFD */ + __u32 pad; +}; + +/* + * All counters are monotonic. They are used for profiling of compute jobs. + * The profiling is done by userspace. + * + * In case of GPU reset, the counter should not be affected. + */ + +struct kfd_ioctl_get_clock_counters_args { + __u64 gpu_clock_counter; /* from KFD */ + __u64 cpu_clock_counter; /* from KFD */ + __u64 system_clock_counter; /* from KFD */ + __u64 system_clock_freq; /* from KFD */ + + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_process_device_apertures { + __u64 lds_base; /* from KFD */ + __u64 lds_limit; /* from KFD */ + __u64 scratch_base; /* from KFD */ + __u64 scratch_limit; /* from KFD */ + __u64 gpuvm_base; /* from KFD */ + __u64 gpuvm_limit; /* from KFD */ + __u32 gpu_id; /* from KFD */ + __u32 pad; +}; + +/* + * AMDKFD_IOC_GET_PROCESS_APERTURES is deprecated. Use + * AMDKFD_IOC_GET_PROCESS_APERTURES_NEW instead, which supports an + * unlimited number of GPUs. + */ +#define NUM_OF_SUPPORTED_GPUS 7 +struct kfd_ioctl_get_process_apertures_args { + struct kfd_process_device_apertures + process_apertures[NUM_OF_SUPPORTED_GPUS];/* from KFD */ + + /* from KFD, should be in the range [1 - NUM_OF_SUPPORTED_GPUS] */ + __u32 num_of_nodes; + __u32 pad; +}; + +struct kfd_ioctl_get_process_apertures_new_args { + /* User allocated. Pointer to struct kfd_process_device_apertures + * filled in by Kernel + */ + __u64 kfd_process_device_apertures_ptr; + /* to KFD - indicates amount of memory present in + * kfd_process_device_apertures_ptr + * from KFD - Number of entries filled by KFD. + */ + __u32 num_of_nodes; + __u32 pad; +}; + +#define MAX_ALLOWED_NUM_POINTS 100 +#define MAX_ALLOWED_AW_BUFF_SIZE 4096 +#define MAX_ALLOWED_WAC_BUFF_SIZE 128 + +struct kfd_ioctl_dbg_register_args { + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_dbg_unregister_args { + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_dbg_address_watch_args { + __u64 content_ptr; /* a pointer to the actual content */ + __u32 gpu_id; /* to KFD */ + __u32 buf_size_in_bytes; /*including gpu_id and buf_size */ +}; + +struct kfd_ioctl_dbg_wave_control_args { + __u64 content_ptr; /* a pointer to the actual content */ + __u32 gpu_id; /* to KFD */ + __u32 buf_size_in_bytes; /*including gpu_id and buf_size */ +}; + +/* Matching HSA_EVENTTYPE */ +#define KFD_IOC_EVENT_SIGNAL 0 +#define KFD_IOC_EVENT_NODECHANGE 1 +#define KFD_IOC_EVENT_DEVICESTATECHANGE 2 +#define KFD_IOC_EVENT_HW_EXCEPTION 3 +#define KFD_IOC_EVENT_SYSTEM_EVENT 4 +#define KFD_IOC_EVENT_DEBUG_EVENT 5 +#define KFD_IOC_EVENT_PROFILE_EVENT 6 +#define KFD_IOC_EVENT_QUEUE_EVENT 7 +#define KFD_IOC_EVENT_MEMORY 8 + +#define KFD_IOC_WAIT_RESULT_COMPLETE 0 +#define KFD_IOC_WAIT_RESULT_TIMEOUT 1 +#define KFD_IOC_WAIT_RESULT_FAIL 2 + +#define KFD_SIGNAL_EVENT_LIMIT 4096 + +/* For kfd_event_data.hw_exception_data.reset_type. */ +#define KFD_HW_EXCEPTION_WHOLE_GPU_RESET 0 +#define KFD_HW_EXCEPTION_PER_ENGINE_RESET 1 + +/* For kfd_event_data.hw_exception_data.reset_cause. */ +#define KFD_HW_EXCEPTION_GPU_HANG 0 +#define KFD_HW_EXCEPTION_ECC 1 + +/* For kfd_hsa_memory_exception_data.ErrorType */ +#define KFD_MEM_ERR_NO_RAS 0 +#define KFD_MEM_ERR_SRAM_ECC 1 +#define KFD_MEM_ERR_POISON_CONSUMED 2 +#define KFD_MEM_ERR_GPU_HANG 3 + +struct kfd_ioctl_create_event_args { + __u64 event_page_offset; /* from KFD */ + __u32 event_trigger_data; /* from KFD - signal events only */ + __u32 event_type; /* to KFD */ + __u32 auto_reset; /* to KFD */ + __u32 node_id; /* to KFD - only valid for certain + event types */ + __u32 event_id; /* from KFD */ + __u32 event_slot_index; /* from KFD */ +}; + +struct kfd_ioctl_destroy_event_args { + __u32 event_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_set_event_args { + __u32 event_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_reset_event_args { + __u32 event_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_memory_exception_failure { + __u32 NotPresent; /* Page not present or supervisor privilege */ + __u32 ReadOnly; /* Write access to a read-only page */ + __u32 NoExecute; /* Execute access to a page marked NX */ + __u32 imprecise; /* Can't determine the exact fault address */ +}; + +/* memory exception data*/ +struct kfd_hsa_memory_exception_data { + struct kfd_memory_exception_failure failure; + __u64 va; + __u32 gpu_id; + __u32 ErrorType; /* 0 = no RAS error, + * 1 = ECC_SRAM, + * 2 = Link_SYNFLOOD (poison), + * 3 = GPU hang (not attributable to a specific cause), + * other values reserved + */ +}; + +/* hw exception data */ +struct kfd_hsa_hw_exception_data { + __u32 reset_type; + __u32 reset_cause; + __u32 memory_lost; + __u32 gpu_id; +}; + +/* Event data */ +struct kfd_event_data { + union { + struct kfd_hsa_memory_exception_data memory_exception_data; + struct kfd_hsa_hw_exception_data hw_exception_data; + }; /* From KFD */ + __u64 kfd_event_data_ext; /* pointer to an extension structure + for future exception types */ + __u32 event_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_wait_events_args { + __u64 events_ptr; /* pointed to struct + kfd_event_data array, to KFD */ + __u32 num_events; /* to KFD */ + __u32 wait_for_all; /* to KFD */ + __u32 timeout; /* to KFD */ + __u32 wait_result; /* from KFD */ +}; + +struct kfd_ioctl_set_scratch_backing_va_args { + __u64 va_addr; /* to KFD */ + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_get_tile_config_args { + /* to KFD: pointer to tile array */ + __u64 tile_config_ptr; + /* to KFD: pointer to macro tile array */ + __u64 macro_tile_config_ptr; + /* to KFD: array size allocated by user mode + * from KFD: array size filled by kernel + */ + __u32 num_tile_configs; + /* to KFD: array size allocated by user mode + * from KFD: array size filled by kernel + */ + __u32 num_macro_tile_configs; + + __u32 gpu_id; /* to KFD */ + __u32 gb_addr_config; /* from KFD */ + __u32 num_banks; /* from KFD */ + __u32 num_ranks; /* from KFD */ + /* struct size can be extended later if needed + * without breaking ABI compatibility + */ +}; + +struct kfd_ioctl_set_trap_handler_args { + __u64 tba_addr; /* to KFD */ + __u64 tma_addr; /* to KFD */ + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + +struct kfd_ioctl_acquire_vm_args { + __u32 drm_fd; /* to KFD */ + __u32 gpu_id; /* to KFD */ +}; + +/* Allocation flags: memory types */ +#define KFD_IOC_ALLOC_MEM_FLAGS_VRAM (1 << 0) +#define KFD_IOC_ALLOC_MEM_FLAGS_GTT (1 << 1) +#define KFD_IOC_ALLOC_MEM_FLAGS_USERPTR (1 << 2) +#define KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL (1 << 3) +#define KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP (1 << 4) +/* Allocation flags: attributes/access options */ +#define KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE (1 << 31) +#define KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE (1 << 30) +#define KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC (1 << 29) +#define KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE (1 << 28) +#define KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM (1 << 27) +#define KFD_IOC_ALLOC_MEM_FLAGS_COHERENT (1 << 26) + +/* Allocate memory for later SVM (shared virtual memory) mapping. + * + * @va_addr: virtual address of the memory to be allocated + * all later mappings on all GPUs will use this address + * @size: size in bytes + * @handle: buffer handle returned to user mode, used to refer to + * this allocation for mapping, unmapping and freeing + * @mmap_offset: for CPU-mapping the allocation by mmapping a render node + * for userptrs this is overloaded to specify the CPU address + * @gpu_id: device identifier + * @flags: memory type and attributes. See KFD_IOC_ALLOC_MEM_FLAGS above + */ +struct kfd_ioctl_alloc_memory_of_gpu_args { + __u64 va_addr; /* to KFD */ + __u64 size; /* to KFD */ + __u64 handle; /* from KFD */ + __u64 mmap_offset; /* to KFD (userptr), from KFD (mmap offset) */ + __u32 gpu_id; /* to KFD */ + __u32 flags; +}; + +/* Free memory allocated with kfd_ioctl_alloc_memory_of_gpu + * + * @handle: memory handle returned by alloc + */ +struct kfd_ioctl_free_memory_of_gpu_args { + __u64 handle; /* to KFD */ +}; + +/* Map memory to one or more GPUs + * + * @handle: memory handle returned by alloc + * @device_ids_array_ptr: array of gpu_ids (__u32 per device) + * @n_devices: number of devices in the array + * @n_success: number of devices mapped successfully + * + * @n_success returns information to the caller how many devices from + * the start of the array have mapped the buffer successfully. It can + * be passed into a subsequent retry call to skip those devices. For + * the first call the caller should initialize it to 0. + * + * If the ioctl completes with return code 0 (success), n_success == + * n_devices. + */ +struct kfd_ioctl_map_memory_to_gpu_args { + __u64 handle; /* to KFD */ + __u64 device_ids_array_ptr; /* to KFD */ + __u32 n_devices; /* to KFD */ + __u32 n_success; /* to/from KFD */ +}; + +/* Unmap memory from one or more GPUs + * + * same arguments as for mapping + */ +struct kfd_ioctl_unmap_memory_from_gpu_args { + __u64 handle; /* to KFD */ + __u64 device_ids_array_ptr; /* to KFD */ + __u32 n_devices; /* to KFD */ + __u32 n_success; /* to/from KFD */ +}; + +struct kfd_ioctl_get_dmabuf_info_args { + __u64 size; /* from KFD */ + __u64 metadata_ptr; /* to KFD */ + __u32 metadata_size; /* to KFD (space allocated by user) + * from KFD (actual metadata size) + */ + __u32 gpu_id; /* from KFD */ + __u32 flags; /* from KFD (KFD_IOC_ALLOC_MEM_FLAGS) */ + __u32 dmabuf_fd; /* to KFD */ +}; + +struct kfd_ioctl_import_dmabuf_args { + __u64 va_addr; /* to KFD */ + __u64 handle; /* from KFD */ + __u32 gpu_id; /* to KFD */ + __u32 dmabuf_fd; /* to KFD */ +}; + +/* Register offset inside the remapped mmio page + */ +enum kfd_mmio_remap { + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL = 0, + KFD_MMIO_REMAP_HDP_REG_FLUSH_CNTL = 4, +}; + +#define AMDKFD_IOCTL_BASE 'K' +#define AMDKFD_IO(nr) _IO(AMDKFD_IOCTL_BASE, nr) +#define AMDKFD_IOR(nr, type) _IOR(AMDKFD_IOCTL_BASE, nr, type) +#define AMDKFD_IOW(nr, type) _IOW(AMDKFD_IOCTL_BASE, nr, type) +#define AMDKFD_IOWR(nr, type) _IOWR(AMDKFD_IOCTL_BASE, nr, type) + +#define AMDKFD_IOC_GET_VERSION \ + AMDKFD_IOR(0x01, struct kfd_ioctl_get_version_args) + +#define AMDKFD_IOC_CREATE_QUEUE \ + AMDKFD_IOWR(0x02, struct kfd_ioctl_create_queue_args) + +#define AMDKFD_IOC_DESTROY_QUEUE \ + AMDKFD_IOWR(0x03, struct kfd_ioctl_destroy_queue_args) + +#define AMDKFD_IOC_SET_MEMORY_POLICY \ + AMDKFD_IOW(0x04, struct kfd_ioctl_set_memory_policy_args) + +#define AMDKFD_IOC_GET_CLOCK_COUNTERS \ + AMDKFD_IOWR(0x05, struct kfd_ioctl_get_clock_counters_args) + +#define AMDKFD_IOC_GET_PROCESS_APERTURES \ + AMDKFD_IOR(0x06, struct kfd_ioctl_get_process_apertures_args) + +#define AMDKFD_IOC_UPDATE_QUEUE \ + AMDKFD_IOW(0x07, struct kfd_ioctl_update_queue_args) + +#define AMDKFD_IOC_CREATE_EVENT \ + AMDKFD_IOWR(0x08, struct kfd_ioctl_create_event_args) + +#define AMDKFD_IOC_DESTROY_EVENT \ + AMDKFD_IOW(0x09, struct kfd_ioctl_destroy_event_args) + +#define AMDKFD_IOC_SET_EVENT \ + AMDKFD_IOW(0x0A, struct kfd_ioctl_set_event_args) + +#define AMDKFD_IOC_RESET_EVENT \ + AMDKFD_IOW(0x0B, struct kfd_ioctl_reset_event_args) + +#define AMDKFD_IOC_WAIT_EVENTS \ + AMDKFD_IOWR(0x0C, struct kfd_ioctl_wait_events_args) + +#define AMDKFD_IOC_DBG_REGISTER \ + AMDKFD_IOW(0x0D, struct kfd_ioctl_dbg_register_args) + +#define AMDKFD_IOC_DBG_UNREGISTER \ + AMDKFD_IOW(0x0E, struct kfd_ioctl_dbg_unregister_args) + +#define AMDKFD_IOC_DBG_ADDRESS_WATCH \ + AMDKFD_IOW(0x0F, struct kfd_ioctl_dbg_address_watch_args) + +#define AMDKFD_IOC_DBG_WAVE_CONTROL \ + AMDKFD_IOW(0x10, struct kfd_ioctl_dbg_wave_control_args) + +#define AMDKFD_IOC_SET_SCRATCH_BACKING_VA \ + AMDKFD_IOWR(0x11, struct kfd_ioctl_set_scratch_backing_va_args) + +#define AMDKFD_IOC_GET_TILE_CONFIG \ + AMDKFD_IOWR(0x12, struct kfd_ioctl_get_tile_config_args) + +#define AMDKFD_IOC_SET_TRAP_HANDLER \ + AMDKFD_IOW(0x13, struct kfd_ioctl_set_trap_handler_args) + +#define AMDKFD_IOC_GET_PROCESS_APERTURES_NEW \ + AMDKFD_IOWR(0x14, \ + struct kfd_ioctl_get_process_apertures_new_args) + +#define AMDKFD_IOC_ACQUIRE_VM \ + AMDKFD_IOW(0x15, struct kfd_ioctl_acquire_vm_args) + +#define AMDKFD_IOC_ALLOC_MEMORY_OF_GPU \ + AMDKFD_IOWR(0x16, struct kfd_ioctl_alloc_memory_of_gpu_args) + +#define AMDKFD_IOC_FREE_MEMORY_OF_GPU \ + AMDKFD_IOW(0x17, struct kfd_ioctl_free_memory_of_gpu_args) + +#define AMDKFD_IOC_MAP_MEMORY_TO_GPU \ + AMDKFD_IOWR(0x18, struct kfd_ioctl_map_memory_to_gpu_args) + +#define AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU \ + AMDKFD_IOWR(0x19, struct kfd_ioctl_unmap_memory_from_gpu_args) + +#define AMDKFD_IOC_SET_CU_MASK \ + AMDKFD_IOW(0x1A, struct kfd_ioctl_set_cu_mask_args) + +#define AMDKFD_IOC_GET_QUEUE_WAVE_STATE \ + AMDKFD_IOWR(0x1B, struct kfd_ioctl_get_queue_wave_state_args) + +#define AMDKFD_IOC_GET_DMABUF_INFO \ + AMDKFD_IOWR(0x1C, struct kfd_ioctl_get_dmabuf_info_args) + +#define AMDKFD_IOC_IMPORT_DMABUF \ + AMDKFD_IOWR(0x1D, struct kfd_ioctl_import_dmabuf_args) + +#define AMDKFD_COMMAND_START 0x01 +#define AMDKFD_COMMAND_END 0x1E + +#endif diff --git a/sys/dev/pci/drm/include/video/mipi_display.h b/sys/dev/pci/drm/include/video/mipi_display.h index 7b303a62f81..1e54e64ced8 100644 --- a/sys/dev/pci/drm/include/video/mipi_display.h +++ b/sys/dev/pci/drm/include/video/mipi_display.h @@ -7,6 +7,8 @@ #define MIPI_DSI_V_SYNC_END 0x11 #define MIPI_DSI_H_SYNC_START 0x21 #define MIPI_DSI_H_SYNC_END 0x31 +#define MIPI_DSI_COMPRESSION_MODE 0x07 +#define MIPI_DSI_END_OF_TRANSMISSION 0x08 #define MIPI_DSI_COLOR_MODE_OFF 0x02 #define MIPI_DSI_COLOR_MODE_ON 0x12 #define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22 @@ -20,14 +22,14 @@ #define MIPI_DSI_DCS_SHORT_WRITE 0x05 #define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15 #define MIPI_DSI_DCS_READ 0x06 -#define MIPI_DSI_DCS_COMPRESSION_MODE 0x07 -#define MIPI_DSI_PPS_LONG_WRITE 0x0a +#define MIPI_DSI_EXECUTE_QUEUE 0x16 #define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37 -#define MIPI_DSI_END_OF_TRANSMISSION 0x08 #define MIPI_DSI_NULL_PACKET 0x09 #define MIPI_DSI_BLANKING_PACKET 0x19 #define MIPI_DSI_GENERIC_LONG_WRITE 0x29 #define MIPI_DSI_DCS_LONG_WRITE 0x39 +#define MIPI_DSI_PICTURE_PARAMETER_SET 0x0a +#define MIPI_DSI_COMPRESSED_PIXEL_STREAM 0x0b #define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0c #define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1c #define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2c |