From 813cfc89f826edc6d78ac0dc0cfbf45ca6483fd4 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sun, 25 Sep 2016 15:38:28 +0800 Subject: drm/rockchip: add missing header dependencies We get 2 warnings when building kernel with W=1: drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c:130:5: warning: no previous prototype for 'rockchip_drm_fbdev_init' [-Wmissing-prototypes] drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c:173:6: warning: no previous prototype for 'rockchip_drm_fbdev_fini' [-Wmissing-prototypes] In fact, these functions are declared in drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h, so this patch adds missing header dependencies. Signed-off-by: Baoyou Xie Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474789109-22010-1-git-send-email-baoyou.xie@linaro.org --- drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index 207e01de6e32..a16c69f96ed5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -20,6 +20,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" #include "rockchip_drm_fb.h" +#include "rockchip_drm_fbdev.h" #define PREFERRED_BPP 32 #define to_drm_private(x) \ -- cgit v1.2.3 From 6239817702e6fc3737d95256586a767a9b4f7fc0 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sun, 25 Sep 2016 15:43:08 +0800 Subject: drm/rockchip: mark symbols static where possible We get 2 warnings when building kernel with W=1: drivers/gpu/drm/rockchip/rockchip_drm_drv.c:309:6: warning: no previous prototype for 'rockchip_drm_fb_suspend' [-Wmissing-prototypes] drivers/gpu/drm/rockchip/rockchip_drm_drv.c:318:6: warning: no previous prototype for 'rockchip_drm_fb_resume' [-Wmissing-prototypes] In fact, these functions are only used in the file in which they are declared and don't need a declaration, but can be made static. So this patch marks these functions with 'static'. Signed-off-by: Baoyou Xie Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474789388-3284-1-git-send-email-baoyou.xie@linaro.org --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 446b5d7e85f7..8c8cbe837e61 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = { }; #ifdef CONFIG_PM_SLEEP -void rockchip_drm_fb_suspend(struct drm_device *drm) +static void rockchip_drm_fb_suspend(struct drm_device *drm) { struct rockchip_drm_private *priv = drm->dev_private; @@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm) console_unlock(); } -void rockchip_drm_fb_resume(struct drm_device *drm) +static void rockchip_drm_fb_resume(struct drm_device *drm) { struct rockchip_drm_private *priv = drm->dev_private; -- cgit v1.2.3 From 188af070d4d20474cba4d42b4eaf728ba116f418 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sun, 25 Sep 2016 15:38:29 +0800 Subject: drm/mediatek: mark symbols static where possible We get 4 warnings when building kernel with W=1: drivers/gpu/drm/mediatek/mtk_hdmi.c:1089:6: warning: no previous prototype for 'mtk_hdmi_audio_enable' [-Wmissing-prototypes] drivers/gpu/drm/mediatek/mtk_hdmi.c:1095:6: warning: no previous prototype for 'mtk_hdmi_audio_disable' [-Wmissing-prototypes] drivers/gpu/drm/mediatek/mtk_hdmi.c:1101:5: warning: no previous prototype for 'mtk_hdmi_audio_set_param' [-Wmissing-prototypes] drivers/gpu/drm/mediatek/mtk_hdmi.c:1627:5: warning: no previous prototype for 'mtk_hdmi_audio_digital_mute' [-Wmissing-prototypes] In fact, both functions are only used in the file in which they are declared and don't need a declaration, but can be made static. So this patch marks both functions with 'static'. Signed-off-by: Baoyou Xie [seanpaul fixed checkpatch warning for argument alignment] Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1474789109-22010-2-git-send-email-baoyou.xie@linaro.org --- drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 334562d06731..71227deef21b 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1086,20 +1086,20 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi) return 0; } -void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi) +static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi) { mtk_hdmi_aud_enable_packet(hdmi, true); hdmi->audio_enable = true; } -void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi) +static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi) { mtk_hdmi_aud_enable_packet(hdmi, false); hdmi->audio_enable = false; } -int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi, - struct hdmi_audio_param *param) +static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi, + struct hdmi_audio_param *param) { if (!hdmi->audio_enable) { dev_err(hdmi->dev, "hdmi audio is in disable state!\n"); @@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data) mtk_hdmi_audio_disable(hdmi); } -int mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable) +static int +mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable) { struct mtk_hdmi *hdmi = dev_get_drvdata(dev); -- cgit v1.2.3 From 077675c1e8a193a6355d4a7c8c7bf63be310b472 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Sep 2016 21:44:14 +0100 Subject: drm: Convert prime dma-buf <-> handle to rbtree Currently we use a linear walk to lookup a handle and return a dma-buf, and vice versa. A long overdue TODO task is to convert that to a hashtable. Since the initial implementation of dma-buf/prime, we now have resizeable hashtables we can use (and now a future task is to RCU enable the lookup!). However, this patch opts to use an rbtree instead to provide O(lgN) lookups (and insertion, deletion). rbtrees were chosen over using the RCU backed resizable hashtable to firstly avoid the reallocations (rbtrees can be embedded entirely within the parent struct) and to favour simpler code with predictable worst case behaviour. In simple testing, the difference between using the constant lookup and insertion of the rhashtable and the rbtree was less than 10% of the wall time (igt/benchmarks/prime_lookup) - both are dramatic improvements over the existing linear lists. v2: Favour rbtree over rhashtable Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94631 Signed-off-by: Chris Wilson Cc: Sean Paul Cc: David Herrmann Reviewed-by: David Herrmann Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160926204414.23222-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_prime.c | 85 +++++++++++++++++++++++++++++++++++++++------ include/drm/drmP.h | 5 +-- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 780589b420a4..57201d68cf61 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -61,9 +62,11 @@ */ struct drm_prime_member { - struct list_head entry; struct dma_buf *dma_buf; uint32_t handle; + + struct rb_node dmabuf_rb; + struct rb_node handle_rb; }; struct drm_prime_attachment { @@ -75,6 +78,7 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) { struct drm_prime_member *member; + struct rb_node **p, *rb; member = kmalloc(sizeof(*member), GFP_KERNEL); if (!member) @@ -83,18 +87,56 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, get_dma_buf(dma_buf); member->dma_buf = dma_buf; member->handle = handle; - list_add(&member->entry, &prime_fpriv->head); + + rb = NULL; + p = &prime_fpriv->dmabufs.rb_node; + while (*p) { + struct drm_prime_member *pos; + + rb = *p; + pos = rb_entry(rb, struct drm_prime_member, dmabuf_rb); + if (dma_buf > pos->dma_buf) + p = &rb->rb_right; + else + p = &rb->rb_left; + } + rb_link_node(&member->dmabuf_rb, rb, p); + rb_insert_color(&member->dmabuf_rb, &prime_fpriv->dmabufs); + + rb = NULL; + p = &prime_fpriv->handles.rb_node; + while (*p) { + struct drm_prime_member *pos; + + rb = *p; + pos = rb_entry(rb, struct drm_prime_member, handle_rb); + if (handle > pos->handle) + p = &rb->rb_right; + else + p = &rb->rb_left; + } + rb_link_node(&member->handle_rb, rb, p); + rb_insert_color(&member->handle_rb, &prime_fpriv->handles); + return 0; } static struct dma_buf *drm_prime_lookup_buf_by_handle(struct drm_prime_file_private *prime_fpriv, uint32_t handle) { - struct drm_prime_member *member; + struct rb_node *rb; + + rb = prime_fpriv->handles.rb_node; + while (rb) { + struct drm_prime_member *member; - list_for_each_entry(member, &prime_fpriv->head, entry) { + member = rb_entry(rb, struct drm_prime_member, handle_rb); if (member->handle == handle) return member->dma_buf; + else if (member->handle < handle) + rb = rb->rb_right; + else + rb = rb->rb_left; } return NULL; @@ -104,14 +146,23 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri struct dma_buf *dma_buf, uint32_t *handle) { - struct drm_prime_member *member; + struct rb_node *rb; + + rb = prime_fpriv->dmabufs.rb_node; + while (rb) { + struct drm_prime_member *member; - list_for_each_entry(member, &prime_fpriv->head, entry) { + member = rb_entry(rb, struct drm_prime_member, dmabuf_rb); if (member->dma_buf == dma_buf) { *handle = member->handle; return 0; + } else if (member->dma_buf < dma_buf) { + rb = rb->rb_right; + } else { + rb = rb->rb_left; } } + return -ENOENT; } @@ -166,13 +217,24 @@ static void drm_gem_map_detach(struct dma_buf *dma_buf, void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) { - struct drm_prime_member *member, *safe; + struct rb_node *rb; - list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { + rb = prime_fpriv->dmabufs.rb_node; + while (rb) { + struct drm_prime_member *member; + + member = rb_entry(rb, struct drm_prime_member, dmabuf_rb); if (member->dma_buf == dma_buf) { + rb_erase(&member->handle_rb, &prime_fpriv->handles); + rb_erase(&member->dmabuf_rb, &prime_fpriv->dmabufs); + dma_buf_put(dma_buf); - list_del(&member->entry); kfree(member); + return; + } else if (member->dma_buf < dma_buf) { + rb = rb->rb_right; + } else { + rb = rb->rb_left; } } } @@ -759,12 +821,13 @@ EXPORT_SYMBOL(drm_prime_gem_destroy); void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) { - INIT_LIST_HEAD(&prime_fpriv->head); mutex_init(&prime_fpriv->lock); + prime_fpriv->dmabufs = RB_ROOT; + prime_fpriv->handles = RB_ROOT; } void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) { /* by now drm_gem_release should've made sure the list is empty */ - WARN_ON(!list_empty(&prime_fpriv->head)); + WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs)); } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c53dc90942e0..289207f12adb 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -371,10 +372,10 @@ struct drm_pending_event { we deliver the event, for tracing only */ }; -/* initial implementaton using a linked list - todo hashtab */ struct drm_prime_file_private { - struct list_head head; struct mutex lock; + struct rb_root dmabufs; + struct rb_root handles; }; /** File private data */ -- cgit v1.2.3 From 85c91580555ac610b266260bc7866c51bdc4d205 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:34 +0300 Subject: drm/edid: Clear old audio latency values before parsing the new EDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear out stale audio latency information (potentially from a previous EDID) before constructing the ELD from the EDID. Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-2-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 50541324a4ab..065896add86e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3358,6 +3358,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) memset(eld, 0, sizeof(connector->eld)); + connector->latency_present[0] = false; + connector->latency_present[1] = false; + connector->video_latency[0] = 0; + connector->audio_latency[0] = 0; + connector->video_latency[1] = 0; + connector->audio_latency[1] = 0; + cea = drm_find_cea_extension(edid); if (!cea) { DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); -- cgit v1.2.3 From 75d7e542bd3669a7ce41b713be8d3fd71e0ed2fa Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:35 +0300 Subject: drm/edid: Clear old dvi_dual/max_tmds_clock before parsing the new EDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear out old max_tmds_clock and dvi_dual information (possibly from a previous EDID) before parsing the current EDID. Tne current EDID might not even have these in its HDMI VSDB, which would mean that we'd leave the old stale values in place. Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-3-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 065896add86e..d0166cc990cb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3365,6 +3365,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) connector->video_latency[1] = 0; connector->audio_latency[1] = 0; + connector->max_tmds_clock = 0; + connector->dvi_dual = false; + cea = drm_find_cea_extension(edid); if (!cea) { DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); -- cgit v1.2.3 From ab5603c4d334224e3a884e62e7083ec69849fa7a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:36 +0300 Subject: drm/edid: Make max_tmds_clock kHz instead of MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We generally store clocks in kHz, so let's do that for the HDMI max TMDS clock value as well. Less surpising. v2: Deal with superfluous code shuffling Cc: Alex Deucher Cc: "Christian König" Signed-off-by: Ville Syrjälä Reviewed-by: Christian König (v1) Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-4-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 +- drivers/gpu/drm/drm_edid.c | 2 +- drivers/gpu/drm/radeon/radeon_connectors.c | 2 +- include/drm/drm_connector.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index decbba5ad438..58d51e680385 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -173,7 +173,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) mode_clock = amdgpu_connector->pixelclock_for_modeset; /* Maximum allowable input clock in kHz */ - max_tmds_clock = connector->max_tmds_clock * 1000; + max_tmds_clock = connector->max_tmds_clock; DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", connector->name, mode_clock, max_tmds_clock); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d0166cc990cb..b144d5ee66ea 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3262,7 +3262,7 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) connector->dvi_dual = db[6] & 1; } if (len >= 7) - connector->max_tmds_clock = db[7] * 5; + connector->max_tmds_clock = db[7] * 5000; if (len >= 8) { connector->latency_present[0] = db[8] >> 7; connector->latency_present[1] = (db[8] >> 6) & 1; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index b79f3b002471..db5488732e31 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -203,7 +203,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) mode_clock = radeon_connector->pixelclock_for_modeset; /* Maximum allowable input clock in kHz */ - max_tmds_clock = connector->max_tmds_clock * 1000; + max_tmds_clock = connector->max_tmds_clock; DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", connector->name, mode_clock, max_tmds_clock); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 51a15deda161..5928cb74a06d 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -651,7 +651,7 @@ struct drm_connector { /* EDID bits */ uint8_t eld[MAX_ELD_BYTES]; bool dvi_dual; - int max_tmds_clock; /* in MHz */ + int max_tmds_clock; /* in kHz */ bool latency_present[2]; int video_latency[2]; /* [0]: progressive, [1]: interlaced */ int audio_latency[2]; -- cgit v1.2.3 From 2a272ca9b8f748aa50f5f2df391a4bf05fd9fd29 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:37 +0300 Subject: drm/edid: Move dvi_dual/max_tmds_clock to drm_display_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the drm_display_info for storing information about the sink, so let's move dvi_dual and max_tmds_clock in there. v2: Deal with superfluous code shuffling Document dvi_dual and max_tmds_clock too Cc: Alex Deucher Cc: "Christian König" Signed-off-by: Ville Syrjälä Reviewed-by: Christian König (v1) Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-5-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 4 ++-- drivers/gpu/drm/drm_edid.c | 14 ++++++++------ drivers/gpu/drm/radeon/radeon_connectors.c | 4 ++-- include/drm/drm_connector.h | 15 +++++++++++---- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 58d51e680385..22c11e7698c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -168,12 +168,12 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) } /* Any defined maximum tmds clock limit we must not exceed? */ - if (connector->max_tmds_clock > 0) { + if (connector->display_info.max_tmds_clock > 0) { /* mode_clock is clock in kHz for mode to be modeset on this connector */ mode_clock = amdgpu_connector->pixelclock_for_modeset; /* Maximum allowable input clock in kHz */ - max_tmds_clock = connector->max_tmds_clock; + max_tmds_clock = connector->display_info.max_tmds_clock; DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", connector->name, mode_clock, max_tmds_clock); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b144d5ee66ea..81b9ef82af73 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3255,14 +3255,15 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) static void parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) { + struct drm_display_info *info = &connector->display_info; u8 len = cea_db_payload_len(db); if (len >= 6) { connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ - connector->dvi_dual = db[6] & 1; + info->dvi_dual = db[6] & 1; } if (len >= 7) - connector->max_tmds_clock = db[7] * 5000; + info->max_tmds_clock = db[7] * 5000; if (len >= 8) { connector->latency_present[0] = db[8] >> 7; connector->latency_present[1] = (db[8] >> 6) & 1; @@ -3281,8 +3282,8 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) "latency present %d %d, " "video latency %d %d, " "audio latency %d %d\n", - connector->dvi_dual, - connector->max_tmds_clock, + info->dvi_dual, + info->max_tmds_clock, (int) connector->latency_present[0], (int) connector->latency_present[1], connector->video_latency[0], @@ -3349,6 +3350,7 @@ EXPORT_SYMBOL(drm_edid_get_monitor_name); */ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { + struct drm_display_info *info = &connector->display_info; uint8_t *eld = connector->eld; u8 *cea; u8 *db; @@ -3365,8 +3367,8 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) connector->video_latency[1] = 0; connector->audio_latency[1] = 0; - connector->max_tmds_clock = 0; - connector->dvi_dual = false; + info->max_tmds_clock = 0; + info->dvi_dual = false; cea = drm_find_cea_extension(edid); if (!cea) { diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index db5488732e31..50e96d2c593d 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -198,12 +198,12 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) } /* Any defined maximum tmds clock limit we must not exceed? */ - if (connector->max_tmds_clock > 0) { + if (connector->display_info.max_tmds_clock > 0) { /* mode_clock is clock in kHz for mode to be modeset on this connector */ mode_clock = radeon_connector->pixelclock_for_modeset; /* Maximum allowable input clock in kHz */ - max_tmds_clock = connector->max_tmds_clock; + max_tmds_clock = connector->display_info.max_tmds_clock; DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", connector->name, mode_clock, max_tmds_clock); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 5928cb74a06d..287a610f464e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -166,6 +166,17 @@ struct drm_display_info { */ u32 bus_flags; + /** + * @max_tmds_clock: Maximum TMDS clock rate supported by the + * sink in kHz. 0 means undefined. + */ + int max_tmds_clock; + + /** + * @dvi_dual: Dual-link DVI sink? + */ + bool dvi_dual; + /** * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even * more stuff redundant with @bus_formats. @@ -515,8 +526,6 @@ struct drm_cmdline_mode { * @encoder_ids: valid encoders for this connector * @encoder: encoder driving this connector, if any * @eld: EDID-like data, if present - * @dvi_dual: dual link DVI, if found - * @max_tmds_clock: max clock rate, if found * @latency_present: AV delay info from ELD, if found * @video_latency: video latency info from ELD, if found * @audio_latency: audio latency info from ELD, if found @@ -650,8 +659,6 @@ struct drm_connector { #define MAX_ELD_BYTES 128 /* EDID bits */ uint8_t eld[MAX_ELD_BYTES]; - bool dvi_dual; - int max_tmds_clock; /* in kHz */ bool latency_present[2]; int video_latency[2]; /* [0]: progressive, [1]: interlaced */ int audio_latency[2]; -- cgit v1.2.3 From 1826750f5775fa17909d02755bc872dfcfc6685e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:38 +0300 Subject: drm/edid: Don't pass around drm_display_info needlessly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already pass the connector to drm_add_display_info() and drm_assign_hdmi_deep_color_info(), so passing the connector->display_info also is pointless. Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-6-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 81b9ef82af73..caa84a056779 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3738,9 +3738,9 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable); * Return true if HDMI deep color supported, false if not or unknown. */ static bool drm_assign_hdmi_deep_color_info(struct edid *edid, - struct drm_display_info *info, struct drm_connector *connector) { + struct drm_display_info *info = &connector->display_info; u8 *edid_ext, *hdmi; int i; int start_offset, end_offset; @@ -3828,9 +3828,9 @@ static bool drm_assign_hdmi_deep_color_info(struct edid *edid, } static void drm_add_display_info(struct edid *edid, - struct drm_display_info *info, struct drm_connector *connector) { + struct drm_display_info *info = &connector->display_info; u8 *edid_ext; info->width_mm = edid->width_cm * 10; @@ -3860,7 +3860,7 @@ static void drm_add_display_info(struct edid *edid, } /* HDMI deep color modes supported? Assign to info, if so */ - drm_assign_hdmi_deep_color_info(edid, info, connector); + drm_assign_hdmi_deep_color_info(edid, connector); /* * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3? @@ -4096,7 +4096,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); - drm_add_display_info(edid, &connector->display_info, connector); + drm_add_display_info(edid, connector); if (quirks & EDID_QUIRK_FORCE_6BPC) connector->display_info.bpc = 6; -- cgit v1.2.3 From 1cea146a806ae1f34cb1b5e3206ff63a2bb90782 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:39 +0300 Subject: drm/edid: Reduce the number of times we parse the CEA extension block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of parsing parts of the CEA extension block in two places to determine supported color formats and whatnot, let's just consolidate it to one function. This also makes it possible to neatly flatten drm_assign_hdmi_deep_color_info(). Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-7-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 185 +++++++++++++++++++++------------------------ 1 file changed, 88 insertions(+), 97 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index caa84a056779..ef8ae691f7aa 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3733,105 +3733,110 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) } EXPORT_SYMBOL(drm_rgb_quant_range_selectable); -/* - * Parse the CEA extension according to CEA-861-B. - * Return true if HDMI deep color supported, false if not or unknown. - */ -static bool drm_assign_hdmi_deep_color_info(struct edid *edid, - struct drm_connector *connector) +static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, + const u8 *hdmi) { struct drm_display_info *info = &connector->display_info; - u8 *edid_ext, *hdmi; - int i; - int start_offset, end_offset; unsigned int dc_bpc = 0; - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return false; + /* HDMI supports at least 8 bpc */ + info->bpc = 8; - if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) - return false; + if (cea_db_payload_len(hdmi) < 6) + return; + + if (hdmi[6] & DRM_EDID_HDMI_DC_30) { + dc_bpc = 10; + info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30; + DRM_DEBUG("%s: HDMI sink does deep color 30.\n", + connector->name); + } + + if (hdmi[6] & DRM_EDID_HDMI_DC_36) { + dc_bpc = 12; + info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; + DRM_DEBUG("%s: HDMI sink does deep color 36.\n", + connector->name); + } + + if (hdmi[6] & DRM_EDID_HDMI_DC_48) { + dc_bpc = 16; + info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; + DRM_DEBUG("%s: HDMI sink does deep color 48.\n", + connector->name); + } + + if (dc_bpc == 0) { + DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", + connector->name); + return; + } + + DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", + connector->name, dc_bpc); + info->bpc = dc_bpc; /* - * Because HDMI identifier is in Vendor Specific Block, - * search it from all data blocks of CEA extension. + * Deep color support mandates RGB444 support for all video + * modes and forbids YCRCB422 support for all video modes per + * HDMI 1.3 spec. */ - for_each_cea_db(edid_ext, i, start_offset, end_offset) { - if (cea_db_is_hdmi_vsdb(&edid_ext[i])) { - /* HDMI supports at least 8 bpc */ - info->bpc = 8; - - hdmi = &edid_ext[i]; - if (cea_db_payload_len(hdmi) < 6) - return false; - - if (hdmi[6] & DRM_EDID_HDMI_DC_30) { - dc_bpc = 10; - info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30; - DRM_DEBUG("%s: HDMI sink does deep color 30.\n", - connector->name); - } + info->color_formats = DRM_COLOR_FORMAT_RGB444; - if (hdmi[6] & DRM_EDID_HDMI_DC_36) { - dc_bpc = 12; - info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; - DRM_DEBUG("%s: HDMI sink does deep color 36.\n", - connector->name); - } + /* YCRCB444 is optional according to spec. */ + if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; + DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", + connector->name); + } - if (hdmi[6] & DRM_EDID_HDMI_DC_48) { - dc_bpc = 16; - info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; - DRM_DEBUG("%s: HDMI sink does deep color 48.\n", - connector->name); - } + /* + * Spec says that if any deep color mode is supported at all, + * then deep color 36 bit must be supported. + */ + if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) { + DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n", + connector->name); + } +} - if (dc_bpc > 0) { - DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", - connector->name, dc_bpc); - info->bpc = dc_bpc; - - /* - * Deep color support mandates RGB444 support for all video - * modes and forbids YCRCB422 support for all video modes per - * HDMI 1.3 spec. - */ - info->color_formats = DRM_COLOR_FORMAT_RGB444; - - /* YCRCB444 is optional according to spec. */ - if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { - info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; - DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", - connector->name); - } +static void drm_parse_cea_ext(struct drm_connector *connector, + struct edid *edid) +{ + struct drm_display_info *info = &connector->display_info; + const u8 *edid_ext; + int i, start, end; - /* - * Spec says that if any deep color mode is supported at all, - * then deep color 36 bit must be supported. - */ - if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) { - DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n", - connector->name); - } + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return; - return true; - } - else { - DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", - connector->name); - } - } - } + info->cea_rev = edid_ext[1]; - return false; + /* The existence of a CEA block should imply RGB support */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; + if (edid_ext[3] & EDID_CEA_YCRCB444) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; + if (edid_ext[3] & EDID_CEA_YCRCB422) + info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; + + if (cea_db_offsets(edid_ext, &start, &end)) + return; + + for_each_cea_db(edid_ext, i, start, end) { + const u8 *db = &edid_ext[i]; + + if (!cea_db_is_hdmi_vsdb(db)) + continue; + + drm_parse_hdmi_deep_color_info(connector, db); + } } -static void drm_add_display_info(struct edid *edid, - struct drm_connector *connector) +static void drm_add_display_info(struct drm_connector *connector, + struct edid *edid) { struct drm_display_info *info = &connector->display_info; - u8 *edid_ext; info->width_mm = edid->width_cm * 10; info->height_mm = edid->height_cm * 10; @@ -3846,21 +3851,7 @@ static void drm_add_display_info(struct edid *edid, if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) return; - /* Get data from CEA blocks if present */ - edid_ext = drm_find_cea_extension(edid); - if (edid_ext) { - info->cea_rev = edid_ext[1]; - - /* The existence of a CEA block should imply RGB support */ - info->color_formats = DRM_COLOR_FORMAT_RGB444; - if (edid_ext[3] & EDID_CEA_YCRCB444) - info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; - if (edid_ext[3] & EDID_CEA_YCRCB422) - info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; - } - - /* HDMI deep color modes supported? Assign to info, if so */ - drm_assign_hdmi_deep_color_info(edid, connector); + drm_parse_cea_ext(connector, edid); /* * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3? @@ -4096,7 +4087,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); - drm_add_display_info(edid, connector); + drm_add_display_info(connector, edid); if (quirks & EDID_QUIRK_FORCE_6BPC) connector->display_info.bpc = 6; -- cgit v1.2.3 From 011acce2859ad50b7a923cad4a726220b5f24455 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:40 +0300 Subject: drm/edid: Clear the old cea_rev when there's no CEA extension in the new EDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not a good idea to leave stale cea_rev in the drm_display_info. The current EDID might not even have a CEA ext block in which case we'd end up leaving the stale value in place. Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-8-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ef8ae691f7aa..48e529df344e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3844,6 +3844,7 @@ static void drm_add_display_info(struct drm_connector *connector, /* driver figures it out in this case */ info->bpc = 0; info->color_formats = 0; + info->cea_rev = 0; if (edid->revision < 3) return; -- cgit v1.2.3 From 23ebf8b9eab9151c3cccca8dbf44a8d47357158d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:41 +0300 Subject: drm/edid: Move dvi_dual/max_tmds_clock parsing out from drm_edid_to_eld() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_edid_to_eld() is just mean to cook up the ELD for the audio driver, so having it parse non-audio related stuff seems just wrong, and potentially could lead to that information not being even filled out if the function doesn't even get called. Let's move that stuff to the place where we parse the color formats and whatnot from the CEA ext block. Signed-off-by: Ville Syrjälä Acked-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-9-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 64 +++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 48e529df344e..ec77bd3e1f08 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3253,17 +3253,12 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) } static void -parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) +drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) { - struct drm_display_info *info = &connector->display_info; u8 len = cea_db_payload_len(db); - if (len >= 6) { + if (len >= 6) connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ - info->dvi_dual = db[6] & 1; - } - if (len >= 7) - info->max_tmds_clock = db[7] * 5000; if (len >= 8) { connector->latency_present[0] = db[8] >> 7; connector->latency_present[1] = (db[8] >> 6) & 1; @@ -3277,19 +3272,15 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) if (len >= 12) connector->audio_latency[1] = db[12]; - DRM_DEBUG_KMS("HDMI: DVI dual %d, " - "max TMDS clock %d, " - "latency present %d %d, " - "video latency %d %d, " - "audio latency %d %d\n", - info->dvi_dual, - info->max_tmds_clock, - (int) connector->latency_present[0], - (int) connector->latency_present[1], - connector->video_latency[0], - connector->video_latency[1], - connector->audio_latency[0], - connector->audio_latency[1]); + DRM_DEBUG_KMS("HDMI: latency present %d %d, " + "video latency %d %d, " + "audio latency %d %d\n", + connector->latency_present[0], + connector->latency_present[1], + connector->video_latency[0], + connector->video_latency[1], + connector->audio_latency[0], + connector->audio_latency[1]); } static void @@ -3350,7 +3341,6 @@ EXPORT_SYMBOL(drm_edid_get_monitor_name); */ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { - struct drm_display_info *info = &connector->display_info; uint8_t *eld = connector->eld; u8 *cea; u8 *db; @@ -3367,9 +3357,6 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) connector->video_latency[1] = 0; connector->audio_latency[1] = 0; - info->max_tmds_clock = 0; - info->dvi_dual = false; - cea = drm_find_cea_extension(edid); if (!cea) { DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); @@ -3419,7 +3406,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) case VENDOR_BLOCK: /* HDMI Vendor-Specific Data Block */ if (cea_db_is_hdmi_vsdb(db)) - parse_hdmi_vsdb(connector, db); + drm_parse_hdmi_vsdb_audio(connector, db); break; default: break; @@ -3800,6 +3787,25 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, } } +static void +drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) +{ + struct drm_display_info *info = &connector->display_info; + u8 len = cea_db_payload_len(db); + + if (len >= 6) + info->dvi_dual = db[6] & 1; + if (len >= 7) + info->max_tmds_clock = db[7] * 5000; + + DRM_DEBUG_KMS("HDMI: DVI dual %d, " + "max TMDS clock %d kHz\n", + info->dvi_dual, + info->max_tmds_clock); + + drm_parse_hdmi_deep_color_info(connector, db); +} + static void drm_parse_cea_ext(struct drm_connector *connector, struct edid *edid) { @@ -3826,10 +3832,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, for_each_cea_db(edid_ext, i, start, end) { const u8 *db = &edid_ext[i]; - if (!cea_db_is_hdmi_vsdb(db)) - continue; - - drm_parse_hdmi_deep_color_info(connector, db); + if (cea_db_is_hdmi_vsdb(db)) + drm_parse_hdmi_vsdb_video(connector, db); } } @@ -3845,6 +3849,8 @@ static void drm_add_display_info(struct drm_connector *connector, info->bpc = 0; info->color_formats = 0; info->cea_rev = 0; + info->max_tmds_clock = 0; + info->dvi_dual = false; if (edid->revision < 3) return; -- cgit v1.2.3 From 6a2a5c5dea7e83474f3481553caf00dc018647b3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:42 +0300 Subject: drm/i915: Replace a bunch of connector->base.display_info with a local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce the eyesore with a local variable. Signed-off-by: Ville Syrjälä Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-10-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d4c35d55b1b..ad8d712ae84c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12654,22 +12654,22 @@ static void connected_sink_compute_bpp(struct intel_connector *connector, struct intel_crtc_state *pipe_config) { + const struct drm_display_info *info = &connector->base.display_info; int bpp = pipe_config->pipe_bpp; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n", - connector->base.base.id, - connector->base.name); + connector->base.base.id, + connector->base.name); /* Don't use an invalid EDID bpc value */ - if (connector->base.display_info.bpc && - connector->base.display_info.bpc * 3 < bpp) { + if (info->bpc != 0 && info->bpc * 3 < bpp) { DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", - bpp, connector->base.display_info.bpc*3); - pipe_config->pipe_bpp = connector->base.display_info.bpc*3; + bpp, info->bpc * 3); + pipe_config->pipe_bpp = info->bpc * 3; } /* Clamp bpp to 8 on screens without EDID 1.4 */ - if (connector->base.display_info.bpc == 0 && bpp > 24) { + if (info->bpc == 0 && bpp > 24) { DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", bpp); pipe_config->pipe_bpp = 24; -- cgit v1.2.3 From 8cadab0a2adc612692c7ad8a176881732fa25e2a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2016 16:51:43 +0300 Subject: drm/i915: Account for sink max TMDS clock when checking the port clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's perfectly legal for the sink to support 12bpc only for some lower resolution modes, while the higher resolution modes can only be used with 8bpc. So let's take the sink's max TMDS clock into account before we go and decide that a particular mode can be used with 12bpc. Signed-off-by: Ville Syrjälä Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475070703-6435-11-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c51073f78730..f40a35f2913a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1220,10 +1220,17 @@ static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev)); if (respect_downstream_limits) { + struct intel_connector *connector = hdmi->attached_connector; + const struct drm_display_info *info = &connector->base.display_info; + if (hdmi->dp_dual_mode.max_tmds_clock) max_tmds_clock = min(max_tmds_clock, hdmi->dp_dual_mode.max_tmds_clock); - if (!hdmi->has_hdmi_sink) + + if (info->max_tmds_clock) + max_tmds_clock = min(max_tmds_clock, + info->max_tmds_clock); + else if (!hdmi->has_hdmi_sink) max_tmds_clock = min(max_tmds_clock, 165000); } -- cgit v1.2.3 From 6bd488db80a4264669a7d612a1be1a91cb941cf6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 25 Sep 2016 19:18:34 -0700 Subject: drm: Simplify drm_printk to reduce object size quite a bit Remove function name and special " *ERROR*" from argument list $ size drivers/gpu/drm/built-in.o* (x86-32 defconfig, most drm selected) text data bss dec hex filename 5635366 182579 14328 5832273 58fe51 drivers/gpu/drm/built-in.o.new 5779552 182579 14328 5976459 5b318b drivers/gpu/drm/built-in.o.old Using "%ps", __builtin_return_address(0) is the same as "%s", __func__ except for static inlines, but it's more or less the same output. Miscellanea: o Convert args... to ##__VA_ARGS__ o The equivalent DRM_DEV_ macros are rarely used and not worth conversion Reviewed-by: Chris Wilson Signed-off-by: Joe Perches Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/01f976d5ab93c985756fc1b2e83656fb0a2a28c8.1474856262.git.joe@perches.com --- drivers/gpu/drm/drm_drv.c | 5 +++-- include/drm/drmP.h | 30 ++++++++++++++---------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 80c7f25b5b74..6efdba4993fc 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -89,7 +89,6 @@ void drm_dev_printk(const struct device *dev, const char *level, EXPORT_SYMBOL(drm_dev_printk); void drm_printk(const char *level, unsigned int category, - const char *function_name, const char *prefix, const char *format, ...) { struct va_format vaf; @@ -102,7 +101,9 @@ void drm_printk(const char *level, unsigned int category, vaf.fmt = format; vaf.va = &args; - printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); + printk("%s" "[" DRM_NAME ":%ps]%s %pV", + level, __builtin_return_address(0), + strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf); va_end(args); } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 289207f12adb..0e99669159c1 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -141,9 +141,8 @@ void drm_dev_printk(const struct device *dev, const char *level, unsigned int category, const char *function_name, const char *prefix, const char *format, ...); -extern __printf(5, 6) +extern __printf(3, 4) void drm_printk(const char *level, unsigned int category, - const char *function_name, const char *prefix, const char *format, ...); /***********************************************************************/ @@ -199,8 +198,7 @@ void drm_printk(const char *level, unsigned int category, drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\ fmt, ##__VA_ARGS__) #define DRM_ERROR(fmt, ...) \ - drm_printk(KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*", fmt, \ - ##__VA_ARGS__) + drm_printk(KERN_ERR, DRM_UT_NONE, fmt, ##__VA_ARGS__) /** * Rate limited error output. Like DRM_ERROR() but won't flood the log. @@ -242,38 +240,38 @@ void drm_printk(const char *level, unsigned int category, #define DRM_DEV_DEBUG(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \ ##args) -#define DRM_DEBUG(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, ##args) +#define DRM_DEBUG(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__) #define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \ fmt, ##args) -#define DRM_DEBUG_DRIVER(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_DRIVER, __func__, "", fmt, ##args) +#define DRM_DEBUG_DRIVER(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) #define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \ ##args) -#define DRM_DEBUG_KMS(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, ##args) +#define DRM_DEBUG_KMS(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__) #define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \ fmt, ##args) -#define DRM_DEBUG_PRIME(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_PRIME, __func__, "", fmt, ##args) +#define DRM_DEBUG_PRIME(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__) #define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \ fmt, ##args) -#define DRM_DEBUG_ATOMIC(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", fmt, ##args) +#define DRM_DEBUG_ATOMIC(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__) #define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \ drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \ ##args) -#define DRM_DEBUG_VBL(fmt, args...) \ - drm_printk(KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, ##args) +#define DRM_DEBUG_VBL(fmt, ...) \ + drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__) #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \ ({ \ -- cgit v1.2.3 From 58f0f9f75c1b94dabbfc3daa333a4e68536b0a42 Mon Sep 17 00:00:00 2001 From: Emilio López Date: Tue, 27 Sep 2016 11:31:42 -0300 Subject: uapi: add missing install of sync_file.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of the sync framework destaging, the sync_file.h header was moved, but an entry was not added on Kbuild to install it. This patch resolves this omission so that "make headers_install" installs this header. Fixes: 460bfc41fd52 ("dma-buf/sync_file: de-stage sync_file headers") Reported-by: Michael Ellerman Reviewed-by: Gustavo Padovan Signed-off-by: Emilio López Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/20160927143142.8975-1-emilio.lopez@collabora.co.uk --- include/uapi/linux/Kbuild | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 185f8ea2702f..407ca0d7a938 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -396,6 +396,7 @@ header-y += string.h header-y += suspend_ioctls.h header-y += swab.h header-y += synclink.h +header-y += sync_file.h header-y += sysctl.h header-y += sysinfo.h header-y += target_core_user.h -- cgit v1.2.3 From 61802130d85fdaf9646340bf1cc64b3e06d0b19c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 30 Sep 2016 12:04:56 +0200 Subject: drm: Document caveats around atomic event handling It's not that obvious how a driver can all race the atomic commit with handling the completion event. And there's unfortunately a pile of drivers with rather bad event handling which misdirect people into the wrong direction. Try to remedy this by documenting everything better. v2: Type fixes Alex spotted. v3: More typos Alex spotted. Cc: Andrzej Hajda Cc: Alex Deucher Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475229896-6047-1-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_irq.c | 32 +++++++++++++++++++++++++-- include/drm/drm_crtc.h | 56 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 404a1ce7730c..b969a64a1514 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1008,6 +1008,31 @@ static void send_vblank_event(struct drm_device *dev, * period. This helper function implements exactly the required vblank arming * behaviour. * + * NOTE: Drivers using this to send out the event in struct &drm_crtc_state + * as part of an atomic commit must ensure that the next vblank happens at + * exactly the same time as the atomic commit is committed to the hardware. This + * function itself does **not** protect again the next vblank interrupt racing + * with either this function call or the atomic commit operation. A possible + * sequence could be: + * + * 1. Driver commits new hardware state into vblank-synchronized registers. + * 2. A vblank happens, committing the hardware state. Also the corresponding + * vblank interrupt is fired off and fully processed by the interrupt + * handler. + * 3. The atomic commit operation proceeds to call drm_crtc_arm_vblank_event(). + * 4. The event is only send out for the next vblank, which is wrong. + * + * An equivalent race can happen when the driver calls + * drm_crtc_arm_vblank_event() before writing out the new hardware state. + * + * The only way to make this work safely is to prevent the vblank from firing + * (and the hardware from committing anything else) until the entire atomic + * commit sequence has run to completion. If the hardware does not have such a + * feature (e.g. using a "go" bit), then it is unsafe to use this functions. + * Instead drivers need to manually send out the event from their interrupt + * handler by calling drm_crtc_send_vblank_event() and make sure that there's no + * possible race with the hardware committing the atomic update. + * * Caller must hold event lock. Caller must also hold a vblank reference for * the event @e, which will be dropped when the next vblank arrives. */ @@ -1030,8 +1055,11 @@ EXPORT_SYMBOL(drm_crtc_arm_vblank_event); * @crtc: the source CRTC of the vblank event * @e: the event to send * - * Updates sequence # and timestamp on event, and sends it to userspace. - * Caller must hold event lock. + * Updates sequence # and timestamp on event for the most recently processed + * vblank, and sends it to userspace. Caller must hold event lock. + * + * See drm_crtc_arm_vblank_event() for a helper which can be used in certain + * situation, especially to send out events for atomic commit operations. */ void drm_crtc_send_vblank_event(struct drm_crtc *crtc, struct drm_pending_vblank_event *e) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a544b7502493..61932f55f788 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -109,8 +109,6 @@ struct drm_plane_helper_funcs; * @ctm: Transformation matrix * @gamma_lut: Lookup table for converting pixel data after the * conversion matrix - * @event: optional pointer to a DRM event to signal upon completion of the - * state update * @state: backpointer to global drm_atomic_state * * Note that the distinction between @enable and @active is rather subtile: @@ -159,6 +157,46 @@ struct drm_crtc_state { struct drm_property_blob *ctm; struct drm_property_blob *gamma_lut; + /** + * @event: + * + * Optional pointer to a DRM event to signal upon completion of the + * state update. The driver must send out the event when the atomic + * commit operation completes. There are two cases: + * + * - The event is for a CRTC which is being disabled through this + * atomic commit. In that case the event can be send out any time + * after the hardware has stopped scanning out the current + * framebuffers. It should contain the timestamp and counter for the + * last vblank before the display pipeline was shut off. + * + * - For a CRTC which is enabled at the end of the commit (even when it + * undergoes an full modeset) the vblank timestamp and counter must + * be for the vblank right before the first frame that scans out the + * new set of buffers. Again the event can only be sent out after the + * hardware has stopped scanning out the old buffers. + * + * - Events for disabled CRTCs are not allowed, and drivers can ignore + * that case. + * + * This can be handled by the drm_crtc_send_vblank_event() function, + * which the driver should call on the provided event upon completion of + * the atomic commit. Note that if the driver supports vblank signalling + * and timestamping the vblank counters and timestamps must agree with + * the ones returned from page flip events. With the current vblank + * helper infrastructure this can be achieved by holding a vblank + * reference while the page flip is pending, acquired through + * drm_crtc_vblank_get() and released with drm_crtc_vblank_put(). + * Drivers are free to implement their own vblank counter and timestamp + * tracking though, e.g. if they have accurate timestamp registers in + * hardware. + * + * For hardware which supports some means to synchronize vblank + * interrupt delivery with committing display state there's also + * drm_crtc_arm_vblank_event(). See the documentation of that function + * for a detailed discussion of the constraints it needs to be used + * safely. + */ struct drm_pending_vblank_event *event; struct drm_atomic_state *state; @@ -835,17 +873,9 @@ struct drm_mode_config_funcs { * CRTC index supplied in &drm_event to userspace. * * The drm core will supply a struct &drm_event in the event - * member of each CRTC's &drm_crtc_state structure. This can be handled by the - * drm_crtc_send_vblank_event() function, which the driver should call on - * the provided event upon completion of the atomic commit. Note that if - * the driver supports vblank signalling and timestamping the vblank - * counters and timestamps must agree with the ones returned from page - * flip events. With the current vblank helper infrastructure this can - * be achieved by holding a vblank reference while the page flip is - * pending, acquired through drm_crtc_vblank_get() and released with - * drm_crtc_vblank_put(). Drivers are free to implement their own vblank - * counter and timestamp tracking though, e.g. if they have accurate - * timestamp registers in hardware. + * member of each CRTC's &drm_crtc_state structure. See the + * documentation for &drm_crtc_state for more details about the precise + * semantics of this event. * * NOTE: * -- cgit v1.2.3 From 74064893901ac5103cf101ecef5946e82b6ce9c6 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Thu, 29 Sep 2016 22:48:37 +0200 Subject: drm/fb-helper: add DRM_FB_HELPER_DEFAULT_OPS for fb_ops The define DRM_FB_HELPER_DEFAULT_OPS provides the drm_fb_helper default implementations for functions in struct fb_ops. A drm driver can use it like: static struct fb_ops drm_fbdev_cma_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, /* driver specific implementations */ }; Suggested-by: Daniel Vetter Signed-off-by: Stefan Christ Reviewed-by: Gustavo Padovan Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475182136-15191-2-git-send-email-contact@stefanchrist.eu --- include/drm/drm_fb_helper.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index e19458dd1a43..3c5f5992b96a 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -217,6 +217,19 @@ struct drm_fb_helper { bool delayed_hotplug; }; +/** + * @DRM_FB_HELPER_DEFAULT_OPS: + * + * Helper define to register default implementations of drm_fb_helper + * functions. To be used in struct fb_ops of drm drivers. + */ +#define DRM_FB_HELPER_DEFAULT_OPS \ + .fb_check_var = drm_fb_helper_check_var, \ + .fb_set_par = drm_fb_helper_set_par, \ + .fb_setcmap = drm_fb_helper_setcmap, \ + .fb_blank = drm_fb_helper_blank, \ + .fb_pan_display = drm_fb_helper_pan_display + #ifdef CONFIG_DRM_FBDEV_EMULATION void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, const struct drm_fb_helper_funcs *funcs); -- cgit v1.2.3 From 561b069008dcf1b2909aebb7a904a32c7d802a93 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 23 Sep 2016 16:06:39 +0200 Subject: drm/bridge: analogix_dp: Add analogix_dp_psr_supported So users know whether PSR should be enabled or not. Cc: Yakir Yang Reviewed-by: Sean Paul Signed-off-by: Tomeu Vizoso Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1474639600-30090-1-git-send-email-tomeu.vizoso@collabora.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 8 ++++++++ include/drm/bridge/analogix_dp.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 0f2e42310694..001b075e171b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -98,6 +98,14 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_psr_supported(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + return dp->psr_support; +} +EXPORT_SYMBOL_GPL(analogix_dp_psr_supported); + int analogix_dp_enable_psr(struct device *dev) { struct analogix_dp_device *dp = dev_get_drvdata(dev); diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 9cd8838e1ec3..f6f0c062205c 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -38,6 +38,7 @@ struct analogix_dp_plat_data { struct drm_connector *); }; +int analogix_dp_psr_supported(struct device *dev); int analogix_dp_enable_psr(struct device *dev); int analogix_dp_disable_psr(struct device *dev); -- cgit v1.2.3 From 0546d685f07cc4fc5748fd36e57d167877c2842d Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 23 Sep 2016 16:06:40 +0200 Subject: drm/rockchip: analogix_dp: Refuse to enable PSR if panel doesn't support it There's no point in enabling PSR when the panel doesn't support it. This also avoids a problem when PSR gets enabled when a CRTC is being disabled, because sometimes in that situation the DSP_HOLD_VALID_INTR interrupt on which we wait will never arrive. This was observed on RK3288 with a panel without PSR (veyron-jaq Chromebook). It's very easy to reproduce by running the kms_rmfb test in IGT a few times. Cc: Yakir Yang Reviewed-by: Sean Paul Signed-off-by: Tomeu Vizoso Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1474639600-30090-2-git-send-email-tomeu.vizoso@collabora.com --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e83be157cc2a..8548e8271639 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -85,6 +85,9 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) struct rockchip_dp_device *dp = to_dp(encoder); unsigned long flags; + if (!analogix_dp_psr_supported(dp->dev)) + return; + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); spin_lock_irqsave(&dp->psr_lock, flags); -- cgit v1.2.3