From bc2532ab7c20844d16c5cda97d0806eb80ab1275 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 23 Nov 2020 12:56:45 +0100 Subject: drm/cma-helper: Remove prime infix from GEM object functions These functions are not directly related to PRIME interfaces any longer, but are now GEM object functions. Rename them accordingly and fix the docs. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201123115646.11004-2-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_bo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 469d1b4f2643..813e6cb3f9af 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -385,7 +385,7 @@ static const struct vm_operations_struct vc4_vm_ops = { static const struct drm_gem_object_funcs vc4_gem_object_funcs = { .free = vc4_free_object, .export = vc4_prime_export, - .get_sg_table = drm_gem_cma_prime_get_sg_table, + .get_sg_table = drm_gem_cma_get_sg_table, .vmap = vc4_prime_vmap, .vm_ops = &vc4_vm_ops, }; @@ -794,7 +794,7 @@ int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) return -EINVAL; } - return drm_gem_cma_prime_vmap(obj, map); + return drm_gem_cma_vmap(obj, map); } struct drm_gem_object * -- cgit v1.2.3 From f5ca8eb6f9bd5ea76e11bbcee09528e2d71fa920 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 23 Nov 2020 12:56:46 +0100 Subject: drm/cma-helper: Implement mmap as GEM CMA object functions The new GEM object function drm_gem_cma_mmap() sets the VMA flags and offset as in the old implementation and immediately maps in the buffer's memory pages. Changing CMA helpers to use the GEM object function allows for the removal of the special implementations for mmap and gem_prime_mmap callbacks. The regular functions drm_gem_mmap() and drm_gem_prime_mmap() are now used. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201123115646.11004-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_file.c | 3 +- drivers/gpu/drm/drm_gem_cma_helper.c | 121 +++++++++++------------------------ drivers/gpu/drm/pl111/pl111_drv.c | 2 +- drivers/gpu/drm/vc4/vc4_bo.c | 2 +- include/drm/drm_gem_cma_helper.h | 10 +-- 5 files changed, 44 insertions(+), 94 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index b50380fa80ce..80886d50d0f1 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -113,8 +113,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) * The memory mapping implementation will vary depending on how the driver * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() * function, modern drivers should use one of the provided memory-manager - * specific implementations. For GEM-based drivers this is drm_gem_mmap(), and - * for drivers which use the CMA GEM helpers it's drm_gem_cma_mmap(). + * specific implementations. For GEM-based drivers this is drm_gem_mmap(). * * No other file operations are supported by the DRM userspace API. Overall the * following is an example &file_operations structure:: diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 6a4ef335ebc9..7942cf05cd93 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -38,6 +38,7 @@ static const struct drm_gem_object_funcs drm_gem_cma_default_funcs = { .print_info = drm_gem_cma_print_info, .get_sg_table = drm_gem_cma_get_sg_table, .vmap = drm_gem_cma_vmap, + .mmap = drm_gem_cma_mmap, .vm_ops = &drm_gem_cma_vm_ops, }; @@ -277,62 +278,6 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = { }; EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); -static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj, - struct vm_area_struct *vma) -{ - int ret; - - /* - * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the - * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map - * the whole buffer. - */ - vma->vm_flags &= ~VM_PFNMAP; - vma->vm_pgoff = 0; - - ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr, - cma_obj->paddr, vma->vm_end - vma->vm_start); - if (ret) - drm_gem_vm_close(vma); - - return ret; -} - -/** - * drm_gem_cma_mmap - memory-map a CMA GEM object - * @filp: file object - * @vma: VMA for the area to be mapped - * - * This function implements an augmented version of the GEM DRM file mmap - * operation for CMA objects: In addition to the usual GEM VMA setup it - * immediately faults in the entire object instead of using on-demaind - * faulting. Drivers which employ the CMA helpers should use this function - * as their ->mmap() handler in the DRM device file's file_operations - * structure. - * - * Instead of directly referencing this function, drivers should use the - * DEFINE_DRM_GEM_CMA_FOPS().macro. - * - * Returns: - * 0 on success or a negative error code on failure. - */ -int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_gem_cma_object *cma_obj; - struct drm_gem_object *gem_obj; - int ret; - - ret = drm_gem_mmap(filp, vma); - if (ret) - return ret; - - gem_obj = vma->vm_private_data; - cma_obj = to_drm_gem_cma_obj(gem_obj); - - return drm_gem_cma_mmap_obj(cma_obj, vma); -} -EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); - #ifndef CONFIG_MMU /** * drm_gem_cma_get_unmapped_area - propose address for mapping in noMMU cases @@ -500,33 +445,6 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, } EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table); -/** - * drm_gem_cma_prime_mmap - memory-map an exported CMA GEM object - * @obj: GEM object - * @vma: VMA for the area to be mapped - * - * This function maps a buffer imported via DRM PRIME into a userspace - * process's address space. Drivers that use the CMA helpers should set this - * as their &drm_driver.gem_prime_mmap callback. - * - * Returns: - * 0 on success or a negative error code on failure. - */ -int drm_gem_cma_prime_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma) -{ - struct drm_gem_cma_object *cma_obj; - int ret; - - ret = drm_gem_mmap_obj(obj, obj->size, vma); - if (ret < 0) - return ret; - - cma_obj = to_drm_gem_cma_obj(obj); - return drm_gem_cma_mmap_obj(cma_obj, vma); -} -EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap); - /** * drm_gem_cma_vmap - map a CMA GEM object into the kernel's virtual * address space @@ -553,6 +471,43 @@ int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) } EXPORT_SYMBOL_GPL(drm_gem_cma_vmap); +/** + * drm_gem_cma_mmap - memory-map an exported CMA GEM object + * @obj: GEM object + * @vma: VMA for the area to be mapped + * + * This function maps a buffer into a userspace process's address space. + * In addition to the usual GEM VMA setup it immediately faults in the entire + * object instead of using on-demand faulting. Drivers that use the CMA + * helpers should set this as their &drm_gem_object_funcs.mmap callback. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +int drm_gem_cma_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + struct drm_gem_cma_object *cma_obj; + int ret; + + /* + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the + * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); + vma->vm_flags &= ~VM_PFNMAP; + + cma_obj = to_drm_gem_cma_obj(obj); + + ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr, + cma_obj->paddr, vma->vm_end - vma->vm_start); + if (ret) + drm_gem_vm_close(vma); + + return ret; +} +EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); + /** * drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's * scatter/gather table and get the virtual address of the buffer diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 40e6708fbbe2..e4dcaef6c143 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -228,7 +228,7 @@ static const struct drm_driver pl111_drm_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import_sg_table = pl111_gem_import_sg_table, - .gem_prime_mmap = drm_gem_cma_prime_mmap, + .gem_prime_mmap = drm_gem_prime_mmap, #if defined(CONFIG_DEBUG_FS) .debugfs_init = pl111_debugfs_init, diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 813e6cb3f9af..dc316cb79e00 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -782,7 +782,7 @@ int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) return -EINVAL; } - return drm_gem_cma_prime_mmap(obj, vma); + return drm_gem_prime_mmap(obj, vma); } int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 4680275ab339..0a9711caa3e8 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -59,7 +59,7 @@ struct drm_gem_cma_object { .poll = drm_poll,\ .read = drm_read,\ .llseek = noop_llseek,\ - .mmap = drm_gem_cma_mmap,\ + .mmap = drm_gem_mmap,\ DRM_GEM_CMA_UNMAPPED_AREA_FOPS \ } @@ -76,9 +76,6 @@ int drm_gem_cma_dumb_create(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args); -/* set vm_flags and we can change the VM attribute to other one at here */ -int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma); - /* allocate physical memory */ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, size_t size); @@ -101,9 +98,8 @@ struct drm_gem_object * drm_gem_cma_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); -int drm_gem_cma_prime_mmap(struct drm_gem_object *obj, - struct vm_area_struct *vma); int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int drm_gem_cma_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); /** * DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE - CMA GEM driver operations @@ -123,7 +119,7 @@ int drm_gem_cma_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); .prime_handle_to_fd = drm_gem_prime_handle_to_fd, \ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, \ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, \ - .gem_prime_mmap = drm_gem_cma_prime_mmap + .gem_prime_mmap = drm_gem_prime_mmap /** * DRM_GEM_CMA_DRIVER_OPS - CMA GEM driver operations -- cgit v1.2.3 From e2f9b2edf7b5554cfe013d621e295e9b853d545a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 3 Dec 2020 08:46:24 +0100 Subject: drm/vc4: hdmi: Don't poll for the infoframes status on setup The infoframes are sent at a regular interval as a data island packet, so we don't need to wait for them to be sent when we're setting them up. However, we do need to poll when we're enabling since the we can't update the packet RAM until it has been sent. Let's add a boolean flag to tell whether we want to poll or not to support both cases. Suggested-by: Dave Stevenson Signed-off-by: Maxime Ripard Reviewed-by: Dave Stevenson Link: https://patchwork.freedesktop.org/patch/msgid/20201203074624.721559-1-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b80eb9d3d9d5..ab5da0e4a233 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -219,7 +219,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, } static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, - enum hdmi_infoframe_type type) + enum hdmi_infoframe_type type, + bool poll) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); u32 packet_id = type - 0x80; @@ -227,6 +228,9 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + if (!poll) + return 0; + return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) & BIT(packet_id)), 100); } @@ -253,7 +257,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, if (len < 0) return; - ret = vc4_hdmi_stop_packet(encoder, frame->any.type); + ret = vc4_hdmi_stop_packet(encoder, frame->any.type, true); if (ret) { DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret); return; @@ -893,7 +897,7 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) int ret; vc4_hdmi->audio.streaming = false; - ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); + ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false); if (ret) dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); -- cgit v1.2.3 From 51f4fcd9c4ea867c3b4fe58111f342ad0e80642a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 3 Dec 2020 14:25:36 +0100 Subject: drm/vc4: drv: Remove the DSI pointer in vc4_drv That pointer isn't used anywhere, so there's no point in keeping it. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-2-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_drv.h | 1 - drivers/gpu/drm/vc4/vc4_dsi.c | 9 --------- 2 files changed, 10 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 137c382256d5..dcafb4cf4b18 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -77,7 +77,6 @@ struct vc4_dev { struct vc4_hvs *hvs; struct vc4_v3d *v3d; struct vc4_dpi *dpi; - struct vc4_dsi *dsi1; struct vc4_vec *vec; struct vc4_txp *txp; diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 19aab4e7e209..b1d8765795f1 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1459,7 +1459,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); struct vc4_dsi_encoder *vc4_dsi_encoder; struct drm_panel *panel; @@ -1612,9 +1611,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - if (dsi->port == 1) - vc4->dsi1 = dsi; - drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI); drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); @@ -1643,8 +1639,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) static void vc4_dsi_unbind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); if (dsi->bridge) @@ -1656,9 +1650,6 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, */ list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain); drm_encoder_cleanup(dsi->encoder); - - if (dsi->port == 1) - vc4->dsi1 = NULL; } static const struct component_ops vc4_dsi_ops = { -- cgit v1.2.3 From e02d5c43f2fdf7d71935de16e8c91b2cd3139f71 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 3 Dec 2020 14:25:37 +0100 Subject: drm/vc4: dsi: Correct DSI register definition The DSI1_PHY_AFEC0_PD_DLANE1 and DSI1_PHY_AFEC0_PD_DLANE3 register definitions were swapped, so trying to use more than a single data lane failed as lane 1 would get powered down. (In theory a 4 lane device would work as all lanes would remain powered). Correct the definitions. Signed-off-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-3-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index b1d8765795f1..bb316e6cc12b 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -306,11 +306,11 @@ # define DSI0_PHY_AFEC0_RESET BIT(11) # define DSI1_PHY_AFEC0_PD_BG BIT(11) # define DSI0_PHY_AFEC0_PD BIT(10) -# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(10) +# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(10) # define DSI0_PHY_AFEC0_PD_BG BIT(9) # define DSI1_PHY_AFEC0_PD_DLANE2 BIT(9) # define DSI0_PHY_AFEC0_PD_DLANE1 BIT(8) -# define DSI1_PHY_AFEC0_PD_DLANE1 BIT(8) +# define DSI1_PHY_AFEC0_PD_DLANE3 BIT(8) # define DSI_PHY_AFEC0_PTATADJ_MASK VC4_MASK(7, 4) # define DSI_PHY_AFEC0_PTATADJ_SHIFT 4 # define DSI_PHY_AFEC0_CTATADJ_MASK VC4_MASK(3, 0) -- cgit v1.2.3 From dc0bf36401e891c853e0a25baeb4e0b4e6f3626d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 3 Dec 2020 14:25:38 +0100 Subject: drm/vc4: dsi: Use snprintf for the PHY clocks instead of an array The DSI clocks setup function has been using an array to store the clock name of either the DSI0 or DSI1 blocks, using the port ID to choose the proper one. Let's switch to an snprintf call to do the same thing and simplify the array a bit. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-4-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_dsi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index bb316e6cc12b..f704d959e65b 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1398,12 +1398,12 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) struct device *dev = &dsi->pdev->dev; const char *parent_name = __clk_get_name(dsi->pll_phy_clock); static const struct { - const char *dsi0_name, *dsi1_name; + const char *name; int div; } phy_clocks[] = { - { "dsi0_byte", "dsi1_byte", 8 }, - { "dsi0_ddr2", "dsi1_ddr2", 4 }, - { "dsi0_ddr", "dsi1_ddr", 2 }, + { "byte", 8 }, + { "ddr2", 4 }, + { "ddr", 2 }, }; int i; @@ -1419,8 +1419,12 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) for (i = 0; i < ARRAY_SIZE(phy_clocks); i++) { struct clk_fixed_factor *fix = &dsi->phy_clocks[i]; struct clk_init_data init; + char clk_name[16]; int ret; + snprintf(clk_name, sizeof(clk_name), + "dsi%u_%s", dsi->port, phy_clocks[i].name); + /* We just use core fixed factor clock ops for the PHY * clocks. The clocks are actually gated by the * PHY_AFEC0_DDRCLK_EN bits, which we should be @@ -1437,10 +1441,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) memset(&init, 0, sizeof(init)); init.parent_names = &parent_name; init.num_parents = 1; - if (dsi->port == 1) - init.name = phy_clocks[i].dsi1_name; - else - init.name = phy_clocks[i].dsi0_name; + init.name = clk_name; init.ops = &clk_fixed_factor_ops; ret = devm_clk_hw_register(dev, &fix->hw); -- cgit v1.2.3 From d1d195ce26a14ec0a87816c09ae514e1c40e97f7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 3 Dec 2020 14:25:39 +0100 Subject: drm/vc4: dsi: Introduce a variant structure Most of the differences between DSI0 and DSI1 are handled through the ID. However, the BCM2711 DSI is going to introduce one more variable to the mix and will break some expectations of the earlier, simpler, test. Let's add a variant structure that will address most of the differences between those three controllers. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-5-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_dsi.c | 63 +++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index f704d959e65b..601020c10053 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -493,6 +493,18 @@ */ #define DSI1_ID 0x8c +struct vc4_dsi_variant { + /* Whether we're on bcm2835's DSI0 or DSI1. */ + unsigned int port; + + bool broken_axi_workaround; + + const char *debugfs_name; + const struct debugfs_reg32 *regs; + size_t nregs; + +}; + /* General DSI hardware state. */ struct vc4_dsi { struct platform_device *pdev; @@ -509,8 +521,7 @@ struct vc4_dsi { u32 *reg_dma_mem; dma_addr_t reg_paddr; - /* Whether we're on bcm2835's DSI0 or DSI1. */ - int port; + const struct vc4_dsi_variant *variant; /* DSI channel for the panel we're connected to. */ u32 channel; @@ -586,10 +597,10 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) #define DSI_READ(offset) readl(dsi->regs + (offset)) #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val) #define DSI_PORT_READ(offset) \ - DSI_READ(dsi->port ? DSI1_##offset : DSI0_##offset) + DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset) #define DSI_PORT_WRITE(offset, val) \ - DSI_WRITE(dsi->port ? DSI1_##offset : DSI0_##offset, val) -#define DSI_PORT_BIT(bit) (dsi->port ? DSI1_##bit : DSI0_##bit) + DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val) +#define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit) /* VC4 DSI encoder KMS struct */ struct vc4_dsi_encoder { @@ -837,7 +848,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) ret = pm_runtime_get_sync(dev); if (ret) { - DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->port); + DRM_ERROR("Failed to runtime PM enable on DSI%d\n", dsi->variant->port); return; } @@ -871,7 +882,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DSI_PORT_WRITE(STAT, DSI_PORT_READ(STAT)); /* Set AFE CTR00/CTR1 to release powerdown of analog. */ - if (dsi->port == 0) { + if (dsi->variant->port == 0) { u32 afec0 = (VC4_SET_FIELD(7, DSI_PHY_AFEC0_PTATADJ) | VC4_SET_FIELD(7, DSI_PHY_AFEC0_CTATADJ)); @@ -1017,7 +1028,7 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DSI_PORT_BIT(PHYC_CLANE_ENABLE) | ((dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) ? 0 : DSI_PORT_BIT(PHYC_HS_CLK_CONTINUOUS)) | - (dsi->port == 0 ? + (dsi->variant->port == 0 ? VC4_SET_FIELD(lpx - 1, DSI0_PHYC_ESC_CLK_LPDT) : VC4_SET_FIELD(lpx - 1, DSI1_PHYC_ESC_CLK_LPDT))); @@ -1043,13 +1054,13 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DSI_DISP1_ENABLE); /* Ungate the block. */ - if (dsi->port == 0) + if (dsi->variant->port == 0) DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI0_CTRL_CTRL0); else DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN); /* Bring AFE out of reset. */ - if (dsi->port == 0) { + if (dsi->variant->port == 0) { } else { DSI_PORT_WRITE(PHY_AFEC0, DSI_PORT_READ(PHY_AFEC0) & @@ -1313,8 +1324,16 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { .mode_fixup = vc4_dsi_encoder_mode_fixup, }; +static const struct vc4_dsi_variant bcm2835_dsi1_variant = { + .port = 1, + .broken_axi_workaround = true, + .debugfs_name = "dsi1_regs", + .regs = dsi1_regs, + .nregs = ARRAY_SIZE(dsi1_regs), +}; + static const struct of_device_id vc4_dsi_dt_match[] = { - { .compatible = "brcm,bcm2835-dsi1", (void *)(uintptr_t)1 }, + { .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant }, {} }; @@ -1325,7 +1344,7 @@ static void dsi_handle_error(struct vc4_dsi *dsi, if (!(stat & bit)) return; - DRM_ERROR("DSI%d: %s error\n", dsi->port, type); + DRM_ERROR("DSI%d: %s error\n", dsi->variant->port, type); *ret = IRQ_HANDLED; } @@ -1423,7 +1442,7 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi) int ret; snprintf(clk_name, sizeof(clk_name), - "dsi%u_%s", dsi->port, phy_clocks[i].name); + "dsi%u_%s", dsi->variant->port, phy_clocks[i].name); /* We just use core fixed factor clock ops for the PHY * clocks. The clocks are actually gated by the @@ -1471,7 +1490,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) if (!match) return -ENODEV; - dsi->port = (uintptr_t)match->data; + dsi->variant = match->data; vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), GFP_KERNEL); @@ -1488,13 +1507,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(dsi->regs); dsi->regset.base = dsi->regs; - if (dsi->port == 0) { - dsi->regset.regs = dsi0_regs; - dsi->regset.nregs = ARRAY_SIZE(dsi0_regs); - } else { - dsi->regset.regs = dsi1_regs; - dsi->regset.nregs = ARRAY_SIZE(dsi1_regs); - } + dsi->regset.regs = dsi->variant->regs; + dsi->regset.nregs = dsi->variant->nregs; if (DSI_PORT_READ(ID) != DSI_ID_VALUE) { dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", @@ -1506,7 +1520,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) * from the ARM. It does handle writes from the DMA engine, * so set up a channel for talking to it. */ - if (dsi->port == 1) { + if (dsi->variant->broken_axi_workaround) { dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, &dsi->reg_dma_paddr, GFP_KERNEL); @@ -1627,10 +1641,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) */ list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain); - if (dsi->port == 0) - vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset); - else - vc4_debugfs_add_regset32(drm, "dsi1_regs", &dsi->regset); + vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset); pm_runtime_enable(dev); -- cgit v1.2.3 From 4b265fe11fad4234b12d92dd8091f9aa0c878eea Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 3 Dec 2020 14:25:40 +0100 Subject: drm/vc4: dsi: Add support for DSI0 DSI0 was partially supported, but didn't register with the main driver, and the code was inconsistent as to whether it checked port == 0 or port == 1. Add compatible string and other support to make it consistent. Signed-off-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-6-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 601020c10053..82162900e351 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1324,6 +1324,13 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { .mode_fixup = vc4_dsi_encoder_mode_fixup, }; +static const struct vc4_dsi_variant bcm2835_dsi0_variant = { + .port = 0, + .debugfs_name = "dsi0_regs", + .regs = dsi0_regs, + .nregs = ARRAY_SIZE(dsi0_regs), +}; + static const struct vc4_dsi_variant bcm2835_dsi1_variant = { .port = 1, .broken_axi_workaround = true, @@ -1333,6 +1340,7 @@ static const struct vc4_dsi_variant bcm2835_dsi1_variant = { }; static const struct of_device_id vc4_dsi_dt_match[] = { + { .compatible = "brcm,bcm2835-dsi0", &bcm2835_dsi0_variant }, { .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant }, {} }; -- cgit v1.2.3 From d0666be8ef9e8e65d4b7fabc1606ec51f61384c0 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 3 Dec 2020 14:25:42 +0100 Subject: drm/vc4: dsi: Add configuration for BCM2711 DSI1 BCM2711 DSI1 doesn't have the issue with the ARM not being able to write to the registers, therefore remove the DMA workaround for that compatible string. Signed-off-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201203132543.861591-8-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_dsi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 82162900e351..a55256ed0955 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1324,6 +1324,13 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { .mode_fixup = vc4_dsi_encoder_mode_fixup, }; +static const struct vc4_dsi_variant bcm2711_dsi1_variant = { + .port = 1, + .debugfs_name = "dsi1_regs", + .regs = dsi1_regs, + .nregs = ARRAY_SIZE(dsi1_regs), +}; + static const struct vc4_dsi_variant bcm2835_dsi0_variant = { .port = 0, .debugfs_name = "dsi0_regs", @@ -1340,6 +1347,7 @@ static const struct vc4_dsi_variant bcm2835_dsi1_variant = { }; static const struct of_device_id vc4_dsi_dt_match[] = { + { .compatible = "brcm,bcm2711-dsi1", &bcm2711_dsi1_variant }, { .compatible = "brcm,bcm2835-dsi0", &bcm2835_dsi0_variant }, { .compatible = "brcm,bcm2835-dsi1", &bcm2835_dsi1_variant }, {} @@ -1524,8 +1532,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) return -ENODEV; } - /* DSI1 has a broken AXI slave that doesn't respond to writes - * from the ARM. It does handle writes from the DMA engine, + /* DSI1 on BCM2835/6/7 has a broken AXI slave that doesn't respond to + * writes from the ARM. It does handle writes from the DMA engine, * so set up a channel for talking to it. */ if (dsi->variant->broken_axi_workaround) { -- cgit v1.2.3 From d62a8ed7671ee1deaabe339df3703f8dff56183b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 16:11:34 +0100 Subject: drm/vc4: Simplify a bit the global atomic_check When we can't allocate a new channel, we can simply return instead of having to handle both cases, and that simplifies a bit the code. Reviewed-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201204151138.1739736-4-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_kms.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index ba310c0ab5f6..8937eb0b751d 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -794,6 +794,7 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, to_vc4_crtc_state(new_crtc_state); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); unsigned int matching_channels; + unsigned int channel; /* Nothing to do here, let's skip it */ if (old_crtc_state->enable == new_crtc_state->enable) @@ -834,14 +835,12 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, * but it works so far. */ matching_channels = hvs_new_state->unassigned_channels & vc4_crtc->data->hvs_available_channels; - if (matching_channels) { - unsigned int channel = ffs(matching_channels) - 1; - - new_vc4_crtc_state->assigned_channel = channel; - hvs_new_state->unassigned_channels &= ~BIT(channel); - } else { + if (!matching_channels) return -EINVAL; - } + + channel = ffs(matching_channels) - 1; + new_vc4_crtc_state->assigned_channel = channel; + hvs_new_state->unassigned_channels &= ~BIT(channel); } return 0; -- cgit v1.2.3 From 9ec03d7f1ed394897891319a4dda75f52c5d292d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 16:11:35 +0100 Subject: drm/vc4: kms: Wait on previous FIFO users before a commit If we're having two subsequent, non-blocking, commits on two different CRTCs that share no resources, there's no guarantee on the order of execution of both commits. However, the second one will consider the first one as the old state, and will be in charge of freeing it once that second commit is done. If the first commit happens after that second commit, it might access some resources related to its state that has been freed, resulting in a use-after-free bug. The standard DRM objects are protected against this, but our HVS private state isn't so let's make sure we wait for all the previous FIFO users to finish their commit before going with our own. Signed-off-by: Maxime Ripard Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20201204151138.1739736-5-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_kms.c | 123 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 8937eb0b751d..fdd698df5fbe 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -40,6 +40,11 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv) struct vc4_hvs_state { struct drm_private_state base; unsigned int unassigned_channels; + + struct { + unsigned in_use: 1; + struct drm_crtc_commit *pending_commit; + } fifo_state[HVS_NUM_CHANNELS]; }; static struct vc4_hvs_state * @@ -182,6 +187,32 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state) VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); } +static struct vc4_hvs_state * +vc4_hvs_get_new_global_state(struct drm_atomic_state *state) +{ + struct vc4_dev *vc4 = to_vc4_dev(state->dev); + struct drm_private_state *priv_state; + + priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels); + if (IS_ERR(priv_state)) + return ERR_CAST(priv_state); + + return to_vc4_hvs_state(priv_state); +} + +static struct vc4_hvs_state * +vc4_hvs_get_old_global_state(struct drm_atomic_state *state) +{ + struct vc4_dev *vc4 = to_vc4_dev(state->dev); + struct drm_private_state *priv_state; + + priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels); + if (IS_ERR(priv_state)) + return ERR_CAST(priv_state); + + return to_vc4_hvs_state(priv_state); +} + static struct vc4_hvs_state * vc4_hvs_get_global_state(struct drm_atomic_state *state) { @@ -308,8 +339,10 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) struct drm_device *dev = state->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; + struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *new_crtc_state; struct drm_crtc *crtc; + struct vc4_hvs_state *old_hvs_state; int i; for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -329,6 +362,36 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) drm_atomic_helper_wait_for_dependencies(state); + old_hvs_state = vc4_hvs_get_old_global_state(state); + if (!old_hvs_state) + return; + + for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) { + struct vc4_crtc_state *vc4_crtc_state = + to_vc4_crtc_state(old_crtc_state); + struct drm_crtc_commit *commit; + unsigned int channel = vc4_crtc_state->assigned_channel; + unsigned long done; + + if (channel == VC4_HVS_CHANNEL_DISABLED) + continue; + + if (!old_hvs_state->fifo_state[channel].in_use) + continue; + + commit = old_hvs_state->fifo_state[i].pending_commit; + if (!commit) + continue; + + done = wait_for_completion_timeout(&commit->hw_done, 10 * HZ); + if (!done) + drm_err(dev, "Timed out waiting for hw_done\n"); + + done = wait_for_completion_timeout(&commit->flip_done, 10 * HZ); + if (!done) + drm_err(dev, "Timed out waiting for flip_done\n"); + } + drm_atomic_helper_commit_modeset_disables(dev, state); vc4_ctm_commit(vc4, state); @@ -368,6 +431,36 @@ static void commit_work(struct work_struct *work) vc4_atomic_complete_commit(state); } +static int vc4_atomic_commit_setup(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct vc4_hvs_state *hvs_state; + struct drm_crtc *crtc; + unsigned int i; + + hvs_state = vc4_hvs_get_new_global_state(state); + if (!hvs_state) + return -EINVAL; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc_state *vc4_crtc_state = + to_vc4_crtc_state(crtc_state); + unsigned int channel = + vc4_crtc_state->assigned_channel; + + if (channel == VC4_HVS_CHANNEL_DISABLED) + continue; + + if (!hvs_state->fifo_state[channel].in_use) + continue; + + hvs_state->fifo_state[channel].pending_commit = + drm_crtc_commit_get(crtc_state->commit); + } + + return 0; +} + /** * vc4_atomic_commit - commit validated state object * @dev: DRM device @@ -697,6 +790,7 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) { struct vc4_hvs_state *old_state = to_vc4_hvs_state(obj->state); struct vc4_hvs_state *state; + unsigned int i; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) @@ -706,6 +800,16 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) state->unassigned_channels = old_state->unassigned_channels; + for (i = 0; i < HVS_NUM_CHANNELS; i++) { + state->fifo_state[i].in_use = old_state->fifo_state[i].in_use; + + if (!old_state->fifo_state[i].pending_commit) + continue; + + state->fifo_state[i].pending_commit = + drm_crtc_commit_get(old_state->fifo_state[i].pending_commit); + } + return &state->base; } @@ -713,6 +817,14 @@ static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj, struct drm_private_state *state) { struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); + unsigned int i; + + for (i = 0; i < HVS_NUM_CHANNELS; i++) { + if (!hvs_state->fifo_state[i].pending_commit) + continue; + + drm_crtc_commit_put(hvs_state->fifo_state[i].pending_commit); + } kfree(hvs_state); } @@ -805,7 +917,10 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, /* If we're disabling our CRTC, we put back our channel */ if (!new_crtc_state->enable) { - hvs_new_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel); + channel = old_vc4_crtc_state->assigned_channel; + + hvs_new_state->unassigned_channels |= BIT(channel); + hvs_new_state->fifo_state[channel].in_use = false; new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; continue; } @@ -841,6 +956,7 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, channel = ffs(matching_channels) - 1; new_vc4_crtc_state->assigned_channel = channel; hvs_new_state->unassigned_channels &= ~BIT(channel); + hvs_new_state->fifo_state[channel].in_use = true; } return 0; @@ -866,6 +982,10 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) return vc4_load_tracker_atomic_check(state); } +static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = { + .atomic_commit_setup = vc4_atomic_commit_setup, +}; + static const struct drm_mode_config_funcs vc4_mode_funcs = { .atomic_check = vc4_atomic_check, .atomic_commit = vc4_atomic_commit, @@ -909,6 +1029,7 @@ int vc4_kms_load(struct drm_device *dev) } dev->mode_config.funcs = &vc4_mode_funcs; + dev->mode_config.helper_private = &vc4_mode_config_helpers; dev->mode_config.preferred_depth = 24; dev->mode_config.async_page_flip = true; dev->mode_config.allow_fb_modifiers = true; -- cgit v1.2.3 From 03b03efebeed3a928e168505d32939f35055264a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 16:11:36 +0100 Subject: drm/vc4: kms: Remove unassigned_channels from the HVS state The HVS state now has both unassigned_channels that reflects the channels that are not used in the associated state, and the in_use boolean for each channel that says whether or not a particular channel is in use. Both express pretty much the same thing, and we need the in_use variable to properly track the commits, so let's get rid of unassigned_channels. Suggested-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20201204151138.1739736-6-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_kms.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index fdd698df5fbe..5d81b90383a0 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -39,7 +39,6 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv) struct vc4_hvs_state { struct drm_private_state base; - unsigned int unassigned_channels; struct { unsigned in_use: 1; @@ -798,7 +797,6 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj) __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); - state->unassigned_channels = old_state->unassigned_channels; for (i = 0; i < HVS_NUM_CHANNELS; i++) { state->fifo_state[i].in_use = old_state->fifo_state[i].in_use; @@ -849,7 +847,6 @@ static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4) if (!state) return -ENOMEM; - state->unassigned_channels = GENMASK(HVS_NUM_CHANNELS - 1, 0); drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels, &state->base, &vc4_hvs_state_funcs); @@ -893,12 +890,17 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, struct vc4_hvs_state *hvs_new_state; struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_crtc *crtc; + unsigned int unassigned_channels = 0; unsigned int i; hvs_new_state = vc4_hvs_get_global_state(state); if (!hvs_new_state) return -EINVAL; + for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++) + if (!hvs_new_state->fifo_state[i].in_use) + unassigned_channels |= BIT(i); + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct vc4_crtc_state *old_vc4_crtc_state = to_vc4_crtc_state(old_crtc_state); @@ -918,8 +920,6 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, /* If we're disabling our CRTC, we put back our channel */ if (!new_crtc_state->enable) { channel = old_vc4_crtc_state->assigned_channel; - - hvs_new_state->unassigned_channels |= BIT(channel); hvs_new_state->fifo_state[channel].in_use = false; new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; continue; @@ -949,13 +949,13 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, * the future, we will need to have something smarter, * but it works so far. */ - matching_channels = hvs_new_state->unassigned_channels & vc4_crtc->data->hvs_available_channels; + matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels; if (!matching_channels) return -EINVAL; channel = ffs(matching_channels) - 1; new_vc4_crtc_state->assigned_channel = channel; - hvs_new_state->unassigned_channels &= ~BIT(channel); + unassigned_channels &= ~BIT(channel); hvs_new_state->fifo_state[channel].in_use = true; } -- cgit v1.2.3 From 82faa3276012d272d930026e7666d978ef2c6fef Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 16:11:37 +0100 Subject: drm/vc4: kms: Remove async modeset semaphore Now that we have proper ordering guaranteed by the previous patch, the semaphore is redundant and can be removed. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201204151138.1739736-7-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_crtc.c | 13 ------------- drivers/gpu/drm/vc4/vc4_drv.h | 2 -- drivers/gpu/drm/vc4/vc4_kms.c | 24 ++---------------------- 3 files changed, 2 insertions(+), 37 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index ea710beb8e00..ee4f657a5ce0 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -697,7 +697,6 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) container_of(cb, struct vc4_async_flip_state, cb); struct drm_crtc *crtc = flip_state->crtc; struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_plane *plane = crtc->primary; vc4_plane_async_set_fb(plane, flip_state->fb); @@ -729,8 +728,6 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) } kfree(flip_state); - - up(&vc4->async_modeset); } /* Implements async (non-vblank-synced) page flips. @@ -745,7 +742,6 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, uint32_t flags) { struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_plane *plane = crtc->primary; int ret = 0; struct vc4_async_flip_state *flip_state; @@ -774,15 +770,6 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, flip_state->crtc = crtc; flip_state->event = event; - /* Make sure all other async modesetes have landed. */ - ret = down_interruptible(&vc4->async_modeset); - if (ret) { - drm_framebuffer_put(fb); - vc4_bo_dec_usecnt(bo); - kfree(flip_state); - return ret; - } - /* Save the current FB before it's replaced by the new one in * drm_atomic_set_fb_for_plane(). We'll need the old FB in * vc4_async_page_flip_complete() to decrement the BO usecnt and keep diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index fc06297cb918..6db4c944ecba 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -214,8 +214,6 @@ struct vc4_dev { struct work_struct reset_work; } hangcheck; - struct semaphore async_modeset; - struct drm_modeset_lock ctm_state_lock; struct drm_private_obj ctm_manager; struct drm_private_obj hvs_channels; diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 5d81b90383a0..48d07ea686f0 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -418,8 +418,6 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) clk_set_min_rate(hvs->core_clk, 0); drm_atomic_state_put(state); - - up(&vc4->async_modeset); } static void commit_work(struct work_struct *work) @@ -477,26 +475,17 @@ static int vc4_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { - struct vc4_dev *vc4 = to_vc4_dev(dev); int ret; if (state->async_update) { - ret = down_interruptible(&vc4->async_modeset); - if (ret) - return ret; - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) { - up(&vc4->async_modeset); + if (ret) return ret; - } drm_atomic_helper_async_commit(dev, state); drm_atomic_helper_cleanup_planes(dev, state); - up(&vc4->async_modeset); - return 0; } @@ -512,21 +501,14 @@ static int vc4_atomic_commit(struct drm_device *dev, INIT_WORK(&state->commit_work, commit_work); - ret = down_interruptible(&vc4->async_modeset); - if (ret) - return ret; - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) { - up(&vc4->async_modeset); + if (ret) return ret; - } if (!nonblock) { ret = drm_atomic_helper_wait_for_fences(dev, state, true); if (ret) { drm_atomic_helper_cleanup_planes(dev, state); - up(&vc4->async_modeset); return ret; } } @@ -1008,8 +990,6 @@ int vc4_kms_load(struct drm_device *dev) vc4->load_tracker_enabled = true; } - sema_init(&vc4->async_modeset, 1); - /* Set support for vblank irq fast disable, before drm_vblank_init() */ dev->vblank_disable_immediate = true; -- cgit v1.2.3 From f3c420fe19f8cc39adf379365decf63167596dc3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 16:11:38 +0100 Subject: drm/vc4: kms: Convert to atomic helpers Now that the semaphore is gone, our atomic_commit implementation is basically drm_atomic_helper_commit with a somewhat custom commit_tail, the main difference being that we're using wait_for_flip_done instead of wait_for_vblanks used in the drm_atomic_helper_commit_tail helper. Let's switch to using drm_atomic_helper_commit. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201204151138.1739736-8-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_kms.c | 110 ++---------------------------------------- 1 file changed, 3 insertions(+), 107 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 48d07ea686f0..f09254c2497d 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -332,8 +332,7 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, } } -static void -vc4_atomic_complete_commit(struct drm_atomic_state *state) +static void vc4_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); @@ -357,10 +356,6 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) if (vc4->hvs->hvs5) clk_set_min_rate(hvs->core_clk, 500000000); - drm_atomic_helper_wait_for_fences(dev, state, false); - - drm_atomic_helper_wait_for_dependencies(state); - old_hvs_state = vc4_hvs_get_old_global_state(state); if (!old_hvs_state) return; @@ -412,20 +407,8 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_helper_commit_cleanup_done(state); - if (vc4->hvs->hvs5) clk_set_min_rate(hvs->core_clk, 0); - - drm_atomic_state_put(state); -} - -static void commit_work(struct work_struct *work) -{ - struct drm_atomic_state *state = container_of(work, - struct drm_atomic_state, - commit_work); - vc4_atomic_complete_commit(state); } static int vc4_atomic_commit_setup(struct drm_atomic_state *state) @@ -458,94 +441,6 @@ static int vc4_atomic_commit_setup(struct drm_atomic_state *state) return 0; } -/** - * vc4_atomic_commit - commit validated state object - * @dev: DRM device - * @state: the driver state object - * @nonblock: nonblocking commit - * - * This function commits a with drm_atomic_helper_check() pre-validated state - * object. This can still fail when e.g. the framebuffer reservation fails. For - * now this doesn't implement asynchronous commits. - * - * RETURNS - * Zero for success or -errno. - */ -static int vc4_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - int ret; - - if (state->async_update) { - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - drm_atomic_helper_async_commit(dev, state); - - drm_atomic_helper_cleanup_planes(dev, state); - - return 0; - } - - /* We know for sure we don't want an async update here. Set - * state->legacy_cursor_update to false to prevent - * drm_atomic_helper_setup_commit() from auto-completing - * commit->flip_done. - */ - state->legacy_cursor_update = false; - ret = drm_atomic_helper_setup_commit(state, nonblock); - if (ret) - return ret; - - INIT_WORK(&state->commit_work, commit_work); - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - if (!nonblock) { - ret = drm_atomic_helper_wait_for_fences(dev, state, true); - if (ret) { - drm_atomic_helper_cleanup_planes(dev, state); - return ret; - } - } - - /* - * This is the point of no return - everything below never fails except - * when the hw goes bonghits. Which means we can commit the new state on - * the software side now. - */ - - BUG_ON(drm_atomic_helper_swap_state(state, false) < 0); - - /* - * Everything below can be run asynchronously without the need to grab - * any modeset locks at all under one condition: It must be guaranteed - * that the asynchronous work has either been cancelled (if the driver - * supports it, which at least requires that the framebuffers get - * cleaned up with drm_atomic_helper_cleanup_planes()) or completed - * before the new state gets committed on the software side with - * drm_atomic_helper_swap_state(). - * - * This scheme allows new atomic state updates to be prepared and - * checked in parallel to the asynchronous completion of the previous - * update. Which is important since compositors need to figure out the - * composition of the next frame right after having submitted the - * current layout. - */ - - drm_atomic_state_get(state); - if (nonblock) - queue_work(system_unbound_wq, &state->commit_work); - else - vc4_atomic_complete_commit(state); - - return 0; -} - static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) @@ -966,11 +861,12 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = { .atomic_commit_setup = vc4_atomic_commit_setup, + .atomic_commit_tail = vc4_atomic_commit_tail, }; static const struct drm_mode_config_funcs vc4_mode_funcs = { .atomic_check = vc4_atomic_check, - .atomic_commit = vc4_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, .fb_create = vc4_fb_create, }; -- cgit v1.2.3 From 6ca2ab8086af8434a4c0990882321a345c3cc2c6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 11 Dec 2020 13:42:36 +0200 Subject: drm: automatic legacy gamma support To support legacy gamma ioctls the drivers need to set drm_crtc_funcs.gamma_set either to a custom implementation or to drm_atomic_helper_legacy_gamma_set. Most of the atomic drivers do the latter. We can simplify this by making the core handle it automatically. Move the drm_atomic_helper_legacy_gamma_set() functionality into drm_color_mgmt.c to make drm_mode_gamma_set_ioctl() use drm_crtc_funcs.gamma_set if set or GAMMA_LUT property if not. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Reviewed-by: Philippe Cornu Link: https://patchwork.freedesktop.org/patch/msgid/20201211114237.213288-2-tomi.valkeinen@ti.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 - drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 1 - drivers/gpu/drm/arm/malidp_crtc.c | 1 - drivers/gpu/drm/armada/armada_crtc.c | 1 - drivers/gpu/drm/ast/ast_mode.c | 1 - drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 1 - drivers/gpu/drm/drm_atomic_helper.c | 70 -------------- drivers/gpu/drm/drm_color_mgmt.c | 111 ++++++++++++++++++++-- drivers/gpu/drm/i915/display/intel_display.c | 1 - drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 2 - drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 1 - drivers/gpu/drm/nouveau/dispnv50/head.c | 2 - drivers/gpu/drm/omapdrm/omap_crtc.c | 1 - drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 1 - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 - drivers/gpu/drm/stm/ltdc.c | 1 - drivers/gpu/drm/vc4/vc4_crtc.c | 1 - drivers/gpu/drm/vc4/vc4_txp.c | 1 - include/drm/drm_atomic_helper.h | 4 - 19 files changed, 102 insertions(+), 101 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c23896207e9d..5675c1f9368a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5452,7 +5452,6 @@ static void dm_disable_vblank(struct drm_crtc *crtc) static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .reset = dm_crtc_reset_state, .destroy = amdgpu_dm_crtc_destroy, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = dm_crtc_duplicate_state, diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 4b485eb512e2..59172acb9738 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -550,7 +550,6 @@ static void komeda_crtc_vblank_disable(struct drm_crtc *crtc) } static const struct drm_crtc_funcs komeda_crtc_funcs = { - .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index 108e7a31bd26..494075ddbef6 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -510,7 +510,6 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc) } static const struct drm_crtc_funcs malidp_crtc_funcs = { - .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 3ebcf5a52c8b..b7bb90ae787f 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -820,7 +820,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .cursor_set = armada_drm_crtc_cursor_set, .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 9db371f4054f..5b0ec785c516 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -903,7 +903,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, static const struct drm_crtc_funcs ast_crtc_funcs = { .reset = ast_crtc_reset, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index c58fa00b4848..05ad75d155e8 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -473,7 +473,6 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state, .enable_vblank = atmel_hlcdc_crtc_enable_vblank, .disable_vblank = atmel_hlcdc_crtc_disable_vblank, - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; int atmel_hlcdc_crtc_create(struct drm_device *dev) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7fcf91ecb1d9..a84dc427cf82 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3508,76 +3508,6 @@ fail: } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); -/** - * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table - * @crtc: CRTC object - * @red: red correction table - * @green: green correction table - * @blue: green correction table - * @size: size of the tables - * @ctx: lock acquire context - * - * Implements support for legacy gamma correction table for drivers - * that support color management through the DEGAMMA_LUT/GAMMA_LUT - * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for - * how the atomic color management and gamma tables work. - */ -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_device *dev = crtc->dev; - struct drm_atomic_state *state; - struct drm_crtc_state *crtc_state; - struct drm_property_blob *blob = NULL; - struct drm_color_lut *blob_data; - int i, ret = 0; - bool replaced; - - state = drm_atomic_state_alloc(crtc->dev); - if (!state) - return -ENOMEM; - - blob = drm_property_create_blob(dev, - sizeof(struct drm_color_lut) * size, - NULL); - if (IS_ERR(blob)) { - ret = PTR_ERR(blob); - blob = NULL; - goto fail; - } - - /* Prepare GAMMA_LUT with the legacy values. */ - blob_data = blob->data; - for (i = 0; i < size; i++) { - blob_data[i].red = red[i]; - blob_data[i].green = green[i]; - blob_data[i].blue = blue[i]; - } - - state->acquire_ctx = ctx; - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto fail; - } - - /* Reset DEGAMMA_LUT and CTM properties. */ - replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); - replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); - replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); - crtc_state->color_mgmt_changed |= replaced; - - ret = drm_atomic_commit(state); - -fail: - drm_atomic_state_put(state); - drm_property_blob_put(blob); - return ret; -} -EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); - /** * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to * the input end of a bridge diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 3bcabc2f6e0e..553f423a8498 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -89,9 +90,8 @@ * 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_mode_crtc_set_gamma_size(). The DRM core will then alias the legacy gamma + * ramp with "GAMMA_LUT". * * Support for different non RGB color encodings is controlled through * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They @@ -156,9 +156,6 @@ EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n); * 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. - * - * Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the - * legacy &drm_crtc_funcs.gamma_set callback. */ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, uint degamma_lut_size, @@ -231,6 +228,102 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); +/** + * drm_crtc_supports_legacy_gamma - does the crtc support legacy gamma correction table + * @crtc: CRTC object + * + * Returns true/false if the given crtc supports setting the legacy gamma + * correction table. + */ +static bool drm_crtc_supports_legacy_gamma(struct drm_crtc *crtc) +{ + u32 gamma_id = crtc->dev->mode_config.gamma_lut_property->base.id; + + if (!crtc->gamma_size) + return false; + + if (crtc->funcs->gamma_set) + return true; + + return !!drm_mode_obj_find_prop_id(&crtc->base, gamma_id); +} + +/** + * drm_crtc_legacy_gamma_set - set the legacy gamma correction table + * @crtc: CRTC object + * @red: red correction table + * @green: green correction table + * @blue: green correction table + * @size: size of the tables + * @ctx: lock acquire context + * + * Implements support for legacy gamma correction table for drivers + * that have set drm_crtc_funcs.gamma_set or that support color management + * through the DEGAMMA_LUT/GAMMA_LUT properties. See + * drm_crtc_enable_color_mgmt() and the containing chapter for + * how the atomic color management and gamma tables work. + * + * This function sets the gamma using drm_crtc_funcs.gamma_set if set, or + * alternatively using crtc color management properties. + */ +static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + u32 size, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_device *dev = crtc->dev; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_property_blob *blob; + struct drm_color_lut *blob_data; + int i, ret = 0; + bool replaced; + + if (crtc->funcs->gamma_set) + return crtc->funcs->gamma_set(crtc, red, green, blue, size, ctx); + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return -ENOMEM; + + blob = drm_property_create_blob(dev, + sizeof(struct drm_color_lut) * size, + NULL); + if (IS_ERR(blob)) { + ret = PTR_ERR(blob); + blob = NULL; + goto fail; + } + + /* Prepare GAMMA_LUT with the legacy values. */ + blob_data = blob->data; + for (i = 0; i < size; i++) { + blob_data[i].red = red[i]; + blob_data[i].green = green[i]; + blob_data[i].blue = blue[i]; + } + + state->acquire_ctx = ctx; + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + /* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */ + replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); + replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); + replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); + crtc_state->color_mgmt_changed |= replaced; + + ret = drm_atomic_commit(state); + +fail: + drm_atomic_state_put(state); + drm_property_blob_put(blob); + return ret; +} + /** * drm_mode_gamma_set_ioctl - set the gamma table * @dev: DRM device @@ -262,7 +355,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, if (!crtc) return -ENOENT; - if (crtc->funcs->gamma_set == NULL) + if (!drm_crtc_supports_legacy_gamma(crtc)) return -ENOSYS; /* memcpy into gamma store */ @@ -290,8 +383,8 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, goto out; } - ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, - crtc->gamma_size, &ctx); + ret = drm_crtc_legacy_gamma_set(crtc, r_base, g_base, b_base, + crtc->gamma_size, &ctx); out: DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 53a00cf3fa32..3d53ec508a66 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -17267,7 +17267,6 @@ fail: } #define INTEL_CRTC_FUNCS \ - .gamma_set = drm_atomic_helper_legacy_gamma_set, \ .set_config = drm_atomic_helper_set_config, \ .destroy = intel_crtc_destroy, \ .page_flip = drm_atomic_helper_page_flip, \ diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 42d335d3a114..7bb31fbee29d 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -774,8 +774,6 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = { .enable_vblank = ingenic_drm_enable_vblank, .disable_vblank = ingenic_drm_disable_vblank, - - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = { diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index bfe994230543..b665bd498a4a 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -619,7 +619,6 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = { .reset = mtk_drm_crtc_reset, .atomic_duplicate_state = mtk_drm_crtc_duplicate_state, .atomic_destroy_state = mtk_drm_crtc_destroy_state, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .enable_vblank = mtk_drm_crtc_enable_vblank, .disable_vblank = mtk_drm_crtc_disable_vblank, }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 537c1ef2e464..ec361d17e900 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -503,7 +503,6 @@ nv50_head_destroy(struct drm_crtc *crtc) static const struct drm_crtc_funcs nv50_head_func = { .reset = nv50_head_reset, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = nv50_head_destroy, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -518,7 +517,6 @@ nv50_head_func = { static const struct drm_crtc_funcs nvd9_head_func = { .reset = nv50_head_reset, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = nv50_head_destroy, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 7d66269ad998..b97f21cf4a91 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -741,7 +741,6 @@ static const struct drm_crtc_funcs omap_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = omap_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .atomic_duplicate_state = omap_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_set_property = omap_crtc_atomic_set_property, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index b5fb941e0f53..f93e0750431d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -1144,7 +1144,6 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = { .set_crc_source = rcar_du_crtc_set_crc_source, .verify_crc_source = rcar_du_crtc_verify_crc_source, .get_crc_sources = rcar_du_crtc_get_crc_sources, - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d1e05482641b..8d15cabdcb02 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1643,7 +1643,6 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { .disable_vblank = vop_crtc_disable_vblank, .set_crc_source = vop_crtc_set_crc_source, .verify_crc_source = vop_crtc_verify_crc_source, - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 3980677435cb..7812094f93d6 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -713,7 +713,6 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = { .enable_vblank = ltdc_crtc_enable_vblank, .disable_vblank = ltdc_crtc_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, - .gamma_set = drm_atomic_helper_legacy_gamma_set, }; /* diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index ee4f657a5ce0..a8199a257328 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -871,7 +871,6 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { .reset = vc4_crtc_reset, .atomic_duplicate_state = vc4_crtc_duplicate_state, .atomic_destroy_state = vc4_crtc_destroy_state, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .enable_vblank = vc4_enable_vblank, .disable_vblank = vc4_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 8aa5220885f4..e4b782e42f69 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -382,7 +382,6 @@ static const struct drm_crtc_funcs vc4_txp_crtc_funcs = { .reset = vc4_crtc_reset, .atomic_duplicate_state = vc4_crtc_duplicate_state, .atomic_destroy_state = vc4_crtc_destroy_state, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .enable_vblank = vc4_txp_enable_vblank, .disable_vblank = vc4_txp_disable_vblank, }; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 5f47720440fa..4045e2507e11 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -147,10 +147,6 @@ int drm_atomic_helper_page_flip_target( uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx); -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx); /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC -- cgit v1.2.3 From ee6965c864e3f5e05304ea07ede452d13980f754 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:35 +0100 Subject: drm/vc4: hvs: Align the HVS atomic hooks to the new API Since the CRTC setup in vc4 is split between the PixelValves/TXP and the HVS, only the PV/TXP atomic hooks were updated in the previous commits, but it makes sense to update the HVS ones too. Reviewed-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-2-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++---- drivers/gpu/drm/vc4/vc4_drv.h | 9 ++++----- drivers/gpu/drm/vc4/vc4_hvs.c | 18 ++++++++++-------- drivers/gpu/drm/vc4/vc4_txp.c | 10 +++------- 4 files changed, 19 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index a8199a257328..db71c0ab1337 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -503,8 +503,6 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, - crtc); struct drm_device *dev = crtc->dev; struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc); @@ -517,7 +515,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, */ drm_crtc_vblank_on(crtc); - vc4_hvs_atomic_enable(crtc, old_state); + vc4_hvs_atomic_enable(crtc, state); if (vc4_encoder->pre_crtc_configure) vc4_encoder->pre_crtc_configure(encoder); @@ -593,7 +591,7 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_connector_state *conn_state; int ret, i; - ret = vc4_hvs_atomic_check(crtc, crtc_state); + ret = vc4_hvs_atomic_check(crtc, state); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 6db4c944ecba..5a115bc62cc8 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -913,11 +913,10 @@ void vc4_irq_reset(struct drm_device *dev); extern struct platform_driver vc4_hvs_driver; void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output); int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output); -int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state); -void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state); -void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state); -void vc4_hvs_atomic_flush(struct drm_crtc *crtc, - struct drm_atomic_state *state); +int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); +void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state); +void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state); +void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_dump_state(struct drm_device *dev); void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel); void vc4_hvs_mask_underrun(struct drm_device *dev, int channel); diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index cccd341e5d67..2b3a597fa65f 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -326,10 +326,10 @@ void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan) SCALER_DISPSTATX_EMPTY); } -int vc4_hvs_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) +int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_plane *plane; @@ -341,10 +341,10 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, /* The pixelvalve can only feed one encoder (and encoders are * 1:1 with connectors.) */ - if (hweight32(state->connector_mask) > 1) + if (hweight32(crtc_state->connector_mask) > 1) return -EINVAL; - drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, state) + drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) dlist_count += vc4_plane_dlist_size(plane_state); dlist_count++; /* Account for SCALER_CTL0_END. */ @@ -391,11 +391,12 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) } void vc4_hvs_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state); struct drm_display_mode *mode = &crtc->state->adjusted_mode; bool oneshot = vc4_state->feed_txp; @@ -404,9 +405,10 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, } void vc4_hvs_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; + struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state); unsigned int chan = vc4_state->assigned_channel; diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index e4b782e42f69..c0122d83b651 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -394,7 +394,7 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc, struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); int ret; - ret = vc4_hvs_atomic_check(crtc, crtc_state); + ret = vc4_hvs_atomic_check(crtc, state); if (ret) return ret; @@ -407,23 +407,19 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc, static void vc4_txp_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, - crtc); drm_crtc_vblank_on(crtc); - vc4_hvs_atomic_enable(crtc, old_state); + vc4_hvs_atomic_enable(crtc, state); } static void vc4_txp_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, - crtc); struct drm_device *dev = crtc->dev; /* Disable vblank irq handling before crtc is disabled. */ drm_crtc_vblank_off(crtc); - vc4_hvs_atomic_disable(crtc, old_state); + vc4_hvs_atomic_disable(crtc, state); /* * Make sure we issue a vblank event after disabling the CRTC if -- cgit v1.2.3 From 8d9147466776c44b6d259077041fa24dcca63abc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:36 +0100 Subject: drm/vc4: Pass the atomic state to encoder hooks We'll need to access the connector state in our encoder setup, so let's just pass the whole DRM state to our private encoder hooks. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-3-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_crtc.c | 18 ++++++++++-------- drivers/gpu/drm/vc4/vc4_drv.h | 10 +++++----- drivers/gpu/drm/vc4/vc4_hdmi.c | 15 ++++++++++----- 3 files changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index db71c0ab1337..269390bc586e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -403,7 +403,9 @@ static void require_hvs_enabled(struct drm_device *dev) SCALER_DISPCTRL_ENABLE); } -static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel) +static int vc4_crtc_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state, + unsigned int channel) { struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc); struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); @@ -435,13 +437,13 @@ static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel) mdelay(20); if (vc4_encoder && vc4_encoder->post_crtc_disable) - vc4_encoder->post_crtc_disable(encoder); + vc4_encoder->post_crtc_disable(encoder, state); vc4_crtc_pixelvalve_reset(crtc); vc4_hvs_stop_channel(dev, channel); if (vc4_encoder && vc4_encoder->post_crtc_powerdown) - vc4_encoder->post_crtc_powerdown(encoder); + vc4_encoder->post_crtc_powerdown(encoder, state); return 0; } @@ -468,7 +470,7 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) if (channel < 0) return 0; - return vc4_crtc_disable(crtc, channel); + return vc4_crtc_disable(crtc, NULL, channel); } static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, @@ -484,7 +486,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, /* Disable vblank irq handling before crtc is disabled. */ drm_crtc_vblank_off(crtc); - vc4_crtc_disable(crtc, old_vc4_state->assigned_channel); + vc4_crtc_disable(crtc, state, old_vc4_state->assigned_channel); /* * Make sure we issue a vblank event after disabling the CRTC if @@ -518,14 +520,14 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, vc4_hvs_atomic_enable(crtc, state); if (vc4_encoder->pre_crtc_configure) - vc4_encoder->pre_crtc_configure(encoder); + vc4_encoder->pre_crtc_configure(encoder, state); vc4_crtc_config_pv(crtc); CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN); if (vc4_encoder->pre_crtc_enable) - vc4_encoder->pre_crtc_enable(encoder); + vc4_encoder->pre_crtc_enable(encoder, state); /* When feeding the transposer block the pixelvalve is unneeded and * should not be enabled. @@ -534,7 +536,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); if (vc4_encoder->post_crtc_enable) - vc4_encoder->post_crtc_enable(encoder); + vc4_encoder->post_crtc_enable(encoder, state); } static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 5a115bc62cc8..051ad4e31e52 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -441,12 +441,12 @@ struct vc4_encoder { enum vc4_encoder_type type; u32 clock_select; - void (*pre_crtc_configure)(struct drm_encoder *encoder); - void (*pre_crtc_enable)(struct drm_encoder *encoder); - void (*post_crtc_enable)(struct drm_encoder *encoder); + void (*pre_crtc_configure)(struct drm_encoder *encoder, struct drm_atomic_state *state); + void (*pre_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state); + void (*post_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state); - void (*post_crtc_disable)(struct drm_encoder *encoder); - void (*post_crtc_powerdown)(struct drm_encoder *encoder); + void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state); + void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state); }; static inline struct vc4_encoder * diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 9f8d74e32355..8ce5dd65f6e4 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -360,7 +360,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) vc4_hdmi_set_audio_infoframe(encoder); } -static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder) +static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); @@ -373,7 +374,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder) HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); } -static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder) +static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); int ret; @@ -587,7 +589,8 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); } -static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder) +static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); @@ -679,7 +682,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder) vc4_hdmi->variant->set_timings(vc4_hdmi, mode); } -static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder) +static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); @@ -701,7 +705,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder) HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); } -static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder) +static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); -- cgit v1.2.3 From 320e84dc6111ecc1c957e2b186d4d2bafee6bde2 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:37 +0100 Subject: drm/vc4: hdmi: Take into account the clock doubling flag in atomic_check Commit 63495f6b4aed ("drm/vc4: hdmi: Make sure our clock rate is within limits") was intended to compute the pixel rate to make sure we remain within the boundaries of what the hardware can provide. However, unlike what mode_valid was checking for, we forgot to take into account the clock doubling flag that can be set for modes. Let's honor that flag if it's there. Acked-by: Thomas Zimmermann Reported-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Fixes: 63495f6b4aed ("drm/vc4: hdmi: Make sure our clock rate is within limits") Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-4-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 8ce5dd65f6e4..3dac839b0fa5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -799,6 +799,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, pixel_rate = mode->clock * 1000; } + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + pixel_rate = pixel_rate * 2; + if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) return -EINVAL; -- cgit v1.2.3 From e55a07751146ef8ebc2c561564437b78f46405d3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:38 +0100 Subject: drm/vc4: hdmi: Don't access the connector state in reset if kmalloc fails drm_atomic_helper_connector_reset uses kmalloc which, from an API standpoint, can fail, and thus setting connector->state to NULL. However, our reset hook then calls drm_atomic_helper_connector_tv_reset that will access connector->state without checking if it's a valid pointer or not. Make sure we don't end up accessing a NULL pointer. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Suggested-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-5-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 3dac839b0fa5..920895deb2e7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -171,7 +171,9 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) static void vc4_hdmi_connector_reset(struct drm_connector *connector) { drm_atomic_helper_connector_reset(connector); - drm_atomic_helper_connector_tv_reset(connector); + + if (connector->state) + drm_atomic_helper_connector_tv_reset(connector); } static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { -- cgit v1.2.3 From fbe7271e47bebd7600fec171bce9d5bf066275f8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:39 +0100 Subject: drm/vc4: hdmi: Create a custom connector state When run with a higher bpc than 8, the clock of the HDMI controller needs to be adjusted. Let's create a connector state that will be used at atomic_check and atomic_enable to compute and store the clock rate associated to the state. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Reviewed-by: Dave Stevenson Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-6-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 33 ++++++++++++++++++++++++++++++--- drivers/gpu/drm/vc4/vc4_hdmi.h | 10 ++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 920895deb2e7..d22a0dbd0ce2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -170,10 +170,37 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) static void vc4_hdmi_connector_reset(struct drm_connector *connector) { - drm_atomic_helper_connector_reset(connector); + struct vc4_hdmi_connector_state *old_state = + conn_state_to_vc4_hdmi_conn_state(connector->state); + struct vc4_hdmi_connector_state *new_state = + kzalloc(sizeof(*new_state), GFP_KERNEL); if (connector->state) - drm_atomic_helper_connector_tv_reset(connector); + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(old_state); + __drm_atomic_helper_connector_reset(connector, &new_state->base); + + if (!new_state) + return; + + drm_atomic_helper_connector_tv_reset(connector); +} + +static struct drm_connector_state * +vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) +{ + struct drm_connector_state *conn_state = connector->state; + struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state); + struct vc4_hdmi_connector_state *new_state; + + new_state = kzalloc(sizeof(*new_state), GFP_KERNEL); + if (!new_state) + return NULL; + + __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); + + return &new_state->base; } static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { @@ -181,7 +208,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .destroy = vc4_hdmi_connector_destroy, .reset = vc4_hdmi_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 0526a9cf608a..2cf5362052e2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -180,6 +180,16 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder) return container_of(_encoder, struct vc4_hdmi, encoder); } +struct vc4_hdmi_connector_state { + struct drm_connector_state base; +}; + +static inline struct vc4_hdmi_connector_state * +conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state) +{ + return container_of(conn_state, struct vc4_hdmi_connector_state, base); +} + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode); void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); -- cgit v1.2.3 From f623746f74721be7ac1cf10e0f5e731f30d191b0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:40 +0100 Subject: drm/vc4: hdmi: Store pixel frequency in the connector state The pixel rate is for now quite simple to compute, but with more features (30 and 36 bits output, YUV output, etc.) will depend on a bunch of connectors properties. Let's store the rate we have to run the pixel clock at in our custom connector state, and compute it in atomic_check. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-7-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 26 +++++++++++++++++++++++++- drivers/gpu/drm/vc4/vc4_hdmi.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d22a0dbd0ce2..a6422d7af019 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -198,6 +198,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) if (!new_state) return NULL; + new_state->pixel_rate = vc4_state->pixel_rate; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -618,9 +619,29 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); } +static struct drm_connector_state * +vc4_hdmi_encoder_get_connector_state(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_connector_state *conn_state; + struct drm_connector *connector; + unsigned int i; + + for_each_new_connector_in_state(state, connector, conn_state, i) { + if (conn_state->best_encoder == encoder) + return conn_state; + } + + return NULL; +} + static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, struct drm_atomic_state *state) { + struct drm_connector_state *conn_state = + vc4_hdmi_encoder_get_connector_state(encoder, state); + struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(conn_state); struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long pixel_rate, hsm_rate; @@ -632,7 +653,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, return; } - pixel_rate = mode->clock * 1000 * ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1); + pixel_rate = vc4_conn_state->pixel_rate; ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate); if (ret) { DRM_ERROR("Failed to set pixel clock rate: %d\n", ret); @@ -804,6 +825,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(conn_state); struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long long pixel_rate = mode->clock * 1000; @@ -834,6 +856,8 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) return -EINVAL; + vc4_state->pixel_rate = pixel_rate; + return 0; } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 2cf5362052e2..bca6943de884 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -182,6 +182,7 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder) struct vc4_hdmi_connector_state { struct drm_connector_state base; + unsigned long long pixel_rate; }; static inline struct vc4_hdmi_connector_state * -- cgit v1.2.3 From d2a7dd004c49e547999d75099218d9d0198030fe Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:41 +0100 Subject: drm/vc4: hdmi: Use the connector state pixel rate for the PHY The PHY initialisation parameters are not based on the pixel clock but the TMDS clock rate which can be the pixel clock in the standard case, but could be adjusted based on some parameters like the bits per color. Since the TMDS clock rate is stored in our custom connector state already, let's reuse it from there instead of computing it again. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-8-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- drivers/gpu/drm/vc4/vc4_hdmi.h | 11 +++++------ drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 8 +++++--- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index a6422d7af019..dbe516d89726 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -721,7 +721,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, vc4_hdmi->variant->reset(vc4_hdmi); if (vc4_hdmi->variant->phy_init) - vc4_hdmi->variant->phy_init(vc4_hdmi, mode); + vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state); HDMI_WRITE(HDMI_SCHEDULER_CONTROL, HDMI_READ(HDMI_SCHEDULER_CONTROL) | diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index bca6943de884..60c53d7c9bad 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -21,10 +21,9 @@ to_vc4_hdmi_encoder(struct drm_encoder *encoder) return container_of(encoder, struct vc4_hdmi_encoder, base.base); } -struct drm_display_mode; - struct vc4_hdmi; struct vc4_hdmi_register; +struct vc4_hdmi_connector_state; enum vc4_hdmi_phy_channel { PHY_LANE_0 = 0, @@ -80,9 +79,9 @@ struct vc4_hdmi_variant { void (*set_timings)(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode); - /* Callback to initialize the PHY according to the mode */ + /* Callback to initialize the PHY according to the connector state */ void (*phy_init)(struct vc4_hdmi *vc4_hdmi, - struct drm_display_mode *mode); + struct vc4_hdmi_connector_state *vc4_conn_state); /* Callback to disable the PHY */ void (*phy_disable)(struct vc4_hdmi *vc4_hdmi); @@ -192,13 +191,13 @@ conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state) } void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, - struct drm_display_mode *mode); + struct vc4_hdmi_connector_state *vc4_conn_state); void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, - struct drm_display_mode *mode); + struct vc4_hdmi_connector_state *vc4_conn_state); void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c index 057796b54c51..36535480f8e2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c @@ -127,7 +127,8 @@ #define OSCILLATOR_FREQUENCY 54000000 -void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) +void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *conn_state) { /* PHY should be in reset, like * vc4_hdmi_encoder_disable() does. @@ -339,11 +340,12 @@ static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10)); } -void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) +void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *conn_state) { const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings; const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; - unsigned long long pixel_freq = mode->clock * 1000; + unsigned long long pixel_freq = conn_state->pixel_rate; unsigned long long vco_freq; unsigned char word_sel; u8 vco_sel, vco_div; -- cgit v1.2.3 From 24169a2b0533a6c4030c91a7a074039e7c98fde6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:42 +0100 Subject: drm/vc4: hdmi: Limit the BCM2711 to the max without scrambling Unlike the previous generations, the HSM clock limitation is way above what we can reach without scrambling, so let's move the maximum frequency we support to the maximum clock frequency without scrambling. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-9-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index dbe516d89726..41897b8e9d51 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -82,6 +82,8 @@ #define CEC_CLOCK_FREQ 40000 #define VC4_HSM_MID_CLOCK 149985000 +#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *)m->private; @@ -1918,7 +1920,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { .encoder_type = VC4_ENCODER_TYPE_HDMI0, .debugfs_name = "hdmi0_regs", .card_name = "vc4-hdmi-0", - .max_pixel_clock = 297000000, + .max_pixel_clock = HDMI_14_MAX_TMDS_CLK, .registers = vc5_hdmi_hdmi0_fields, .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields), .phy_lane_mapping = { @@ -1944,7 +1946,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { .encoder_type = VC4_ENCODER_TYPE_HDMI1, .debugfs_name = "hdmi1_regs", .card_name = "vc4-hdmi-1", - .max_pixel_clock = 297000000, + .max_pixel_clock = HDMI_14_MAX_TMDS_CLK, .registers = vc5_hdmi_hdmi1_fields, .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields), .phy_lane_mapping = { -- cgit v1.2.3 From ba8c0faebbb0af3f65495992a6543f9d424fd0a3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 15 Dec 2020 16:42:43 +0100 Subject: drm/vc4: hdmi: Enable 10/12 bpc output The BCM2711 supports higher bpc count than just 8, so let's support it in our driver. Signed-off-by: Maxime Ripard Reviewed-by: Dave Stevenson Link: https://patchwork.freedesktop.org/patch/msgid/20201215154243.540115-10-maxime@cerno.tech --- drivers/gpu/drm/vc4/vc4_hdmi.c | 70 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vc4/vc4_hdmi.h | 1 + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 9 +++++ 3 files changed, 79 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 41897b8e9d51..2e5449b25ce4 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -76,6 +76,17 @@ #define VC5_HDMI_VERTB_VSPO_SHIFT 16 #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) +#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8 +#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8) + +#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_SHIFT 0 +#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK VC4_MASK(3, 0) + +#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE BIT(31) + +#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT 8 +#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK VC4_MASK(15, 8) + # define VC4_HD_M_SW_RST BIT(2) # define VC4_HD_M_ENABLE BIT(0) @@ -186,6 +197,8 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) if (!new_state) return; + new_state->base.max_bpc = 8; + new_state->base.max_requested_bpc = 8; drm_atomic_helper_connector_tv_reset(connector); } @@ -232,12 +245,20 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, vc4_hdmi->ddc); drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); + /* + * Some of the properties below require access to state, like bpc. + * Allocate some default initial connector state with our reset helper. + */ + if (connector->funcs->reset) + connector->funcs->reset(connector); + /* Create and attach TV margin props to this connector. */ ret = drm_mode_create_tv_margin_properties(dev); if (ret) return ret; drm_connector_attach_tv_margin_properties(connector); + drm_connector_attach_max_bpc_property(connector, 8, 12); connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT); @@ -506,6 +527,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) } static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, struct drm_display_mode *mode) { bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; @@ -549,7 +571,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VERTB0, vertb_even); HDMI_WRITE(HDMI_VERTB1, vertb); } + static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, struct drm_display_mode *mode) { bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; @@ -569,6 +593,9 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, mode->crtc_vsync_end - interlaced, VC4_HDMI_VERTB_VBP)); + unsigned char gcp; + bool gcp_en; + u32 reg; HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); HDMI_WRITE(HDMI_HORZA, @@ -594,6 +621,39 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VERTB0, vertb_even); HDMI_WRITE(HDMI_VERTB1, vertb); + switch (state->max_bpc) { + case 12: + gcp = 6; + gcp_en = true; + break; + case 10: + gcp = 5; + gcp_en = true; + break; + case 8: + default: + gcp = 4; + gcp_en = false; + break; + } + + reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1); + reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK | + VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK); + reg |= VC4_SET_FIELD(2, VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE) | + VC4_SET_FIELD(gcp, VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH); + HDMI_WRITE(HDMI_DEEP_COLOR_CONFIG_1, reg); + + reg = HDMI_READ(HDMI_GCP_WORD_1); + reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK; + reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1); + HDMI_WRITE(HDMI_GCP_WORD_1, reg); + + reg = HDMI_READ(HDMI_GCP_CONFIG); + reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE; + reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0; + HDMI_WRITE(HDMI_GCP_CONFIG, reg); + HDMI_WRITE(HDMI_CLOCK_STOP, 0); } @@ -731,7 +791,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); if (vc4_hdmi->variant->set_timings) - vc4_hdmi->variant->set_timings(vc4_hdmi, mode); + vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode); } static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, @@ -852,6 +912,14 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, pixel_rate = mode->clock * 1000; } + if (conn_state->max_bpc == 12) { + pixel_rate = pixel_rate * 150; + do_div(pixel_rate, 100); + } else if (conn_state->max_bpc == 10) { + pixel_rate = pixel_rate * 125; + do_div(pixel_rate, 100); + } + if (mode->flags & DRM_MODE_FLAG_DBLCLK) pixel_rate = pixel_rate * 2; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 60c53d7c9bad..4c8994cfd932 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -77,6 +77,7 @@ struct vc4_hdmi_variant { /* Callback to configure the video timings in the HDMI block */ void (*set_timings)(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, struct drm_display_mode *mode); /* Callback to initialize the PHY according to the connector state */ diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 96d764ebfe67..401863cb8c98 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -59,9 +59,12 @@ enum vc4_hdmi_field { */ HDMI_CTS_0, HDMI_CTS_1, + HDMI_DEEP_COLOR_CONFIG_1, HDMI_DVP_CTL, HDMI_FIFO_CTL, HDMI_FRAME_COUNT, + HDMI_GCP_CONFIG, + HDMI_GCP_WORD_1, HDMI_HORZA, HDMI_HORZB, HDMI_HOTPLUG, @@ -229,6 +232,9 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = { VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), + VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170), + VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178), + VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c), VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), @@ -305,6 +311,9 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = { VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), + VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170), + VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178), + VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c), VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), -- cgit v1.2.3 From 57b155f00259642562781895ce69ca8bdc9786f9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Jan 2018 23:15:18 +0200 Subject: drm: vc4: Remove unnecessary drm_plane_cleanup() wrapper Use the drm_plane_cleanup() function directly as the drm_plane_funcs .destroy() handler without creating an unnecessary wrapper around it. Signed-off-by: Laurent Pinchart Acked-by: Maxime Ripard Acked-by: Daniel Vetter --- drivers/gpu/drm/vc4/vc4_plane.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 6b39cc2ca18d..6bd8260aa9f2 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1268,11 +1268,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { .atomic_async_update = vc4_plane_atomic_async_update, }; -static void vc4_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); -} - static bool vc4_format_mod_supported(struct drm_plane *plane, uint32_t format, uint64_t modifier) @@ -1323,7 +1318,7 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, static const struct drm_plane_funcs vc4_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = vc4_plane_destroy, + .destroy = drm_plane_cleanup, .set_property = NULL, .reset = vc4_plane_reset, .atomic_duplicate_state = vc4_plane_duplicate_state, -- cgit v1.2.3 From b100ed1ee8f27306be9ed523ebd5681acdd17134 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 8 Jan 2021 15:08:06 +0100 Subject: drm/vc4: Use drm_gem_cma_vmap() directly Validated shaders cannot be exported. There's no need for testing this in the BO's vmap implementation. Call drm_gem_cma_vmap() directly instead. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210108140808.25775-2-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_bo.c | 14 +------------- drivers/gpu/drm/vc4/vc4_drv.h | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index dc316cb79e00..eff12be616b0 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -386,7 +386,7 @@ static const struct drm_gem_object_funcs vc4_gem_object_funcs = { .free = vc4_free_object, .export = vc4_prime_export, .get_sg_table = drm_gem_cma_get_sg_table, - .vmap = vc4_prime_vmap, + .vmap = drm_gem_cma_vmap, .vm_ops = &vc4_vm_ops, }; @@ -785,18 +785,6 @@ int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) return drm_gem_prime_mmap(obj, vma); } -int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) -{ - struct vc4_bo *bo = to_vc4_bo(obj); - - if (bo->validated_shader) { - DRM_DEBUG("mmaping of shader BOs not allowed.\n"); - return -EINVAL; - } - - return drm_gem_cma_vmap(obj, map); -} - struct drm_gem_object * vc4_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 051ad4e31e52..61848c6f85ad 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -808,7 +808,6 @@ int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); -int vc4_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); int vc4_bo_cache_init(struct drm_device *dev); int vc4_bo_inc_usecnt(struct vc4_bo *bo); void vc4_bo_dec_usecnt(struct vc4_bo *bo); -- cgit v1.2.3 From ccfe8e9c12f9210d58dda7007b62de3fe4f96108 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 8 Jan 2021 15:08:07 +0100 Subject: drm/vc4: Make several BO functions static Rearrange the code to make BO functions static. This will also help with streamlining the BO's mmap implementation. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210108140808.25775-3-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_bo.c | 34 +++++++++++++++++----------------- drivers/gpu/drm/vc4/vc4_drv.h | 2 -- 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index eff12be616b0..f9b42ff098e3 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -21,7 +21,7 @@ #include "vc4_drv.h" #include "uapi/drm/vc4_drm.h" -static vm_fault_t vc4_fault(struct vm_fault *vmf); +static const struct drm_gem_object_funcs vc4_gem_object_funcs; static const char * const bo_type_names[] = { "kernel", @@ -376,20 +376,6 @@ out: return bo; } -static const struct vm_operations_struct vc4_vm_ops = { - .fault = vc4_fault, - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, -}; - -static const struct drm_gem_object_funcs vc4_gem_object_funcs = { - .free = vc4_free_object, - .export = vc4_prime_export, - .get_sg_table = drm_gem_cma_get_sg_table, - .vmap = drm_gem_cma_vmap, - .vm_ops = &vc4_vm_ops, -}; - /** * vc4_create_object - Implementation of driver->gem_create_object. * @dev: DRM device @@ -538,7 +524,7 @@ static void vc4_bo_cache_free_old(struct drm_device *dev) /* Called on the last userspace/kernel unreference of the BO. Returns * it to the BO cache if possible, otherwise frees it. */ -void vc4_free_object(struct drm_gem_object *gem_bo) +static void vc4_free_object(struct drm_gem_object *gem_bo) { struct drm_device *dev = gem_bo->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); @@ -673,7 +659,7 @@ static void vc4_bo_cache_time_timer(struct timer_list *t) schedule_work(&vc4->bo_cache.time_work); } -struct dma_buf * vc4_prime_export(struct drm_gem_object *obj, int flags) +static struct dma_buf *vc4_prime_export(struct drm_gem_object *obj, int flags) { struct vc4_bo *bo = to_vc4_bo(obj); struct dma_buf *dmabuf; @@ -785,6 +771,20 @@ int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) return drm_gem_prime_mmap(obj, vma); } +static const struct vm_operations_struct vc4_vm_ops = { + .fault = vc4_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static const struct drm_gem_object_funcs vc4_gem_object_funcs = { + .free = vc4_free_object, + .export = vc4_prime_export, + .get_sg_table = drm_gem_cma_get_sg_table, + .vmap = drm_gem_cma_vmap, + .vm_ops = &vc4_vm_ops, +}; + struct drm_gem_object * vc4_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 61848c6f85ad..a3d8d87fe355 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -782,13 +782,11 @@ struct vc4_validated_shader_info { /* vc4_bo.c */ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size); -void vc4_free_object(struct drm_gem_object *gem_obj); struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size, bool from_cache, enum vc4_kernel_bo_type type); int vc4_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); -struct dma_buf *vc4_prime_export(struct drm_gem_object *obj, int flags); int vc4_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From fa49fdbe78a5af9e438608e53ad4d7123f25bd45 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 8 Jan 2021 15:08:08 +0100 Subject: drm/vc4: Move mmap implementation into GEM object function Moving vc4's mmap code from vc4_mmap() into a GEM object function allows for the use drm_gem_mmap() and drm_gem_prime_mmap(). The content of vc4_drm_fpos can then be generated by DEFINE_DRM_GEM_FOPS(). The actual mmap implementation is just a check if the BO is a validated shader plus the default CMA mmap code. Signed-off-by: Thomas Zimmermann Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210108140808.25775-4-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_bo.c | 55 ++++--------------------------------------- drivers/gpu/drm/vc4/vc4_drv.c | 14 ++--------- drivers/gpu/drm/vc4/vc4_drv.h | 2 -- 3 files changed, 6 insertions(+), 65 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index f9b42ff098e3..28e48ef2d295 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -704,19 +704,9 @@ static vm_fault_t vc4_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -int vc4_mmap(struct file *filp, struct vm_area_struct *vma) +static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { - struct drm_gem_object *gem_obj; - unsigned long vm_pgoff; - struct vc4_bo *bo; - int ret; - - ret = drm_gem_mmap(filp, vma); - if (ret) - return ret; - - gem_obj = vma->vm_private_data; - bo = to_vc4_bo(gem_obj); + struct vc4_bo *bo = to_vc4_bo(obj); if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n"); @@ -730,45 +720,7 @@ int vc4_mmap(struct file *filp, struct vm_area_struct *vma) return -EINVAL; } - /* - * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the - * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map - * the whole buffer. - */ - vma->vm_flags &= ~VM_PFNMAP; - - /* This ->vm_pgoff dance is needed to make all parties happy: - * - dma_mmap_wc() uses ->vm_pgoff as an offset within the allocated - * mem-region, hence the need to set it to zero (the value set by - * the DRM core is a virtual offset encoding the GEM object-id) - * - the mmap() core logic needs ->vm_pgoff to be restored to its - * initial value before returning from this function because it - * encodes the offset of this GEM in the dev->anon_inode pseudo-file - * and this information will be used when we invalidate userspace - * mappings with drm_vma_node_unmap() (called from vc4_gem_purge()). - */ - vm_pgoff = vma->vm_pgoff; - vma->vm_pgoff = 0; - ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr, - bo->base.paddr, vma->vm_end - vma->vm_start); - vma->vm_pgoff = vm_pgoff; - - if (ret) - drm_gem_vm_close(vma); - - return ret; -} - -int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -{ - struct vc4_bo *bo = to_vc4_bo(obj); - - if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { - DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n"); - return -EINVAL; - } - - return drm_gem_prime_mmap(obj, vma); + return drm_gem_cma_mmap(obj, vma); } static const struct vm_operations_struct vc4_vm_ops = { @@ -782,6 +734,7 @@ static const struct drm_gem_object_funcs vc4_gem_object_funcs = { .export = vc4_prime_export, .get_sg_table = drm_gem_cma_get_sg_table, .vmap = drm_gem_cma_vmap, + .mmap = vc4_gem_object_mmap, .vm_ops = &vc4_vm_ops, }; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 2cd97a39c286..d9b3bba7f2b7 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -140,17 +140,7 @@ static void vc4_close(struct drm_device *dev, struct drm_file *file) kfree(vc4file); } -static const struct file_operations vc4_drm_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = vc4_mmap, - .poll = drm_poll, - .read = drm_read, - .compat_ioctl = drm_compat_ioctl, - .llseek = noop_llseek, -}; +DEFINE_DRM_GEM_FOPS(vc4_drm_fops); static const struct drm_ioctl_desc vc4_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, DRM_RENDER_ALLOW), @@ -193,7 +183,7 @@ static struct drm_driver vc4_drm_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import_sg_table = vc4_prime_import_sg_table, - .gem_prime_mmap = vc4_prime_mmap, + .gem_prime_mmap = drm_gem_prime_mmap, .dumb_create = vc4_dumb_create, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index a3d8d87fe355..0d9c0ecc4769 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -801,8 +801,6 @@ int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_label_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int vc4_mmap(struct file *filp, struct vm_area_struct *vma); -int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); -- cgit v1.2.3 From 1355a484ef2ab5d4390c99048ec9f6901950a12b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 14 Jan 2021 09:49:49 +0100 Subject: drm/vc4: Initialize vc4_drm_driver with CMA helper defaults The function vc4_prime_import_sg_table() is an otherwise empty wrapper around CMA's drm_gem_cma_prime_import_sg_table(). Removing it in favor of the latter allows to initialize vc4_drm_driver with CMA's initializer macro. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210114084949.29014-1-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_bo.c | 14 -------------- drivers/gpu/drm/vc4/vc4_drv.c | 7 +------ drivers/gpu/drm/vc4/vc4_drv.h | 3 --- 3 files changed, 1 insertion(+), 23 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 28e48ef2d295..fddaeb0b09c1 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -738,20 +738,6 @@ static const struct drm_gem_object_funcs vc4_gem_object_funcs = { .vm_ops = &vc4_vm_ops, }; -struct drm_gem_object * -vc4_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sgt) -{ - struct drm_gem_object *obj; - - obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); - if (IS_ERR(obj)) - return obj; - - return obj; -} - static int vc4_grab_bin_bo(struct vc4_dev *vc4, struct vc4_file *vc4file) { int ret; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index d9b3bba7f2b7..556ad0f02a0d 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -180,12 +180,7 @@ static struct drm_driver vc4_drm_driver = { .gem_create_object = vc4_create_object, - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import_sg_table = vc4_prime_import_sg_table, - .gem_prime_mmap = drm_gem_prime_mmap, - - .dumb_create = vc4_dumb_create, + DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_dumb_create), .ioctls = vc4_drm_ioctls, .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 0d9c0ecc4769..a7500716cf3f 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -801,9 +801,6 @@ int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_label_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sgt); int vc4_bo_cache_init(struct drm_device *dev); int vc4_bo_inc_usecnt(struct vc4_bo *bo); void vc4_bo_dec_usecnt(struct vc4_bo *bo); -- cgit v1.2.3 From 902dc5c19a8fecd3113dd41cc601b34557bdede9 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Mon, 11 Jan 2021 15:22:56 +0100 Subject: drm/vc4: hdmi: Move hdmi reset to bind The hdmi reset got moved to a later point in the commit 9045e91a476b ("drm/vc4: hdmi: Add reset callback"). However, the reset now occurs after vc4_hdmi_cec_init and so tramples the setup of registers like HDMI_CEC_CNTRL_1 This only affects pi0-3 as on pi4 the cec registers are in a separate block Fixes: 9045e91a476b ("drm/vc4: hdmi: Add reset callback") Reviewed-by: Dave Stevenson Signed-off-by: Dom Cobley Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-3-maxime@cerno.tech (cherry picked from commit 7155334f15f360f5c98391c5c7e12af4c13395c4) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index bd7514612e95..94be67aa9ee5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -779,9 +779,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, return; } - if (vc4_hdmi->variant->reset) - vc4_hdmi->variant->reset(vc4_hdmi); - if (vc4_hdmi->variant->phy_init) vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state); @@ -1875,6 +1872,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->disable_wifi_frequencies = of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence"); + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + pm_runtime_enable(dev); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); -- cgit v1.2.3 From 4a59ed546c0511f01a4bf6b886fe34b6cce2513f Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Mon, 11 Jan 2021 15:22:57 +0100 Subject: drm/vc4: hdmi: Fix register offset with longer CEC messages The code prior to 311e305fdb4e ("drm/vc4: hdmi: Implement a register layout abstraction") was relying on the fact that the register offset was incremented by 4 for each readl call. That worked since the register width is 4 bytes. However, since that commit the HDMI_READ macro is now taking an enum, and the offset doesn't increment by 4 but 1 now. Divide the index by 4 to fix this. Fixes: 311e305fdb4e ("drm/vc4: hdmi: Implement a register layout abstraction") Reviewed-by: Dave Stevenson Signed-off-by: Dom Cobley Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-4-maxime@cerno.tech (cherry picked from commit e9c9481f373eb7344f9e973eb28fc6e9d0f46485) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 94be67aa9ee5..184e1f0936c0 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1444,13 +1444,20 @@ static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) { + struct drm_device *dev = vc4_hdmi->connector.dev; struct cec_msg *msg = &vc4_hdmi->cec_rx_msg; unsigned int i; msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >> VC4_HDMI_CEC_REC_WRD_CNT_SHIFT); + + if (msg->len > 16) { + drm_err(dev, "Attempting to read too much data (%d)\n", msg->len); + return; + } + for (i = 0; i < msg->len; i += 4) { - u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + i); + u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + (i >> 2)); msg->msg[i] = val & 0xff; msg->msg[i + 1] = (val >> 8) & 0xff; @@ -1543,11 +1550,17 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + struct drm_device *dev = vc4_hdmi->connector.dev; u32 val; unsigned int i; + if (msg->len > 16) { + drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len); + return -ENOMEM; + } + for (i = 0; i < msg->len; i += 4) - HDMI_WRITE(HDMI_CEC_TX_DATA_1 + i, + HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2), (msg->msg[i]) | (msg->msg[i + 1] << 8) | (msg->msg[i + 2] << 16) | -- cgit v1.2.3 From 5a32bfd563e8b5766e57475c2c81c769e5a13f5d Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Mon, 11 Jan 2021 15:22:58 +0100 Subject: drm/vc4: hdmi: Fix up CEC registers The commit 311e305fdb4e ("drm/vc4: hdmi: Implement a register layout abstraction") forgot one CEC register, and made a copy and paste mistake for another one. Fix those mistakes. Fixes: 311e305fdb4e ("drm/vc4: hdmi: Implement a register layout abstraction") Reviewed-by: Dave Stevenson Signed-off-by: Dom Cobley Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-5-maxime@cerno.tech (cherry picked from commit 303085bc11bb7aebeeaaf09213f99fd7aa539a34) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 401863cb8c98..e1b58eac766f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -29,6 +29,7 @@ enum vc4_hdmi_field { HDMI_CEC_CPU_MASK_SET, HDMI_CEC_CPU_MASK_STATUS, HDMI_CEC_CPU_STATUS, + HDMI_CEC_CPU_SET, /* * Transmit data, first byte is low byte of the 32-bit reg. @@ -199,9 +200,10 @@ static const struct vc4_hdmi_register __maybe_unused vc4_hdmi_fields[] = { VC4_HDMI_REG(HDMI_TX_PHY_RESET_CTL, 0x02c0), VC4_HDMI_REG(HDMI_TX_PHY_CTL_0, 0x02c4), VC4_HDMI_REG(HDMI_CEC_CPU_STATUS, 0x0340), + VC4_HDMI_REG(HDMI_CEC_CPU_SET, 0x0344), VC4_HDMI_REG(HDMI_CEC_CPU_CLEAR, 0x0348), VC4_HDMI_REG(HDMI_CEC_CPU_MASK_STATUS, 0x034c), - VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x034c), + VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x0350), VC4_HDMI_REG(HDMI_CEC_CPU_MASK_CLEAR, 0x0354), VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400), }; -- cgit v1.2.3 From 4d8602b8ec16f5721a4d1339c610a81f95df1856 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Mon, 11 Jan 2021 15:22:59 +0100 Subject: drm/vc4: hdmi: Restore cec physical address on reconnect Currently we call cec_phys_addr_invalidate on a hotplug deassert. That may be due to a TV power cycling, or an AVR being switched on (and switching edid). This makes CEC unusable since our controller wouldn't have a physical address anymore. Set it back up again on the hotplug assert. Fixes: 15b4511a4af6 ("drm/vc4: add HDMI CEC support") Signed-off-by: Dom Cobley Signed-off-by: Maxime Ripard Acked-by: Dave Stevenson Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-6-maxime@cerno.tech (cherry picked from commit b06eecb5158e5f3eb47b9d05aea8c259985cc5f7) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 184e1f0936c0..df2c05f2e20c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -136,20 +136,32 @@ static enum drm_connector_status vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) { struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); + bool connected = false; if (vc4_hdmi->hpd_gpio) { if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ vc4_hdmi->hpd_active_low) - return connector_status_connected; - cec_phys_addr_invalidate(vc4_hdmi->cec_adap); - return connector_status_disconnected; + connected = true; + } else if (drm_probe_ddc(vc4_hdmi->ddc)) { + connected = true; + } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { + connected = true; } - if (drm_probe_ddc(vc4_hdmi->ddc)) - return connector_status_connected; + if (connected) { + if (connector->status != connector_status_connected) { + struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc); + + if (edid) { + cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); + vc4_hdmi->encoder.hdmi_monitor = drm_detect_hdmi_monitor(edid); + kfree(edid); + } + } - if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) return connector_status_connected; + } + cec_phys_addr_invalidate(vc4_hdmi->cec_adap); return connector_status_disconnected; } -- cgit v1.2.3 From 163a3ef681e5e9d5df558e855d86ccd4708d6200 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:00 +0100 Subject: drm/vc4: hdmi: Compute the CEC clock divider from the clock rate The CEC clock divider needs to output a frequency of 40kHz from the HSM rate on the BCM2835. The driver used to have a fixed frequency for it, but that changed for the BCM2711 and we now need to compute it dynamically to maintain the proper rate. Fixes: cd4cb49dc5bb ("drm/vc4: hdmi: Adjust HSM clock rate depending on pixel rate") Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-7-maxime@cerno.tech (cherry picked from commit f1ceb9d10043683b89e5e5e5848fb4e855295762) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index df2c05f2e20c..cf4b5f5ff766 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1599,6 +1599,7 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { struct cec_connector_info conn_info; struct platform_device *pdev = vc4_hdmi->pdev; + u16 clk_cnt; u32 value; int ret; @@ -1624,8 +1625,9 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) * divider: the hsm_clock rate and this divider setting will * give a 40 kHz CEC clock. */ + clk_cnt = clk_get_rate(vc4_hdmi->hsm_clock) / CEC_CLOCK_FREQ; value |= VC4_HDMI_CEC_ADDR_MASK | - (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); + (clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); HDMI_WRITE(HDMI_CEC_CNTRL_1, value); ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0), vc4_cec_irq_handler, -- cgit v1.2.3 From 47fa9a80270e20a0c4ddaffca1f144d22cc59620 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:01 +0100 Subject: drm/vc4: hdmi: Update the CEC clock divider on HSM rate change As part of the enable sequence we might change the HSM clock rate if the pixel rate is different than the one we were already dealing with. On the BCM2835 however, the CEC clock derives from the HSM clock so any rate change will need to be reflected in the CEC clock divider to output 40kHz. Fixes: cd4cb49dc5bb ("drm/vc4: hdmi: Adjust HSM clock rate depending on pixel rate") Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-8-maxime@cerno.tech (cherry picked from commit a9dd0b9a5c3e11c79e6ff9c7fdf07c471732dcb6) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index cf4b5f5ff766..d5a2e936eac5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -132,6 +132,27 @@ static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL); } +#ifdef CONFIG_DRM_VC4_HDMI_CEC +static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) +{ + u16 clk_cnt; + u32 value; + + value = HDMI_READ(HDMI_CEC_CNTRL_1); + value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; + + /* + * Set the clock divider: the hsm_clock rate and this divider + * setting will give a 40 kHz CEC clock. + */ + clk_cnt = clk_get_rate(vc4_hdmi->hsm_clock) / CEC_CLOCK_FREQ; + value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; + HDMI_WRITE(HDMI_CEC_CNTRL_1, value); +} +#else +static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {} +#endif + static enum drm_connector_status vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) { @@ -770,6 +791,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, return; } + vc4_hdmi_cec_update_clk_div(vc4_hdmi); + /* * FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup * at 300MHz. @@ -1599,7 +1622,6 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { struct cec_connector_info conn_info; struct platform_device *pdev = vc4_hdmi->pdev; - u16 clk_cnt; u32 value; int ret; @@ -1618,17 +1640,14 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); + value = HDMI_READ(HDMI_CEC_CNTRL_1); - value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; - /* - * Set the logical address to Unregistered and set the clock - * divider: the hsm_clock rate and this divider setting will - * give a 40 kHz CEC clock. - */ - clk_cnt = clk_get_rate(vc4_hdmi->hsm_clock) / CEC_CLOCK_FREQ; - value |= VC4_HDMI_CEC_ADDR_MASK | - (clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); + /* Set the logical address to Unregistered */ + value |= VC4_HDMI_CEC_ADDR_MASK; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + + vc4_hdmi_cec_update_clk_div(vc4_hdmi); + ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0), vc4_cec_irq_handler, vc4_cec_irq_handler_thread, 0, -- cgit v1.2.3 From 23b7eb5c12b35913e61f8f64536b8932bdd17a46 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:02 +0100 Subject: drm/vc4: hdmi: Introduce a CEC clock While the BCM2835 had the CEC clock derived from the HSM clock, the BCM2711 has a dedicated parent clock for it. Let's introduce a separate clock for it so that we can handle both cases. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-9-maxime@cerno.tech (cherry picked from commit cd7f016c93b697dea79a884162cbf7311283fe12) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 9 ++++++++- drivers/gpu/drm/vc4/vc4_hdmi.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d5a2e936eac5..56209cbeff01 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -145,7 +145,7 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) * Set the clock divider: the hsm_clock rate and this divider * setting will give a 40 kHz CEC clock. */ - clk_cnt = clk_get_rate(vc4_hdmi->hsm_clock) / CEC_CLOCK_FREQ; + clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ; value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); } @@ -1753,6 +1753,7 @@ static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) return PTR_ERR(vc4_hdmi->hsm_clock); } vc4_hdmi->audio_clock = vc4_hdmi->hsm_clock; + vc4_hdmi->cec_clock = vc4_hdmi->hsm_clock; return 0; } @@ -1846,6 +1847,12 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) return PTR_ERR(vc4_hdmi->audio_clock); } + vc4_hdmi->cec_clock = devm_clk_get(dev, "cec"); + if (IS_ERR(vc4_hdmi->cec_clock)) { + DRM_ERROR("Failed to get CEC clock\n"); + return PTR_ERR(vc4_hdmi->cec_clock); + } + vc4_hdmi->reset = devm_reset_control_get(dev, NULL); if (IS_ERR(vc4_hdmi->reset)) { DRM_ERROR("Failed to get HDMI reset line\n"); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 4c8994cfd932..6966db1a0957 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -155,6 +155,7 @@ struct vc4_hdmi { bool cec_tx_ok; bool cec_irq_was_rx; + struct clk *cec_clock; struct clk *pixel_clock; struct clk *hsm_clock; struct clk *audio_clock; -- cgit v1.2.3 From ed4a6bbd638618b74fdb6d0eb924d8b11f80bdc0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:03 +0100 Subject: drm/vc4: hdmi: Split the interrupt handlers The BCM2711 has two different interrupt sources to transmit and receive CEC messages, provided through an external interrupt chip shared between the two HDMI interrupt controllers. The rest of the CEC controller is identical though so we need to change a bit the code organisation to share the code as much as possible, yet still allowing to register independent handlers. Signed-off-by: Maxime Ripard Reviewed-by: Dave Stevenson Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-10-maxime@cerno.tech (cherry picked from commit 0c38490a031071c0d81b400949f43ea6f4b0cd8f) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 86 +++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 56209cbeff01..68c30276b980 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1455,15 +1455,22 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) } #ifdef CONFIG_DRM_VC4_HDMI_CEC -static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) +static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv) +{ + struct vc4_hdmi *vc4_hdmi = priv; + + if (vc4_hdmi->cec_rx_msg.len) + cec_received_msg(vc4_hdmi->cec_adap, + &vc4_hdmi->cec_rx_msg); + + return IRQ_HANDLED; +} + +static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv) { struct vc4_hdmi *vc4_hdmi = priv; - if (vc4_hdmi->cec_irq_was_rx) { - if (vc4_hdmi->cec_rx_msg.len) - cec_received_msg(vc4_hdmi->cec_adap, - &vc4_hdmi->cec_rx_msg); - } else if (vc4_hdmi->cec_tx_ok) { + if (vc4_hdmi->cec_tx_ok) { cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); } else { @@ -1477,6 +1484,19 @@ static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) return IRQ_HANDLED; } +static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) +{ + struct vc4_hdmi *vc4_hdmi = priv; + irqreturn_t ret; + + if (vc4_hdmi->cec_irq_was_rx) + ret = vc4_cec_irq_handler_rx_thread(irq, priv); + else + ret = vc4_cec_irq_handler_tx_thread(irq, priv); + + return ret; +} + static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) { struct drm_device *dev = vc4_hdmi->connector.dev; @@ -1501,31 +1521,55 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) } } +static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv) +{ + struct vc4_hdmi *vc4_hdmi = priv; + u32 cntrl1; + + cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); + vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; + cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv) +{ + struct vc4_hdmi *vc4_hdmi = priv; + u32 cntrl1; + + vc4_hdmi->cec_rx_msg.len = 0; + cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); + vc4_cec_read_msg(vc4_hdmi, cntrl1); + cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); + cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); + + return IRQ_WAKE_THREAD; +} + static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) { struct vc4_hdmi *vc4_hdmi = priv; u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS); - u32 cntrl1, cntrl5; + irqreturn_t ret; + u32 cntrl5; if (!(stat & VC4_HDMI_CPU_CEC)) return IRQ_NONE; - vc4_hdmi->cec_rx_msg.len = 0; - cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); + cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5); vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; - if (vc4_hdmi->cec_irq_was_rx) { - vc4_cec_read_msg(vc4_hdmi, cntrl1); - cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; - HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); - cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; - } else { - vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; - cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; - } - HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); - HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC); + if (vc4_hdmi->cec_irq_was_rx) + ret = vc4_cec_irq_handler_rx_bare(irq, priv); + else + ret = vc4_cec_irq_handler_tx_bare(irq, priv); - return IRQ_WAKE_THREAD; + HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC); + return ret; } static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) -- cgit v1.2.3 From 185e98b3bd93c91828a3b394b0400efff63199bf Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:04 +0100 Subject: drm/vc4: hdmi: Support BCM2711 CEC interrupt setup The HDMI controller found in the BCM2711 has an external interrupt controller for the CEC and hotplug interrupt shared between the two instances. Let's add a variant flag to register a single interrupt handler and deals with the interrupt handler setup, or two interrupt handlers relying on an external irqchip. Signed-off-by: Maxime Ripard Reviewed-by: Dave Stevenson Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-11-maxime@cerno.tech (cherry picked from commit ad6380e9aaf459c22006c73fd3d4dd6f41e8f048) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 42 ++++++++++++++++++++++++++++++++---------- drivers/gpu/drm/vc4/vc4_hdmi.h | 7 +++++++ 2 files changed, 39 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 68c30276b980..165405e5739d 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1606,9 +1606,11 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) | ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT)); - HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); + if (!vc4_hdmi->variant->external_irq_controller) + HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); } else { - HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC); + if (!vc4_hdmi->variant->external_irq_controller) + HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC); HDMI_WRITE(HDMI_CEC_CNTRL_5, val | VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET); } @@ -1683,8 +1685,6 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); - HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); - value = HDMI_READ(HDMI_CEC_CNTRL_1); /* Set the logical address to Unregistered */ value |= VC4_HDMI_CEC_ADDR_MASK; @@ -1692,12 +1692,32 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) vc4_hdmi_cec_update_clk_div(vc4_hdmi); - ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0), - vc4_cec_irq_handler, - vc4_cec_irq_handler_thread, 0, - "vc4 hdmi cec", vc4_hdmi); - if (ret) - goto err_delete_cec_adap; + if (vc4_hdmi->variant->external_irq_controller) { + ret = devm_request_threaded_irq(&pdev->dev, + platform_get_irq_byname(pdev, "cec-rx"), + vc4_cec_irq_handler_rx_bare, + vc4_cec_irq_handler_rx_thread, 0, + "vc4 hdmi cec rx", vc4_hdmi); + if (ret) + goto err_delete_cec_adap; + + ret = devm_request_threaded_irq(&pdev->dev, + platform_get_irq_byname(pdev, "cec-tx"), + vc4_cec_irq_handler_tx_bare, + vc4_cec_irq_handler_tx_thread, 0, + "vc4 hdmi cec tx", vc4_hdmi); + if (ret) + goto err_delete_cec_adap; + } else { + HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); + + ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0), + vc4_cec_irq_handler, + vc4_cec_irq_handler_thread, 0, + "vc4 hdmi cec", vc4_hdmi); + if (ret) + goto err_delete_cec_adap; + } ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev); if (ret < 0) @@ -2096,6 +2116,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { PHY_LANE_CK, }, .unsupported_odd_h_timings = true, + .external_irq_controller = true, .init_resources = vc5_hdmi_init_resources, .csc_setup = vc5_hdmi_csc_setup, @@ -2122,6 +2143,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { PHY_LANE_2, }, .unsupported_odd_h_timings = true, + .external_irq_controller = true, .init_resources = vc5_hdmi_init_resources, .csc_setup = vc5_hdmi_csc_setup, diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 6966db1a0957..d71f6ed321bf 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -64,6 +64,13 @@ struct vc4_hdmi_variant { /* The BCM2711 cannot deal with odd horizontal pixel timings */ bool unsupported_odd_h_timings; + /* + * The BCM2711 CEC/hotplug IRQ controller is shared between the + * two HDMI controllers, and we have a proper irqchip driver for + * it. + */ + bool external_irq_controller; + /* Callback to get the resources (memory region, interrupts, * clocks, etc) for that variant. */ -- cgit v1.2.3 From 1e5e4bbdfdd2ac5fef78298458c8b02e2ebb82b3 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Mon, 11 Jan 2021 15:23:05 +0100 Subject: drm/vc4: hdmi: Remove cec_available flag Now that our HDMI controller supports CEC for the BCM2711, let's remove that flag. Reviewed-by: Dave Stevenson Signed-off-by: Dom Cobley Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-12-maxime@cerno.tech (cherry picked from commit f551863af919edd60f76a24126da3ac10294ace1) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ---- drivers/gpu/drm/vc4/vc4_hdmi.h | 3 --- 2 files changed, 7 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 165405e5739d..f8c5309b47bf 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1671,9 +1671,6 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) u32 value; int ret; - if (!vc4_hdmi->variant->cec_available) - return 0; - vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, vc4_hdmi, "vc4", CEC_CAP_DEFAULTS | @@ -2087,7 +2084,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = { .debugfs_name = "hdmi_regs", .card_name = "vc4-hdmi", .max_pixel_clock = 162000000, - .cec_available = true, .registers = vc4_hdmi_fields, .num_registers = ARRAY_SIZE(vc4_hdmi_fields), diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index d71f6ed321bf..3cebd1fd00fc 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -42,9 +42,6 @@ struct vc4_hdmi_variant { /* Filename to expose the registers in debugfs */ const char *debugfs_name; - /* Set to true when the CEC support is available */ - bool cec_available; - /* Maximum pixel clock supported by the controller (in Hz) */ unsigned long long max_pixel_clock; -- cgit v1.2.3 From ae442bf6d6072f3066040e5760a4f0647972a9ae Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 11 Jan 2021 15:23:06 +0100 Subject: drm/vc4: hdmi: Don't register the CEC adapter if there's no interrupts We introduced the BCM2711 support to the vc4 HDMI controller with 5.10, but this was lacking any of the interrupts of the CEC controller so we have to deal with the backward compatibility. Do so by simply ignoring the CEC setup if the DT doesn't have the interrupts property. Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard Acked-by: Hans Verkuil Tested-by: Hans Verkuil Link: https://patchwork.freedesktop.org/patch/msgid/20210111142309.193441-13-maxime@cerno.tech (cherry picked from commit 4d03ed7ad731a2cf922fa37246fb7068a52f18ff) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f8c5309b47bf..1fda574579af 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1668,9 +1668,15 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { struct cec_connector_info conn_info; struct platform_device *pdev = vc4_hdmi->pdev; + struct device *dev = &pdev->dev; u32 value; int ret; + if (!of_find_property(dev->of_node, "interrupts", NULL)) { + dev_warn(dev, "'interrupts' DT property is missing, no CEC\n"); + return 0; + } + vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, vc4_hdmi, "vc4", CEC_CAP_DEFAULTS | -- cgit v1.2.3 From 439dde0a96f0d7a396f342a3918a0af28d9b5541 Mon Sep 17 00:00:00 2001 From: Bernard Zhao Date: Tue, 2 Feb 2021 04:23:38 -0800 Subject: drm/vc4: remove unneeded variable: "ret" remove unneeded variable: "ret". Signed-off-by: Bernard Zhao Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210202122338.15351-1-bernard@vivo.com (cherry picked from commit f0c5a89e534b43bfef8e7bf7baa5624cd84e1e18) Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/vc4/vc4_gem.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index b641252939d8..445d3bab89e0 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -1026,7 +1026,6 @@ int vc4_queue_seqno_cb(struct drm_device *dev, void (*func)(struct vc4_seqno_cb *cb)) { struct vc4_dev *vc4 = to_vc4_dev(dev); - int ret = 0; unsigned long irqflags; cb->func = func; @@ -1041,7 +1040,7 @@ int vc4_queue_seqno_cb(struct drm_device *dev, } spin_unlock_irqrestore(&vc4->job_lock, irqflags); - return ret; + return 0; } /* Scheduled when any job has been completed, this walks the list of -- cgit v1.2.3