From d4e6823609442953f272dd25507b82b9a3f76ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 15 Feb 2021 16:17:26 +0100 Subject: [PATCH 001/192] drm/ttm: make global mutex and use count static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only needed during device hot plug and remove and not exported. Signed-off-by: Christian König Suggested-by: Bernard Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210409110730.2958-1-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 9b787b3caeb5..1f2024164d72 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -39,8 +39,8 @@ /** * ttm_global_mutex - protecting the global state */ -DEFINE_MUTEX(ttm_global_mutex); -unsigned ttm_glob_use_count; +static DEFINE_MUTEX(ttm_global_mutex); +static unsigned ttm_glob_use_count; struct ttm_global ttm_glob; EXPORT_SYMBOL(ttm_glob); From 5690e4863930801a17ef67d279bc5306f2cf6efb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Apr 2021 16:01:36 +0200 Subject: [PATCH 002/192] drm/gem-ttm-helper: Provide helper for struct drm_driver.dumb_map_offset Provides an implementation of struct drm_driver.dumb_map_offset that can be used by TTM-based GEM drivers. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210408140139.27731-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_ttm_helper.c | 33 ++++++++++++++++++++++++++++ include/drm/drm_gem_ttm_helper.h | 5 ++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c index de28720757af..b14bed8be771 100644 --- a/drivers/gpu/drm/drm_gem_ttm_helper.c +++ b/drivers/gpu/drm/drm_gem_ttm_helper.c @@ -114,5 +114,38 @@ int drm_gem_ttm_mmap(struct drm_gem_object *gem, } EXPORT_SYMBOL(drm_gem_ttm_mmap); +/** + * drm_gem_ttm_dumb_map_offset() - Implements struct &drm_driver.dumb_map_offset + * @file: DRM file pointer. + * @dev: DRM device. + * @handle: GEM handle + * @offset: Returns the mapping's memory offset on success + * + * Provides an implementation of struct &drm_driver.dumb_map_offset for + * TTM-based GEM drivers. TTM allocates the offset internally and + * drm_gem_ttm_dumb_map_offset() returns it for dumb-buffer implementations. + * + * See struct &drm_driver.dumb_map_offset. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_ttm_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *gem; + + gem = drm_gem_object_lookup(file, handle); + if (!gem) + return -ENOENT; + + *offset = drm_vma_node_offset_addr(&gem->vma_node); + + drm_gem_object_put(gem); + + return 0; +} +EXPORT_SYMBOL(drm_gem_ttm_dumb_map_offset); + MODULE_DESCRIPTION("DRM gem ttm helpers"); MODULE_LICENSE("GPL"); diff --git a/include/drm/drm_gem_ttm_helper.h b/include/drm/drm_gem_ttm_helper.h index 7c6d874910b8..c1aa02bd4c89 100644 --- a/include/drm/drm_gem_ttm_helper.h +++ b/include/drm/drm_gem_ttm_helper.h @@ -5,8 +5,8 @@ #include -#include #include +#include #include #include @@ -24,4 +24,7 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem, int drm_gem_ttm_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma); +int drm_gem_ttm_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset); + #endif From ede0c69ceb3fa4e139ffd95083c2698880c25b6f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Apr 2021 16:01:37 +0200 Subject: [PATCH 003/192] drm/vram-helper: Use drm_gem_ttm_dumb_map_offset() VRAM helpers now use drm_gem_ttm_dumb_map_offset() to implement struct drm_driver.dumb_map_offset. v2: * update hibmc as well (kernel test robot) Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210408140139.27731-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_vram_helper.c | 48 ------------------- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 2 +- include/drm/drm_gem_vram_helper.h | 7 +-- 3 files changed, 3 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 2b7c3a07956d..797200315854 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -245,22 +245,6 @@ void drm_gem_vram_put(struct drm_gem_vram_object *gbo) } EXPORT_SYMBOL(drm_gem_vram_put); -/** - * drm_gem_vram_mmap_offset() - Returns a GEM VRAM object's mmap offset - * @gbo: the GEM VRAM object - * - * See drm_vma_node_offset_addr() for more information. - * - * Returns: - * The buffer object's offset for userspace mappings on success, or - * 0 if no offset is allocated. - */ -u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo) -{ - return drm_vma_node_offset_addr(&gbo->bo.base.vma_node); -} -EXPORT_SYMBOL(drm_gem_vram_mmap_offset); - static u64 drm_gem_vram_pg_offset(struct drm_gem_vram_object *gbo) { /* Keep TTM behavior for now, remove when drivers are audited */ @@ -638,38 +622,6 @@ int drm_gem_vram_driver_dumb_create(struct drm_file *file, } EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); -/** - * drm_gem_vram_driver_dumb_mmap_offset() - \ - Implements &struct drm_driver.dumb_mmap_offset - * @file: DRM file pointer. - * @dev: DRM device. - * @handle: GEM handle - * @offset: Returns the mapping's memory offset on success - * - * Returns: - * 0 on success, or - * a negative errno code otherwise. - */ -int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, uint64_t *offset) -{ - struct drm_gem_object *gem; - struct drm_gem_vram_object *gbo; - - gem = drm_gem_object_lookup(file, handle); - if (!gem) - return -ENOENT; - - gbo = drm_gem_vram_of_gem(gem); - *offset = drm_gem_vram_mmap_offset(gbo); - - drm_gem_object_put(gem); - - return 0; -} -EXPORT_SYMBOL(drm_gem_vram_driver_dumb_mmap_offset); - /* * Helpers for struct drm_plane_helper_funcs */ diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index abd6250d5a14..89edc796deda 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -60,7 +60,7 @@ static const struct drm_driver hibmc_driver = { .minor = 0, .debugfs_init = drm_vram_mm_debugfs_init, .dumb_create = hibmc_dumb_create, - .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, .gem_prime_mmap = drm_gem_prime_mmap, .irq_handler = hibmc_drm_interrupt, }; diff --git a/include/drm/drm_gem_vram_helper.h b/include/drm/drm_gem_vram_helper.h index 288055d397d9..27ed7e9243b9 100644 --- a/include/drm/drm_gem_vram_helper.h +++ b/include/drm/drm_gem_vram_helper.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -93,7 +94,6 @@ struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, size_t size, unsigned long pg_align); void drm_gem_vram_put(struct drm_gem_vram_object *gbo); -u64 drm_gem_vram_mmap_offset(struct drm_gem_vram_object *gbo); s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo); int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag); int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo); @@ -113,9 +113,6 @@ int drm_gem_vram_fill_create_dumb(struct drm_file *file, int drm_gem_vram_driver_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); -int drm_gem_vram_driver_dumb_mmap_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, uint64_t *offset); /* * Helpers for struct drm_plane_helper_funcs @@ -149,7 +146,7 @@ void drm_gem_vram_simple_display_pipe_cleanup_fb( #define DRM_GEM_VRAM_DRIVER \ .debugfs_init = drm_vram_mm_debugfs_init, \ .dumb_create = drm_gem_vram_driver_dumb_create, \ - .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, \ + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, \ .gem_prime_mmap = drm_gem_prime_mmap /* From 4c398f50a1fbc94d0c3615f284244dbb19e06add Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Apr 2021 16:01:38 +0200 Subject: [PATCH 004/192] drm/nouveau: Use drm_gem_ttm_dumb_map_offset() Nouveau now uses drm_gem_ttm_dumb_map_offset() to implement struct drm_driver.dumb_map_offset. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210408140139.27731-4-tzimmermann@suse.de --- drivers/gpu/drm/nouveau/nouveau_display.c | 18 ------------------ drivers/gpu/drm/nouveau/nouveau_display.h | 2 -- drivers/gpu/drm/nouveau/nouveau_drm.c | 3 ++- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index dac02c7be54d..14101bd2a0ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -838,21 +838,3 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, drm_gem_object_put(&bo->bo.base); return ret; } - -int -nouveau_display_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle, uint64_t *poffset) -{ - struct drm_gem_object *gem; - - gem = drm_gem_object_lookup(file_priv, handle); - if (gem) { - struct nouveau_bo *bo = nouveau_gem_object(gem); - *poffset = drm_vma_node_offset_addr(&bo->bo.base.vma_node); - drm_gem_object_put(gem); - return 0; - } - - return -ENOENT; -} diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 616c43427059..2ab2ddb1eadf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -58,8 +58,6 @@ bool nouveau_display_scanoutpos(struct drm_crtc *crtc, int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, struct drm_mode_create_dumb *args); -int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, - u32 handle, u64 *offset); void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 885815ea917f..9766218a99ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -1212,7 +1213,7 @@ driver_stub = { .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table, .dumb_create = nouveau_display_dumb_create, - .dumb_map_offset = nouveau_display_dumb_map_offset, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, .name = DRIVER_NAME, .desc = DRIVER_DESC, From f4268a4bf1eecb4b38353f6310e561502e04f4dd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Apr 2021 16:01:39 +0200 Subject: [PATCH 005/192] drm/qxl: Use drm_gem_ttm_dumb_map_offset() Qxl now uses drm_gem_ttm_dumb_map_offset() to implement struct drm_driver.dumb_map_offset. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210408140139.27731-5-tzimmermann@suse.de --- drivers/gpu/drm/qxl/qxl_drv.c | 3 ++- drivers/gpu/drm/qxl/qxl_drv.h | 3 --- drivers/gpu/drm/qxl/qxl_dumb.c | 17 ----------------- drivers/gpu/drm/qxl/qxl_ioctl.c | 4 ++-- drivers/gpu/drm/qxl/qxl_object.h | 5 ----- 5 files changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 1864467f1063..db92eec07d96 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -271,7 +272,7 @@ static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .dumb_create = qxl_mode_dumb_create, - .dumb_map_offset = qxl_mode_dumb_mmap, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, #if defined(CONFIG_DEBUG_FS) .debugfs_init = qxl_debugfs_init, #endif diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 6dd57cfb2e7c..20a0f3ab84ad 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -330,9 +330,6 @@ void qxl_bo_force_delete(struct qxl_device *qdev); int qxl_mode_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); -int qxl_mode_dumb_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p); /* qxl ttm */ int qxl_ttm_init(struct qxl_device *qdev); diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c index 48a58ba1db96..a635d9fdf8ac 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c @@ -69,20 +69,3 @@ int qxl_mode_dumb_create(struct drm_file *file_priv, args->handle = handle; return 0; } - -int qxl_mode_dumb_mmap(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p) -{ - struct drm_gem_object *gobj; - struct qxl_bo *qobj; - - BUG_ON(!offset_p); - gobj = drm_gem_object_lookup(file_priv, handle); - if (gobj == NULL) - return -ENOENT; - qobj = gem_to_qxl_bo(gobj); - *offset_p = qxl_bo_mmap_offset(qobj); - drm_gem_object_put(gobj); - return 0; -} diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index b6075f452b9e..38aabcbe2238 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -67,8 +67,8 @@ static int qxl_map_ioctl(struct drm_device *dev, void *data, struct qxl_device *qdev = to_qxl(dev); struct drm_qxl_map *qxl_map = data; - return qxl_mode_dumb_mmap(file_priv, &qdev->ddev, qxl_map->handle, - &qxl_map->offset); + return drm_gem_ttm_dumb_map_offset(file_priv, &qdev->ddev, qxl_map->handle, + &qxl_map->offset); } struct qxl_reloc_info { diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index ee9c29de4d3d..cee4b52b75dd 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -53,11 +53,6 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo) return bo->tbo.base.size; } -static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo) -{ - return drm_vma_node_offset_addr(&bo->tbo.base.vma_node); -} - extern int qxl_bo_create(struct qxl_device *qdev, unsigned long size, bool kernel, bool pinned, u32 domain, From a28e10ed99bcf57cbd55a6146367f7ea752af6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 9 Apr 2021 14:58:43 +0200 Subject: [PATCH 006/192] drm/ttm: fix return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function returns the number of swapped pages here. Only abort when we get a negative error code. Signed-off-by: Christian König Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210409130113.1459-1-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_tt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 7dcd3fb69495..7d479095dcf8 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -326,7 +326,7 @@ int ttm_tt_populate(struct ttm_device *bdev, ttm_dma32_pages_limit) { ret = ttm_global_swapout(ctx, GFP_KERNEL); - if (ret) + if (ret < 0) goto error; } From b057f37bb24f9c4f833549ce48a0d2d6fccba2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 9 Apr 2021 15:00:10 +0200 Subject: [PATCH 007/192] drm/ttm: re-add debugfs tt_shrink file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That got lost when we moved back to a static limit. Signed-off-by: Christian König Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20210409130113.1459-2-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_tt.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 7d479095dcf8..4d8498a3d642 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -389,6 +389,21 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) ttm->page_flags &= ~TTM_PAGE_FLAG_PRIV_POPULATED; } +#ifdef CONFIG_DEBUG_FS + +/* Test the shrinker functions and dump the result */ +static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data) +{ + struct ttm_operation_ctx ctx = { false, false }; + + seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL)); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(ttm_tt_debugfs_shrink); + +#endif + + /** * ttm_tt_mgr_init - register with the MM shrinker * @@ -396,6 +411,11 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm) */ void ttm_tt_mgr_init(unsigned long num_pages, unsigned long num_dma32_pages) { +#ifdef CONFIG_DEBUG_FS + debugfs_create_file("tt_shrink", 0400, ttm_debugfs_root, NULL, + &ttm_tt_debugfs_shrink_fops); +#endif + if (!ttm_pages_limit) ttm_pages_limit = num_pages; From 1cdb005d6ef14a45db62528806f9b47012266bcd Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Mon, 12 Apr 2021 12:53:09 +0200 Subject: [PATCH 008/192] gpu: drm: Replace bare "unsigned" with "unsigned int" Replaced the type "unsigned" with "unsigned int" because it is preferred. Issue detected by checkpatch.pl. Signed-off-by: Fabio M. De Francesco Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210412105309.27156-1-fmdefrancesco@gmail.com --- drivers/gpu/drm/drm_atomic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 5b4547e0f775..46dceb51c90f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1302,8 +1302,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) struct drm_crtc_state *new_crtc_state; struct drm_connector *conn; struct drm_connector_state *conn_state; - unsigned requested_crtc = 0; - unsigned affected_crtc = 0; + unsigned int requested_crtc = 0; + unsigned int affected_crtc = 0; int i, ret = 0; DRM_DEBUG_ATOMIC("checking %p\n", state); From 9237ec1f3b87d776638e72b26e2fe515ccafabaa Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Mon, 12 Apr 2021 14:42:14 +0200 Subject: [PATCH 009/192] drm: drm_atomic_helper.c: Replace "unsigned" with "unsigned int" Replaced "unsigned with "unsigned int" since the latter is preferred. Signed-off-by: Fabio M. De Francesco Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210412124213.4628-2-fmdefrancesco@gmail.com --- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f2b3e28d938b..cd748ff61162 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -106,7 +106,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct drm_encoder *encoder; - unsigned encoder_mask = 0; + unsigned int encoder_mask = 0; int i, ret = 0; /* @@ -609,7 +609,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_connector *connector; struct drm_connector_state *old_connector_state, *new_connector_state; int i, ret; - unsigned connectors_mask = 0; + unsigned int connectors_mask = 0; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { bool has_connectors = @@ -1478,7 +1478,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; int i, ret; - unsigned crtc_mask = 0; + unsigned int crtc_mask = 0; /* * Legacy cursor ioctls are completely unsynced, and userspace @@ -2575,7 +2575,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); struct drm_plane *plane; - unsigned plane_mask; + unsigned int plane_mask; plane_mask = old_crtc_state->plane_mask; plane_mask |= new_crtc_state->plane_mask; From 1758f403d8faff5d3ddb98f43c4adc4f715f9236 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Mon, 12 Apr 2021 14:42:16 +0200 Subject: [PATCH 010/192] drm: drm_atomic_helper.c: Correct comments format Corrected comments format in accordance to the Linux style guides. Signed-off-by: Fabio M. De Francesco Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20210412124213.4628-3-fmdefrancesco@gmail.com --- drivers/gpu/drm/drm_atomic_helper.c | 32 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index cd748ff61162..bc3487964fb5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1018,8 +1018,10 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) struct drm_encoder *encoder; struct drm_bridge *bridge; - /* Shut down everything that's in the changeset and currently - * still on. So need to check the old, saved state. */ + /* + * Shut down everything that's in the changeset and currently + * still on. So need to check the old, saved state. + */ if (!old_conn_state->crtc) continue; @@ -1409,7 +1411,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); * @dev: DRM device * @state: atomic state object with old state structures * @pre_swap: If true, do an interruptible wait, and @state is the new state. - * Otherwise @state is the old state. + * Otherwise @state is the old state. * * For implicit sync, driver should fish the exclusive fence out from the * incoming fb's and stash it in the drm_plane_state. This is called after @@ -1953,8 +1955,10 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock) list_for_each_entry(commit, &crtc->commit_list, commit_entry) { if (i == 0) { completed = try_wait_for_completion(&commit->flip_done); - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (!completed && nonblock) { spin_unlock(&crtc->commit_lock); DRM_DEBUG_ATOMIC("[CRTC:%d:%s] busy with a previous commit\n", @@ -2103,9 +2107,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, if (ret) return ret; - /* Drivers only send out events when at least either current or + /* + * Drivers only send out events when at least either current or * new CRTC state is active. Complete right away if everything - * stays off. */ + * stays off. + */ if (!old_crtc_state->active && !new_crtc_state->active) { complete_all(&commit->flip_done); continue; @@ -2137,8 +2143,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, } for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) { - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (nonblock && old_conn_state->commit && !try_wait_for_completion(&old_conn_state->commit->flip_done)) { DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] busy with a previous commit\n", @@ -2156,8 +2164,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, } for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { - /* Userspace is not allowed to get ahead of the previous - * commit with nonblocking ones. */ + /* + * Userspace is not allowed to get ahead of the previous + * commit with nonblocking ones. + */ if (nonblock && old_plane_state->commit && !try_wait_for_completion(&old_plane_state->commit->flip_done)) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] busy with a previous commit\n", From 7169d082e7e623209081318abc26b0d899a4e63f Mon Sep 17 00:00:00 2001 From: Parshuram Thombare Date: Sat, 10 Apr 2021 20:15:08 +0200 Subject: [PATCH 011/192] dt-bindings: drm/bridge: MHDP8546 bridge binding changes for HDCP Add binding changes for HDCP in the MHDP8546 DPI/DP bridge binding. Signed-off-by: Parshuram Thombare Reviewed-by: Rob Herring Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/1618078508-30466-1-git-send-email-pthombar@cadence.com --- .../bindings/display/bridge/cdns,mhdp8546.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml index 63427878715e..2333fdbe9296 100644 --- a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8546.yaml @@ -18,7 +18,7 @@ properties: reg: minItems: 1 - maxItems: 2 + maxItems: 3 items: - description: Register block of mhdptx apb registers up to PHY mapped area (AUX_CONFIG_P). @@ -26,13 +26,16 @@ properties: included in the associated PHY. - description: Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI J7 SoCs. + - description: + Register block of mhdptx sapb registers. reg-names: minItems: 1 - maxItems: 2 + maxItems: 3 items: - const: mhdptx - const: j721e-intg + - const: mhdptx-sapb clocks: maxItems: 1 @@ -99,14 +102,18 @@ allOf: properties: reg: minItems: 2 + maxItems: 3 reg-names: minItems: 2 + maxItems: 3 else: properties: reg: - maxItems: 1 + minItems: 1 + maxItems: 2 reg-names: - maxItems: 1 + minItems: 1 + maxItems: 2 required: - compatible From 6a3608eae6d33a478a29348eb5e9ca330a528ae6 Mon Sep 17 00:00:00 2001 From: Parshuram Thombare Date: Sat, 10 Apr 2021 20:15:42 +0200 Subject: [PATCH 012/192] drm: bridge: cdns-mhdp8546: Enable HDCP This patch enable HDCP in MHDP driver. Signed-off-by: Parshuram Thombare Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/1618078542-30679-1-git-send-email-pthombar@cadence.com --- drivers/gpu/drm/bridge/cadence/Makefile | 2 +- .../drm/bridge/cadence/cdns-mhdp8546-core.c | 128 +++- .../drm/bridge/cadence/cdns-mhdp8546-core.h | 22 + .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 570 ++++++++++++++++++ .../drm/bridge/cadence/cdns-mhdp8546-hdcp.h | 92 +++ 5 files changed, 801 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile index 8f647991b374..4d2db8df1bc6 100644 --- a/drivers/gpu/drm/bridge/cadence/Makefile +++ b/drivers/gpu/drm/bridge/cadence/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o -cdns-mhdp8546-y := cdns-mhdp8546-core.o +cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 989a05bc8197..01e95466502a 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,7 @@ #include #include "cdns-mhdp8546-core.h" - +#include "cdns-mhdp8546-hdcp.h" #include "cdns-mhdp8546-j721e.h" static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) @@ -1614,10 +1615,51 @@ enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn, return MODE_OK; } +static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct cdns_mhdp_device *mhdp = connector_to_mhdp(conn); + struct drm_connector_state *old_state, *new_state; + struct drm_crtc_state *crtc_state; + u64 old_cp, new_cp; + + if (!mhdp->hdcp_supported) + return 0; + + old_state = drm_atomic_get_old_connector_state(state, conn); + new_state = drm_atomic_get_new_connector_state(state, conn); + old_cp = old_state->content_protection; + new_cp = new_state->content_protection; + + if (old_state->hdcp_content_type != new_state->hdcp_content_type && + new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + goto mode_changed; + } + + if (!new_state->crtc) { + if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + return 0; + } + + if (old_cp == new_cp || + (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED && + new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) + return 0; + +mode_changed: + crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); + crtc_state->mode_changed = true; + + return 0; +} + static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = { .detect_ctx = cdns_mhdp_connector_detect, .get_modes = cdns_mhdp_get_modes, .mode_valid = cdns_mhdp_mode_valid, + .atomic_check = cdns_mhdp_connector_atomic_check, }; static const struct drm_connector_funcs cdns_mhdp_conn_funcs = { @@ -1662,7 +1704,10 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) return ret; } - return 0; + if (mhdp->hdcp_supported) + ret = drm_connector_attach_content_protection_property(conn, true); + + return ret; } static int cdns_mhdp_attach(struct drm_bridge *bridge, @@ -1957,6 +2002,15 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, if (WARN_ON(!conn_state)) goto out; + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_DESIRED) { + mutex_unlock(&mhdp->link_mutex); + cdns_mhdp_hdcp_enable(mhdp, conn_state->hdcp_content_type); + mutex_lock(&mhdp->link_mutex); + } + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); if (WARN_ON(!crtc_state)) goto out; @@ -2000,6 +2054,9 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, mutex_lock(&mhdp->link_mutex); + if (mhdp->hdcp_supported) + cdns_mhdp_hdcp_disable(mhdp); + mhdp->bridge_enabled = false; cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); resp &= ~CDNS_DP_FRAMER_EN; @@ -2288,7 +2345,6 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data) struct cdns_mhdp_device *mhdp = data; u32 apb_stat, sw_ev0; bool bridge_attached; - int ret; apb_stat = readl(mhdp->regs + CDNS_APB_INT_STATUS); if (!(apb_stat & CDNS_APB_INT_MASK_SW_EVENT_INT)) @@ -2307,20 +2363,54 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data) spin_unlock(&mhdp->start_lock); if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD)) { - ret = cdns_mhdp_update_link_status(mhdp); - if (mhdp->connector.dev) { - if (ret < 0) - schedule_work(&mhdp->modeset_retry_work); - else - drm_kms_helper_hotplug_event(mhdp->bridge.dev); - } else { - drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); - } + schedule_work(&mhdp->hpd_work); + } + + if (sw_ev0 & ~CDNS_DPTX_HPD) { + mhdp->sw_events |= (sw_ev0 & ~CDNS_DPTX_HPD); + wake_up(&mhdp->sw_events_wq); } return IRQ_HANDLED; } +u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, u32 event) +{ + u32 ret; + + ret = wait_event_timeout(mhdp->sw_events_wq, + mhdp->sw_events & event, + msecs_to_jiffies(500)); + if (!ret) { + dev_dbg(mhdp->dev, "SW event 0x%x timeout\n", event); + goto sw_event_out; + } + + ret = mhdp->sw_events; + mhdp->sw_events &= ~event; + +sw_event_out: + return ret; +} + +static void cdns_mhdp_hpd_work(struct work_struct *work) +{ + struct cdns_mhdp_device *mhdp = container_of(work, + struct cdns_mhdp_device, + hpd_work); + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); + if (mhdp->connector.dev) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + } else { + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); + } +} + static int cdns_mhdp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2356,6 +2446,15 @@ static int cdns_mhdp_probe(struct platform_device *pdev) return PTR_ERR(mhdp->regs); } + mhdp->sapb_regs = devm_platform_ioremap_resource_byname(pdev, "mhdptx-sapb"); + if (IS_ERR(mhdp->sapb_regs)) { + mhdp->hdcp_supported = false; + dev_warn(dev, + "Failed to get SAPB memory resource, HDCP not supported\n"); + } else { + mhdp->hdcp_supported = true; + } + mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node, 0); if (IS_ERR(mhdp->phy)) { dev_err(dev, "no PHY configured\n"); @@ -2430,13 +2529,18 @@ static int cdns_mhdp_probe(struct platform_device *pdev) /* Initialize the work for modeset in case of link train failure */ INIT_WORK(&mhdp->modeset_retry_work, cdns_mhdp_modeset_retry_fn); + INIT_WORK(&mhdp->hpd_work, cdns_mhdp_hpd_work); init_waitqueue_head(&mhdp->fw_load_wq); + init_waitqueue_head(&mhdp->sw_events_wq); ret = cdns_mhdp_load_firmware(mhdp); if (ret) goto phy_exit; + if (mhdp->hdcp_supported) + cdns_mhdp_hdcp_init(mhdp); + drm_bridge_add(&mhdp->bridge); return 0; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h index 5897a85e3159..c74439d0b1a7 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h @@ -47,6 +47,10 @@ struct phy; #define CDNS_SW_EVENT0 0x00044 #define CDNS_DPTX_HPD BIT(0) +#define CDNS_HDCP_TX_STATUS BIT(4) +#define CDNS_HDCP2_TX_IS_KM_STORED BIT(5) +#define CDNS_HDCP2_TX_STORE_KM BIT(6) +#define CDNS_HDCP_TX_IS_RCVR_ID_VALID BIT(7) #define CDNS_SW_EVENT1 0x00048 #define CDNS_SW_EVENT2 0x0004c @@ -339,8 +343,17 @@ struct cdns_mhdp_platform_info { #define to_cdns_mhdp_bridge_state(s) \ container_of(s, struct cdns_mhdp_bridge_state, base) +struct cdns_mhdp_hdcp { + struct delayed_work check_work; + struct work_struct prop_work; + struct mutex mutex; /* mutex to protect hdcp.value */ + u32 value; + u8 hdcp_content_type; +}; + struct cdns_mhdp_device { void __iomem *regs; + void __iomem *sapb_regs; void __iomem *j721e_regs; struct device *dev; @@ -392,9 +405,18 @@ struct cdns_mhdp_device { /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work; + struct work_struct hpd_work; + + wait_queue_head_t sw_events_wq; + u32 sw_events; + + struct cdns_mhdp_hdcp hdcp; + bool hdcp_supported; }; #define connector_to_mhdp(x) container_of(x, struct cdns_mhdp_device, connector) #define bridge_to_mhdp(x) container_of(x, struct cdns_mhdp_device, bridge) +u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, uint32_t event); + #endif diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c new file mode 100644 index 000000000000..fccd6fbcc257 --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Cadence MHDP8546 DP bridge driver. + * + * Copyright (C) 2020 Cadence Design Systems, Inc. + * + */ + +#include +#include + +#include + +#include + +#include "cdns-mhdp8546-hdcp.h" + +static int cdns_mhdp_secure_mailbox_read(struct cdns_mhdp_device *mhdp) +{ + int ret, empty; + + WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); + + ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_EMPTY, + empty, !empty, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + return readl(mhdp->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff; +} + +static int cdns_mhdp_secure_mailbox_write(struct cdns_mhdp_device *mhdp, + u8 val) +{ + int ret, full; + + WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); + + ret = readx_poll_timeout(readl, mhdp->sapb_regs + CDNS_MAILBOX_FULL, + full, !full, MAILBOX_RETRY_US, + MAILBOX_TIMEOUT_US); + if (ret < 0) + return ret; + + writel(val, mhdp->sapb_regs + CDNS_MAILBOX_TX_DATA); + + return 0; +} + +static int cdns_mhdp_secure_mailbox_recv_header(struct cdns_mhdp_device *mhdp, + u8 module_id, + u8 opcode, + u16 req_size) +{ + u32 mbox_size, i; + u8 header[4]; + int ret; + + /* read the header of the message */ + for (i = 0; i < sizeof(header); i++) { + ret = cdns_mhdp_secure_mailbox_read(mhdp); + if (ret < 0) + return ret; + + header[i] = ret; + } + + mbox_size = get_unaligned_be16(header + 2); + + if (opcode != header[0] || module_id != header[1] || + (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) { + for (i = 0; i < mbox_size; i++) + if (cdns_mhdp_secure_mailbox_read(mhdp) < 0) + break; + return -EINVAL; + } + + return 0; +} + +static int cdns_mhdp_secure_mailbox_recv_data(struct cdns_mhdp_device *mhdp, + u8 *buff, u16 buff_size) +{ + int ret; + u32 i; + + for (i = 0; i < buff_size; i++) { + ret = cdns_mhdp_secure_mailbox_read(mhdp); + if (ret < 0) + return ret; + + buff[i] = ret; + } + + return 0; +} + +static int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_device *mhdp, + u8 module_id, + u8 opcode, + u16 size, + u8 *message) +{ + u8 header[4]; + int ret; + u32 i; + + header[0] = opcode; + header[1] = module_id; + put_unaligned_be16(size, header + 2); + + for (i = 0; i < sizeof(header); i++) { + ret = cdns_mhdp_secure_mailbox_write(mhdp, header[i]); + if (ret) + return ret; + } + + for (i = 0; i < size; i++) { + ret = cdns_mhdp_secure_mailbox_write(mhdp, message[i]); + if (ret) + return ret; + } + + return 0; +} + +static int cdns_mhdp_hdcp_get_status(struct cdns_mhdp_device *mhdp, + u16 *hdcp_port_status) +{ + u8 hdcp_status[HDCP_STATUS_SIZE]; + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_STATUS_CHANGE, 0, NULL); + if (ret) + goto err_get_hdcp_status; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_STATUS_CHANGE, + sizeof(hdcp_status)); + if (ret) + goto err_get_hdcp_status; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_status, + sizeof(hdcp_status)); + if (ret) + goto err_get_hdcp_status; + + *hdcp_port_status = ((u16)(hdcp_status[0] << 8) | hdcp_status[1]); + +err_get_hdcp_status: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static u8 cdns_mhdp_hdcp_handle_status(struct cdns_mhdp_device *mhdp, + u16 status) +{ + u8 err = GET_HDCP_PORT_STS_LAST_ERR(status); + + if (err) + dev_dbg(mhdp->dev, "HDCP Error = %d", err); + + return err; +} + +static int cdns_mhdp_hdcp_rx_id_valid_response(struct cdns_mhdp_device *mhdp, + u8 valid) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_RESPOND_RECEIVER_ID_VALID, + 1, &valid); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_rx_id_valid(struct cdns_mhdp_device *mhdp, + u8 *recv_num, u8 *hdcp_rx_id) +{ + u8 rec_id_hdr[2]; + u8 status; + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_IS_REC_ID_VALID, 0, NULL); + if (ret) + goto err_rx_id_valid; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_IS_REC_ID_VALID, + sizeof(status)); + if (ret) + goto err_rx_id_valid; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, rec_id_hdr, 2); + if (ret) + goto err_rx_id_valid; + + *recv_num = rec_id_hdr[0]; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, hdcp_rx_id, 5 * *recv_num); + +err_rx_id_valid: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_km_stored_resp(struct cdns_mhdp_device *mhdp, + u32 size, u8 *km) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_RESPOND_KM, size, km); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_tx_is_km_stored(struct cdns_mhdp_device *mhdp, + u8 *resp, u32 size) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_IS_KM_STORED, 0, NULL); + if (ret) + goto err_is_km_stored; + + ret = cdns_mhdp_secure_mailbox_recv_header(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_IS_KM_STORED, + size); + if (ret) + goto err_is_km_stored; + + ret = cdns_mhdp_secure_mailbox_recv_data(mhdp, resp, size); +err_is_km_stored: + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp, + u8 hdcp_cfg) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP_TRAN_CONFIGURATION, 1, &hdcp_cfg); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +static int cdns_mhdp_hdcp_set_config(struct cdns_mhdp_device *mhdp, + u8 hdcp_config, bool enable) +{ + u16 hdcp_port_status; + u32 ret_event; + u8 hdcp_cfg; + int ret; + + hdcp_cfg = hdcp_config | (enable ? 0x04 : 0) | + (HDCP_CONTENT_TYPE_0 << 3); + cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg); + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); + if (!ret_event) + return -1; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + + return 0; +} + +static int cdns_mhdp_hdcp_auth_check(struct cdns_mhdp_device *mhdp) +{ + u16 hdcp_port_status; + u32 ret_event; + int ret; + + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, CDNS_HDCP_TX_STATUS); + if (!ret_event) + return -1; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + + if (hdcp_port_status & 1) { + dev_dbg(mhdp->dev, "Authentication completed successfully!\n"); + return 0; + } + + dev_dbg(mhdp->dev, "Authentication failed\n"); + + return -1; +} + +static int cdns_mhdp_hdcp_check_receviers(struct cdns_mhdp_device *mhdp) +{ + u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES]; + u8 hdcp_num_rec; + u32 ret_event; + + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, + CDNS_HDCP_TX_IS_RCVR_ID_VALID); + if (!ret_event) + return -1; + + hdcp_num_rec = 0; + memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id)); + cdns_mhdp_hdcp_rx_id_valid(mhdp, &hdcp_num_rec, (u8 *)hdcp_rec_id); + cdns_mhdp_hdcp_rx_id_valid_response(mhdp, 1); + + return 0; +} + +static int cdns_mhdp_hdcp_auth_22(struct cdns_mhdp_device *mhdp) +{ + u8 resp[HDCP_STATUS_SIZE]; + u16 hdcp_port_status; + u32 ret_event; + int ret; + + dev_dbg(mhdp->dev, "HDCP: Start 2.2 Authentication\n"); + ret_event = cdns_mhdp_wait_for_sw_event(mhdp, + CDNS_HDCP2_TX_IS_KM_STORED); + if (!ret_event) + return -1; + + if (ret_event & CDNS_HDCP_TX_STATUS) { + mhdp->sw_events &= ~CDNS_HDCP_TX_STATUS; + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (ret || cdns_mhdp_hdcp_handle_status(mhdp, hdcp_port_status)) + return -1; + } + + cdns_mhdp_hdcp_tx_is_km_stored(mhdp, resp, sizeof(resp)); + cdns_mhdp_hdcp_km_stored_resp(mhdp, 0, NULL); + + if (cdns_mhdp_hdcp_check_receviers(mhdp)) + return -1; + + return 0; +} + +static inline int cdns_mhdp_hdcp_auth_14(struct cdns_mhdp_device *mhdp) +{ + dev_dbg(mhdp->dev, "HDCP: Starting 1.4 Authentication\n"); + return cdns_mhdp_hdcp_check_receviers(mhdp); +} + +static int cdns_mhdp_hdcp_auth(struct cdns_mhdp_device *mhdp, + u8 hdcp_config) +{ + int ret; + + ret = cdns_mhdp_hdcp_set_config(mhdp, hdcp_config, true); + if (ret) + goto auth_failed; + + if (hdcp_config == HDCP_TX_1) + ret = cdns_mhdp_hdcp_auth_14(mhdp); + else + ret = cdns_mhdp_hdcp_auth_22(mhdp); + + if (ret) + goto auth_failed; + + ret = cdns_mhdp_hdcp_auth_check(mhdp); + if (ret) + ret = cdns_mhdp_hdcp_auth_check(mhdp); + +auth_failed: + return ret; +} + +static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) +{ + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", + mhdp->connector.name, mhdp->connector.base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + + return ret; +} + +static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) +{ + int ret, tries = 3; + u32 i; + + for (i = 0; i < tries; i++) { + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0 || + content_type == DRM_MODE_HDCP_CONTENT_TYPE1) { + ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_2); + if (!ret) + return 0; + _cdns_mhdp_hdcp_disable(mhdp); + } + + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) { + ret = cdns_mhdp_hdcp_auth(mhdp, HDCP_TX_1); + if (!ret) + return 0; + _cdns_mhdp_hdcp_disable(mhdp); + } + } + + dev_err(mhdp->dev, "HDCP authentication failed (%d tries/%d)\n", + tries, ret); + + return ret; +} + +static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) +{ + u16 hdcp_port_status; + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + + ret = cdns_mhdp_hdcp_get_status(mhdp, &hdcp_port_status); + if (!ret && hdcp_port_status & HDCP_PORT_STS_AUTH) + goto out; + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", + mhdp->connector.name, mhdp->connector.base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&mhdp->hdcp.prop_work); + goto out; + } + + ret = _cdns_mhdp_hdcp_enable(mhdp, mhdp->hdcp.hdcp_content_type); + if (ret) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&mhdp->hdcp.prop_work); + } +out: + mutex_unlock(&mhdp->hdcp.mutex); + return ret; +} + +static void cdns_mhdp_hdcp_check_work(struct work_struct *work) +{ + struct delayed_work *d_work = to_delayed_work(work); + struct cdns_mhdp_hdcp *hdcp = container_of(d_work, + struct cdns_mhdp_hdcp, + check_work); + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); + + if (!cdns_mhdp_hdcp_check_link(mhdp)) + schedule_delayed_work(&hdcp->check_work, + DRM_HDCP_CHECK_PERIOD_MS); +} + +static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) +{ + struct cdns_mhdp_hdcp *hdcp = container_of(work, + struct cdns_mhdp_hdcp, + prop_work); + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); + struct drm_device *dev = mhdp->connector.dev; + struct drm_connector_state *state; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + state = mhdp->connector.state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); + drm_modeset_unlock(&dev->mode_config.connection_mutex); +} + +int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_GENERAL, + HDCP_GENERAL_SET_LC_128, + 16, val); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +int +cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp, + struct cdns_hdcp_tx_public_key_param *val) +{ + int ret; + + mutex_lock(&mhdp->mbox_mutex); + ret = cdns_mhdp_secure_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, + HDCP2X_TX_SET_PUBLIC_KEY_PARAMS, + sizeof(*val), (u8 *)val); + mutex_unlock(&mhdp->mbox_mutex); + + return ret; +} + +int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) +{ + int ret; + + mutex_lock(&mhdp->hdcp.mutex); + ret = _cdns_mhdp_hdcp_enable(mhdp, content_type); + if (ret) + goto out; + + mhdp->hdcp.hdcp_content_type = content_type; + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&mhdp->hdcp.prop_work); + schedule_delayed_work(&mhdp->hdcp.check_work, + DRM_HDCP_CHECK_PERIOD_MS); +out: + mutex_unlock(&mhdp->hdcp.mutex); + return ret; +} + +int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) +{ + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + schedule_work(&mhdp->hdcp.prop_work); + ret = _cdns_mhdp_hdcp_disable(mhdp); + } + mutex_unlock(&mhdp->hdcp.mutex); + cancel_delayed_work_sync(&mhdp->hdcp.check_work); + + return ret; +} + +void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp) +{ + INIT_DELAYED_WORK(&mhdp->hdcp.check_work, cdns_mhdp_hdcp_check_work); + INIT_WORK(&mhdp->hdcp.prop_work, cdns_mhdp_hdcp_prop_work); + mutex_init(&mhdp->hdcp.mutex); +} diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h new file mode 100644 index 000000000000..334c0b8b0d4f --- /dev/null +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Cadence MHDP8546 DP bridge driver. + * + * Copyright (C) 2020 Cadence Design Systems, Inc. + * + */ + +#ifndef CDNS_MHDP8546_HDCP_H +#define CDNS_MHDP8546_HDCP_H + +#include "cdns-mhdp8546-core.h" + +#define HDCP_MAX_RECEIVERS 32 +#define HDCP_RECEIVER_ID_SIZE_BYTES 5 +#define HDCP_STATUS_SIZE 0x5 +#define HDCP_PORT_STS_AUTH 0x1 +#define HDCP_PORT_STS_LAST_ERR_SHIFT 0x5 +#define HDCP_PORT_STS_LAST_ERR_MASK (0x0F << 5) +#define GET_HDCP_PORT_STS_LAST_ERR(__sts__) \ + (((__sts__) & HDCP_PORT_STS_LAST_ERR_MASK) >> \ + HDCP_PORT_STS_LAST_ERR_SHIFT) + +#define HDCP_CONFIG_1_4 BIT(0) /* use HDCP 1.4 only */ +#define HDCP_CONFIG_2_2 BIT(1) /* use HDCP 2.2 only */ +/* use All HDCP versions */ +#define HDCP_CONFIG_ALL (BIT(0) | BIT(1)) +#define HDCP_CONFIG_NONE 0 + +enum { + HDCP_GENERAL_SET_LC_128, + HDCP_SET_SEED, +}; + +enum { + HDCP_TRAN_CONFIGURATION, + HDCP2X_TX_SET_PUBLIC_KEY_PARAMS, + HDCP2X_TX_SET_DEBUG_RANDOM_NUMBERS, + HDCP2X_TX_RESPOND_KM, + HDCP1_TX_SEND_KEYS, + HDCP1_TX_SEND_RANDOM_AN, + HDCP_TRAN_STATUS_CHANGE, + HDCP2X_TX_IS_KM_STORED, + HDCP2X_TX_STORE_KM, + HDCP_TRAN_IS_REC_ID_VALID, + HDCP_TRAN_RESPOND_RECEIVER_ID_VALID, + HDCP_TRAN_TEST_KEYS, + HDCP2X_TX_SET_KM_KEY_PARAMS, + HDCP_NUM_OF_SUPPORTED_MESSAGES +}; + +enum { + HDCP_CONTENT_TYPE_0, + HDCP_CONTENT_TYPE_1, +}; + +#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16) + +#define HDCP_PAIRING_R_ID 5 +#define HDCP_PAIRING_M_LEN 16 +#define HDCP_KM_LEN 16 +#define HDCP_PAIRING_M_EKH 16 + +struct cdns_hdcp_pairing_data { + u8 receiver_id[HDCP_PAIRING_R_ID]; + u8 m[HDCP_PAIRING_M_LEN]; + u8 km[HDCP_KM_LEN]; + u8 ekh[HDCP_PAIRING_M_EKH]; +}; + +enum { + HDCP_TX_2, + HDCP_TX_1, + HDCP_TX_BOTH, +}; + +#define DLP_MODULUS_N 384 +#define DLP_E 3 + +struct cdns_hdcp_tx_public_key_param { + u8 N[DLP_MODULUS_N]; + u8 E[DLP_E]; +}; + +int cdns_mhdp_hdcp_set_public_key_param(struct cdns_mhdp_device *mhdp, + struct cdns_hdcp_tx_public_key_param *val); +int cdns_mhdp_hdcp_set_lc(struct cdns_mhdp_device *mhdp, u8 *val); +int cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type); +int cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp); +void cdns_mhdp_hdcp_init(struct cdns_mhdp_device *mhdp); + +#endif From d510c88cfbb294d2b1e2d0b71576e9b79d0e2e83 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 14 Apr 2021 01:05:08 +0800 Subject: [PATCH 013/192] efifb: Check efifb_pci_dev before using it On some platforms like Hyper-V and RPi4 with UEFI firmware, efifb is not a PCI device. So make sure efifb_pci_dev is found before using it. Fixes: a6c0fd3d5a8b ("efifb: Ensure graphics device for efifb stays at PCI D0") BugLink: https://bugs.launchpad.net/bugs/1922403 Signed-off-by: Kai-Heng Feng Signed-off-by: Alex Deucher Reviewed-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20210413170508.968148-1-kai.heng.feng@canonical.com --- drivers/video/fbdev/efifb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index f58a545b3bf3..8ea8f079cde2 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -575,7 +575,8 @@ static int efifb_probe(struct platform_device *dev) goto err_fb_dealoc; } fb_info(info, "%s frame buffer device\n", info->fix.id); - pm_runtime_get_sync(&efifb_pci_dev->dev); + if (efifb_pci_dev) + pm_runtime_get_sync(&efifb_pci_dev->dev); return 0; err_fb_dealoc: @@ -602,7 +603,8 @@ static int efifb_remove(struct platform_device *pdev) unregister_framebuffer(info); sysfs_remove_groups(&pdev->dev.kobj, efifb_groups); framebuffer_release(info); - pm_runtime_put(&efifb_pci_dev->dev); + if (efifb_pci_dev) + pm_runtime_put(&efifb_pci_dev->dev); return 0; } From 2916059147ea38f76787d7b38dee883da2e9def2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 12 Apr 2021 15:10:41 +0200 Subject: [PATCH 014/192] drm/aperture: Add infrastructure for aperture ownership Platform devices might operate on firmware framebuffers, such as VESA or EFI. Before a native driver for the graphics hardware can take over the device, it has to remove any platform driver that operates on the firmware framebuffer. Aperture helpers provide the infrastructure for native drivers to remove the generic ones. For now, this only concerns generic fbdev drivers. Code for removing these is provided by drm_fb_helper_remove_conflicting_framebuffers() et al. Simply wrap these functions for now. At a later point, code can be added for generic DRM drivers to acquire firmware framebuffers. v2: * fix docs for drm_aperture_remove_framebuffers() Signed-off-by: Thomas Zimmermann Acked-by: Daniel Vetter Acked-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210412131043.5787-2-tzimmermann@suse.de --- Documentation/gpu/drm-internals.rst | 12 +++ drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_aperture.c | 114 ++++++++++++++++++++++++++++ include/drm/drm_aperture.h | 31 ++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_aperture.c create mode 100644 include/drm/drm_aperture.h diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 12272b168580..06af044c882f 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -75,6 +75,18 @@ update it, its value is mostly useless. The DRM core prints it to the kernel log at initialization time and passes it to userspace through the DRM_IOCTL_VERSION ioctl. +Managing Ownership of the Framebuffer Aperture +---------------------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c + :doc: overview + +.. kernel-doc:: include/drm/drm_aperture.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_aperture.c + :export: + Device Instance and Driver Handling ----------------------------------- diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5279db4392df..89e747fedc00 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,7 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -drm-y := drm_auth.o drm_cache.o \ +drm-y := drm_aperture.o drm_auth.o drm_cache.o \ drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_drv.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \ diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c new file mode 100644 index 000000000000..929dcbc0758a --- /dev/null +++ b/drivers/gpu/drm/drm_aperture.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +/** + * DOC: overview + * + * A graphics device might be supported by different drivers, but only one + * driver can be active at any given time. Many systems load a generic + * graphics drivers, such as EFI-GOP or VESA, early during the boot process. + * During later boot stages, they replace the generic driver with a dedicated, + * hardware-specific driver. To take over the device the dedicated driver + * first has to remove the generic driver. DRM aperture functions manage + * ownership of DRM framebuffer memory and hand-over between drivers. + * + * DRM drivers should call drm_aperture_remove_conflicting_framebuffers() + * at the top of their probe function. The function removes any generic + * driver that is currently associated with the given framebuffer memory. + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the + * example given below. + * + * .. code-block:: c + * + * static int remove_conflicting_framebuffers(struct pci_dev *pdev) + * { + * bool primary = false; + * resource_size_t base, size; + * int ret; + * + * base = pci_resource_start(pdev, 0); + * size = pci_resource_len(pdev, 0); + * #ifdef CONFIG_X86 + * primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + * #endif + * + * return drm_aperture_remove_conflicting_framebuffers(base, size, primary, + * "example driver"); + * } + * + * static int probe(struct pci_dev *pdev) + * { + * int ret; + * + * // Remove any generic drivers... + * ret = remove_conflicting_framebuffers(pdev); + * if (ret) + * return ret; + * + * // ... and initialize the hardware. + * ... + * + * drm_dev_register(); + * + * return 0; + * } + * + * PCI device drivers should call + * drm_aperture_remove_conflicting_pci_framebuffers() and let it detect the + * framebuffer apertures automatically. Device drivers without knowledge of + * the framebuffer's location shall call drm_aperture_remove_framebuffers(), + * which removes all drivers for known framebuffer. + */ + +/** + * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range + * @base: the aperture's base address in physical memory + * @size: aperture size in bytes + * @primary: also kick vga16fb if present + * @name: requesting driver name + * + * This function removes graphics device drivers which use memory range described by + * @base and @size. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, + bool primary, const char *name) +{ + struct apertures_struct *a; + int ret; + + a = alloc_apertures(1); + if (!a) + return -ENOMEM; + + a->ranges[0].base = base; + a->ranges[0].size = size; + + ret = drm_fb_helper_remove_conflicting_framebuffers(a, name, primary); + kfree(a); + + return ret; +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); + +/** + * drm_aperture_remove_conflicting_pci_framebuffers - remove existing framebuffers for PCI devices + * @pdev: PCI device + * @name: requesting driver name + * + * This function removes graphics device drivers using memory range configured + * for any of @pdev's memory bars. The function assumes that PCI device with + * shadowed ROM drives a primary display and so kicks out vga16fb. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name) +{ + return drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, name); +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers); diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h new file mode 100644 index 000000000000..23cc01647ed3 --- /dev/null +++ b/include/drm/drm_aperture.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef _DRM_APERTURE_H_ +#define _DRM_APERTURE_H_ + +#include + +struct pci_dev; + +int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, + bool primary, const char *name); + +int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name); + +/** + * drm_aperture_remove_framebuffers - remove all existing framebuffers + * @primary: also kick vga16fb if present + * @name: requesting driver name + * + * This function removes all graphics device drivers. Use this function on systems + * that can have their framebuffer located anywhere in memory. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +static inline int drm_aperture_remove_framebuffers(bool primary, const char *name) +{ + return drm_aperture_remove_conflicting_framebuffers(0, (resource_size_t)-1, primary, name); +} + +#endif From 6848c291a54f8cd1e8b32f4d6e0f681acc8d5095 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 12 Apr 2021 15:10:42 +0200 Subject: [PATCH 015/192] drm/aperture: Convert drivers to aperture interfaces Mass-convert all drivers from FB helpers to aperture interfaces. No functional changes besides checking for returned errno codes. Signed-off-by: Thomas Zimmermann Acked-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210412131043.5787-3-tzimmermann@suse.de --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++- drivers/gpu/drm/armada/armada_drv.c | 5 ++-- drivers/gpu/drm/ast/ast_drv.c | 23 +++++++--------- drivers/gpu/drm/bochs/bochs_drv.c | 3 ++- .../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 4 +-- drivers/gpu/drm/i915/i915_drv.c | 3 ++- drivers/gpu/drm/meson/meson_drv.c | 27 ++++++------------- drivers/gpu/drm/mgag200/mgag200_drv.c | 5 +++- drivers/gpu/drm/msm/msm_fbdev.c | 5 +++- drivers/gpu/drm/nouveau/nouveau_drm.c | 3 ++- drivers/gpu/drm/qxl/qxl_drv.c | 5 +++- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- drivers/gpu/drm/sun4i/sun4i_drv.c | 5 +++- drivers/gpu/drm/tegra/drm.c | 4 +-- drivers/gpu/drm/tiny/cirrus.c | 3 ++- drivers/gpu/drm/vboxvideo/vbox_drv.c | 3 ++- drivers/gpu/drm/vc4/vc4_drv.c | 5 +++- drivers/gpu/drm/virtio/virtgpu_drv.c | 10 ++++--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 +-- 19 files changed, 67 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b26e2fd1c538..671ec1002230 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -1196,7 +1197,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, #endif /* Get rid of things like offb */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 44fe9f994fc5..dab0a1f0983b 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -94,9 +95,7 @@ static int armada_drm_bind(struct device *dev) } /* Remove early framebuffers */ - ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, - "armada-drm-fb", - false); + ret = drm_aperture_remove_framebuffers(false, "armada-drm-fb"); if (ret) { dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", __func__, ret); diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 01837bea18c2..5aa452b4efe6 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -30,10 +30,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -89,23 +89,18 @@ static const struct pci_device_id ast_pciidlist[] = { MODULE_DEVICE_TABLE(pci, ast_pciidlist); -static void ast_kick_out_firmware_fb(struct pci_dev *pdev) +static int ast_remove_conflicting_framebuffers(struct pci_dev *pdev) { - struct apertures_struct *ap; bool primary = false; + resource_size_t base, size; - ap = alloc_apertures(1); - if (!ap) - return; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - + base = pci_resource_start(pdev, 0); + size = pci_resource_len(pdev, 0); #ifdef CONFIG_X86 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; #endif - drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary); - kfree(ap); + + return drm_aperture_remove_conflicting_framebuffers(base, size, primary, "astdrmfb"); } static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -114,7 +109,9 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; - ast_kick_out_firmware_fb(pdev); + ret = ast_remove_conflicting_framebuffers(pdev); + if (ret) + return ret; ret = pcim_enable_device(pdev); if (ret) diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index b469624fe40d..c828cadbabff 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -109,7 +110,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "bochsdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 89edc796deda..f4bc5386574a 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -313,8 +314,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev, struct drm_device *dev; int ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, - "hibmcdrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "hibmcdrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8e9cb44e66e5..e1ae7b804c01 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -557,7 +558,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) if (ret) goto err_perf; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "inteldrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "inteldrmfb"); if (ret) goto err_ggtt; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 453d8b4c5763..66de3f4f7222 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -156,23 +157,6 @@ static void meson_vpu_init(struct meson_drm *priv) writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } -static void meson_remove_framebuffers(void) -{ - struct apertures_struct *ap; - - ap = alloc_apertures(1); - if (!ap) - return; - - /* The framebuffer can be located anywhere in RAM */ - ap->ranges[0].base = 0; - ap->ranges[0].size = ~0; - - drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb", - false); - kfree(ap); -} - struct meson_drm_soc_attr { struct meson_drm_soc_limits limits; const struct soc_device_attribute *attrs; @@ -297,8 +281,13 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) } } - /* Remove early framebuffers (ie. simplefb) */ - meson_remove_framebuffers(); + /* + * Remove early framebuffers (ie. simplefb). The framebuffer can be + * located anywhere in RAM + */ + ret = drm_aperture_remove_framebuffers(false, "meson-drm-fb"); + if (ret) + goto free_drm; ret = drmm_mode_config_init(drm); if (ret) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 4e4c105f9a50..a701d9563257 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -341,7 +342,9 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; - drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); + if (ret) + return ret; ret = pcim_enable_device(pdev); if (ret) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 678dba1725a6..227404077e39 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -4,6 +4,7 @@ * Author: Rob Clark */ +#include #include #include #include @@ -168,7 +169,9 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) } /* the fw fb could be anywhere in memory */ - drm_fb_helper_remove_conflicting_framebuffers(NULL, "msm", false); + ret = drm_aperture_remove_framebuffers(false, "msm"); + if (ret) + goto fini; ret = drm_fb_helper_initial_config(helper, 32); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9766218a99ca..3204fc0a90d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -737,7 +738,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, nvkm_device_del(&device); /* Remove conflicting drivers (vesafb, efifb etc). */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "nouveaufb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "nouveaufb"); if (ret) return ret; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index db92eec07d96..bba0fc39028c 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -29,11 +29,14 @@ */ #include "qxl_drv.h" + #include #include #include +#include #include +#include #include #include #include @@ -93,7 +96,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "qxl"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "qxl"); if (ret) goto disable_pci; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index efeb115ae70e..8885e849717d 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -330,7 +331,7 @@ static int radeon_pci_probe(struct pci_dev *pdev, return -EPROBE_DEFER; /* Get rid of things like offb */ - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "radeondrmfb"); + ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "radeondrmfb"); if (ret) return ret; diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 91502937f26d..af335f58bdfc 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -99,7 +100,9 @@ static int sun4i_drv_bind(struct device *dev) drm->irq_enabled = true; /* Remove early framebuffers (ie. simplefb) */ - drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false); + ret = drm_aperture_remove_framebuffers(false, "sun4i-drm-fb"); + if (ret) + goto cleanup_mode_config; sun4i_framebuffer_init(drm); diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 90709c38c993..e32c0dcf2762 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -1198,8 +1199,7 @@ static int host1x_drm_probe(struct host1x_device *dev) drm_mode_config_reset(drm); - err = drm_fb_helper_remove_conflicting_framebuffers(NULL, "tegradrmfb", - false); + err = drm_aperture_remove_framebuffers(false, "tegradrmfb"); if (err < 0) goto hub; diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index ad922c3ec681..e3afb45d9a5c 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -24,6 +24,7 @@ #include