From 75ae95a75d640129fc4aff412c6ecc057142a149 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 1 Sep 2016 14:48:32 +0200 Subject: drm: remove redundant drm_file->uid Each DRM file-context caches the EUID of the process that opened the file. It is used exclusively for debugging purposes in /proc/dri/ and friends. Note, however, that we can already fetch the EUID from priv->pid->task->creds. The pointer-chasing will not hurt us, since it is only about debugging, anyway. Since we already are in an rcu-read-side, we can use __task_cred() rather than task_cred_xxx(). Signed-off-by: David Herrmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160901124837.680-2-dh.herrmann@gmail.com --- include/drm/drmP.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 94eb138753a9..14f191f0172c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -379,7 +379,6 @@ struct drm_file { unsigned is_master:1; struct pid *pid; - kuid_t uid; drm_magic_t magic; struct list_head lhead; struct drm_minor *minor; -- cgit v1.2.3 From d9a1f0b4eb6080dc42bb6373ab9abb0314cea41e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 1 Sep 2016 14:48:33 +0200 Subject: drm: use drm_file to tag vm-bos Rather than using "struct file*", use "struct drm_file*" as tag VM tag for BOs. This will pave the way for "struct drm_file*" without any "struct file*" back-pointer. Signed-off-by: David Herrmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160901124837.680-3-dh.herrmann@gmail.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 ++- drivers/gpu/drm/ast/ast_ttm.c | 3 ++- drivers/gpu/drm/bochs/bochs_mm.c | 3 ++- drivers/gpu/drm/cirrus/cirrus_ttm.c | 3 ++- drivers/gpu/drm/drm_gem.c | 8 +++---- drivers/gpu/drm/drm_vma_manager.c | 40 ++++++++++++++++----------------- drivers/gpu/drm/mgag200/mgag200_ttm.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 ++- drivers/gpu/drm/qxl/qxl_ttm.c | 3 ++- drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++- include/drm/drm_vma_manager.h | 20 +++++++++-------- 11 files changed, 51 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 5447973483ec..e36bfc47dceb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -226,7 +226,8 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) if (amdgpu_ttm_tt_get_usermm(bo->ttm)) return -EPERM; - return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&rbo->gem_base.vma_node, + filp->private_data); } static void amdgpu_move_null(struct ttm_buffer_object *bo, diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index b29a41218fc9..608df4c90520 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -150,7 +150,8 @@ static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct ast_bo *astbo = ast_bo(bo); - return drm_vma_node_verify_access(&astbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&astbo->gem.vma_node, + filp->private_data); } static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 5c5638a777a1..269cfca9ca06 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -128,7 +128,8 @@ static int bochs_bo_verify_access(struct ttm_buffer_object *bo, { struct bochs_bo *bochsbo = bochs_bo(bo); - return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&bochsbo->gem.vma_node, + filp->private_data); } static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 1cc9ee607128..bb2438dd8733 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -150,7 +150,8 @@ static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *fi { struct cirrus_bo *cirrusbo = cirrus_bo(bo); - return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&cirrusbo->gem.vma_node, + filp->private_data); } static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 9134ae134667..465bacd0a630 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -257,7 +257,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) if (drm_core_check_feature(dev, DRIVER_PRIME)) drm_gem_remove_prime_handles(obj, file_priv); - drm_vma_node_revoke(&obj->vma_node, file_priv->filp); + drm_vma_node_revoke(&obj->vma_node, file_priv); if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, file_priv); @@ -372,7 +372,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, handle = ret; - ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp); + ret = drm_vma_node_allow(&obj->vma_node, file_priv); if (ret) goto err_remove; @@ -386,7 +386,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, return 0; err_revoke: - drm_vma_node_revoke(&obj->vma_node, file_priv->filp); + drm_vma_node_revoke(&obj->vma_node, file_priv); err_remove: spin_lock(&file_priv->table_lock); idr_remove(&file_priv->object_idr, handle); @@ -991,7 +991,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) if (!obj) return -EINVAL; - if (!drm_vma_node_is_allowed(node, filp)) { + if (!drm_vma_node_is_allowed(node, priv)) { drm_gem_object_unreference_unlocked(obj); return -EACCES; } diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 0aef432679f9..20cc33d1bfc1 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -252,9 +251,9 @@ EXPORT_SYMBOL(drm_vma_offset_remove); /** * drm_vma_node_allow - Add open-file to list of allowed users * @node: Node to modify - * @filp: Open file to add + * @tag: Tag of file to remove * - * Add @filp to the list of allowed open-files for this node. If @filp is + * Add @tag to the list of allowed open-files for this node. If @tag is * already on this list, the ref-count is incremented. * * The list of allowed-users is preserved across drm_vma_offset_add() and @@ -269,7 +268,7 @@ EXPORT_SYMBOL(drm_vma_offset_remove); * RETURNS: * 0 on success, negative error code on internal failure (out-of-mem) */ -int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) +int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) { struct rb_node **iter; struct rb_node *parent = NULL; @@ -290,10 +289,10 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) parent = *iter; entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) { + if (tag == entry->vm_tag) { entry->vm_count++; goto unlock; - } else if (filp > entry->vm_filp) { + } else if (tag > entry->vm_tag) { iter = &(*iter)->rb_right; } else { iter = &(*iter)->rb_left; @@ -305,7 +304,7 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp) goto unlock; } - new->vm_filp = filp; + new->vm_tag = tag; new->vm_count = 1; rb_link_node(&new->vm_rb, parent, iter); rb_insert_color(&new->vm_rb, &node->vm_files); @@ -321,17 +320,18 @@ EXPORT_SYMBOL(drm_vma_node_allow); /** * drm_vma_node_revoke - Remove open-file from list of allowed users * @node: Node to modify - * @filp: Open file to remove + * @tag: Tag of file to remove * - * Decrement the ref-count of @filp in the list of allowed open-files on @node. - * If the ref-count drops to zero, remove @filp from the list. You must call - * this once for every drm_vma_node_allow() on @filp. + * Decrement the ref-count of @tag in the list of allowed open-files on @node. + * If the ref-count drops to zero, remove @tag from the list. You must call + * this once for every drm_vma_node_allow() on @tag. * * This is locked against concurrent access internally. * - * If @filp is not on the list, nothing is done. + * If @tag is not on the list, nothing is done. */ -void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) +void drm_vma_node_revoke(struct drm_vma_offset_node *node, + struct drm_file *tag) { struct drm_vma_offset_file *entry; struct rb_node *iter; @@ -341,13 +341,13 @@ void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp) iter = node->vm_files.rb_node; while (likely(iter)) { entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) { + if (tag == entry->vm_tag) { if (!--entry->vm_count) { rb_erase(&entry->vm_rb, &node->vm_files); kfree(entry); } break; - } else if (filp > entry->vm_filp) { + } else if (tag > entry->vm_tag) { iter = iter->rb_right; } else { iter = iter->rb_left; @@ -361,9 +361,9 @@ EXPORT_SYMBOL(drm_vma_node_revoke); /** * drm_vma_node_is_allowed - Check whether an open-file is granted access * @node: Node to check - * @filp: Open-file to check for + * @tag: Tag of file to remove * - * Search the list in @node whether @filp is currently on the list of allowed + * Search the list in @node whether @tag is currently on the list of allowed * open-files (see drm_vma_node_allow()). * * This is locked against concurrent access internally. @@ -372,7 +372,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke); * true iff @filp is on the list */ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, - struct file *filp) + struct drm_file *tag) { struct drm_vma_offset_file *entry; struct rb_node *iter; @@ -382,9 +382,9 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, iter = node->vm_files.rb_node; while (likely(iter)) { entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); - if (filp == entry->vm_filp) + if (tag == entry->vm_tag) break; - else if (filp > entry->vm_filp) + else if (tag > entry->vm_tag) iter = iter->rb_right; else iter = iter->rb_left; diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 68268e55d595..919b35f2ad24 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -150,7 +150,8 @@ static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *f { struct mgag200_bo *mgabo = mgag200_bo(bo); - return drm_vma_node_verify_access(&mgabo->gem.vma_node, filp); + return drm_vma_node_verify_access(&mgabo->gem.vma_node, + filp->private_data); } static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 8ab9ce5089fe..66f31c3eb8ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1315,7 +1315,8 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct nouveau_bo *nvbo = nouveau_bo(bo); - return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); + return drm_vma_node_verify_access(&nvbo->gem.vma_node, + filp->private_data); } static int diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 6a22de045cb5..b2fe2f8e6ae9 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -210,7 +210,8 @@ static int qxl_verify_access(struct ttm_buffer_object *bo, struct file *filp) { struct qxl_bo *qbo = to_qxl_bo(bo); - return drm_vma_node_verify_access(&qbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&qbo->gem_base.vma_node, + filp->private_data); } static int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 93414aca60d6..27ee0ab0e1a7 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -237,7 +237,8 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) if (radeon_ttm_tt_has_userptr(bo->ttm)) return -EPERM; - return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); + return drm_vma_node_verify_access(&rbo->gem_base.vma_node, + filp->private_data); } static void radeon_move_null(struct ttm_buffer_object *bo, diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h index afba6fcac853..9c03895dc479 100644 --- a/include/drm/drm_vma_manager.h +++ b/include/drm/drm_vma_manager.h @@ -24,16 +24,17 @@ */ #include -#include #include #include #include #include #include +struct drm_file; + struct drm_vma_offset_file { struct rb_node vm_rb; - struct file *vm_filp; + struct drm_file *vm_tag; unsigned long vm_count; }; @@ -60,10 +61,11 @@ int drm_vma_offset_add(struct drm_vma_offset_manager *mgr, void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, struct drm_vma_offset_node *node); -int drm_vma_node_allow(struct drm_vma_offset_node *node, struct file *filp); -void drm_vma_node_revoke(struct drm_vma_offset_node *node, struct file *filp); +int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag); +void drm_vma_node_revoke(struct drm_vma_offset_node *node, + struct drm_file *tag); bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, - struct file *filp); + struct drm_file *tag); /** * drm_vma_offset_exact_lookup_locked() - Look up node by exact address @@ -214,9 +216,9 @@ static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, /** * drm_vma_node_verify_access() - Access verification helper for TTM * @node: Offset node - * @filp: Open-file + * @tag: Tag of file to check * - * This checks whether @filp is granted access to @node. It is the same as + * This checks whether @tag is granted access to @node. It is the same as * drm_vma_node_is_allowed() but suitable as drop-in helper for TTM * verify_access() callbacks. * @@ -224,9 +226,9 @@ static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, * 0 if access is granted, -EACCES otherwise. */ static inline int drm_vma_node_verify_access(struct drm_vma_offset_node *node, - struct file *filp) + struct drm_file *tag) { - return drm_vma_node_is_allowed(node, filp) ? 0 : -EACCES; + return drm_vma_node_is_allowed(node, tag) ? 0 : -EACCES; } #endif /* __DRM_VMA_MANAGER_H__ */ -- cgit v1.2.3 From 82d5e73f6b7955867fc86314430bf923ab9cc485 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 1 Sep 2016 14:48:36 +0200 Subject: drm: drop obsolete drm_core.h The drm_core.h header contains a set of constants meant to be used throughout DRM. However, as it turns out, they're each used just once and don't bring any benefit. They're also grossly mis-named and lack name-spacing. This patch inlines them, or moves them into drm_internal.h as appropriate: - CORE_AUTHOR and CORE_DESC are inlined into corresponding MODULE_*() macros. It's just confusing having to follow 2 pointers when trying to find the definition of these fields. Grep'ping for MODULE_AUTHOR() should reveal the full information, if there's no strong reason not to. - CORE_NAME, CORE_DATE, CORE_MAJOR, CORE_MINOR, and CORE_PATCHLEVEL are inlined into the sysfs 'version' attribute. They're stripped everywhere else (which is just some printk() statements). CORE_NAME just doesn't make *any* sense, as we hard-code it in many places, anyway. The other constants are outdated and just serve binary-compatibility purposes. Hence, inline them in 'version' sysfs attribute (we might even try dropping it..). - DRM_IF_MAJOR and DRM_IF_MINOR are moved into drm_internal.h as they're only used by the global ioctl handlers. Furthermore, versioning interfaces breaks backports and as such is deprecated, anyway. We just keep them for historic reasons. I doubt anyone will ever modify them again. Signed-off-by: David Herrmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160901124837.680-6-dh.herrmann@gmail.com --- drivers/gpu/drm/drm_drv.c | 8 +++----- drivers/gpu/drm/drm_internal.h | 3 +++ drivers/gpu/drm/drm_ioc32.c | 1 - drivers/gpu/drm/drm_ioctl.c | 1 - drivers/gpu/drm/drm_sysfs.c | 8 +------- include/drm/drm_core.h | 34 ---------------------------------- 6 files changed, 7 insertions(+), 48 deletions(-) delete mode 100644 include/drm/drm_core.h (limited to 'include') diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index acf6a5f38920..bcd54d4eb336 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "drm_crtc_internal.h" #include "drm_legacy.h" #include "drm_internal.h" @@ -46,8 +45,8 @@ unsigned int drm_debug = 0; EXPORT_SYMBOL(drm_debug); -MODULE_AUTHOR(CORE_AUTHOR); -MODULE_DESCRIPTION(CORE_DESC); +MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); +MODULE_DESCRIPTION("DRM shared core routines"); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" @@ -845,8 +844,7 @@ static int __init drm_core_init(void) goto err_p3; } - DRM_INFO("Initialized %s %d.%d.%d %s\n", - CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); + DRM_INFO("Initialized\n"); return 0; err_p3: drm_sysfs_destroy(); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b86dc9b921a5..e66af289a016 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -21,6 +21,9 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#define DRM_IF_MAJOR 1 +#define DRM_IF_MINOR 4 + /* drm_irq.c */ extern unsigned int drm_timestamp_monotonic; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 5f896e723f73..867ab8c1582b 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -32,7 +32,6 @@ #include #include -#include #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index b97c421c65f4..0ad2c47f808f 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -29,7 +29,6 @@ */ #include -#include #include #include "drm_legacy.h" #include "drm_internal.h" diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 32dd821b7202..9a37196c1bf1 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -19,7 +19,6 @@ #include #include -#include #include #include "drm_internal.h" @@ -37,12 +36,7 @@ static char *drm_devnode(struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } -static CLASS_ATTR_STRING(version, S_IRUGO, - CORE_NAME " " - __stringify(CORE_MAJOR) "." - __stringify(CORE_MINOR) "." - __stringify(CORE_PATCHLEVEL) " " - CORE_DATE); +static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810"); /** * drm_sysfs_init - initialize sysfs helpers diff --git a/include/drm/drm_core.h b/include/drm/drm_core.h deleted file mode 100644 index 4e7523863a4b..000000000000 --- a/include/drm/drm_core.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2004 Jon Smirl - * - * 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 - * VIA, S3 GRAPHICS, 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. - */ -#define CORE_AUTHOR "Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl" - -#define CORE_NAME "drm" -#define CORE_DESC "DRM shared core routines" -#define CORE_DATE "20060810" - -#define DRM_IF_MAJOR 1 -#define DRM_IF_MINOR 4 - -#define CORE_MAJOR 1 -#define CORE_MINOR 1 -#define CORE_PATCHLEVEL 0 -- cgit v1.2.3 From afb21ea63d815d05f6081ee3efef6772a16317eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 31 Aug 2016 18:09:04 +0200 Subject: drm: Move a few macros away from drm_crtc.h Now that there's less stuff in there I noticed that I overlooked them. Sprinkle some docs over them while at it. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160831160913.12991-2-daniel.vetter@ffwll.ch --- include/drm/drm_connector.h | 24 ++++++++++++++++++++++-- include/drm/drm_crtc.h | 32 -------------------------------- include/drm/drm_encoder.h | 22 ++++++++++++++++++++++ include/drm/drm_framebuffer.h | 17 +++++++++++++++++ include/drm/drm_modes.h | 2 ++ include/drm/drm_property.h | 1 + 6 files changed, 64 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 66b7d6744dd2..e4e545e9516d 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -181,14 +181,19 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, /** * struct drm_connector_state - mutable connector state * @connector: backpointer to the connector - * @crtc: CRTC to connect connector to, NULL if disabled * @best_encoder: can be used by helpers and drivers to select the encoder * @state: backpointer to global drm_atomic_state */ struct drm_connector_state { struct drm_connector *connector; - struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */ + /** + * @crtc: CRTC to connect connector to, NULL if disabled. + * + * Do not change this directly, use drm_atomic_set_crtc_for_connector() + * instead. + */ + struct drm_crtc *crtc; struct drm_encoder *best_encoder; @@ -744,4 +749,19 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, int drm_mode_connector_set_tile_property(struct drm_connector *connector); int drm_mode_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); + +/** + * drm_for_each_connector - iterate over all connectors + * @connector: the loop cursor + * @dev: the DRM device + * + * Iterate over all connectors of @dev. + */ +#define drm_for_each_connector(connector, dev) \ + for (assert_drm_connector_list_read_locked(&(dev)->mode_config), \ + connector = list_first_entry(&(dev)->mode_config.connector_list, \ + struct drm_connector, head); \ + &connector->head != (&(dev)->mode_config.connector_list); \ + connector = list_next_entry(connector, head)) + #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8ca71d66282b..749d3b2017fd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2003,22 +2003,7 @@ struct drm_mode_config { list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) -/** - * drm_for_each_encoder_mask - iterate over encoders specified by bitmask - * @encoder: the loop cursor - * @dev: the DRM device - * @encoder_mask: bitmask of encoder indices - * - * Iterate over all encoders specified by bitmask. - */ -#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \ - list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \ - for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) - #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) -#define obj_to_mode(x) container_of(x, struct drm_display_mode, base) -#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) -#define obj_to_blob(x) container_of(x, struct drm_property_blob, base) #define obj_to_plane(x) container_of(x, struct drm_plane, base) extern __printf(6, 7) @@ -2186,23 +2171,6 @@ assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config) !drm_modeset_is_locked(&mode_config->connection_mutex)); } -#define drm_for_each_connector(connector, dev) \ - for (assert_drm_connector_list_read_locked(&(dev)->mode_config), \ - connector = list_first_entry(&(dev)->mode_config.connector_list, \ - struct drm_connector, head); \ - &connector->head != (&(dev)->mode_config.connector_list); \ - connector = list_next_entry(connector, head)) - -#define drm_for_each_encoder(encoder, dev) \ - list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) - -#define drm_for_each_fb(fb, dev) \ - for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)), \ - fb = list_first_entry(&(dev)->mode_config.fb_list, \ - struct drm_framebuffer, head); \ - &fb->head != (&(dev)->mode_config.fb_list); \ - fb = list_next_entry(fb, head)) - /* drm_edid.c */ bool drm_probe_ddc(struct i2c_adapter *adapter); struct edid *drm_get_edid(struct drm_connector *connector, diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index fce0203094f7..387e33a4d6ee 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -224,4 +224,26 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, void drm_encoder_cleanup(struct drm_encoder *encoder); +/** + * drm_for_each_encoder_mask - iterate over encoders specified by bitmask + * @encoder: the loop cursor + * @dev: the DRM device + * @encoder_mask: bitmask of encoder indices + * + * Iterate over all encoders specified by bitmask. + */ +#define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \ + list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \ + for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) + +/** + * drm_for_each_encoder - iterate over all encoders + * @encoder: the loop cursor + * @dev: the DRM device + * + * Iterate over all encoders of @dev. + */ +#define drm_for_each_encoder(encoder, dev) \ + list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) + #endif diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index b2554c50a903..f5ae1f436a4b 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -206,6 +206,8 @@ struct drm_framebuffer { struct list_head filp_head; }; +#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) + int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs); @@ -247,4 +249,19 @@ static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) { return atomic_read(&fb->base.refcount.refcount); } + +/** + * drm_for_each_fb - iterate over all framebuffers + * @fb: the loop cursor + * @dev: the DRM device + * + * Iterate over all framebuffers of @dev. User must hold the fb_lock from + * &drm_mode_config. + */ +#define drm_for_each_fb(fb, dev) \ + for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)), \ + fb = list_first_entry(&(dev)->mode_config.fb_list, \ + struct drm_framebuffer, head); \ + &fb->head != (&(dev)->mode_config.fb_list); \ + fb = list_next_entry(fb, head)) #endif diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 011f199d3bcf..986ed6ff635a 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -403,6 +403,8 @@ struct drm_display_mode { enum hdmi_picture_aspect picture_aspect_ratio; }; +#define obj_to_mode(x) container_of(x, struct drm_display_mode, base) + /** * drm_mode_is_stereo - check for stereo mode flags * @mode: drm_display_mode to check diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 30ab289be05d..43c4b6a2046d 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -219,6 +219,7 @@ struct drm_prop_enum_list { }; #define obj_to_property(x) container_of(x, struct drm_property, base) +#define obj_to_blob(x) container_of(x, struct drm_property_blob, base) /** * drm_property_type_is - check the type of a property -- cgit v1.2.3 From 199e4e967af476bdcab96c76237e6a1f9244d6ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 31 Aug 2016 18:09:05 +0200 Subject: drm: Extract drm_bridge.h We don't want to burry the bridge structures kerneldoc in drm_crtc.h. Cc: Archit Taneja Reviewed-by: Archit Taneja Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160831160913.12991-3-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 7 ++ drivers/gpu/drm/drm_bridge.c | 5 +- include/drm/drm_bridge.h | 218 ++++++++++++++++++++++++++++++++++ include/drm/drm_connector.h | 4 + include/drm/drm_crtc.h | 187 +---------------------------- include/drm/drm_mode_object.h | 1 + include/drm/drm_modes.h | 4 + 7 files changed, 237 insertions(+), 189 deletions(-) create mode 100644 include/drm/drm_bridge.h (limited to 'include') diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 59fa3c11efab..48fc5a96bf95 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -126,6 +126,13 @@ Default bridge callback sequence .. kernel-doc:: drivers/gpu/drm/drm_bridge.c :doc: bridge callbacks + +Bridge Helper Reference +------------------------- + +.. kernel-doc:: include/drm/drm_bridge.h + :internal: + .. kernel-doc:: drivers/gpu/drm/drm_bridge.c :export: diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 484046664d6c..0ee052b7c21a 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -23,10 +23,9 @@ #include #include +#include -#include - -#include "drm/drmP.h" +#include /** * DOC: overview diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h new file mode 100644 index 000000000000..530a1d6e8cde --- /dev/null +++ b/include/drm/drm_bridge.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_BRIDGE_H__ +#define __DRM_BRIDGE_H__ + +#include +#include +#include +#include + +struct drm_bridge; + +/** + * struct drm_bridge_funcs - drm_bridge control functions + */ +struct drm_bridge_funcs { + /** + * @attach: + * + * This callback is invoked whenever our bridge is being attached to a + * &drm_encoder. + * + * The attach callback is optional. + * + * RETURNS: + * + * Zero on success, error code on failure. + */ + int (*attach)(struct drm_bridge *bridge); + + /** + * @detach: + * + * This callback is invoked whenever our bridge is being detached from a + * &drm_encoder. + * + * The detach callback is optional. + */ + void (*detach)(struct drm_bridge *bridge); + + /** + * @mode_fixup: + * + * This callback is used to validate and adjust a mode. The paramater + * mode is the display mode that should be fed to the next element in + * the display chain, either the final &drm_connector or the next + * &drm_bridge. The parameter adjusted_mode is the input mode the bridge + * requires. It can be modified by this callback and does not need to + * match mode. + * + * This is the only hook that allows a bridge to reject a modeset. If + * this function passes all other callbacks must succeed for this + * configuration. + * + * The mode_fixup callback is optional. + * + * NOTE: + * + * This function is called in the check phase of atomic modesets, which + * can be aborted for any reason (including on userspace's request to + * just check whether a configuration would be possible). Drivers MUST + * NOT touch any persistent state (hardware or software) or data + * structures except the passed in @state parameter. + * + * RETURNS: + * + * True if an acceptable configuration is possible, false if the modeset + * operation should be rejected. + */ + bool (*mode_fixup)(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /** + * @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 ->disable() function. If the preceding element is a + * &drm_encoder it's called right before the encoder's ->disable(), + * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_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. + */ + void (*disable)(struct drm_bridge *bridge); + + /** + * @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 ->post_disable() function. If the preceding element is a + * &drm_encoder it's called right after the encoder's ->disable(), + * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs. + * + * The bridge must assume that the display pipe (i.e. clocks and timing + * singals) feeding it is no longer running when this callback is + * called. + * + * The post_disable callback is optional. + */ + void (*post_disable)(struct drm_bridge *bridge); + + /** + * @mode_set: + * + * This callback should set the given mode on the bridge. It is called + * after the ->mode_set() callback for the preceding element in the + * display pipeline has been called already. The display pipe (i.e. + * clocks and timing signals) is off when this function is called. + */ + void (*mode_set)(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /** + * @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 ->pre_enable() function. If the preceding element is a + * &drm_encoder it's called right before the encoder's ->enable(), + * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs. + * + * 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. + * + * The pre_enable callback is optional. + */ + void (*pre_enable)(struct drm_bridge *bridge); + + /** + * @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 ->enable() function. If the preceding element is a + * &drm_encoder it's called right after the encoder's ->enable(), + * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs. + * + * 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. + * + * The enable callback is optional. + */ + void (*enable)(struct drm_bridge *bridge); +}; + +/** + * struct drm_bridge - central DRM bridge control structure + * @dev: DRM device this bridge belongs to + * @encoder: encoder to which this bridge is connected + * @next: the next bridge in the encoder chain + * @of_node: device node pointer to the bridge + * @list: to keep track of all added bridges + * @funcs: control functions + * @driver_private: pointer to the bridge driver's internal context + */ +struct drm_bridge { + struct drm_device *dev; + struct drm_encoder *encoder; + struct drm_bridge *next; +#ifdef CONFIG_OF + struct device_node *of_node; +#endif + struct list_head list; + + const struct drm_bridge_funcs *funcs; + void *driver_private; +}; + +int 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_device *dev, struct drm_bridge *bridge); +void drm_bridge_detach(struct drm_bridge *bridge); + +bool drm_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_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); + +#endif diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e4e545e9516d..51a15deda161 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -27,6 +27,10 @@ #include #include +#include + +struct drm_device; + struct drm_connector_helper_funcs; struct drm_device; struct drm_crtc; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 749d3b2017fd..a2d1108c7c2c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -42,6 +42,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -1018,174 +1019,6 @@ struct drm_plane { struct drm_property *zpos_property; }; -/** - * struct drm_bridge_funcs - drm_bridge control functions - */ -struct drm_bridge_funcs { - /** - * @attach: - * - * This callback is invoked whenever our bridge is being attached to a - * &drm_encoder. - * - * The attach callback is optional. - * - * RETURNS: - * - * Zero on success, error code on failure. - */ - int (*attach)(struct drm_bridge *bridge); - - /** - * @detach: - * - * This callback is invoked whenever our bridge is being detached from a - * &drm_encoder. - * - * The detach callback is optional. - */ - void (*detach)(struct drm_bridge *bridge); - - /** - * @mode_fixup: - * - * This callback is used to validate and adjust a mode. The paramater - * mode is the display mode that should be fed to the next element in - * the display chain, either the final &drm_connector or the next - * &drm_bridge. The parameter adjusted_mode is the input mode the bridge - * requires. It can be modified by this callback and does not need to - * match mode. - * - * This is the only hook that allows a bridge to reject a modeset. If - * this function passes all other callbacks must succeed for this - * configuration. - * - * The mode_fixup callback is optional. - * - * NOTE: - * - * This function is called in the check phase of atomic modesets, which - * can be aborted for any reason (including on userspace's request to - * just check whether a configuration would be possible). Drivers MUST - * NOT touch any persistent state (hardware or software) or data - * structures except the passed in @state parameter. - * - * RETURNS: - * - * True if an acceptable configuration is possible, false if the modeset - * operation should be rejected. - */ - bool (*mode_fixup)(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - /** - * @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 ->disable() function. If the preceding element is a - * &drm_encoder it's called right before the encoder's ->disable(), - * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_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. - */ - void (*disable)(struct drm_bridge *bridge); - - /** - * @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 ->post_disable() function. If the preceding element is a - * &drm_encoder it's called right after the encoder's ->disable(), - * ->prepare() or ->dpms() hook from struct &drm_encoder_helper_funcs. - * - * The bridge must assume that the display pipe (i.e. clocks and timing - * singals) feeding it is no longer running when this callback is - * called. - * - * The post_disable callback is optional. - */ - void (*post_disable)(struct drm_bridge *bridge); - - /** - * @mode_set: - * - * This callback should set the given mode on the bridge. It is called - * after the ->mode_set() callback for the preceding element in the - * display pipeline has been called already. The display pipe (i.e. - * clocks and timing signals) is off when this function is called. - */ - void (*mode_set)(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - /** - * @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 ->pre_enable() function. If the preceding element is a - * &drm_encoder it's called right before the encoder's ->enable(), - * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs. - * - * 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. - * - * The pre_enable callback is optional. - */ - void (*pre_enable)(struct drm_bridge *bridge); - - /** - * @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 ->enable() function. If the preceding element is a - * &drm_encoder it's called right after the encoder's ->enable(), - * ->commit() or ->dpms() hook from struct &drm_encoder_helper_funcs. - * - * 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. - * - * The enable callback is optional. - */ - void (*enable)(struct drm_bridge *bridge); -}; - -/** - * struct drm_bridge - central DRM bridge control structure - * @dev: DRM device this bridge belongs to - * @encoder: encoder to which this bridge is connected - * @next: the next bridge in the encoder chain - * @of_node: device node pointer to the bridge - * @list: to keep track of all added bridges - * @funcs: control functions - * @driver_private: pointer to the bridge driver's internal context - */ -struct drm_bridge { - struct drm_device *dev; - struct drm_encoder *encoder; - struct drm_bridge *next; -#ifdef CONFIG_OF - struct device_node *of_node; -#endif - struct list_head list; - - const struct drm_bridge_funcs *funcs; - void *driver_private; -}; - /** * struct drm_crtc_commit - track modeset commits on a CRTC * @@ -2200,22 +2033,4 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, bool rb); -/* drm_bridge.c */ -extern int drm_bridge_add(struct drm_bridge *bridge); -extern void drm_bridge_remove(struct drm_bridge *bridge); -extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); -extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); -extern void drm_bridge_detach(struct drm_bridge *bridge); - -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_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); - #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index be3d93839ae2..43460b21d112 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -26,6 +26,7 @@ #include struct drm_object_properties; struct drm_property; +struct drm_device; /** * struct drm_mode_object - base structure for modeset objects diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 986ed6ff635a..9934d91619c1 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -27,9 +27,13 @@ #ifndef __DRM_MODES_H__ #define __DRM_MODES_H__ +#include + #include #include +struct videomode; + /* * Note on terminology: here, for brevity and convenience, we refer to connector * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, -- cgit v1.2.3 From cdc3d09fe2a9acd3f79049a70f89a4a8ef07d812 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 31 Aug 2016 18:09:06 +0200 Subject: drm: Move all decl for drm_edid.c to drm_edid.h Some were still left in drm_crtc.h. Also include drm_edid.h in the rst files. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160831160913.12991-4-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 3 +++ include/drm/drm_crtc.h | 30 +----------------------------- include/drm/drm_edid.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 48fc5a96bf95..bb4254d19cbb 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -208,6 +208,9 @@ Output Probing Helper Functions Reference EDID Helper Functions Reference =============================== +.. kernel-doc:: include/drm/drm_edid.h + :internal: + .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a2d1108c7c2c..35b13fc6bbc1 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -43,6 +43,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -2004,33 +2005,4 @@ assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config) !drm_modeset_is_locked(&mode_config->connection_mutex)); } -/* drm_edid.c */ -bool drm_probe_ddc(struct i2c_adapter *adapter); -struct edid *drm_get_edid(struct drm_connector *connector, - struct i2c_adapter *adapter); -struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, - struct i2c_adapter *adapter); -struct edid *drm_edid_duplicate(const struct edid *edid); -int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); - -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); -int drm_add_modes_noedid(struct drm_connector *connector, - int hdisplay, int vdisplay); -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref); - -int drm_edid_header_is_valid(const u8 *raw_edid); -bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, - bool *edid_corrupt); -bool drm_edid_is_valid(struct edid *edid); -void drm_edid_get_monitor_name(struct edid *edid, char *name, - int buflen); -struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, - int hsize, int vsize, int fresh, - bool rb); - #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 919933d1beb4..c3a7d440bc11 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -25,6 +25,9 @@ #include +struct drm_device; +struct i2c_adapter; + #define EDID_LENGTH 128 #define DDC_ADDR 0x50 #define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */ @@ -423,9 +426,36 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; } +bool drm_probe_ddc(struct i2c_adapter *adapter); struct edid *drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len), void *data); +struct edid *drm_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter); +struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, + struct i2c_adapter *adapter); +struct edid *drm_edid_duplicate(const struct edid *edid); +int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); + +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); +int drm_add_modes_noedid(struct drm_connector *connector, + int hdisplay, int vdisplay); +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref); + +int drm_edid_header_is_valid(const u8 *raw_edid); +bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, + bool *edid_corrupt); +bool drm_edid_is_valid(struct edid *edid); +void drm_edid_get_monitor_name(struct edid *edid, char *name, + int buflen); +struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, + int hsize, int vsize, int fresh, + bool rb); #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From 699fbeeac4668ba921a5f588736a56b332bd31c4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 19 Sep 2016 16:33:44 +0300 Subject: drm/fb-helper: Fix sparse warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm/drm_fb_helper.c:2306:12: warning: symbol 'drm_fb_helper_modinit' was not declared. Should it be static? While at it, move the lefover static inline to the right place. Cc: Daniel Vetter Cc: Sean Paul Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474292035-15695-4-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc_helper_internal.h | 7 +++++++ drivers/gpu/drm/drm_fb_helper.c | 2 ++ include/drm/drm_fb_helper.h | 5 ----- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc_helper_internal.h b/drivers/gpu/drm/drm_crtc_helper_internal.h index 4e6b57ae7188..28295e5d0d9e 100644 --- a/drivers/gpu/drm/drm_crtc_helper_internal.h +++ b/drivers/gpu/drm/drm_crtc_helper_internal.h @@ -29,7 +29,14 @@ #include /* drm_fb_helper.c */ +#ifdef CONFIG_DRM_FBDEV_EMULATION int drm_fb_helper_modinit(void); +#else +static inline int drm_fb_helper_modinit(void) +{ + return 0; +} +#endif /* drm_dp_aux_dev.c */ #ifdef CONFIG_DRM_DP_AUX_CHARDEV diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c4d350086def..5e830281bebd 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -41,6 +41,8 @@ #include #include +#include "drm_crtc_helper_internal.h" + static bool drm_fbdev_emulation = true; module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); MODULE_PARM_DESC(fbdev_emulation, diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 797fb5f80c45..e19458dd1a43 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -287,11 +287,6 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); #else -static inline int drm_fb_helper_modinit(void) -{ - return 0; -} - static inline void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, const struct drm_fb_helper_funcs *funcs) -- cgit v1.2.3 From 823d1bc1082970fc02f8172859c789933ed84bc5 Mon Sep 17 00:00:00 2001 From: Emilio López Date: Mon, 19 Sep 2016 01:21:20 -0300 Subject: dma-buf/sync_file: fix documentation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ioctl name and description on the documentation block don't match the ioctl being defined. This was probably overlooked while renaming the ioctls during the sync file destaging. This patch provides a more accurate description of what the ioctl actually does. Signed-off-by: Emilio López Reviewed-by: Gustavo Padovan Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160919042120.6280-1-emilio.lopez@collabora.co.uk --- include/uapi/linux/sync_file.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/sync_file.h b/include/uapi/linux/sync_file.h index 413303d37b56..5b287d6970b3 100644 --- a/include/uapi/linux/sync_file.h +++ b/include/uapi/linux/sync_file.h @@ -85,15 +85,12 @@ struct sync_file_info { #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) /** - * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence + * DOC: SYNC_IOC_FILE_INFO - get detailed information on a sync_file * - * Takes a struct sync_file_info_data with extra space allocated for pt_info. - * Caller should write the size of the buffer into len. On return, len is - * updated to reflect the total size of the sync_file_info_data including - * pt_info. - * - * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. - * To iterate over the sync_pt_infos, use the sync_pt_info.len field. + * Takes a struct sync_file_info. If num_fences is 0, the field is updated + * with the actual number of fences. If num_fences is > 0, the system will + * use the pointer provided on sync_fence_info to return up to num_fences of + * struct sync_fence_info, with detailed fence information. */ #define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info) -- cgit v1.2.3 From 43968d7b806d7a7e021261294c583a216fddf0e5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Sep 2016 10:59:24 +0200 Subject: drm: Extract drm_plane.[hc] Just pure code movement, cleanup and polish will happen in later patches. v2: Don't forget all the ioctl! To extract those cleanly I decided to put check_src_coords into drm_framebuffer.c (and give it a drm_framebuffer_ prefix), since that just checks framebuffer constraints. v3: rebase over PAGE_FLIP_TARGET. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter [seanpaul] This patch as posted on the list was rebased on: commit 6f00975c619064a18c23fd3aced325ae165a73b9 Author: Daniel Vetter Date: Sat Aug 20 12:22:11 2016 +0200 drm: Reject page_flip for !DRIVER_MODESET so as a result of moving the page_flip ioctl, this fix has been rolled into this patch. Signed-off-by: Sean Paul --- Documentation/gpu/drm-kms.rst | 12 + drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_crtc.c | 988 +---------------------------------- drivers/gpu/drm/drm_crtc_internal.h | 38 +- drivers/gpu/drm/drm_framebuffer.c | 26 + drivers/gpu/drm/drm_plane.c | 990 ++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 154 ++++++ include/drm/drm_crtc.h | 583 +-------------------- include/drm/drm_plane.h | 470 +++++++++++++++++ 9 files changed, 1681 insertions(+), 1583 deletions(-) create mode 100644 drivers/gpu/drm/drm_plane.c create mode 100644 include/drm/drm_plane.h (limited to 'include') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index f9a991bb87d4..33181be97151 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -110,6 +110,18 @@ Note that dumb objects may not be used for gpu acceleration, as has been attempted on some ARM embedded platforms. Such drivers really must have a hardware-specific ioctl to allocate suitable buffer objects. +Plane Abstraction +================= + +Plane Functions Reference +------------------------- + +.. kernel-doc:: include/drm/drm_plane.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_plane.c + :export: + Display Modes Function Reference ================================ diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 439d89b25ae0..8eeb07a35798 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -14,7 +14,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ - drm_encoder.o drm_mode_object.o drm_property.o + drm_encoder.o drm_mode_object.o drm_property.o \ + drm_plane.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 631691bae01d..deefb24649b2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -251,255 +251,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -static unsigned int drm_num_planes(struct drm_device *dev) -{ - unsigned int num = 0; - struct drm_plane *tmp; - - drm_for_each_plane(tmp, dev) { - num++; - } - - return num; -} - -/** - * drm_universal_plane_init - Initialize a new universal plane object - * @dev: DRM device - * @plane: plane object to init - * @possible_crtcs: bitmask of possible CRTCs - * @funcs: callbacks for the new plane - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @type: type of plane (overlay, primary, cursor) - * @name: printf style format string for the plane name, or NULL for default name - * - * Initializes a plane object of type @type. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - enum drm_plane_type type, - const char *name, ...) -{ - struct drm_mode_config *config = &dev->mode_config; - int ret; - - ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); - if (ret) - return ret; - - drm_modeset_lock_init(&plane->mutex); - - plane->base.properties = &plane->properties; - plane->dev = dev; - plane->funcs = funcs; - plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), - GFP_KERNEL); - if (!plane->format_types) { - DRM_DEBUG_KMS("out of memory when allocating plane\n"); - drm_mode_object_unregister(dev, &plane->base); - return -ENOMEM; - } - - if (name) { - va_list ap; - - va_start(ap, name); - plane->name = kvasprintf(GFP_KERNEL, name, ap); - va_end(ap); - } else { - plane->name = kasprintf(GFP_KERNEL, "plane-%d", - drm_num_planes(dev)); - } - if (!plane->name) { - kfree(plane->format_types); - drm_mode_object_unregister(dev, &plane->base); - return -ENOMEM; - } - - memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); - plane->format_count = format_count; - plane->possible_crtcs = possible_crtcs; - plane->type = type; - - list_add_tail(&plane->head, &config->plane_list); - plane->index = config->num_total_plane++; - if (plane->type == DRM_PLANE_TYPE_OVERLAY) - config->num_overlay_plane++; - - drm_object_attach_property(&plane->base, - config->plane_type_property, - plane->type); - - if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { - drm_object_attach_property(&plane->base, config->prop_fb_id, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); - drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); - drm_object_attach_property(&plane->base, config->prop_src_x, 0); - drm_object_attach_property(&plane->base, config->prop_src_y, 0); - drm_object_attach_property(&plane->base, config->prop_src_w, 0); - drm_object_attach_property(&plane->base, config->prop_src_h, 0); - } - - return 0; -} -EXPORT_SYMBOL(drm_universal_plane_init); - -static int drm_plane_register_all(struct drm_device *dev) -{ - struct drm_plane *plane; - int ret = 0; - - drm_for_each_plane(plane, dev) { - if (plane->funcs->late_register) - ret = plane->funcs->late_register(plane); - if (ret) - return ret; - } - - return 0; -} - -static void drm_plane_unregister_all(struct drm_device *dev) -{ - struct drm_plane *plane; - - drm_for_each_plane(plane, dev) { - if (plane->funcs->early_unregister) - plane->funcs->early_unregister(plane); - } -} - -/** - * drm_plane_init - Initialize a legacy plane - * @dev: DRM device - * @plane: plane object to init - * @possible_crtcs: bitmask of possible CRTCs - * @funcs: callbacks for the new plane - * @formats: array of supported formats (DRM_FORMAT\_\*) - * @format_count: number of elements in @formats - * @is_primary: plane type (primary vs overlay) - * - * Legacy API to initialize a DRM plane. - * - * New drivers should call drm_universal_plane_init() instead. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary) -{ - enum drm_plane_type type; - - type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; - return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, - formats, format_count, type, NULL); -} -EXPORT_SYMBOL(drm_plane_init); - -/** - * drm_plane_cleanup - Clean up the core plane usage - * @plane: plane to cleanup - * - * This function cleans up @plane and removes it from the DRM mode setting - * core. Note that the function does *not* free the plane structure itself, - * this is the responsibility of the caller. - */ -void drm_plane_cleanup(struct drm_plane *plane) -{ - struct drm_device *dev = plane->dev; - - drm_modeset_lock_all(dev); - kfree(plane->format_types); - drm_mode_object_unregister(dev, &plane->base); - - BUG_ON(list_empty(&plane->head)); - - /* Note that the plane_list is considered to be static; should we - * remove the drm_plane at runtime we would have to decrement all - * the indices on the drm_plane after us in the plane_list. - */ - - list_del(&plane->head); - dev->mode_config.num_total_plane--; - if (plane->type == DRM_PLANE_TYPE_OVERLAY) - dev->mode_config.num_overlay_plane--; - drm_modeset_unlock_all(dev); - - WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); - if (plane->state && plane->funcs->atomic_destroy_state) - plane->funcs->atomic_destroy_state(plane, plane->state); - - kfree(plane->name); - - memset(plane, 0, sizeof(*plane)); -} -EXPORT_SYMBOL(drm_plane_cleanup); - -/** - * drm_plane_from_index - find the registered plane at an index - * @dev: DRM device - * @idx: index of registered plane to find for - * - * Given a plane index, return the registered plane from DRM device's - * list of planes with matching index. - */ -struct drm_plane * -drm_plane_from_index(struct drm_device *dev, int idx) -{ - struct drm_plane *plane; - - drm_for_each_plane(plane, dev) - if (idx == plane->index) - return plane; - - return NULL; -} -EXPORT_SYMBOL(drm_plane_from_index); - -/** - * drm_plane_force_disable - Forcibly disable a plane - * @plane: plane to disable - * - * Forces the plane to be disabled. - * - * Used when the plane's current framebuffer is destroyed, - * and when restoring fbdev mode. - */ -void drm_plane_force_disable(struct drm_plane *plane) -{ - int ret; - - if (!plane->fb) - return; - - plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); - if (ret) { - DRM_ERROR("failed to disable plane with busy fb\n"); - plane->old_fb = NULL; - return; - } - /* disconnect the plane from the fb and crtc: */ - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; - plane->fb = NULL; - plane->crtc = NULL; -} -EXPORT_SYMBOL(drm_plane_force_disable); - int drm_modeset_register_all(struct drm_device *dev) { int ret; @@ -854,343 +605,6 @@ int drm_mode_getcrtc(struct drm_device *dev, return 0; } -/** - * drm_mode_getplane_res - enumerate all plane resources - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a list of plane ids to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getplane_res(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_get_plane_res *plane_resp = data; - struct drm_mode_config *config; - struct drm_plane *plane; - uint32_t __user *plane_ptr; - int copied = 0; - unsigned num_planes; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - config = &dev->mode_config; - - if (file_priv->universal_planes) - num_planes = config->num_total_plane; - else - num_planes = config->num_overlay_plane; - - /* - * This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. - */ - if (num_planes && - (plane_resp->count_planes >= num_planes)) { - plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; - - /* Plane lists are invariant, no locking needed. */ - drm_for_each_plane(plane, dev) { - /* - * Unless userspace set the 'universal planes' - * capability bit, only advertise overlays. - */ - if (plane->type != DRM_PLANE_TYPE_OVERLAY && - !file_priv->universal_planes) - continue; - - if (put_user(plane->base.id, plane_ptr + copied)) - return -EFAULT; - copied++; - } - } - plane_resp->count_planes = num_planes; - - return 0; -} - -/** - * drm_mode_getplane - get plane configuration - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a plane configuration structure to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_get_plane *plane_resp = data; - struct drm_plane *plane; - uint32_t __user *format_ptr; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - plane = drm_plane_find(dev, plane_resp->plane_id); - if (!plane) - return -ENOENT; - - drm_modeset_lock(&plane->mutex, NULL); - if (plane->crtc) - plane_resp->crtc_id = plane->crtc->base.id; - else - plane_resp->crtc_id = 0; - - if (plane->fb) - plane_resp->fb_id = plane->fb->base.id; - else - plane_resp->fb_id = 0; - drm_modeset_unlock(&plane->mutex); - - plane_resp->plane_id = plane->base.id; - plane_resp->possible_crtcs = plane->possible_crtcs; - plane_resp->gamma_size = 0; - - /* - * This ioctl is called twice, once to determine how much space is - * needed, and the 2nd time to fill it. - */ - if (plane->format_count && - (plane_resp->count_format_types >= plane->format_count)) { - format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; - if (copy_to_user(format_ptr, - plane->format_types, - sizeof(uint32_t) * plane->format_count)) { - return -EFAULT; - } - } - plane_resp->count_format_types = plane->format_count; - - return 0; -} - -/** - * drm_plane_check_pixel_format - Check if the plane supports the pixel format - * @plane: plane to check for format support - * @format: the pixel format - * - * Returns: - * Zero of @plane has @format in its list of supported pixel formats, -EINVAL - * otherwise. - */ -int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) -{ - unsigned int i; - - for (i = 0; i < plane->format_count; i++) { - if (format == plane->format_types[i]) - return 0; - } - - return -EINVAL; -} - -static int check_src_coords(uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - const struct drm_framebuffer *fb) -{ - unsigned int fb_width, fb_height; - - fb_width = fb->width << 16; - fb_height = fb->height << 16; - - /* Make sure source coordinates are inside the fb. */ - if (src_w > fb_width || - src_x > fb_width - src_w || - src_h > fb_height || - src_y > fb_height - src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", - src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, - src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, - src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, - src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); - return -ENOSPC; - } - - return 0; -} - -/* - * setplane_internal - setplane handler for internal callers - * - * Note that we assume an extra reference has already been taken on fb. If the - * update fails, this reference will be dropped before return; if it succeeds, - * the previous framebuffer (if any) will be unreferenced instead. - * - * src_{x,y,w,h} are provided in 16.16 fixed point format - */ -static int __setplane_internal(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int32_t crtc_x, int32_t crtc_y, - uint32_t crtc_w, uint32_t crtc_h, - /* src_{x,y,w,h} values are 16.16 fixed point */ - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - int ret = 0; - - /* No fb means shut it down */ - if (!fb) { - plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); - if (!ret) { - plane->crtc = NULL; - plane->fb = NULL; - } else { - plane->old_fb = NULL; - } - goto out; - } - - /* Check whether this plane is usable on this CRTC */ - if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); - ret = -EINVAL; - goto out; - } - - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->pixel_format); - if (ret) { - char *format_name = drm_get_format_name(fb->pixel_format); - DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); - kfree(format_name); - goto out; - } - - /* Give drivers some help against integer overflows */ - if (crtc_w > INT_MAX || - crtc_x > INT_MAX - (int32_t) crtc_w || - crtc_h > INT_MAX || - crtc_y > INT_MAX - (int32_t) crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - crtc_w, crtc_h, crtc_x, crtc_y); - ret = -ERANGE; - goto out; - } - - ret = check_src_coords(src_x, src_y, src_w, src_h, fb); - if (ret) - goto out; - - plane->old_fb = plane->fb; - ret = plane->funcs->update_plane(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - if (!ret) { - plane->crtc = crtc; - plane->fb = fb; - fb = NULL; - } else { - plane->old_fb = NULL; - } - -out: - if (fb) - drm_framebuffer_unreference(fb); - if (plane->old_fb) - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; - - return ret; -} - -static int setplane_internal(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int32_t crtc_x, int32_t crtc_y, - uint32_t crtc_w, uint32_t crtc_h, - /* src_{x,y,w,h} values are 16.16 fixed point */ - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) -{ - int ret; - - drm_modeset_lock_all(plane->dev); - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - drm_modeset_unlock_all(plane->dev); - - return ret; -} - -/** - * drm_mode_setplane - configure a plane's configuration - * @dev: DRM device - * @data: ioctl data* - * @file_priv: DRM file info - * - * Set plane configuration, including placement, fb, scaling, and other factors. - * Or pass a NULL fb to disable (planes may be disabled without providing a - * valid crtc). - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_setplane(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_set_plane *plane_req = data; - struct drm_plane *plane; - struct drm_crtc *crtc = NULL; - struct drm_framebuffer *fb = NULL; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - /* - * First, find the plane, crtc, and fb objects. If not available, - * we don't bother to call the driver. - */ - plane = drm_plane_find(dev, plane_req->plane_id); - if (!plane) { - DRM_DEBUG_KMS("Unknown plane ID %d\n", - plane_req->plane_id); - return -ENOENT; - } - - if (plane_req->fb_id) { - fb = drm_framebuffer_lookup(dev, plane_req->fb_id); - if (!fb) { - DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", - plane_req->fb_id); - return -ENOENT; - } - - crtc = drm_crtc_find(dev, plane_req->crtc_id); - if (!crtc) { - DRM_DEBUG_KMS("Unknown crtc ID %d\n", - plane_req->crtc_id); - return -ENOENT; - } - } - - /* - * setplane_internal will take care of deref'ing either the old or new - * framebuffer depending on success. - */ - return setplane_internal(plane, crtc, fb, - plane_req->crtc_x, plane_req->crtc_y, - plane_req->crtc_w, plane_req->crtc_h, - plane_req->src_x, plane_req->src_y, - plane_req->src_w, plane_req->src_h); -} - /** * drm_mode_set_config_internal - helper to call ->set_config * @set: modeset config to set @@ -1281,8 +695,9 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, DRM_ROTATE_270)) swap(hdisplay, vdisplay); - return check_src_coords(x << 16, y << 16, - hdisplay << 16, vdisplay << 16, fb); + return drm_framebuffer_check_src_coords(x << 16, y << 16, + hdisplay << 16, vdisplay << 16, + fb); } EXPORT_SYMBOL(drm_crtc_check_viewport); @@ -1469,208 +884,6 @@ out: return ret; } -/** - * drm_mode_cursor_universal - translate legacy cursor ioctl call into a - * universal plane handler call - * @crtc: crtc to update cursor for - * @req: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Legacy cursor ioctl's work directly with driver buffer handles. To - * translate legacy ioctl calls into universal plane handler calls, we need to - * wrap the native buffer handle in a drm_framebuffer. - * - * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB - * buffer with a pitch of 4*width; the universal plane interface should be used - * directly in cases where the hardware can support other buffer settings and - * userspace wants to make use of these capabilities. - * - * Returns: - * Zero on success, negative errno on failure. - */ -static int drm_mode_cursor_universal(struct drm_crtc *crtc, - struct drm_mode_cursor2 *req, - struct drm_file *file_priv) -{ - struct drm_device *dev = crtc->dev; - struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd2 fbreq = { - .width = req->width, - .height = req->height, - .pixel_format = DRM_FORMAT_ARGB8888, - .pitches = { req->width * 4 }, - .handles = { req->handle }, - }; - int32_t crtc_x, crtc_y; - uint32_t crtc_w = 0, crtc_h = 0; - uint32_t src_w = 0, src_h = 0; - int ret = 0; - - BUG_ON(!crtc->cursor); - WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); - - /* - * Obtain fb we'll be using (either new or existing) and take an extra - * reference to it if fb != null. setplane will take care of dropping - * the reference if the plane update fails. - */ - if (req->flags & DRM_MODE_CURSOR_BO) { - if (req->handle) { - fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); - if (IS_ERR(fb)) { - DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); - return PTR_ERR(fb); - } - fb->hot_x = req->hot_x; - fb->hot_y = req->hot_y; - } else { - fb = NULL; - } - } else { - fb = crtc->cursor->fb; - if (fb) - drm_framebuffer_reference(fb); - } - - if (req->flags & DRM_MODE_CURSOR_MOVE) { - crtc_x = req->x; - crtc_y = req->y; - } else { - crtc_x = crtc->cursor_x; - crtc_y = crtc->cursor_y; - } - - if (fb) { - crtc_w = fb->width; - crtc_h = fb->height; - src_w = fb->width << 16; - src_h = fb->height << 16; - } - - /* - * setplane_internal will take care of deref'ing either the old or new - * framebuffer depending on success. - */ - ret = __setplane_internal(crtc->cursor, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h); - - /* Update successful; save new cursor position, if necessary */ - if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { - crtc->cursor_x = req->x; - crtc->cursor_y = req->y; - } - - return ret; -} - -static int drm_mode_cursor_common(struct drm_device *dev, - struct drm_mode_cursor2 *req, - struct drm_file *file_priv) -{ - struct drm_crtc *crtc; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) - return -EINVAL; - - crtc = drm_crtc_find(dev, req->crtc_id); - if (!crtc) { - DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); - return -ENOENT; - } - - /* - * If this crtc has a universal cursor plane, call that plane's update - * handler rather than using legacy cursor handlers. - */ - drm_modeset_lock_crtc(crtc, crtc->cursor); - if (crtc->cursor) { - ret = drm_mode_cursor_universal(crtc, req, file_priv); - goto out; - } - - if (req->flags & DRM_MODE_CURSOR_BO) { - if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { - ret = -ENXIO; - goto out; - } - /* Turns off the cursor if handle is 0 */ - if (crtc->funcs->cursor_set2) - ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, - req->width, req->height, req->hot_x, req->hot_y); - else - ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, - req->width, req->height); - } - - if (req->flags & DRM_MODE_CURSOR_MOVE) { - if (crtc->funcs->cursor_move) { - ret = crtc->funcs->cursor_move(crtc, req->x, req->y); - } else { - ret = -EFAULT; - goto out; - } - } -out: - drm_modeset_unlock_crtc(crtc); - - return ret; - -} - - -/** - * drm_mode_cursor_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Set the cursor configuration based on user request. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_cursor *req = data; - struct drm_mode_cursor2 new_req; - - memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); - new_req.hot_x = new_req.hot_y = 0; - - return drm_mode_cursor_common(dev, &new_req, file_priv); -} - -/** - * drm_mode_cursor2_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Set the cursor configuration based on user request. This implements the 2nd - * version of the cursor ioctl, which allows userspace to additionally specify - * the hotspot of the pointer. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_cursor2_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_cursor2 *req = data; - - return drm_mode_cursor_common(dev, req, file_priv); -} - int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) @@ -1686,35 +899,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, return ret; } -/** - * drm_mode_plane_set_obj_prop - set the value of a property - * @plane: drm plane object to set property value for - * @property: property to set - * @value: value the property should be set to - * - * This functions sets a given property on a given plane object. This function - * calls the driver's ->set_property callback and changes the software state of - * the property if the callback succeeds. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_mode_plane_set_obj_prop(struct drm_plane *plane, - struct drm_property *property, - uint64_t value) -{ - int ret = -EINVAL; - struct drm_mode_object *obj = &plane->base; - - if (plane->funcs->set_property) - ret = plane->funcs->set_property(plane, property, value); - if (!ret) - drm_object_property_set_value(obj, property, value); - - return ret; -} -EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); - /** * drm_mode_crtc_set_gamma_size - set the gamma table size * @crtc: CRTC to set the gamma table size for @@ -1890,172 +1074,6 @@ out: return ret; } -/** - * drm_mode_page_flip_ioctl - schedule an asynchronous fb update - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This schedules an asynchronous update on a given CRTC, called page flip. - * Optionally a drm event is generated to signal the completion of the event. - * Generic drivers cannot assume that a pageflip with changed framebuffer - * properties (including driver specific metadata like tiling layout) will work, - * but some drivers support e.g. pixel format changes through the pageflip - * ioctl. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_page_flip_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_page_flip_target *page_flip = data; - struct drm_crtc *crtc; - struct drm_framebuffer *fb = NULL; - struct drm_pending_vblank_event *e = NULL; - u32 target_vblank = page_flip->sequence; - int ret = -EINVAL; - - if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) - return -EINVAL; - - if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) - return -EINVAL; - - /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags - * can be specified - */ - if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) - return -EINVAL; - - if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) - return -EINVAL; - - crtc = drm_crtc_find(dev, page_flip->crtc_id); - if (!crtc) - return -ENOENT; - - if (crtc->funcs->page_flip_target) { - u32 current_vblank; - int r; - - r = drm_crtc_vblank_get(crtc); - if (r) - return r; - - current_vblank = drm_crtc_vblank_count(crtc); - - switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { - case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: - if ((int)(target_vblank - current_vblank) > 1) { - DRM_DEBUG("Invalid absolute flip target %u, " - "must be <= %u\n", target_vblank, - current_vblank + 1); - drm_crtc_vblank_put(crtc); - return -EINVAL; - } - break; - case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: - if (target_vblank != 0 && target_vblank != 1) { - DRM_DEBUG("Invalid relative flip target %u, " - "must be 0 or 1\n", target_vblank); - drm_crtc_vblank_put(crtc); - return -EINVAL; - } - target_vblank += current_vblank; - break; - default: - target_vblank = current_vblank + - !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); - break; - } - } else if (crtc->funcs->page_flip == NULL || - (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { - return -EINVAL; - } - - drm_modeset_lock_crtc(crtc, crtc->primary); - if (crtc->primary->fb == NULL) { - /* The framebuffer is currently unbound, presumably - * due to a hotplug event, that userspace has not - * yet discovered. - */ - ret = -EBUSY; - goto out; - } - - fb = drm_framebuffer_lookup(dev, page_flip->fb_id); - if (!fb) { - ret = -ENOENT; - goto out; - } - - if (crtc->state) { - const struct drm_plane_state *state = crtc->primary->state; - - ret = check_src_coords(state->src_x, state->src_y, - state->src_w, state->src_h, fb); - } else { - ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); - } - if (ret) - goto out; - - if (crtc->primary->fb->pixel_format != fb->pixel_format) { - DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); - ret = -EINVAL; - goto out; - } - - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { - e = kzalloc(sizeof *e, GFP_KERNEL); - if (!e) { - ret = -ENOMEM; - goto out; - } - e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof(e->event); - e->event.user_data = page_flip->user_data; - ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); - if (ret) { - kfree(e); - goto out; - } - } - - crtc->primary->old_fb = crtc->primary->fb; - if (crtc->funcs->page_flip_target) - ret = crtc->funcs->page_flip_target(crtc, fb, e, - page_flip->flags, - target_vblank); - else - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); - if (ret) { - if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) - drm_event_cancel_free(dev, &e->base); - /* Keep the old fb, don't unref it. */ - crtc->primary->old_fb = NULL; - } else { - crtc->primary->fb = fb; - /* Unref only the old framebuffer. */ - fb = NULL; - } - -out: - if (ret && crtc->funcs->page_flip_target) - drm_crtc_vblank_put(crtc); - if (fb) - drm_framebuffer_unreference(fb); - if (crtc->primary->old_fb) - drm_framebuffer_unreference(crtc->primary->old_fb); - crtc->primary->old_fb = NULL; - drm_modeset_unlock_crtc(crtc); - - return ret; -} - /** * drm_mode_config_reset - call ->reset callbacks * @dev: drm device diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 444e609078cc..aff42fc84658 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -36,8 +36,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value); -int drm_plane_check_pixel_format(const struct drm_plane *plane, - u32 format); int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, const struct drm_display_mode *mode, @@ -56,28 +54,15 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, /* IOCTLs */ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getplane_res(struct drm_device *dev, void *data, - struct drm_file *file_priv); int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getplane(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_setplane(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_cursor2_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_page_flip_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); - /* drm_property.c */ void drm_property_destroy_user_blobs(struct drm_device *dev, struct drm_file *file_priv); @@ -155,6 +140,9 @@ drm_internal_framebuffer_create(struct drm_device *dev, const struct drm_mode_fb_cmd2 *r, struct drm_file *file_priv); void drm_framebuffer_free(struct kref *kref); +int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + const struct drm_framebuffer *fb); /* IOCTL */ int drm_mode_addfb(struct drm_device *dev, @@ -180,3 +168,23 @@ void drm_modeset_unregister_all(struct drm_device *dev); /* drm_blend.c */ int drm_atomic_normalize_zpos(struct drm_device *dev, struct drm_atomic_state *state); + +/* drm_plane.c */ +int drm_plane_register_all(struct drm_device *dev); +void drm_plane_unregister_all(struct drm_device *dev); +int drm_plane_check_pixel_format(const struct drm_plane *plane, + u32 format); + +/* IOCTL */ +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_mode_getplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_setplane(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_cursor2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 30dc01e6eb5d..398efd67cb93 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -62,6 +62,32 @@ * &drm_framebuffer. */ +int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + const struct drm_framebuffer *fb) +{ + unsigned int fb_width, fb_height; + + fb_width = fb->width << 16; + fb_height = fb->height << 16; + + /* Make sure source coordinates are inside the fb. */ + if (src_w > fb_width || + src_x > fb_width - src_w || + src_h > fb_height || + src_y > fb_height - src_h) { + DRM_DEBUG_KMS("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, + src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, + src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, + src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); + return -ENOSPC; + } + + return 0; +} + /** * drm_mode_addfb - add an FB to the graphics configuration * @dev: drm device for the ioctl diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c new file mode 100644 index 000000000000..9003b5f835cf --- /dev/null +++ b/drivers/gpu/drm/drm_plane.c @@ -0,0 +1,990 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include + +#include "drm_crtc_internal.h" + +static unsigned int drm_num_planes(struct drm_device *dev) +{ + unsigned int num = 0; + struct drm_plane *tmp; + + drm_for_each_plane(tmp, dev) { + num++; + } + + return num; +} + +/** + * drm_universal_plane_init - Initialize a new universal plane object + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (DRM_FORMAT\_\*) + * @format_count: number of elements in @formats + * @type: type of plane (overlay, primary, cursor) + * @name: printf style format string for the plane name, or NULL for default name + * + * Initializes a plane object of type @type. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + enum drm_plane_type type, + const char *name, ...) +{ + struct drm_mode_config *config = &dev->mode_config; + int ret; + + ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); + if (ret) + return ret; + + drm_modeset_lock_init(&plane->mutex); + + plane->base.properties = &plane->properties; + plane->dev = dev; + plane->funcs = funcs; + plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), + GFP_KERNEL); + if (!plane->format_types) { + DRM_DEBUG_KMS("out of memory when allocating plane\n"); + drm_mode_object_unregister(dev, &plane->base); + return -ENOMEM; + } + + if (name) { + va_list ap; + + va_start(ap, name); + plane->name = kvasprintf(GFP_KERNEL, name, ap); + va_end(ap); + } else { + plane->name = kasprintf(GFP_KERNEL, "plane-%d", + drm_num_planes(dev)); + } + if (!plane->name) { + kfree(plane->format_types); + drm_mode_object_unregister(dev, &plane->base); + return -ENOMEM; + } + + memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); + plane->format_count = format_count; + plane->possible_crtcs = possible_crtcs; + plane->type = type; + + list_add_tail(&plane->head, &config->plane_list); + plane->index = config->num_total_plane++; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + config->num_overlay_plane++; + + drm_object_attach_property(&plane->base, + config->plane_type_property, + plane->type); + + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&plane->base, config->prop_fb_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); + drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); + drm_object_attach_property(&plane->base, config->prop_src_x, 0); + drm_object_attach_property(&plane->base, config->prop_src_y, 0); + drm_object_attach_property(&plane->base, config->prop_src_w, 0); + drm_object_attach_property(&plane->base, config->prop_src_h, 0); + } + + return 0; +} +EXPORT_SYMBOL(drm_universal_plane_init); + +int drm_plane_register_all(struct drm_device *dev) +{ + struct drm_plane *plane; + int ret = 0; + + drm_for_each_plane(plane, dev) { + if (plane->funcs->late_register) + ret = plane->funcs->late_register(plane); + if (ret) + return ret; + } + + return 0; +} + +void drm_plane_unregister_all(struct drm_device *dev) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) { + if (plane->funcs->early_unregister) + plane->funcs->early_unregister(plane); + } +} + +/** + * drm_plane_init - Initialize a legacy plane + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (DRM_FORMAT\_\*) + * @format_count: number of elements in @formats + * @is_primary: plane type (primary vs overlay) + * + * Legacy API to initialize a DRM plane. + * + * New drivers should call drm_universal_plane_init() instead. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + bool is_primary) +{ + enum drm_plane_type type; + + type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, + formats, format_count, type, NULL); +} +EXPORT_SYMBOL(drm_plane_init); + +/** + * drm_plane_cleanup - Clean up the core plane usage + * @plane: plane to cleanup + * + * This function cleans up @plane and removes it from the DRM mode setting + * core. Note that the function does *not* free the plane structure itself, + * this is the responsibility of the caller. + */ +void drm_plane_cleanup(struct drm_plane *plane) +{ + struct drm_device *dev = plane->dev; + + drm_modeset_lock_all(dev); + kfree(plane->format_types); + drm_mode_object_unregister(dev, &plane->base); + + BUG_ON(list_empty(&plane->head)); + + /* Note that the plane_list is considered to be static; should we + * remove the drm_plane at runtime we would have to decrement all + * the indices on the drm_plane after us in the plane_list. + */ + + list_del(&plane->head); + dev->mode_config.num_total_plane--; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + dev->mode_config.num_overlay_plane--; + drm_modeset_unlock_all(dev); + + WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); + if (plane->state && plane->funcs->atomic_destroy_state) + plane->funcs->atomic_destroy_state(plane, plane->state); + + kfree(plane->name); + + memset(plane, 0, sizeof(*plane)); +} +EXPORT_SYMBOL(drm_plane_cleanup); + +/** + * drm_plane_from_index - find the registered plane at an index + * @dev: DRM device + * @idx: index of registered plane to find for + * + * Given a plane index, return the registered plane from DRM device's + * list of planes with matching index. + */ +struct drm_plane * +drm_plane_from_index(struct drm_device *dev, int idx) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) + if (idx == plane->index) + return plane; + + return NULL; +} +EXPORT_SYMBOL(drm_plane_from_index); + +/** + * drm_plane_force_disable - Forcibly disable a plane + * @plane: plane to disable + * + * Forces the plane to be disabled. + * + * Used when the plane's current framebuffer is destroyed, + * and when restoring fbdev mode. + */ +void drm_plane_force_disable(struct drm_plane *plane) +{ + int ret; + + if (!plane->fb) + return; + + plane->old_fb = plane->fb; + ret = plane->funcs->disable_plane(plane); + if (ret) { + DRM_ERROR("failed to disable plane with busy fb\n"); + plane->old_fb = NULL; + return; + } + /* disconnect the plane from the fb and crtc: */ + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + plane->fb = NULL; + plane->crtc = NULL; +} +EXPORT_SYMBOL(drm_plane_force_disable); + +/** + * drm_mode_plane_set_obj_prop - set the value of a property + * @plane: drm plane object to set property value for + * @property: property to set + * @value: value the property should be set to + * + * This functions sets a given property on a given plane object. This function + * calls the driver's ->set_property callback and changes the software state of + * the property if the callback succeeds. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_property *property, + uint64_t value) +{ + int ret = -EINVAL; + struct drm_mode_object *obj = &plane->base; + + if (plane->funcs->set_property) + ret = plane->funcs->set_property(plane, property, value); + if (!ret) + drm_object_property_set_value(obj, property, value); + + return ret; +} +EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); + +/** + * drm_mode_getplane_res - enumerate all plane resources + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Construct a list of plane ids to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getplane_res(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane_res *plane_resp = data; + struct drm_mode_config *config; + struct drm_plane *plane; + uint32_t __user *plane_ptr; + int copied = 0; + unsigned num_planes; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + config = &dev->mode_config; + + if (file_priv->universal_planes) + num_planes = config->num_total_plane; + else + num_planes = config->num_overlay_plane; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (num_planes && + (plane_resp->count_planes >= num_planes)) { + plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; + + /* Plane lists are invariant, no locking needed. */ + drm_for_each_plane(plane, dev) { + /* + * Unless userspace set the 'universal planes' + * capability bit, only advertise overlays. + */ + if (plane->type != DRM_PLANE_TYPE_OVERLAY && + !file_priv->universal_planes) + continue; + + if (put_user(plane->base.id, plane_ptr + copied)) + return -EFAULT; + copied++; + } + } + plane_resp->count_planes = num_planes; + + return 0; +} + +/** + * drm_mode_getplane - get plane configuration + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Construct a plane configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_get_plane *plane_resp = data; + struct drm_plane *plane; + uint32_t __user *format_ptr; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + plane = drm_plane_find(dev, plane_resp->plane_id); + if (!plane) + return -ENOENT; + + drm_modeset_lock(&plane->mutex, NULL); + if (plane->crtc) + plane_resp->crtc_id = plane->crtc->base.id; + else + plane_resp->crtc_id = 0; + + if (plane->fb) + plane_resp->fb_id = plane->fb->base.id; + else + plane_resp->fb_id = 0; + drm_modeset_unlock(&plane->mutex); + + plane_resp->plane_id = plane->base.id; + plane_resp->possible_crtcs = plane->possible_crtcs; + plane_resp->gamma_size = 0; + + /* + * This ioctl is called twice, once to determine how much space is + * needed, and the 2nd time to fill it. + */ + if (plane->format_count && + (plane_resp->count_format_types >= plane->format_count)) { + format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; + if (copy_to_user(format_ptr, + plane->format_types, + sizeof(uint32_t) * plane->format_count)) { + return -EFAULT; + } + } + plane_resp->count_format_types = plane->format_count; + + return 0; +} + +/** + * drm_plane_check_pixel_format - Check if the plane supports the pixel format + * @plane: plane to check for format support + * @format: the pixel format + * + * Returns: + * Zero of @plane has @format in its list of supported pixel formats, -EINVAL + * otherwise. + */ +int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) +{ + unsigned int i; + + for (i = 0; i < plane->format_count; i++) { + if (format == plane->format_types[i]) + return 0; + } + + return -EINVAL; +} + +/* + * setplane_internal - setplane handler for internal callers + * + * Note that we assume an extra reference has already been taken on fb. If the + * update fails, this reference will be dropped before return; if it succeeds, + * the previous framebuffer (if any) will be unreferenced instead. + * + * src_{x,y,w,h} are provided in 16.16 fixed point format + */ +static int __setplane_internal(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + /* src_{x,y,w,h} values are 16.16 fixed point */ + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret = 0; + + /* No fb means shut it down */ + if (!fb) { + plane->old_fb = plane->fb; + ret = plane->funcs->disable_plane(plane); + if (!ret) { + plane->crtc = NULL; + plane->fb = NULL; + } else { + plane->old_fb = NULL; + } + goto out; + } + + /* Check whether this plane is usable on this CRTC */ + if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { + DRM_DEBUG_KMS("Invalid crtc for plane\n"); + ret = -EINVAL; + goto out; + } + + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->pixel_format); + if (ret) { + char *format_name = drm_get_format_name(fb->pixel_format); + DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); + kfree(format_name); + goto out; + } + + /* Give drivers some help against integer overflows */ + if (crtc_w > INT_MAX || + crtc_x > INT_MAX - (int32_t) crtc_w || + crtc_h > INT_MAX || + crtc_y > INT_MAX - (int32_t) crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + crtc_w, crtc_h, crtc_x, crtc_y); + ret = -ERANGE; + goto out; + } + + ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + if (ret) + goto out; + + plane->old_fb = plane->fb; + ret = plane->funcs->update_plane(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + if (!ret) { + plane->crtc = crtc; + plane->fb = fb; + fb = NULL; + } else { + plane->old_fb = NULL; + } + +out: + if (fb) + drm_framebuffer_unreference(fb); + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + + return ret; +} + +static int setplane_internal(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + /* src_{x,y,w,h} values are 16.16 fixed point */ + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret; + + drm_modeset_lock_all(plane->dev); + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + drm_modeset_unlock_all(plane->dev); + + return ret; +} + +/** + * drm_mode_setplane - configure a plane's configuration + * @dev: DRM device + * @data: ioctl data* + * @file_priv: DRM file info + * + * Set plane configuration, including placement, fb, scaling, and other factors. + * Or pass a NULL fb to disable (planes may be disabled without providing a + * valid crtc). + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_setplane(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_set_plane *plane_req = data; + struct drm_plane *plane; + struct drm_crtc *crtc = NULL; + struct drm_framebuffer *fb = NULL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + /* + * First, find the plane, crtc, and fb objects. If not available, + * we don't bother to call the driver. + */ + plane = drm_plane_find(dev, plane_req->plane_id); + if (!plane) { + DRM_DEBUG_KMS("Unknown plane ID %d\n", + plane_req->plane_id); + return -ENOENT; + } + + if (plane_req->fb_id) { + fb = drm_framebuffer_lookup(dev, plane_req->fb_id); + if (!fb) { + DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", + plane_req->fb_id); + return -ENOENT; + } + + crtc = drm_crtc_find(dev, plane_req->crtc_id); + if (!crtc) { + DRM_DEBUG_KMS("Unknown crtc ID %d\n", + plane_req->crtc_id); + return -ENOENT; + } + } + + /* + * setplane_internal will take care of deref'ing either the old or new + * framebuffer depending on success. + */ + return setplane_internal(plane, crtc, fb, + plane_req->crtc_x, plane_req->crtc_y, + plane_req->crtc_w, plane_req->crtc_h, + plane_req->src_x, plane_req->src_y, + plane_req->src_w, plane_req->src_h); +} + +/** + * drm_mode_cursor_universal - translate legacy cursor ioctl call into a + * universal plane handler call + * @crtc: crtc to update cursor for + * @req: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Legacy cursor ioctl's work directly with driver buffer handles. To + * translate legacy ioctl calls into universal plane handler calls, we need to + * wrap the native buffer handle in a drm_framebuffer. + * + * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB + * buffer with a pitch of 4*width; the universal plane interface should be used + * directly in cases where the hardware can support other buffer settings and + * userspace wants to make use of these capabilities. + * + * Returns: + * Zero on success, negative errno on failure. + */ +static int drm_mode_cursor_universal(struct drm_crtc *crtc, + struct drm_mode_cursor2 *req, + struct drm_file *file_priv) +{ + struct drm_device *dev = crtc->dev; + struct drm_framebuffer *fb = NULL; + struct drm_mode_fb_cmd2 fbreq = { + .width = req->width, + .height = req->height, + .pixel_format = DRM_FORMAT_ARGB8888, + .pitches = { req->width * 4 }, + .handles = { req->handle }, + }; + int32_t crtc_x, crtc_y; + uint32_t crtc_w = 0, crtc_h = 0; + uint32_t src_w = 0, src_h = 0; + int ret = 0; + + BUG_ON(!crtc->cursor); + WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); + + /* + * Obtain fb we'll be using (either new or existing) and take an extra + * reference to it if fb != null. setplane will take care of dropping + * the reference if the plane update fails. + */ + if (req->flags & DRM_MODE_CURSOR_BO) { + if (req->handle) { + fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); + if (IS_ERR(fb)) { + DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); + return PTR_ERR(fb); + } + fb->hot_x = req->hot_x; + fb->hot_y = req->hot_y; + } else { + fb = NULL; + } + } else { + fb = crtc->cursor->fb; + if (fb) + drm_framebuffer_reference(fb); + } + + if (req->flags & DRM_MODE_CURSOR_MOVE) { + crtc_x = req->x; + crtc_y = req->y; + } else { + crtc_x = crtc->cursor_x; + crtc_y = crtc->cursor_y; + } + + if (fb) { + crtc_w = fb->width; + crtc_h = fb->height; + src_w = fb->width << 16; + src_h = fb->height << 16; + } + + /* + * setplane_internal will take care of deref'ing either the old or new + * framebuffer depending on success. + */ + ret = __setplane_internal(crtc->cursor, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h); + + /* Update successful; save new cursor position, if necessary */ + if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { + crtc->cursor_x = req->x; + crtc->cursor_y = req->y; + } + + return ret; +} + +static int drm_mode_cursor_common(struct drm_device *dev, + struct drm_mode_cursor2 *req, + struct drm_file *file_priv) +{ + struct drm_crtc *crtc; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) + return -EINVAL; + + crtc = drm_crtc_find(dev, req->crtc_id); + if (!crtc) { + DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); + return -ENOENT; + } + + /* + * If this crtc has a universal cursor plane, call that plane's update + * handler rather than using legacy cursor handlers. + */ + drm_modeset_lock_crtc(crtc, crtc->cursor); + if (crtc->cursor) { + ret = drm_mode_cursor_universal(crtc, req, file_priv); + goto out; + } + + if (req->flags & DRM_MODE_CURSOR_BO) { + if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { + ret = -ENXIO; + goto out; + } + /* Turns off the cursor if handle is 0 */ + if (crtc->funcs->cursor_set2) + ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, + req->width, req->height, req->hot_x, req->hot_y); + else + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, + req->width, req->height); + } + + if (req->flags & DRM_MODE_CURSOR_MOVE) { + if (crtc->funcs->cursor_move) { + ret = crtc->funcs->cursor_move(crtc, req->x, req->y); + } else { + ret = -EFAULT; + goto out; + } + } +out: + drm_modeset_unlock_crtc(crtc); + + return ret; + +} + + +/** + * drm_mode_cursor_ioctl - set CRTC's cursor configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Set the cursor configuration based on user request. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor *req = data; + struct drm_mode_cursor2 new_req; + + memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); + new_req.hot_x = new_req.hot_y = 0; + + return drm_mode_cursor_common(dev, &new_req, file_priv); +} + +/** + * drm_mode_cursor2_ioctl - set CRTC's cursor configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Set the cursor configuration based on user request. This implements the 2nd + * version of the cursor ioctl, which allows userspace to additionally specify + * the hotspot of the pointer. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_cursor2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor2 *req = data; + + return drm_mode_cursor_common(dev, req, file_priv); +} + +/** + * drm_mode_page_flip_ioctl - schedule an asynchronous fb update + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This schedules an asynchronous update on a given CRTC, called page flip. + * Optionally a drm event is generated to signal the completion of the event. + * Generic drivers cannot assume that a pageflip with changed framebuffer + * properties (including driver specific metadata like tiling layout) will work, + * but some drivers support e.g. pixel format changes through the pageflip + * ioctl. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_page_flip_target *page_flip = data; + struct drm_crtc *crtc; + struct drm_framebuffer *fb = NULL; + struct drm_pending_vblank_event *e = NULL; + u32 target_vblank = page_flip->sequence; + int ret = -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS) + return -EINVAL; + + if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) + return -EINVAL; + + /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags + * can be specified + */ + if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET) + return -EINVAL; + + if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) + return -EINVAL; + + crtc = drm_crtc_find(dev, page_flip->crtc_id); + if (!crtc) + return -ENOENT; + + drm_modeset_lock_crtc(crtc, crtc->primary); + if (crtc->primary->fb == NULL) { + /* The framebuffer is currently unbound, presumably + * due to a hotplug event, that userspace has not + * yet discovered. + */ + ret = -EBUSY; + goto out; + } + + if (crtc->funcs->page_flip == NULL) + goto out; + + fb = drm_framebuffer_lookup(dev, page_flip->fb_id); + if (!fb) { + ret = -ENOENT; + goto out; + } + + if (crtc->state) { + const struct drm_plane_state *state = crtc->primary->state; + + ret = drm_framebuffer_check_src_coords(state->src_x, + state->src_y, + state->src_w, + state->src_h, + fb); + } else { + ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); + } + if (ret) + goto out; + + if (crtc->primary->fb->pixel_format != fb->pixel_format) { + DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); + ret = -EINVAL; + goto out; + } + + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { + e = kzalloc(sizeof *e, GFP_KERNEL); + if (!e) { + ret = -ENOMEM; + goto out; + } + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof(e->event); + e->event.user_data = page_flip->user_data; + ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); + if (ret) { + kfree(e); + goto out; + } + } + + crtc->primary->old_fb = crtc->primary->fb; + if (crtc->funcs->page_flip_target) { + u32 current_vblank; + int r; + + r = drm_crtc_vblank_get(crtc); + if (r) + return r; + + current_vblank = drm_crtc_vblank_count(crtc); + + switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) { + case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: + if ((int)(target_vblank - current_vblank) > 1) { + DRM_DEBUG("Invalid absolute flip target %u, " + "must be <= %u\n", target_vblank, + current_vblank + 1); + drm_crtc_vblank_put(crtc); + return -EINVAL; + } + break; + case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: + if (target_vblank != 0 && target_vblank != 1) { + DRM_DEBUG("Invalid relative flip target %u, " + "must be 0 or 1\n", target_vblank); + drm_crtc_vblank_put(crtc); + return -EINVAL; + } + target_vblank += current_vblank; + break; + default: + target_vblank = current_vblank + + !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC); + break; + } + } else if (crtc->funcs->page_flip == NULL || + (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) { + return -EINVAL; + } + + if (crtc->funcs->page_flip_target) + ret = crtc->funcs->page_flip_target(crtc, fb, e, + page_flip->flags, + target_vblank); + else + ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); + if (ret) { + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) + drm_event_cancel_free(dev, &e->base); + /* Keep the old fb, don't unref it. */ + crtc->primary->old_fb = NULL; + } else { + crtc->primary->fb = fb; + /* Unref only the old framebuffer. */ + fb = NULL; + } + +out: + if (ret && crtc->funcs->page_flip_target) + drm_crtc_vblank_put(crtc); + if (crtc->primary->old_fb) + drm_framebuffer_unreference(crtc->primary->old_fb); + crtc->primary->old_fb = NULL; + drm_modeset_unlock_crtc(crtc); + + return ret; +} diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 856a9c85a838..9701f2dfb784 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -30,6 +30,160 @@ #include +/** + * 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 + * is reference counted to allow waiters to safely wait on an event to complete, + * without holding any locks. + * + * It has 3 different events in total to allow a fine-grained synchronization + * between outstanding updates:: + * + * atomic commit thread hardware + * + * write new state into hardware ----> ... + * signal hw_done + * switch to new state on next + * ... v/hblank + * + * wait for buffers to show up ... + * + * ... send completion irq + * irq handler signals flip_done + * cleanup old buffers + * + * signal cleanup_done + * + * 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 + * and modeset state change. + * + * For an implementation of how to use this look at + * drm_atomic_helper_setup_commit() from the atomic helper library. + */ +struct drm_crtc_commit { + /** + * @crtc: + * + * DRM CRTC for this commit. + */ + struct drm_crtc *crtc; + + /** + * @ref: + * + * Reference count for this structure. Needed to allow blocking on + * completions without the risk of the completion disappearing + * meanwhile. + */ + struct kref ref; + + /** + * @flip_done: + * + * Will be signaled when the hardware has flipped to the new set of + * buffers. Signals at the same time as when the drm event for this + * 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. + */ + struct completion flip_done; + + /** + * @hw_done: + * + * Will be signalled when all hw register changes for this commit have + * been written out. Especially when disabling a pipe this can be much + * later than than @flip_done, since that can signal already when the + * screen goes black, whereas to fully shut down a pipe more register + * I/O is required. + * + * Note that this does not need to include separately reference-counted + * resources like backing storage buffer pinning, or runtime pm + * management. + */ + struct completion hw_done; + + /** + * @cleanup_done: + * + * Will be signalled after old buffers have been cleaned up by calling + * drm_atomic_helper_cleanup_planes(). Since this can only happen after + * 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. + */ + struct completion cleanup_done; + + /** + * @commit_entry: + * + * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock. + */ + struct list_head commit_entry; + + /** + * @event: + * + * &drm_pending_vblank_event pointer to clean up private events. + */ + struct drm_pending_vblank_event *event; +}; + +struct __drm_planes_state { + struct drm_plane *ptr; + struct drm_plane_state *state; +}; + +struct __drm_crtcs_state { + struct drm_crtc *ptr; + struct drm_crtc_state *state; + struct drm_crtc_commit *commit; +}; + +struct __drm_connnectors_state { + struct drm_connector *ptr; + struct drm_connector_state *state; +}; + +/** + * struct drm_atomic_state - the global state object for atomic updates + * @dev: parent DRM device + * @allow_modeset: allow full modeset + * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics + * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL. + * @planes: pointer to array of structures with per-plane data + * @crtcs: pointer to array of CRTC pointers + * @num_connector: size of the @connectors and @connector_states arrays + * @connectors: pointer to array of structures with per-connector data + * @acquire_ctx: acquire context for this atomic modeset state update + */ +struct drm_atomic_state { + struct drm_device *dev; + bool allow_modeset : 1; + bool legacy_cursor_update : 1; + bool legacy_set_config : 1; + struct __drm_planes_state *planes; + struct __drm_crtcs_state *crtcs; + int num_connector; + struct __drm_connnectors_state *connectors; + + struct drm_modeset_acquire_ctx *acquire_ctx; + + /** + * @commit_work: + * + * Work item which can be used by the driver or helpers to execute the + * commit without blocking. + */ + struct work_struct commit_work; +}; + void drm_crtc_commit_put(struct drm_crtc_commit *commit); static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit) { diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 35b13fc6bbc1..9375e5c9cddb 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -44,6 +44,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -656,525 +657,6 @@ struct drm_crtc { struct drm_modeset_acquire_ctx *acquire_ctx; }; -/** - * struct drm_plane_state - mutable plane state - * @plane: backpointer to the plane - * @crtc: currently bound CRTC, NULL if disabled - * @fb: currently bound framebuffer - * @fence: optional fence to wait for before scanning out @fb - * @crtc_x: left position of visible portion of plane on crtc - * @crtc_y: upper position of visible portion of plane on crtc - * @crtc_w: width of visible portion of plane on crtc - * @crtc_h: height of visible portion of plane on crtc - * @src_x: left position of visible portion of plane within - * plane (in 16.16) - * @src_y: upper position of visible portion of plane within - * plane (in 16.16) - * @src_w: width of visible portion of plane (in 16.16) - * @src_h: height of visible portion of plane (in 16.16) - * @rotation: rotation of the plane - * @zpos: priority of the given plane on crtc (optional) - * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1 - * where N is the number of active planes for given crtc - * @src: clipped source coordinates of the plane (in 16.16) - * @dst: clipped destination coordinates of the plane - * @visible: visibility of the plane - * @state: backpointer to global drm_atomic_state - */ -struct drm_plane_state { - struct drm_plane *plane; - - struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ - struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ - struct fence *fence; - - /* Signed dest location allows it to be partially off screen */ - int32_t crtc_x, crtc_y; - uint32_t crtc_w, crtc_h; - - /* Source values are 16.16 fixed point */ - uint32_t src_x, src_y; - uint32_t src_h, src_w; - - /* Plane rotation */ - unsigned int rotation; - - /* Plane zpos */ - unsigned int zpos; - unsigned int normalized_zpos; - - /* Clipped coordinates */ - struct drm_rect src, dst; - - /* - * Is the plane actually visible? Can be false even - * if fb!=NULL and crtc!=NULL, due to clipping. - */ - bool visible; - - struct drm_atomic_state *state; -}; - - -/** - * struct drm_plane_funcs - driver plane control functions - */ -struct drm_plane_funcs { - /** - * @update_plane: - * - * This is the legacy entry point to enable and configure the plane for - * the given CRTC and framebuffer. It is never called to disable the - * plane, i.e. the passed-in crtc and fb paramters are never NULL. - * - * The source rectangle in frame buffer memory coordinates is given by - * the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point - * values). Devices that don't support subpixel plane coordinates can - * ignore the fractional part. - * - * The destination rectangle in CRTC coordinates is given by the - * crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values). - * Devices scale the source rectangle to the destination rectangle. If - * scaling is not supported, and the source rectangle size doesn't match - * the destination rectangle size, the driver must return a - * -EINVAL error. - * - * Drivers implementing atomic modeset should use - * drm_atomic_helper_update_plane() to implement this hook. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*update_plane)(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); - - /** - * @disable_plane: - * - * This is the legacy entry point to disable the plane. The DRM core - * calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call - * with the frame buffer ID set to 0. Disabled planes must not be - * processed by the CRTC. - * - * Drivers implementing atomic modeset should use - * drm_atomic_helper_disable_plane() to implement this hook. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*disable_plane)(struct drm_plane *plane); - - /** - * @destroy: - * - * Clean up plane resources. This is only called at driver unload time - * through drm_mode_config_cleanup() since a plane cannot be hotplugged - * in DRM. - */ - void (*destroy)(struct drm_plane *plane); - - /** - * @reset: - * - * Reset plane hardware and software state to off. This function isn't - * called by the core directly, only through drm_mode_config_reset(). - * It's not a helper hook only for historical reasons. - * - * Atomic drivers can use drm_atomic_helper_plane_reset() to reset - * atomic state using this hook. - */ - void (*reset)(struct drm_plane *plane); - - /** - * @set_property: - * - * This is the legacy entry point to update a property attached to the - * plane. - * - * Drivers implementing atomic modeset should use - * drm_atomic_helper_plane_set_property() to implement this hook. - * - * This callback is optional if the driver does not support any legacy - * driver-private properties. - * - * RETURNS: - * - * 0 on success or a negative error code on failure. - */ - int (*set_property)(struct drm_plane *plane, - struct drm_property *property, uint64_t val); - - /** - * @atomic_duplicate_state: - * - * Duplicate the current atomic state for this plane and return it. - * The core and helpers gurantee that any atomic state duplicated with - * this hook and still owned by the caller (i.e. not transferred to the - * driver by calling ->atomic_commit() from struct - * &drm_mode_config_funcs) will be cleaned up by calling the - * @atomic_destroy_state hook in this structure. - * - * Atomic drivers which don't subclass struct &drm_plane_state should use - * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the - * state structure to extend it with driver-private state should use - * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is - * duplicated in a consistent fashion across drivers. - * - * It is an error to call this hook before plane->state has been - * initialized correctly. - * - * NOTE: - * - * If the duplicate state references refcounted resources this hook must - * acquire a reference for each of them. The driver must release these - * references again in @atomic_destroy_state. - * - * RETURNS: - * - * Duplicated atomic state or NULL when the allocation failed. - */ - struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane); - - /** - * @atomic_destroy_state: - * - * Destroy a state duplicated with @atomic_duplicate_state and release - * or unreference all resources it references - */ - void (*atomic_destroy_state)(struct drm_plane *plane, - struct drm_plane_state *state); - - /** - * @atomic_set_property: - * - * Decode a driver-private property value and store the decoded value - * into the passed-in state structure. Since the atomic core decodes all - * standardized properties (even for extensions beyond the core set of - * properties which might not be implemented by all drivers) this - * requires drivers to subclass the state structure. - * - * Such driver-private properties should really only be implemented for - * truly hardware/vendor specific state. Instead it is preferred to - * standardize atomic extension and decode the properties used to expose - * such an extension in the core. - * - * Do not call this function directly, use - * drm_atomic_plane_set_property() instead. - * - * This callback is optional if the driver does not support any - * driver-private atomic properties. - * - * NOTE: - * - * This function is called in the state assembly phase of atomic - * modesets, which can be aborted for any reason (including on - * userspace's request to just check whether a configuration would be - * possible). Drivers MUST NOT touch any persistent state (hardware or - * software) or data structures except the passed in @state parameter. - * - * Also since userspace controls in which order properties are set this - * function must not do any input validation (since the state update is - * incomplete and hence likely inconsistent). Instead any such input - * validation must be done in the various atomic_check callbacks. - * - * RETURNS: - * - * 0 if the property has been found, -EINVAL if the property isn't - * implemented by the driver (which shouldn't ever happen, the core only - * asks for properties attached to this plane). No other validation is - * allowed by the driver. The core already checks that the property - * value is within the range (integer, valid enum value, ...) the driver - * set when registering the property. - */ - int (*atomic_set_property)(struct drm_plane *plane, - struct drm_plane_state *state, - struct drm_property *property, - uint64_t val); - - /** - * @atomic_get_property: - * - * Reads out the decoded driver-private property. This is used to - * implement the GETPLANE IOCTL. - * - * Do not call this function directly, use - * drm_atomic_plane_get_property() instead. - * - * This callback is optional if the driver does not support any - * driver-private atomic properties. - * - * RETURNS: - * - * 0 on success, -EINVAL if the property isn't implemented by the - * driver (which should never happen, the core only asks for - * properties attached to this plane). - */ - int (*atomic_get_property)(struct drm_plane *plane, - const struct drm_plane_state *state, - struct drm_property *property, - uint64_t *val); - /** - * @late_register: - * - * This optional hook can be used to register additional userspace - * interfaces attached to the plane like debugfs interfaces. - * It is called late in the driver load sequence from drm_dev_register(). - * Everything added from this callback should be unregistered in - * the early_unregister callback. - * - * Returns: - * - * 0 on success, or a negative error code on failure. - */ - int (*late_register)(struct drm_plane *plane); - - /** - * @early_unregister: - * - * This optional hook should be used to unregister the additional - * userspace interfaces attached to the plane from - * late_unregister(). It is called from drm_dev_unregister(), - * early in the driver unload sequence to disable userspace access - * before data structures are torndown. - */ - void (*early_unregister)(struct drm_plane *plane); -}; - -enum drm_plane_type { - DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_PRIMARY, - DRM_PLANE_TYPE_CURSOR, -}; - - -/** - * struct drm_plane - central DRM plane control structure - * @dev: DRM device this plane belongs to - * @head: for list management - * @name: human readable name, can be overwritten by the driver - * @base: base mode object - * @possible_crtcs: pipes this plane can be bound to - * @format_types: array of formats supported by this plane - * @format_count: number of formats supported - * @format_default: driver hasn't supplied supported formats for the plane - * @crtc: currently bound CRTC - * @fb: currently bound fb - * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by - * drm_mode_set_config_internal() to implement correct refcounting. - * @funcs: helper functions - * @properties: property tracking for this plane - * @type: type of plane (overlay, primary, cursor) - * @state: current atomic state for this plane - * @zpos_property: zpos property for this plane - * @helper_private: mid-layer private data - */ -struct drm_plane { - struct drm_device *dev; - struct list_head head; - - char *name; - - /** - * @mutex: - * - * Protects modeset plane state, together with the mutex of &drm_crtc - * this plane is linked to (when active, getting actived or getting - * disabled). - */ - struct drm_modeset_lock mutex; - - struct drm_mode_object base; - - uint32_t possible_crtcs; - uint32_t *format_types; - unsigned int format_count; - bool format_default; - - struct drm_crtc *crtc; - struct drm_framebuffer *fb; - - struct drm_framebuffer *old_fb; - - const struct drm_plane_funcs *funcs; - - struct drm_object_properties properties; - - enum drm_plane_type type; - - /** - * @index: Position inside the mode_config.list, can be used as an array - * index. It is invariant over the lifetime of the plane. - */ - unsigned index; - - const struct drm_plane_helper_funcs *helper_private; - - struct drm_plane_state *state; - - struct drm_property *zpos_property; -}; - -/** - * 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 - * is reference counted to allow waiters to safely wait on an event to complete, - * without holding any locks. - * - * It has 3 different events in total to allow a fine-grained synchronization - * between outstanding updates:: - * - * atomic commit thread hardware - * - * write new state into hardware ----> ... - * signal hw_done - * switch to new state on next - * ... v/hblank - * - * wait for buffers to show up ... - * - * ... send completion irq - * irq handler signals flip_done - * cleanup old buffers - * - * signal cleanup_done - * - * 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 - * and modeset state change. - * - * For an implementation of how to use this look at - * drm_atomic_helper_setup_commit() from the atomic helper library. - */ -struct drm_crtc_commit { - /** - * @crtc: - * - * DRM CRTC for this commit. - */ - struct drm_crtc *crtc; - - /** - * @ref: - * - * Reference count for this structure. Needed to allow blocking on - * completions without the risk of the completion disappearing - * meanwhile. - */ - struct kref ref; - - /** - * @flip_done: - * - * Will be signaled when the hardware has flipped to the new set of - * buffers. Signals at the same time as when the drm event for this - * 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. - */ - struct completion flip_done; - - /** - * @hw_done: - * - * Will be signalled when all hw register changes for this commit have - * been written out. Especially when disabling a pipe this can be much - * later than than @flip_done, since that can signal already when the - * screen goes black, whereas to fully shut down a pipe more register - * I/O is required. - * - * Note that this does not need to include separately reference-counted - * resources like backing storage buffer pinning, or runtime pm - * management. - */ - struct completion hw_done; - - /** - * @cleanup_done: - * - * Will be signalled after old buffers have been cleaned up by calling - * drm_atomic_helper_cleanup_planes(). Since this can only happen after - * 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. - */ - struct completion cleanup_done; - - /** - * @commit_entry: - * - * Entry on the per-CRTC commit_list. Protected by crtc->commit_lock. - */ - struct list_head commit_entry; - - /** - * @event: - * - * &drm_pending_vblank_event pointer to clean up private events. - */ - struct drm_pending_vblank_event *event; -}; - -struct __drm_planes_state { - struct drm_plane *ptr; - struct drm_plane_state *state; -}; - -struct __drm_crtcs_state { - struct drm_crtc *ptr; - struct drm_crtc_state *state; - struct drm_crtc_commit *commit; -}; - -struct __drm_connnectors_state { - struct drm_connector *ptr; - struct drm_connector_state *state; -}; - -/** - * struct drm_atomic_state - the global state object for atomic updates - * @dev: parent DRM device - * @allow_modeset: allow full modeset - * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics - * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL. - * @planes: pointer to array of structures with per-plane data - * @crtcs: pointer to array of CRTC pointers - * @num_connector: size of the @connectors and @connector_states arrays - * @connectors: pointer to array of structures with per-connector data - * @acquire_ctx: acquire context for this atomic modeset state update - */ -struct drm_atomic_state { - struct drm_device *dev; - bool allow_modeset : 1; - bool legacy_cursor_update : 1; - bool legacy_set_config : 1; - struct __drm_planes_state *planes; - struct __drm_crtcs_state *crtcs; - int num_connector; - struct __drm_connnectors_state *connectors; - - struct drm_modeset_acquire_ctx *acquire_ctx; - - /** - * @commit_work: - * - * Work item which can be used by the driver or helpers to execute the - * commit without blocking. - */ - struct work_struct commit_work; -}; - - /** * struct drm_mode_set - new values for a CRTC config change * @fb: framebuffer to use for new config @@ -1825,20 +1307,7 @@ struct drm_mode_config { struct drm_mode_config_helper_funcs *helper_private; }; -/** - * drm_for_each_plane_mask - iterate over planes specified by bitmask - * @plane: the loop cursor - * @dev: the DRM device - * @plane_mask: bitmask of plane indices - * - * Iterate over all planes specified by bitmask. - */ -#define drm_for_each_plane_mask(plane, dev, plane_mask) \ - list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ - for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) - #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) -#define obj_to_plane(x) container_of(x, struct drm_plane, base) extern __printf(6, 7) int drm_crtc_init_with_planes(struct drm_device *dev, @@ -1873,36 +1342,6 @@ static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -extern __printf(8, 9) -int drm_universal_plane_init(struct drm_device *dev, - struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, - unsigned int format_count, - enum drm_plane_type type, - const char *name, ...); -extern int drm_plane_init(struct drm_device *dev, - struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary); -extern void drm_plane_cleanup(struct drm_plane *plane); - -/** - * drm_plane_index - find the index of a registered plane - * @plane: plane to find index for - * - * Given a registered plane, return the index of that plane within a DRM - * device's list of planes. - */ -static inline unsigned int drm_plane_index(struct drm_plane *plane) -{ - return plane->index; -} -extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); -extern void drm_plane_force_disable(struct drm_plane *plane); extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, int *hdisplay, int *vdisplay); extern int drm_crtc_force_disable(struct drm_crtc *crtc); @@ -1924,10 +1363,6 @@ extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, extern void drm_mode_put_tile_group(struct drm_device *dev, struct drm_tile_group *tg); -extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, - struct drm_property *property, - uint64_t value); - extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, unsigned int supported_rotations); extern unsigned int drm_rotation_simplify(unsigned int rotation, @@ -1945,14 +1380,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, unsigned int zpos); /* Helpers */ -static inline struct drm_plane *drm_plane_find(struct drm_device *dev, - uint32_t id) -{ - struct drm_mode_object *mo; - mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE); - return mo ? obj_to_plane(mo) : NULL; -} - static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) { @@ -1980,14 +1407,6 @@ static inline uint32_t drm_color_lut_extract(uint32_t user_input, return clamp_val(val, 0, max); } -/* Plane list iterator for legacy (overlay only) planes. */ -#define drm_for_each_legacy_plane(plane, dev) \ - list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ - for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY) - -#define drm_for_each_plane(plane, dev) \ - list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) - #define drm_for_each_crtc(crtc, dev) \ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h new file mode 100644 index 000000000000..1407715736a5 --- /dev/null +++ b/include/drm/drm_plane.h @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_PLANE_H__ +#define __DRM_PLANE_H__ + +#include +#include +#include + +struct drm_crtc; + +/** + * struct drm_plane_state - mutable plane state + * @plane: backpointer to the plane + * @crtc: currently bound CRTC, NULL if disabled + * @fb: currently bound framebuffer + * @fence: optional fence to wait for before scanning out @fb + * @crtc_x: left position of visible portion of plane on crtc + * @crtc_y: upper position of visible portion of plane on crtc + * @crtc_w: width of visible portion of plane on crtc + * @crtc_h: height of visible portion of plane on crtc + * @src_x: left position of visible portion of plane within + * plane (in 16.16) + * @src_y: upper position of visible portion of plane within + * plane (in 16.16) + * @src_w: width of visible portion of plane (in 16.16) + * @src_h: height of visible portion of plane (in 16.16) + * @rotation: rotation of the plane + * @zpos: priority of the given plane on crtc (optional) + * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1 + * where N is the number of active planes for given crtc + * @src: clipped source coordinates of the plane (in 16.16) + * @dst: clipped destination coordinates of the plane + * @visible: visibility of the plane + * @state: backpointer to global drm_atomic_state + */ +struct drm_plane_state { + struct drm_plane *plane; + + struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */ + struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */ + struct fence *fence; + + /* Signed dest location allows it to be partially off screen */ + int32_t crtc_x, crtc_y; + uint32_t crtc_w, crtc_h; + + /* Source values are 16.16 fixed point */ + uint32_t src_x, src_y; + uint32_t src_h, src_w; + + /* Plane rotation */ + unsigned int rotation; + + /* Plane zpos */ + unsigned int zpos; + unsigned int normalized_zpos; + + /* Clipped coordinates */ + struct drm_rect src, dst; + + /* + * Is the plane actually visible? Can be false even + * if fb!=NULL and crtc!=NULL, due to clipping. + */ + bool visible; + + struct drm_atomic_state *state; +}; + + +/** + * struct drm_plane_funcs - driver plane control functions + */ +struct drm_plane_funcs { + /** + * @update_plane: + * + * This is the legacy entry point to enable and configure the plane for + * the given CRTC and framebuffer. It is never called to disable the + * plane, i.e. the passed-in crtc and fb paramters are never NULL. + * + * The source rectangle in frame buffer memory coordinates is given by + * the src_x, src_y, src_w and src_h parameters (as 16.16 fixed point + * values). Devices that don't support subpixel plane coordinates can + * ignore the fractional part. + * + * The destination rectangle in CRTC coordinates is given by the + * crtc_x, crtc_y, crtc_w and crtc_h parameters (as integer values). + * Devices scale the source rectangle to the destination rectangle. If + * scaling is not supported, and the source rectangle size doesn't match + * the destination rectangle size, the driver must return a + * -EINVAL error. + * + * Drivers implementing atomic modeset should use + * drm_atomic_helper_update_plane() to implement this hook. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*update_plane)(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); + + /** + * @disable_plane: + * + * This is the legacy entry point to disable the plane. The DRM core + * calls this method in response to a DRM_IOCTL_MODE_SETPLANE IOCTL call + * with the frame buffer ID set to 0. Disabled planes must not be + * processed by the CRTC. + * + * Drivers implementing atomic modeset should use + * drm_atomic_helper_disable_plane() to implement this hook. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*disable_plane)(struct drm_plane *plane); + + /** + * @destroy: + * + * Clean up plane resources. This is only called at driver unload time + * through drm_mode_config_cleanup() since a plane cannot be hotplugged + * in DRM. + */ + void (*destroy)(struct drm_plane *plane); + + /** + * @reset: + * + * Reset plane hardware and software state to off. This function isn't + * called by the core directly, only through drm_mode_config_reset(). + * It's not a helper hook only for historical reasons. + * + * Atomic drivers can use drm_atomic_helper_plane_reset() to reset + * atomic state using this hook. + */ + void (*reset)(struct drm_plane *plane); + + /** + * @set_property: + * + * This is the legacy entry point to update a property attached to the + * plane. + * + * Drivers implementing atomic modeset should use + * drm_atomic_helper_plane_set_property() to implement this hook. + * + * This callback is optional if the driver does not support any legacy + * driver-private properties. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*set_property)(struct drm_plane *plane, + struct drm_property *property, uint64_t val); + + /** + * @atomic_duplicate_state: + * + * Duplicate the current atomic state for this plane and return it. + * The core and helpers gurantee that any atomic state duplicated with + * this hook and still owned by the caller (i.e. not transferred to the + * driver by calling ->atomic_commit() from struct + * &drm_mode_config_funcs) will be cleaned up by calling the + * @atomic_destroy_state hook in this structure. + * + * Atomic drivers which don't subclass struct &drm_plane_state should use + * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the + * state structure to extend it with driver-private state should use + * __drm_atomic_helper_plane_duplicate_state() to make sure shared state is + * duplicated in a consistent fashion across drivers. + * + * It is an error to call this hook before plane->state has been + * initialized correctly. + * + * NOTE: + * + * If the duplicate state references refcounted resources this hook must + * acquire a reference for each of them. The driver must release these + * references again in @atomic_destroy_state. + * + * RETURNS: + * + * Duplicated atomic state or NULL when the allocation failed. + */ + struct drm_plane_state *(*atomic_duplicate_state)(struct drm_plane *plane); + + /** + * @atomic_destroy_state: + * + * Destroy a state duplicated with @atomic_duplicate_state and release + * or unreference all resources it references + */ + void (*atomic_destroy_state)(struct drm_plane *plane, + struct drm_plane_state *state); + + /** + * @atomic_set_property: + * + * Decode a driver-private property value and store the decoded value + * into the passed-in state structure. Since the atomic core decodes all + * standardized properties (even for extensions beyond the core set of + * properties which might not be implemented by all drivers) this + * requires drivers to subclass the state structure. + * + * Such driver-private properties should really only be implemented for + * truly hardware/vendor specific state. Instead it is preferred to + * standardize atomic extension and decode the properties used to expose + * such an extension in the core. + * + * Do not call this function directly, use + * drm_atomic_plane_set_property() instead. + * + * This callback is optional if the driver does not support any + * driver-private atomic properties. + * + * NOTE: + * + * This function is called in the state assembly phase of atomic + * modesets, which can be aborted for any reason (including on + * userspace's request to just check whether a configuration would be + * possible). Drivers MUST NOT touch any persistent state (hardware or + * software) or data structures except the passed in @state parameter. + * + * Also since userspace controls in which order properties are set this + * function must not do any input validation (since the state update is + * incomplete and hence likely inconsistent). Instead any such input + * validation must be done in the various atomic_check callbacks. + * + * RETURNS: + * + * 0 if the property has been found, -EINVAL if the property isn't + * implemented by the driver (which shouldn't ever happen, the core only + * asks for properties attached to this plane). No other validation is + * allowed by the driver. The core already checks that the property + * value is within the range (integer, valid enum value, ...) the driver + * set when registering the property. + */ + int (*atomic_set_property)(struct drm_plane *plane, + struct drm_plane_state *state, + struct drm_property *property, + uint64_t val); + + /** + * @atomic_get_property: + * + * Reads out the decoded driver-private property. This is used to + * implement the GETPLANE IOCTL. + * + * Do not call this function directly, use + * drm_atomic_plane_get_property() instead. + * + * This callback is optional if the driver does not support any + * driver-private atomic properties. + * + * RETURNS: + * + * 0 on success, -EINVAL if the property isn't implemented by the + * driver (which should never happen, the core only asks for + * properties attached to this plane). + */ + int (*atomic_get_property)(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, + uint64_t *val); + /** + * @late_register: + * + * This optional hook can be used to register additional userspace + * interfaces attached to the plane like debugfs interfaces. + * It is called late in the driver load sequence from drm_dev_register(). + * Everything added from this callback should be unregistered in + * the early_unregister callback. + * + * Returns: + * + * 0 on success, or a negative error code on failure. + */ + int (*late_register)(struct drm_plane *plane); + + /** + * @early_unregister: + * + * This optional hook should be used to unregister the additional + * userspace interfaces attached to the plane from + * late_unregister(). It is called from drm_dev_unregister(), + * early in the driver unload sequence to disable userspace access + * before data structures are torndown. + */ + void (*early_unregister)(struct drm_plane *plane); +}; + +enum drm_plane_type { + DRM_PLANE_TYPE_OVERLAY, + DRM_PLANE_TYPE_PRIMARY, + DRM_PLANE_TYPE_CURSOR, +}; + + +/** + * struct drm_plane - central DRM plane control structure + * @dev: DRM device this plane belongs to + * @head: for list management + * @name: human readable name, can be overwritten by the driver + * @base: base mode object + * @possible_crtcs: pipes this plane can be bound to + * @format_types: array of formats supported by this plane + * @format_count: number of formats supported + * @format_default: driver hasn't supplied supported formats for the plane + * @crtc: currently bound CRTC + * @fb: currently bound fb + * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by + * drm_mode_set_config_internal() to implement correct refcounting. + * @funcs: helper functions + * @properties: property tracking for this plane + * @type: type of plane (overlay, primary, cursor) + * @state: current atomic state for this plane + * @zpos_property: zpos property for this plane + * @helper_private: mid-layer private data + */ +struct drm_plane { + struct drm_device *dev; + struct list_head head; + + char *name; + + /** + * @mutex: + * + * Protects modeset plane state, together with the mutex of &drm_crtc + * this plane is linked to (when active, getting actived or getting + * disabled). + */ + struct drm_modeset_lock mutex; + + struct drm_mode_object base; + + uint32_t possible_crtcs; + uint32_t *format_types; + unsigned int format_count; + bool format_default; + + struct drm_crtc *crtc; + struct drm_framebuffer *fb; + + struct drm_framebuffer *old_fb; + + const struct drm_plane_funcs *funcs; + + struct drm_object_properties properties; + + enum drm_plane_type type; + + /** + * @index: Position inside the mode_config.list, can be used as an array + * index. It is invariant over the lifetime of the plane. + */ + unsigned index; + + const struct drm_plane_helper_funcs *helper_private; + + struct drm_plane_state *state; + + struct drm_property *zpos_property; +}; + +#define obj_to_plane(x) container_of(x, struct drm_plane, base) + +extern __printf(8, 9) +int drm_universal_plane_init(struct drm_device *dev, + struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, + unsigned int format_count, + enum drm_plane_type type, + const char *name, ...); +extern int drm_plane_init(struct drm_device *dev, + struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + bool is_primary); +extern void drm_plane_cleanup(struct drm_plane *plane); + +/** + * drm_plane_index - find the index of a registered plane + * @plane: plane to find index for + * + * Given a registered plane, return the index of that plane within a DRM + * device's list of planes. + */ +static inline unsigned int drm_plane_index(struct drm_plane *plane) +{ + return plane->index; +} +extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); +extern void drm_plane_force_disable(struct drm_plane *plane); + +int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_property *property, + uint64_t value); + +/** + * drm_plane_find - find a &drm_plane + * @dev: DRM device + * @id: plane id + * + * Returns the plane with @id, NULL if it doesn't exist. Simple wrapper around + * drm_mode_object_find(). + */ +static inline struct drm_plane *drm_plane_find(struct drm_device *dev, + uint32_t id) +{ + struct drm_mode_object *mo; + mo = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_PLANE); + return mo ? obj_to_plane(mo) : NULL; +} + +/** + * drm_for_each_plane_mask - iterate over planes specified by bitmask + * @plane: the loop cursor + * @dev: the DRM device + * @plane_mask: bitmask of plane indices + * + * Iterate over all planes specified by bitmask. + */ +#define drm_for_each_plane_mask(plane, dev, plane_mask) \ + list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ + for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) + +/* Plane list iterator for legacy (overlay only) planes. */ +#define drm_for_each_legacy_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ + for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY) + +#define drm_for_each_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) + + +#endif -- cgit v1.2.3 From 532b36712ddfdca90f4db9a5365039cc08a3ff84 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Sep 2016 10:59:25 +0200 Subject: drm/doc: Polish for drm_plane.[hc] Big thing is untangling and carefully documenting the different uapi types of planes. I also sprinkled a few more cross references around to make this easier to discover. As usual, remove the kerneldoc for internal functions which are not exported. Aside: We should probably go OCD on all the ioctl handlers and consistenly give them an _ioctl postfix. Acked-by: Archit Taneja Signed-off-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474448370-32227-2-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 47 +-------------- drivers/gpu/drm/drm_crtc.c | 6 +- drivers/gpu/drm/drm_plane.c | 132 ++++++++---------------------------------- include/drm/drm_plane.h | 57 +++++++++++++++++- 4 files changed, 86 insertions(+), 156 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 33181be97151..b1029e292e5c 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -113,6 +113,9 @@ a hardware-specific ioctl to allocate suitable buffer objects. Plane Abstraction ================= +.. kernel-doc:: drivers/gpu/drm/drm_plane.c + :doc: overview + Plane Functions Reference ------------------------- @@ -189,50 +192,6 @@ allocated and zeroed by the driver, possibly as part of a larger structure, and registered with a call to :c:func:`drm_crtc_init()` with a pointer to CRTC functions. -Planes (:c:type:`struct drm_plane `) ------------------------------------------------ - -A plane represents an image source that can be blended with or overlayed -on top of a CRTC during the scanout process. Planes are associated with -a frame buffer to crop a portion of the image memory (source) and -optionally scale it to a destination size. The result is then blended -with or overlayed on top of a CRTC. - -The DRM core recognizes three types of planes: - -- DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. - Primary planes are the planes operated upon by CRTC modesetting and - flipping operations described in the page_flip hook in - :c:type:`struct drm_crtc_funcs `. -- DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC. - Cursor planes are the planes operated upon by the - DRM_IOCTL_MODE_CURSOR and DRM_IOCTL_MODE_CURSOR2 ioctls. -- DRM_PLANE_TYPE_OVERLAY represents all non-primary, non-cursor - planes. Some drivers refer to these types of planes as "sprites" - internally. - -For compatibility with legacy userspace, only overlay planes are made -available to userspace by default. Userspace clients may set the -DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate -that they wish to receive a universal plane list containing all plane -types. - -Plane Initialization -~~~~~~~~~~~~~~~~~~~~ - -To create a plane, a KMS drivers allocates and zeroes an instances of -:c:type:`struct drm_plane ` (possibly as part of a -larger structure) and registers it with a call to -:c:func:`drm_universal_plane_init()`. The function takes a -bitmask of the CRTCs that can be associated with the plane, a pointer to -the plane functions, a list of format supported formats, and the type of -plane (primary, cursor, or overlay) being initialized. - -Cursor and overlay planes are optional. All drivers should provide one -primary plane per CRTC (although this requirement may change in the -future); drivers that do not wish to provide special handling for -primary planes may make use of the helper functions described in ? to -create and register a primary plane with standard capabilities. Cleanup ------- diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index deefb24649b2..a1a02cdd8883 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -151,7 +151,11 @@ static void drm_crtc_unregister_all(struct drm_device *dev) * @funcs: callbacks for the new CRTC * @name: printf style format string for the CRTC name, or NULL for default name * - * Inits a new object created as base part of a driver crtc object. + * Inits a new object created as base part of a driver crtc object. Drivers + * should use this function instead of drm_crtc_init(), which is only provided + * for backwards compatibility with drivers which do not yet support universal + * planes). For really simple hardware which has only 1 plane look at + * drm_simple_display_pipe_init() instead. * * Returns: * Zero on success, error code on failure. diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 9003b5f835cf..c17c9c2a342e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -25,6 +25,28 @@ #include "drm_crtc_internal.h" +/** + * DOC: overview + * + * A plane represents an image source that can be blended with or overlayed on + * top of a CRTC during the scanout process. Planes take their input data from a + * &drm_framebuffer object. The plane itself specifies the cropping and scaling + * of that image, and where it is placed on the visible are of a display + * pipeline, represented by &drm_crtc. A plane can also have additional + * properties that specify how the pixels are positioned and blended, like + * rotation or Z-position. All these properties are stored in &drm_plane_state. + * + * To create a plane, a KMS drivers allocates and zeroes an instances of + * struct &drm_plane (possibly as part of a larger structure) and registers it + * with a call to drm_universal_plane_init(). + * + * Cursor and overlay planes are optional. All drivers should provide one + * primary plane per CRTC to avoid surprising userspace too much. See enum + * &drm_plane_type for a more in-depth discussion of these special uapi-relevant + * plane types. Special planes are associated with their CRTC by calling + * drm_crtc_init_with_planes(). + */ + static unsigned int drm_num_planes(struct drm_device *dev) { unsigned int num = 0; @@ -303,19 +325,6 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane, } EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); -/** - * drm_mode_getplane_res - enumerate all plane resources - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a list of plane ids to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_getplane_res(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -364,19 +373,6 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, return 0; } -/** - * drm_mode_getplane - get plane configuration - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Construct a plane configuration structure to return to the user. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_getplane(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -425,15 +421,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data, return 0; } -/** - * drm_plane_check_pixel_format - Check if the plane supports the pixel format - * @plane: plane to check for format support - * @format: the pixel format - * - * Returns: - * Zero of @plane has @format in its list of supported pixel formats, -EINVAL - * otherwise. - */ int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) { unsigned int i; @@ -552,19 +539,6 @@ static int setplane_internal(struct drm_plane *plane, return ret; } -/** - * drm_mode_setplane - configure a plane's configuration - * @dev: DRM device - * @data: ioctl data* - * @file_priv: DRM file info - * - * Set plane configuration, including placement, fb, scaling, and other factors. - * Or pass a NULL fb to disable (planes may be disabled without providing a - * valid crtc). - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_setplane(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -614,25 +588,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, plane_req->src_w, plane_req->src_h); } -/** - * drm_mode_cursor_universal - translate legacy cursor ioctl call into a - * universal plane handler call - * @crtc: crtc to update cursor for - * @req: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Legacy cursor ioctl's work directly with driver buffer handles. To - * translate legacy ioctl calls into universal plane handler calls, we need to - * wrap the native buffer handle in a drm_framebuffer. - * - * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB - * buffer with a pitch of 4*width; the universal plane interface should be used - * directly in cases where the hardware can support other buffer settings and - * userspace wants to make use of these capabilities. - * - * Returns: - * Zero on success, negative errno on failure. - */ static int drm_mode_cursor_universal(struct drm_crtc *crtc, struct drm_mode_cursor2 *req, struct drm_file *file_priv) @@ -768,19 +723,6 @@ out: } -/** - * drm_mode_cursor_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Set the cursor configuration based on user request. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -793,20 +735,10 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, return drm_mode_cursor_common(dev, &new_req, file_priv); } -/** - * drm_mode_cursor2_ioctl - set CRTC's cursor configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * +/* * Set the cursor configuration based on user request. This implements the 2nd * version of the cursor ioctl, which allows userspace to additionally specify * the hotspot of the pointer. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. */ int drm_mode_cursor2_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -816,24 +748,6 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev, return drm_mode_cursor_common(dev, req, file_priv); } -/** - * drm_mode_page_flip_ioctl - schedule an asynchronous fb update - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This schedules an asynchronous update on a given CRTC, called page flip. - * Optionally a drm event is generated to signal the completion of the event. - * Generic drivers cannot assume that a pageflip with changed framebuffer - * properties (including driver specific metadata like tiling layout) will work, - * but some drivers support e.g. pixel format changes through the pageflip - * ioctl. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 1407715736a5..256219bfd07b 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -319,10 +319,48 @@ struct drm_plane_funcs { void (*early_unregister)(struct drm_plane *plane); }; +/** + * enum drm_plane_type - uapi plane type enumeration + * + * For historical reasons not all planes are made the same. This enumeration is + * used to tell the different types of planes apart to implement the different + * uapi semantics for them. For userspace which is universal plane aware and + * which is using that atomic IOCTL there's no difference between these planes + * (beyong what the driver and hardware can support of course). + * + * For compatibility with legacy userspace, only overlay planes are made + * available to userspace by default. Userspace clients may set the + * DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that they + * wish to receive a universal plane list containing all plane types. See also + * drm_for_each_legacy_plane(). + */ enum drm_plane_type { - DRM_PLANE_TYPE_OVERLAY, + /** + * @DRM_PLANE_TYPE_PRIMARY: + * + * Primary planes represent a "main" plane for a CRTC. Primary planes + * are the planes operated upon by CRTC modesetting and flipping + * operations described in the page_flip and set_config hooks in struct + * &drm_crtc_funcs. + */ DRM_PLANE_TYPE_PRIMARY, + + /** + * @DRM_PLANE_TYPE_CURSOR: + * + * Cursor planes represent a "cursor" plane for a CRTC. Cursor planes + * are the planes operated upon by the DRM_IOCTL_MODE_CURSOR and + * DRM_IOCTL_MODE_CURSOR2 IOCTLs. + */ DRM_PLANE_TYPE_CURSOR, + + /** + * @DRM_PLANE_TYPE_OVERLAY: + * + * Overlay planes represent all non-primary, non-cursor planes. Some + * drivers refer to these types of planes as "sprites" internally. + */ + DRM_PLANE_TYPE_OVERLAY, }; @@ -458,11 +496,26 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) -/* Plane list iterator for legacy (overlay only) planes. */ +/** + * drm_for_each_legacy_plane - iterate over all planes for legacy userspace + * @plane: the loop cursor + * @dev: the DRM device + * + * Iterate over all legacy planes of @dev, excluding primary and cursor planes. + * This is useful for implementing userspace apis when userspace is not + * universal plane aware. See also enum &drm_plane_type. + */ #define drm_for_each_legacy_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY) +/** + * drm_for_each_plane - iterate over all planes + * @plane: the loop cursor + * @dev: the DRM device + * + * Iterate over all planes of @dev, include primary and cursor planes. + */ #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) -- cgit v1.2.3 From 18733802466d032cd84e57f1e4b21ecae635f192 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Sep 2016 10:59:26 +0200 Subject: drm: Conslidate blending properties in drm_blend.[hc] Imo zpos, rotatation, blending eq (once we have it) and all that should be in drm_blend.c, since those are all about how exactly the pixels are rendered onto the CRTC's visible area. Also noticed that one exported function accidentally ended up in drm_crtc_internal.h, move it to the right place too. Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474448370-32227-3-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_blend.c | 51 +++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_crtc.c | 49 ------------------------------ drivers/gpu/drm/drm_crtc_internal.h | 3 -- include/drm/drm_blend.h | 59 +++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 27 +---------------- 5 files changed, 110 insertions(+), 79 deletions(-) create mode 100644 include/drm/drm_blend.h (limited to 'include') diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 0a0b9357db35..0b8e227aa175 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -25,13 +25,62 @@ */ #include #include -#include +#include #include #include #include #include "drm_crtc_internal.h" +struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, + unsigned int supported_rotations) +{ + static const struct drm_prop_enum_list props[] = { + { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, + { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, + { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, + { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, + { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, + { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, + }; + + return drm_property_create_bitmask(dev, 0, "rotation", + props, ARRAY_SIZE(props), + supported_rotations); +} +EXPORT_SYMBOL(drm_mode_create_rotation_property); + +/** + * drm_rotation_simplify() - Try to simplify the rotation + * @rotation: Rotation to be simplified + * @supported_rotations: Supported rotations + * + * Attempt to simplify the rotation to a form that is supported. + * Eg. if the hardware supports everything except DRM_REFLECT_X + * one could call this function like this: + * + * drm_rotation_simplify(rotation, DRM_ROTATE_0 | + * DRM_ROTATE_90 | DRM_ROTATE_180 | + * DRM_ROTATE_270 | DRM_REFLECT_Y); + * + * to eliminate the DRM_ROTATE_X flag. Depending on what kind of + * transforms the hardware supports, this function may not + * be able to produce a supported transform, so the caller should + * check the result afterwards. + */ +unsigned int drm_rotation_simplify(unsigned int rotation, + unsigned int supported_rotations) +{ + if (rotation & ~supported_rotations) { + rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; + rotation = (rotation & DRM_REFLECT_MASK) | + BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); + } + + return rotation; +} +EXPORT_SYMBOL(drm_rotation_simplify); + /** * drm_plane_create_zpos_property - create mutable zpos property * @plane: drm plane diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index a1a02cdd8883..3ac81019ae6f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1222,37 +1222,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_destroy(file_priv, dev, args->handle); } -/** - * drm_rotation_simplify() - Try to simplify the rotation - * @rotation: Rotation to be simplified - * @supported_rotations: Supported rotations - * - * Attempt to simplify the rotation to a form that is supported. - * Eg. if the hardware supports everything except DRM_REFLECT_X - * one could call this function like this: - * - * drm_rotation_simplify(rotation, DRM_ROTATE_0 | - * DRM_ROTATE_90 | DRM_ROTATE_180 | - * DRM_ROTATE_270 | DRM_REFLECT_Y); - * - * to eliminate the DRM_ROTATE_X flag. Depending on what kind of - * transforms the hardware supports, this function may not - * be able to produce a supported transform, so the caller should - * check the result afterwards. - */ -unsigned int drm_rotation_simplify(unsigned int rotation, - unsigned int supported_rotations) -{ - if (rotation & ~supported_rotations) { - rotation ^= DRM_REFLECT_X | DRM_REFLECT_Y; - rotation = (rotation & DRM_REFLECT_MASK) | - BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); - } - - return rotation; -} -EXPORT_SYMBOL(drm_rotation_simplify); - /** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device @@ -1369,24 +1338,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, - unsigned int supported_rotations) -{ - static const struct drm_prop_enum_list props[] = { - { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, - { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, - { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, - { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, - { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, - { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, - }; - - return drm_property_create_bitmask(dev, 0, "rotation", - props, ARRAY_SIZE(props), - supported_rotations); -} -EXPORT_SYMBOL(drm_mode_create_rotation_property); - /** * DOC: Tile group * diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index aff42fc84658..2672f3b45d9c 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -165,9 +165,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, int drm_modeset_register_all(struct drm_device *dev); void drm_modeset_unregister_all(struct drm_device *dev); -/* drm_blend.c */ -int drm_atomic_normalize_zpos(struct drm_device *dev, - struct drm_atomic_state *state); /* drm_plane.c */ int drm_plane_register_all(struct drm_device *dev); diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h new file mode 100644 index 000000000000..868f0364e939 --- /dev/null +++ b/include/drm/drm_blend.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_BLEND_H__ +#define __DRM_BLEND_H__ + +#include +#include + +struct drm_device; +struct drm_atomic_state; + +/* + * Rotation property bits. DRM_ROTATE_ rotates the image by the + * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and + * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation + */ +#define DRM_ROTATE_0 BIT(0) +#define DRM_ROTATE_90 BIT(1) +#define DRM_ROTATE_180 BIT(2) +#define DRM_ROTATE_270 BIT(3) +#define DRM_ROTATE_MASK (DRM_ROTATE_0 | DRM_ROTATE_90 | \ + DRM_ROTATE_180 | DRM_ROTATE_270) +#define DRM_REFLECT_X BIT(4) +#define DRM_REFLECT_Y BIT(5) +#define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) + +struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, + unsigned int supported_rotations); +unsigned int drm_rotation_simplify(unsigned int rotation, + unsigned int supported_rotations); + +int drm_plane_create_zpos_property(struct drm_plane *plane, + unsigned int zpos, + unsigned int min, unsigned int max); +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); +#endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 9375e5c9cddb..8d06cabede59 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -45,6 +45,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -63,21 +64,6 @@ static inline uint64_t I642U64(int64_t val) return (uint64_t)*((uint64_t *)&val); } -/* - * Rotation property bits. DRM_ROTATE_ rotates the image by the - * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and - * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation - */ -#define DRM_ROTATE_0 BIT(0) -#define DRM_ROTATE_90 BIT(1) -#define DRM_ROTATE_180 BIT(2) -#define DRM_ROTATE_270 BIT(3) -#define DRM_ROTATE_MASK (DRM_ROTATE_0 | DRM_ROTATE_90 | \ - DRM_ROTATE_180 | DRM_ROTATE_270) -#define DRM_REFLECT_X BIT(4) -#define DRM_REFLECT_Y BIT(5) -#define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) - /* data corresponds to displayid vend/prod/serial */ struct drm_tile_group { struct kref refcount; @@ -1363,22 +1349,11 @@ extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, extern void drm_mode_put_tile_group(struct drm_device *dev, struct drm_tile_group *tg); -extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, - unsigned int supported_rotations); -extern unsigned int drm_rotation_simplify(unsigned int rotation, - unsigned int supported_rotations); extern void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, uint degamma_lut_size, bool has_ctm, uint gamma_lut_size); -int drm_plane_create_zpos_property(struct drm_plane *plane, - unsigned int zpos, - unsigned int min, unsigned int max); - -int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, - unsigned int zpos); - /* Helpers */ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) -- cgit v1.2.3 From f1e2f66ce2d9f732fec184ab885fba4b53c06016 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Sep 2016 10:59:28 +0200 Subject: drm: Extract drm_color_mgmt.[hc] For both the new degamm/lut/gamma atomic combo, and the old legacy gamma tables. Acked-by: Lionel Landwerlin Cc: Lionel Landwerlin Signed-off-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474448370-32227-5-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_color_mgmt.c | 248 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 220 -------------------------------- drivers/gpu/drm/drm_crtc_internal.h | 4 + include/drm/drm_color_mgmt.h | 56 ++++++++ include/drm/drm_crtc.h | 28 +--- 6 files changed, 310 insertions(+), 248 deletions(-) create mode 100644 drivers/gpu/drm/drm_color_mgmt.c create mode 100644 include/drm/drm_color_mgmt.h (limited to 'include') diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8eeb07a35798..25c720454017 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -15,7 +15,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ drm_encoder.o drm_mode_object.o drm_property.o \ - drm_plane.o + drm_plane.o drm_color_mgmt.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c new file mode 100644 index 000000000000..aca1b7a6397c --- /dev/null +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "drm_crtc_internal.h" + + +/** + * drm_crtc_enable_color_mgmt - enable color management properties + * @crtc: DRM CRTC + * @degamma_lut_size: the size of the degamma lut (before CSC) + * @has_ctm: whether to attach ctm_property for CSC matrix + * @gamma_lut_size: the size of the gamma lut (after CSC) + * + * This function lets the driver enable the color correction + * properties on a CRTC. This includes 3 degamma, csc and gamma + * properties that userspace can set and 2 size properties to inform + * the userspace of the lut sizes. Each of the properties are + * optional. The gamma and degamma properties are only attached if + * their size is not 0 and ctm_property is only attached if has_ctm is + * true. + */ +void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, + uint degamma_lut_size, + bool has_ctm, + uint gamma_lut_size) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (degamma_lut_size) { + drm_object_attach_property(&crtc->base, + config->degamma_lut_property, 0); + drm_object_attach_property(&crtc->base, + config->degamma_lut_size_property, + degamma_lut_size); + } + + if (has_ctm) + drm_object_attach_property(&crtc->base, + config->ctm_property, 0); + + if (gamma_lut_size) { + drm_object_attach_property(&crtc->base, + config->gamma_lut_property, 0); + drm_object_attach_property(&crtc->base, + config->gamma_lut_size_property, + gamma_lut_size); + } +} +EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); + +/** + * drm_mode_crtc_set_gamma_size - set the gamma table size + * @crtc: CRTC to set the gamma table size for + * @gamma_size: size of the gamma table + * + * Drivers which support gamma tables should set this to the supported gamma + * table size when initializing the CRTC. Currently the drm core only supports a + * fixed gamma table size. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, + int gamma_size) +{ + uint16_t *r_base, *g_base, *b_base; + int i; + + crtc->gamma_size = gamma_size; + + crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, + GFP_KERNEL); + if (!crtc->gamma_store) { + crtc->gamma_size = 0; + return -ENOMEM; + } + + r_base = crtc->gamma_store; + g_base = r_base + gamma_size; + b_base = g_base + gamma_size; + for (i = 0; i < gamma_size; i++) { + r_base[i] = i << 8; + g_base[i] = i << 8; + b_base[i] = i << 8; + } + + + return 0; +} +EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); + +/** + * drm_mode_gamma_set_ioctl - set the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Set the gamma table of a CRTC to the one passed in by the user. Userspace can + * inquire the required gamma table size through drm_mode_gamma_get_ioctl. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_gamma_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { + ret = -ENOENT; + goto out; + } + + if (crtc->funcs->gamma_set == NULL) { + ret = -ENOSYS; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { + ret = -EFAULT; + goto out; + } + + ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + +out: + drm_modeset_unlock_all(dev); + return ret; + +} + +/** + * drm_mode_gamma_get_ioctl - get the gamma table + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Copy the current gamma table into the storage provided. This also provides + * the gamma table size the driver expects, which can be used to size the + * allocated storage. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_gamma_get_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + drm_modeset_lock_all(dev); + crtc = drm_crtc_find(dev, crtc_lut->crtc_id); + if (!crtc) { + ret = -ENOENT; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { + ret = -EFAULT; + goto out; + } +out: + drm_modeset_unlock_all(dev); + return ret; +} diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3ac81019ae6f..2d7bedf28647 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -903,181 +903,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, return ret; } -/** - * drm_mode_crtc_set_gamma_size - set the gamma table size - * @crtc: CRTC to set the gamma table size for - * @gamma_size: size of the gamma table - * - * Drivers which support gamma tables should set this to the supported gamma - * table size when initializing the CRTC. Currently the drm core only supports a - * fixed gamma table size. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, - int gamma_size) -{ - uint16_t *r_base, *g_base, *b_base; - int i; - - crtc->gamma_size = gamma_size; - - crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, - GFP_KERNEL); - if (!crtc->gamma_store) { - crtc->gamma_size = 0; - return -ENOMEM; - } - - r_base = crtc->gamma_store; - g_base = r_base + gamma_size; - b_base = g_base + gamma_size; - for (i = 0; i < gamma_size; i++) { - r_base[i] = i << 8; - g_base[i] = i << 8; - b_base[i] = i << 8; - } - - - return 0; -} -EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); - -/** - * drm_mode_gamma_set_ioctl - set the gamma table - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Set the gamma table of a CRTC to the one passed in by the user. Userspace can - * inquire the required gamma table size through drm_mode_gamma_get_ioctl. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_gamma_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_crtc *crtc; - void *r_base, *g_base, *b_base; - int size; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } - - if (crtc->funcs->gamma_set == NULL) { - ret = -ENOSYS; - goto out; - } - - /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } - - size = crtc_lut->gamma_size * (sizeof(uint16_t)); - r_base = crtc->gamma_store; - if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { - ret = -EFAULT; - goto out; - } - - g_base = r_base + size; - if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { - ret = -EFAULT; - goto out; - } - - b_base = g_base + size; - if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { - ret = -EFAULT; - goto out; - } - - ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); - -out: - drm_modeset_unlock_all(dev); - return ret; - -} - -/** - * drm_mode_gamma_get_ioctl - get the gamma table - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Copy the current gamma table into the storage provided. This also provides - * the gamma table size the driver expects, which can be used to size the - * allocated storage. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_gamma_get_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_crtc_lut *crtc_lut = data; - struct drm_crtc *crtc; - void *r_base, *g_base, *b_base; - int size; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - drm_modeset_lock_all(dev); - crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } - - /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } - - size = crtc_lut->gamma_size * (sizeof(uint16_t)); - r_base = crtc->gamma_store; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { - ret = -EFAULT; - goto out; - } - - g_base = r_base + size; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { - ret = -EFAULT; - goto out; - } - - b_base = g_base + size; - if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { - ret = -EFAULT; - goto out; - } -out: - drm_modeset_unlock_all(dev); - return ret; -} - /** * drm_mode_config_reset - call ->reset callbacks * @dev: drm device @@ -1436,48 +1261,3 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, return tg; } EXPORT_SYMBOL(drm_mode_create_tile_group); - -/** - * drm_crtc_enable_color_mgmt - enable color management properties - * @crtc: DRM CRTC - * @degamma_lut_size: the size of the degamma lut (before CSC) - * @has_ctm: whether to attach ctm_property for CSC matrix - * @gamma_lut_size: the size of the gamma lut (after CSC) - * - * This function lets the driver enable the color correction - * properties on a CRTC. This includes 3 degamma, csc and gamma - * properties that userspace can set and 2 size properties to inform - * the userspace of the lut sizes. Each of the properties are - * optional. The gamma and degamma properties are only attached if - * their size is not 0 and ctm_property is only attached if has_ctm is - * true. - */ -void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, - uint degamma_lut_size, - bool has_ctm, - uint gamma_lut_size) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (degamma_lut_size) { - drm_object_attach_property(&crtc->base, - config->degamma_lut_property, 0); - drm_object_attach_property(&crtc->base, - config->degamma_lut_size_property, - degamma_lut_size); - } - - if (has_ctm) - drm_object_attach_property(&crtc->base, - config->ctm_property, 0); - - if (gamma_lut_size) { - drm_object_attach_property(&crtc->base, - config->gamma_lut_property, 0); - drm_object_attach_property(&crtc->base, - config->gamma_lut_size_property, - gamma_lut_size); - } -} -EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 2672f3b45d9c..c48ba02c5365 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -58,6 +58,10 @@ int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); + +/* drm_color_mgmt.c */ + +/* IOCTLs */ int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_gamma_set_ioctl(struct drm_device *dev, diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h new file mode 100644 index 000000000000..1e01c58bbe81 --- /dev/null +++ b/include/drm/drm_color_mgmt.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_COLOR_MGMT_H__ +#define __DRM_COLOR_MGMT_H__ + +#include + +void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, + uint degamma_lut_size, + bool has_ctm, + uint gamma_lut_size); + +int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, + int gamma_size); + +/* + * Extract a degamma/gamma LUT value provided by user and round it to the + * precision supported by the hardware. + */ +static inline uint32_t drm_color_lut_extract(uint32_t user_input, + uint32_t bit_precision) +{ + uint32_t val = user_input; + uint32_t 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); +} + + +#endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8d06cabede59..a544b7502493 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -46,6 +46,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -1337,9 +1338,6 @@ extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); -extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, - int gamma_size); - extern int drm_mode_set_config_internal(struct drm_mode_set *set); extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, @@ -1349,11 +1347,6 @@ extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, extern void drm_mode_put_tile_group(struct drm_device *dev, struct drm_tile_group *tg); -extern void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, - uint degamma_lut_size, - bool has_ctm, - uint gamma_lut_size); - /* Helpers */ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) @@ -1363,25 +1356,6 @@ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, return mo ? obj_to_crtc(mo) : NULL; } -/* - * Extract a degamma/gamma LUT value provided by user and round it to the - * precision supported by the hardware. - */ -static inline uint32_t drm_color_lut_extract(uint32_t user_input, - uint32_t bit_precision) -{ - uint32_t val = user_input; - uint32_t 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); -} - #define drm_for_each_crtc(crtc, dev) \ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) -- cgit v1.2.3 From a6acccf8ef222aa4b4622cdf82aa97e1b6700b92 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Sep 2016 10:59:29 +0200 Subject: drm/doc: Document color space handling Again move it from the unmaintainable csv into DOC free-form overview sections. v2: Types Lionel&Sean spotted. Cc: Lionel Landwerlin Reviewed-by: Sean Paul Reviewed-by: Lionel Landwerlin Signed-off-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474448370-32227-6-git-send-email-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 12 +++++++++ Documentation/gpu/kms-properties.csv | 5 ---- drivers/gpu/drm/drm_color_mgmt.c | 48 ++++++++++++++++++++++++++++++++++++ include/drm/drm_color_mgmt.h | 11 ++++++--- 4 files changed, 68 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 6be8d3359620..53b872c105d2 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -296,6 +296,18 @@ Plane Composition Properties .. kernel-doc:: drivers/gpu/drm/drm_blend.c :export: +Color Management Properties +--------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c + :doc: overview + +.. kernel-doc:: include/drm/drm_color_mgmt.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c + :export: + Existing KMS Properties ----------------------- diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index 1aa2493d1ef9..1a5729c4af65 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -24,11 +24,6 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,De ,,“suggested Y”,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an Y offset for a connector ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" }",Connector,TDB ,,“dirty”,ENUM | IMMUTABLE,"{ ""Off"", ""On"", ""Annotate"" }",Connector,TBD -,,“DEGAMMA_LUT”,BLOB,0,CRTC,DRM property to set the degamma lookup table (LUT) mapping pixel data from the framebuffer before it is given to the transformation matrix. The data is an interpreted as an array of struct drm_color_lut elements. Hardware might choose not to use the full precision of the LUT elements nor use all the elements of the LUT (for example the hardware might choose to interpolate between LUT[0] and LUT[4]). -,,“DEGAMMA_LUT_SIZE”,RANGE | IMMUTABLE,"Min=0, Max=UINT_MAX",CRTC,DRM property to gives the size of the lookup table to be set on the DEGAMMA_LUT property (the size depends on the underlying hardware). -,,“CTM”,BLOB,0,CRTC,DRM property to set the current transformation matrix (CTM) apply to pixel data after the lookup through the degamma LUT and before the lookup through the gamma LUT. The data is an interpreted as a struct drm_color_ctm. -,,“GAMMA_LUT”,BLOB,0,CRTC,DRM property to set the gamma lookup table (LUT) mapping pixel data after to the transformation matrix to data sent to the connector. The data is an interpreted as an array of struct drm_color_lut elements. Hardware might choose not to use the full precision of the LUT elements nor use all the elements of the LUT (for example the hardware might choose to interpolate between LUT[0] and LUT[4]). -,,“GAMMA_LUT_SIZE”,RANGE | IMMUTABLE,"Min=0, Max=UINT_MAX",CRTC,DRM property to gives the size of the lookup table to be set on the GAMMA_LUT property (the size depends on the underlying hardware). i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is set, the hardware will be programmed with the result of the multiplication of CTM by the limited range matrix to ensure the pixels normaly in the range 0..1.0 are remapped to the range 16/255..235/255." ,,“audio”,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } etc.",Connector,TBD diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index aca1b7a6397c..d28ffdd2b929 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -26,6 +26,54 @@ #include "drm_crtc_internal.h" +/** + * DOC: overview + * + * Color management or color space adjustments is supported through a set of 5 + * properties on the &drm_crtc object. They are set up by calling + * drm_crtc_enable_color_mgmt(). + * + * "DEGAMMA_LUT”: + * Blob property to set the degamma lookup table (LUT) mapping pixel data + * from the framebuffer before it is given to the transformation matrix. + * The data is interpreted as an array of struct &drm_color_lut elements. + * Hardware might choose not to use the full precision of the LUT elements + * nor use all the elements of the LUT (for example the hardware might + * choose to interpolate between LUT[0] and LUT[4]). + * + * “DEGAMMA_LUT_SIZE”: + * Unsinged range property to give the size of the lookup table to be set + * on the DEGAMMA_LUT property (the size depends on the underlying + * hardware). If drivers support multiple LUT sizes then they should + * publish the largest size, and sub-sample smaller sized LUTs (e.g. for + * split-gamma modes) appropriately. + * + * “CTM”: + * Blob property to set the current transformation matrix (CTM) apply to + * pixel data after the lookup through the degamma LUT and before the + * lookup through the gamma LUT. The data is interpreted as a struct + * &drm_color_ctm. + * + * “GAMMA_LUT”: + * Blob property to set the gamma lookup table (LUT) mapping pixel data + * after the transformation matrix to data sent to the connector. The + * data is interpreted as an array of struct &drm_color_lut elements. + * Hardware might choose not to use the full precision of the LUT elements + * nor use all the elements of the LUT (for example the hardware might + * choose to interpolate between LUT[0] and LUT[4]). + * + * “GAMMA_LUT_SIZE”: + * Unsigned range property to give the size of the lookup table to be set + * on the GAMMA_LUT property (the size depends on the underlying hardware). + * If drivers support multiple LUT sizes then they should publish the + * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma + * modes) appropriately. + * + * There is also support for a legacy gamma table, which is set up by calling + * drm_mode_crtc_set_gamma_size(). Drivers which support both should use + * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the + * "GAMMA_LUT" property above. + */ /** * drm_crtc_enable_color_mgmt - enable color management properties diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index 1e01c58bbe81..c767238ac9d5 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -33,9 +33,14 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); -/* - * Extract a degamma/gamma LUT value provided by user and round it to the - * precision supported by the hardware. +/** + * drm_color_lut_extract - clamp&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 uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision) -- cgit v1.2.3 From 226714dc7c6af6d0acee449eb2afce08d128edad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 23 Sep 2016 08:35:25 +0200 Subject: drm: Fix plane type uabi breakage Turns out assuming that only stuff in uabi is uabi is a bit naive, and we have a bunch of properties for which the enum values are placed in random headers. A proper fix would be to split out uapi include headers, but meanwhile sprinkle at least some warning over them. Fixes: 532b36712ddf ("drm/doc: Polish for drm_plane.[hc]") Cc: Archit Taneja Cc: Sean Paul Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474612525-9488-1-git-send-email-daniel.vetter@ffwll.ch --- include/drm/drm_blend.h | 3 +++ include/drm/drm_plane.h | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 868f0364e939..36baa175de99 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -33,6 +33,9 @@ struct drm_atomic_state; * Rotation property bits. DRM_ROTATE_ rotates the image by the * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation + * + * WARNING: These defines are UABI since they're exposed in the rotation + * property. */ #define DRM_ROTATE_0 BIT(0) #define DRM_ROTATE_90 BIT(1) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 256219bfd07b..43cf193e54d6 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -333,8 +333,19 @@ struct drm_plane_funcs { * DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that they * wish to receive a universal plane list containing all plane types. See also * drm_for_each_legacy_plane(). + * + * WARNING: The values of this enum is UABI since they're exposed in the "type" + * property. */ enum drm_plane_type { + /** + * @DRM_PLANE_TYPE_OVERLAY: + * + * Overlay planes represent all non-primary, non-cursor planes. Some + * drivers refer to these types of planes as "sprites" internally. + */ + DRM_PLANE_TYPE_OVERLAY, + /** * @DRM_PLANE_TYPE_PRIMARY: * @@ -353,14 +364,6 @@ enum drm_plane_type { * DRM_IOCTL_MODE_CURSOR2 IOCTLs. */ DRM_PLANE_TYPE_CURSOR, - - /** - * @DRM_PLANE_TYPE_OVERLAY: - * - * Overlay planes represent all non-primary, non-cursor planes. Some - * drivers refer to these types of planes as "sprites" internally. - */ - DRM_PLANE_TYPE_OVERLAY, }; -- cgit v1.2.3