From 5eb2c72c8acc3f84c85f9d504b87f25f78ef0eb0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 31 Mar 2017 11:00:42 +0100 Subject: dma-buf: fence debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add debugfs output to report shared and exclusive fences on a dma_buf object. This produces output such as: Dma-buf Objects: size flags mode count exp_name 08294400 00000000 00000005 00000005 drm Exclusive fence: etnaviv 134000.gpu signalled Attached Devices: gpu-subsystem Total 1 devices attached Total 1 objects, 8294400 bytes Signed-off-by: Russell King Reviewed-by: Christian König Signed-off-by: Gustavo Padovan Link: http://patchwork.freedesktop.org/patch/msgid/E1cttMI-00068z-3X@rmk-PC.armlinux.org.uk --- drivers/dma-buf/dma-buf.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 0007b79..ebaf1923 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1059,7 +1059,11 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) int ret; struct dma_buf *buf_obj; struct dma_buf_attachment *attach_obj; - int count = 0, attach_count; + struct reservation_object *robj; + struct reservation_object_list *fobj; + struct dma_fence *fence; + unsigned seq; + int count = 0, attach_count, shared_count, i; size_t size = 0; ret = mutex_lock_interruptible(&db_list.lock); @@ -1085,6 +1089,34 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) file_count(buf_obj->file), buf_obj->exp_name); + robj = buf_obj->resv; + while (true) { + seq = read_seqcount_begin(&robj->seq); + rcu_read_lock(); + fobj = rcu_dereference(robj->fence); + shared_count = fobj ? fobj->shared_count : 0; + fence = rcu_dereference(robj->fence_excl); + if (!read_seqcount_retry(&robj->seq, seq)) + break; + rcu_read_unlock(); + } + + if (fence) + seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + dma_fence_is_signaled(fence) ? "" : "un"); + for (i = 0; i < shared_count; i++) { + fence = rcu_dereference(fobj->shared[i]); + if (!dma_fence_get_rcu(fence)) + continue; + seq_printf(s, "\tShared fence: %s %s %ssignalled\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + dma_fence_is_signaled(fence) ? "" : "un"); + } + rcu_read_unlock(); + seq_puts(s, "\tAttached Devices:\n"); attach_count = 0; -- cgit v1.1 From 4b4f99f57febb9c58d1f20b4a0cea27343519713 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Mar 2017 16:43:51 +0200 Subject: drm/fb-helper: Cleanup checkpatch warnings Fix up a couple of checkpatch warnings, such as whitespace or coding style issues. Tested-by: John Stultz Reviewed-by: Daniel Vetter Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170329144401.1804-2-thierry.reding@gmail.com --- drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 45fde2f..2be1cd9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -213,9 +213,9 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, fb_helper_connector = fb_helper->connector_info[i]; drm_connector_put(fb_helper_connector->connector); - for (j = i + 1; j < fb_helper->connector_count; j++) { + for (j = i + 1; j < fb_helper->connector_count; j++) fb_helper->connector_info[j - 1] = fb_helper->connector_info[j]; - } + fb_helper->connector_count--; kfree(fb_helper_connector); @@ -316,6 +316,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) for (i = 0; i < helper->crtc_count; i++) { struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; + crtc = mode_set->crtc; funcs = crtc->helper_private; fb = drm_mode_config_fb(crtc); @@ -346,7 +347,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) struct drm_plane *plane; struct drm_atomic_state *state; int i, ret; - unsigned plane_mask; + unsigned int plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -378,7 +379,7 @@ retry: goto fail; } - for(i = 0; i < fb_helper->crtc_count; i++) { + for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; ret = __drm_atomic_helper_set_config(mode_set, state); @@ -488,8 +489,10 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) struct drm_crtc *crtc; int bound = 0, crtcs_bound = 0; - /* Sometimes user space wants everything disabled, so don't steal the - * display if there's a master. */ + /* + * Sometimes user space wants everything disabled, so don't steal the + * display if there's a master. + */ if (READ_ONCE(dev->master)) return false; @@ -537,6 +540,7 @@ static bool drm_fb_helper_force_kernel_mode(void) static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) { bool ret; + ret = drm_fb_helper_force_kernel_mode(); if (ret == true) DRM_ERROR("Failed to restore crtc configuration\n"); @@ -870,9 +874,8 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) mutex_lock(&kernel_fb_helper_lock); if (!list_empty(&fb_helper->kernel_fb_list)) { list_del(&fb_helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) { + if (list_empty(&kernel_fb_helper_list)) unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - } } mutex_unlock(&kernel_fb_helper_lock); @@ -1165,6 +1168,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, (blue << info->var.blue.offset); if (info->var.transp.length > 0) { u32 mask = (1 << info->var.transp.length) - 1; + mask <<= info->var.transp.offset; value |= mask; } @@ -1447,7 +1451,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, struct drm_atomic_state *state; struct drm_plane *plane; int i, ret; - unsigned plane_mask; + unsigned int plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -1456,7 +1460,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, state->acquire_ctx = dev->mode_config.acquire_ctx; retry: plane_mask = 0; - for(i = 0; i < fb_helper->crtc_count; i++) { + for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set; mode_set = &fb_helper->crtc_info[i].mode_set; @@ -1561,11 +1565,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; sizes.surface_bpp = 32; - sizes.fb_width = (unsigned)-1; - sizes.fb_height = (unsigned)-1; + sizes.fb_width = (u32)-1; + sizes.fb_height = (u32)-1; - /* if driver picks 8 or 16 by default use that - for both depth/bpp */ + /* if driver picks 8 or 16 by default use that for both depth/bpp */ if (preferred_bpp != sizes.surface_bpp) sizes.surface_depth = sizes.surface_bpp = preferred_bpp; @@ -1630,6 +1633,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, for (j = 0; j < mode_set->num_connectors; j++) { struct drm_connector *connector = mode_set->connectors[j]; + if (connector->has_tile) { lasth = (connector->tile_h_loc == (connector->num_h_tile - 1)); lastv = (connector->tile_v_loc == (connector->num_v_tile - 1)); @@ -1645,8 +1649,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { - /* hmm everyone went away - assume VGA cable just fell out - and will come back later. */ + /* + * hmm everyone went away - assume VGA cable just fell out + * and will come back later. + */ DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); sizes.fb_width = sizes.surface_width = 1024; sizes.fb_height = sizes.surface_height = 768; @@ -1703,7 +1709,6 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, info->fix.accel = FB_ACCEL_NONE; info->fix.line_length = pitch; - return; } EXPORT_SYMBOL(drm_fb_helper_fill_fix); @@ -1725,6 +1730,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe uint32_t fb_width, uint32_t fb_height) { struct drm_framebuffer *fb = fb_helper->fb; + info->pseudo_palette = fb_helper->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; @@ -2057,13 +2063,15 @@ retry: continue; } else { - if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && + if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 && fb_helper_conn->connector->tile_v_loc != tile_pass - 1) /* if this tile_pass doesn't cover any of the tiles - keep going */ continue; - /* find the tile offsets for this pass - need - to find all tiles left and above */ + /* + * find the tile offsets for this pass - need to find + * all tiles left and above + */ drm_get_tile_offsets(fb_helper, modes, offsets, i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); } @@ -2147,8 +2155,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, if (!encoder) goto out; - /* select a crtc for this connector and then attempt to configure - remaining connectors */ + /* + * select a crtc for this connector and then attempt to configure + * remaining connectors + */ for (c = 0; c < fb_helper->crtc_count; c++) { crtc = &fb_helper->crtc_info[c]; -- cgit v1.1 From 39b8b2ed4239191b1d37c9cd3599b9b34b838d3a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Mar 2017 16:43:52 +0200 Subject: drm/fb-helper: Reshuffle code for subsequent patches An unlocked version of the drm_fb_helper_add_one_connector() function will be added in a subsequent patch. Reshuffle the code separately to make the diff more readable later on. Tested-by: John Stultz Reviewed-by: Daniel Vetter Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170329144401.1804-3-thierry.reding@gmail.com --- drivers/gpu/drm/drm_fb_helper.c | 59 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2be1cd9..875a490 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -109,6 +109,35 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); for (({ lockdep_assert_held(&(fbh)->dev->mode_config.mutex); }), \ i__ = 0; i__ < (fbh)->connector_count; i__++) +int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) +{ + struct drm_fb_helper_connector **temp; + struct drm_fb_helper_connector *fb_helper_connector; + + if (!drm_fbdev_emulation) + return 0; + + WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); + if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { + temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; + fb_helper->connector_info = temp; + } + + fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); + if (!fb_helper_connector) + return -ENOMEM; + + drm_connector_get(connector); + fb_helper_connector->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; + return 0; +} +EXPORT_SYMBOL(drm_fb_helper_add_one_connector); + /** * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev * emulation helper @@ -162,36 +191,6 @@ out: } EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); -int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) -{ - struct drm_fb_helper_connector **temp; - struct drm_fb_helper_connector *fb_helper_connector; - - if (!drm_fbdev_emulation) - return 0; - - WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); - if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { - temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); - if (!temp) - return -ENOMEM; - - fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; - fb_helper->connector_info = temp; - } - - - fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); - if (!fb_helper_connector) - return -ENOMEM; - - drm_connector_get(connector); - fb_helper_connector->connector = connector; - fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; - return 0; -} -EXPORT_SYMBOL(drm_fb_helper_add_one_connector); - int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) { -- cgit v1.1 From 50021ff1ad5da500a09ca4866467a12cf66f37cb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Mar 2017 16:43:53 +0200 Subject: drm/fb-helper: Improve code readability Add a couple of temporary variables and use shorter names for existing variables in drm_fb_helper_add_one_connector() for better readability. Tested-by: John Stultz Reviewed-by: Daniel Vetter Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170329144401.1804-4-thierry.reding@gmail.com --- drivers/gpu/drm/drm_fb_helper.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 875a490..8afc1bb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -109,31 +109,38 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); for (({ lockdep_assert_held(&(fbh)->dev->mode_config.mutex); }), \ i__ = 0; i__ < (fbh)->connector_count; i__++) -int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) +int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, + struct drm_connector *connector) { + struct drm_fb_helper_connector *fb_conn; struct drm_fb_helper_connector **temp; - struct drm_fb_helper_connector *fb_helper_connector; + unsigned int count; if (!drm_fbdev_emulation) return 0; WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); - if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { - temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); + + count = fb_helper->connector_count + 1; + + if (count > fb_helper->connector_info_alloc_count) { + size_t size = count * sizeof(fb_conn); + + temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL); if (!temp) return -ENOMEM; - fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; + fb_helper->connector_info_alloc_count = count; fb_helper->connector_info = temp; } - fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); - if (!fb_helper_connector) + fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL); + if (!fb_conn) return -ENOMEM; drm_connector_get(connector); - fb_helper_connector->connector = connector; - fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; + fb_conn->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_conn; return 0; } EXPORT_SYMBOL(drm_fb_helper_add_one_connector); -- cgit v1.1 From a68ee76f4a2880c12fa18359a0e85e6a05c95147 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 30 Mar 2017 10:19:28 +0200 Subject: drm/bridge: megachips-stdpxxxx-ge-b850v3-fw: Fix bridge initialization Reordering of the device nodes based on unit address resulted in ge_b850v3_lvds_attach() being called before ge_b850v3_lvds_ptr->stdp4028_i2c was populated. This patch moves the drm bridge initialization from ge_b850v3_lvds_init() to stdp4028_ge_b850v3_fw_probe() ensuring that ge_b850v3_lvds_ptr->stdp4028_i2c is properly populated. Signed-off-by: Peter Senna Tschudin Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170330081928.8537-1-peter.senna@collabora.com --- drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index cfc606a..11f1108 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -279,10 +279,6 @@ static int ge_b850v3_lvds_init(struct device *dev) return -ENOMEM; } - ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; - ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; - drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); - success: mutex_unlock(&ge_b850v3_lvds_dev_mutex); return 0; @@ -317,6 +313,11 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); + /* drm bridge initialization */ + ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; + ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; + drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); + /* Clear pending interrupts since power up. */ i2c_smbus_write_word_data(stdp4028_i2c, STDP4028_DPTX_IRQ_STS_REG, -- cgit v1.1 From d0353118fd589c127875290017c7fdd266937bee Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 3 Apr 2017 16:42:34 +0200 Subject: media: uapi: Add RGB and YUV bus formats for Synopsys HDMI TX Controller In order to describe the RGB and YUV bus formats used to feed the Synopsys DesignWare HDMI TX Controller, add missing formats to the list of Bus Formats. Documentation for these formats is added in a separate patch. Reviewed-by: Archit Taneja Reviewed-by: Jose Abreu Acked-by: Hans Verkuil Acked-by: Mauro Carvalho Chehab Signed-off-by: Neil Armstrong Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491230558-10804-3-git-send-email-narmstrong@baylibre.com --- include/uapi/linux/media-bus-format.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 2168759..ef6fb30 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1018 */ +/* RGB - next is 0x101b */ #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -57,8 +57,11 @@ #define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d #define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f +#define MEDIA_BUS_FMT_RGB101010_1X30 0x1018 +#define MEDIA_BUS_FMT_RGB121212_1X36 0x1019 +#define MEDIA_BUS_FMT_RGB161616_1X48 0x101a -/* YUV (including grey) - next is 0x2026 */ +/* YUV (including grey) - next is 0x202c */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 @@ -90,12 +93,18 @@ #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e #define MEDIA_BUS_FMT_VUY8_1X24 0x2024 #define MEDIA_BUS_FMT_YUV8_1X24 0x2025 +#define MEDIA_BUS_FMT_UYYVYY8_0_5X24 0x2026 #define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 #define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 #define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 #define MEDIA_BUS_FMT_YVYU12_1X24 0x2023 #define MEDIA_BUS_FMT_YUV10_1X30 0x2016 +#define MEDIA_BUS_FMT_UYYVYY10_0_5X30 0x2027 #define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 +#define MEDIA_BUS_FMT_UYYVYY12_0_5X36 0x2028 +#define MEDIA_BUS_FMT_YUV12_1X36 0x2029 +#define MEDIA_BUS_FMT_YUV16_1X48 0x202a +#define MEDIA_BUS_FMT_UYYVYY16_0_5X48 0x202b /* Bayer - next is 0x3021 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 -- cgit v1.1 From 3c2507d308afb233dd41387b41512e7aa97535f0 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 3 Apr 2017 16:42:35 +0200 Subject: documentation: media: Add documentation for new RGB and YUV bus formats Add documentation for added Bus Formats to describe RGB and YUV formats used as input to the Synopsys DesignWare HDMI TX Controller. Acked-by: Hans Verkuil Reviewed-by: Archit Taneja Acked-by: Mauro Carvalho Chehab Signed-off-by: Neil Armstrong Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491230558-10804-4-git-send-email-narmstrong@baylibre.com --- Documentation/media/uapi/v4l/subdev-formats.rst | 3000 +++++++++++++++-------- 1 file changed, 1979 insertions(+), 1021 deletions(-) diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst index d6152c9..4032d97 100644 --- a/Documentation/media/uapi/v4l/subdev-formats.rst +++ b/Documentation/media/uapi/v4l/subdev-formats.rst @@ -1258,157 +1258,470 @@ The following tables list existing packed RGB formats. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB101010-1X30: + + - MEDIA_BUS_FMT_RGB101010_1X30 + - 0x1018 + - + - 0 + - 0 + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` .. raw:: latex \endgroup -On LVDS buses, usually each sample is transferred serialized in seven -time slots per pixel clock, on three (18-bit) or four (24-bit) -differential data pairs at the same time. The remaining bits are used -for control signals as defined by SPWG/PSWG/VESA or JEIDA standards. The -24-bit RGB format serialized in seven time slots on four lanes using -JEIDA defined bit mapping will be named -``MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA``, for example. -.. raw:: latex +The following table list existing packed 36bit wide RGB formats. - \begin{adjustbox}{width=\columnwidth} +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| -.. _v4l2-mbus-pixelcode-rgb-lvds: +.. _v4l2-mbus-pixelcode-rgb-36: -.. flat-table:: LVDS RGB formats +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. flat-table:: 36bit RGB formats :header-rows: 2 :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 * - Identifier - Code - - - - - :cspan:`3` Data organization + - :cspan:`35` Data organization * - - - - Timeslot - - Lane + - Bit + - 35 + - 34 + - 33 + - 32 + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 20 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 - 3 - 2 - 1 - 0 - * .. _MEDIA-BUS-FMT-RGB666-1X7X3-SPWG: + * .. _MEDIA-BUS-FMT-RGB121212-1X36: - - MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - - 0x1010 - - 0 + - MEDIA_BUS_FMT_RGB121212_1X36 + - 0x1019 - - - - - d - - b\ :sub:`1` + - r\ :sub:`11` + - r\ :sub:`10` + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`11` + - g\ :sub:`10` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` - g\ :sub:`0` + - b\ :sub:`11` + - b\ :sub:`10` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + + +The following table list existing packed 48bit wide RGB formats. + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-rgb-48: + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. flat-table:: 48bit RGB formats + :header-rows: 3 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`31` Data organization * - - - - 1 + - Bit - - - - d - - b\ :sub:`0` - - r\ :sub:`5` - * - - - - 2 - - - - d - - g\ :sub:`5` - - r\ :sub:`4` - * - - - - 3 - - - - b\ :sub:`5` - - g\ :sub:`4` - - r\ :sub:`3` - * - - - - 4 - - - - b\ :sub:`4` - - g\ :sub:`3` - - r\ :sub:`2` - * - - - - 5 - - - - b\ :sub:`3` - - g\ :sub:`2` - - r\ :sub:`1` + - + - + - 47 + - 46 + - 45 + - 44 + - 43 + - 42 + - 41 + - 40 + - 39 + - 38 + - 37 + - 36 + - 35 + - 34 + - 33 + - 32 * - - + - + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 20 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-RGB161616-1X48: + + - MEDIA_BUS_FMT_RGB161616_1X48 + - 0x101a - - - - b\ :sub:`2` - - g\ :sub:`1` - - r\ :sub:`0` - * .. _MEDIA-BUS-FMT-RGB888-1X7X4-SPWG: - - - MEDIA_BUS_FMT_RGB888_1X7X4_SPWG - - 0x1011 - - 0 - - - d - - d - - b\ :sub:`1` - - g\ :sub:`0` - * - - - - 1 - - - b\ :sub:`7` - - d - - b\ :sub:`0` - - r\ :sub:`5` - * - - - - 2 - - - b\ :sub:`6` - - d - - g\ :sub:`5` - - r\ :sub:`4` - * - - - - 3 - - - g\ :sub:`7` - - b\ :sub:`5` - - g\ :sub:`4` - - r\ :sub:`3` - * - - - - 4 - - - g\ :sub:`6` - - b\ :sub:`4` - - g\ :sub:`3` - - r\ :sub:`2` - * - - - - 5 - - - r\ :sub:`7` - - b\ :sub:`3` - - g\ :sub:`2` - - r\ :sub:`1` - * - - - - 6 - - - r\ :sub:`6` - - b\ :sub:`2` - - g\ :sub:`1` + - + - + - r\ :sub:`15` + - r\ :sub:`14` + - r\ :sub:`13` + - r\ :sub:`12` + - r\ :sub:`11` + - r\ :sub:`10` + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * - + - + - + - g\ :sub:`15` + - g\ :sub:`14` + - g\ :sub:`13` + - g\ :sub:`12` + - g\ :sub:`11` + - g\ :sub:`10` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`15` + - b\ :sub:`14` + - b\ :sub:`13` + - b\ :sub:`12` + - b\ :sub:`11` + - b\ :sub:`10` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + +On LVDS buses, usually each sample is transferred serialized in seven +time slots per pixel clock, on three (18-bit) or four (24-bit) +differential data pairs at the same time. The remaining bits are used +for control signals as defined by SPWG/PSWG/VESA or JEIDA standards. The +24-bit RGB format serialized in seven time slots on four lanes using +JEIDA defined bit mapping will be named +``MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA``, for example. + +.. raw:: latex + + \begin{adjustbox}{width=\columnwidth} + +.. _v4l2-mbus-pixelcode-rgb-lvds: + +.. flat-table:: LVDS RGB formats + :header-rows: 2 + :stub-columns: 0 + + * - Identifier + - Code + - + - + - :cspan:`3` Data organization + * - + - + - Timeslot + - Lane + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-RGB666-1X7X3-SPWG: + + - MEDIA_BUS_FMT_RGB666_1X7X3_SPWG + - 0x1010 + - 0 + - + - + - d + - b\ :sub:`1` + - g\ :sub:`0` + * - + - + - 1 + - + - + - d + - b\ :sub:`0` + - r\ :sub:`5` + * - + - + - 2 + - + - + - d + - g\ :sub:`5` + - r\ :sub:`4` + * - + - + - 3 + - + - + - b\ :sub:`5` + - g\ :sub:`4` + - r\ :sub:`3` + * - + - + - 4 + - + - + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * - + - + - 5 + - + - + - b\ :sub:`3` + - g\ :sub:`2` + - r\ :sub:`1` + * - + - + - 6 + - + - + - b\ :sub:`2` + - g\ :sub:`1` + - r\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB888-1X7X4-SPWG: + + - MEDIA_BUS_FMT_RGB888_1X7X4_SPWG + - 0x1011 + - 0 + - + - d + - d + - b\ :sub:`1` + - g\ :sub:`0` + * - + - + - 1 + - + - b\ :sub:`7` + - d + - b\ :sub:`0` + - r\ :sub:`5` + * - + - + - 2 + - + - b\ :sub:`6` + - d + - g\ :sub:`5` + - r\ :sub:`4` + * - + - + - 3 + - + - g\ :sub:`7` + - b\ :sub:`5` + - g\ :sub:`4` + - r\ :sub:`3` + * - + - + - 4 + - + - g\ :sub:`6` + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * - + - + - 5 + - + - r\ :sub:`7` + - b\ :sub:`3` + - g\ :sub:`2` + - r\ :sub:`1` + * - + - + - 6 + - + - r\ :sub:`6` + - b\ :sub:`2` + - g\ :sub:`1` - r\ :sub:`0` * .. _MEDIA-BUS-FMT-RGB888-1X7X4-JEIDA: @@ -2344,7 +2657,8 @@ The format code is made of the following information. - The number of bus samples per pixel. Pixels that are wider than the bus width must be transferred in multiple samples. Common values are - 1, 1.5 (encoded as 1_5) and 2. + 0.5 (encoded as 0_5; in this case two pixels are transferred per bus + sample), 1, 1.5 (encoded as 1_5) and 2. - The bus width. When the bus width is larger than the number of bits per pixel component, several components are packed in a single bus @@ -2472,10 +2786,399 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-UV8-1X8: - - - MEDIA_BUS_FMT_UV8_1X8 - - 0x2015 + * .. _MEDIA-BUS-FMT-UV8-1X8: + + - MEDIA_BUS_FMT_UV8_1X8 + - 0x2015 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYVY8-1_5X8: + + - MEDIA_BUS_FMT_UYVY8_1_5X8 + - 0x2002 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-VYUY8-1_5X8: + + - MEDIA_BUS_FMT_VYUY8_1_5X8 + - 0x2003 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - - - - @@ -2536,18 +3239,123 @@ the following codes. - - - - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY8-1_5X8: + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUYV8-1_5X8: - - MEDIA_BUS_FMT_UYVY8_1_5X8 - - 0x2002 + - MEDIA_BUS_FMT_YUYV8_1_5X8 + - 0x2004 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - - - - @@ -2686,8 +3494,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * - - - + * .. _MEDIA-BUS-FMT-YVYU8-1_5X8: + + - MEDIA_BUS_FMT_YVYU8_1_5X8 + - 0x2005 - - - @@ -2756,10 +3566,8 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY8-1_5X8: - - - MEDIA_BUS_FMT_VYUY8_1_5X8 - - 0x2003 + * - + - - - - @@ -2898,6 +3706,43 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYVY8-2X8: + + - MEDIA_BUS_FMT_UYVY8_2X8 + - 0x2006 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` * - - - @@ -2960,6 +3805,41 @@ the following codes. - - - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -2968,10 +3848,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV8-1_5X8: + * .. _MEDIA-BUS-FMT-VYUY8-2X8: - - MEDIA_BUS_FMT_YUYV8_1_5X8 - - 0x2004 + - MEDIA_BUS_FMT_VYUY8_2X8 + - 0x2007 - - - @@ -2997,14 +3877,14 @@ the following codes. - - - - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` * - - - @@ -3110,8 +3990,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * - - - + * .. _MEDIA-BUS-FMT-YUYV8-2X8: + + - MEDIA_BUS_FMT_YUYV8_2X8 + - 0x2008 - - - @@ -3172,18 +4054,16 @@ the following codes. - - - - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU8-1_5X8: - - - MEDIA_BUS_FMT_YVYU8_1_5X8 - - 0x2005 + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * - + - - - - @@ -3244,6 +4124,43 @@ the following codes. - - - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-YVYU8-2X8: + + - MEDIA_BUS_FMT_YVYU8_2X8 + - 0x2009 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3349,18 +4266,18 @@ the following codes. - - - - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * - - - - - - - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * .. _MEDIA-BUS-FMT-Y10-1X10: + + - MEDIA_BUS_FMT_Y10_1X10 + - 0x200a - - - @@ -3384,20 +4301,20 @@ the following codes. - - - - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY8-2X8: + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYVY10-2X10: - - MEDIA_BUS_FMT_UYVY8_2X8 - - 0x2006 - - - - + - MEDIA_BUS_FMT_UYVY10_2X10 + - 0x2018 - - - @@ -3421,6 +4338,8 @@ the following codes. - - - + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -3454,8 +4373,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3489,8 +4408,8 @@ the following codes. - - - - - - - + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -3524,8 +4443,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3534,12 +4453,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY8-2X8: + * .. _MEDIA-BUS-FMT-VYUY10-2X10: - - MEDIA_BUS_FMT_VYUY8_2X8 - - 0x2007 - - - - + - MEDIA_BUS_FMT_VYUY10_2X10 + - 0x2019 - - - @@ -3563,6 +4480,8 @@ the following codes. - - - + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -3596,8 +4515,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3631,8 +4550,8 @@ the following codes. - - - - - - - + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -3666,8 +4585,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3676,12 +4595,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV8-2X8: + * .. _MEDIA-BUS-FMT-YUYV10-2X10: - - MEDIA_BUS_FMT_YUYV8_2X8 - - 0x2008 - - - - + - MEDIA_BUS_FMT_YUYV10_2X10 + - 0x200b - - - @@ -3705,6 +4622,8 @@ the following codes. - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3738,8 +4657,8 @@ the following codes. - - - - - - - + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -3773,8 +4692,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3808,8 +4727,8 @@ the following codes. - - - - - - - + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -3818,12 +4737,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU8-2X8: + * .. _MEDIA-BUS-FMT-YVYU10-2X10: - - MEDIA_BUS_FMT_YVYU8_2X8 - - 0x2009 - - - - + - MEDIA_BUS_FMT_YVYU10_2X10 + - 0x200c - - - @@ -3847,6 +4764,8 @@ the following codes. - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3880,8 +4799,8 @@ the following codes. - - - - - - - + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -3915,8 +4834,8 @@ the following codes. - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -3950,8 +4869,8 @@ the following codes. - - - - - - - + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -3960,12 +4879,10 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-Y10-1X10: + * .. _MEDIA-BUS-FMT-Y12-1X12: - - MEDIA_BUS_FMT_Y10_1X10 - - 0x200a - - - - + - MEDIA_BUS_FMT_Y12_1X12 + - 0x2013 - - - @@ -3987,6 +4904,8 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -3997,12 +4916,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY10-2X10: + * .. _MEDIA-BUS-FMT-UYVY12-2X12: - - MEDIA_BUS_FMT_UYVY10_2X10 - - 0x2018 - - - - + - MEDIA_BUS_FMT_UYVY12_2X12 + - 0x201c - - - @@ -4024,6 +4941,8 @@ the following codes. - - - + - u\ :sub:`11` + - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -4057,8 +4976,8 @@ the following codes. - - - - - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4092,8 +5011,8 @@ the following codes. - - - - - - - + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -4127,8 +5046,8 @@ the following codes. - - - - - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4139,12 +5058,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY10-2X10: + * .. _MEDIA-BUS-FMT-VYUY12-2X12: - - MEDIA_BUS_FMT_VYUY10_2X10 - - 0x2019 - - - - + - MEDIA_BUS_FMT_VYUY12_2X12 + - 0x201d - - - @@ -4166,6 +5083,8 @@ the following codes. - - - + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -4199,8 +5118,8 @@ the following codes. - - - - - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4234,8 +5153,8 @@ the following codes. - - - - - - - + - u\ :sub:`11` + - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -4246,9 +5165,7 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * - - - - - + * - - - - @@ -4271,6 +5188,8 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4281,12 +5200,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV10-2X10: + * .. _MEDIA-BUS-FMT-YUYV12-2X12: - - MEDIA_BUS_FMT_YUYV10_2X10 - - 0x200b - - - - + - MEDIA_BUS_FMT_YUYV12_2X12 + - 0x201e - - - @@ -4308,6 +5225,8 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4341,8 +5260,8 @@ the following codes. - - - - - - - + - u\ :sub:`11` + - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -4376,8 +5295,8 @@ the following codes. - - - - - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4411,8 +5330,8 @@ the following codes. - - - - - - - + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -4423,12 +5342,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU10-2X10: + * .. _MEDIA-BUS-FMT-YVYU12-2X12: - - MEDIA_BUS_FMT_YVYU10_2X10 - - 0x200c - - - - + - MEDIA_BUS_FMT_YVYU12_2X12 + - 0x201f - - - @@ -4450,6 +5367,8 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4483,8 +5402,8 @@ the following codes. - - - - - - - + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -4518,8 +5437,8 @@ the following codes. - - - - - - - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -4553,8 +5472,8 @@ the following codes. - - - - - - - + - u\ :sub:`11` + - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -4565,51 +5484,10 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-Y12-1X12: - - - MEDIA_BUS_FMT_Y12_1X12 - - 0x2013 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY12-2X12: + * .. _MEDIA-BUS-FMT-UYVY8-1X16: - - MEDIA_BUS_FMT_UYVY12_2X12 - - 0x201c - - - - - - - - + - MEDIA_BUS_FMT_UYVY8_1X16 + - 0x200f - - - @@ -4627,10 +5505,6 @@ the following codes. - - - - - u\ :sub:`11` - - u\ :sub:`10` - - u\ :sub:`9` - - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -4639,6 +5513,14 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` * - - - @@ -4658,14 +5540,14 @@ the following codes. - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4674,12 +5556,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * - - - - - - - - - - - + * .. _MEDIA-BUS-FMT-VYUY8-1X16: + + - MEDIA_BUS_FMT_VYUY8_1X16 + - 0x2010 - - - @@ -4697,10 +5577,6 @@ the following codes. - - - - - v\ :sub:`11` - - v\ :sub:`10` - - v\ :sub:`9` - - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -4709,6 +5585,14 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` * - - - @@ -4728,14 +5612,14 @@ the following codes. - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4744,14 +5628,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY12-2X12: + * .. _MEDIA-BUS-FMT-YUYV8-1X16: - - MEDIA_BUS_FMT_VYUY12_2X12 - - 0x201d - - - - - - - - + - MEDIA_BUS_FMT_YUYV8_1X16 + - 0x2011 - - - @@ -4769,18 +5649,22 @@ the following codes. - - - - - v\ :sub:`11` - - v\ :sub:`10` - - v\ :sub:`9` - - v\ :sub:`8` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` * - - - @@ -4800,14 +5684,6 @@ the following codes. - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4816,12 +5692,18 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * - - - - - - - - - - - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-YVYU8-1X16: + + - MEDIA_BUS_FMT_YVYU8_1X16 + - 0x2012 - - - @@ -4839,18 +5721,22 @@ the following codes. - - - - - u\ :sub:`11` - - u\ :sub:`10` - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` * - - - @@ -4870,14 +5756,6 @@ the following codes. - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4886,14 +5764,18 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV12-2X12: + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * .. _MEDIA-BUS-FMT-YDYUYDYV8-1X16: - - MEDIA_BUS_FMT_YUYV12_2X12 - - 0x201e - - - - - - - - + - MEDIA_BUS_FMT_YDYUYDYV8_1X16 + - 0x2014 - - - @@ -4911,10 +5793,6 @@ the following codes. - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4923,6 +5801,14 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - d + - d + - d + - d + - d + - d + - d + - d * - - - @@ -4942,14 +5828,14 @@ the following codes. - - - - - - - - - - - - - u\ :sub:`11` - - u\ :sub:`10` - - u\ :sub:`9` - - u\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -4977,14 +5863,6 @@ the following codes. - - - - - - - - - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -4993,6 +5871,14 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - d + - d + - d + - d + - d + - d + - d + - d * - - - @@ -5012,14 +5898,14 @@ the following codes. - - - - - - - - - - - - - v\ :sub:`11` - - v\ :sub:`10` - - v\ :sub:`9` - - v\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -5028,18 +5914,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU12-2X12: + * .. _MEDIA-BUS-FMT-UYVY10-1X20: - - MEDIA_BUS_FMT_YVYU12_2X12 - - 0x201f - - - - - - - - - - - - - - - - + - MEDIA_BUS_FMT_UYVY10_1X20 + - 0x201a - - - @@ -5053,8 +5931,16 @@ the following codes. - - - - - y\ :sub:`11` - - y\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -5080,16 +5966,6 @@ the following codes. - - - - - - - - - - - - - - - - - - - - - v\ :sub:`11` - - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -5100,16 +5976,20 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * - - - - - - - - - - - - - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-VYUY10-1X20: + + - MEDIA_BUS_FMT_VYUY10_1X20 + - 0x201b - - - @@ -5123,8 +6003,16 @@ the following codes. - - - - - y\ :sub:`11` - - y\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -5150,16 +6038,6 @@ the following codes. - - - - - - - - - - - - - - - - - - - - - u\ :sub:`11` - - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -5170,14 +6048,20 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY8-1X16: + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUYV10-1X20: - - MEDIA_BUS_FMT_UYVY8_1X16 - - 0x200f - - - - - - - - + - MEDIA_BUS_FMT_YUYV10_1X20 + - 0x200d - - - @@ -5191,14 +6075,8 @@ the following codes. - - - - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5207,6 +6085,16 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` * - - - @@ -5222,18 +6110,8 @@ the following codes. - - - - - - - - - - - - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5242,27 +6120,8 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY8-1X16: - - - MEDIA_BUS_FMT_VYUY8_1X16 - - 0x2010 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -5271,20 +6130,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * - - - - - - - - - - - + * .. _MEDIA-BUS-FMT-YVYU10-1X20: + + - MEDIA_BUS_FMT_YVYU10_1X20 + - 0x200e - - - @@ -5298,14 +6147,8 @@ the following codes. - - - - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5314,13 +6157,17 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV8-1X16: - - - MEDIA_BUS_FMT_YUYV8_1X16 - - 0x2011 - - - - - - + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * - - - - @@ -5335,6 +6182,8 @@ the following codes. - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5343,6 +6192,8 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -5351,7 +6202,10 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * - + * .. _MEDIA-BUS-FMT-VUY8-1X24: + + - MEDIA_BUS_FMT_VUY8_1X24 + - 0x201a - - - @@ -5361,6 +6215,34 @@ the following codes. - - - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUV8-1X24: + + - MEDIA_BUS_FMT_YUV8_1X24 + - 0x2025 - - - @@ -5378,6 +6260,14 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -5386,18 +6276,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU8-1X16: + * .. _MEDIA-BUS-FMT-UYYVYY8-0-5X24: - - MEDIA_BUS_FMT_YVYU8_1X16 - - 0x2012 - - - - - - - - - - - - - - - - + - MEDIA_BUS_FMT_UYYVYY8_0_5X24 + - 0x2026 - - - @@ -5407,6 +6289,22 @@ the following codes. - - - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5415,14 +6313,6 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` * - - - @@ -5434,14 +6324,22 @@ the following codes. - - - - - - - - - - - - - - - - - - - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5450,6 +6348,23 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYVY12-1X24: + + - MEDIA_BUS_FMT_UYVY12_1X24 + - 0x2020 + - + - + - + - + - + - + - + - + - + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -5458,10 +6373,20 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-YDYUYDYV8-1X16: - - - MEDIA_BUS_FMT_YDYUYDYV8_1X16 - - 0x2014 + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - - - - @@ -5471,6 +6396,35 @@ the following codes. - - - + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-VYUY12-1X24: + + - MEDIA_BUS_FMT_VYUY12_1X24 + - 0x2021 + - - - - @@ -5479,6 +6433,22 @@ the following codes. - - - + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5487,14 +6457,6 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - d - - d - - d - - d - - d - - d - - d - - d * - - - @@ -5506,6 +6468,35 @@ the following codes. - - - + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUYV12-1X24: + + - MEDIA_BUS_FMT_YUYV12_1X24 + - 0x2022 + - - - - @@ -5514,6 +6505,10 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5522,6 +6517,10 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` - u\ :sub:`7` - u\ :sub:`6` - u\ :sub:`5` @@ -5541,6 +6540,35 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-YVYU12-1X24: + + - MEDIA_BUS_FMT_YVYU12_1X24 + - 0x2023 + - - - - @@ -5549,6 +6577,10 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5557,14 +6589,18 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - d - - d - - d - - d - - d - - d - - d - - d + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` * - - - @@ -5576,14 +6612,39 @@ the following codes. - - - + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUV10-1X30: + + - MEDIA_BUS_FMT_YUV10_1X30 + - 0x2016 - - - - - - - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5592,6 +6653,18 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - v\ :sub:`9` + - v\ :sub:`8` - v\ :sub:`7` - v\ :sub:`6` - v\ :sub:`5` @@ -5600,20 +6673,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY10-1X20: + * .. _MEDIA-BUS-FMT-UYYVYY10-0-5X30: - - MEDIA_BUS_FMT_UYVY10_1X20 - - 0x201a - - - - - - - - - - - - - - - - - - - - + - MEDIA_BUS_FMT_UYYVYY10_0_5X30 + - 0x2027 - - - @@ -5637,21 +6700,21 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` * - - - - - - - - - - - - - - - - - - - - - - - - - - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -5672,23 +6735,166 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY10-1X20: - - - MEDIA_BUS_FMT_VYUY10_1X20 - - 0x201b - - - - - - - - - - - - - - - - - - - - - - + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-AYUV8-1X32: + + - MEDIA_BUS_FMT_AYUV8_1X32 + - 0x2017 + - + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + + +.. raw:: latex + + \endgroup + + +The following table list existing packed 36bit wide YUV formats. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-yuv8-36bit: + +.. flat-table:: 36bit YUV Formats + :header-rows: 2 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`35` Data organization + * - + - + - Bit + - 35 + - 34 + - 33 + - 32 + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 10 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-UYYVYY12-0-5X36: + + - MEDIA_BUS_FMT_UYYVYY12_0_5X36 + - 0x2028 + - + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - - - + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -5699,6 +6905,8 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -5709,31 +6917,8 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -5744,23 +6929,13 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV10-1X20: + * .. _MEDIA-BUS-FMT-YUV12-1X36: - - MEDIA_BUS_FMT_YUYV10_1X20 - - 0x200d - - - - - - - - - - - - - - - - - - - - - - - - + - MEDIA_BUS_FMT_YUV12_1X36 + - 0x2029 - + - y\ :sub:`11` + - y\ :sub:`10` - y\ :sub:`9` - y\ :sub:`8` - y\ :sub:`7` @@ -5771,6 +6946,8 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` + - u\ :sub:`11` + - u\ :sub:`10` - u\ :sub:`9` - u\ :sub:`8` - u\ :sub:`7` @@ -5781,31 +6958,8 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` + - v\ :sub:`11` + - v\ :sub:`10` - v\ :sub:`9` - v\ :sub:`8` - v\ :sub:`7` @@ -5816,44 +6970,41 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU10-1X20: - - MEDIA_BUS_FMT_YVYU10_1X20 - - 0x200e - - - - - - - - - - - - - - + +.. raw:: latex + + \endgroup + + +The following table list existing packed 48bit wide YUV formats. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-yuv8-48bit: + +.. flat-table:: 48bit YUV Formats + :header-rows: 3 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code - + - :cspan:`31` Data organization + * - - + - Bit - - - - - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - - v\ :sub:`9` - - v\ :sub:`8` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * - - - - @@ -5866,33 +7017,61 @@ the following codes. - - - + - 47 + - 46 + - 45 + - 44 + - 43 + - 42 + - 41 + - 40 + - 39 + - 38 + - 37 + - 36 + - 35 + - 34 + - 33 + - 32 + * - - - - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-VUY8-1X24: + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 10 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-YUV16-1X48: - - MEDIA_BUS_FMT_VUY8_1X24 - - 0x201a - - + - MEDIA_BUS_FMT_YUV16_1X48 + - 0x202a - - - @@ -5901,34 +7080,6 @@ the following codes. - - - - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUV8-1X24: - - - MEDIA_BUS_FMT_YUV8_1X24 - - 0x2025 - - - @@ -5938,6 +7089,14 @@ the following codes. - - - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`8` + - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` - y\ :sub:`5` @@ -5946,35 +7105,13 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-UYVY12-1X24: - - - MEDIA_BUS_FMT_UYVY12_1X24 - - 0x2020 - - - - - - - - - - - - - - + * - - - + - u\ :sub:`15` + - u\ :sub:`14` + - u\ :sub:`13` + - u\ :sub:`12` - u\ :sub:`11` - u\ :sub:`10` - u\ :sub:`9` @@ -5987,29 +7124,10 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * - - - - - - - - - - - - - - - - - - - - - + - v\ :sub:`15` + - v\ :sub:`14` + - v\ :sub:`13` + - v\ :sub:`12` - v\ :sub:`11` - v\ :sub:`10` - v\ :sub:`9` @@ -6022,24 +7140,10 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-VYUY12-1X24: + * .. _MEDIA-BUS-FMT-UYYVYY16-0-5X48: - - MEDIA_BUS_FMT_VYUY12_1X24 - - 0x2021 - - - - + - MEDIA_BUS_FMT_UYYVYY16_0_5X48 + - 0x202b - - - @@ -6047,31 +7151,6 @@ the following codes. - - - - - v\ :sub:`11` - - v\ :sub:`10` - - v\ :sub:`9` - - v\ :sub:`8` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - * - - - - @@ -6082,6 +7161,10 @@ the following codes. - - - + - u\ :sub:`15` + - u\ :sub:`14` + - u\ :sub:`13` + - u\ :sub:`12` - u\ :sub:`11` - u\ :sub:`10` - u\ :sub:`9` @@ -6094,6 +7177,13 @@ the following codes. - u\ :sub:`2` - u\ :sub:`1` - u\ :sub:`0` + * - + - + - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` - y\ :sub:`11` - y\ :sub:`10` - y\ :sub:`9` @@ -6106,22 +7196,13 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUYV12-1X24: - - - MEDIA_BUS_FMT_YUYV12_1X24 - - 0x2022 - - - - - - - - - - - - - - - - - - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` - y\ :sub:`11` - y\ :sub:`10` - - y\ :sub:`9` + - y\ :sub:`8` - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` @@ -6131,18 +7212,6 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - u\ :sub:`11` - - u\ :sub:`10` - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` * - - - @@ -6154,35 +7223,6 @@ the following codes. - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - - v\ :sub:`11` - - v\ :sub:`10` - - v\ :sub:`9` - - v\ :sub:`8` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-YVYU12-1X24: - - - MEDIA_BUS_FMT_YVYU12_1X24 - - 0x2023 - - - - - @@ -6191,18 +7231,10 @@ the following codes. - - - - - y\ :sub:`11` - - y\ :sub:`10` - - y\ :sub:`9` - - y\ :sub:`8` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` + - v\ :sub:`15` + - v\ :sub:`14` + - v\ :sub:`13` + - v\ :sub:`12` - v\ :sub:`11` - v\ :sub:`10` - v\ :sub:`9` @@ -6218,14 +7250,10 @@ the following codes. * - - - - - - - - - - - - - - - - - - - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` - y\ :sub:`11` - y\ :sub:`10` - y\ :sub:`9` @@ -6238,26 +7266,13 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - u\ :sub:`11` - - u\ :sub:`10` - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - * .. _MEDIA-BUS-FMT-YUV10-1X30: - - - MEDIA_BUS_FMT_YUV10_1X30 - - 0x2016 - - - - - - - - y\ :sub:`9` + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`8` - y\ :sub:`8` - y\ :sub:`7` - y\ :sub:`6` @@ -6267,63 +7282,6 @@ the following codes. - y\ :sub:`2` - y\ :sub:`1` - y\ :sub:`0` - - u\ :sub:`9` - - u\ :sub:`8` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - - v\ :sub:`9` - - v\ :sub:`8` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` - * .. _MEDIA-BUS-FMT-AYUV8-1X32: - - - MEDIA_BUS_FMT_AYUV8_1X32 - - 0x2017 - - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - y\ :sub:`7` - - y\ :sub:`6` - - y\ :sub:`5` - - y\ :sub:`4` - - y\ :sub:`3` - - y\ :sub:`2` - - y\ :sub:`1` - - y\ :sub:`0` - - u\ :sub:`7` - - u\ :sub:`6` - - u\ :sub:`5` - - u\ :sub:`4` - - u\ :sub:`3` - - u\ :sub:`2` - - u\ :sub:`1` - - u\ :sub:`0` - - v\ :sub:`7` - - v\ :sub:`6` - - v\ :sub:`5` - - v\ :sub:`4` - - v\ :sub:`3` - - v\ :sub:`2` - - v\ :sub:`1` - - v\ :sub:`0` .. raw:: latex -- cgit v1.1 From da6c8f5e2a63de7148dfffa8bffab1be02f378c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 31 Mar 2017 11:03:20 +0100 Subject: dma-buf: align debugfs output Align the heading with the values output from debugfs. Signed-off-by: Russell King Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/E1cttOq-0006GX-U7@rmk-PC.armlinux.org.uk --- drivers/dma-buf/dma-buf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index ebaf1923..f72aaac 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1072,7 +1072,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) return ret; seq_puts(s, "\nDma-buf Objects:\n"); - seq_puts(s, "size\tflags\tmode\tcount\texp_name\n"); + seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\n", + "size", "flags", "mode", "count"); list_for_each_entry(buf_obj, &db_list.head, list_node) { ret = mutex_lock_interruptible(&buf_obj->lock); -- cgit v1.1 From 5d5f7c571549099dd03e56cdb46a551da088a106 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 10:01:34 +0200 Subject: MAINTAINERS: meson-drm: remove useless git repository Meson DRM is switching to drm-misc, so remove the freedesktop drm/meson-drm git repository from MAINTAINERS entry. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong Link: http://patchwork.freedesktop.org/patch/msgid/1491292894-9190-1-git-send-email-narmstrong@baylibre.com --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d0d9ed8..8d3eb6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4258,7 +4258,6 @@ W: http://linux-meson.com/ S: Supported F: drivers/gpu/drm/meson/ F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -T: git git://anongit.freedesktop.org/drm/drm-meson T: git git://anongit.freedesktop.org/drm/drm-misc DRM DRIVERS FOR EXYNOS -- cgit v1.1 From d519cb76181efc78ba67e87b38286fa04d46dfa3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 Apr 2017 09:08:44 +0200 Subject: drm: virtio: add virtio_gpu_translate_format Factors out code, no functional change. Signed-off-by: Gerd Hoffmann Acked-by: Daniel Vetter Tested-by: Laurent Vivier Link: http://patchwork.freedesktop.org/patch/msgid/20170403070845.10793-2-kraxel@redhat.com --- drivers/gpu/drm/virtio/virtgpu_drv.h | 1 + drivers/gpu/drm/virtio/virtgpu_fb.c | 58 +---------------------------- drivers/gpu/drm/virtio/virtgpu_plane.c | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 93900a8..1328185 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -334,6 +334,7 @@ int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); /* virtio_gpu_plane.c */ +uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc); struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, enum drm_plane_type type, int index); diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 9bfaef3..33df067 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -231,63 +231,9 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, mode_cmd.pitches[0] = mode_cmd.width * 4; mode_cmd.pixel_format = drm_mode_legacy_fb_format(32, 24); - switch (mode_cmd.pixel_format) { -#ifdef __BIG_ENDIAN - case DRM_FORMAT_XRGB8888: - format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM; - break; - case DRM_FORMAT_ARGB8888: - format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; - break; - case DRM_FORMAT_BGRX8888: - format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; - break; - case DRM_FORMAT_BGRA8888: - format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; - break; - case DRM_FORMAT_RGBX8888: - format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; - break; - case DRM_FORMAT_RGBA8888: - format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM; - break; - case DRM_FORMAT_XBGR8888: - format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM; - break; - case DRM_FORMAT_ABGR8888: - format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM; - break; -#else - case DRM_FORMAT_XRGB8888: - format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; - break; - case DRM_FORMAT_ARGB8888: - format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; - break; - case DRM_FORMAT_BGRX8888: - format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM; - break; - case DRM_FORMAT_BGRA8888: - format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; - break; - case DRM_FORMAT_RGBX8888: - format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM; - break; - case DRM_FORMAT_RGBA8888: - format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM; - break; - case DRM_FORMAT_XBGR8888: - format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; - break; - case DRM_FORMAT_ABGR8888: - format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM; - break; -#endif - default: - DRM_ERROR("failed to find virtio gpu format for %d\n", - mode_cmd.pixel_format); + format = virtio_gpu_translate_format(mode_cmd.pixel_format); + if (format == 0) return -EINVAL; - } size = mode_cmd.pitches[0] * mode_cmd.height; obj = virtio_gpu_alloc_object(dev, size, false, true); diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 1ff9c64..372c91c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -42,6 +42,74 @@ static const uint32_t virtio_gpu_cursor_formats[] = { DRM_FORMAT_ARGB8888, }; +uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc) +{ + uint32_t format; + + switch (drm_fourcc) { +#ifdef __BIG_ENDIAN + case DRM_FORMAT_XRGB8888: + format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM; + break; + case DRM_FORMAT_ARGB8888: + format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; + break; + case DRM_FORMAT_BGRX8888: + format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; + break; + case DRM_FORMAT_BGRA8888: + format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; + break; + case DRM_FORMAT_RGBX8888: + format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; + break; + case DRM_FORMAT_RGBA8888: + format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM; + break; + case DRM_FORMAT_XBGR8888: + format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM; + break; + case DRM_FORMAT_ABGR8888: + format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM; + break; +#else + case DRM_FORMAT_XRGB8888: + format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; + break; + case DRM_FORMAT_ARGB8888: + format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; + break; + case DRM_FORMAT_BGRX8888: + format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM; + break; + case DRM_FORMAT_BGRA8888: + format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM; + break; + case DRM_FORMAT_RGBX8888: + format = VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM; + break; + case DRM_FORMAT_RGBA8888: + format = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM; + break; + case DRM_FORMAT_XBGR8888: + format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; + break; + case DRM_FORMAT_ABGR8888: + format = VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM; + break; +#endif + default: + /* + * This should not happen, we handle everything listed + * in virtio_gpu_formats[]. + */ + format = 0; + break; + } + WARN_ON(format == 0); + return format; +} + static void virtio_gpu_plane_destroy(struct drm_plane *plane) { drm_plane_cleanup(plane); -- cgit v1.1 From 9c4ad466d1dd2e067d5fdb2fcdbcc30fc5c145f9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 Apr 2017 09:08:45 +0200 Subject: drm: virtio: fix virtio_gpu_mode_dumb_create Lookup format using virtio_gpu_translate_format() instead of hardcoding it. Fixes xorg display on bigendian guests (i.e. ppc64). Signed-off-by: Gerd Hoffmann Reviewed-by: Dave Airlie Acked-by: Daniel Vetter Tested-by: Laurent Vivier Link: http://patchwork.freedesktop.org/patch/msgid/20170403070845.10793-3-kraxel@redhat.com --- drivers/gpu/drm/virtio/virtgpu_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 336a57f..cc025d8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -88,6 +88,7 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv, int ret; uint32_t pitch; uint32_t resid; + uint32_t format; pitch = args->width * ((args->bpp + 1) / 8); args->size = pitch * args->height; @@ -98,9 +99,10 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv, if (ret) goto fail; + format = virtio_gpu_translate_format(DRM_FORMAT_XRGB8888); virtio_gpu_resource_id_get(vgdev, &resid); - virtio_gpu_cmd_create_resource(vgdev, resid, - 2, args->width, args->height); + virtio_gpu_cmd_create_resource(vgdev, resid, format, + args->width, args->height); /* attach the object to the resource */ obj = gem_to_virtio_gpu_obj(gobj); -- cgit v1.1 From a23d6265f033501529932db2d6b3f4bc138552ab Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 4 Apr 2017 14:31:56 +0200 Subject: drm: bridge: dw-hdmi: Extract PHY interrupt setup to a function In preparation for adding PHY operations to handle RX SENSE and HPD, group all the PHY interrupt setup code in a single location and extract it to a separate function. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu [narmstrong: renamed dw_hdmi_fb_registered to dw_hdmi_setup_i2c] Reviewed-by: Archit Taneja Signed-off-by: Neil Armstrong --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 51 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 32f02e9..ff1fae3 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1558,8 +1558,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) return 0; } -/* Wait until we are registered to enable interrupts */ -static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) +static void dw_hdmi_setup_i2c(struct dw_hdmi *hdmi) { hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, HDMI_PHY_I2CM_INT_ADDR); @@ -1567,15 +1566,6 @@ static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, HDMI_PHY_I2CM_CTLINT_ADDR); - - /* enable cable hot plug irq */ - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); - - /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - - return 0; } static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) @@ -1693,6 +1683,26 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); } +static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi) +{ + /* + * Configure the PHY RX SENSE and HPD interrupts polarities and clear + * any pending interrupt. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + + /* Enable cable hot plug irq. */ + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); + + /* Clear and unmute interrupts. */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); +} + static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, bool force) { @@ -2204,29 +2214,14 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->ddc = NULL; } - /* - * Configure registers related to HDMI interrupt - * generation before registering IRQ. - */ - hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); - - /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - hdmi->bridge.driver_private = hdmi; hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; #ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; #endif - ret = dw_hdmi_fb_registered(hdmi); - if (ret) - goto err_iahb; - - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), - HDMI_IH_MUTE_PHY_STAT0); + dw_hdmi_setup_i2c(hdmi); + dw_hdmi_phy_setup_hpd(hdmi); memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; -- cgit v1.1 From def23aa7e9821a3dfe3fb7b139dd0229a89fdeb0 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:31:57 +0200 Subject: drm: bridge: dw-hdmi: Switch to V4L bus format and encodings Switch code to use the newly introduced V4L bus formats IDs instead of custom defines. Also use the V4L encoding defines. Some display pipelines can only provide non-RBG input pixels to the HDMI TX Controller, this patch takes the pixel format from the plat_data if provided. Reviewed-by: Jose Abreu Reviewed-by: Archit Taneja Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 326 +++++++++++++++++++++--------- include/drm/bridge/dw_hdmi.h | 63 ++++++ 2 files changed, 294 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ff1fae3..16d5fff3 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -30,18 +30,15 @@ #include #include +#include +#include + #include "dw-hdmi.h" #include "dw-hdmi-audio.h" #define DDC_SEGMENT_ADDR 0x30 #define HDMI_EDID_LEN 512 -#define RGB 0 -#define YCBCR444 1 -#define YCBCR422_16BITS 2 -#define YCBCR422_8BITS 3 -#define XVYCC444 4 - enum hdmi_datamap { RGB444_8B = 0x01, RGB444_10B = 0x03, @@ -95,10 +92,10 @@ struct hdmi_vmode { }; struct hdmi_data_info { - unsigned int enc_in_format; - unsigned int enc_out_format; - unsigned int enc_color_depth; - unsigned int colorimetry; + unsigned int enc_in_bus_format; + unsigned int enc_out_bus_format; + unsigned int enc_in_encoding; + unsigned int enc_out_encoding; unsigned int pix_repet_factor; unsigned int hdcp_enable; struct hdmi_vmode video_mode; @@ -567,6 +564,92 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); +static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_RGB161616_1X48: + return true; + + default: + return false; + } +} + +static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_YUV16_1X48: + return true; + + default: + return false; + } +} + +static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_UYVY12_1X24: + return true; + + default: + return false; + } +} + +static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + return true; + + default: + return false; + } +} + +static int hdmi_bus_fmt_color_depth(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + return 8; + + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + return 10; + + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_UYVY12_1X24: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + return 12; + + case MEDIA_BUS_FMT_RGB161616_1X48: + case MEDIA_BUS_FMT_YUV16_1X48: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + return 16; + + default: + return 0; + } +} + /* * this submodule is responsible for the video data synchronization. * for example, for RGB 4:4:4 input, the data map is defined as @@ -579,37 +662,49 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi) int color_format = 0; u8 val; - if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x01; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x03; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x05; - else if (hdmi->hdmi_data.enc_color_depth == 16) - color_format = 0x07; - else - return; - } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x09; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x0B; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x0D; - else if (hdmi->hdmi_data.enc_color_depth == 16) - color_format = 0x0F; - else - return; - } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x16; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x14; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x12; - else - return; + switch (hdmi->hdmi_data.enc_in_bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + color_format = 0x01; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + color_format = 0x03; + break; + case MEDIA_BUS_FMT_RGB121212_1X36: + color_format = 0x05; + break; + case MEDIA_BUS_FMT_RGB161616_1X48: + color_format = 0x07; + break; + + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + color_format = 0x09; + break; + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + color_format = 0x0B; + break; + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + color_format = 0x0D; + break; + case MEDIA_BUS_FMT_YUV16_1X48: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + color_format = 0x0F; + break; + + case MEDIA_BUS_FMT_UYVY8_1X16: + color_format = 0x16; + break; + case MEDIA_BUS_FMT_UYVY10_1X20: + color_format = 0x14; + break; + case MEDIA_BUS_FMT_UYVY12_1X24: + color_format = 0x12; + break; + + default: + return; } val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | @@ -632,26 +727,30 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi) static int is_color_space_conversion(struct dw_hdmi *hdmi) { - return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format; + return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format; } static int is_color_space_decimation(struct dw_hdmi *hdmi) { - if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS) + if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) return 0; - if (hdmi->hdmi_data.enc_in_format == RGB || - hdmi->hdmi_data.enc_in_format == YCBCR444) + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format)) return 1; + return 0; } static int is_color_space_interpolation(struct dw_hdmi *hdmi) { - if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS) + if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format)) return 0; - if (hdmi->hdmi_data.enc_out_format == RGB || - hdmi->hdmi_data.enc_out_format == YCBCR444) + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) return 1; + return 0; } @@ -662,15 +761,16 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi) u32 csc_scale = 1; if (is_color_space_conversion(hdmi)) { - if (hdmi->hdmi_data.enc_out_format == RGB) { - if (hdmi->hdmi_data.colorimetry == - HDMI_COLORIMETRY_ITU_601) + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { + if (hdmi->hdmi_data.enc_out_encoding == + V4L2_YCBCR_ENC_601) csc_coeff = &csc_coeff_rgb_out_eitu601; else csc_coeff = &csc_coeff_rgb_out_eitu709; - } else if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.colorimetry == - HDMI_COLORIMETRY_ITU_601) + } else if (hdmi_bus_fmt_is_rgb( + hdmi->hdmi_data.enc_in_bus_format)) { + if (hdmi->hdmi_data.enc_out_encoding == + V4L2_YCBCR_ENC_601) csc_coeff = &csc_coeff_rgb_in_eitu601; else csc_coeff = &csc_coeff_rgb_in_eitu709; @@ -708,16 +808,23 @@ static void hdmi_video_csc(struct dw_hdmi *hdmi) else if (is_color_space_decimation(hdmi)) decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3; - if (hdmi->hdmi_data.enc_color_depth == 8) + switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) { + case 8: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; - else if (hdmi->hdmi_data.enc_color_depth == 10) + break; + case 10: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP; - else if (hdmi->hdmi_data.enc_color_depth == 12) + break; + case 12: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP; - else if (hdmi->hdmi_data.enc_color_depth == 16) + break; + case 16: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP; - else + break; + + default: return; + } /* Configure the CSC registers */ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); @@ -740,32 +847,43 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi) struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; u8 val, vp_conf; - if (hdmi_data->enc_out_format == RGB || - hdmi_data->enc_out_format == YCBCR444) { - if (!hdmi_data->enc_color_depth) { - output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 8) { + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) { + switch (hdmi_bus_fmt_color_depth( + hdmi->hdmi_data.enc_out_bus_format)) { + case 8: color_depth = 4; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 10) { + break; + case 10: color_depth = 5; - } else if (hdmi_data->enc_color_depth == 12) { + break; + case 12: color_depth = 6; - } else if (hdmi_data->enc_color_depth == 16) { + break; + case 16: color_depth = 7; - } else { - return; + break; + default: + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; } - } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { - if (!hdmi_data->enc_color_depth || - hdmi_data->enc_color_depth == 8) + } else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { + switch (hdmi_bus_fmt_color_depth( + hdmi->hdmi_data.enc_out_bus_format)) { + case 0: + case 8: remap_size = HDMI_VP_REMAP_YCC422_16bit; - else if (hdmi_data->enc_color_depth == 10) + break; + case 10: remap_size = HDMI_VP_REMAP_YCC422_20bit; - else if (hdmi_data->enc_color_depth == 12) + break; + case 12: remap_size = HDMI_VP_REMAP_YCC422_24bit; - else + break; + + default: return; + } output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; } else { return; @@ -1148,28 +1266,35 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* Initialise info frame from DRM mode */ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (hdmi->hdmi_data.enc_out_format == YCBCR444) + if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) + else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV422; else frame.colorspace = HDMI_COLORSPACE_RGB; /* Set up colorimetry */ - if (hdmi->hdmi_data.enc_out_format == XVYCC444) { - frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; - if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) - frame.extended_colorimetry = + switch (hdmi->hdmi_data.enc_out_encoding) { + case V4L2_YCBCR_ENC_601: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/ - frame.extended_colorimetry = + case V4L2_YCBCR_ENC_709: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_709; + frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; - } else if (hdmi->hdmi_data.enc_out_format != RGB) { - frame.colorimetry = hdmi->hdmi_data.colorimetry; - frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } else { /* Carries no data */ - frame.colorimetry = HDMI_COLORIMETRY_NONE; - frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; + default: /* Carries no data */ + frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; } frame.scan_mode = HDMI_SCAN_MODE_NONE; @@ -1498,19 +1623,30 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) (hdmi->vic == 21) || (hdmi->vic == 22) || (hdmi->vic == 2) || (hdmi->vic == 3) || (hdmi->vic == 17) || (hdmi->vic == 18)) - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601; else - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709; hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; - /* TODO: Get input format from IPU (via FB driver interface) */ - hdmi->hdmi_data.enc_in_format = RGB; + /* TOFIX: Get input format from plat data or fallback to RGB888 */ + if (hdmi->plat_data->input_bus_format >= 0) + hdmi->hdmi_data.enc_in_bus_format = + hdmi->plat_data->input_bus_format; + else + hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + /* TOFIX: Get input encoding from plat data or fallback to none */ + if (hdmi->plat_data->input_bus_encoding >= 0) + hdmi->hdmi_data.enc_in_encoding = + hdmi->plat_data->input_bus_encoding; + else + hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; - hdmi->hdmi_data.enc_out_format = RGB; + /* TOFIX: Default to RGB888 output format */ + hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - hdmi->hdmi_data.enc_color_depth = 8; hdmi->hdmi_data.pix_repet_factor = 0; hdmi->hdmi_data.hdcp_enable = 0; hdmi->hdmi_data.video_mode.mdataenablepolarity = true; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index bcceee8..5d6b92c 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -14,6 +14,67 @@ struct dw_hdmi; +/** + * DOC: Supported input formats and encodings + * + * Depending on the Hardware configuration of the Controller IP, it supports + * a subset of the following input formats and encodings on its internal + * 48bit bus. + * + * +----------------------+----------------------------------+------------------------------+ + * + Format Name + Format Code + Encodings + + * +----------------------+----------------------------------+------------------------------+ + * + RGB 4:4:4 8bit + ``MEDIA_BUS_FMT_RGB888_1X24`` + ``V4L2_YCBCR_ENC_DEFAULT`` + + * +----------------------+----------------------------------+------------------------------+ + * + RGB 4:4:4 10bits + ``MEDIA_BUS_FMT_RGB101010_1X30`` + ``V4L2_YCBCR_ENC_DEFAULT`` + + * +----------------------+----------------------------------+------------------------------+ + * + RGB 4:4:4 12bits + ``MEDIA_BUS_FMT_RGB121212_1X36`` + ``V4L2_YCBCR_ENC_DEFAULT`` + + * +----------------------+----------------------------------+------------------------------+ + * + RGB 4:4:4 16bits + ``MEDIA_BUS_FMT_RGB161616_1X48`` + ``V4L2_YCBCR_ENC_DEFAULT`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:4:4 8bit + ``MEDIA_BUS_FMT_YUV8_1X24`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * + + + or ``V4L2_YCBCR_ENC_XV601`` + + * + + + or ``V4L2_YCBCR_ENC_XV709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:4:4 10bits + ``MEDIA_BUS_FMT_YUV10_1X30`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * + + + or ``V4L2_YCBCR_ENC_XV601`` + + * + + + or ``V4L2_YCBCR_ENC_XV709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:4:4 12bits + ``MEDIA_BUS_FMT_YUV12_1X36`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * + + + or ``V4L2_YCBCR_ENC_XV601`` + + * + + + or ``V4L2_YCBCR_ENC_XV709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:4:4 16bits + ``MEDIA_BUS_FMT_YUV16_1X48`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * + + + or ``V4L2_YCBCR_ENC_XV601`` + + * + + + or ``V4L2_YCBCR_ENC_XV709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:2 8bit + ``MEDIA_BUS_FMT_UYVY8_1X16`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:2 10bits + ``MEDIA_BUS_FMT_UYVY10_1X20`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:2 12bits + ``MEDIA_BUS_FMT_UYVY12_1X24`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:0 8bit + ``MEDIA_BUS_FMT_UYYVYY8_0_5X24`` + ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:0 10bits + ``MEDIA_BUS_FMT_UYYVYY10_0_5X30``+ ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:0 12bits + ``MEDIA_BUS_FMT_UYYVYY12_0_5X36``+ ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + * + YCbCr 4:2:0 16bits + ``MEDIA_BUS_FMT_UYYVYY16_0_5X48``+ ``V4L2_YCBCR_ENC_601`` + + * + + + or ``V4L2_YCBCR_ENC_709`` + + * +----------------------+----------------------------------+------------------------------+ + */ + enum { DW_HDMI_RES_8, DW_HDMI_RES_10, @@ -62,6 +123,8 @@ struct dw_hdmi_plat_data { struct regmap *regm; enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); + unsigned long input_bus_format; + unsigned long input_bus_encoding; /* Vendor PHY support */ const struct dw_hdmi_phy_ops *phy_ops; -- cgit v1.1 From e624f516d99986faf678c22ed492797416c80215 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:31:58 +0200 Subject: drm: bridge: dw-hdmi: Add Documentation on supported input formats This patch adds a new DRM documentation entry and links to the input format table added in the dw_hdmi header. Reviewed-by: Archit Taneja Acked-by: Laurent Pinchart Signed-off-by: Neil Armstrong --- Documentation/gpu/bridge/dw-hdmi.rst | 15 +++++++++++++++ Documentation/gpu/index.rst | 1 + 2 files changed, 16 insertions(+) create mode 100644 Documentation/gpu/bridge/dw-hdmi.rst diff --git a/Documentation/gpu/bridge/dw-hdmi.rst b/Documentation/gpu/bridge/dw-hdmi.rst new file mode 100644 index 0000000..486faad --- /dev/null +++ b/Documentation/gpu/bridge/dw-hdmi.rst @@ -0,0 +1,15 @@ +======================================================= + drm/bridge/dw-hdmi Synopsys DesignWare HDMI Controller +======================================================= + +Synopsys DesignWare HDMI Controller +=================================== + +This section covers everything related to the Synopsys DesignWare HDMI +Controller implemented as a DRM bridge. + +Supported Input Formats and Encodings +------------------------------------- + +.. kernel-doc:: include/drm/bridge/dw_hdmi.h + :doc: Supported input formats and encodings diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index e998ee0..d81c6ff 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -15,6 +15,7 @@ Linux GPU Driver Developer's Guide vc4 vga-switcheroo vgaarbiter + bridge/dw-hdmi todo .. only:: subproject and html -- cgit v1.1 From 386d3299ef7298a3bc57e2ff3498ce41ac7f6184 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:31:59 +0200 Subject: drm: bridge: dw-hdmi: Move HPD handling to PHY operations The HDMI TX controller support HPD and RXSENSE signaling from the PHY via it's STAT0 PHY interface, but some vendor PHYs can manage these signals independently from the controller, thus these STAT0 handling should be moved to PHY specific operations and become optional. The existing STAT0 HPD and RXSENSE handling code is refactored into a supplementaty set of default PHY operations that are used automatically when the platform glue doesn't provide its own operations. Reviewed-by: Jose Abreu Reviewed-by: Archit Taneja Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong Link: http://patchwork.freedesktop.org/patch/msgid/1491309119-24220-2-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 135 ++++++++++++++++++------------ include/drm/bridge/dw_hdmi.h | 5 ++ 2 files changed, 86 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 16d5fff3..84cc949 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1229,10 +1229,46 @@ static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, connector_status_connected : connector_status_disconnected; } +static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, + bool force, bool disabled, bool rxsense) +{ + u8 old_mask = hdmi->phy_mask; + + if (force || disabled || !rxsense) + hdmi->phy_mask |= HDMI_PHY_RX_SENSE; + else + hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; + + if (old_mask != hdmi->phy_mask) + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); +} + +static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) +{ + /* + * Configure the PHY RX SENSE and HPD interrupts polarities and clear + * any pending interrupt. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + + /* Enable cable hot plug irq. */ + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); + + /* Clear and unmute interrupts. */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); +} + static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = { .init = dw_hdmi_phy_init, .disable = dw_hdmi_phy_disable, .read_hpd = dw_hdmi_phy_read_hpd, + .update_hpd = dw_hdmi_phy_update_hpd, + .setup_hpd = dw_hdmi_phy_setup_hpd, }; /* ----------------------------------------------------------------------------- @@ -1808,35 +1844,10 @@ static void dw_hdmi_update_power(struct dw_hdmi *hdmi) */ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) { - u8 old_mask = hdmi->phy_mask; - - if (hdmi->force || hdmi->disabled || !hdmi->rxsense) - hdmi->phy_mask |= HDMI_PHY_RX_SENSE; - else - hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; - - if (old_mask != hdmi->phy_mask) - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); -} - -static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi) -{ - /* - * Configure the PHY RX SENSE and HPD interrupts polarities and clear - * any pending interrupt. - */ - hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - - /* Enable cable hot plug irq. */ - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); - - /* Clear and unmute interrupts. */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), - HDMI_IH_MUTE_PHY_STAT0); + if (hdmi->phy.ops->update_hpd) + hdmi->phy.ops->update_hpd(hdmi, hdmi->phy.data, + hdmi->force, hdmi->disabled, + hdmi->rxsense); } static enum drm_connector_status @@ -2028,6 +2039,41 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) return ret; } +void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) +{ + mutex_lock(&hdmi->mutex); + + if (!hdmi->force) { + /* + * If the RX sense status indicates we're disconnected, + * clear the software rxsense status. + */ + if (!rx_sense) + hdmi->rxsense = false; + + /* + * Only set the software rxsense status when both + * rxsense and hpd indicates we're connected. + * This avoids what seems to be bad behaviour in + * at least iMX6S versions of the phy. + */ + if (hpd) + hdmi->rxsense = true; + + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + } + mutex_unlock(&hdmi->mutex); +} + +void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + __dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense); +} +EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense); + static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) { struct dw_hdmi *hdmi = dev_id; @@ -2060,30 +2106,10 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) * ask the source to re-read the EDID. */ if (intr_stat & - (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { - mutex_lock(&hdmi->mutex); - if (!hdmi->force) { - /* - * If the RX sense status indicates we're disconnected, - * clear the software rxsense status. - */ - if (!(phy_stat & HDMI_PHY_RX_SENSE)) - hdmi->rxsense = false; - - /* - * Only set the software rxsense status when both - * rxsense and hpd indicates we're connected. - * This avoids what seems to be bad behaviour in - * at least iMX6S versions of the phy. - */ - if (phy_stat & HDMI_PHY_HPD) - hdmi->rxsense = true; - - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - } - mutex_unlock(&hdmi->mutex); - } + (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) + __dw_hdmi_setup_rx_sense(hdmi, + phy_stat & HDMI_PHY_HPD, + phy_stat & HDMI_PHY_RX_SENSE); if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { dev_dbg(hdmi->dev, "EVENT=%s\n", @@ -2357,7 +2383,8 @@ __dw_hdmi_probe(struct platform_device *pdev, #endif dw_hdmi_setup_i2c(hdmi); - dw_hdmi_phy_setup_hpd(hdmi); + if (hdmi->phy.ops->setup_hpd) + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 5d6b92c..ed599be 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -117,6 +117,9 @@ struct dw_hdmi_phy_ops { struct drm_display_mode *mode); void (*disable)(struct dw_hdmi *hdmi, void *data); enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); + void (*update_hpd)(struct dw_hdmi *hdmi, void *data, + bool force, bool disabled, bool rxsense); + void (*setup_hpd)(struct dw_hdmi *hdmi, void *data); }; struct dw_hdmi_plat_data { @@ -147,6 +150,8 @@ void dw_hdmi_unbind(struct device *dev); int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_plat_data *plat_data); +void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense); + void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); -- cgit v1.1 From cc0c43a0450ce46fcd8f2aa793703d36d9af761e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:21 +0200 Subject: drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Clean the crtc_enable by using the proper crtc_state instead of the state of the primary plane state data. Also fix the dependency to commit the plane changes even if enable is called after the flush. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_crtc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 0fe49ec..c986eb0 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -82,11 +82,18 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { static void meson_crtc_enable(struct drm_crtc *crtc) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); - struct drm_plane *plane = meson_crtc->priv->primary_plane; + struct drm_crtc_state *crtc_state = crtc->state; struct meson_drm *priv = meson_crtc->priv; + DRM_DEBUG_DRIVER("\n"); + + if (!crtc_state) { + DRM_ERROR("Invalid crtc_state\n"); + return; + } + /* Enable VPP Postblend */ - writel(plane->state->crtc_w, + writel(crtc_state->mode.hdisplay, priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE, @@ -101,6 +108,7 @@ static void meson_crtc_disable(struct drm_crtc *crtc) struct meson_drm *priv = meson_crtc->priv; priv->viu.osd1_enabled = false; + priv->viu.osd1_commit = false; /* Disable VPP Postblend */ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, @@ -137,8 +145,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc, struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; - if (priv->viu.osd1_enabled) - priv->viu.osd1_commit = true; + priv->viu.osd1_commit = true; } static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { -- cgit v1.1 From 8437d59ab312f0d71e7e328d700260d2fbd55c1c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:22 +0200 Subject: drm/meson: Add missing HDMI register Add missing VPU HDMI register. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_registers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 6adf9c1..2847381 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -1319,6 +1319,7 @@ #define VPU_MISC_CTRL 0x2740 #define VPU_ISP_GCLK_CTRL0 0x2741 #define VPU_ISP_GCLK_CTRL1 0x2742 +#define VPU_HDMI_FMT_CTRL 0x2743 #define VPU_VDIN_ASYNC_HOLD_CTRL 0x2743 #define VPU_VDISP_ASYNC_HOLD_CTRL 0x2744 #define VPU_VPUARB2_ASYNC_HOLD_CTRL 0x2745 -- cgit v1.1 From a41e82e6c4575b6c0a48bcc25a3feae4b2910934 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:23 +0200 Subject: drm/meson: Add support for components This patch adds support for optional components connected through the Device Tree endpoints scheme. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_drv.c | 113 +++++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index bc562a0..a2e9f56 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -150,9 +151,9 @@ static struct regmap_config meson_regmap_config = { .max_register = 0x1000, }; -static int meson_drv_probe(struct platform_device *pdev) +static int meson_drv_bind(struct device *dev) { - struct device *dev = &pdev->dev; + struct platform_device *pdev = to_platform_device(dev); struct meson_drm *priv; struct drm_device *drm; struct resource *res; @@ -215,6 +216,15 @@ static int meson_drv_probe(struct platform_device *pdev) drm_vblank_init(drm, 1); drm_mode_config_init(drm); + drm->mode_config.max_width = 3840; + drm->mode_config.max_height = 2160; + drm->mode_config.funcs = &meson_mode_config_funcs; + + /* Hardware Initialization */ + + meson_venc_init(priv); + meson_vpp_init(priv); + meson_viu_init(priv); /* Encoder Initialization */ @@ -222,11 +232,11 @@ static int meson_drv_probe(struct platform_device *pdev) if (ret) goto free_drm; - /* Hardware Initialization */ - - meson_venc_init(priv); - meson_vpp_init(priv); - meson_viu_init(priv); + ret = component_bind_all(drm->dev, drm); + if (ret) { + dev_err(drm->dev, "Couldn't bind all components\n"); + goto free_drm; + } ret = meson_plane_create(priv); if (ret) @@ -241,9 +251,6 @@ static int meson_drv_probe(struct platform_device *pdev) goto free_drm; drm_mode_config_reset(drm); - drm->mode_config.max_width = 8192; - drm->mode_config.max_height = 8192; - drm->mode_config.funcs = &meson_mode_config_funcs; priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector); @@ -268,9 +275,9 @@ free_drm: return ret; } -static int meson_drv_remove(struct platform_device *pdev) +static void meson_drv_unbind(struct device *dev) { - struct drm_device *drm = dev_get_drvdata(&pdev->dev); + struct drm_device *drm = dev_get_drvdata(dev); struct meson_drm *priv = drm->dev_private; drm_dev_unregister(drm); @@ -280,9 +287,88 @@ static int meson_drv_remove(struct platform_device *pdev) drm_vblank_cleanup(drm); drm_dev_unref(drm); - return 0; } +static const struct component_master_ops meson_drv_master_ops = { + .bind = meson_drv_bind, + .unbind = meson_drv_unbind, +}; + +static int compare_of(struct device *dev, void *data) +{ + DRM_DEBUG_DRIVER("Comparing of node %s with %s\n", + of_node_full_name(dev->of_node), + of_node_full_name(data)); + + return dev->of_node == data; +} + +/* Possible connectors nodes to ignore */ +static const struct of_device_id connectors_match[] = { + { .compatible = "composite-video-connector" }, + { .compatible = "svideo-connector" }, + { .compatible = "hdmi-connector" }, + { .compatible = "dvi-connector" }, + {} +}; + +static int meson_probe_remote(struct platform_device *pdev, + struct component_match **match, + struct device_node *parent, + struct device_node *remote) +{ + struct device_node *ep, *remote_node; + int count = 1; + + /* If node is a connector, return and do not add to match table */ + if (of_match_node(connectors_match, remote)) + return 1; + + component_match_add(&pdev->dev, match, compare_of, remote); + + for_each_endpoint_of_node(remote, ep) { + remote_node = of_graph_get_remote_port_parent(ep); + if (!remote_node || + remote_node == parent || /* Ignore parent endpoint */ + !of_device_is_available(remote_node)) + continue; + + count += meson_probe_remote(pdev, match, remote, remote_node); + + of_node_put(remote_node); + } + + return count; +} + +static int meson_drv_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct device_node *np = pdev->dev.of_node; + struct device_node *ep, *remote; + int count = 0; + + for_each_endpoint_of_node(np, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) + continue; + + count += meson_probe_remote(pdev, &match, np, remote); + } + + /* If some endpoints were found, initialize the nodes */ + if (count) { + dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count); + + return component_master_add_with_match(&pdev->dev, + &meson_drv_master_ops, + match); + } + + /* If no output endpoints were available, simply bail out */ + return 0; +}; + static const struct of_device_id dt_match[] = { { .compatible = "amlogic,meson-gxbb-vpu" }, { .compatible = "amlogic,meson-gxl-vpu" }, @@ -293,7 +379,6 @@ MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver meson_drm_platform_driver = { .probe = meson_drv_probe, - .remove = meson_drv_remove, .driver = { .name = "meson-drm", .of_match_table = dt_match, -- cgit v1.1 From cb110b665e77ebf99f8235f257b88eea007186d3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:24 +0200 Subject: drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available Since this is managed now by the components code, if CVBS is not available and HDMI neither, the drm driver won't bind anyway. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_venc_cvbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index a2bcc70..a96fcb4 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -248,7 +248,7 @@ int meson_venc_cvbs_create(struct meson_drm *priv) if (!meson_venc_cvbs_connector_is_available(priv)) { dev_info(drm->dev, "CVBS Output connector not available\n"); - return -ENODEV; + return 0; } meson_venc_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_venc_cvbs), -- cgit v1.1 From 2f4c95dc3d1d1518cb6a5e280050c48a79d3ee08 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:25 +0200 Subject: drm/meson: add support for HDMI clock support This patchs adds support for the supported HDMI modes clocks frequencies. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_vclk.c | 624 +++++++++++++++++++++++++++++++- drivers/gpu/drm/meson/meson_vclk.h | 6 +- drivers/gpu/drm/meson/meson_venc_cvbs.c | 9 +- 3 files changed, 623 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 252cfd4..3731479 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -27,9 +27,26 @@ * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. * We handle the following encodings : * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks - * - * What is missing : * - HDMI Pixel Clocks generation + * What is missing : + * - Genenate Pixel clocks for 2K/4K 10bit formats + * + * Clock generator scheme : + * __________ _________ _____ + * | | | | | |--ENCI + * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL + * |__________| |_________| \ | MUX |--ENCP + * --VCLK2-| |--VDAC + * |_____|--HDMI-TX + * + * Final clocks can take input for either VCLK or VCLK2, but + * VCLK is the preferred path for HDMI clocking and VCLK2 is the + * preferred path for CVBS VDAC clocking. + * + * VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12. + * + * The PLL_DIV can achieve an additional fractional dividing like + * 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks. */ /* HHI Registers */ @@ -50,11 +67,34 @@ #define VCLK2_SOFT_RESET BIT(15) #define VCLK2_DIV1_EN BIT(0) #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ +#define VCLK_DIV_MASK 0xff +#define VCLK_DIV_EN BIT(16) +#define VCLK_DIV_RESET BIT(17) +#define CTS_ENCP_SEL_MASK (0xf << 24) +#define CTS_ENCP_SEL_SHIFT 24 #define CTS_ENCI_SEL_MASK (0xf << 28) #define CTS_ENCI_SEL_SHIFT 28 +#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ +#define VCLK_EN BIT(19) +#define VCLK_SEL_MASK (0x7 << 16) +#define VCLK_SEL_SHIFT 16 +#define VCLK_SOFT_RESET BIT(15) +#define VCLK_DIV1_EN BIT(0) +#define VCLK_DIV2_EN BIT(1) +#define VCLK_DIV4_EN BIT(2) +#define VCLK_DIV6_EN BIT(3) +#define VCLK_DIV12_EN BIT(4) #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ #define CTS_ENCI_EN BIT(0) +#define CTS_ENCP_EN BIT(2) #define CTS_VDAC_EN BIT(4) +#define HDMI_TX_PIXEL_EN BIT(5) +#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ +#define HDMI_TX_PIXEL_SEL_MASK (0xf << 16) +#define HDMI_TX_PIXEL_SEL_SHIFT 16 +#define CTS_HDMI_SYS_SEL_MASK (0x7 << 9) +#define CTS_HDMI_SYS_DIV_MASK (0x7f) +#define CTS_HDMI_SYS_EN BIT(8) #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ @@ -69,6 +109,126 @@ #define HDMI_PLL_RESET BIT(28) #define HDMI_PLL_LOCK BIT(31) +/* VID PLL Dividers */ +enum { + VID_PLL_DIV_1 = 0, + VID_PLL_DIV_2, + VID_PLL_DIV_2p5, + VID_PLL_DIV_3, + VID_PLL_DIV_3p5, + VID_PLL_DIV_3p75, + VID_PLL_DIV_4, + VID_PLL_DIV_5, + VID_PLL_DIV_6, + VID_PLL_DIV_6p25, + VID_PLL_DIV_7, + VID_PLL_DIV_7p5, + VID_PLL_DIV_12, + VID_PLL_DIV_14, + VID_PLL_DIV_15, +}; + +void meson_vid_pll_set(struct meson_drm *priv, unsigned int div) +{ + unsigned int shift_val = 0; + unsigned int shift_sel = 0; + + /* Disable vid_pll output clock */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0); + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0); + + switch (div) { + case VID_PLL_DIV_2: + shift_val = 0x0aaa; + shift_sel = 0; + break; + case VID_PLL_DIV_2p5: + shift_val = 0x5294; + shift_sel = 2; + break; + case VID_PLL_DIV_3: + shift_val = 0x0db6; + shift_sel = 0; + break; + case VID_PLL_DIV_3p5: + shift_val = 0x36cc; + shift_sel = 1; + break; + case VID_PLL_DIV_3p75: + shift_val = 0x6666; + shift_sel = 2; + break; + case VID_PLL_DIV_4: + shift_val = 0x0ccc; + shift_sel = 0; + break; + case VID_PLL_DIV_5: + shift_val = 0x739c; + shift_sel = 2; + break; + case VID_PLL_DIV_6: + shift_val = 0x0e38; + shift_sel = 0; + break; + case VID_PLL_DIV_6p25: + shift_val = 0x0000; + shift_sel = 3; + break; + case VID_PLL_DIV_7: + shift_val = 0x3c78; + shift_sel = 1; + break; + case VID_PLL_DIV_7p5: + shift_val = 0x78f0; + shift_sel = 2; + break; + case VID_PLL_DIV_12: + shift_val = 0x0fc0; + shift_sel = 0; + break; + case VID_PLL_DIV_14: + shift_val = 0x3f80; + shift_sel = 1; + break; + case VID_PLL_DIV_15: + shift_val = 0x7f80; + shift_sel = 2; + break; + } + + if (div == VID_PLL_DIV_1) + /* Enable vid_pll bypass to HDMI pll */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_BYPASS, VID_PLL_BYPASS); + else { + /* Disable Bypass */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_BYPASS, 0); + /* Clear sel */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + 3 << 16, 0); + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_PRESET, 0); + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + 0x7fff, 0); + + /* Setup sel and val */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + 3 << 16, shift_sel << 16); + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_PRESET, VID_PLL_PRESET); + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + 0x7fff, shift_val); + + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_PRESET, 0); + } + + /* Enable the vid_pll output clock */ + regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, + VID_PLL_EN, VID_PLL_EN); +} + /* * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC * @@ -110,15 +270,8 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) /* Disable VCLK2 */ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); - /* Disable vid_pll output clock */ - regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0); - regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0); - /* Enable vid_pll bypass to HDMI pll */ - regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, - VID_PLL_BYPASS, VID_PLL_BYPASS); - /* Enable the vid_pll output clock */ - regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, - VID_PLL_EN, VID_PLL_EN); + /* Setup vid_pll to /1 */ + meson_vid_pll_set(priv, VID_PLL_DIV_1); /* Setup the VCLK2 divider value to achieve 27MHz */ regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, @@ -159,9 +312,454 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) CTS_VDAC_EN, CTS_VDAC_EN); } + +/* PLL O1 O2 O3 VP DV EN TX */ +/* 4320 /4 /4 /1 /5 /1 => /2 /2 */ +#define MESON_VCLK_HDMI_ENCI_54000 1 +/* 4320 /4 /4 /1 /5 /1 => /1 /2 */ +#define MESON_VCLK_HDMI_DDR_54000 2 +/* 2970 /4 /1 /1 /5 /1 => /1 /2 */ +#define MESON_VCLK_HDMI_DDR_148500 3 +/* 2970 /2 /2 /2 /5 /1 => /1 /1 */ +#define MESON_VCLK_HDMI_74250 4 +/* 2970 /1 /2 /2 /5 /1 => /1 /1 */ +#define MESON_VCLK_HDMI_148500 5 +/* 2970 /1 /1 /1 /5 /2 => /1 /1 */ +#define MESON_VCLK_HDMI_297000 6 +/* 5940 /1 /1 /2 /5 /1 => /1 /1 */ +#define MESON_VCLK_HDMI_594000 7 + +struct meson_vclk_params { + unsigned int pll_base_freq; + unsigned int pll_od1; + unsigned int pll_od2; + unsigned int pll_od3; + unsigned int vid_pll_div; + unsigned int vclk_div; +} params[] = { + [MESON_VCLK_HDMI_ENCI_54000] = { + .pll_base_freq = 4320000, + .pll_od1 = 4, + .pll_od2 = 4, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_DDR_54000] = { + .pll_base_freq = 4320000, + .pll_od1 = 4, + .pll_od2 = 4, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_DDR_148500] = { + .pll_base_freq = 2970000, + .pll_od1 = 4, + .pll_od2 = 1, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_74250] = { + .pll_base_freq = 2970000, + .pll_od1 = 2, + .pll_od2 = 2, + .pll_od3 = 2, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_148500] = { + .pll_base_freq = 2970000, + .pll_od1 = 1, + .pll_od2 = 2, + .pll_od3 = 2, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_297000] = { + .pll_base_freq = 2970000, + .pll_od1 = 1, + .pll_od2 = 1, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_594000] = { + .pll_base_freq = 5940000, + .pll_od1 = 1, + .pll_od2 = 1, + .pll_od3 = 2, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, +}; + +static inline unsigned int pll_od_to_reg(unsigned int od) +{ + switch (od) { + case 1: + return 0; + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + } + + /* Invalid */ + return 0; +} + +void meson_hdmi_pll_set(struct meson_drm *priv, + unsigned int base, + unsigned int od1, + unsigned int od2, + unsigned int od3) +{ + unsigned int val; + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + switch (base) { + case 2970000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* Enable and unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 0x7 << 28, 0x4 << 28); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + + /* div_frac */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4e00); + break; + + case 4320000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + break; + + case 5940000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b); + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0xFFFF, 0x4c00); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + + /* unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + BIT(28), 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); + break; + }; + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + switch (base) { + case 2970000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + case 4320000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + case 5940000: + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); + break; + + }; + + /* Reset PLL */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + HDMI_PLL_RESET, HDMI_PLL_RESET); + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + HDMI_PLL_RESET, 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + (val & HDMI_PLL_LOCK), 10, 0); + }; + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 16, pll_od_to_reg(od1) << 16); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 21, pll_od_to_reg(od1) << 21); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 22, pll_od_to_reg(od2) << 22); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 23, pll_od_to_reg(od2) << 23); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 18, pll_od_to_reg(od3) << 18); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 19, pll_od_to_reg(od3) << 19); +} + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - unsigned int freq) + unsigned int vclk_freq, unsigned int venc_freq, + unsigned int dac_freq, bool hdmi_use_enci) { - if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS) + unsigned int freq; + unsigned int hdmi_tx_div; + unsigned int venc_div; + + if (target == MESON_VCLK_TARGET_CVBS) { meson_venci_cvbs_clock_config(priv); + return; + } + + hdmi_tx_div = vclk_freq / dac_freq; + + if (hdmi_tx_div == 0) { + pr_err("Fatal Error, invalid HDMI-TX freq %d\n", + dac_freq); + return; + } + + venc_div = vclk_freq / venc_freq; + + if (venc_div == 0) { + pr_err("Fatal Error, invalid HDMI venc freq %d\n", + venc_freq); + return; + } + + switch (vclk_freq) { + case 54000: + if (hdmi_use_enci) + freq = MESON_VCLK_HDMI_ENCI_54000; + else + freq = MESON_VCLK_HDMI_DDR_54000; + break; + case 74250: + freq = MESON_VCLK_HDMI_74250; + break; + case 148500: + if (dac_freq != 148500) + freq = MESON_VCLK_HDMI_DDR_148500; + else + freq = MESON_VCLK_HDMI_148500; + break; + case 297000: + freq = MESON_VCLK_HDMI_297000; + break; + case 594000: + freq = MESON_VCLK_HDMI_594000; + break; + default: + pr_err("Fatal Error, invalid HDMI vclk freq %d\n", + vclk_freq); + return; + } + + /* Set HDMI-TX sys clock */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + CTS_HDMI_SYS_SEL_MASK, 0); + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + CTS_HDMI_SYS_DIV_MASK, 0); + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); + + /* Set HDMI PLL rate */ + meson_hdmi_pll_set(priv, params[freq].pll_base_freq, + params[freq].pll_od1, + params[freq].pll_od2, + params[freq].pll_od3); + + /* Setup vid_pll divider */ + meson_vid_pll_set(priv, params[freq].vid_pll_div); + + /* Set VCLK div */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_SEL_MASK, 0); + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + VCLK_DIV_MASK, params[freq].vclk_div - 1); + + /* Set HDMI-TX source */ + switch (hdmi_tx_div) { + case 1: + /* enable vclk_div1 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV1_EN, VCLK_DIV1_EN); + + /* select vclk_div1 for HDMI-TX */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + HDMI_TX_PIXEL_SEL_MASK, 0); + break; + case 2: + /* enable vclk_div2 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV2_EN, VCLK_DIV2_EN); + + /* select vclk_div2 for HDMI-TX */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT); + break; + case 4: + /* enable vclk_div4 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV4_EN, VCLK_DIV4_EN); + + /* select vclk_div4 for HDMI-TX */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT); + break; + case 6: + /* enable vclk_div6 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV6_EN, VCLK_DIV6_EN); + + /* select vclk_div6 for HDMI-TX */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT); + break; + case 12: + /* enable vclk_div12 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV12_EN, VCLK_DIV12_EN); + + /* select vclk_div12 for HDMI-TX */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT); + break; + } + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, + HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN); + + /* Set ENCI/ENCP Source */ + switch (venc_div) { + case 1: + /* enable vclk_div1 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV1_EN, VCLK_DIV1_EN); + + if (hdmi_use_enci) + /* select vclk_div1 for enci */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCI_SEL_MASK, 0); + else + /* select vclk_div1 for encp */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCP_SEL_MASK, 0); + break; + case 2: + /* enable vclk_div2 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV2_EN, VCLK_DIV2_EN); + + if (hdmi_use_enci) + /* select vclk_div2 for enci */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT); + else + /* select vclk_div2 for encp */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT); + break; + case 4: + /* enable vclk_div4 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV4_EN, VCLK_DIV4_EN); + + if (hdmi_use_enci) + /* select vclk_div4 for enci */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT); + else + /* select vclk_div4 for encp */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT); + break; + case 6: + /* enable vclk_div6 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV6_EN, VCLK_DIV6_EN); + + if (hdmi_use_enci) + /* select vclk_div6 for enci */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT); + else + /* select vclk_div6 for encp */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT); + break; + case 12: + /* enable vclk_div12 gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_DIV12_EN, VCLK_DIV12_EN); + + if (hdmi_use_enci) + /* select vclk_div12 for enci */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT); + else + /* select vclk_div12 for encp */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, + CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT); + break; + } + + if (hdmi_use_enci) + /* Enable ENCI clock gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, + CTS_ENCI_EN, CTS_ENCI_EN); + else + /* Enable ENCP clock gate */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, + CTS_ENCP_EN, CTS_ENCP_EN); + + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); } +EXPORT_SYMBOL_GPL(meson_vclk_setup); diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index ec62735..0401b52 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -23,12 +23,14 @@ enum { MESON_VCLK_TARGET_CVBS = 0, + MESON_VCLK_TARGET_HDMI = 1, }; /* 27MHz is the CVBS Pixel Clock */ -#define MESON_VCLK_CVBS 27000 +#define MESON_VCLK_CVBS 27000 void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - unsigned int freq); + unsigned int vclk_freq, unsigned int venc_freq, + unsigned int dac_freq, bool hdmi_use_enci); #endif /* __MESON_VCLK_H */ diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index a96fcb4..5d4f19a 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -32,6 +32,7 @@ #include "meson_venc_cvbs.h" #include "meson_venc.h" +#include "meson_vclk.h" #include "meson_registers.h" /* HHI VDAC Registers */ @@ -194,14 +195,20 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, { struct meson_venc_cvbs *meson_venc_cvbs = encoder_to_meson_venc_cvbs(encoder); + struct meson_drm *priv = meson_venc_cvbs->priv; int i; for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; if (drm_mode_equal(mode, &meson_mode->mode)) { - meson_venci_cvbs_mode_set(meson_venc_cvbs->priv, + meson_venci_cvbs_mode_set(priv, meson_mode->enci); + + /* Setup 27MHz vclk2 for ENCI and VDAC */ + meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, + MESON_VCLK_CVBS, MESON_VCLK_CVBS, + MESON_VCLK_CVBS, true); break; } } -- cgit v1.1 From 335e3713afb87b72c3e4740e5775355648806b32 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:26 +0200 Subject: drm/meson: Add support for HDMI venc modes and settings This patch adds support for the supported HDMI Venc modes and add the VPP mux value to switch to ENCP encoder. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_venc.c | 1245 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/meson/meson_venc.h | 7 + drivers/gpu/drm/meson/meson_vpp.h | 2 + 3 files changed, 1249 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index f7c87017..31dc275 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -30,12 +30,37 @@ * VENC Handle the pixels encoding to the output formats. * We handle the following encodings : * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter - * - * What is missing : * - TMDS/HDMI Encoding via ENCI_DIV and ENCP * - Setup of more clock rates for HDMI modes + * + * What is missing : * - LCD Panel encoding via ENCL * - TV Panel encoding via ENCT + * + * VENC paths : + * _____ _____ ____________________ + * vd1---| |-| | | VENC /---------|----VDAC + * vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\ + * osd1--| |-| | | \ | X--HDMI-TX + * osd2--|_____|-|_____| | |\-ENCP--ENCP_DVI-|/ + * | | | + * | \--ENCL-----------|----LVDS + * |____________________| + * + * The ENCI is designed for PAl or NTSC encoding and can go through the VDAC + * directly for CVBS encoding or through the ENCI_DVI encoder for HDMI. + * The ENCP is designed for Progressive encoding but can also generate + * 1080i interlaced pixels, and was initialy desined to encode pixels for + * VDAC to output RGB ou YUV analog outputs. + * It's output is only used through the ENCP_DVI encoder for HDMI. + * The ENCL LVDS encoder is not implemented. + * + * The ENCI and ENCP encoders needs specially defined parameters for each + * supported mode and thus cannot be determined from standard video timings. + * + * The ENCI end ENCP DVI encoders are more generic and can generate any timings + * from the pixel data generated by ENCI or ENCP, so can use the standard video + * timings are source for HW parameters. */ /* HHI Registers */ @@ -91,6 +116,1219 @@ struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc = { .analog_sync_adj = 0x9c00, }; +union meson_hdmi_venc_mode { + struct { + unsigned int mode_tag; + unsigned int hso_begin; + unsigned int hso_end; + unsigned int vso_even; + unsigned int vso_odd; + unsigned int macv_max_amp; + unsigned int video_prog_mode; + unsigned int video_mode; + unsigned int sch_adjust; + unsigned int yc_delay; + unsigned int pixel_start; + unsigned int pixel_end; + unsigned int top_field_line_start; + unsigned int top_field_line_end; + unsigned int bottom_field_line_start; + unsigned int bottom_field_line_end; + } enci; + struct { + unsigned int dvi_settings; + unsigned int video_mode; + unsigned int video_mode_adv; + unsigned int video_prog_mode; + bool video_prog_mode_present; + unsigned int video_sync_mode; + bool video_sync_mode_present; + unsigned int video_yc_dly; + bool video_yc_dly_present; + unsigned int video_rgb_ctrl; + bool video_rgb_ctrl_present; + unsigned int video_filt_ctrl; + bool video_filt_ctrl_present; + unsigned int video_ofld_voav_ofst; + bool video_ofld_voav_ofst_present; + unsigned int yfp1_htime; + unsigned int yfp2_htime; + unsigned int max_pxcnt; + unsigned int hspuls_begin; + unsigned int hspuls_end; + unsigned int hspuls_switch; + unsigned int vspuls_begin; + unsigned int vspuls_end; + unsigned int vspuls_bline; + unsigned int vspuls_eline; + unsigned int eqpuls_begin; + bool eqpuls_begin_present; + unsigned int eqpuls_end; + bool eqpuls_end_present; + unsigned int eqpuls_bline; + bool eqpuls_bline_present; + unsigned int eqpuls_eline; + bool eqpuls_eline_present; + unsigned int havon_begin; + unsigned int havon_end; + unsigned int vavon_bline; + unsigned int vavon_eline; + unsigned int hso_begin; + unsigned int hso_end; + unsigned int vso_begin; + unsigned int vso_end; + unsigned int vso_bline; + unsigned int vso_eline; + bool vso_eline_present; + unsigned int sy_val; + bool sy_val_present; + unsigned int sy2_val; + bool sy2_val_present; + unsigned int max_lncnt; + } encp; +}; + +union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { + .enci = { + .hso_begin = 5, + .hso_end = 129, + .vso_even = 3, + .vso_odd = 260, + .macv_max_amp = 0x810b, + .video_prog_mode = 0xf0, + .video_mode = 0x8, + .sch_adjust = 0x20, + .yc_delay = 0, + .pixel_start = 227, + .pixel_end = 1667, + .top_field_line_start = 18, + .top_field_line_end = 258, + .bottom_field_line_start = 19, + .bottom_field_line_end = 259, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { + .enci = { + .hso_begin = 3, + .hso_end = 129, + .vso_even = 3, + .vso_odd = 260, + .macv_max_amp = 8107, + .video_prog_mode = 0xff, + .video_mode = 0x13, + .sch_adjust = 0x28, + .yc_delay = 0x333, + .pixel_start = 251, + .pixel_end = 1691, + .top_field_line_start = 22, + .top_field_line_end = 310, + .bottom_field_line_start = 23, + .bottom_field_line_end = 311, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4000, + .video_mode_adv = 0x9, + .video_prog_mode = 0, + .video_prog_mode_present = true, + .video_sync_mode = 7, + .video_sync_mode_present = true, + /* video_yc_dly */ + /* video_rgb_ctrl */ + .video_filt_ctrl = 0x2052, + .video_filt_ctrl_present = true, + /* video_ofld_voav_ofst */ + .yfp1_htime = 244, + .yfp2_htime = 1630, + .max_pxcnt = 1715, + .hspuls_begin = 0x22, + .hspuls_end = 0xa0, + .hspuls_switch = 88, + .vspuls_begin = 0, + .vspuls_end = 1589, + .vspuls_bline = 0, + .vspuls_eline = 5, + .havon_begin = 249, + .havon_end = 1689, + .vavon_bline = 42, + .vavon_eline = 521, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 3, + .hso_end = 5, + .vso_begin = 3, + .vso_end = 5, + .vso_bline = 0, + /* vso_eline */ + .sy_val = 8, + .sy_val_present = true, + .sy2_val = 0x1d8, + .sy2_val_present = true, + .max_lncnt = 524, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = { + .encp = { + .dvi_settings = 0x21, + .video_mode = 0x4000, + .video_mode_adv = 0x9, + .video_prog_mode = 0, + .video_prog_mode_present = true, + .video_sync_mode = 7, + .video_sync_mode_present = true, + /* video_yc_dly */ + /* video_rgb_ctrl */ + .video_filt_ctrl = 0x52, + .video_filt_ctrl_present = true, + /* video_ofld_voav_ofst */ + .yfp1_htime = 235, + .yfp2_htime = 1674, + .max_pxcnt = 1727, + .hspuls_begin = 0, + .hspuls_end = 0x80, + .hspuls_switch = 88, + .vspuls_begin = 0, + .vspuls_end = 1599, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 235, + .havon_end = 1674, + .vavon_bline = 44, + .vavon_eline = 619, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 0x80, + .hso_end = 0, + .vso_begin = 0, + .vso_end = 5, + .vso_bline = 0, + /* vso_eline */ + .sy_val = 8, + .sy_val_present = true, + .sy2_val = 0x1d8, + .sy2_val_present = true, + .max_lncnt = 624, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = { + .encp = { + .dvi_settings = 0x2029, + .video_mode = 0x4040, + .video_mode_adv = 0x19, + /* video_prog_mode */ + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + .yfp1_htime = 648, + .yfp2_htime = 3207, + .max_pxcnt = 3299, + .hspuls_begin = 80, + .hspuls_end = 240, + .hspuls_switch = 80, + .vspuls_begin = 688, + .vspuls_end = 3248, + .vspuls_bline = 4, + .vspuls_eline = 8, + .havon_begin = 648, + .havon_end = 3207, + .vavon_bline = 29, + .vavon_eline = 748, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 256, + .hso_end = 168, + .vso_begin = 168, + .vso_end = 256, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 749, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = { + .encp = { + .dvi_settings = 0x202d, + .video_mode = 0x4040, + .video_mode_adv = 0x19, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + .video_sync_mode = 0x407, + .video_sync_mode_present = true, + .video_yc_dly = 0, + .video_yc_dly_present = true, + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + .yfp1_htime = 648, + .yfp2_htime = 3207, + .max_pxcnt = 3959, + .hspuls_begin = 80, + .hspuls_end = 240, + .hspuls_switch = 80, + .vspuls_begin = 688, + .vspuls_end = 3248, + .vspuls_bline = 4, + .vspuls_eline = 8, + .havon_begin = 648, + .havon_end = 3207, + .vavon_bline = 29, + .vavon_eline = 748, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 128, + .hso_end = 208, + .vso_begin = 128, + .vso_end = 128, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 749, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = { + .encp = { + .dvi_settings = 0x2029, + .video_mode = 0x5ffc, + .video_mode_adv = 0x19, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + .video_sync_mode = 0x207, + .video_sync_mode_present = true, + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + .video_ofld_voav_ofst = 0x11, + .video_ofld_voav_ofst_present = true, + .yfp1_htime = 516, + .yfp2_htime = 4355, + .max_pxcnt = 4399, + .hspuls_begin = 88, + .hspuls_end = 264, + .hspuls_switch = 88, + .vspuls_begin = 440, + .vspuls_end = 2200, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 516, + .havon_end = 4355, + .vavon_bline = 20, + .vavon_eline = 559, + .eqpuls_begin = 2288, + .eqpuls_begin_present = true, + .eqpuls_end = 2464, + .eqpuls_end_present = true, + .eqpuls_bline = 0, + .eqpuls_bline_present = true, + .eqpuls_eline = 4, + .eqpuls_eline_present = true, + .hso_begin = 264, + .hso_end = 176, + .vso_begin = 88, + .vso_end = 88, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = { + .encp = { + .dvi_settings = 0x202d, + .video_mode = 0x5ffc, + .video_mode_adv = 0x19, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + .video_sync_mode = 0x7, + .video_sync_mode_present = true, + /* video_yc_dly */ + /* video_rgb_ctrl */ + /* video_filt_ctrl */ + .video_ofld_voav_ofst = 0x11, + .video_ofld_voav_ofst_present = true, + .yfp1_htime = 526, + .yfp2_htime = 4365, + .max_pxcnt = 5279, + .hspuls_begin = 88, + .hspuls_end = 264, + .hspuls_switch = 88, + .vspuls_begin = 440, + .vspuls_end = 2200, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 526, + .havon_end = 4365, + .vavon_bline = 20, + .vavon_eline = 559, + .eqpuls_begin = 2288, + .eqpuls_begin_present = true, + .eqpuls_end = 2464, + .eqpuls_end_present = true, + .eqpuls_bline = 0, + .eqpuls_bline_present = true, + .eqpuls_eline = 4, + .eqpuls_eline_present = true, + .hso_begin = 142, + .hso_end = 230, + .vso_begin = 142, + .vso_end = 142, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = { + .encp = { + .dvi_settings = 0xd, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + .video_sync_mode = 0x7, + .video_sync_mode_present = true, + .video_yc_dly = 0, + .video_yc_dly_present = true, + .video_rgb_ctrl = 2, + .video_rgb_ctrl_present = true, + .video_filt_ctrl = 0x1052, + .video_filt_ctrl_present = true, + /* video_ofld_voav_ofst */ + .yfp1_htime = 271, + .yfp2_htime = 2190, + .max_pxcnt = 2749, + .hspuls_begin = 44, + .hspuls_end = 132, + .hspuls_switch = 44, + .vspuls_begin = 220, + .vspuls_end = 2140, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 271, + .havon_end = 2190, + .vavon_bline = 41, + .vavon_eline = 1120, + /* eqpuls_begin */ + /* eqpuls_end */ + .eqpuls_bline = 0, + .eqpuls_bline_present = true, + .eqpuls_eline = 4, + .eqpuls_eline_present = true, + .hso_begin = 79, + .hso_end = 123, + .vso_begin = 79, + .vso_end = 79, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = { + .encp = { + .dvi_settings = 0x1, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + .video_filt_ctrl = 0x1052, + .video_filt_ctrl_present = true, + /* video_ofld_voav_ofst */ + .yfp1_htime = 140, + .yfp2_htime = 2060, + .max_pxcnt = 2199, + .hspuls_begin = 2156, + .hspuls_end = 44, + .hspuls_switch = 44, + .vspuls_begin = 140, + .vspuls_end = 2059, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 148, + .havon_end = 2067, + .vavon_bline = 41, + .vavon_eline = 1120, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 44, + .hso_end = 2156, + .vso_begin = 2100, + .vso_end = 2164, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = { + .encp = { + .dvi_settings = 0xd, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + .video_sync_mode = 0x7, + .video_sync_mode_present = true, + .video_yc_dly = 0, + .video_yc_dly_present = true, + .video_rgb_ctrl = 2, + .video_rgb_ctrl_present = true, + /* video_filt_ctrl */ + /* video_ofld_voav_ofst */ + .yfp1_htime = 271, + .yfp2_htime = 2190, + .max_pxcnt = 2639, + .hspuls_begin = 44, + .hspuls_end = 132, + .hspuls_switch = 44, + .vspuls_begin = 220, + .vspuls_end = 2140, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 271, + .havon_end = 2190, + .vavon_bline = 41, + .vavon_eline = 1120, + /* eqpuls_begin */ + /* eqpuls_end */ + .eqpuls_bline = 0, + .eqpuls_bline_present = true, + .eqpuls_eline = 4, + .eqpuls_eline_present = true, + .hso_begin = 79, + .hso_end = 123, + .vso_begin = 79, + .vso_end = 79, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { + .encp = { + .dvi_settings = 0x1, + .video_mode = 0x4040, + .video_mode_adv = 0x18, + .video_prog_mode = 0x100, + .video_prog_mode_present = true, + /* video_sync_mode */ + /* video_yc_dly */ + /* video_rgb_ctrl */ + .video_filt_ctrl = 0x1052, + .video_filt_ctrl_present = true, + /* video_ofld_voav_ofst */ + .yfp1_htime = 140, + .yfp2_htime = 2060, + .max_pxcnt = 2199, + .hspuls_begin = 2156, + .hspuls_end = 44, + .hspuls_switch = 44, + .vspuls_begin = 140, + .vspuls_end = 2059, + .vspuls_bline = 0, + .vspuls_eline = 4, + .havon_begin = 148, + .havon_end = 2067, + .vavon_bline = 41, + .vavon_eline = 1120, + /* eqpuls_begin */ + /* eqpuls_end */ + /* eqpuls_bline */ + /* eqpuls_eline */ + .hso_begin = 44, + .hso_end = 2156, + .vso_begin = 2100, + .vso_end = 2164, + .vso_bline = 0, + .vso_eline = 5, + .vso_eline_present = true, + /* sy_val */ + /* sy2_val */ + .max_lncnt = 1124, + }, +}; + +struct meson_hdmi_venc_vic_mode { + unsigned int vic; + union meson_hdmi_venc_mode *mode; +} meson_hdmi_venc_vic_modes[] = { + { 6, &meson_hdmi_enci_mode_480i }, + { 7, &meson_hdmi_enci_mode_480i }, + { 21, &meson_hdmi_enci_mode_576i }, + { 22, &meson_hdmi_enci_mode_576i }, + { 2, &meson_hdmi_encp_mode_480p }, + { 3, &meson_hdmi_encp_mode_480p }, + { 17, &meson_hdmi_encp_mode_576p }, + { 18, &meson_hdmi_encp_mode_576p }, + { 4, &meson_hdmi_encp_mode_720p60 }, + { 19, &meson_hdmi_encp_mode_720p50 }, + { 5, &meson_hdmi_encp_mode_1080i60 }, + { 20, &meson_hdmi_encp_mode_1080i50 }, + { 32, &meson_hdmi_encp_mode_1080p24 }, + { 34, &meson_hdmi_encp_mode_1080p30 }, + { 31, &meson_hdmi_encp_mode_1080p50 }, + { 16, &meson_hdmi_encp_mode_1080p60 }, + { 0, NULL}, /* sentinel */ +}; + +static signed int to_signed(unsigned int a) +{ + if (a <= 7) + return a; + else + return a - 16; +} + +static unsigned long modulo(unsigned long a, unsigned long b) +{ + if (a >= b) + return a - b; + else + return a; +} + +bool meson_venc_hdmi_supported_vic(int vic) +{ + struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; + + while (vmode->vic && vmode->mode) { + if (vmode->vic == vic) + return true; + vmode++; + } + + return false; +} +EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); + +static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) +{ + struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; + + while (vmode->vic && vmode->mode) { + if (vmode->vic == vic) + return vmode->mode; + vmode++; + } + + return NULL; +} + +bool meson_venc_hdmi_venc_repeat(int vic) +{ + /* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */ + if (vic == 6 || vic == 7 || /* 480i */ + vic == 21 || vic == 22 || /* 576i */ + vic == 17 || vic == 18 || /* 576p */ + vic == 2 || vic == 3 || /* 480p */ + vic == 4 || /* 720p60 */ + vic == 19 || /* 720p50 */ + vic == 5 || /* 1080i60 */ + vic == 20) /* 1080i50 */ + return true; + + return false; +} +EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat); + +void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + struct drm_display_mode *mode) +{ + union meson_hdmi_venc_mode *vmode = NULL; + bool use_enci = false; + bool venc_repeat = false; + bool hdmi_repeat = false; + unsigned int venc_hdmi_latency = 2; + unsigned long total_pixels_venc = 0; + unsigned long active_pixels_venc = 0; + unsigned long front_porch_venc = 0; + unsigned long hsync_pixels_venc = 0; + unsigned long de_h_begin = 0; + unsigned long de_h_end = 0; + unsigned long de_v_begin_even = 0; + unsigned long de_v_end_even = 0; + unsigned long de_v_begin_odd = 0; + unsigned long de_v_end_odd = 0; + unsigned long hs_begin = 0; + unsigned long hs_end = 0; + unsigned long vs_adjust = 0; + unsigned long vs_bline_evn = 0; + unsigned long vs_eline_evn = 0; + unsigned long vs_bline_odd = 0; + unsigned long vs_eline_odd = 0; + unsigned long vso_begin_evn = 0; + unsigned long vso_begin_odd = 0; + unsigned int eof_lines; + unsigned int sof_lines; + unsigned int vsync_lines; + + vmode = meson_venc_hdmi_get_vic_vmode(vic); + if (!vmode) { + dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n", + __func__, vic); + return; + } + + /* Use VENCI for 480i and 576i and double HDMI pixels */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { + hdmi_repeat = true; + use_enci = true; + venc_hdmi_latency = 1; + } + + /* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */ + if (meson_venc_hdmi_venc_repeat(vic)) + venc_repeat = true; + + eof_lines = mode->vsync_start - mode->vdisplay; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + eof_lines /= 2; + sof_lines = mode->vtotal - mode->vsync_end; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + sof_lines /= 2; + vsync_lines = mode->vsync_end - mode->vsync_start; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vsync_lines /= 2; + + total_pixels_venc = mode->htotal; + if (hdmi_repeat) + total_pixels_venc /= 2; + if (venc_repeat) + total_pixels_venc *= 2; + + active_pixels_venc = mode->hdisplay; + if (hdmi_repeat) + active_pixels_venc /= 2; + if (venc_repeat) + active_pixels_venc *= 2; + + front_porch_venc = (mode->hsync_start - mode->hdisplay); + if (hdmi_repeat) + front_porch_venc /= 2; + if (venc_repeat) + front_porch_venc *= 2; + + hsync_pixels_venc = (mode->hsync_end - mode->hsync_start); + if (hdmi_repeat) + hsync_pixels_venc /= 2; + if (venc_repeat) + hsync_pixels_venc *= 2; + + /* Disable VDACs */ + writel_bits_relaxed(0x1f, 0x1f, + priv->io_base + _REG(VENC_VDAC_SETTING)); + + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); + + if (use_enci) { + unsigned int lines_f0; + unsigned int lines_f1; + + /* CVBS Filter settings */ + writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); + writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); + + /* Digital Video Select : Interlace, clk27 clk, external */ + writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); + + /* Reset Video Mode */ + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE)); + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + + /* Horizontal sync signal output */ + writel_relaxed(vmode->enci.hso_begin, + priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN)); + writel_relaxed(vmode->enci.hso_end, + priv->io_base + _REG(ENCI_SYNC_HSO_END)); + + /* Vertical Sync lines */ + writel_relaxed(vmode->enci.vso_even, + priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN)); + writel_relaxed(vmode->enci.vso_odd, + priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); + + /* Macrovision max amplitude change */ + writel_relaxed(vmode->enci.macv_max_amp, + priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + + /* Video mode */ + writel_relaxed(vmode->enci.video_prog_mode, + priv->io_base + _REG(VENC_VIDEO_PROG_MODE)); + writel_relaxed(vmode->enci.video_mode, + priv->io_base + _REG(ENCI_VIDEO_MODE)); + + /* Advanced Video Mode : + * Demux shifting 0x2 + * Blank line end at line17/22 + * High bandwidth Luma Filter + * Low bandwidth Chroma Filter + * Bypass luma low pass filter + * No macrovision on CSYNC + */ + writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + + writel(vmode->enci.sch_adjust, + priv->io_base + _REG(ENCI_VIDEO_SCH)); + + /* Sync mode : MASTER Master mode, free run, send HSO/VSO out */ + writel_relaxed(0x07, priv->io_base + _REG(ENCI_SYNC_MODE)); + + if (vmode->enci.yc_delay) + writel_relaxed(vmode->enci.yc_delay, + priv->io_base + _REG(ENCI_YC_DELAY)); + + + /* UNreset Interlaced TV Encoder */ + writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); + + /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ + writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + + /* Timings */ + writel_relaxed(vmode->enci.pixel_start, + priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START)); + writel_relaxed(vmode->enci.pixel_end, + priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END)); + + writel_relaxed(vmode->enci.top_field_line_start, + priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START)); + writel_relaxed(vmode->enci.top_field_line_end, + priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END)); + + writel_relaxed(vmode->enci.bottom_field_line_start, + priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START)); + writel_relaxed(vmode->enci.bottom_field_line_end, + priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END)); + + /* Select ENCI for VIU */ + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); + + /* Interlace video enable */ + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + + lines_f0 = mode->vtotal >> 1; + lines_f1 = lines_f0 + 1; + + de_h_begin = modulo(readl_relaxed(priv->io_base + + _REG(ENCI_VFIFO2VD_PIXEL_START)) + + venc_hdmi_latency, + total_pixels_venc); + de_h_end = modulo(de_h_begin + active_pixels_venc, + total_pixels_venc); + + writel_relaxed(de_h_begin, + priv->io_base + _REG(ENCI_DE_H_BEGIN)); + writel_relaxed(de_h_end, + priv->io_base + _REG(ENCI_DE_H_END)); + + de_v_begin_even = readl_relaxed(priv->io_base + + _REG(ENCI_VFIFO2VD_LINE_TOP_START)); + de_v_end_even = de_v_begin_even + mode->vdisplay; + de_v_begin_odd = readl_relaxed(priv->io_base + + _REG(ENCI_VFIFO2VD_LINE_BOT_START)); + de_v_end_odd = de_v_begin_odd + mode->vdisplay; + + writel_relaxed(de_v_begin_even, + priv->io_base + _REG(ENCI_DE_V_BEGIN_EVEN)); + writel_relaxed(de_v_end_even, + priv->io_base + _REG(ENCI_DE_V_END_EVEN)); + writel_relaxed(de_v_begin_odd, + priv->io_base + _REG(ENCI_DE_V_BEGIN_ODD)); + writel_relaxed(de_v_end_odd, + priv->io_base + _REG(ENCI_DE_V_END_ODD)); + + /* Program Hsync timing */ + hs_begin = de_h_end + front_porch_venc; + if (de_h_end + front_porch_venc >= total_pixels_venc) { + hs_begin -= total_pixels_venc; + vs_adjust = 1; + } else { + hs_begin = de_h_end + front_porch_venc; + vs_adjust = 0; + } + + hs_end = modulo(hs_begin + hsync_pixels_venc, + total_pixels_venc); + writel_relaxed(hs_begin, + priv->io_base + _REG(ENCI_DVI_HSO_BEGIN)); + writel_relaxed(hs_end, + priv->io_base + _REG(ENCI_DVI_HSO_END)); + + /* Program Vsync timing for even field */ + if (((de_v_end_odd - 1) + eof_lines + vs_adjust) >= lines_f1) { + vs_bline_evn = (de_v_end_odd - 1) + + eof_lines + + vs_adjust + - lines_f1; + vs_eline_evn = vs_bline_evn + vsync_lines; + + writel_relaxed(vs_bline_evn, + priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN)); + + writel_relaxed(vs_eline_evn, + priv->io_base + _REG(ENCI_DVI_VSO_ELINE_EVN)); + + writel_relaxed(hs_begin, + priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_EVN)); + writel_relaxed(hs_begin, + priv->io_base + _REG(ENCI_DVI_VSO_END_EVN)); + } else { + vs_bline_odd = (de_v_end_odd - 1) + + eof_lines + + vs_adjust; + + writel_relaxed(vs_bline_odd, + priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD)); + + writel_relaxed(hs_begin, + priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD)); + + if ((vs_bline_odd + vsync_lines) >= lines_f1) { + vs_eline_evn = vs_bline_odd + + vsync_lines + - lines_f1; + + writel_relaxed(vs_eline_evn, priv->io_base + + _REG(ENCI_DVI_VSO_ELINE_EVN)); + + writel_relaxed(hs_begin, priv->io_base + + _REG(ENCI_DVI_VSO_END_EVN)); + } else { + vs_eline_odd = vs_bline_odd + + vsync_lines; + + writel_relaxed(vs_eline_odd, priv->io_base + + _REG(ENCI_DVI_VSO_ELINE_ODD)); + + writel_relaxed(hs_begin, priv->io_base + + _REG(ENCI_DVI_VSO_END_ODD)); + } + } + + /* Program Vsync timing for odd field */ + if (((de_v_end_even - 1) + (eof_lines + 1)) >= lines_f0) { + vs_bline_odd = (de_v_end_even - 1) + + (eof_lines + 1) + - lines_f0; + vs_eline_odd = vs_bline_odd + vsync_lines; + + writel_relaxed(vs_bline_odd, + priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD)); + + writel_relaxed(vs_eline_odd, + priv->io_base + _REG(ENCI_DVI_VSO_ELINE_ODD)); + + vso_begin_odd = modulo(hs_begin + + (total_pixels_venc >> 1), + total_pixels_venc); + + writel_relaxed(vso_begin_odd, + priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD)); + writel_relaxed(vso_begin_odd, + priv->io_base + _REG(ENCI_DVI_VSO_END_ODD)); + } else { + vs_bline_evn = (de_v_end_even - 1) + + (eof_lines + 1); + + writel_relaxed(vs_bline_evn, + priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN)); + + vso_begin_evn = modulo(hs_begin + + (total_pixels_venc >> 1), + total_pixels_venc); + + writel_relaxed(vso_begin_evn, priv->io_base + + _REG(ENCI_DVI_VSO_BEGIN_EVN)); + + if (vs_bline_evn + vsync_lines >= lines_f0) { + vs_eline_odd = vs_bline_evn + + vsync_lines + - lines_f0; + + writel_relaxed(vs_eline_odd, priv->io_base + + _REG(ENCI_DVI_VSO_ELINE_ODD)); + + writel_relaxed(vso_begin_evn, priv->io_base + + _REG(ENCI_DVI_VSO_END_ODD)); + } else { + vs_eline_evn = vs_bline_evn + vsync_lines; + + writel_relaxed(vs_eline_evn, priv->io_base + + _REG(ENCI_DVI_VSO_ELINE_EVN)); + + writel_relaxed(vso_begin_evn, priv->io_base + + _REG(ENCI_DVI_VSO_END_EVN)); + } + } + } else { + writel_relaxed(vmode->encp.dvi_settings, + priv->io_base + _REG(VENC_DVI_SETTING)); + writel_relaxed(vmode->encp.video_mode, + priv->io_base + _REG(ENCP_VIDEO_MODE)); + writel_relaxed(vmode->encp.video_mode_adv, + priv->io_base + _REG(ENCP_VIDEO_MODE_ADV)); + if (vmode->encp.video_prog_mode_present) + writel_relaxed(vmode->encp.video_prog_mode, + priv->io_base + _REG(VENC_VIDEO_PROG_MODE)); + if (vmode->encp.video_sync_mode_present) + writel_relaxed(vmode->encp.video_sync_mode, + priv->io_base + _REG(ENCP_VIDEO_SYNC_MODE)); + if (vmode->encp.video_yc_dly_present) + writel_relaxed(vmode->encp.video_yc_dly, + priv->io_base + _REG(ENCP_VIDEO_YC_DLY)); + if (vmode->encp.video_rgb_ctrl_present) + writel_relaxed(vmode->encp.video_rgb_ctrl, + priv->io_base + _REG(ENCP_VIDEO_RGB_CTRL)); + if (vmode->encp.video_filt_ctrl_present) + writel_relaxed(vmode->encp.video_filt_ctrl, + priv->io_base + _REG(ENCP_VIDEO_FILT_CTRL)); + if (vmode->encp.video_ofld_voav_ofst_present) + writel_relaxed(vmode->encp.video_ofld_voav_ofst, + priv->io_base + + _REG(ENCP_VIDEO_OFLD_VOAV_OFST)); + writel_relaxed(vmode->encp.yfp1_htime, + priv->io_base + _REG(ENCP_VIDEO_YFP1_HTIME)); + writel_relaxed(vmode->encp.yfp2_htime, + priv->io_base + _REG(ENCP_VIDEO_YFP2_HTIME)); + writel_relaxed(vmode->encp.max_pxcnt, + priv->io_base + _REG(ENCP_VIDEO_MAX_PXCNT)); + writel_relaxed(vmode->encp.hspuls_begin, + priv->io_base + _REG(ENCP_VIDEO_HSPULS_BEGIN)); + writel_relaxed(vmode->encp.hspuls_end, + priv->io_base + _REG(ENCP_VIDEO_HSPULS_END)); + writel_relaxed(vmode->encp.hspuls_switch, + priv->io_base + _REG(ENCP_VIDEO_HSPULS_SWITCH)); + writel_relaxed(vmode->encp.vspuls_begin, + priv->io_base + _REG(ENCP_VIDEO_VSPULS_BEGIN)); + writel_relaxed(vmode->encp.vspuls_end, + priv->io_base + _REG(ENCP_VIDEO_VSPULS_END)); + writel_relaxed(vmode->encp.vspuls_bline, + priv->io_base + _REG(ENCP_VIDEO_VSPULS_BLINE)); + writel_relaxed(vmode->encp.vspuls_eline, + priv->io_base + _REG(ENCP_VIDEO_VSPULS_ELINE)); + if (vmode->encp.eqpuls_begin_present) + writel_relaxed(vmode->encp.eqpuls_begin, + priv->io_base + _REG(ENCP_VIDEO_EQPULS_BEGIN)); + if (vmode->encp.eqpuls_end_present) + writel_relaxed(vmode->encp.eqpuls_end, + priv->io_base + _REG(ENCP_VIDEO_EQPULS_END)); + if (vmode->encp.eqpuls_bline_present) + writel_relaxed(vmode->encp.eqpuls_bline, + priv->io_base + _REG(ENCP_VIDEO_EQPULS_BLINE)); + if (vmode->encp.eqpuls_eline_present) + writel_relaxed(vmode->encp.eqpuls_eline, + priv->io_base + _REG(ENCP_VIDEO_EQPULS_ELINE)); + writel_relaxed(vmode->encp.havon_begin, + priv->io_base + _REG(ENCP_VIDEO_HAVON_BEGIN)); + writel_relaxed(vmode->encp.havon_end, + priv->io_base + _REG(ENCP_VIDEO_HAVON_END)); + writel_relaxed(vmode->encp.vavon_bline, + priv->io_base + _REG(ENCP_VIDEO_VAVON_BLINE)); + writel_relaxed(vmode->encp.vavon_eline, + priv->io_base + _REG(ENCP_VIDEO_VAVON_ELINE)); + writel_relaxed(vmode->encp.hso_begin, + priv->io_base + _REG(ENCP_VIDEO_HSO_BEGIN)); + writel_relaxed(vmode->encp.hso_end, + priv->io_base + _REG(ENCP_VIDEO_HSO_END)); + writel_relaxed(vmode->encp.vso_begin, + priv->io_base + _REG(ENCP_VIDEO_VSO_BEGIN)); + writel_relaxed(vmode->encp.vso_end, + priv->io_base + _REG(ENCP_VIDEO_VSO_END)); + writel_relaxed(vmode->encp.vso_bline, + priv->io_base + _REG(ENCP_VIDEO_VSO_BLINE)); + if (vmode->encp.vso_eline_present) + writel_relaxed(vmode->encp.vso_eline, + priv->io_base + _REG(ENCP_VIDEO_VSO_ELINE)); + if (vmode->encp.sy_val_present) + writel_relaxed(vmode->encp.sy_val, + priv->io_base + _REG(ENCP_VIDEO_SY_VAL)); + if (vmode->encp.sy2_val_present) + writel_relaxed(vmode->encp.sy2_val, + priv->io_base + _REG(ENCP_VIDEO_SY2_VAL)); + writel_relaxed(vmode->encp.max_lncnt, + priv->io_base + _REG(ENCP_VIDEO_MAX_LNCNT)); + + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); + + /* Set DE signal’s polarity is active high */ + writel_bits_relaxed(BIT(14), BIT(14), + priv->io_base + _REG(ENCP_VIDEO_MODE)); + + /* Program DE timing */ + de_h_begin = modulo(readl_relaxed(priv->io_base + + _REG(ENCP_VIDEO_HAVON_BEGIN)) + + venc_hdmi_latency, + total_pixels_venc); + de_h_end = modulo(de_h_begin + active_pixels_venc, + total_pixels_venc); + + writel_relaxed(de_h_begin, + priv->io_base + _REG(ENCP_DE_H_BEGIN)); + writel_relaxed(de_h_end, + priv->io_base + _REG(ENCP_DE_H_END)); + + /* Program DE timing for even field */ + de_v_begin_even = readl_relaxed(priv->io_base + + _REG(ENCP_VIDEO_VAVON_BLINE)); + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + de_v_end_even = de_v_begin_even + + (mode->vdisplay / 2); + else + de_v_end_even = de_v_begin_even + mode->vdisplay; + + writel_relaxed(de_v_begin_even, + priv->io_base + _REG(ENCP_DE_V_BEGIN_EVEN)); + writel_relaxed(de_v_end_even, + priv->io_base + _REG(ENCP_DE_V_END_EVEN)); + + /* Program DE timing for odd field if needed */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + unsigned int ofld_voav_ofst = + readl_relaxed(priv->io_base + + _REG(ENCP_VIDEO_OFLD_VOAV_OFST)); + de_v_begin_odd = to_signed((ofld_voav_ofst & 0xf0) >> 4) + + de_v_begin_even + + ((mode->vtotal - 1) / 2); + de_v_end_odd = de_v_begin_odd + (mode->vdisplay / 2); + + writel_relaxed(de_v_begin_odd, + priv->io_base + _REG(ENCP_DE_V_BEGIN_ODD)); + writel_relaxed(de_v_end_odd, + priv->io_base + _REG(ENCP_DE_V_END_ODD)); + } + + /* Program Hsync timing */ + if ((de_h_end + front_porch_venc) >= total_pixels_venc) { + hs_begin = de_h_end + + front_porch_venc + - total_pixels_venc; + vs_adjust = 1; + } else { + hs_begin = de_h_end + + front_porch_venc; + vs_adjust = 0; + } + + hs_end = modulo(hs_begin + hsync_pixels_venc, + total_pixels_venc); + + writel_relaxed(hs_begin, + priv->io_base + _REG(ENCP_DVI_HSO_BEGIN)); + writel_relaxed(hs_end, + priv->io_base + _REG(ENCP_DVI_HSO_END)); + + /* Program Vsync timing for even field */ + if (de_v_begin_even >= + (sof_lines + vsync_lines + (1 - vs_adjust))) + vs_bline_evn = de_v_begin_even + - sof_lines + - vsync_lines + - (1 - vs_adjust); + else + vs_bline_evn = mode->vtotal + + de_v_begin_even + - sof_lines + - vsync_lines + - (1 - vs_adjust); + + vs_eline_evn = modulo(vs_bline_evn + vsync_lines, + mode->vtotal); + + writel_relaxed(vs_bline_evn, + priv->io_base + _REG(ENCP_DVI_VSO_BLINE_EVN)); + writel_relaxed(vs_eline_evn, + priv->io_base + _REG(ENCP_DVI_VSO_ELINE_EVN)); + + vso_begin_evn = hs_begin; + writel_relaxed(vso_begin_evn, + priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_EVN)); + writel_relaxed(vso_begin_evn, + priv->io_base + _REG(ENCP_DVI_VSO_END_EVN)); + + /* Program Vsync timing for odd field if needed */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + vs_bline_odd = (de_v_begin_odd - 1) + - sof_lines + - vsync_lines; + vs_eline_odd = (de_v_begin_odd - 1) + - vsync_lines; + vso_begin_odd = modulo(hs_begin + + (total_pixels_venc >> 1), + total_pixels_venc); + + writel_relaxed(vs_bline_odd, + priv->io_base + _REG(ENCP_DVI_VSO_BLINE_ODD)); + writel_relaxed(vs_eline_odd, + priv->io_base + _REG(ENCP_DVI_VSO_ELINE_ODD)); + writel_relaxed(vso_begin_odd, + priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_ODD)); + writel_relaxed(vso_begin_odd, + priv->io_base + _REG(ENCP_DVI_VSO_END_ODD)); + } + + /* Select ENCP for VIU */ + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP); + } + + writel_relaxed((use_enci ? 1 : 2) | + (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | + (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | + 4 << 5 | + (venc_repeat ? 1 << 8 : 0) | + (hdmi_repeat ? 1 << 12 : 0), + priv->io_base + _REG(VPU_HDMI_SETTING)); + + priv->venc.hdmi_repeat = hdmi_repeat; + priv->venc.venc_repeat = venc_repeat; + priv->venc.hdmi_use_enci = use_enci; + + priv->venc.current_mode = MESON_VENC_MODE_HDMI; +} +EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); + void meson_venci_cvbs_mode_set(struct meson_drm *priv, struct meson_cvbs_enci_mode *mode) { @@ -223,9 +1461,6 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, writel_relaxed(mode->analog_sync_adj, priv->io_base + _REG(ENCI_SYNC_ADJ)); - /* Setup 27MHz vclk2 for ENCI and VDAC */ - meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS); - priv->venc.current_mode = mode->mode_tag; } diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index 77d4a7d..a1b96e8 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -30,6 +30,7 @@ enum { MESON_VENC_MODE_NONE = 0, MESON_VENC_MODE_CVBS_PAL, MESON_VENC_MODE_CVBS_NTSC, + MESON_VENC_MODE_HDMI, }; struct meson_cvbs_enci_mode { @@ -56,12 +57,18 @@ struct meson_cvbs_enci_mode { unsigned int analog_sync_adj; }; +/* HDMI Clock parameters */ +bool meson_venc_hdmi_supported_vic(int vic); +bool meson_venc_hdmi_venc_repeat(int vic); + /* CVBS Timings and Parameters */ extern struct meson_cvbs_enci_mode meson_cvbs_enci_pal; extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc; void meson_venci_cvbs_mode_set(struct meson_drm *priv, struct meson_cvbs_enci_mode *mode); +void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + struct drm_display_mode *mode); unsigned int meson_venci_get_field(struct meson_drm *priv); void meson_venc_enable_vsync(struct meson_drm *priv); diff --git a/drivers/gpu/drm/meson/meson_vpp.h b/drivers/gpu/drm/meson/meson_vpp.h index ede3b26..815177c 100644 --- a/drivers/gpu/drm/meson/meson_vpp.h +++ b/drivers/gpu/drm/meson/meson_vpp.h @@ -23,6 +23,8 @@ /* Mux VIU/VPP to ENCI */ #define MESON_VIU_VPP_MUX_ENCI 0x5 +/* Mux VIU/VPP to ENCP */ +#define MESON_VIU_VPP_MUX_ENCP 0xA void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux); -- cgit v1.1 From 3f68be7d8e96253288d89d392078aa88e56e7ffa Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:27 +0200 Subject: drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX Controller with a custom Bridge + PHY around the Controller. This driver makes uses of all the custom PHY plat data callbacks and enables the compatible HDMI modes to be configured as a drm_encoder instance. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/Kconfig | 6 + drivers/gpu/drm/meson/Makefile | 1 + drivers/gpu/drm/meson/meson_drv.h | 3 + drivers/gpu/drm/meson/meson_dw_hdmi.c | 910 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/meson/meson_dw_hdmi.h | 146 ++++++ 5 files changed, 1066 insertions(+) create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.c create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.h diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index 99719af..3ce51d8 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -7,3 +7,9 @@ config DRM_MESON select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS select REGMAP_MMIO + +config DRM_MESON_DW_HDMI + tristate "HDMI Synopsys Controller support for Amlogic Meson Display" + depends on DRM_MESON + default y if DRM_MESON + select DRM_DW_HDMI diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index 92cf845..c5c4cc3 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -2,3 +2,4 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o obj-$(CONFIG_DRM_MESON) += meson-drm.o +obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 6195327..5e8b392 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -47,6 +47,9 @@ struct meson_drm { struct { unsigned int current_mode; + bool hdmi_repeat; + bool venc_repeat; + bool hdmi_use_enci; } venc; }; diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c new file mode 100644 index 0000000..8851dcb --- /dev/null +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "meson_drv.h" +#include "meson_venc.h" +#include "meson_vclk.h" +#include "meson_dw_hdmi.h" +#include "meson_registers.h" + +#define DRIVER_NAME "meson-dw-hdmi" +#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" + +/* + * HDMI Output is composed of : + * - A Synopsys DesignWare HDMI Controller IP + * - A TOP control block controlling the Clocks and PHY + * - A custom HDMI PHY in order convert video to TMDS signal + * ___________________________________ + * | HDMI TOP |<= HPD + * |___________________________________| + * | | | + * | Synopsys HDMI | HDMI PHY |=> TMDS + * | Controller |________________| + * |___________________________________|<=> DDC + * + * The HDMI TOP block only supports HPD sensing. + * The Synopsys HDMI Controller interrupt is routed + * through the TOP Block interrupt. + * Communication to the TOP Block and the Synopsys + * HDMI Controller is done a pair of addr+read/write + * registers. + * The HDMI PHY is configured by registers in the + * HHI register block. + * + * Pixel data arrives in 4:4:4 format from the VENC + * block and the VPU HDMI mux selects either the ENCI + * encoder for the 576i or 480i formats or the ENCP + * encoder for all the other formats including + * interlaced HD formats. + * The VENC uses a DVI encoder on top of the ENCI + * or ENCP encoders to generate DVI timings for the + * HDMI controller. + * + * GXBB, GXL and GXM embeds the Synopsys DesignWare + * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF + * audio source interfaces. + * + * We handle the following features : + * - HPD Rise & Fall interrupt + * - HDMI Controller Interrupt + * - HDMI PHY Init for 480i to 1080p60 + * - VENC & HDMI Clock setup for 480i to 1080p60 + * - VENC Mode setup for 480i to 1080p60 + * + * What is missing : + * - PHY, Clock and Mode setup for 2k && 4k modes + * - SDDC Scrambling mode for HDMI 2.0a + * - HDCP Setup + * - CEC Management + */ + +/* TOP Block Communication Channel */ +#define HDMITX_TOP_ADDR_REG 0x0 +#define HDMITX_TOP_DATA_REG 0x4 +#define HDMITX_TOP_CTRL_REG 0x8 + +/* Controller Communication Channel */ +#define HDMITX_DWC_ADDR_REG 0x10 +#define HDMITX_DWC_DATA_REG 0x14 +#define HDMITX_DWC_CTRL_REG 0x18 + +/* HHI Registers */ +#define HHI_MEM_PD_REG0 0x100 /* 0x40 */ +#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */ +#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */ +#define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ +#define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ +#define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ + +static DEFINE_SPINLOCK(reg_lock); + +enum meson_venc_source { + MESON_VENC_SOURCE_NONE = 0, + MESON_VENC_SOURCE_ENCI = 1, + MESON_VENC_SOURCE_ENCP = 2, +}; + +struct meson_dw_hdmi { + struct drm_encoder encoder; + struct dw_hdmi_plat_data dw_plat_data; + struct meson_drm *priv; + struct device *dev; + void __iomem *hdmitx; + struct reset_control *hdmitx_apb; + struct reset_control *hdmitx_ctrl; + struct reset_control *hdmitx_phy; + struct clk *hdmi_pclk; + struct clk *venci_clk; + u32 irq_stat; +}; +#define encoder_to_meson_dw_hdmi(x) \ + container_of(x, struct meson_dw_hdmi, encoder) + +static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, + const char *compat) +{ + return of_device_is_compatible(dw_hdmi->dev->of_node, compat); +} + +/* PHY (via TOP bridge) and Controller dedicated register interface */ + +static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr) +{ + unsigned long flags; + unsigned int data; + + spin_lock_irqsave(®_lock, flags); + + /* ADDR must be written twice */ + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); + + /* Read needs a second DATA read */ + data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); + data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); + + spin_unlock_irqrestore(®_lock, flags); + + return data; +} + +static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) +{ + unsigned long flags; + + spin_lock_irqsave(®_lock, flags); + + /* ADDR must be written twice */ + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); + + /* Write needs single DATA write */ + writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); + + spin_unlock_irqrestore(®_lock, flags); +} + +/* Helper to change specific bits in PHY registers */ +static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, + unsigned int mask, + unsigned int val) +{ + unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); + + data &= ~mask; + data |= val; + + dw_hdmi_top_write(dw_hdmi, addr, data); +} + +static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr) +{ + unsigned long flags; + unsigned int data; + + spin_lock_irqsave(®_lock, flags); + + /* ADDR must be written twice */ + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); + + /* Read needs a second DATA read */ + data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); + data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); + + spin_unlock_irqrestore(®_lock, flags); + + return data; +} + +static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) +{ + unsigned long flags; + + spin_lock_irqsave(®_lock, flags); + + /* ADDR must be written twice */ + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); + + /* Write needs single DATA write */ + writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); + + spin_unlock_irqrestore(®_lock, flags); +} + +/* Helper to change specific bits in controller registers */ +static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, + unsigned int mask, + unsigned int val) +{ + unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); + + data &= ~mask; + data |= val; + + dw_hdmi_dwc_write(dw_hdmi, addr, data); +} + +/* Bridge */ + +/* Setup PHY bandwidth modes */ +static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, + struct drm_display_mode *mode) +{ + struct meson_drm *priv = dw_hdmi->priv; + unsigned int pixel_clock = mode->clock; + + if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { + if (pixel_clock >= 371250) { + /* 5.94Gbps, 3.7125Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b); + } else if (pixel_clock >= 297000) { + /* 2.97Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b); + } else if (pixel_clock >= 148500) { + /* 1.485Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b); + } else { + /* 742.5Mbps, and below */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b); + } + } else if (dw_hdmi_is_compatible(dw_hdmi, + "amlogic,meson-gxbb-dw-hdmi")) { + if (pixel_clock >= 371250) { + /* 5.94Gbps, 3.7125Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b); + } else if (pixel_clock >= 297000) { + /* 2.97Gbps */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b); + } else { + /* 1.485Gbps, and below */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); + } + } +} + +static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi) +{ + struct meson_drm *priv = dw_hdmi->priv; + + /* Enable and software reset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf); + + mdelay(2); + + /* Enable and unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe); + + mdelay(2); +} + +static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + struct drm_display_mode *mode) +{ + struct meson_drm *priv = dw_hdmi->priv; + int vic = drm_match_cea_mode(mode); + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; + + vclk_freq = mode->clock; + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + vclk_freq *= 2; + + venc_freq = vclk_freq; + hdmi_freq = vclk_freq; + + if (meson_venc_hdmi_venc_repeat(vic)) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + + DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n", + vclk_freq, venc_freq, hdmi_freq, + priv->venc.hdmi_use_enci); + + meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq, + venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); +} + +static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + struct drm_display_mode *mode) +{ + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + struct meson_drm *priv = dw_hdmi->priv; + unsigned int wr_clk = + readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); + + DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name); + + /* Enable clocks */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); + + /* Bring HDMITX MEM output of power down */ + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); + + /* Bring out of reset */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); + + /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, + 0x3, 0x3); + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, + 0x3 << 4, 0x3 << 4); + + /* Enable normal output to PHY */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); + + /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f); + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f); + + /* Load TMDS pattern */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); + msleep(20); + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); + + /* Setup PHY parameters */ + meson_hdmi_phy_setup_mode(dw_hdmi, mode); + + /* Setup PHY */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, + 0xffff << 16, 0x0390 << 16); + + /* BIT_INVERT */ + if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, + BIT(17), 0); + else + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, + BIT(17), BIT(17)); + + /* Disable clock, fifo, fifo_wr */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); + + msleep(100); + + /* Reset PHY 3 times in a row */ + dw_hdmi_phy_reset(dw_hdmi); + dw_hdmi_phy_reset(dw_hdmi); + dw_hdmi_phy_reset(dw_hdmi); + + /* Temporary Disable VENC video stream */ + if (priv->venc.hdmi_use_enci) + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); + else + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); + + /* Temporary Disable HDMI video stream to HDMI-TX */ + writel_bits_relaxed(0x3, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + writel_bits_relaxed(0xf << 8, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + + /* Re-Enable VENC video stream */ + if (priv->venc.hdmi_use_enci) + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + else + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); + + /* Push back HDMI clock settings */ + writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8), + priv->io_base + _REG(VPU_HDMI_SETTING)); + + /* Enable and Select HDMI video source for HDMI-TX */ + if (priv->venc.hdmi_use_enci) + writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI, + priv->io_base + _REG(VPU_HDMI_SETTING)); + else + writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP, + priv->io_base + _REG(VPU_HDMI_SETTING)); + + return 0; +} + +static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, + void *data) +{ + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + struct meson_drm *priv = dw_hdmi->priv; + + DRM_DEBUG_DRIVER("\n"); + + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); +} + +static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, + void *data) +{ + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + + return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? + connector_status_connected : connector_status_disconnected; +} + +static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, + void *data) +{ + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + + /* Setup HPD Filter */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, + (0xa << 12) | 0xa0); + + /* Clear interrupts */ + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); + + /* Unmask interrupts */ + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN, + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL, + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); +} + +static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = { + .init = dw_hdmi_phy_init, + .disable = dw_hdmi_phy_disable, + .read_hpd = dw_hdmi_read_hpd, + .setup_hpd = dw_hdmi_setup_hpd, +}; + +static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) +{ + struct meson_dw_hdmi *dw_hdmi = dev_id; + u32 stat; + + stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); + + /* HPD Events, handle in the threaded interrupt handler */ + if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { + dw_hdmi->irq_stat = stat; + return IRQ_WAKE_THREAD; + } + + /* HDMI Controller Interrupt */ + if (stat & 1) + return IRQ_NONE; + + /* TOFIX Handle HDCP Interrupts */ + + return IRQ_HANDLED; +} + +/* Threaded interrupt handler to manage HPD events */ +static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) +{ + struct meson_dw_hdmi *dw_hdmi = dev_id; + u32 stat = dw_hdmi->irq_stat; + + /* HPD Events */ + if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { + bool hpd_connected = false; + + if (stat & HDMITX_TOP_INTR_HPD_RISE) + hpd_connected = true; + + dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected, + hpd_connected); + + drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); + } + + return IRQ_HANDLED; +} + +/* TOFIX Enable support for non-vic modes */ +static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; + int vic = drm_match_cea_mode(mode); + + DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->base.id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type, mode->flags); + + /* For now, only accept VIC modes */ + if (!vic) + return MODE_BAD; + + /* For now, filter by supported VIC modes */ + if (!meson_venc_hdmi_supported_vic(vic)) + return MODE_BAD; + + vclk_freq = mode->clock; + + /* 480i/576i needs global pixel doubling */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + vclk_freq *= 2; + + venc_freq = vclk_freq; + hdmi_freq = vclk_freq; + + /* VENC double pixels for 1080i and 720p modes */ + if (meson_venc_hdmi_venc_repeat(vic)) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + + dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, + vclk_freq, venc_freq, hdmi_freq); + + /* Finally filter by configurable vclk frequencies */ + switch (vclk_freq) { + case 54000: + case 74250: + case 148500: + case 297000: + case 594000: + return MODE_OK; + } + + return MODE_CLOCK_RANGE; +} + +/* Encoder */ + +static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = { + .destroy = meson_venc_hdmi_encoder_destroy, +}; + +static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + return 0; +} + +static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder) +{ + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); + struct meson_drm *priv = dw_hdmi->priv; + + DRM_DEBUG_DRIVER("\n"); + + writel_bits_relaxed(0x3, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); +} + +static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder) +{ + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); + struct meson_drm *priv = dw_hdmi->priv; + + DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); + + if (priv->venc.hdmi_use_enci) + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + else + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); +} + +static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); + struct meson_drm *priv = dw_hdmi->priv; + int vic = drm_match_cea_mode(mode); + + DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", + mode->base.id, mode->name, vic); + + /* Should have been filtered */ + if (!vic) + return; + + /* VENC + VENC-DVI Mode setup */ + meson_venc_hdmi_mode_set(priv, vic, mode); + + /* VCLK Set clock */ + dw_hdmi_set_vclk(dw_hdmi, mode); + + /* Setup YUV444 to HDMI-TX, no 10bit diphering */ + writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); +} + +static const struct drm_encoder_helper_funcs + meson_venc_hdmi_encoder_helper_funcs = { + .atomic_check = meson_venc_hdmi_encoder_atomic_check, + .disable = meson_venc_hdmi_encoder_disable, + .enable = meson_venc_hdmi_encoder_enable, + .mode_set = meson_venc_hdmi_encoder_mode_set, +}; + +/* DW HDMI Regmap */ + +static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, + unsigned int *result) +{ + *result = dw_hdmi_dwc_read(context, reg); + + return 0; + +} + +static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + dw_hdmi_dwc_write(context, reg, val); + + return 0; +} + +static const struct regmap_config meson_dw_hdmi_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .reg_read = meson_dw_hdmi_reg_read, + .reg_write = meson_dw_hdmi_reg_write, + .max_register = 0x10000, +}; + +static bool meson_hdmi_connector_is_available(struct device *dev) +{ + struct device_node *ep, *remote; + + /* HDMI Connector is on the second port, first endpoint */ + ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0); + if (!ep) + return false; + + /* If the endpoint node exists, consider it enabled */ + remote = of_graph_get_remote_port(ep); + if (remote) { + of_node_put(ep); + return true; + } + + of_node_put(ep); + of_node_put(remote); + + return false; +} + +static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct meson_dw_hdmi *meson_dw_hdmi; + struct drm_device *drm = data; + struct meson_drm *priv = drm->dev_private; + struct dw_hdmi_plat_data *dw_plat_data; + struct drm_encoder *encoder; + struct resource *res; + int irq; + int ret; + + DRM_DEBUG_DRIVER("\n"); + + if (!meson_hdmi_connector_is_available(dev)) { + dev_info(drm->dev, "HDMI Output connector not available\n"); + return -ENODEV; + } + + meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), + GFP_KERNEL); + if (!meson_dw_hdmi) + return -ENOMEM; + + meson_dw_hdmi->priv = priv; + meson_dw_hdmi->dev = dev; + dw_plat_data = &meson_dw_hdmi->dw_plat_data; + encoder = &meson_dw_hdmi->encoder; + + meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev, + "hdmitx_apb"); + if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) { + dev_err(dev, "Failed to get hdmitx_apb reset\n"); + return PTR_ERR(meson_dw_hdmi->hdmitx_apb); + } + + meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev, + "hdmitx"); + if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) { + dev_err(dev, "Failed to get hdmitx reset\n"); + return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl); + } + + meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev, + "hdmitx_phy"); + if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) { + dev_err(dev, "Failed to get hdmitx_phy reset\n"); + return PTR_ERR(meson_dw_hdmi->hdmitx_phy); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res); + if (IS_ERR(meson_dw_hdmi->hdmitx)) + return PTR_ERR(meson_dw_hdmi->hdmitx); + + meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr"); + if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) { + dev_err(dev, "Unable to get HDMI pclk\n"); + return PTR_ERR(meson_dw_hdmi->hdmi_pclk); + } + clk_prepare_enable(meson_dw_hdmi->hdmi_pclk); + + meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci"); + if (IS_ERR(meson_dw_hdmi->venci_clk)) { + dev_err(dev, "Unable to get venci clk\n"); + return PTR_ERR(meson_dw_hdmi->venci_clk); + } + clk_prepare_enable(meson_dw_hdmi->venci_clk); + + dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi, + &meson_dw_hdmi_regmap_config); + if (IS_ERR(dw_plat_data->regm)) + return PTR_ERR(dw_plat_data->regm); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "Failed to get hdmi top irq\n"); + return irq; + } + + ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq, + dw_hdmi_top_thread_irq, IRQF_SHARED, + "dw_hdmi_top_irq", meson_dw_hdmi); + if (ret) { + dev_err(dev, "Failed to request hdmi top irq\n"); + return ret; + } + + /* Encoder */ + + drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs); + + ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS, "meson_hdmi"); + if (ret) { + dev_err(priv->dev, "Failed to init HDMI encoder\n"); + return ret; + } + + encoder->possible_crtcs = BIT(0); + + DRM_DEBUG_DRIVER("encoder initialized\n"); + + /* Enable clocks */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); + + /* Bring HDMITX MEM output of power down */ + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); + + /* Reset HDMITX APB & TX & PHY */ + reset_control_reset(meson_dw_hdmi->hdmitx_apb); + reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); + reset_control_reset(meson_dw_hdmi->hdmitx_phy); + + /* Enable APB3 fail on error */ + writel_bits_relaxed(BIT(15), BIT(15), + meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); + writel_bits_relaxed(BIT(15), BIT(15), + meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); + + /* Bring out of reset */ + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); + + msleep(20); + + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); + + /* Enable HDMI-TX Interrupt */ + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_CORE); + + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, + HDMITX_TOP_INTR_CORE); + + /* Bridge / Connector */ + + dw_plat_data->mode_valid = dw_hdmi_mode_valid; + dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; + dw_plat_data->phy_name = "meson_dw_hdmi_phy"; + dw_plat_data->phy_data = meson_dw_hdmi; + dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; + dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; + + ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data); + if (ret) + return ret; + + DRM_DEBUG_DRIVER("HDMI controller initialized\n"); + + return 0; +} + +static void meson_dw_hdmi_unbind(struct device *dev, struct device *master, + void *data) +{ + dw_hdmi_unbind(dev); +} + +static const struct component_ops meson_dw_hdmi_ops = { + .bind = meson_dw_hdmi_bind, + .unbind = meson_dw_hdmi_unbind, +}; + +static int meson_dw_hdmi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &meson_dw_hdmi_ops); +} + +static int meson_dw_hdmi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &meson_dw_hdmi_ops); + + return 0; +} + +static const struct of_device_id meson_dw_hdmi_of_table[] = { + { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, + { .compatible = "amlogic,meson-gxl-dw-hdmi" }, + { .compatible = "amlogic,meson-gxm-dw-hdmi" }, + { } +}; +MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); + +static struct platform_driver meson_dw_hdmi_platform_driver = { + .probe = meson_dw_hdmi_probe, + .remove = meson_dw_hdmi_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = meson_dw_hdmi_of_table, + }, +}; +module_platform_driver(meson_dw_hdmi_platform_driver); + +MODULE_AUTHOR("Neil Armstrong "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h new file mode 100644 index 0000000..0b81183 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __MESON_DW_HDMI_H +#define __MESON_DW_HDMI_H + +/* + * Bit 7 RW Reserved. Default 1. + * Bit 6 RW Reserved. Default 1. + * Bit 5 RW Reserved. Default 1. + * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. + * Default 1. + * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; + * 0=Release from reset. + * Default 1. + * Bit 2 RW sw_reset_mem: KSV/REVOC mem. 1=Apply reset; 0=Release from reset. + * Default 1. + * Bit 1 RW sw_reset_rnd: random number interface to HDCP. 1=Apply reset; + * 0=Release from reset. Default 1. + * Bit 0 RW sw_reset_core: connects to IP's ~irstz. 1=Apply reset; + * 0=Release from reset. Default 1. + */ +#define HDMITX_TOP_SW_RESET (0x000) + +/* + * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. + * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. + * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. + * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. + * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. + * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. + * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. + * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. + * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. + * Bit 0 RW pixel_clk_en: 1=enable pixel_clk; 0=disable. Default 0. + */ +#define HDMITX_TOP_CLK_CNTL (0x001) + +/* + * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. + * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. + */ +#define HDMITX_TOP_HPD_FILTER (0x002) + +/* + * intr_maskn: MASK_N, one bit per interrupt source. + * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. + * [ 4] hdcp22_rndnum_err + * [ 3] nonce_rfrsh_rise + * [ 2] hpd_fall_intr + * [ 1] hpd_rise_intr + * [ 0] core_intr + */ +#define HDMITX_TOP_INTR_MASKN (0x003) + +/* + * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt + * bit, read back the interrupt status. + * Bit 31 R IP interrupt status + * Bit 2 RW hpd_fall + * Bit 1 RW hpd_rise + * Bit 0 RW IP interrupt + */ +#define HDMITX_TOP_INTR_STAT (0x004) + +/* + * [4] hdcp22_rndnum_err + * [3] nonce_rfrsh_rise + * [2] hpd_fall + * [1] hpd_rise + * [0] core_intr_rise + */ +#define HDMITX_TOP_INTR_STAT_CLR (0x005) + +#define HDMITX_TOP_INTR_CORE BIT(0) +#define HDMITX_TOP_INTR_HPD_RISE BIT(1) +#define HDMITX_TOP_INTR_HPD_FALL BIT(2) + +/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; + * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. + * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern + * every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0. + * Bit 8 RW shift_pttn_en: 1= Enable shift pattern generator; 0=Disable. + * Default 0. + * Bit 4: 3 RW prbs_pttn_mode: 0=PRBS11; 1=PRBS15; 2=PRBS7; 3=PRBS31. Default 0. + * Bit 2: 1 RW prbs_pttn_width: 0=idle; 1=output 8-bit pattern; + * 2=Output 1-bit pattern; 3=output 10-bit pattern. Default 0. + * Bit 0 RW prbs_pttn_en: 1=Enable PRBS generator; 0=Disable. Default 0. + */ +#define HDMITX_TOP_BIST_CNTL (0x006) + +/* Bit 29:20 RW shift_pttn_data[59:50]. Default 0. */ +/* Bit 19:10 RW shift_pttn_data[69:60]. Default 0. */ +/* Bit 9: 0 RW shift_pttn_data[79:70]. Default 0. */ +#define HDMITX_TOP_SHIFT_PTTN_012 (0x007) + +/* Bit 29:20 RW shift_pttn_data[29:20]. Default 0. */ +/* Bit 19:10 RW shift_pttn_data[39:30]. Default 0. */ +/* Bit 9: 0 RW shift_pttn_data[49:40]. Default 0. */ +#define HDMITX_TOP_SHIFT_PTTN_345 (0x008) + +/* Bit 19:10 RW shift_pttn_data[ 9: 0]. Default 0. */ +/* Bit 9: 0 RW shift_pttn_data[19:10]. Default 0. */ +#define HDMITX_TOP_SHIFT_PTTN_67 (0x009) + +/* Bit 25:16 RW tmds_clk_pttn[19:10]. Default 0. */ +/* Bit 9: 0 RW tmds_clk_pttn[ 9: 0]. Default 0. */ +#define HDMITX_TOP_TMDS_CLK_PTTN_01 (0x00A) + +/* Bit 25:16 RW tmds_clk_pttn[39:30]. Default 0. */ +/* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */ +#define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B) + +/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, + * used when TMDS CLK rate = TMDS character rate /4. Default 0. + * Bit 0 R Reserved. Default 0. + * [ 1] shift_tmds_clk_pttn + * [ 0] load_tmds_clk_pttn + */ +#define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C) + +/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM + * failure, write 1 to clear the failure flag. Default 0. + */ +#define HDMITX_TOP_REVOCMEM_STAT (0x00D) + +/* Bit 0 R filtered HPD status. */ +#define HDMITX_TOP_STAT0 (0x00E) + +#endif /* __MESON_DW_HDMI_H */ -- cgit v1.1 From 8cceda5349377e30cee5550acd41fefdd79d4ac6 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:28 +0200 Subject: dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension This binding describes the Amlogic Meson specific extension to the Synopsys Designware HDMI Controller. Acked-by: Rob Herring Signed-off-by: Neil Armstrong --- .../bindings/display/amlogic,meson-dw-hdmi.txt | 111 +++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt new file mode 100644 index 0000000..7f040ed --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt @@ -0,0 +1,111 @@ +Amlogic specific extensions to the Synopsys Designware HDMI Controller +====================================================================== + +The Amlogic Meson Synopsys Designware Integration is composed of : +- A Synopsys DesignWare HDMI Controller IP +- A TOP control block controlling the Clocks and PHY +- A custom HDMI PHY in order to convert video to TMDS signal + ___________________________________ +| HDMI TOP |<= HPD +|___________________________________| +| | | +| Synopsys HDMI | HDMI PHY |=> TMDS +| Controller |________________| +|___________________________________|<=> DDC + +The HDMI TOP block only supports HPD sensing. +The Synopsys HDMI Controller interrupt is routed through the +TOP Block interrupt. +Communication to the TOP Block and the Synopsys HDMI Controller is done +via a pair of dedicated addr+read/write registers. +The HDMI PHY is configured by registers in the HHI register block. + +Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux +selects either the ENCI encoder for the 576i or 480i formats or the ENCP +encoder for all the other formats including interlaced HD formats. + +The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate +DVI timings for the HDMI controller. + +Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare +HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF +audio source interfaces. + +Required properties: +- compatible: value should be different for each SoC family as : + - GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi" + - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" + - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" + followed by the common "amlogic,meson-gx-dw-hdmi" +- reg: Physical base address and length of the controller's registers. +- interrupts: The HDMI interrupt number +- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, + and the Amlogic Meson venci clocks as described in + Documentation/devicetree/bindings/clock/clock-bindings.txt, + the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci" +- resets, resets-names: must have the phandles to the HDMI apb, glue and phy + resets as described in : + Documentation/devicetree/bindings/reset/reset.txt, + the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy" + +Required nodes: + +The connections to the HDMI ports are modeled using the OF graph +bindings specified in Documentation/devicetree/bindings/graph.txt. + +The following table lists for each supported model the port number +corresponding to each HDMI output and input. + + Port 0 Port 1 +----------------------------------------- + S905 (GXBB) VENC Input TMDS Output + S905X (GXL) VENC Input TMDS Output + S905D (GXL) VENC Input TMDS Output + S912 (GXM) VENC Input TMDS Output + +Example: + +hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; +}; + +hdmi_tx: hdmi-tx@c883a000 { + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + reg = <0x0 0xc883a000 0x0 0x1c>; + interrupts = ; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; +}; -- cgit v1.1 From 2021d5b7d9f404bcb91301ececdf09a68b856ad7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:29 +0200 Subject: drm/meson: Convert existing documentation to actual kerneldoc Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- drivers/gpu/drm/meson/meson_canvas.c | 4 +++- drivers/gpu/drm/meson/meson_drv.c | 5 +++-- drivers/gpu/drm/meson/meson_dw_hdmi.c | 25 +++++++++++++++++-------- drivers/gpu/drm/meson/meson_vclk.c | 22 +++++++++++++++------- drivers/gpu/drm/meson/meson_venc.c | 25 ++++++++++++++++--------- drivers/gpu/drm/meson/meson_viu.c | 6 +++++- drivers/gpu/drm/meson/meson_vpp.c | 8 ++++++-- 7 files changed, 65 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c index 4109e36..08f6073 100644 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ b/drivers/gpu/drm/meson/meson_canvas.c @@ -24,7 +24,9 @@ #include "meson_canvas.h" #include "meson_registers.h" -/* +/** + * DOC: Canvas + * * CANVAS is a memory zone where physical memory frames information * are stored for the VIU to scanout. */ diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index a2e9f56..75382f5 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -52,13 +52,14 @@ #define DRIVER_NAME "meson" #define DRIVER_DESC "Amlogic Meson DRM driver" -/* - * Video Processing Unit +/** + * DOC: Video Processing Unit * * VPU Handles the Global Video Processing, it includes management of the * clocks gates, blocks reset lines and power domains. * * What is missing : + * * - Full reset of entire video processing HW blocks * - Scaling and setup of the VPU clock * - Bus clock gates diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 8851dcb..7b86eb7 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -42,18 +42,25 @@ #define DRIVER_NAME "meson-dw-hdmi" #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" -/* +/** + * DOC: HDMI Output + * * HDMI Output is composed of : + * * - A Synopsys DesignWare HDMI Controller IP * - A TOP control block controlling the Clocks and PHY * - A custom HDMI PHY in order convert video to TMDS signal - * ___________________________________ - * | HDMI TOP |<= HPD - * |___________________________________| - * | | | - * | Synopsys HDMI | HDMI PHY |=> TMDS - * | Controller |________________| - * |___________________________________|<=> DDC + * + * .. code:: + * + * ___________________________________ + * | HDMI TOP |<= HPD + * |___________________________________| + * | | | + * | Synopsys HDMI | HDMI PHY |=> TMDS + * | Controller |________________| + * |___________________________________|<=> DDC + * * * The HDMI TOP block only supports HPD sensing. * The Synopsys HDMI Controller interrupt is routed @@ -78,6 +85,7 @@ * audio source interfaces. * * We handle the following features : + * * - HPD Rise & Fall interrupt * - HDMI Controller Interrupt * - HDMI PHY Init for 480i to 1080p60 @@ -85,6 +93,7 @@ * - VENC Mode setup for 480i to 1080p60 * * What is missing : + * * - PHY, Clock and Mode setup for 2k && 4k modes * - SDDC Scrambling mode for HDMI 2.0a * - HDCP Setup diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 3731479..4767704 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -23,21 +23,29 @@ #include "meson_drv.h" #include "meson_vclk.h" -/* +/** + * DOC: Video Clocks + * * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. * We handle the following encodings : + * * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks * - HDMI Pixel Clocks generation + * * What is missing : + * * - Genenate Pixel clocks for 2K/4K 10bit formats * * Clock generator scheme : - * __________ _________ _____ - * | | | | | |--ENCI - * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL - * |__________| |_________| \ | MUX |--ENCP - * --VCLK2-| |--VDAC - * |_____|--HDMI-TX + * + * .. code:: + * + * __________ _________ _____ + * | | | | | |--ENCI + * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL + * |__________| |_________| \ | MUX |--ENCP + * --VCLK2-| |--VDAC + * |_____|--HDMI-TX * * Final clocks can take input for either VCLK or VCLK2, but * VCLK is the preferred path for HDMI clocking and VCLK2 is the diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 31dc275..9509017 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -26,26 +26,33 @@ #include "meson_vclk.h" #include "meson_registers.h" -/* +/** + * DOC: Video Encoder + * * VENC Handle the pixels encoding to the output formats. * We handle the following encodings : + * * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter * - TMDS/HDMI Encoding via ENCI_DIV and ENCP * - Setup of more clock rates for HDMI modes * * What is missing : + * * - LCD Panel encoding via ENCL * - TV Panel encoding via ENCT * * VENC paths : - * _____ _____ ____________________ - * vd1---| |-| | | VENC /---------|----VDAC - * vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\ - * osd1--| |-| | | \ | X--HDMI-TX - * osd2--|_____|-|_____| | |\-ENCP--ENCP_DVI-|/ - * | | | - * | \--ENCL-----------|----LVDS - * |____________________| + * + * .. code:: + * + * _____ _____ ____________________ + * vd1---| |-| | | VENC /---------|----VDAC + * vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|-| + * osd1--| |-| | | \ | X--HDMI-TX + * osd2--|_____|-|_____| | |\-ENCP--ENCP_DVI-|-| + * | | | + * | \--ENCL-----------|----LVDS + * |____________________| * * The ENCI is designed for PAl or NTSC encoding and can go through the VDAC * directly for CVBS encoding or through the ENCI_DVI encoder for HDMI. diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index a6de8ba..6bcfa52 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -28,9 +28,12 @@ #include "meson_canvas.h" #include "meson_registers.h" -/* +/** + * DOC: Video Input Unit + * * VIU Handles the Pixel scanout and the basic Colorspace conversions * We handle the following features : + * * - OSD1 RGB565/RGB888/xRGB8888 scanout * - RGB conversion to x/cb/cr * - Progressive or Interlace buffer scanout @@ -38,6 +41,7 @@ * - HDR OSD matrix for GXL/GXM * * What is missing : + * * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes * - YUV4:2:2 Y0CbY1Cr scanout * - Conversion to YUV 4:4:4 from 4:2:2 input diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 671909d..27356f8 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -25,16 +25,20 @@ #include "meson_vpp.h" #include "meson_registers.h" -/* +/** + * DOC: Video Post Processing + * * VPP Handles all the Post Processing after the Scanout from the VIU * We handle the following post processings : - * - Postblend : Blends the OSD1 only + * + * - Postblend, Blends the OSD1 only * We exclude OSD2, VS1, VS1 and Preblend output * - Vertical OSD Scaler for OSD1 only, we disable vertical scaler and * use it only for interlace scanout * - Intermediate FIFO with default Amlogic values * * What is missing : + * * - Preblend for video overlay pre-scaling * - OSD2 support for cursor framebuffer * - Video pre-scaling before postblend -- cgit v1.1 From 3650c25ad0a7bb3d31d5ae0728c7a216cc4af488 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:30 +0200 Subject: drm/meson: Add RST to bring together kerneldoc Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong --- Documentation/gpu/index.rst | 1 + Documentation/gpu/meson.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 Documentation/gpu/meson.rst diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index d81c6ff..c572f09 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -11,6 +11,7 @@ Linux GPU Driver Developer's Guide drm-kms-helpers drm-uapi i915 + meson tinydrm vc4 vga-switcheroo diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst new file mode 100644 index 0000000..479f6f5 --- /dev/null +++ b/Documentation/gpu/meson.rst @@ -0,0 +1,61 @@ +============================================= +drm/meson AmLogic Meson Video Processing Unit +============================================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c + :doc: Video Processing Unit + +Video Processing Unit +===================== + +The Amlogic Meson Display controller is composed of several components +that are going to be documented below: + +.. code:: + + DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| + | vd1 _______ _____________ _________________ | | + D |-------| |----| | | | | HDMI PLL | + D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | + R |-------| |----| Processing | | | | | + | osd2 | | | |---| Enci ----------|----|-----VDAC------| + R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| + A | osd1 | | | Blenders | | Encl ----------|----|---------------| + M |-------|______|----|____________| |________________| | | + ___|__________________________________________________________|_______________| + +Video Input Unit +================ + +.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c + :doc: Video Input Unit + +Video Post Processing +===================== + +.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c + :doc: Video Post Processing + +Video Encoder +============= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c + :doc: Video Encoder + +Video Canvas Management +======================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c + :doc: Canvas + +Video Clocks +============ + +.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c + :doc: Video Clocks + +HDMI Video Output +================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c + :doc: HDMI Output -- cgit v1.1 From b40af4d5ba441c7ffb32d3447614b12659d381e5 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 4 Apr 2017 14:15:31 +0200 Subject: MAINTAINERS: update files for Amlogic DRM Driver This patch adds the dw-hdmi bindings and RST kerneldoc to maintained files. Acked-by: Daniel Vetter Signed-off-by: Neil Armstrong Link: http://patchwork.freedesktop.org/patch/msgid/1491308131-22071-2-git-send-email-narmstrong@baylibre.com --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6c2c3a2..4ea82b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4257,6 +4257,8 @@ W: http://linux-meson.com/ S: Supported F: drivers/gpu/drm/meson/ F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +F: Documentation/gpu/meson.rst T: git git://anongit.freedesktop.org/drm/drm-misc DRM DRIVERS FOR EXYNOS -- cgit v1.1 From cc85dcde42204aa4f0df5e1cb0eeacf266b8fe79 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Fri, 3 Mar 2017 11:39:45 +0000 Subject: dt-bindings: display: rk3288-mipi-dsi: add reset property This reset is required in order to fully reset the internal state of the MIPI controller. Signed-off-by: John Keeping Reviewed-by: Brian Norris Acked-by: Rob Herring Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/20170303113945.3bd2cbd9.john@metanate.com --- .../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 1d722f5..543b074 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -17,9 +17,12 @@ Required properties: Optional properties: - power-domains: a phandle to mipi dsi power domain node. +- resets: list of phandle + reset specifier pairs, as described in [3]. +- reset-names: string reset name, must be "apb". [1] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/media/video-interfaces.txt +[3] Documentation/devicetree/bindings/reset/reset.txt Example: mipi_dsi: mipi@ff960000 { @@ -30,6 +33,8 @@ Example: interrupts = ; clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPI_DSI0>; clock-names = "ref", "pclk"; + resets = <&cru SRST_MIPIDSI0>; + reset-names = "apb"; rockchip,grf = <&grf>; status = "okay"; -- cgit v1.1 From 085c6c09c5c8529434a26107440bd28209b694d4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Apr 2017 11:52:54 +0200 Subject: drm: update todo.rst Just drive-by, but we have gsoc running so better to update it now. Great news is that two entries can be removed because essentially all done. v2: Keep a bunch of the todos, Gabriel is working on them. Cc: Gabriel Krisman Bertazi Reviewed-by: Neil Armstrong Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170404095304.17599-1-daniel.vetter@ffwll.ch --- Documentation/gpu/todo.rst | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index e255b36..1bdb735 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -16,7 +16,7 @@ De-midlayer drivers With the recent ``drm_bus`` cleanup patches for 3.17 it is no longer required to have a ``drm_bus`` structure set up. Drivers can directly set up the ``drm_device`` structure instead of relying on bus methods in ``drm_usb.c`` -and ``drm_platform.c``. The goal is to get rid of the driver's ``->load`` / +and ``drm_pci.c``. The goal is to get rid of the driver's ``->load`` / ``->unload`` callbacks and open-code the load/unload sequence properly, using the new two-stage ``drm_device`` setup/teardown. @@ -175,7 +175,7 @@ fine-grained per-buffer object and per-context lockings scheme. Currently the following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and ``udl``. -Contact: Daniel Vetter +Contact: Daniel Vetter, respective driver maintainers Switch to drm_connector_list_iter for any connector_list walking ---------------------------------------------------------------- @@ -217,6 +217,8 @@ plan is to switch to per-file driver API headers, which will also structure the kerneldoc better. This should also allow more fine-grained ``#include`` directives. +In the end no .c file should need to include ``drmP.h`` anymore. + Contact: Daniel Vetter Add missing kerneldoc for exported functions @@ -244,13 +246,8 @@ be hidden so that driver writers don't accidentally end up using it. And to prevent security issues in those legacy IOCTLs from being exploited on modern drivers. This has multiple possible subtasks: -* Make sure legacy IOCTLs can't be used on modern drivers. * Extract support code for legacy features into a ``drm-legacy.ko`` kernel module and compile it only when one of the legacy drivers is enabled. -* Extract legacy functions into their own headers and remove it that from the - monolithic ``drmP.h`` header. -* Remove any lingering cruft from the OS abstraction layer from modern - drivers. This is mostly done, the only thing left is to split up ``drm_irq.c`` into legacy cruft and the parts needed by modern KMS drivers. @@ -408,23 +405,3 @@ Contact: Noralf Trønnes, Daniel Vetter Outside DRM =========== - -Better kerneldoc ----------------- - -This is pretty much done, but there's some advanced topics: - -Come up with a way to hyperlink to struct members. Currently you can hyperlink -to the struct using ``#struct_name``, but not to a member within. Would need -buy-in from kerneldoc maintainers, and the big question is how to make it work -without totally unsightly -``drm_foo_bar_really_long_structure->even_longer_memeber`` all over the text -which breaks text flow. - -Figure out how to integrate the asciidoc support for ascii-diagrams. We have a -few of those (e.g. to describe mode timings), and asciidoc supports converting -some ascii-art dialect into pngs. Would be really pretty to make that work. - -Contact: Daniel Vetter, Jani Nikula - -Jani is working on this already, hopefully lands in 4.8. -- cgit v1.1 From e22717046a7da3cd0c0b0eec323e1dc38c777a42 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Apr 2017 11:52:55 +0200 Subject: drm: Consolidate and document sysfs support - remove docs for internal func, doesn't add value - add short overview snippet instead explaining that drivers don't have to bother themselves with reg/unreg concerns - drop the ttm comment about drmP.h, drmP.h is disappearing ... Reviewed-by: Neil Armstrong Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170404095304.17599-2-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-uapi.rst | 10 ++++++ drivers/gpu/drm/drm_sysfs.c | 70 ++++++++++++++++-------------------------- include/drm/drmP.h | 5 +-- include/drm/drm_sysfs.h | 8 ++--- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 76356c8..8b0f0e4 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -219,6 +219,16 @@ Debugfs Support .. kernel-doc:: drivers/gpu/drm/drm_debugfs.c :export: +Sysfs Support +============= + +.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c + :export: + + VBlank event handling ===================== diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 513288b..1c5b5ce 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -25,6 +25,20 @@ #define to_drm_minor(d) dev_get_drvdata(d) #define to_drm_connector(d) dev_get_drvdata(d) +/** + * DOC: overview + * + * DRM provides very little additional support to drivers for sysfs + * interactions, beyond just all the standard stuff. Drivers who want to expose + * additional sysfs properties and property groups can attach them at either + * &drm_device.dev or &drm_connector.kdev. + * + * Registration is automatically handled when calling drm_dev_register(), or + * drm_connector_register() in case of hot-plugged connectors. Unregistration is + * also automatically handled by drm_dev_unregister() and + * drm_connector_unregister(). + */ + static struct device_type drm_sysfs_device_minor = { .name = "drm_minor" }; @@ -250,15 +264,6 @@ static const struct attribute_group *connector_dev_groups[] = { NULL }; -/** - * drm_sysfs_connector_add - add a connector to sysfs - * @connector: connector to add - * - * Create a connector device in sysfs, along with its associated connector - * properties (so far, connection status, dpms, mode list and edid) and - * generate a hotplug event so userspace knows there's a new connector - * available. - */ int drm_sysfs_connector_add(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -285,19 +290,6 @@ int drm_sysfs_connector_add(struct drm_connector *connector) return 0; } -/** - * drm_sysfs_connector_remove - remove an connector device from sysfs - * @connector: connector to remove - * - * Remove @connector and its associated attributes from sysfs. Note that - * the device model core will take care of sending the "remove" uevent - * at this time, so we don't need to do it. - * - * Note: - * This routine should only be called if the connector was previously - * successfully registered. If @connector hasn't been registered yet, - * you'll likely see a panic somewhere deep in sysfs code when called. - */ void drm_sysfs_connector_remove(struct drm_connector *connector) { if (!connector->kdev) @@ -333,20 +325,6 @@ static void drm_sysfs_release(struct device *dev) kfree(dev); } -/** - * drm_sysfs_minor_alloc() - Allocate sysfs device for given minor - * @minor: minor to allocate sysfs device for - * - * This allocates a new sysfs device for @minor and returns it. The device is - * not registered nor linked. The caller has to use device_add() and - * device_del() to register and unregister it. - * - * Note that dev_get_drvdata() on the new device will return the minor. - * However, the device does not hold a ref-count to the minor nor to the - * underlying drm_device. This is unproblematic as long as you access the - * private data only in sysfs callbacks. device_del() disables those - * synchronously, so they cannot be called after you cleanup a minor. - */ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor) { const char *minor_str; @@ -384,15 +362,13 @@ err_free: } /** - * drm_class_device_register - Register a struct device in the drm class. + * drm_class_device_register - register new device with the DRM sysfs class + * @dev: device to register * - * @dev: pointer to struct device to register. - * - * @dev should have all relevant members pre-filled with the exception - * of the class member. In particular, the device_type member must - * be set. + * Registers a new &struct device within the DRM sysfs class. Essentially only + * used by ttm to have a place for its global settings. Drivers should never use + * this. */ - int drm_class_device_register(struct device *dev) { if (!drm_class || IS_ERR(drm_class)) @@ -403,6 +379,14 @@ int drm_class_device_register(struct device *dev) } EXPORT_SYMBOL_GPL(drm_class_device_register); +/** + * drm_class_device_unregister - unregister device with the DRM sysfs class + * @dev: device to unregister + * + * Unregisters a &struct device from the DRM sysfs class. Essentially only used + * by ttm to have a place for its global settings. Drivers should never use + * this. + */ void drm_class_device_unregister(struct device *dev) { return device_unregister(dev); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 3bfafcd..e1daa4f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -80,6 +80,7 @@ #include #include #include +#include struct module; @@ -512,10 +513,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev) * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. */ - /* sysfs support (drm_sysfs.c) */ -extern void drm_sysfs_hotplug_event(struct drm_device *dev); - - /*@}*/ /* returns true if currently okay to sleep */ diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h index 23418c1..70c9a10 100644 --- a/include/drm/drm_sysfs.h +++ b/include/drm/drm_sysfs.h @@ -1,12 +1,12 @@ #ifndef _DRM_SYSFS_H_ #define _DRM_SYSFS_H_ -/** - * This minimalistic include file is intended for users (read TTM) that - * don't want to include the full drmP.h file. - */ +struct drm_device; +struct device; int drm_class_device_register(struct device *dev); void drm_class_device_unregister(struct device *dev); +void drm_sysfs_hotplug_event(struct drm_device *dev); + #endif -- cgit v1.1 From 2640981f36004085eeff65849410121809fcf560 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Apr 2017 11:52:57 +0200 Subject: drm: document drm_ioctl.[hc] Also unify/merge with the existing stuff. I was a bit torn where to put this, but in the end I decided to put all the ioctl/sysfs/debugfs stuff into drm-uapi.rst. That means we have a bit a split with the other uapi related stuff used internally, like drm_file.[hc], but I think overall this makes more sense. If it's too confusing we can always add more cross-links to make it more discoverable. But the auto-sprinkling of links kernel-doc already does seems sufficient. Also for prettier docs and more cross-links, switch the internal defines over to an enum, as usual. v2: Update kerneldoc fro drm_compat_ioctl too (caught by 0day), plus a bit more drive-by polish. v3: Fix typo, spotted by xerpi on irc (Sergi). v4: Add missing space in comment (Neil). Cc: Sergi Granell Reviewed-by: Neil Armstrong Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170404095304.17599-4-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-internals.rst | 50 ---------------- Documentation/gpu/drm-uapi.rst | 14 +++++ drivers/gpu/drm/drm_ioc32.c | 76 ++++++++++++----------- drivers/gpu/drm/drm_ioctl.c | 50 +++++++++++++++- include/drm/drm_ioctl.h | 116 +++++++++++++++++++++++++++++++----- 5 files changed, 203 insertions(+), 103 deletions(-) diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index a09c721..babfb61 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -255,56 +255,6 @@ File Operations .. kernel-doc:: drivers/gpu/drm/drm_file.c :export: -IOCTLs ------- - -struct drm_ioctl_desc \*ioctls; int num_ioctls; - Driver-specific ioctls descriptors table. - -Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls -descriptors table is indexed by the ioctl number offset from the base -value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize -the table entries. - -:: - - DRM_IOCTL_DEF_DRV(ioctl, func, flags) - -``ioctl`` is the ioctl name. Drivers must define the DRM_##ioctl and -DRM_IOCTL_##ioctl macros to the ioctl number offset from -DRM_COMMAND_BASE and the ioctl number respectively. The first macro is -private to the device while the second must be exposed to userspace in a -public header. - -``func`` is a pointer to the ioctl handler function compatible with the -``drm_ioctl_t`` type. - -:: - - typedef int drm_ioctl_t(struct drm_device *dev, void *data, - struct drm_file *file_priv); - -``flags`` is a bitmask combination of the following values. It restricts -how the ioctl is allowed to be called. - -- DRM_AUTH - Only authenticated callers allowed - -- DRM_MASTER - The ioctl can only be called on the master file handle - -- DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed - -- DRM_CONTROL_ALLOW - The ioctl can only be called on a control - device - -- DRM_UNLOCKED - The ioctl handler will be called without locking the - DRM global mutex. This is the enforced default for kms drivers (i.e. - using the DRIVER_MODESET flag) and hence shouldn't be used any more - for new drivers. - -.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c - :export: - - Misc Utilities ============== diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 8b0f0e4..8584575 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -160,6 +160,20 @@ other hand, a driver requires shared state between clients which is visible to user-space and accessible beyond open-file boundaries, they cannot support render nodes. +IOCTL Support on Device Nodes +============================= + +.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c + :doc: driver specific ioctls + +.. kernel-doc:: include/drm/drm_ioctl.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c + :export: + +.. kernel-doc:: drivers/gpu/drm/drm_ioc32.c + :export: Testing and validation ====================== diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index b134482..ae38678 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -1,4 +1,4 @@ -/** +/* * \file drm_ioc32.c * * 32-bit ioctl compatibility routines for the DRM. @@ -72,15 +72,15 @@ #define DRM_IOCTL_MODE_ADDFB232 DRM_IOWR(0xb8, drm_mode_fb_cmd232_t) typedef struct drm_version_32 { - int version_major; /**< Major version */ - int version_minor; /**< Minor version */ - int version_patchlevel; /**< Patch level */ - u32 name_len; /**< Length of name buffer */ - u32 name; /**< Name of driver */ - u32 date_len; /**< Length of date buffer */ - u32 date; /**< User-space buffer to hold date */ - u32 desc_len; /**< Length of desc buffer */ - u32 desc; /**< User-space buffer to hold desc */ + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel; /* Patch level */ + u32 name_len; /* Length of name buffer */ + u32 name; /* Name of driver */ + u32 date_len; /* Length of date buffer */ + u32 date; /* User-space buffer to hold date */ + u32 desc_len; /* Length of desc buffer */ + u32 desc; /* User-space buffer to hold desc */ } drm_version32_t; static int compat_drm_version(struct file *file, unsigned int cmd, @@ -126,8 +126,8 @@ static int compat_drm_version(struct file *file, unsigned int cmd, } typedef struct drm_unique32 { - u32 unique_len; /**< Length of unique */ - u32 unique; /**< Unique name for driver instantiation */ + u32 unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ } drm_unique32_t; static int compat_drm_getunique(struct file *file, unsigned int cmd, @@ -180,12 +180,12 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, } typedef struct drm_map32 { - u32 offset; /**< Requested physical address (0 for SAREA)*/ - u32 size; /**< Requested physical size (bytes) */ - enum drm_map_type type; /**< Type of memory to map */ - enum drm_map_flags flags; /**< Flags */ - u32 handle; /**< User-space: "Handle" to pass to mmap() */ - int mtrr; /**< MTRR slot used */ + u32 offset; /* Requested physical address (0 for SAREA) */ + u32 size; /* Requested physical size (bytes) */ + enum drm_map_type type; /* Type of memory to map */ + enum drm_map_flags flags; /* Flags */ + u32 handle; /* User-space: "Handle" to pass to mmap() */ + int mtrr; /* MTRR slot used */ } drm_map32_t; static int compat_drm_getmap(struct file *file, unsigned int cmd, @@ -286,12 +286,12 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd, } typedef struct drm_client32 { - int idx; /**< Which client desired? */ - int auth; /**< Is client authenticated? */ - u32 pid; /**< Process ID */ - u32 uid; /**< User ID */ - u32 magic; /**< Magic */ - u32 iocs; /**< Ioctl count */ + int idx; /* Which client desired? */ + int auth; /* Is client authenticated? */ + u32 pid; /* Process ID */ + u32 uid; /* User ID */ + u32 magic; /* Magic */ + u32 iocs; /* Ioctl count */ } drm_client32_t; static int compat_drm_getclient(struct file *file, unsigned int cmd, @@ -366,12 +366,12 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, } typedef struct drm_buf_desc32 { - int count; /**< Number of buffers of this size */ - int size; /**< Size in bytes */ - int low_mark; /**< Low water mark */ - int high_mark; /**< High water mark */ + int count; /* Number of buffers of this size */ + int size; /* Size in bytes */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ int flags; - u32 agp_start; /**< Start address in the AGP aperture */ + u32 agp_start; /* Start address in the AGP aperture */ } drm_buf_desc32_t; static int compat_drm_addbufs(struct file *file, unsigned int cmd, @@ -1111,13 +1111,18 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = { }; /** - * Called whenever a 32-bit process running under a 64-bit kernel - * performs an ioctl on /dev/drm. + * drm_compat_ioctl - 32bit IOCTL compatibility handler for DRM drivers + * @filp: file this ioctl is called on + * @cmd: ioctl cmd number + * @arg: user argument + * + * Compatibility handler for 32 bit userspace running on 64 kernels. All actual + * IOCTL handling is forwarded to drm_ioctl(), while marshalling structures as + * appropriate. Note that this only handles DRM core IOCTLs, if the driver has + * botched IOCTL itself, it must handle those by wrapping this function. * - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument. - * \return zero on success or negative number on failure. + * Returns: + * Zero on success, negative error code on failure. */ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1141,5 +1146,4 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; } - EXPORT_SYMBOL(drm_compat_ioctl); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 7d6deaa..9f4241f 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -647,13 +647,59 @@ static const struct drm_ioctl_desc drm_ioctls[] = { #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** + * DOC: driver specific ioctls + * + * First things first, driver private IOCTLs should only be needed for drivers + * supporting rendering. Kernel modesetting is all standardized, and extended + * through properties. There are a few exceptions in some existing drivers, + * which define IOCTL for use by the display DRM master, but they all predate + * properties. + * + * Now if you do have a render driver you always have to support it through + * driver private properties. There's a few steps needed to wire all the things + * up. + * + * First you need to define the structure for your IOCTL in your driver private + * UAPI header in ``include/uapi/drm/my_driver_drm.h``:: + * + * struct my_driver_operation { + * u32 some_thing; + * u32 another_thing; + * }; + * + * Please make sure that you follow all the best practices from + * ``Documentation/ioctl/botching-up-ioctls.txt``. Note that drm_ioctl() + * automatically zero-extends structures, hence make sure you can add more stuff + * at the end, i.e. don't put a variable sized array there. + * + * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(), + * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix:: + * + * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ + * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) + * + * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to + * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire + * up the handlers and set the access rights: + * + * static const struct drm_ioctl_desc my_driver_ioctls[] = { + * DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation, + * DRM_AUTH|DRM_RENDER_ALLOW), + * }; + * + * And then assign this to the &drm_driver.ioctls field in your driver + * structure. + */ + +/** * drm_ioctl - ioctl callback implementation for DRM drivers * @filp: file this ioctl is called on * @cmd: ioctl cmd number * @arg: user argument * - * Looks up the ioctl function in the ::ioctls table, checking for root - * previleges if so required, and dispatches to the respective function. + * Looks up the ioctl function in the DRM core and the driver dispatch table, + * stored in &drm_driver.ioctls. It checks for necessary permission by calling + * drm_ioctl_permit(), and dispatches to the respective function. * * Returns: * Zero on success, negative error code on failure. diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h index f17ee07..ee03b3c 100644 --- a/include/drm/drm_ioctl.h +++ b/include/drm/drm_ioctl.h @@ -33,6 +33,7 @@ #define _DRM_IOCTL_H_ #include +#include #include @@ -41,41 +42,126 @@ struct drm_file; struct file; /** - * Ioctl function type. + * drm_ioctl_t - DRM ioctl function type. + * @dev: DRM device inode + * @data: private pointer of the ioctl call + * @file_priv: DRM file this ioctl was made on * - * \param inode device inode. - * \param file_priv DRM file private pointer. - * \param cmd command. - * \param arg argument. + * This is the DRM ioctl typedef. Note that drm_ioctl() has alrady copied @data + * into kernel-space, and will also copy it back, depending upon the read/write + * settings in the ioctl command code. */ typedef int drm_ioctl_t(struct drm_device *dev, void *data, struct drm_file *file_priv); +/** + * drm_ioctl_compat_t - compatibility DRM ioctl function type. + * @filp: file pointer + * @cmd: ioctl command code + * @arg: DRM file this ioctl was made on + * + * Just a typedef to make declaring an array of compatibility handlers easier. + * New drivers shouldn't screw up the structure layout for their ioctl + * structures and hence never need this. + */ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, unsigned long arg); #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_MAJOR 226 -#define DRM_AUTH 0x1 -#define DRM_MASTER 0x2 -#define DRM_ROOT_ONLY 0x4 -#define DRM_CONTROL_ALLOW 0x8 -#define DRM_UNLOCKED 0x10 -#define DRM_RENDER_ALLOW 0x20 +/** + * enum drm_ioctl_flags - DRM ioctl flags + * + * Various flags that can be set in &drm_ioctl_desc.flags to control how + * userspace can use a given ioctl. + */ +enum drm_ioctl_flags { + /** + * @DRM_AUTH: + * + * This is for ioctl which are used for rendering, and require that the + * file descriptor is either for a render node, or if it's a + * legacy/primary node, then it must be authenticated. + */ + DRM_AUTH = BIT(0), + /** + * @DRM_MASTER: + * + * This must be set for any ioctl which can change the modeset or + * display state. Userspace must call the ioctl through a primary node, + * while it is the active master. + * + * Note that read-only modeset ioctl can also be called by + * unauthenticated clients, or when a master is not the currently active + * one. + */ + DRM_MASTER = BIT(1), + /** + * @DRM_ROOT_ONLY: + * + * Anything that could potentially wreak a master file descriptor needs + * to have this flag set. Current that's only for the SETMASTER and + * DROPMASTER ioctl, which e.g. logind can call to force a non-behaving + * master (display compositor) into compliance. + * + * This is equivalent to callers with the SYSADMIN capability. + */ + DRM_ROOT_ONLY = BIT(2), + /** + * @DRM_CONTROL_ALLOW: + * + * Deprecated, do not use. Control nodes are in the process of getting + * removed. + */ + DRM_CONTROL_ALLOW = BIT(3), + /** + * @DRM_UNLOCKED: + * + * Whether &drm_ioctl_desc.func should be called with the DRM BKL held + * or not. Enforced as the default for all modern drivers, hence there + * should never be a need to set this flag. + */ + DRM_UNLOCKED = BIT(4), + /** + * @DRM_RENDER_ALLOW: + * + * This is used for all ioctl needed for rendering only, for drivers + * which support render nodes. This should be all new render drivers, + * and hence it should be always set for any ioctl with DRM_AUTH set. + * Note though that read-only query ioctl might have this set, but have + * not set DRM_AUTH because they do not require authentication. + */ + DRM_RENDER_ALLOW = BIT(5), +}; +/** + * struct drm_ioctl_desc - DRM driver ioctl entry + * @cmd: ioctl command number, without flags + * @flags: a bitmask of &enum drm_ioctl_flags + * @func: handler for this ioctl + * @name: user-readable name for debug output + * + * For convenience it's easier to create these using the DRM_IOCTL_DEF_DRV() + * macro. + */ struct drm_ioctl_desc { unsigned int cmd; - int flags; + enum drm_ioctl_flags flags; drm_ioctl_t *func; const char *name; }; /** - * Creates a driver or general drm_ioctl_desc array entry for the given - * ioctl, for use by drm_ioctl(). + * DRM_IOCTL_DEF_DRV() - helper macro to fill out a &struct drm_ioctl_desc + * @ioctl: ioctl command suffix + * @_func: handler for the ioctl + * @_flags: a bitmask of &enum drm_ioctl_flags + * + * Small helper macro to create a &struct drm_ioctl_desc entry. The ioctl + * command number is constructed by prepending ``DRM_IOCTL\_`` and passing that + * to DRM_IOCTL_NR(). */ - #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ .cmd = DRM_IOCTL_##ioctl, \ -- cgit v1.1 From 1bbfe9d1a315bb573d4f10bbf443b68b5ddac473 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Apr 2017 11:53:04 +0200 Subject: drm/doc: Small markup fixup Drive-by cleanup. Reviewed-by: Neil Armstrong Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170404095304.17599-11-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_probe_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 85005d5..efb5e5e 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -44,7 +44,7 @@ * * This library provides some helper code for output probing. It provides an * implementation of the core &drm_connector_funcs.fill_modes interface with - * drm_helper_probe_single_connector_modes. + * drm_helper_probe_single_connector_modes(). * * It also provides support for polling connectors with a work item and for * generic hotplug interrupt handling where the driver doesn't or cannot keep -- cgit v1.1 From 5db06a8a98f515f67446a69c57577c4c363ec65d Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 4 Apr 2017 17:52:21 +0100 Subject: drm: Pass CRTC ID in userspace vblank events With the atomic API, it is possible that a single commit affects multiple crtcs. If the user requests an event with that commit, one event will be sent for each CRTC, but it is not possible to distinguish which crtc an event is for in user space. To solve this, the reserved field in struct drm_vblank_event is repurposed to include the crtc_id which the event is for. The DRM_CAP_CRTC_IN_VBLANK_EVENT is added to allow userspace to query if the crtc field will be set properly. [daniels: Rebased, using Maarten's forward-port.] Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Stone Cc: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/20170404165221.28240-2-daniels@collabora.com --- drivers/gpu/drm/drm_ioctl.c | 3 +++ drivers/gpu/drm/drm_irq.c | 2 ++ include/uapi/drm/drm.h | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 9f4241f..865e3ee 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -286,6 +286,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ case DRM_CAP_ADDFB2_MODIFIERS: req->value = dev->mode_config.allow_fb_modifiers; break; + case DRM_CAP_CRTC_IN_VBLANK_EVENT: + req->value = 1; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index dac1b25..8c866ca 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1026,6 +1026,7 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, e->pipe = pipe; e->event.sequence = drm_vblank_count(dev, pipe); + e->event.crtc_id = crtc->base.id; list_add_tail(&e->base.link, &dev->vblank_event_list); } EXPORT_SYMBOL(drm_crtc_arm_vblank_event); @@ -1056,6 +1057,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc, now = get_drm_timestamp(); } e->pipe = pipe; + e->event.crtc_id = crtc->base.id; send_vblank_event(dev, e, seq, &now); } EXPORT_SYMBOL(drm_crtc_send_vblank_event); diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index b2c5284..42d9f64 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -647,6 +647,7 @@ struct drm_gem_open { #define DRM_CAP_CURSOR_HEIGHT 0x9 #define DRM_CAP_ADDFB2_MODIFIERS 0x10 #define DRM_CAP_PAGE_FLIP_TARGET 0x11 +#define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12 /** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { @@ -851,7 +852,7 @@ struct drm_event_vblank { __u32 tv_sec; __u32 tv_usec; __u32 sequence; - __u32 reserved; + __u32 crtc_id; /* 0 on older kernels that do not support this */ }; /* typedef area */ -- cgit v1.1 From 5f27502655f657989dac0622ecf70b9e173e90f8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:50 +0200 Subject: drm: Make drm_modeset_lock_crtc internal This is only for legacy paths that need to grab the crtc/plane lock combo. If you want to lock a crtc, just use drm_modeset_lock(). Reviewed-by: Harry Wentland Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-2-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc_internal.h | 3 +++ drivers/gpu/drm/drm_modeset_lock.c | 14 -------------- include/drm/drm_modeset_lock.h | 2 -- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 8c04275..de10475 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -61,6 +61,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* drm_modeset_lock.c */ +void drm_modeset_lock_crtc(struct drm_crtc *crtc, + struct drm_plane *plane); /* drm_dumb_buffers.c */ /* IOCTLs */ int drm_mode_create_dumb_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index bf60f26..c94eff9 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -148,19 +148,6 @@ void drm_modeset_unlock_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_modeset_unlock_all); -/** - * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update - * @crtc: DRM CRTC - * @plane: DRM plane to be updated on @crtc - * - * This function locks the given crtc and plane (which should be either the - * primary or cursor plane) using a hidden acquire context. This is necessary so - * that drivers internally using the atomic interfaces can grab further locks - * with the lock acquire context. - * - * Note that @plane can be NULL, e.g. when the cursor support hasn't yet been - * converted to universal planes yet. - */ void drm_modeset_lock_crtc(struct drm_crtc *crtc, struct drm_plane *plane) { @@ -205,7 +192,6 @@ fail: goto retry; } } -EXPORT_SYMBOL(drm_modeset_lock_crtc); /** * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 96d39fb..88d35bf 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -121,8 +121,6 @@ struct drm_plane; void drm_modeset_lock_all(struct drm_device *dev); void drm_modeset_unlock_all(struct drm_device *dev); -void drm_modeset_lock_crtc(struct drm_crtc *crtc, - struct drm_plane *plane); void drm_modeset_unlock_crtc(struct drm_crtc *crtc); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); struct drm_modeset_acquire_ctx * -- cgit v1.1 From b95ff0319a829d5e707d64a3994c75f012f6b6ec Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:51 +0200 Subject: drm: Remove drm_modeset_(un)lock_crtc The last user, the cursor ioctl, can just open-code this too. We simply have to move the acquire ctx dance from the universal function up into the top-level ioctl handler. Reviewed-by: Harry Wentland Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-3-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc_internal.h | 3 -- drivers/gpu/drm/drm_modeset_lock.c | 67 ------------------------------------- drivers/gpu/drm/drm_plane.c | 49 +++++++++++++-------------- include/drm/drm_modeset_lock.h | 1 - 4 files changed, 24 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index de10475..8c04275 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -61,9 +61,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* drm_modeset_lock.c */ -void drm_modeset_lock_crtc(struct drm_crtc *crtc, - struct drm_plane *plane); /* drm_dumb_buffers.c */ /* IOCTLs */ int drm_mode_create_dumb_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index c94eff9..c3ca6b8 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -148,51 +148,6 @@ void drm_modeset_unlock_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_modeset_unlock_all); -void drm_modeset_lock_crtc(struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct drm_modeset_acquire_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (WARN_ON(!ctx)) - return; - - drm_modeset_acquire_init(ctx, 0); - -retry: - ret = drm_modeset_lock(&crtc->mutex, ctx); - if (ret) - goto fail; - - if (plane) { - ret = drm_modeset_lock(&plane->mutex, ctx); - if (ret) - goto fail; - - if (plane->crtc) { - ret = drm_modeset_lock(&plane->crtc->mutex, ctx); - if (ret) - goto fail; - } - } - - WARN_ON(crtc->acquire_ctx); - - /* now we hold the locks, so now that it is safe, stash the - * ctx for drm_modeset_unlock_crtc(): - */ - crtc->acquire_ctx = ctx; - - return; - -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } -} - /** * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls * @crtc: drm crtc @@ -215,28 +170,6 @@ drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); /** - * drm_modeset_unlock_crtc - drop crtc lock - * @crtc: drm crtc - * - * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other - * locks acquired through the hidden context. - */ -void drm_modeset_unlock_crtc(struct drm_crtc *crtc) -{ - struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; - - if (WARN_ON(!ctx)) - return; - - crtc->acquire_ctx = NULL; - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - - kfree(ctx); -} -EXPORT_SYMBOL(drm_modeset_unlock_crtc); - -/** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device * diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index bc71aa2..838ca74 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -620,7 +620,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, static int drm_mode_cursor_universal(struct drm_crtc *crtc, struct drm_mode_cursor2 *req, - struct drm_file *file_priv) + struct drm_file *file_priv, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct drm_framebuffer *fb = NULL; @@ -634,21 +635,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, int32_t crtc_x, crtc_y; uint32_t crtc_w = 0, crtc_h = 0; uint32_t src_w = 0, src_h = 0; - struct drm_modeset_acquire_ctx ctx; int ret = 0; BUG_ON(!crtc->cursor); WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); - drm_modeset_acquire_init(&ctx, 0); -retry: - ret = drm_modeset_lock(&crtc->mutex, &ctx); - if (ret) - goto fail; - ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); - if (ret) - goto fail; - /* * Obtain fb we'll be using (either new or existing) and take an extra * reference to it if fb != null. setplane will take care of dropping @@ -693,7 +684,7 @@ retry: */ ret = __setplane_internal(crtc->cursor, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h, &ctx); + 0, 0, src_w, src_h, ctx); /* Update successful; save new cursor position, if necessary */ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -701,15 +692,6 @@ retry: crtc->cursor_y = req->y; } -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - return ret; } @@ -718,6 +700,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, struct drm_file *file_priv) { struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -732,14 +715,24 @@ static int drm_mode_cursor_common(struct drm_device *dev, return -ENOENT; } + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto out; + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto out; + /* * If this crtc has a universal cursor plane, call that plane's update * handler rather than using legacy cursor handlers. */ - if (crtc->cursor) - return drm_mode_cursor_universal(crtc, req, file_priv); + if (crtc->cursor) { + ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx); + goto out; + } - drm_modeset_lock_crtc(crtc, crtc->cursor); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; @@ -763,7 +756,13 @@ static int drm_mode_cursor_common(struct drm_device *dev, } } out: - drm_modeset_unlock_crtc(crtc); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 88d35bf..2bb065b 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -121,7 +121,6 @@ struct drm_plane; void drm_modeset_lock_all(struct drm_device *dev); void drm_modeset_unlock_all(struct drm_device *dev); -void drm_modeset_unlock_crtc(struct drm_crtc *crtc); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); struct drm_modeset_acquire_ctx * drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc); -- cgit v1.1 From b260ac3ebef5eb748207cd542dba00af6c5caaa5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:52 +0200 Subject: drm: Remove drm_modeset_legacy_acquire_ctx and crtc->acquire_ctx With all the callers of drm_modeset_lock_crtc gone, and all the places it was formerly used properly wiring the acquire ctx through, we can remove this. The only hidden context magic we still have is now the global one. Reviewed-by: Harry Wentland Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-4-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic.c | 14 -------------- drivers/gpu/drm/drm_atomic_helper.c | 2 +- drivers/gpu/drm/drm_modeset_lock.c | 21 --------------------- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_pipe_crc.c | 2 +- include/drm/drm_crtc.h | 9 --------- include/drm/drm_modeset_lock.h | 2 -- 7 files changed, 4 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9b892af..3453102 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1516,19 +1516,9 @@ EXPORT_SYMBOL(drm_atomic_add_affected_planes); void drm_atomic_legacy_backoff(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - unsigned crtc_mask = 0; - struct drm_crtc *crtc; int ret; bool global = false; - drm_for_each_crtc(crtc, dev) { - if (crtc->acquire_ctx != state->acquire_ctx) - continue; - - crtc_mask |= drm_crtc_mask(crtc); - crtc->acquire_ctx = NULL; - } - if (WARN_ON(dev->mode_config.acquire_ctx == state->acquire_ctx)) { global = true; @@ -1542,10 +1532,6 @@ retry: if (ret) goto retry; - drm_for_each_crtc(crtc, dev) - if (drm_crtc_mask(crtc) & crtc_mask) - crtc->acquire_ctx = state->acquire_ctx; - if (global) dev->mode_config.acquire_ctx = state->acquire_ctx; } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3994b4..3160d08 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2975,7 +2975,7 @@ int drm_atomic_helper_connector_dpms(struct drm_connector *connector, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) { diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index c3ca6b8..64ef09a 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -149,27 +149,6 @@ void drm_modeset_unlock_all(struct drm_device *dev) EXPORT_SYMBOL(drm_modeset_unlock_all); /** - * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls - * @crtc: drm crtc - * - * Legacy ioctl operations like cursor updates or page flips only have per-crtc - * locking, and store the acquire ctx in the corresponding crtc. All other - * legacy operations take all locks and use a global acquire context. This - * function grabs the right one. - */ -struct drm_modeset_acquire_ctx * -drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) -{ - if (crtc->acquire_ctx) - return crtc->acquire_ctx; - - WARN_ON(!crtc->dev->mode_config.acquire_ctx); - - return crtc->dev->mode_config.acquire_ctx; -} -EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); - -/** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device * diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e27ea89..84abff3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10715,7 +10715,7 @@ out_hang: state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = dev->mode_config.acquire_ctx; retry: plane_state = drm_atomic_get_plane_state(state, primary); @@ -13075,7 +13075,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) return; } - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 9fd9c70..206ee4f 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -522,7 +522,7 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, goto unlock; } - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(&crtc->base); + state->acquire_ctx = crtc->base.dev->mode_config.acquire_ctx; pipe_config = intel_atomic_get_crtc_state(state, crtc); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 2be2192..ede60d6 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -782,15 +782,6 @@ struct drm_crtc { */ spinlock_t commit_lock; - /** - * @acquire_ctx: - * - * Per-CRTC implicit acquire context used by atomic drivers for legacy - * IOCTLs, so that atomic drivers can get at the locking acquire - * context. - */ - struct drm_modeset_acquire_ctx *acquire_ctx; - #ifdef CONFIG_DEBUG_FS /** * @debugfs_entry: diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 2bb065b..4b27c2b 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -122,8 +122,6 @@ struct drm_plane; void drm_modeset_lock_all(struct drm_device *dev); void drm_modeset_unlock_all(struct drm_device *dev); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); -struct drm_modeset_acquire_ctx * -drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc); int drm_modeset_lock_all_ctx(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); -- cgit v1.1 From a5b8444e289c9e759927f9bf2e82f10719729fe7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:53 +0200 Subject: drm/atomic-helper: remove modeset_lock_all from helper_resume Atomic code rely shouldn't rely on the magic hidden acquire context. v2: Remove unused config local var (gcc). Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-5-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 3160d08..0a3d91c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2622,14 +2622,22 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); int drm_atomic_helper_resume(struct drm_device *dev, struct drm_atomic_state *state) { - struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx ctx; int err; drm_mode_config_reset(dev); - drm_modeset_lock_all(dev); - err = drm_atomic_helper_commit_duplicated_state(state, config->acquire_ctx); - drm_modeset_unlock_all(dev); + drm_modeset_acquire_init(&ctx, 0); + while (1) { + err = drm_atomic_helper_commit_duplicated_state(state, &ctx); + if (err != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return err; } -- cgit v1.1 From c2d855649e303523787473d388931948e8fbf93d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:54 +0200 Subject: drm: drop modeset_lock_all from drm_state_info If we push the locks down we don't have to take them all at the same time. Aside: Making dump_info fully safe should be fairly simple, if we protect the ->state pointers with rcu. Simply putting a synchronize_rcu() into the drm_atomic_state free function should be all that's roughly needed. Well except we shouldn't block in there, so better to put that into a work_struct. But I've not set out to fix that little issue. Cc: Rob Clark Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic.c | 60 ++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3453102..9afb143 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1676,22 +1676,8 @@ static void drm_atomic_print_state(const struct drm_atomic_state *state) drm_atomic_connector_print_state(&p, connector_state); } -/** - * drm_state_dump - dump entire device atomic state - * @dev: the drm device - * @p: where to print the state to - * - * Just for debugging. Drivers might want an option to dump state - * to dmesg in case of error irq's. (Hint, you probably want to - * ratelimit this!) - * - * The caller must drm_modeset_lock_all(), or if this is called - * from error irq handler, it should not be enabled by default. - * (Ie. if you are debugging errors you might not care that this - * is racey. But calling this without all modeset locks held is - * not inherently safe.) - */ -void drm_state_dump(struct drm_device *dev, struct drm_printer *p) +static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, + bool take_locks) { struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; @@ -1702,17 +1688,51 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p) if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) return; - list_for_each_entry(plane, &config->plane_list, head) + list_for_each_entry(plane, &config->plane_list, head) { + if (take_locks) + drm_modeset_lock(&plane->mutex, NULL); drm_atomic_plane_print_state(p, plane->state); + if (take_locks) + drm_modeset_unlock(&plane->mutex); + } - list_for_each_entry(crtc, &config->crtc_list, head) + list_for_each_entry(crtc, &config->crtc_list, head) { + if (take_locks) + drm_modeset_lock(&crtc->mutex, NULL); drm_atomic_crtc_print_state(p, crtc->state); + if (take_locks) + drm_modeset_unlock(&crtc->mutex); + } drm_connector_list_iter_begin(dev, &conn_iter); + if (take_locks) + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); drm_for_each_connector_iter(connector, &conn_iter) drm_atomic_connector_print_state(p, connector->state); + if (take_locks) + drm_modeset_unlock(&dev->mode_config.connection_mutex); drm_connector_list_iter_end(&conn_iter); } + +/** + * drm_state_dump - dump entire device atomic state + * @dev: the drm device + * @p: where to print the state to + * + * Just for debugging. Drivers might want an option to dump state + * to dmesg in case of error irq's. (Hint, you probably want to + * ratelimit this!) + * + * The caller must drm_modeset_lock_all(), or if this is called + * from error irq handler, it should not be enabled by default. + * (Ie. if you are debugging errors you might not care that this + * is racey. But calling this without all modeset locks held is + * not inherently safe.) + */ +void drm_state_dump(struct drm_device *dev, struct drm_printer *p) +{ + __drm_state_dump(dev, p, false); +} EXPORT_SYMBOL(drm_state_dump); #ifdef CONFIG_DEBUG_FS @@ -1722,9 +1742,7 @@ static int drm_state_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_printer p = drm_seq_file_printer(m); - drm_modeset_lock_all(dev); - drm_state_dump(dev, &p); - drm_modeset_unlock_all(dev); + __drm_state_dump(dev, &p, true); return 0; } -- cgit v1.1 From eb8eb02ed850df95ba2224515b95eb311904e992 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:55 +0200 Subject: drm: Drop modeset_lock_all from the getproperty ioctl Properties, i.e. the struct drm_property specifying the type and value range of a property, not the instantiation on a given object, are invariant over the lifetime of a driver. Hence no locking at all is needed, we can just remove it. While at it give the function some love and simplify it, to get it under the 80 char limit: - Straighten the loops to reduce the nesting. - use u64_to_user_ptr casting helper - use put_user for fixed u64 copies. Note there's a small behavioural change in that we now copy parts of the values to userspace if the arrays are a bit too small. Since userspace will immediately retry anyway, this doesn't matter. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-7-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_property.c | 72 +++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index b17959c..3feef06 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -442,8 +442,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_property *property; int enum_count = 0; int value_count = 0; - int ret = 0, i; - int copied; + int i, copied; struct drm_property_enum *prop_enum; struct drm_mode_property_enum __user *enum_ptr; uint64_t __user *values_ptr; @@ -451,55 +450,43 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); property = drm_property_find(dev, out_resp->prop_id); - if (!property) { - ret = -ENOENT; - goto done; - } - - if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || - drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { - list_for_each_entry(prop_enum, &property->enum_list, head) - enum_count++; - } - - value_count = property->num_values; + if (!property) + return -ENOENT; strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); out_resp->name[DRM_PROP_NAME_LEN-1] = 0; out_resp->flags = property->flags; - if ((out_resp->count_values >= value_count) && value_count) { - values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; - for (i = 0; i < value_count; i++) { - if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { - ret = -EFAULT; - goto done; - } + value_count = property->num_values; + values_ptr = u64_to_user_ptr(out_resp->values_ptr); + + for (i = 0; i < value_count; i++) { + if (i < out_resp->count_values && + put_user(property->values[i], values_ptr + i)) { + return -EFAULT; } } out_resp->count_values = value_count; + copied = 0; + enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr); + if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || - drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { - if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { - copied = 0; - enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; - list_for_each_entry(prop_enum, &property->enum_list, head) { - - if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { - ret = -EFAULT; - goto done; - } - - if (copy_to_user(&enum_ptr[copied].name, - &prop_enum->name, DRM_PROP_NAME_LEN)) { - ret = -EFAULT; - goto done; - } - copied++; - } + drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { + list_for_each_entry(prop_enum, &property->enum_list, head) { + enum_count++; + if (out_resp->count_enum_blobs <= enum_count) + continue; + + if (copy_to_user(&enum_ptr[copied].value, + &prop_enum->value, sizeof(uint64_t))) + return -EFAULT; + + if (copy_to_user(&enum_ptr[copied].name, + &prop_enum->name, DRM_PROP_NAME_LEN)) + return -EFAULT; + copied++; } out_resp->count_enum_blobs = enum_count; } @@ -514,9 +501,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, */ if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) out_resp->count_enum_blobs = 0; -done: - drm_modeset_unlock_all(dev); - return ret; + + return 0; } static void drm_property_free_blob(struct kref *kref) -- cgit v1.1 From 04ee39ba9fff5bf6278328e2da1740001159c4c6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:56 +0200 Subject: drm: Only take crtc lock in get_gamma ioctl We don't call into drivers at all here, this is enough. Also, we can reduce the critical section a bit to simplify the code. crtc->gamma_size is set up once at driver load and then invariant, so also doesn't need any protection. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-8-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_color_mgmt.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index cc23b9a..a32be59 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -295,19 +295,15 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } + if (!crtc) + return -ENOENT; /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } + if (crtc_lut->gamma_size != crtc->gamma_size) + return -EINVAL; + drm_modeset_lock(&crtc->mutex, NULL); size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { @@ -327,6 +323,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, goto out; } out: - drm_modeset_unlock_all(dev); + drm_modeset_unlock(&crtc->mutex); return ret; } -- cgit v1.1 From 3fab2f09959d1ddffdb35d0c8c662cd58f2d587f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:57 +0200 Subject: drm/i915: Nuke intel_atomic_legacy_gamma_set We do set DRIVER_ATOMIC now. Note that the comment is outdated, the property paths switched over to checking drm_drv_uses_atomic_modeset() a while ago. Which means this can't even break if we revert DRIVER_ATOMIC again. v2: Add note that this is even safer (Maarten). Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-9-daniel.vetter@ffwll.ch --- drivers/gpu/drm/i915/intel_display.c | 44 +----------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 84abff3..f41a1f8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13098,50 +13098,8 @@ out: drm_atomic_state_put(state); } -/* - * FIXME: Remove this once i915 is fully DRIVER_ATOMIC by calling - * drm_atomic_helper_legacy_gamma_set() directly. - */ -static int intel_atomic_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - struct drm_crtc_state *state; - int ret; - - ret = drm_atomic_helper_legacy_gamma_set(crtc, red, green, blue, size); - if (ret) - return ret; - - /* - * Make sure we update the legacy properties so this works when - * atomic is not enabled. - */ - - state = crtc->state; - - drm_object_property_set_value(&crtc->base, - config->degamma_lut_property, - (state->degamma_lut) ? - state->degamma_lut->base.id : 0); - - drm_object_property_set_value(&crtc->base, - config->ctm_property, - (state->ctm) ? - state->ctm->base.id : 0); - - drm_object_property_set_value(&crtc->base, - config->gamma_lut_property, - (state->gamma_lut) ? - state->gamma_lut->base.id : 0); - - return 0; -} - static const struct drm_crtc_funcs intel_crtc_funcs = { - .gamma_set = intel_atomic_legacy_gamma_set, + .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_config = drm_atomic_helper_set_config, .set_property = drm_atomic_helper_crtc_set_property, .destroy = intel_crtc_destroy, -- cgit v1.1 From 9c79e0b1d096c06e4b012a32dddb04be0ce9716e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:32:59 +0200 Subject: drm/fb-helper: Give up on kgdb for atomic drivers It just doesn't work. It probably stopped working way, way before that (e.g. i915 grabbed random mutexes all over in modeset code at least since gen6), but with atomic and all the ww_mutex stuff it's indeed hopeless. Remove ->mode_set_base_atomic from the 2 atomic drivers (i915 and nouveau) that still had one (both had dummy implementations already anyway), and shunt atomic drivers in the helpers debug_enter/leave functions. I'll leave the code in for radeon and amdgpu, but I think as soon as amdgpu is atomic we should think about just ripping it out. Only having it around for radeon and pre-nv50 is rather pointless. This would also allow us to nuke all that code from fbdev. Funny part is that _all_ kms drivers set this hook, despite that no one else provides the required ->mode_set_base_atomic implementation. The reason I'm jumping on this is that I want to wire up a full acquire ctx for the benefit of atomic drivers, everywhere. And the debug_enter/leave implementations call ->gamma_set. And there's just no way ever we can create an acquire_ctx in the nmi context of kgdb. Cc: Ben Skeggs Cc: Alex Deucher Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-11-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_fb_helper.c | 6 ++++++ drivers/gpu/drm/i915/intel_display.c | 12 ------------ drivers/gpu/drm/nouveau/nv50_display.c | 10 ---------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 673a474..9147abb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -281,6 +281,9 @@ int drm_fb_helper_debug_enter(struct fb_info *info) if (funcs->mode_set_base_atomic == NULL) continue; + if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev)) + continue; + drm_fb_helper_save_lut_atomic(mode_set->crtc, helper); funcs->mode_set_base_atomic(mode_set->crtc, mode_set->fb, @@ -338,6 +341,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info) if (funcs->mode_set_base_atomic == NULL) continue; + if (drm_drv_uses_atomic_modeset(crtc->dev)) + continue; + drm_fb_helper_restore_lut_atomic(mode_set->crtc); funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, crtc->y, LEAVE_ATOMIC_MODE_SET); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f41a1f8..602fd47 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3439,17 +3439,6 @@ static void skylake_disable_primary_plane(struct drm_plane *primary, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } -/* Assume fb object is pinned & idle & fenced and just update base pointers */ -static int -intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, enum mode_set_atomic state) -{ - /* Support for kgdboc is disabled, this needs a major rework. */ - DRM_ERROR("legacy panic handler not supported any more.\n"); - - return -ENODEV; -} - static void intel_complete_page_flips(struct drm_i915_private *dev_priv) { struct intel_crtc *crtc; @@ -11005,7 +10994,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs intel_helper_funcs = { - .mode_set_base_atomic = intel_pipe_set_base_atomic, .atomic_begin = intel_begin_crtc_commit, .atomic_flush = intel_finish_crtc_commit, .atomic_check = intel_crtc_atomic_check, diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 418872b..3d381d5 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2210,18 +2210,8 @@ nv50_head_lut_load(struct drm_crtc *crtc) } } -static int -nv50_head_mode_set_base_atomic(struct drm_crtc *crtc, - struct drm_framebuffer *fb, int x, int y, - enum mode_set_atomic state) -{ - WARN_ON(1); - return 0; -} - static const struct drm_crtc_helper_funcs nv50_head_help = { - .mode_set_base_atomic = nv50_head_mode_set_base_atomic, .load_lut = nv50_head_lut_load, .atomic_check = nv50_head_atomic_check, }; -- cgit v1.1 From ca659e0e3cda69c5e8bbb7038adad30442a8ce39 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:33:00 +0200 Subject: drm: Add explicit acquire ctx handling around ->gamma_set Just the groundwork to prepare for adding the acquire cxt parameter to the ->gamma_set hook. Again we need a temporary hack to fill out mode_config.acquire_ctx until the atomic helpers are switched over. Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-12-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_color_mgmt.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index a32be59..e1b4084 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -218,28 +218,29 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; + struct drm_modeset_acquire_ctx ctx; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } + if (!crtc) + return -ENOENT; - if (crtc->funcs->gamma_set == NULL) { - ret = -ENOSYS; - goto out; - } + if (crtc->funcs->gamma_set == NULL) + return -ENOSYS; /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; + if (crtc_lut->gamma_size != crtc->gamma_size) + return -EINVAL; + + drm_modeset_acquire_init(&ctx, 0); + dev->mode_config.acquire_ctx = &ctx; +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) goto out; - } size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; @@ -263,7 +264,13 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); out: - drm_modeset_unlock_all(dev); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } -- cgit v1.1 From 6d124ff845334bc466f56c059147e7ad587c2e7e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:33:01 +0200 Subject: drm: Add acquire ctx to ->gamma_set hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atomic helpers really want this instead of the hacked-up legacy backoff trick, which unfortunately prevents drivers from using their own private drm_modeset_locks. Aside: There's a few atomic drivers (nv50, vc4, soon vmwgfx) which don't yet use the new atomic color mgmt/gamma table stuff. Would be nice if they could switch over and just hook up drm_atomic_helper_legacy_gamma_set() instead. Cc: Dave Airlie Cc: Alex Deucher Cc: Christian König Cc: Gerd Hoffmann Cc: Ben Skeggs Cc: Sinclair Yeh Cc: Thomas Hellstrom Cc: Eric Anholt Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Reviewed-by: Sinclair Yeh Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-13-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 3 ++- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 3 ++- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 3 ++- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 3 ++- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 3 ++- drivers/gpu/drm/ast/ast_mode.c | 3 ++- drivers/gpu/drm/cirrus/cirrus_mode.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 4 +++- drivers/gpu/drm/drm_color_mgmt.c | 3 ++- drivers/gpu/drm/drm_fb_helper.c | 3 ++- drivers/gpu/drm/gma500/gma_display.c | 3 ++- drivers/gpu/drm/gma500/gma_display.h | 3 ++- drivers/gpu/drm/mgag200/mgag200_mode.c | 3 ++- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 3 ++- drivers/gpu/drm/nouveau/nv50_display.c | 3 ++- drivers/gpu/drm/radeon/radeon_display.c | 3 ++- drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 3 ++- include/drm/drm_atomic_helper.h | 3 ++- include/drm/drm_crtc.h | 3 ++- 21 files changed, 43 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index f525ae4..daf003d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2631,7 +2631,8 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v10_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 3eac27f..3a72967 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2651,7 +2651,8 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v11_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 838cf1a..8ccada5 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1998,7 +1998,8 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v6_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 1b0717b11..6943f26 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2482,7 +2482,8 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v8_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 5c51f9a..81a24b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -165,7 +165,8 @@ static void dce_virtual_bandwidth_update(struct amdgpu_device *adev) } static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, - u16 *green, u16 *blue, uint32_t size) + u16 *green, u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 47b78e5..aaef0a6 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -645,7 +645,8 @@ static void ast_crtc_reset(struct drm_crtc *crtc) } static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct ast_crtc *ast_crtc = to_ast_crtc(crtc); int i; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index ed43ab1..53f6f0f 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -327,7 +327,8 @@ static void cirrus_crtc_commit(struct drm_crtc *crtc) * but it's a requirement that we provide the function */ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); int i; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0a3d91c..25569e5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3479,6 +3479,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); * @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 @@ -3486,7 +3487,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); */ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct drm_mode_config *config = &dev->mode_config; diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index e1b4084..b81dcb1 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -261,7 +261,8 @@ retry: goto out; } - ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, + crtc->gamma_size, &ctx); out: if (ret == -EDEADLK) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9147abb..6dc5381 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -256,7 +256,8 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) g_base = r_base + crtc->gamma_size; b_base = g_base + crtc->gamma_size; - crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, + crtc->gamma_size, NULL); } /** diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 93ff465..e7fd356 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -177,7 +177,8 @@ void gma_crtc_load_lut(struct drm_crtc *crtc) } int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, - u32 size) + u32 size, + struct drm_modeset_acquire_ctx *ctx) { struct gma_crtc *gma_crtc = to_gma_crtc(crtc); int i; diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 166e608..239c374 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -73,7 +73,8 @@ extern int gma_crtc_cursor_set(struct drm_crtc *crtc, extern int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); extern void gma_crtc_load_lut(struct drm_crtc *crtc); extern int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, u32 size); + u16 *blue, u32 size, + struct drm_modeset_acquire_ctx *ctx); extern void gma_crtc_dpms(struct drm_crtc *crtc, int mode); extern void gma_crtc_prepare(struct drm_crtc *crtc); extern void gma_crtc_commit(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index f2e9b2b..adb411a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1393,7 +1393,8 @@ static void mga_crtc_commit(struct drm_crtc *crtc) * but it's a requirement that we provide the function */ static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct mga_crtc *mga_crtc = to_mga_crtc(crtc); int i; diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 43ab560..4b4b0b4 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -788,7 +788,8 @@ nv_crtc_disable(struct drm_crtc *crtc) static int nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int i; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 3d381d5..bf50478 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2218,7 +2218,8 @@ nv50_head_help = { static int nv50_head_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); u32 i; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 146297a..981385e 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -232,7 +232,8 @@ void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, } static int radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); int i; diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index e8f28c9..d86c8cc 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -314,7 +314,8 @@ vc4_crtc_lut_load(struct drm_crtc *crtc) static int vc4_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); u32 i; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6078654..ef9f3a2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2026,7 +2026,8 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, int vmw_du_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); int i; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 0c226b2..13f2f1d2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -254,7 +254,8 @@ void vmw_du_crtc_save(struct drm_crtc *crtc); void vmw_du_crtc_restore(struct drm_crtc *crtc); int vmw_du_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size); + uint32_t size, + struct drm_modeset_acquire_ctx *ctx); int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index fd395dc..f0a8678 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -176,7 +176,8 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state); int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, - uint32_t size); + uint32_t size, + struct drm_modeset_acquire_ctx *ctx); /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index ede60d6..a8176a8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -322,7 +322,8 @@ struct drm_crtc_funcs { * hooks. */ int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size); + uint32_t size, + struct drm_modeset_acquire_ctx *ctx); /** * @destroy: -- cgit v1.1 From 3a09f737ee056e022b4c3285852c663e9d294911 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:33:02 +0200 Subject: drm/atomic-helper: Remove legacy backoff hack from gamma_set Another one knocked down. With this we can also remove the temporary hack in the gamma_set ioctl. Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-14-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 13 ++----------- drivers/gpu/drm/drm_color_mgmt.c | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 25569e5..a90d67b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3519,8 +3519,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, blob_data[i].blue = blue[i]; } - state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; -retry: + state->acquire_ctx = ctx; crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) { ret = PTR_ERR(crtc_state); @@ -3544,18 +3543,10 @@ retry: goto fail; ret = drm_atomic_commit(state); -fail: - if (ret == -EDEADLK) - goto backoff; +fail: drm_atomic_state_put(state); drm_property_blob_put(blob); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index b81dcb1..533f3a3 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -236,7 +236,6 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, return -EINVAL; drm_modeset_acquire_init(&ctx, 0); - dev->mode_config.acquire_ctx = &ctx; retry: ret = drm_modeset_lock_all_ctx(dev, &ctx); if (ret) -- cgit v1.1 From 941b8caaa88db02d7c287e937182a71de2751cbb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:33:03 +0200 Subject: drm: extract legacy framebuffer remove I got confused every time I audited what that lock_all is doing in there until realizing it's for legacy kms only. Make that a notch more obvious by having 2 entirely different paths. While at it also move the atomic version of this into drm_framebuffer.c, there's no reason it needs to be in drm_atomic.c. That way it becomes a simple static function. Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-15-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic.c | 88 ----------------------- drivers/gpu/drm/drm_crtc_internal.h | 1 - drivers/gpu/drm/drm_framebuffer.c | 137 ++++++++++++++++++++++++++++++------ 3 files changed, 115 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9afb143..f32506a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -2081,94 +2081,6 @@ static void complete_crtc_signaling(struct drm_device *dev, kfree(fence_state); } -int drm_atomic_remove_fb(struct drm_framebuffer *fb) -{ - struct drm_modeset_acquire_ctx ctx; - struct drm_device *dev = fb->dev; - struct drm_atomic_state *state; - struct drm_plane *plane; - struct drm_connector *conn; - struct drm_connector_state *conn_state; - int i, ret = 0; - unsigned plane_mask; - - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - - drm_modeset_acquire_init(&ctx, 0); - state->acquire_ctx = &ctx; - -retry: - plane_mask = 0; - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (ret) - goto unlock; - - drm_for_each_plane(plane, dev) { - struct drm_plane_state *plane_state; - - if (plane->state->fb != fb) - continue; - - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - ret = PTR_ERR(plane_state); - goto unlock; - } - - if (plane_state->crtc->primary == plane) { - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); - - ret = drm_atomic_add_affected_connectors(state, plane_state->crtc); - if (ret) - goto unlock; - - crtc_state->active = false; - ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); - if (ret) - goto unlock; - } - - drm_atomic_set_fb_for_plane(plane_state, NULL); - ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); - if (ret) - goto unlock; - - plane_mask |= BIT(drm_plane_index(plane)); - - plane->old_fb = plane->fb; - } - - for_each_connector_in_state(state, conn, conn_state, i) { - ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); - - if (ret) - goto unlock; - } - - if (plane_mask) - ret = drm_atomic_commit(state); - -unlock: - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); - - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } - - drm_atomic_state_put(state); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} - int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 8c04275..d077c54 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -182,7 +182,6 @@ int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_atomic_remove_fb(struct drm_framebuffer *fb); /* drm_plane.c */ diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index e8f9c13..fc8ef42 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" @@ -755,6 +756,117 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_cleanup); +static int atomic_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_device *dev = fb->dev; + struct drm_atomic_state *state; + struct drm_plane *plane; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + int i, ret = 0; + unsigned plane_mask; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); + state->acquire_ctx = &ctx; + +retry: + plane_mask = 0; + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) + goto unlock; + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + if (plane->state->fb != fb) + continue; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto unlock; + } + + if (plane_state->crtc->primary == plane) { + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); + + ret = drm_atomic_add_affected_connectors(state, plane_state->crtc); + if (ret) + goto unlock; + + crtc_state->active = false; + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret) + goto unlock; + } + + drm_atomic_set_fb_for_plane(plane_state, NULL); + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret) + goto unlock; + + plane_mask |= BIT(drm_plane_index(plane)); + + plane->old_fb = plane->fb; + } + + for_each_connector_in_state(state, conn, conn_state, i) { + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); + + if (ret) + goto unlock; + } + + if (plane_mask) + ret = drm_atomic_commit(state); + +unlock: + if (plane_mask) + drm_atomic_clean_old_fb(dev, plane_mask, ret); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +static void legacy_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + struct drm_crtc *crtc; + struct drm_plane *plane; + + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + if (drm_crtc_force_disable(crtc)) + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + } + } + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } + drm_modeset_unlock_all(dev); +} + /** * drm_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove @@ -770,8 +882,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); void drm_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_plane *plane; if (!fb) return; @@ -797,29 +907,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) */ if (drm_framebuffer_read_refcount(fb) > 1) { if (drm_drv_uses_atomic_modeset(dev)) { - int ret = drm_atomic_remove_fb(fb); + int ret = atomic_remove_fb(fb); WARN(ret, "atomic remove_fb failed with %i\n", ret); - goto out; - } - - drm_modeset_lock_all(dev); - /* remove from any CRTC */ - drm_for_each_crtc(crtc, dev) { - if (crtc->primary->fb == fb) { - /* should turn off the crtc */ - if (drm_crtc_force_disable(crtc)) - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); - } - } - - drm_for_each_plane(plane, dev) { - if (plane->fb == fb) - drm_plane_force_disable(plane); - } - drm_modeset_unlock_all(dev); + } else + legacy_remove_fb(fb); } -out: drm_framebuffer_put(fb); } EXPORT_SYMBOL(drm_framebuffer_remove); -- cgit v1.1 From 7128645d5c647ba3fe1684f2d5710ee403babca2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Apr 2017 10:33:04 +0200 Subject: drm/fb-helper: Extract _legacy kms functions The goal is to push all the kms locking down into these separate _atomic and _legacy functions, so that we can correctly pass the acquire ctx into all atomic drivers. Instead of playing games with hidden ctx in mode_config.acquire_ctx. All the fbdev state will be protected by a new fbdev private lock that Thierry is working on. This here is just prep by creating a clean split between atomic and legacy paths, which also simplifies the control flow a bit. Reviewed-by: Maarten Lankhorst Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170403083304.9083-16-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_fb_helper.c | 72 +++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 6dc5381..a0ea324 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -418,17 +418,12 @@ backoff: goto retry; } -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) +static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; struct drm_plane *plane; int i; - drm_warn_on_modeset_not_all_locked(dev); - - if (drm_drv_uses_atomic_modeset(dev)) - return restore_fbdev_mode_atomic(fb_helper); - drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -462,6 +457,18 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) return 0; } +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) +{ + struct drm_device *dev = fb_helper->dev; + + drm_warn_on_modeset_not_all_locked(dev); + + if (drm_drv_uses_atomic_modeset(dev)) + return restore_fbdev_mode_atomic(fb_helper); + else + return restore_fbdev_mode_legacy(fb_helper); +} + /** * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration * @fb_helper: fbcon to restore @@ -1513,34 +1520,14 @@ backoff: goto retry; } -/** - * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display - * @var: updated screen information - * @info: fbdev registered by the helper - */ -int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, +static int pan_display_legacy(struct fb_var_screeninfo *var, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; struct drm_mode_set *modeset; int ret = 0; int i; - if (oops_in_progress) - return -EBUSY; - - drm_modeset_lock_all(dev); - if (!drm_fb_helper_is_bound(fb_helper)) { - drm_modeset_unlock_all(dev); - return -EBUSY; - } - - if (drm_drv_uses_atomic_modeset(dev)) { - ret = pan_display_atomic(var, info); - goto unlock; - } - for (i = 0; i < fb_helper->crtc_count; i++) { modeset = &fb_helper->crtc_info[i].mode_set; @@ -1555,8 +1542,37 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, } } } -unlock: + + return ret; +} + +/** + * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display + * @var: updated screen information + * @info: fbdev registered by the helper + */ +int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_device *dev = fb_helper->dev; + int ret; + + if (oops_in_progress) + return -EBUSY; + + drm_modeset_lock_all(dev); + if (!drm_fb_helper_is_bound(fb_helper)) { + drm_modeset_unlock_all(dev); + return -EBUSY; + } + + if (drm_drv_uses_atomic_modeset(dev)) + ret = pan_display_atomic(var, info); + else + ret = pan_display_legacy(var, info); drm_modeset_unlock_all(dev); + return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); -- cgit v1.1 From 4c67b20c98a1a711cc010bff4927129d82a851c7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Apr 2017 09:32:59 +0200 Subject: drm: bridge: dw-hdmi: remove unused hdmi_bus_fmt_is_yuv420 Remove usused yet hdmi_bus_fmt_is_yuv420 function. Fixes: def23aa7e982 ("drm: bridge: dw-hdmi: Switch to V4L bus format and encodings") Signed-off-by: Neil Armstrong Acked-by: Laurent Pinchart Link: http://patchwork.freedesktop.org/patch/msgid/1491377579-9353-1-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 84cc949..7dd6699 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -605,20 +605,6 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) } } -static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format) -{ - switch (bus_format) { - case MEDIA_BUS_FMT_UYYVYY8_0_5X24: - case MEDIA_BUS_FMT_UYYVYY10_0_5X30: - case MEDIA_BUS_FMT_UYYVYY12_0_5X36: - case MEDIA_BUS_FMT_UYYVYY16_0_5X48: - return true; - - default: - return false; - } -} - static int hdmi_bus_fmt_color_depth(unsigned int bus_format) { switch (bus_format) { -- cgit v1.1 From f40d6560eba65b2a2b84805d2927fed96978669a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Apr 2017 08:21:32 +0300 Subject: drm: bridge: dw-hdmi: Add a missing break statement There was supposed to be a break before the next case statement. Fixes: def23aa7e982 ("drm: bridge: dw-hdmi: Switch to V4L bus format and encodings") Signed-off-by: Dan Carpenter Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: http://patchwork.freedesktop.org/patch/msgid/20170406052132.GA26605@mwanda --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 7dd6699..5dc5a5f 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1304,6 +1304,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) frame.colorimetry = HDMI_COLORIMETRY_ITU_601; frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; case V4L2_YCBCR_ENC_709: if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; -- cgit v1.1 From 99748ab64fcc857837acfd754b530487a490edb5 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 5 Apr 2017 10:09:15 +0200 Subject: drm: virtio: fix virtio_gpu_cursor_formats When we use virtio-vga with a big-endian guest, the mouse pointer disappears. To fix that, on big-endian use DRM_FORMAT_BGRA8888 instead of DRM_FORMAT_ARGB8888. Signed-off-by: Laurent Vivier Link: http://patchwork.freedesktop.org/patch/msgid/20170405080915.823-1-lvivier@redhat.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_plane.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 372c91c..adcdbd0 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -39,7 +39,11 @@ static const uint32_t virtio_gpu_formats[] = { }; static const uint32_t virtio_gpu_cursor_formats[] = { +#ifdef __BIG_ENDIAN + DRM_FORMAT_BGRA8888, +#else DRM_FORMAT_ARGB8888, +#endif }; uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc) -- cgit v1.1 From 6c5ed5ae353cdf156f9ac4db17e15db56b4de880 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Apr 2017 20:55:20 +0200 Subject: drm/atomic: Acquire connection_mutex lock in drm_helper_probe_single_connector_modes, v4. mode_valid() called from drm_helper_probe_single_connector_modes() may need to look at connector->state because what a valid mode is may depend on connector properties being set. For example some HDMI modes might be rejected when a connector property forces the connector into DVI mode. Some implementations of detect() already lock all state, so we have to pass an acquire_ctx to them to prevent a deadlock. This means changing the function signature of detect() slightly, and passing the acquire_ctx for locking multiple crtc's. For the callbacks, it will always be non-zero. To allow callers not to worry about this, drm_helper_probe_detect_ctx is added which might handle -EDEADLK for you. Changes since v1: - Always set ctx parameter. Changes since v2: - Always take connection_mutex when probing. Changes since v3: - Remove the ctx from intel_dp_long_pulse, and add WARN_ON(!connection_mutex) (danvet) - Update docs to clarify the locking situation. (danvet) Signed-off-by: Maarten Lankhorst Cc: Boris Brezillon Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1491504920-4017-1-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_probe_helper.c | 100 ++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_crt.c | 25 ++++---- drivers/gpu/drm/i915/intel_display.c | 25 ++++---- drivers/gpu/drm/i915/intel_dp.c | 21 +++---- drivers/gpu/drm/i915/intel_drv.h | 8 +-- drivers/gpu/drm/i915/intel_hotplug.c | 3 +- drivers/gpu/drm/i915/intel_tv.c | 21 +++---- include/drm/drm_connector.h | 6 ++ include/drm/drm_crtc_helper.h | 3 + include/drm/drm_modeset_helper_vtables.h | 36 +++++++++++ 10 files changed, 187 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index efb5e5e..1b0c14a 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -169,12 +169,73 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) EXPORT_SYMBOL(drm_kms_helper_poll_enable); static enum drm_connector_status -drm_connector_detect(struct drm_connector *connector, bool force) +drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force) { - return connector->funcs->detect ? - connector->funcs->detect(connector, force) : - connector_status_connected; + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex, &ctx); + if (!ret) { + if (funcs->detect_ctx) + ret = funcs->detect_ctx(connector, &ctx, force); + else if (connector->funcs->detect) + ret = connector->funcs->detect(connector, force); + else + ret = connector_status_connected; + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + if (WARN_ON(ret < 0)) + ret = connector_status_unknown; + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +/** + * drm_helper_probe_detect - probe connector status + * @connector: connector to probe + * @ctx: acquire_ctx, or NULL to let this function handle locking. + * @force: Whether destructive probe operations should be performed. + * + * This function calls the detect callbacks of the connector. + * This function returns &drm_connector_status, or + * if @ctx is set, it might also return -EDEADLK. + */ +int +drm_helper_probe_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + struct drm_device *dev = connector->dev; + int ret; + + if (!ctx) + return drm_helper_probe_detect_ctx(connector, force); + + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); + if (ret) + return ret; + + if (funcs->detect_ctx) + return funcs->detect_ctx(connector, ctx, force); + else if (connector->funcs->detect) + return connector->funcs->detect(connector, force); + else + return connector_status_connected; } +EXPORT_SYMBOL(drm_helper_probe_detect); /** * drm_helper_probe_single_connector_modes - get complete set of display modes @@ -239,15 +300,27 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, struct drm_display_mode *mode; const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; - int count = 0; + int count = 0, ret; int mode_flags = 0; bool verbose_prune = true; enum drm_connector_status old_status; + struct drm_modeset_acquire_ctx ctx; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + drm_modeset_acquire_init(&ctx, 0); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + +retry: + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else + WARN_ON(ret < 0); + /* set all old modes to the stale state */ list_for_each_entry(mode, &connector->modes, head) mode->status = MODE_STALE; @@ -263,7 +336,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->funcs->force) connector->funcs->force(connector); } else { - connector->status = drm_connector_detect(connector, true); + ret = drm_helper_probe_detect(connector, &ctx, true); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN(ret < 0, "Invalid return value %i for connector detection\n", ret)) + ret = connector_status_unknown; + + connector->status = ret; } /* @@ -355,6 +436,9 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, prune: drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + if (list_empty(&connector->modes)) return 0; @@ -440,7 +524,7 @@ static void output_poll_execute(struct work_struct *work) repoll = true; - connector->status = drm_connector_detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); if (old_status != connector->status) { const char *old, *new; @@ -588,7 +672,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) old_status = connector->status; - connector->status = drm_connector_detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", connector->base.id, connector->name, diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8c82607..2797bf3 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -669,15 +669,16 @@ static const struct dmi_system_id intel_spurious_crt_detect[] = { { } }; -static enum drm_connector_status -intel_crt_detect(struct drm_connector *connector, bool force) +static int +intel_crt_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_crt *crt = intel_attached_crt(connector); struct intel_encoder *intel_encoder = &crt->base; - enum drm_connector_status status; + int status, ret; struct intel_load_detect_pipe tmp; - struct drm_modeset_acquire_ctx ctx; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", connector->base.id, connector->name, @@ -721,10 +722,9 @@ intel_crt_detect(struct drm_connector *connector, bool force) goto out; } - drm_modeset_acquire_init(&ctx, 0); - /* for pre-945g platforms use load detect */ - if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { + ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx); + if (ret > 0) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else if (INTEL_GEN(dev_priv) < 4) @@ -734,12 +734,11 @@ intel_crt_detect(struct drm_connector *connector, bool force) status = connector_status_disconnected; else status = connector_status_unknown; - intel_release_load_detect_pipe(connector, &tmp, &ctx); - } else + intel_release_load_detect_pipe(connector, &tmp, ctx); + } else if (ret == 0) status = connector_status_unknown; - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + else if (ret < 0) + status = ret; out: intel_display_power_put(dev_priv, intel_encoder->power_domain); @@ -811,7 +810,6 @@ void intel_crt_reset(struct drm_encoder *encoder) static const struct drm_connector_funcs intel_crt_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_crt_detect, .fill_modes = drm_helper_probe_single_connector_modes, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, @@ -823,6 +821,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { + .detect_ctx = intel_crt_detect, .mode_valid = intel_crt_mode_valid, .get_modes = intel_crt_get_modes, }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 602fd47..e217d04 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9480,10 +9480,10 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state, return 0; } -bool intel_get_load_detect_pipe(struct drm_connector *connector, - struct drm_display_mode *mode, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx) +int intel_get_load_detect_pipe(struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old, + struct drm_modeset_acquire_ctx *ctx) { struct intel_crtc *intel_crtc; struct intel_encoder *intel_encoder = @@ -9506,10 +9506,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, old->restore_state = NULL; -retry: - ret = drm_modeset_lock(&config->connection_mutex, ctx); - if (ret) - goto fail; + WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); /* * Algorithm gets a little messy: @@ -9659,10 +9656,8 @@ fail: restore_state = NULL; } - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } + if (ret == -EDEADLK) + return ret; return false; } @@ -15030,6 +15025,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) struct drm_connector *crt = NULL; struct intel_load_detect_pipe load_detect_temp; struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx; + int ret; /* We can't just switch on the pipe A, we need to set things up with a * proper mode and output configuration. As a gross hack, enable pipe A @@ -15046,7 +15042,10 @@ static void intel_enable_pipe_a(struct drm_device *dev) if (!crt) return; - if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx)) + ret = intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx); + WARN(ret < 0, "All modeset mutexes are locked, but intel_get_load_detect_pipe failed\n"); + + if (ret > 0) intel_release_load_detect_pipe(crt, &load_detect_temp, ctx); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fd96a6c..6e04cb5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4566,7 +4566,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->has_audio = false; } -static enum drm_connector_status +static int intel_dp_long_pulse(struct intel_connector *intel_connector) { struct drm_connector *connector = &intel_connector->base; @@ -4577,6 +4577,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) enum drm_connector_status status; u8 sink_irq_vector = 0; + WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.connection_mutex)); + intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain); /* Can't disconnect eDP, but you can close the lid... */ @@ -4635,14 +4637,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) status = connector_status_disconnected; goto out; } else if (connector->status == connector_status_connected) { - /* - * If display was connected already and is still connected - * check links status, there has been known issues of - * link loss triggerring long pulse!!!! - */ - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); intel_dp_check_link_status(intel_dp); - drm_modeset_unlock(&dev->mode_config.connection_mutex); goto out; } @@ -4682,11 +4677,13 @@ out: return status; } -static enum drm_connector_status -intel_dp_detect(struct drm_connector *connector, bool force) +static int +intel_dp_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct intel_dp *intel_dp = intel_attached_dp(connector); - enum drm_connector_status status = connector->status; + int status = connector->status; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -5014,7 +5011,6 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder) static const struct drm_connector_funcs intel_dp_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_dp_detect, .force = intel_dp_force, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_dp_set_property, @@ -5027,6 +5023,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { + .detect_ctx = intel_dp_detect, .get_modes = intel_dp_get_modes, .mode_valid = intel_dp_mode_valid, }; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 51228fe..fb7afcf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1353,10 +1353,10 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); void vlv_wait_port_ready(struct drm_i915_private *dev_priv, struct intel_digital_port *dport, unsigned int expected_mask); -bool intel_get_load_detect_pipe(struct drm_connector *connector, - struct drm_display_mode *mode, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx); +int intel_get_load_detect_pipe(struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old, + struct drm_modeset_acquire_ctx *ctx); void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 7d21009..f120027 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -243,7 +243,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev, WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); old_status = connector->status; - connector->status = connector->funcs->detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); + if (old_status == connector->status) return false; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 6ed1a3c..e077c2a 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1315,8 +1315,10 @@ static void intel_tv_find_better_format(struct drm_connector *connector) * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure * we have a pipe programmed in order to probe the TV. */ -static enum drm_connector_status -intel_tv_detect(struct drm_connector *connector, bool force) +static int +intel_tv_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct drm_display_mode mode; struct intel_tv *intel_tv = intel_attached_tv(connector); @@ -1331,21 +1333,20 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (force) { struct intel_load_detect_pipe tmp; - struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_acquire_init(&ctx, 0); + ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx); + if (ret < 0) + return ret; - if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { + if (ret > 0) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp, ctx); status = type < 0 ? connector_status_disconnected : connector_status_connected; } else status = connector_status_unknown; - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); } else return connector->status; @@ -1516,7 +1517,6 @@ out: static const struct drm_connector_funcs intel_tv_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_tv_detect, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, .destroy = intel_tv_destroy, @@ -1528,6 +1528,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { + .detect_ctx = intel_tv_detect, .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, }; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 941f57f..e2ee74c 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -32,6 +32,7 @@ struct drm_device; struct drm_connector_helper_funcs; +struct drm_modeset_acquire_ctx; struct drm_device; struct drm_crtc; struct drm_encoder; @@ -378,6 +379,11 @@ struct drm_connector_funcs { * the helper library vtable purely for historical reasons. The only DRM * core entry point to probe connector state is @fill_modes. * + * Note that the helper library will already hold + * &drm_mode_config.connection_mutex. Drivers which need to grab additional + * locks to avoid races with concurrent modeset changes need to use + * &drm_connector_helper_funcs.detect_ctx instead. + * * RETURNS: * * drm_connector_status indicating the connector's status. diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 43505c7..76e237b 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -67,6 +67,9 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); +int drm_helper_probe_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force); void drm_kms_helper_poll_init(struct drm_device *dev); void drm_kms_helper_poll_fini(struct drm_device *dev); bool drm_helper_hpd_irq_event(struct drm_device *dev); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 091c422..7847bab 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -747,6 +747,10 @@ struct drm_connector_helper_funcs { * This callback is used by the probe helpers in e.g. * drm_helper_probe_single_connector_modes(). * + * To avoid races with concurrent connector state updates, the helper + * libraries always call this with the &drm_mode_config.connection_mutex + * held. Because of this it's safe to inspect &drm_connector->state. + * * RETURNS: * * The number of modes added by calling drm_mode_probed_add(). @@ -754,6 +758,34 @@ struct drm_connector_helper_funcs { int (*get_modes)(struct drm_connector *connector); /** + * @detect_ctx: + * + * Check to see if anything is attached to the connector. The parameter + * force is set to false whilst polling, true when checking the + * connector due to a user request. force can be used by the driver to + * avoid expensive, destructive operations during automated probing. + * + * This callback is optional, if not implemented the connector will be + * considered as always being attached. + * + * This is the atomic version of &drm_connector_funcs.detect. + * + * To avoid races against concurrent connector state updates, the + * helper libraries always call this with ctx set to a valid context, + * and &drm_mode_config.connection_mutex will always be locked with + * the ctx parameter set to this ctx. This allows taking additional + * locks as required. + * + * RETURNS: + * + * &drm_connector_status indicating the connector's status, + * or the error code returned by drm_modeset_lock(), -EDEADLK. + */ + int (*detect_ctx)(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force); + + /** * @mode_valid: * * Callback to validate a mode for a connector, irrespective of the @@ -771,6 +803,10 @@ struct drm_connector_helper_funcs { * CRTC helpers will not call this function. Drivers therefore must * still fully validate any mode passed in in a modeset request. * + * To avoid races with concurrent connector state updates, the helper + * libraries always call this with the &drm_mode_config.connection_mutex + * held. Because of this it's safe to inspect &drm_connector->state. + * * RETURNS: * * Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum -- cgit v1.1 From 53552d5df6694f68f276b2e86f8162d0ef7cad93 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Apr 2017 21:06:54 +0200 Subject: drm: Take mode_config.mutex in setcrtc ioctl Legacy drivers insist that we really take all the locks in this path, and the harm in doing so is minimal. v2: Like git add, it exists :( Fixes: 2ceb585a956c ("drm: Add explicit acquire ctx handling around ->set_config") Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Vetter Cc: Jani Nikula Cc: Sean Paul Cc: David Airlie Cc: dri-devel@lists.freedesktop.org Cc: Alex Deucher Reported-by: Alex Deucher Acked-and-tested-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170406190654.6733-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d69e180..5af25ce 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -576,6 +576,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, } DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + mutex_lock(&crtc->dev->mode_config.mutex); drm_modeset_acquire_init(&ctx, 0); retry: ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); @@ -721,6 +722,7 @@ out: } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + mutex_unlock(&crtc->dev->mode_config.mutex); return ret; } -- cgit v1.1 From 44596b8c4750d9a2323f52aecdeecf34f6aaa2e0 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Apr 2017 13:19:00 +0200 Subject: drm/atomic: Unify conflicting encoder handling. Currently we use a flag to change behavior in atomic commit whether a conflicting encoder should be enabled or disabled. This is used for the legacy set_config helper, which disables connectors that have a conflicting encoder but not part of the active crtc list. There's no need for this to be handled in atomic commit, it could be done in the set_config helper instead. This will let the atomic check function reject any conflicting encoders, while set_config can disable conflicting crtc's. This makes it possible to recalculate the changed flags in 1 loop. Signed-off-by: Maarten Lankhorst Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491477543-31257-2-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 7 +++++-- include/drm/drm_atomic.h | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index a90d67b..37a7fc7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -517,7 +517,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, } } - ret = handle_conflicting_encoders(state, state->legacy_set_config); + ret = handle_conflicting_encoders(state, false); if (ret) return ret; @@ -2289,12 +2289,15 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set, if (!state) return -ENOMEM; - state->legacy_set_config = true; state->acquire_ctx = ctx; ret = __drm_atomic_helper_set_config(set, state); if (ret != 0) goto fail; + ret = handle_conflicting_encoders(state, true); + if (ret) + return ret; + ret = drm_atomic_commit(state); fail: diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index fd33ed5..788daf7 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -160,7 +160,6 @@ struct __drm_connnectors_state { * @dev: parent DRM device * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics - * @legacy_set_config: Disable conflicting encoders instead of failing with -EINVAL. * @planes: pointer to array of structures with per-plane data * @crtcs: pointer to array of CRTC pointers * @num_connector: size of the @connectors and @connector_states arrays @@ -173,7 +172,6 @@ struct drm_atomic_state { struct drm_device *dev; bool allow_modeset : 1; bool legacy_cursor_update : 1; - bool legacy_set_config : 1; struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; -- cgit v1.1 From 24d6652c1508ccb530726ad8065de92ac31f2449 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Apr 2017 13:19:01 +0200 Subject: drm/atomic: Set all the changed flags in one place. Now that handle_conflicting_encoders cannot disable crtc's any more it makes sense to set all the changed flags in 1 place. This makes the code slightly less magical. The (now removed) comment is out of date. The only reason the active_changed was set late was because handle_conflicting_encoders could disable connectors. This is no longer the case, and we can put everything in 1 place. Signed-off-by: Maarten Lankhorst Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491477543-31257-3-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 37a7fc7..2d50682 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -515,6 +515,12 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_crtc_state->mode_changed = true; new_crtc_state->connectors_changed = true; } + + if (old_crtc_state->active != new_crtc_state->active) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n", + crtc->base.id, crtc->name); + new_crtc_state->active_changed = true; + } } ret = handle_conflicting_encoders(state, false); @@ -551,17 +557,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, bool has_connectors = !!new_crtc_state->connector_mask; - /* - * We must set ->active_changed after walking connectors for - * otherwise an update that only changes active would result in - * a full modeset because update_connector_routing force that. - */ - if (old_crtc_state->active != new_crtc_state->active) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n", - crtc->base.id, crtc->name); - new_crtc_state->active_changed = true; - } - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; -- cgit v1.1 From 970ece83fdd46cb4fa834a4d5adfdf746e4174b2 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Apr 2017 13:19:02 +0200 Subject: drm/atomic: Move enable/connector check up in check_modeset() Now that handle_conflicting_encoders no longer touches active state, so there's no need to do the check quite that late any more. Doing it with all the other checks makes it a lot more clear what the below block tries to accomplish, and this feels like a better place to put the check. Signed-off-by: Maarten Lankhorst Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491477543-31257-4-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 2d50682..ff3c6eb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -494,6 +494,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, int i, ret; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + bool has_connectors = + !!new_crtc_state->connector_mask; + if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n", crtc->base.id, crtc->name); @@ -521,6 +524,13 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, crtc->base.id, crtc->name); new_crtc_state->active_changed = true; } + + if (new_crtc_state->enable != has_connectors) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n", + crtc->base.id, crtc->name); + + return -EINVAL; + } } ret = handle_conflicting_encoders(state, false); @@ -554,9 +564,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, * crtc only changed its mode but has the same set of connectors. */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - bool has_connectors = - !!new_crtc_state->connector_mask; - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; @@ -572,13 +579,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, ret = drm_atomic_add_affected_planes(state, crtc); if (ret != 0) return ret; - - if (new_crtc_state->enable != has_connectors) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n", - crtc->base.id, crtc->name); - - return -EINVAL; - } } return mode_fixup(state); -- cgit v1.1 From ce09d7667dd225564df1e20b8185d4ce7be886cc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Apr 2017 13:19:03 +0200 Subject: drm/atomic: Add connector atomic_check function, v2. The atomic_check function is useful for implementing properties, but it can be used for other connector modeset related checks as well. Similar to plane check functions, on a modeset atomic_check() is always called. Changes since v1: - Make sure atomic_check() is called on any modeset. Signed-off-by: Maarten Lankhorst Reviewed-by: Dhinakaran Pandiyan Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491477543-31257-5-git-send-email-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_atomic_helper.c | 44 +++++++++++++++++++++++++++++--- include/drm/drm_modeset_helper_vtables.h | 34 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ff3c6eb..8be9719 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -459,10 +459,20 @@ mode_fixup(struct drm_atomic_state *state) * * Check the state object to see if the requested state is physically possible. * This does all the crtc and connector related computations for an atomic - * update and adds any additional connectors needed for full modesets and calls - * down into &drm_crtc_helper_funcs.mode_fixup and - * &drm_encoder_helper_funcs.mode_fixup or - * &drm_encoder_helper_funcs.atomic_check functions of the driver backend. + * update and adds any additional connectors needed for full modesets. It calls + * the various per-object callbacks in the follow order: + * + * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder. + * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state. + * 3. If it's determined a modeset is needed then all connectors on the affected crtc + * crtc are added and &drm_connector_helper_funcs.atomic_check is run on them. + * 4. &drm_bridge_funcs.mode_fixup is called on all encoder bridges. + * 5. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state. + * This function is only called when the encoder will be part of a configured crtc, + * it must not be used for implementing connector property validation. + * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called + * instead. + * 6. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints. * * &drm_crtc_state.mode_changed is set when the input mode is changed. * &drm_crtc_state.connectors_changed is set when a connector is added or @@ -492,6 +502,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_connector *connector; struct drm_connector_state *old_connector_state, *new_connector_state; int i, ret; + unsigned connectors_mask = 0; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { bool has_connectors = @@ -538,6 +549,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) { + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + /* * This only sets crtc->connectors_changed for routing changes, * drivers must set crtc->connectors_changed themselves when @@ -555,6 +568,13 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_connector_state->link_status) new_crtc_state->connectors_changed = true; } + + if (funcs->atomic_check) + ret = funcs->atomic_check(connector, new_connector_state); + if (ret) + return ret; + + connectors_mask += BIT(i); } /* @@ -581,6 +601,22 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } + /* + * Iterate over all connectors again, to make sure atomic_check() + * has been called on them when a modeset is forced. + */ + for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) { + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + + if (connectors_mask & BIT(i)) + continue; + + if (funcs->atomic_check) + ret = funcs->atomic_check(connector, new_connector_state); + if (ret) + return ret; + } + return mode_fixup(state); } EXPORT_SYMBOL(drm_atomic_helper_check_modeset); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 7847bab..c01c328 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -872,6 +872,40 @@ struct drm_connector_helper_funcs { */ struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector, struct drm_connector_state *connector_state); + + /** + * @atomic_check: + * + * This hook is used to validate connector state. This function is + * called from &drm_atomic_helper_check_modeset, and is called when + * a connector property is set, or a modeset on the crtc is forced. + * + * Because &drm_atomic_helper_check_modeset may be called multiple times, + * this function should handle being called multiple times as well. + * + * This function is also allowed to inspect any other object's state and + * can add more state objects to the atomic commit if needed. Care must + * be taken though to ensure that state check and compute functions for + * these added states are all called, and derived state in other objects + * all updated. Again the recommendation is to just call check helpers + * until a maximal configuration is reached. + * + * NOTE: + * + * This function is called in the check phase of an atomic update. The + * driver is not allowed to change anything outside of the free-standing + * state objects passed-in or assembled in the overall &drm_atomic_state + * update tracking structure. + * + * RETURNS: + * + * 0 on success, -EINVAL if the state or the transition can't be + * supported, -ENOMEM on memory allocation failure and -EDEADLK if an + * attempt to obtain another state object ran into a &drm_modeset_lock + * deadlock. + */ + int (*atomic_check)(struct drm_connector *connector, + struct drm_connector_state *state); }; /** -- cgit v1.1 From b61c8d5d9a27715dd31781910aef12be4882ebfd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Mar 2017 08:26:04 -0500 Subject: drm: make of_drm_find_panel also depend on CONFIG_DRM_PANEL For drm_of_find_panel_or_bridge() added in the next commit, an empty version of of_drm_find_panel is needed for !CONFIG_DRM_PANEL. Signed-off-by: Rob Herring Reviewed-by: Eric Anholt Signed-off-by: Sean Paul --- include/drm/drm_panel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 4b76cf2..1b364b0 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -192,7 +192,7 @@ void drm_panel_remove(struct drm_panel *panel); int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); int drm_panel_detach(struct drm_panel *panel); -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct drm_panel *of_drm_find_panel(const struct device_node *np); #else static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) -- cgit v1.1 From 1f2db3034c9f16ed918e34809167546f21d0fcb4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Mar 2017 08:26:05 -0500 Subject: drm: of: introduce drm_of_find_panel_or_bridge Many drivers have a common pattern of searching the OF graph for either an attached panel or bridge and then finding the DRM struct for the panel or bridge. Also, most drivers need to handle deferred probing when the DRM device is not yet instantiated. Create a common function, drm_of_find_panel_or_bridge, to find the connected node and the associated DRM panel or bridge device. Signed-off-by: Rob Herring Acked-by: Philipp Zabel [seanpaul dropped extern from drm_of.h] Signed-off-by: Sean Paul --- drivers/gpu/drm/drm_of.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_of.h | 13 ++++++++++++ 2 files changed, 65 insertions(+) diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index b5f2f0f..2120f33 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include static void drm_release_of(struct device *dev, void *data) @@ -208,3 +210,53 @@ int drm_of_encoder_active_endpoint(struct device_node *node, return -EINVAL; } EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); + +/* + * drm_of_find_panel_or_bridge - return connected panel or bridge device + * @np: device tree node containing encoder output ports + * @panel: pointer to hold returned drm_panel + * @bridge: pointer to hold returned drm_bridge + * + * Given a DT node's port and endpoint number, find the connected node and + * return either the associated struct drm_panel or drm_bridge device. Either + * @panel or @bridge must not be NULL. + * + * Returns zero if successful, or one of the standard error codes if it fails. + */ +int drm_of_find_panel_or_bridge(const struct device_node *np, + int port, int endpoint, + struct drm_panel **panel, + struct drm_bridge **bridge) +{ + int ret = -EPROBE_DEFER; + struct device_node *remote; + + if (!panel && !bridge) + return -EINVAL; + + remote = of_graph_get_remote_node(np, port, endpoint); + if (!remote) + return -ENODEV; + + if (panel) { + *panel = of_drm_find_panel(remote); + if (*panel) + ret = 0; + } + + /* No panel found yet, check for a bridge next. */ + if (bridge) { + if (ret) { + *bridge = of_drm_find_bridge(remote); + if (*bridge) + ret = 0; + } else { + *bridge = NULL; + } + + } + + of_node_put(remote); + return ret; +} +EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge); diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index d1fc563..104dd51 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -8,6 +8,8 @@ struct component_match; struct device; struct drm_device; struct drm_encoder; +struct drm_panel; +struct drm_bridge; struct device_node; #ifdef CONFIG_OF @@ -23,6 +25,10 @@ int drm_of_component_probe(struct device *dev, int drm_of_encoder_active_endpoint(struct device_node *node, struct drm_encoder *encoder, struct of_endpoint *endpoint); +int drm_of_find_panel_or_bridge(const struct device_node *np, + int port, int endpoint, + struct drm_panel **panel, + struct drm_bridge **bridge); #else static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) @@ -52,6 +58,13 @@ static inline int drm_of_encoder_active_endpoint(struct device_node *node, { return -EINVAL; } +static inline int drm_of_find_panel_or_bridge(const struct device_node *np, + int port, int endpoint, + struct drm_panel **panel, + struct drm_bridge **bridge) +{ + return -EINVAL; +} #endif static inline int drm_of_encoder_active_endpoint_id(struct device_node *node, -- cgit v1.1 From 86418f90a4c1a0073db65d8a1e2bf94421117a60 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Mar 2017 08:26:06 -0500 Subject: drm: convert drivers to use of_graph_get_remote_node Convert drivers to use the new of_graph_get_remote_node() helper instead of parsing the endpoint node and then getting the remote device node. Now drivers can just specify the device node and which port/endpoint and get back the connected remote device node. The details of the graph binding are nicely abstracted into the core OF graph code. This changes some error messages to debug messages (in the graph core). Graph connections are often "no connects" depending on the particular board, so we want to avoid spurious messages. Plus the kernel is not a DT validator. Signed-off-by: Rob Herring Acked-by: Neil Armstrong Tested-by: Liviu Dudau Tested-by: Eric Anholt Tested-by: Jyri Sarha Tested by: Archit Taneja Signed-off-by: Sean Paul --- drivers/gpu/drm/arm/hdlcd_drv.c | 22 ++------ drivers/gpu/drm/arm/malidp_drv.c | 28 ++-------- drivers/gpu/drm/bridge/adv7511/adv7533.c | 12 +---- drivers/gpu/drm/bridge/dumb-vga-dac.c | 15 ++---- drivers/gpu/drm/bridge/ti-tfp410.c | 15 ++---- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 16 +----- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 13 ++--- drivers/gpu/drm/exynos/exynos_drm_mic.c | 25 +-------- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 30 +---------- drivers/gpu/drm/mediatek/mtk_dpi.c | 12 ++--- drivers/gpu/drm/mediatek/mtk_hdmi.c | 26 ++-------- drivers/gpu/drm/meson/meson_venc_cvbs.c | 19 ++----- drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 28 +--------- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 12 +---- drivers/gpu/drm/tilcdc/tilcdc_external.c | 68 +++---------------------- drivers/gpu/drm/vc4/vc4_dpi.c | 15 ++---- 17 files changed, 48 insertions(+), 310 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 0e74880..0f49c4b 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -392,29 +392,13 @@ static int compare_dev(struct device *dev, void *data) static int hdlcd_probe(struct platform_device *pdev) { - struct device_node *port, *ep; + struct device_node *port; struct component_match *match = NULL; - if (!pdev->dev.of_node) - return -ENODEV; - /* there is only one output port inside each device, find it */ - ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); - if (!ep) - return -ENODEV; - - if (!of_device_is_available(ep)) { - of_node_put(ep); + port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0); + if (!port) return -ENODEV; - } - - /* add the remote encoder port as component */ - port = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (!port || !of_device_is_available(port)) { - of_node_put(port); - return -EAGAIN; - } drm_of_component_match_add(&pdev->dev, &match, compare_dev, port); of_node_put(port); diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index ea2546f..898c2b58 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -283,7 +283,6 @@ static int malidp_bind(struct device *dev) { struct resource *res; struct drm_device *drm; - struct device_node *ep; struct malidp_drm *malidp; struct malidp_hw_device *hwdev; struct platform_device *pdev = to_platform_device(dev); @@ -398,12 +397,7 @@ static int malidp_bind(struct device *dev) goto init_fail; /* Set the CRTC's port so that the encoder component can find it */ - ep = of_graph_get_next_endpoint(dev->of_node, NULL); - if (!ep) { - ret = -EINVAL; - goto port_fail; - } - malidp->crtc.port = of_get_next_parent(ep); + malidp->crtc.port = of_graph_get_port_by_id(dev->of_node, 0); ret = component_bind_all(dev, drm); if (ret) { @@ -458,7 +452,6 @@ irq_init_fail: bind_fail: of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; -port_fail: malidp_fini(drm); init_fail: drm->dev_private = NULL; @@ -516,29 +509,16 @@ static int malidp_compare_dev(struct device *dev, void *data) static int malidp_platform_probe(struct platform_device *pdev) { - struct device_node *port, *ep; + struct device_node *port; struct component_match *match = NULL; if (!pdev->dev.of_node) return -ENODEV; /* there is only one output port inside each device, find it */ - ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); - if (!ep) - return -ENODEV; - - if (!of_device_is_available(ep)) { - of_node_put(ep); + port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0); + if (!port) return -ENODEV; - } - - /* add the remote encoder port as component */ - port = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (!port || !of_device_is_available(port)) { - of_node_put(port); - return -EAGAIN; - } drm_of_component_match_add(&pdev->dev, &match, malidp_compare_dev, port); diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 8b21037..ac804f8 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -232,7 +232,6 @@ void adv7533_detach_dsi(struct adv7511 *adv) int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) { u32 num_lanes; - struct device_node *endpoint; of_property_read_u32(np, "adi,dsi-lanes", &num_lanes); @@ -241,17 +240,10 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) adv->num_dsi_lanes = num_lanes; - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) + adv->host_node = of_graph_get_remote_node(np, 0, 0); + if (!adv->host_node) return -ENODEV; - adv->host_node = of_graph_get_remote_port_parent(endpoint); - if (!adv->host_node) { - of_node_put(endpoint); - return -ENODEV; - } - - of_node_put(endpoint); of_node_put(adv->host_node); adv->use_timing_gen = !of_property_read_bool(np, diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 63e113b..831a606 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -154,21 +154,12 @@ static const struct drm_bridge_funcs dumb_vga_bridge_funcs = { static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev) { - struct device_node *end_node, *phandle, *remote; + struct device_node *phandle, *remote; struct i2c_adapter *ddc; - end_node = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); - if (!end_node) { - dev_err(dev, "Missing connector endpoint\n"); - return ERR_PTR(-ENODEV); - } - - remote = of_graph_get_remote_port_parent(end_node); - of_node_put(end_node); - if (!remote) { - dev_err(dev, "Enable to parse remote node\n"); + remote = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!remote) return ERR_PTR(-EINVAL); - } phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); of_node_put(remote); diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 7d519b4..eee4efd 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -165,18 +165,13 @@ static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) static int tfp410_get_connector_properties(struct tfp410 *dvi) { - struct device_node *ep = NULL, *connector_node = NULL; - struct device_node *ddc_phandle = NULL; + struct device_node *connector_node, *ddc_phandle; int ret = 0; /* port@1 is the connector node */ - ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 1, -1); - if (!ep) - goto fail; - - connector_node = of_graph_get_remote_port_parent(ep); + connector_node = of_graph_get_remote_node(dvi->dev->of_node, 1, -1); if (!connector_node) - goto fail; + return -ENODEV; dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, "hpd-gpios", 0, GPIOD_IN, "hpd"); @@ -199,10 +194,10 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi) else ret = -EPROBE_DEFER; + of_node_put(ddc_phandle); + fail: - of_node_put(ep); of_node_put(connector_node); - of_node_put(ddc_phandle); return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 3aab71a..63abcd2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -163,27 +163,13 @@ enum { FIMD_PORT_WRB, }; -static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev) -{ - struct device_node *np, *ep; - - ep = of_graph_get_endpoint_by_regs(dev->of_node, FIMD_PORT_RGB, 0); - if (!ep) - return NULL; - - np = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - - return np; -} - static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) { struct device *dev = ctx->dev; struct device_node *dn = dev->of_node; struct device_node *np; - ctx->panel_node = exynos_dpi_of_find_panel_node(dev); + ctx->panel_node = of_graph_get_remote_node(dn, FIMD_PORT_RGB, 0); np = of_get_child_by_name(dn, "display-timings"); if (np) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 6d4da2f..fc4fda7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1659,17 +1659,10 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) of_node_put(ep); - ep = of_graph_get_next_endpoint(node, NULL); - if (!ep) { - ret = -EINVAL; - goto end; - } + dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0); + if (!dsi->bridge_node) + return -EINVAL; - dsi->bridge_node = of_graph_get_remote_port_parent(ep); - if (!dsi->bridge_node) { - ret = -EINVAL; - goto end; - } end: of_node_put(ep); diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2ef43d4..e457205 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -229,29 +229,6 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable) writel(reg, mic->reg + MIC_OP); } -static struct device_node *get_remote_node(struct device_node *from, int reg) -{ - struct device_node *endpoint = NULL, *remote_node = NULL; - - endpoint = of_graph_get_endpoint_by_regs(from, reg, -1); - if (!endpoint) { - DRM_ERROR("mic: Failed to find remote port from %s", - from->full_name); - goto exit; - } - - remote_node = of_graph_get_remote_port_parent(endpoint); - if (!remote_node) { - DRM_ERROR("mic: Failed to find remote port parent from %s", - from->full_name); - goto exit; - } - -exit: - of_node_put(endpoint); - return remote_node; -} - static int parse_dt(struct exynos_mic *mic) { int ret = 0, i, j; @@ -263,7 +240,7 @@ static int parse_dt(struct exynos_mic *mic) * The first node must be for decon and the second one must be for dsi. */ for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) { - remote_node = get_remote_node(mic->dev->of_node, i); + remote_node = of_graph_get_remote_node(mic->dev->of_node, i, 0); if (!remote_node) { ret = -EPIPE; goto exit; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index df4f507..9c90367 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -230,34 +230,6 @@ static const struct component_master_ops kirin_drm_ops = { .unbind = kirin_drm_unbind, }; -static struct device_node *kirin_get_remote_node(struct device_node *np) -{ - struct device_node *endpoint, *remote; - - /* get the first endpoint, in our case only one remote node - * is connected to display controller. - */ - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) { - DRM_ERROR("no valid endpoint node\n"); - return ERR_PTR(-ENODEV); - } - - remote = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!remote) { - DRM_ERROR("no valid remote node\n"); - return ERR_PTR(-ENODEV); - } - - if (!of_device_is_available(remote)) { - DRM_ERROR("not available for remote node\n"); - return ERR_PTR(-ENODEV); - } - - return remote; -} - static int kirin_drm_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -271,7 +243,7 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) return -EINVAL; } - remote = kirin_get_remote_node(np); + remote = of_graph_get_remote_node(np, 0, 0); if (IS_ERR(remote)) return PTR_ERR(remote); diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 3bd3bd6..32ca351 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -661,7 +661,7 @@ static int mtk_dpi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mtk_dpi *dpi; struct resource *mem; - struct device_node *ep, *bridge_node = NULL; + struct device_node *bridge_node; int comp_id; int ret; @@ -706,15 +706,9 @@ static int mtk_dpi_probe(struct platform_device *pdev) return -EINVAL; } - ep = of_graph_get_next_endpoint(dev->of_node, NULL); - if (ep) { - bridge_node = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - } - if (!bridge_node) { - dev_err(dev, "Failed to find bridge node\n"); + bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0); + if (!bridge_node) return -ENODEV; - } dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index c262512..41a1c03 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1434,7 +1434,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *cec_np, *port, *ep, *remote, *i2c_np; + struct device_node *cec_np, *remote, *i2c_np; struct platform_device *cec_pdev; struct regmap *regmap; struct resource *mem; @@ -1486,29 +1486,9 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi, if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); - port = of_graph_get_port_by_id(np, 1); - if (!port) { - dev_err(dev, "Missing output port node\n"); + remote = of_graph_get_remote_node(np, 1, 0); + if (!remote) return -EINVAL; - } - - ep = of_get_child_by_name(port, "endpoint"); - if (!ep) { - dev_err(dev, "Missing endpoint node in port %s\n", - port->full_name); - of_node_put(port); - return -EINVAL; - } - of_node_put(port); - - remote = of_graph_get_remote_port_parent(ep); - if (!remote) { - dev_err(dev, "Missing connector/bridge node for endpoint %s\n", - ep->full_name); - of_node_put(ep); - return -EINVAL; - } - of_node_put(ep); if (!of_device_is_compatible(remote, "hdmi-connector")) { hdmi->next_bridge = of_drm_find_bridge(remote); diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 5d4f19a..00775b3 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -224,25 +224,14 @@ static const struct drm_encoder_helper_funcs static bool meson_venc_cvbs_connector_is_available(struct meson_drm *priv) { - struct device_node *ep, *remote; + struct device_node *remote; - /* CVBS VDAC output is on the first port, first endpoint */ - ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0); - if (!ep) + remote = of_graph_get_remote_node(priv->dev->of_node, 0, 0); + if (!remote) return false; - - /* If the endpoint node exists, consider it enabled */ - remote = of_graph_get_remote_port(ep); - if (remote) { - of_node_put(ep); - return true; - } - - of_node_put(ep); of_node_put(remote); - - return false; + return true; } int meson_venc_cvbs_create(struct meson_drm *priv) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4f79b10..f97a780 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1635,7 +1635,7 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) } /* Get panel node from the output port's endpoint data */ - device_node = of_graph_get_remote_port_parent(endpoint); + device_node = of_graph_get_remote_node(np, 1, 0); if (!device_node) { dev_dbg(dev, "%s: no valid device\n", __func__); goto err; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index a4e1206..5b6516b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -225,32 +225,6 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms) return 0; } -static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev) -{ - struct device_node *endpoint, *panel_node; - struct device_node *np = dev->dev->of_node; - - /* - * LVDS/LCDC is the first port described in the list of ports in the - * MDP4 DT node. - */ - endpoint = of_graph_get_endpoint_by_regs(np, 0, -1); - if (!endpoint) { - DBG("no LVDS remote endpoint\n"); - return NULL; - } - - panel_node = of_graph_get_remote_port_parent(endpoint); - if (!panel_node) { - DBG("no valid panel node in LVDS endpoint\n"); - of_node_put(endpoint); - return NULL; - } - - of_node_put(endpoint); - - return panel_node; -} static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms, int intf_type) @@ -269,7 +243,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms, * bail out early if there is no panel node (no need to * initialize LCDC encoder and LVDS connector) */ - panel_node = mdp4_detect_lcdc_panel(dev); + panel_node = of_graph_get_remote_node(dev->dev->of_node, 0, 0); if (!panel_node) return 0; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index afd2a7b..d524ed0 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "tilcdc_drv.h" #include "tilcdc_regs.h" @@ -1035,16 +1036,7 @@ int tilcdc_crtc_create(struct drm_device *dev) drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs); if (priv->is_componentized) { - struct device_node *ports = - of_get_child_by_name(dev->dev->of_node, "ports"); - - if (ports) { - crtc->port = of_get_child_by_name(ports, "port"); - of_node_put(ports); - } else { - crtc->port = - of_get_child_by_name(dev->dev->of_node, "port"); - } + crtc->port = of_graph_get_port_by_id(dev->dev->of_node, 0); if (!crtc->port) { /* This should never happen */ dev_err(dev->dev, "Port node not found in %s\n", dev->dev->of_node->full_name); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index b0dd5e8..711c7b3 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -185,39 +185,6 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge) return ret; } -static int tilcdc_node_has_port(struct device_node *dev_node) -{ - struct device_node *node; - - node = of_get_child_by_name(dev_node, "ports"); - if (!node) - node = of_get_child_by_name(dev_node, "port"); - if (!node) - return 0; - of_node_put(node); - - return 1; -} - -static -struct device_node *tilcdc_get_remote_node(struct device_node *node) -{ - struct device_node *ep; - struct device_node *parent; - - if (!tilcdc_node_has_port(node)) - return NULL; - - ep = of_graph_get_next_endpoint(node, NULL); - if (!ep) - return NULL; - - parent = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - - return parent; -} - int tilcdc_attach_external_device(struct drm_device *ddev) { struct tilcdc_drm_private *priv = ddev->dev_private; @@ -225,7 +192,7 @@ int tilcdc_attach_external_device(struct drm_device *ddev) struct drm_bridge *bridge; int ret; - remote_node = tilcdc_get_remote_node(ddev->dev->of_node); + remote_node = of_graph_get_remote_node(ddev->dev->of_node, 0, 0); if (!remote_node) return 0; @@ -264,35 +231,16 @@ int tilcdc_get_external_components(struct device *dev, struct component_match **match) { struct device_node *node; - struct device_node *ep = NULL; - int count = 0; - int ret = 0; - - if (!tilcdc_node_has_port(dev->of_node)) - return 0; - while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) { - node = of_graph_get_remote_port_parent(ep); - if (!node || !of_device_is_available(node)) { - of_node_put(node); - continue; - } - - dev_dbg(dev, "Subdevice node '%s' found\n", node->name); - - if (of_device_is_compatible(node, "nxp,tda998x")) { - if (match) - drm_of_component_match_add(dev, match, - dev_match_of, node); - ret = 1; - } + node = of_graph_get_remote_node(dev->of_node, 0, 0); + if (!of_device_is_compatible(node, "nxp,tda998x")) { of_node_put(node); - if (count++ > 1) { - dev_err(dev, "Only one port is supported\n"); - return -EINVAL; - } + return 0; } - return ret; + if (match) + drm_of_component_match_add(dev, match, dev_match_of, node); + of_node_put(node); + return 1; } diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 7143579..c6d7039 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -356,23 +356,14 @@ static const struct of_device_id vc4_dpi_dt_match[] = { */ static struct drm_panel *vc4_dpi_get_panel(struct device *dev) { - struct device_node *endpoint, *panel_node; + struct device_node *panel_node; struct device_node *np = dev->of_node; struct drm_panel *panel; - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) { - dev_err(dev, "no endpoint to fetch DPI panel\n"); - return NULL; - } - /* don't proceed if we have an endpoint but no panel_node tied to it */ - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_err(dev, "no valid panel node\n"); + panel_node = of_graph_get_remote_node(np, 0, 0); + if (!panel_node) return NULL; - } panel = of_drm_find_panel(panel_node); of_node_put(panel_node); -- cgit v1.1 From ebc9446135671b89c2397f438af45d9cef0d1368 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Mar 2017 13:55:46 -0500 Subject: drm: convert drivers to use drm_of_find_panel_or_bridge Similar to the previous commit, convert drivers open coding OF graph parsing to use drm_of_find_panel_or_bridge instead. This changes some error messages to debug messages (in the graph core). Graph connections are often "no connects" depending on the particular board, so we want to avoid spurious messages. Plus the kernel is not a DT validator. Signed-off-by: Rob Herring Reviewed-by: Archit Taneja Tested-by: Philipp Zabel Acked-by: Maxime Ripard [seanpaul dropped rockchip changes since they're now obsolete] Signed-off-by: Sean Paul --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 73 ++++++------------- drivers/gpu/drm/bridge/nxp-ptn3460.c | 16 ++--- drivers/gpu/drm/bridge/parade-ps8622.c | 16 ++--- drivers/gpu/drm/bridge/tc358767.c | 27 +------ drivers/gpu/drm/exynos/exynos_dp.c | 35 ++++----- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 44 ++++-------- drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 27 ++----- drivers/gpu/drm/imx/imx-ldb.c | 27 ++----- drivers/gpu/drm/imx/parallel-display.c | 36 ++-------- drivers/gpu/drm/mediatek/mtk_dsi.c | 23 ++---- drivers/gpu/drm/mxsfb/mxsfb_out.c | 40 ++--------- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 26 ++----- drivers/gpu/drm/sun4i/sun4i_rgb.c | 11 +-- drivers/gpu/drm/sun4i/sun4i_tcon.c | 90 ++---------------------- 14 files changed, 95 insertions(+), 396 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index e7799b6..f987b45 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include "atmel_hlcdc_dc.h" @@ -152,29 +152,11 @@ static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int atmel_hlcdc_check_endpoint(struct drm_device *dev, - const struct of_endpoint *ep) -{ - struct device_node *np; - void *obj; - - np = of_graph_get_remote_port_parent(ep->local_node); - - obj = of_drm_find_panel(np); - if (!obj) - obj = of_drm_find_bridge(np); - - of_node_put(np); - - return obj ? 0 : -EPROBE_DEFER; -} - static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, - const struct of_endpoint *ep) + const struct device_node *np) { struct atmel_hlcdc_dc *dc = dev->dev_private; struct atmel_hlcdc_rgb_output *output; - struct device_node *np; struct drm_panel *panel; struct drm_bridge *bridge; int ret; @@ -195,13 +177,11 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, output->encoder.possible_crtcs = 0x1; - np = of_graph_get_remote_port_parent(ep->local_node); - - ret = -EPROBE_DEFER; + ret = drm_of_find_panel_or_bridge(np, 0, 0, &panel, &bridge); + if (ret) + return ret; - panel = of_drm_find_panel(np); if (panel) { - of_node_put(np); output->connector.dpms = DRM_MODE_DPMS_OFF; output->connector.polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_helper_add(&output->connector, @@ -226,9 +206,6 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, return 0; } - bridge = of_drm_find_bridge(np); - of_node_put(np); - if (bridge) { ret = drm_bridge_attach(&output->encoder, bridge, NULL); if (!ret) @@ -243,31 +220,23 @@ err_encoder_cleanup: int atmel_hlcdc_create_outputs(struct drm_device *dev) { - struct device_node *ep_np = NULL; - struct of_endpoint ep; - int ret; - - for_each_endpoint_of_node(dev->dev->of_node, ep_np) { - ret = of_graph_parse_endpoint(ep_np, &ep); - if (!ret) - ret = atmel_hlcdc_check_endpoint(dev, &ep); - - if (ret) { - of_node_put(ep_np); - return ret; - } - } - - for_each_endpoint_of_node(dev->dev->of_node, ep_np) { - ret = of_graph_parse_endpoint(ep_np, &ep); - if (!ret) - ret = atmel_hlcdc_attach_endpoint(dev, &ep); - - if (ret) { - of_node_put(ep_np); + struct device_node *remote; + int ret, endpoint = 0; + + while (true) { + /* Loop thru possible multiple connections to the output */ + remote = of_graph_get_remote_node(dev->dev->of_node, 0, + endpoint++); + if (!remote) + break; + + ret = atmel_hlcdc_attach_endpoint(dev, remote); + of_node_put(remote); + if (ret) return ret; - } } - return 0; + if (!endpoint) + return -ENODEV; + return ret; } diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 27f98c5..3517043 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -20,8 +20,8 @@ #include #include #include -#include +#include #include #include "drm_crtc.h" @@ -292,7 +292,6 @@ static int ptn3460_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct ptn3460_bridge *ptn_bridge; - struct device_node *endpoint, *panel_node; int ret; ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); @@ -300,16 +299,9 @@ static int ptn3460_probe(struct i2c_client *client, return -ENOMEM; } - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - panel_node = of_graph_get_remote_port_parent(endpoint); - if (panel_node) { - ptn_bridge->panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (!ptn_bridge->panel) - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL); + if (ret) + return ret; ptn_bridge->client = client; diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index ac8cc5b..1dcec3b 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -22,10 +22,10 @@ #include #include #include -#include #include #include +#include #include #include "drmP.h" @@ -536,7 +536,6 @@ static int ps8622_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *endpoint, *panel_node; struct ps8622_bridge *ps8622; int ret; @@ -544,16 +543,9 @@ static int ps8622_probe(struct i2c_client *client, if (!ps8622) return -ENOMEM; - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - panel_node = of_graph_get_remote_port_parent(endpoint); - if (panel_node) { - ps8622->panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (!ps8622->panel) - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL); + if (ret) + return ret; ps8622->client = client; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index de9ffb4..5c26488 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1244,7 +1244,6 @@ static const struct regmap_config tc_regmap_config = { static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *ep; struct tc_data *tc; int ret; @@ -1255,29 +1254,9 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) tc->dev = dev; /* port@2 is the output port */ - ep = of_graph_get_endpoint_by_regs(dev->of_node, 2, -1); - if (ep) { - struct device_node *remote; - - remote = of_graph_get_remote_port_parent(ep); - if (!remote) { - dev_warn(dev, "endpoint %s not connected\n", - ep->full_name); - of_node_put(ep); - return -ENODEV; - } - of_node_put(ep); - tc->panel = of_drm_find_panel(remote); - if (tc->panel) { - dev_dbg(dev, "found panel %s\n", remote->full_name); - } else { - dev_dbg(dev, "waiting for panel %s\n", - remote->full_name); - of_node_put(remote); - return -EPROBE_DEFER; - } - of_node_put(remote); - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL); + if (ret) + return ret; /* Shut down GPIO is optional */ tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index b445b50..385537b 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -211,8 +212,11 @@ static const struct component_ops exynos_dp_ops = { static int exynos_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = NULL, *endpoint = NULL; + struct device_node *np; struct exynos_dp_device *dp; + struct drm_panel *panel; + struct drm_bridge *bridge; + int ret; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); @@ -236,28 +240,13 @@ static int exynos_dp_probe(struct platform_device *pdev) goto out; } - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - np = of_graph_get_remote_port_parent(endpoint); - if (np) { - /* The remote port can be either a panel or a bridge */ - dp->plat_data.panel = of_drm_find_panel(np); - if (!dp->plat_data.panel) { - dp->ptn_bridge = of_drm_find_bridge(np); - if (!dp->ptn_bridge) { - of_node_put(np); - return -EPROBE_DEFER; - } - } - of_node_put(np); - } else { - DRM_ERROR("no remote endpoint device node found.\n"); - return -EINVAL; - } - } else { - DRM_ERROR("no port endpoint subnode found.\n"); - return -EINVAL; - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge); + if (ret) + return ret; + + /* The remote port can be either a panel or a bridge */ + dp->plat_data.panel = panel; + dp->ptn_bridge = bridge; out: return component_add(&pdev->dev, &exynos_dp_ops); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index c365145..dcbf3c0 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "fsl_dcu_drm_drv.h" @@ -141,32 +142,11 @@ err_cleanup: return ret; } -static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev, - const struct of_endpoint *ep) -{ - struct drm_bridge *bridge; - struct device_node *np; - - np = of_graph_get_remote_port_parent(ep->local_node); - - fsl_dev->connector.panel = of_drm_find_panel(np); - if (fsl_dev->connector.panel) { - of_node_put(np); - return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); - } - - bridge = of_drm_find_bridge(np); - of_node_put(np); - if (!bridge) - return -ENODEV; - - return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL); -} - int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) { - struct of_endpoint ep; - struct device_node *ep_node, *panel_node; + struct device_node *panel_node; + struct drm_panel *panel; + struct drm_bridge *bridge; int ret; /* This is for backward compatibility */ @@ -179,14 +159,14 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); } - ep_node = of_graph_get_next_endpoint(fsl_dev->np, NULL); - if (!ep_node) - return -ENODEV; - - ret = of_graph_parse_endpoint(ep_node, &ep); - of_node_put(ep_node); + ret = drm_of_find_panel_or_bridge(fsl_dev->np, 0, 0, &panel, &bridge); if (ret) - return -ENODEV; + return ret; + + if (panel) { + fsl_dev->connector.panel = panel; + return fsl_dcu_attach_panel(fsl_dev, panel); + } - return fsl_dcu_attach_endpoint(fsl_dev, &ep); + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL); } diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index 1737e98..5abc69c 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -754,34 +753,16 @@ static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi) { struct dsi_hw_ctx *ctx = dsi->ctx; struct device_node *np = pdev->dev.of_node; - struct device_node *endpoint, *bridge_node; - struct drm_bridge *bridge; struct resource *res; + int ret; /* * Get the endpoint node. In our case, dsi has one output port1 * to which the external HDMI bridge is connected. */ - endpoint = of_graph_get_endpoint_by_regs(np, 1, -1); - if (!endpoint) { - DRM_ERROR("no valid endpoint node\n"); - return -ENODEV; - } - of_node_put(endpoint); - - bridge_node = of_graph_get_remote_port_parent(endpoint); - if (!bridge_node) { - DRM_ERROR("no valid bridge node\n"); - return -ENODEV; - } - of_node_put(bridge_node); - - bridge = of_drm_find_bridge(bridge_node); - if (!bridge) { - DRM_INFO("wait for external HDMI bridge driver.\n"); - return -EPROBE_DEFER; - } - dsi->bridge = bridge; + ret = drm_of_find_panel_or_bridge(np, 0, 0, NULL, &dsi->bridge); + if (ret) + return ret; ctx->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(ctx->pclk)) { diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 88cd11d..8fb801f 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -647,7 +647,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; - struct device_node *ep; int bus_format; ret = of_property_read_u32(child, "reg", &i); @@ -671,27 +670,11 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) * The output port is port@4 with an external 4-port mux or * port@2 with the internal 2-port mux. */ - ep = of_graph_get_endpoint_by_regs(child, - imx_ldb->lvds_mux ? 4 : 2, - -1); - if (ep) { - struct device_node *remote; - - remote = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (remote) { - channel->panel = of_drm_find_panel(remote); - channel->bridge = of_drm_find_bridge(remote); - } else - return -EPROBE_DEFER; - of_node_put(remote); - - if (!channel->panel && !channel->bridge) { - dev_err(dev, "panel/bridge not found: %s\n", - remote->full_name); - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(child, + imx_ldb->lvds_mux ? 4 : 2, 0, + &channel->panel, &channel->bridge); + if (ret) + return ret; /* panel ddc only if there is no bridge */ if (!channel->bridge) { diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index d5c06fd..636031a 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -19,10 +19,10 @@ #include #include #include +#include #include #include #include