From f0e36723a68dfd959168c73bfa7ca6fa426eadf5 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Mon, 9 Jan 2017 19:56:48 -0200 Subject: drm: Document drm_cache interface Notice that this uncovers an issue with the kernel-doc handling of array arguments, causing the first parameter of drm_clflush_pages() to not show up in the rst-generated page. A proposed fix is under review in linux-doc: Changes since v1: - Add section to drm-mm.rst. - Fix kernel-doc style issues. - s/memory/kernel memory/. Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170109215649.6860-1-krisman@collabora.co.uk --- Documentation/gpu/drm-mm.rst | 6 ++++++ drivers/gpu/drm/drm_cache.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 1ea94fc86caa..91d82f39fbf4 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -470,3 +470,9 @@ DRM MM Range Allocator Function References .. kernel-doc:: include/drm/drm_mm.h :internal: + +DRM Cache Handling +================== + +.. kernel-doc:: drivers/gpu/drm/drm_cache.c + :export: diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index a7916e5f8864..5066638928ec 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -67,6 +67,14 @@ static void drm_cache_flush_clflush(struct page *pages[], } #endif +/** + * drm_clflush_pages - Flush dcache lines of a set of pages. + * @pages: List of pages to be flushed. + * @num_pages: Number of pages in the array. + * + * Flush every data cache line entry that points to an address belonging + * to a page in the array. + */ void drm_clflush_pages(struct page *pages[], unsigned long num_pages) { @@ -101,6 +109,13 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) } EXPORT_SYMBOL(drm_clflush_pages); +/** + * drm_clflush_sg - Flush dcache lines pointing to a scather-gather. + * @st: struct sg_table. + * + * Flush every data cache line entry that points to an address in the + * sg. + */ void drm_clflush_sg(struct sg_table *st) { @@ -125,6 +140,14 @@ drm_clflush_sg(struct sg_table *st) } EXPORT_SYMBOL(drm_clflush_sg); +/** + * drm_clflush_virt_range - Flush dcache lines of a region + * @addr: Initial kernel memory address. + * @length: Region size. + * + * Flush every data cache line entry that points to an address in the + * region requested. + */ void drm_clflush_virt_range(void *addr, unsigned long length) { -- cgit v1.3.1 From f9a87bd7d5b64075af87345ae42f3984c56bddb6 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Mon, 9 Jan 2017 19:56:49 -0200 Subject: drm: Move drm_clflush prototypes to drm_cache header file Continue to clean up drmP.h by moving the cache flushing functions into it's own header file. Compile-tested only Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170109215649.6860-2-krisman@collabora.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/vgem/vgem_drv.h | 1 + include/drm/drmP.h | 5 ----- include/drm/drm_cache.h | 4 ++++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 52d01be956cc..24eb16231938 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -49,6 +49,7 @@ #include /* for struct drm_dma_handle */ #include #include +#include #include "i915_params.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h index 1f8798ad329c..cb59c7ab98b9 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.h +++ b/drivers/gpu/drm/vgem/vgem_drv.h @@ -31,6 +31,7 @@ #include #include +#include #include diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 9af3bb14641f..e5882d5a68e5 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -731,11 +731,6 @@ int drm_noop(struct drm_device *dev, void *data, int drm_invalid_op(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* Cache management (drm_cache.c) */ -void drm_clflush_pages(struct page *pages[], unsigned long num_pages); -void drm_clflush_sg(struct sg_table *st); -void drm_clflush_virt_range(void *addr, unsigned long length); - /* * These are exported to drivers so that they can implement fencing using * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index cebecff536a3..beab0f0d0cfb 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h @@ -33,7 +33,11 @@ #ifndef _DRM_CACHE_H_ #define _DRM_CACHE_H_ +#include + void drm_clflush_pages(struct page *pages[], unsigned long num_pages); +void drm_clflush_sg(struct sg_table *st); +void drm_clflush_virt_range(void *addr, unsigned long length); static inline bool drm_arch_can_wc_memory(void) { -- cgit v1.3.1 From fc36ec76f3f6a6578086b5c045322805df0b9d83 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 9 Jan 2017 23:24:53 +0530 Subject: drm/exynos: constify exynos_drm_crtc_ops structures Declare exynos_drm_crtc_ops structures as const as they are only passed as an argument to the function exynos_drm_crtc_create. This argument is of type const struct exynos_drm_crtc_ops *, so exynos_drm_crtc_ops structures having this property can be declared const. Done using Coccinelle: @r disable optional_qualifier@ identifier i; position p; @@ static struct exynos_drm_crtc_ops i@p={...}; @ok@ position p; identifier r.i; @@ exynos_drm_crtc_create(...,&i@p,...) @bad@ position p!={r.p,ok.p}; identifier r.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ +const struct exynos_drm_crtc_ops i; File size before: text data bss dec hex filename 5008 280 0 5288 14a8 exynos/exynos5433_drm_decon.o File size after: text data bss dec hex filename 5120 176 0 5296 14b0 exynos/exynos5433_drm_decon.o Signed-off-by: Bhumika Goyal Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1483984493-25284-1-git-send-email-bhumirks@gmail.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index c5c01628c715..31eafc546d6c 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -470,7 +470,7 @@ err: clk_disable_unprepare(ctx->clks[i]); } -static struct exynos_drm_crtc_ops decon_crtc_ops = { +static const struct exynos_drm_crtc_ops decon_crtc_ops = { .enable = decon_enable, .disable = decon_disable, .enable_vblank = decon_enable_vblank, -- cgit v1.3.1 From 95b8c64afad824014178df6b396c6ba0f4b1b80a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Jan 2017 14:40:31 +0000 Subject: drm: Fix error handling in drm_mm eviction kselftest drivers/gpu/drm/selftests/test-drm_mm.c:1277 evict_everything() warn: calling list_del() inside list_for_each The list_del() inside the error handling in the eviction loop is overkill. We have to undo the eviction scan to return the drm_mm back to a recoverable state, so have to iterate over the full list, but we only want to report the error once and once we have an error we can return early. Reported-by: Dan Carpenter Fixes: 560b32842912 ("drm: kselftest for drm_mm and eviction") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Daniel Vetter Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170110144031.7609-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/selftests/test-drm_mm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c index 6d2a5cd211f3..6df53e6c1308 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/selftests/test-drm_mm.c @@ -1274,13 +1274,19 @@ static bool evict_everything(struct drm_mm *mm, if (drm_mm_scan_add_block(&scan, &e->node)) break; } + + err = 0; list_for_each_entry(e, &evict_list, link) { if (!drm_mm_scan_remove_block(&scan, &e->node)) { - pr_err("Node %lld not marked for eviction!\n", - e->node.start); - list_del(&e->link); + if (!err) { + pr_err("Node %lld not marked for eviction!\n", + e->node.start); + err = -EINVAL; + } } } + if (err) + return false; list_for_each_entry(e, &evict_list, link) drm_mm_remove_node(&e->node); -- cgit v1.3.1 From f0c379a1cc294fdc6b925f01249477960edc3b90 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Jan 2017 14:33:35 +0100 Subject: drm: add more MMU dependencies Many DRM drivers only work with an MMU, and after the patch to enable core DRM support without MMU, we already had one fixup for many of them. The etnaviv, armada and msm drivers were missed and have the same problem: warning: (DRM_ETNAVIV) selects IOMMU_SUPPORT which has unmet direct dependencies (MMU) warning: (DRM_I915 && DRM_MSM && DRM_ETNAVIV) selects SHMEM which has unmet direct dependencies (MMU) drivers/gpu/drm/armada/armada_gem.o: In function `armada_gem_vm_fault': armada_gem.c:(.text.armada_gem_vm_fault+0x14): undefined reference to `vm_insert_pfn' arch/arm/mm/dma-mapping.c: In function '__iommu_alloc_remap': arch/arm/mm/dma-mapping.c:1390:4: error: 'VM_ARM_DMA_CONSISTENT' undeclared (first use in this function) arch/arm/mm/dma-mapping.c:1456:31: error: 'atomic_pool' undeclared (first use in this function); did you mean 'atomic_xor'? Fixes: 011cda589938 ("drm: fix compilations issues introduced by "drm: allow to use mmuless SoC"") Fixes: 62a0d98a188c ("drm: allow to use mmuless SoC") Signed-off-by: Arnd Bergmann Acked-by: Lucas Stach Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170111133357.3664191-2-arnd@arndb.de --- drivers/gpu/drm/armada/Kconfig | 2 +- drivers/gpu/drm/etnaviv/Kconfig | 1 + drivers/gpu/drm/msm/Kconfig | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index 15f3ecfb16f1..eafaeeb7b5b1 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -1,6 +1,6 @@ config DRM_ARMADA tristate "DRM support for Marvell Armada SoCs" - depends on DRM && HAVE_CLK && ARM + depends on DRM && HAVE_CLK && ARM && MMU select DRM_KMS_HELPER help Support the "LCD" controllers found on the Marvell Armada 510 diff --git a/drivers/gpu/drm/etnaviv/Kconfig b/drivers/gpu/drm/etnaviv/Kconfig index 2cde7a5442fb..656c061b439d 100644 --- a/drivers/gpu/drm/etnaviv/Kconfig +++ b/drivers/gpu/drm/etnaviv/Kconfig @@ -3,6 +3,7 @@ config DRM_ETNAVIV tristate "ETNAVIV (DRM support for Vivante GPU IP cores)" depends on DRM depends on ARCH_MXC || ARCH_DOVE + depends on MMU select SHMEM select TMPFS select IOMMU_API diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index d96b2b6898a3..7f78da695dff 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -4,6 +4,7 @@ config DRM_MSM depends on DRM depends on ARCH_QCOM || (ARM && COMPILE_TEST) depends on OF && COMMON_CLK + depends on MMU select REGULATOR select DRM_KMS_HELPER select DRM_PANEL -- cgit v1.3.1 From fd056f05b9fcba35b77ec5b20e553cc48884c11c Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 4 Jan 2017 19:38:55 +0100 Subject: drm: add fourcc codes for 16bit R and RG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds fourcc codes for 16bit planes required for DRM buffer export to mesa. Signed-off-by: Rainer Hochecker Link: http://patchwork.freedesktop.org/patch/msgid/20170104183855.3852-1-fernetmenta@kodi.tv Reviewed-by: Ville Syrjälä Acked-by: Christian König Signed-off-by: Ville Syrjälä --- include/uapi/drm/drm_fourcc.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 9e1bb7fabcde..1596d53c9ccf 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -41,10 +41,17 @@ extern "C" { /* 8 bpp Red */ #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ +/* 16 bpp Red */ +#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */ + /* 16 bpp RG */ #define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */ #define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ +/* 32 bpp RG */ +#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */ +#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */ + /* 8 bpp RGB */ #define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ #define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ -- cgit v1.3.1 From f869a6ecf254194d96f82c71f528a2bcc048d44b Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Fri, 6 Jan 2017 15:39:40 -0500 Subject: drm/atomic: Add target_vblank support in atomic helpers (v2) Allows usage of the new page_flip_target hook for drivers implementing the atomic path. Provides default atomic helper for the new hook. v2: Update code sharing logic between exsiting and the new flip hooks. Improve kerneldoc. Signed-off-by: Andrey Grodzovsky Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1483735180-4173-1-git-send-email-Andrey.Grodzovsky@amd.com --- drivers/gpu/drm/drm_atomic_helper.c | 133 ++++++++++++++++++++++++++++++------ include/drm/drm_atomic_helper.h | 6 ++ include/drm/drm_crtc.h | 9 +++ 3 files changed, 127 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 9460f3a4c1c2..3cfe2cbb1fe6 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2706,6 +2706,44 @@ backoff: } EXPORT_SYMBOL(drm_atomic_helper_connector_set_property); +static int page_flip_common( + struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_plane *plane = crtc->primary; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + int ret = 0; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->event = event; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (ret != 0) + return ret; + drm_atomic_set_fb_for_plane(plane_state, fb); + + /* Make sure we don't accidentally do a full modeset. */ + state->allow_modeset = false; + if (!crtc_state->active) { + DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n", + crtc->base.id); + return -EINVAL; + } + + return ret; +} + /** * drm_atomic_helper_page_flip - execute a legacy page flip * @crtc: DRM crtc @@ -2713,7 +2751,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property); * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates * - * Provides a default page flip implementation using the atomic driver interface. + * Provides a default &drm_crtc_funcs.page_flip implementation + * using the atomic driver interface. * * Note that for now so called async page flips (i.e. updates which are not * synchronized to vblank) are not supported, since the atomic interfaces have @@ -2721,6 +2760,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_set_property); * * Returns: * Returns 0 on success, negative errno numbers on failure. + * + * See also: + * drm_atomic_helper_page_flip_target() */ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -2729,8 +2771,6 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, { struct drm_plane *plane = crtc->primary; struct drm_atomic_state *state; - struct drm_plane_state *plane_state; - struct drm_crtc_state *crtc_state; int ret = 0; if (flags & DRM_MODE_PAGE_FLIP_ASYNC) @@ -2741,35 +2781,86 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, return -ENOMEM; state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + retry: - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); + ret = page_flip_common(state, crtc, fb, event); + if (ret != 0) goto fail; - } - crtc_state->event = event; - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - ret = PTR_ERR(plane_state); - goto fail; - } + ret = drm_atomic_nonblocking_commit(state); - ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); +fail: + if (ret == -EDEADLK) + goto backoff; + + drm_atomic_state_put(state); + return ret; + +backoff: + drm_atomic_state_clear(state); + drm_atomic_legacy_backoff(state); + + /* + * Someone might have exchanged the framebuffer while we dropped locks + * in the backoff code. We need to fix up the fb refcount tracking the + * core does for us. + */ + plane->old_fb = plane->fb; + + goto retry; +} +EXPORT_SYMBOL(drm_atomic_helper_page_flip); + +/** + * drm_atomic_helper_page_flip_target - do page flip on target vblank period. + * @crtc: DRM crtc + * @fb: DRM framebuffer + * @event: optional DRM event to signal upon completion + * @flags: flip flags for non-vblank sync'ed updates + * @target: specifying the target vblank period when the flip to take effect + * + * Provides a default &drm_crtc_funcs.page_flip_target implementation. + * Similar to drm_atomic_helper_page_flip() with extra parameter to specify + * target vblank period to flip. + * + * Returns: + * Returns 0 on success, negative errno numbers on failure. + */ +int drm_atomic_helper_page_flip_target( + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags, + uint32_t target) +{ + struct drm_plane *plane = crtc->primary; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + int ret = 0; + + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) + return -EINVAL; + + state = drm_atomic_state_alloc(plane->dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + +retry: + ret = page_flip_common(state, crtc, fb, event); if (ret != 0) goto fail; - drm_atomic_set_fb_for_plane(plane_state, fb); - /* Make sure we don't accidentally do a full modeset. */ - state->allow_modeset = false; - if (!crtc_state->active) { - DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n", - crtc->base.id); + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (WARN_ON(!crtc_state)) { ret = -EINVAL; goto fail; } + crtc_state->target_vblank = target; ret = drm_atomic_nonblocking_commit(state); + fail: if (ret == -EDEADLK) goto backoff; @@ -2790,7 +2881,7 @@ backoff: goto retry; } -EXPORT_SYMBOL(drm_atomic_helper_page_flip); +EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); /** * drm_atomic_helper_connector_dpms() - connector dpms helper implementation diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 4b2353dc34ba..9afcd3810785 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -121,6 +121,12 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags); +int drm_atomic_helper_page_flip_target( + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags, + uint32_t target); int drm_atomic_helper_connector_dpms(struct drm_connector *connector, int mode); struct drm_encoder * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 17c9f52d6ecb..06c943d1e04c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -148,6 +148,15 @@ struct drm_crtc_state { struct drm_property_blob *ctm; struct drm_property_blob *gamma_lut; + /** + * @target_vblank: + * + * Target vertical blank period when a page flip + * should take effect. + */ + + u32 target_vblank; + /** * @event: * -- cgit v1.3.1 From f5c5d57a949cd0a17254581f848562c7076166f9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 27 Dec 2016 11:49:21 +0100 Subject: drm/msm: Stop using drm_framebuffer_unregister_private This is the deprecated function for when you embedded the framebuffer somewhere else (which breaks refcounting). But msm is using drm_framebuffer_remove and a free-standing fb, so this is rendundant. Cc: Rob Clark Reviewed-by: Archit Taneja Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1482835765-12044-1-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/msm/msm_fbdev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 5d68ab362d75..f8a587eac6b8 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -174,10 +174,8 @@ fail_unlock: fail: if (ret) { - if (fb) { - drm_framebuffer_unregister_private(fb); + if (fb) drm_framebuffer_remove(fb); - } } return ret; @@ -247,7 +245,6 @@ void msm_fbdev_free(struct drm_device *dev) /* this will free the backing object */ if (fbdev->fb) { msm_gem_put_vaddr(fbdev->bo); - drm_framebuffer_unregister_private(fbdev->fb); drm_framebuffer_remove(fbdev->fb); } -- cgit v1.3.1 From 7e53c284ec7e056e2f94faba623c6c2759552464 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 12 Jan 2017 09:57:36 +0100 Subject: drm: fix MMU dependencies DRM_VM and DRM_LEGACY shouldn't be selected if MMU isn't set. Fixes: 62a0d98a188c ("drm: allow to use mmuless SoC") Signed-off-by: Benjamin Gaignard Cc: Arnd Bergmann Cc: Daniel Vetter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1484211456-5759-1-git-send-email-benjamin.gaignard@linaro.org --- drivers/gpu/drm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6f3f9e68c218..90bc65d07a35 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -138,7 +138,7 @@ config DRM_KMS_CMA_HELPER config DRM_VM bool - depends on DRM + depends on DRM && MMU source "drivers/gpu/drm/i2c/Kconfig" @@ -267,7 +267,7 @@ source "drivers/gpu/drm/meson/Kconfig" menuconfig DRM_LEGACY bool "Enable legacy drivers (DANGEROUS)" - depends on DRM + depends on DRM && MMU select DRM_VM help Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous -- cgit v1.3.1 From b77bc10bba410637dfe25396e9784f5dc43ab817 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 27 Dec 2016 11:49:24 +0100 Subject: drm/omap: Stop using drm_framebuffer_unregister_private This is the deprecated function for when you embedded the framebuffer somewhere else (which breaks refcounting). But omapdrm is using drm_framebuffer_remove and a free-standing fb, so this is rendundant. Cc: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1482835765-12044-4-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index aed99a0fc44b..2a839956dae6 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -225,10 +225,8 @@ fail: drm_fb_helper_release_fbi(helper); - if (fb) { - drm_framebuffer_unregister_private(fb); + if (fb) drm_framebuffer_remove(fb); - } } return ret; @@ -314,10 +312,8 @@ void omap_fbdev_free(struct drm_device *dev) omap_gem_put_paddr(fbdev->bo); /* this will free the backing object */ - if (fbdev->fb) { - drm_framebuffer_unregister_private(fbdev->fb); + if (fbdev->fb) drm_framebuffer_remove(fbdev->fb); - } kfree(fbdev); -- cgit v1.3.1 From 2384d62385aea91d7ec1589287b6daa41af1ed8b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 27 Dec 2016 11:49:22 +0100 Subject: drm/cma-helper: Stop using drm_framebuffer_unregister_private This is the deprecated function for when you embedded the framebuffer somewhere else (which breaks refcounting). But cma helpers are using drm_framebuffer_remove and a free-standing fb, so this is rendundant. Cc: Laurent Pinchart Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1482835765-12044-2-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_fb_cma_helper.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 20a4011f790d..4364abfb6a71 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -473,8 +473,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper, return 0; err_cma_destroy: - drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); - drm_fb_cma_destroy(&fbdev_cma->fb->fb); + drm_framebuffer_remove(&fbdev_cma->fb->fb); err_fb_info_destroy: drm_fb_helper_release_fbi(helper); err_gem_free_object: @@ -574,10 +573,8 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); - if (fbdev_cma->fb) { - drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); - drm_fb_cma_destroy(&fbdev_cma->fb->fb); - } + if (fbdev_cma->fb) + drm_framebuffer_remove(&fbdev_cma->fb->fb); drm_fb_helper_fini(&fbdev_cma->fb_helper); kfree(fbdev_cma); -- cgit v1.3.1 From 3e7d2fddba5a3e9243fc461027511a350f88c23b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 27 Dec 2016 11:49:25 +0100 Subject: drm/tegra: Stop using drm_framebuffer_unregister_private This is the deprecated function for when you embedded the framebuffer somewhere else (which breaks refcounting). But Tegra is using drm_framebuffer_remove and a free-standing FB, so this is redundant. One caveat here is that the failure path in the init code still manually cleaned up the fb. I presume that was an oversight and changed it over to drm_framebuffer_remove too. Cc: Thierry Reding Reviewed-by: Archit Taneja Acked-by: Thierry Reding Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1482835765-12044-5-git-send-email-daniel.vetter@ffwll.ch Link: http://patchwork.freedesktop.org/patch/msgid/1482835765-12044-2-git-send-email-daniel.vetter@ffwll.ch --- drivers/gpu/drm/tegra/fb.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 8df7783cecc2..f896e2ff7d47 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -271,8 +271,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, return 0; destroy: - drm_framebuffer_unregister_private(fb); - tegra_fb_destroy(fb); + drm_framebuffer_remove(fb); release: drm_fb_helper_release_fbi(helper); return err; @@ -342,10 +341,8 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) drm_fb_helper_unregister_fbi(&fbdev->base); drm_fb_helper_release_fbi(&fbdev->base); - if (fbdev->fb) { - drm_framebuffer_unregister_private(&fbdev->fb->base); + if (fbdev->fb) drm_framebuffer_remove(&fbdev->fb->base); - } drm_fb_helper_fini(&fbdev->base); tegra_fbdev_free(fbdev); -- cgit v1.3.1 From e9a7c0beb2361a44dbdb852f3cff99e08ddbe029 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 11 Jan 2017 12:22:26 +0530 Subject: dt-bindings: drm/bridge: adv7511: Add regulator bindings Add the regulator supply properties needed by ADV7511 and ADV7533. Acked-by: Laurent Pinchart Acked-by: Rob Herring Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484117547-26417-2-git-send-email-architt@codeaurora.org --- .../devicetree/bindings/display/bridge/adi,adv7511.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index 6532a59c9b43..00ea670b8c4d 100644 --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt @@ -38,10 +38,22 @@ The following input format properties are required except in "rgb 1x" and - adi,input-justification: The input bit justification ("left", "evenly", "right"). +- avdd-supply: A 1.8V supply that powers up the AVDD pin on the chip. +- dvdd-supply: A 1.8V supply that powers up the DVDD pin on the chip. +- pvdd-supply: A 1.8V supply that powers up the PVDD pin on the chip. +- dvdd-3v-supply: A 3.3V supply that powers up the pin called DVDD_3V + on the chip. +- bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is + needed only for ADV7511. + The following properties are required for ADV7533: - adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should be one of 1, 2, 3 or 4. +- a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip. +- v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip. +- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be + either 1.2V or 1.8V. Optional properties: -- cgit v1.3.1 From 5b06ba2378e177fdb8f100adda6e55b205308202 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 11 Jan 2017 12:22:27 +0530 Subject: drm/bridge: adv7511: Initialize regulators Maintain a table of regulator names expected by ADV7511 and ADV7533. Use regulator_bulk_* api to configure these. Initialize and enable the regulators during probe itself. Controlling these dynamically is left for later. Reviewed-by: Laurent Pinchart Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484117547-26417-3-git-send-email-architt@codeaurora.org --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 4 ++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 86 +++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 992d76ce02bb..039147fde7b0 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -329,6 +330,9 @@ struct adv7511 { struct gpio_desc *gpio_pd; + struct regulator_bulk_data *supplies; + unsigned int num_supplies; + /* ADV7533 DSI RX related params */ struct device_node *host_node; struct mipi_dsi_device *dsi; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 8dba729f6ef9..70b426925604 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -839,6 +839,58 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = { * Probe & remove */ +static const char * const adv7511_supply_names[] = { + "avdd", + "dvdd", + "pvdd", + "bgvdd", + "dvdd-3v", +}; + +static const char * const adv7533_supply_names[] = { + "avdd", + "dvdd", + "pvdd", + "a2vdd", + "v3p3", + "v1p2", +}; + +static int adv7511_init_regulators(struct adv7511 *adv) +{ + struct device *dev = &adv->i2c_main->dev; + const char * const *supply_names; + unsigned int i; + int ret; + + if (adv->type == ADV7511) { + supply_names = adv7511_supply_names; + adv->num_supplies = ARRAY_SIZE(adv7511_supply_names); + } else { + supply_names = adv7533_supply_names; + adv->num_supplies = ARRAY_SIZE(adv7533_supply_names); + } + + adv->supplies = devm_kcalloc(dev, adv->num_supplies, + sizeof(*adv->supplies), GFP_KERNEL); + if (!adv->supplies) + return -ENOMEM; + + for (i = 0; i < adv->num_supplies; i++) + adv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, adv->num_supplies, adv->supplies); + if (ret) + return ret; + + return regulator_bulk_enable(adv->num_supplies, adv->supplies); +} + +static void adv7511_uninit_regulators(struct adv7511 *adv) +{ + regulator_bulk_disable(adv->num_supplies, adv->supplies); +} + static int adv7511_parse_dt(struct device_node *np, struct adv7511_link_config *config) { @@ -939,6 +991,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) if (!adv7511) return -ENOMEM; + adv7511->i2c_main = i2c; adv7511->powered = false; adv7511->status = connector_status_disconnected; @@ -956,13 +1009,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) if (ret) return ret; + ret = adv7511_init_regulators(adv7511); + if (ret) { + dev_err(dev, "failed to init regulators\n"); + return ret; + } + /* * The power down GPIO is optional. If present, toggle it from active to * inactive to wake up the encoder. */ adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); - if (IS_ERR(adv7511->gpio_pd)) - return PTR_ERR(adv7511->gpio_pd); + if (IS_ERR(adv7511->gpio_pd)) { + ret = PTR_ERR(adv7511->gpio_pd); + goto uninit_regulators; + } if (adv7511->gpio_pd) { mdelay(5); @@ -970,12 +1031,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) } adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config); - if (IS_ERR(adv7511->regmap)) - return PTR_ERR(adv7511->regmap); + if (IS_ERR(adv7511->regmap)) { + ret = PTR_ERR(adv7511->regmap); + goto uninit_regulators; + } ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val); if (ret) - return ret; + goto uninit_regulators; dev_dbg(dev, "Rev. %d\n", val); if (adv7511->type == ADV7511) @@ -985,7 +1048,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) else ret = adv7533_patch_registers(adv7511); if (ret) - return ret; + goto uninit_regulators; regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr); regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, @@ -995,10 +1058,11 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) adv7511_packet_disable(adv7511, 0xffff); - adv7511->i2c_main = i2c; adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); - if (!adv7511->i2c_edid) - return -ENOMEM; + if (!adv7511->i2c_edid) { + ret = -ENOMEM; + goto uninit_regulators; + } if (adv7511->type == ADV7533) { ret = adv7533_init_cec(adv7511); @@ -1045,6 +1109,8 @@ err_unregister_cec: adv7533_uninit_cec(adv7511); err_i2c_unregister_edid: i2c_unregister_device(adv7511->i2c_edid); +uninit_regulators: + adv7511_uninit_regulators(adv7511); return ret; } @@ -1058,6 +1124,8 @@ static int adv7511_remove(struct i2c_client *i2c) adv7533_uninit_cec(adv7511); } + adv7511_uninit_regulators(adv7511); + drm_bridge_remove(&adv7511->bridge); adv7511_audio_exit(adv7511); -- cgit v1.3.1 From 8e945cba255f41d2413e3208d480588c2420c657 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Thu, 12 Jan 2017 14:16:08 -0200 Subject: drm: qxl: Let DRM core handle connector registering Registering the connector explicitly right after creation is not necessary for modesetting drivers, because drm_dev_register already takes care of this on the core side, by calling drm_modeset_register_all. In addition, performing the initialization too early will get in the way of the load() hook removal, because the connector interface cannot be published prior to registering the minors. Signed-off-by: Gabriel Krisman Bertazi CC: Dave Airlie CC: Daniel Vetter CC: dri-devel@lists.freedesktop.org Signed-off-by: Gustavo Padovan Link: http://patchwork.freedesktop.org/patch/msgid/20170112161610.19924-1-krisman@collabora.co.uk --- drivers/gpu/drm/qxl/qxl_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 659c77742649..416ade8566b7 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -1077,7 +1077,6 @@ static int qdev_output_init(struct drm_device *dev, int num_output) dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.suggested_y_property, 0); - drm_connector_register(connector); return 0; } -- cgit v1.3.1 From cc7e96232763ff33418b088b436a564441347b15 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:51 +0200 Subject: drm: bridge: dw-hdmi: Merge __hdmi_phy_i2c_write and hdmi_phy_i2c_write The latter is just an int wrapper around the former void function that unconditionally returns 0. As the return value is never checked, merge the two functions into one. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-2-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index f5009ae39b89..a6685502571e 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -868,7 +868,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec) return true; } -static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, +static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, unsigned char addr) { hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); @@ -882,13 +882,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, hdmi_phy_wait_i2c_done(hdmi, 1000); } -static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, - unsigned char addr) -{ - __hdmi_phy_i2c_write(hdmi, data, addr); - return 0; -} - static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable) { hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0, -- cgit v1.3.1 From ecaa98f1e6f7ed3f79def1861f21ff2eac82b8e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:52 +0200 Subject: drm: bridge: dw-hdmi: Remove unneeded arguments to bind/unbind functions The master argument isn't used. The data argument, a void pointer, is used by the bind function only where it's cast to a drm_device pointer, which can easily be obtained from the encoder argument instead. Remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-3-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 8 +++----- drivers/gpu/drm/imx/dw_hdmi-imx.c | 4 ++-- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 ++-- include/drm/bridge/dw_hdmi.h | 5 ++--- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index a6685502571e..f86894622070 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1854,12 +1854,10 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) return 0; } -int dw_hdmi_bind(struct device *dev, struct device *master, - void *data, struct drm_encoder *encoder, +int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, struct resource *iores, int irq, const struct dw_hdmi_plat_data *plat_data) { - struct drm_device *drm = data; struct device_node *np = dev->of_node; struct platform_device_info pdevinfo; struct device_node *ddc_node; @@ -1992,7 +1990,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, if (ret) goto err_iahb; - ret = dw_hdmi_register(drm, hdmi); + ret = dw_hdmi_register(encoder->dev, hdmi); if (ret) goto err_iahb; @@ -2059,7 +2057,7 @@ err_res: } EXPORT_SYMBOL_GPL(dw_hdmi_bind); -void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) +void dw_hdmi_unbind(struct device *dev) { struct dw_hdmi *hdmi = dev_get_drvdata(dev); diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 359cd2765552..f79665801543 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -249,7 +249,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data); /* * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), @@ -264,7 +264,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, static void dw_hdmi_imx_unbind(struct device *dev, struct device *master, void *data) { - return dw_hdmi_unbind(dev, master, data); + return dw_hdmi_unbind(dev); } static const struct component_ops dw_hdmi_imx_ops = { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 0665fb915579..e8fb5c56b224 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -301,7 +301,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data); /* * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), @@ -316,7 +316,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, void *data) { - return dw_hdmi_unbind(dev, master, data); + return dw_hdmi_unbind(dev); } static const struct component_ops dw_hdmi_rockchip_ops = { diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index bae79f3c4d28..11edda631a9d 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -56,9 +56,8 @@ struct dw_hdmi_plat_data { struct drm_display_mode *mode); }; -void dw_hdmi_unbind(struct device *dev, struct device *master, void *data); -int dw_hdmi_bind(struct device *dev, struct device *master, - void *data, struct drm_encoder *encoder, +void dw_hdmi_unbind(struct device *dev); +int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, struct resource *iores, int irq, const struct dw_hdmi_plat_data *plat_data); -- cgit v1.3.1 From dfa73065d61b6ce57aed90bb0d745c4b6f5b71e7 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 17 Jan 2017 10:28:53 +0200 Subject: drm: bridge: dw-hdmi: Remove unused function parameter The 'prep' parameter passed to hdmi_phy_configure() is useless. It is hardcoded as 0, and if set, simply prevents the configure function from executing. Remove it. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-4-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index f86894622070..5f8044a7d602 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -931,7 +931,7 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } -static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, +static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char res, int cscon) { unsigned res_idx; @@ -941,9 +941,6 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; - if (prep) - return -EINVAL; - switch (res) { case 0: /* color resolution 0 is 8 bit colour depth */ case 8: @@ -1072,7 +1069,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) dw_hdmi_phy_enable_powerdown(hdmi, true); /* Enable CSC */ - ret = hdmi_phy_configure(hdmi, 0, 8, cscon); + ret = hdmi_phy_configure(hdmi, 8, cscon); if (ret) return ret; } -- cgit v1.3.1 From 70c963ec4f15a13197524611875168f23acc4a97 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:54 +0200 Subject: drm: bridge: dw-hdmi: Embed drm_bridge in struct dw_hdmi The drm_bridge instance is always needed, there's no point in allocating it separately. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-5-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 5f8044a7d602..2c85b6c07a80 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -116,7 +116,7 @@ struct dw_hdmi_i2c { struct dw_hdmi { struct drm_connector connector; struct drm_encoder *encoder; - struct drm_bridge *bridge; + struct drm_bridge bridge; struct platform_device *audio; enum dw_hdmi_devtype dev_type; @@ -1806,7 +1806,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { dev_dbg(hdmi->dev, "EVENT=%s\n", phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); - drm_helper_hpd_irq_event(hdmi->bridge->dev); + drm_helper_hpd_irq_event(hdmi->bridge.dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); @@ -1819,16 +1819,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) { struct drm_encoder *encoder = hdmi->encoder; - struct drm_bridge *bridge; + struct drm_bridge *bridge = &hdmi->bridge; int ret; - bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL); - if (!bridge) { - DRM_ERROR("Failed to allocate drm bridge\n"); - return -ENOMEM; - } - - hdmi->bridge = bridge; bridge->driver_private = hdmi; bridge->funcs = &dw_hdmi_bridge_funcs; ret = drm_bridge_attach(encoder, bridge, NULL); -- cgit v1.3.1 From 527b863f6ad4f4f1707cbc2237df9d83d0c848c1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:55 +0200 Subject: drm: bridge: dw-hdmi: Remove encoder field from struct dw_hdmi The field isn't needed, remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-6-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 2c85b6c07a80..ef10bb866b2f 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -115,7 +115,6 @@ struct dw_hdmi_i2c { struct dw_hdmi { struct drm_connector connector; - struct drm_encoder *encoder; struct drm_bridge bridge; struct platform_device *audio; @@ -1816,9 +1815,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) +static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi) { - struct drm_encoder *encoder = hdmi->encoder; struct drm_bridge *bridge = &hdmi->bridge; int ret; @@ -1835,7 +1833,7 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi) drm_connector_helper_add(&hdmi->connector, &dw_hdmi_connector_helper_funcs); - drm_connector_init(drm, &hdmi->connector, + drm_connector_init(encoder->dev, &hdmi->connector, &dw_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1867,7 +1865,6 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, hdmi->dev = dev; hdmi->dev_type = plat_data->dev_type; hdmi->sample_rate = 48000; - hdmi->encoder = encoder; hdmi->disabled = true; hdmi->rxsense = true; hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); @@ -1980,7 +1977,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, if (ret) goto err_iahb; - ret = dw_hdmi_register(encoder->dev, hdmi); + ret = dw_hdmi_register(encoder, hdmi); if (ret) goto err_iahb; -- cgit v1.3.1 From ba5d7e6160b7aed4df92d1764aa90790db0e7996 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:56 +0200 Subject: drm: bridge: dw-hdmi: Don't forward HPD events to DRM core before attach Hotplug events should only be forwarded to the DRM core by the interrupt handler when the bridge has been attached, otherwise the DRM device pointer will be NULL, resulting in a crash. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-7-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index ef10bb866b2f..488dc1a9204f 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1805,7 +1805,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { dev_dbg(hdmi->dev, "EVENT=%s\n", phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); - drm_helper_hpd_irq_event(hdmi->bridge.dev); + if (hdmi->bridge.dev) + drm_helper_hpd_irq_event(hdmi->bridge.dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); -- cgit v1.3.1 From c608119dfdde9710e4bd068d632beb68bb3517db Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:57 +0200 Subject: drm: bridge: dw-hdmi: Move IRQ and IO resource allocation to common code There's no need to duplicate identical code in multiple drivers (two at the moment, one more to come soon). Move it to the dw-hdmi core where it can be shared. If resource allocation ever becomes device-specific later we'll always have the option of splitting it out again. While it at pass the platform device to the bind function to avoid having to cast struct device to struct platform_device. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-8-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 13 ++++++++++--- drivers/gpu/drm/imx/dw_hdmi-imx.c | 12 +----------- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 +----------- include/drm/bridge/dw_hdmi.h | 3 +-- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 488dc1a9204f..563cbec47da6 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1843,14 +1843,16 @@ static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi) return 0; } -int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, - struct resource *iores, int irq, +int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_plat_data *plat_data) { + struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct platform_device_info pdevinfo; struct device_node *ddc_node; struct dw_hdmi *hdmi; + struct resource *iores; + int irq; int ret; u32 val = 1; u8 config0; @@ -1903,6 +1905,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, dev_dbg(hdmi->dev, "no ddc property found\n"); } + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); hdmi->regs = devm_ioremap_resource(dev, iores); if (IS_ERR(hdmi->regs)) { ret = PTR_ERR(hdmi->regs); @@ -1945,6 +1948,10 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, initialize_hdmi_ih_mutes(hdmi); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + goto err_iahb; + ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, dw_hdmi_irq, IRQF_SHARED, dev_name(dev), hdmi); @@ -2025,7 +2032,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, if (hdmi->i2c) dw_hdmi_i2c_init(hdmi); - dev_set_drvdata(dev, hdmi); + platform_set_drvdata(pdev, hdmi); return 0; diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index f79665801543..f645275e6e63 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -207,8 +207,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, struct drm_device *drm = data; struct drm_encoder *encoder; struct imx_hdmi *hdmi; - struct resource *iores; - int irq; int ret; if (!pdev->dev.of_node) @@ -223,14 +221,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -ENXIO; - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is @@ -249,7 +239,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(pdev, encoder, plat_data); /* * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index e8fb5c56b224..a6d4a0236e8f 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -257,8 +257,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, struct drm_device *drm = data; struct drm_encoder *encoder; struct rockchip_hdmi *hdmi; - struct resource *iores; - int irq; int ret; if (!pdev->dev.of_node) @@ -273,14 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -ENXIO; - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is @@ -301,7 +291,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data); + ret = dw_hdmi_bind(pdev, encoder, plat_data); /* * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 11edda631a9d..94ff6edd070b 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -57,8 +57,7 @@ struct dw_hdmi_plat_data { }; void dw_hdmi_unbind(struct device *dev); -int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder, - struct resource *iores, int irq, +int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_plat_data *plat_data); void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); -- cgit v1.3.1 From fd30b38c27c305fcb522bfa7911de241ee1799b5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:58 +0200 Subject: drm: bridge: dw-hdmi: Reorder functions to prepare for next commit The next commit will reference structures and functions in a way that currently requires forward declarations. Reorder the functions to avoid that. No functional change to the code is performed. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-9-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 72 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 563cbec47da6..92ce9e532603 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1575,42 +1575,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); } -static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *orig_mode, - struct drm_display_mode *mode) -{ - struct dw_hdmi *hdmi = bridge->driver_private; - - mutex_lock(&hdmi->mutex); - - /* Store the display mode for plugin/DKMS poweron events */ - memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); - - mutex_unlock(&hdmi->mutex); -} - -static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) -{ - struct dw_hdmi *hdmi = bridge->driver_private; - - mutex_lock(&hdmi->mutex); - hdmi->disabled = true; - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); -} - -static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) -{ - struct dw_hdmi *hdmi = bridge->driver_private; - - mutex_lock(&hdmi->mutex); - hdmi->disabled = false; - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); -} - static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector *connector, bool force) { @@ -1703,6 +1667,42 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = .best_encoder = drm_atomic_helper_best_encoder, }; +static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *orig_mode, + struct drm_display_mode *mode) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + + mutex_lock(&hdmi->mutex); + + /* Store the display mode for plugin/DKMS poweron events */ + memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); + + mutex_unlock(&hdmi->mutex); +} + +static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + + mutex_lock(&hdmi->mutex); + hdmi->disabled = true; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); +} + +static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + + mutex_lock(&hdmi->mutex); + hdmi->disabled = false; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); +} + static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { .enable = dw_hdmi_bridge_enable, .disable = dw_hdmi_bridge_disable, -- cgit v1.3.1 From d2ae94ae840bd0b347e417e88b1637df95d499ac Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:28:59 +0200 Subject: drm: bridge: dw-hdmi: Create connector in the bridge attach operation The DRM device is not guaranteed by the bridge API to be available before the attach callback. The driver performs properly at the moment as it doesn't use the drm_bridge_add() registration method. As this will be changed later, move connector creation to attach time to ensure compatibility with the API. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-10-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 92ce9e532603..88cd40adb977 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1667,6 +1667,25 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = .best_encoder = drm_atomic_helper_best_encoder, }; +static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) +{ + struct dw_hdmi *hdmi = bridge->driver_private; + struct drm_encoder *encoder = bridge->encoder; + struct drm_connector *connector = &hdmi->connector; + + connector->interlace_allowed = 1; + connector->polled = DRM_CONNECTOR_POLL_HPD; + + drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); + + drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *orig_mode, struct drm_display_mode *mode) @@ -1704,6 +1723,7 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .attach = dw_hdmi_bridge_attach, .enable = dw_hdmi_bridge_enable, .disable = dw_hdmi_bridge_disable, .mode_set = dw_hdmi_bridge_mode_set, @@ -1829,17 +1849,6 @@ static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi) return -EINVAL; } - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; - - drm_connector_helper_add(&hdmi->connector, - &dw_hdmi_connector_helper_funcs); - - drm_connector_init(encoder->dev, &hdmi->connector, - &dw_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); - - drm_mode_connector_attach_encoder(&hdmi->connector, encoder); - return 0; } @@ -1862,8 +1871,6 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, if (!hdmi) return -ENOMEM; - hdmi->connector.interlace_allowed = 1; - hdmi->plat_data = plat_data; hdmi->dev = dev; hdmi->dev_type = plat_data->dev_type; -- cgit v1.3.1 From 69497eb9234eb34994b9a0d2f2c17c4c09f2e969 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:00 +0200 Subject: drm: bridge: dw-hdmi: Implement DRM bridge registration As an option for drivers not based on the component framework, register the bridge with the DRM core with the DRM bridge API. Existing drivers based on dw_hdmi_bind() and dw_hdmi_unbind() are not affected as those functions are preserved with their current behaviour. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-11-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 112 ++++++++++++++++++++++++++++----------- include/drm/bridge/dw_hdmi.h | 3 ++ 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 88cd40adb977..107fea49c4c6 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1836,24 +1836,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi) -{ - struct drm_bridge *bridge = &hdmi->bridge; - int ret; - - bridge->driver_private = hdmi; - bridge->funcs = &dw_hdmi_bridge_funcs; - ret = drm_bridge_attach(encoder, bridge, NULL); - if (ret) { - DRM_ERROR("Failed to initialize bridge with drm\n"); - return -EINVAL; - } - - return 0; -} - -int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, - const struct dw_hdmi_plat_data *plat_data) +static struct dw_hdmi * +__dw_hdmi_probe(struct platform_device *pdev, + const struct dw_hdmi_plat_data *plat_data) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -1869,7 +1854,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) - return -ENOMEM; + return ERR_PTR(-ENOMEM); hdmi->plat_data = plat_data; hdmi->dev = dev; @@ -1896,7 +1881,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, break; default: dev_err(dev, "reg-io-width must be 1 or 4\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); @@ -1905,7 +1890,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, of_node_put(ddc_node); if (!hdmi->ddc) { dev_dbg(hdmi->dev, "failed to read ddc node\n"); - return -EPROBE_DEFER; + return ERR_PTR(-EPROBE_DEFER); } } else { @@ -1956,8 +1941,10 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, initialize_hdmi_ih_mutes(hdmi); irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + ret = irq; goto err_iahb; + } ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, dw_hdmi_irq, IRQF_SHARED, @@ -1988,11 +1975,11 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, HDMI_IH_PHY_STAT0); - ret = dw_hdmi_fb_registered(hdmi); - if (ret) - goto err_iahb; + hdmi->bridge.driver_private = hdmi; + hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; + hdmi->bridge.of_node = pdev->dev.of_node; - ret = dw_hdmi_register(encoder, hdmi); + ret = dw_hdmi_fb_registered(hdmi); if (ret) goto err_iahb; @@ -2041,7 +2028,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, platform_set_drvdata(pdev, hdmi); - return 0; + return hdmi; err_iahb: if (hdmi->i2c) { @@ -2055,14 +2042,11 @@ err_isfr: err_res: i2c_put_adapter(hdmi->ddc); - return ret; + return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(dw_hdmi_bind); -void dw_hdmi_unbind(struct device *dev) +static void __dw_hdmi_remove(struct dw_hdmi *hdmi) { - struct dw_hdmi *hdmi = dev_get_drvdata(dev); - if (hdmi->audio && !IS_ERR(hdmi->audio)) platform_device_unregister(hdmi->audio); @@ -2077,6 +2061,70 @@ void dw_hdmi_unbind(struct device *dev) else i2c_put_adapter(hdmi->ddc); } + +/* ----------------------------------------------------------------------------- + * Probe/remove API, used from platforms based on the DRM bridge API. + */ +int dw_hdmi_probe(struct platform_device *pdev, + const struct dw_hdmi_plat_data *plat_data) +{ + struct dw_hdmi *hdmi; + int ret; + + hdmi = __dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi)) + return PTR_ERR(hdmi); + + ret = drm_bridge_add(&hdmi->bridge); + if (ret < 0) { + __dw_hdmi_remove(hdmi); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(dw_hdmi_probe); + +void dw_hdmi_remove(struct platform_device *pdev) +{ + struct dw_hdmi *hdmi = platform_get_drvdata(pdev); + + drm_bridge_remove(&hdmi->bridge); + + __dw_hdmi_remove(hdmi); +} +EXPORT_SYMBOL_GPL(dw_hdmi_remove); + +/* ----------------------------------------------------------------------------- + * Bind/unbind API, used from platforms based on the component framework. + */ +int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, + const struct dw_hdmi_plat_data *plat_data) +{ + struct dw_hdmi *hdmi; + int ret; + + hdmi = __dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi)) + return PTR_ERR(hdmi); + + ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL); + if (ret) { + dw_hdmi_remove(pdev); + DRM_ERROR("Failed to initialize bridge with drm\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(dw_hdmi_bind); + +void dw_hdmi_unbind(struct device *dev) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + __dw_hdmi_remove(hdmi); +} EXPORT_SYMBOL_GPL(dw_hdmi_unbind); MODULE_AUTHOR("Sascha Hauer "); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 94ff6edd070b..3bb22a849830 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -56,6 +56,9 @@ struct dw_hdmi_plat_data { struct drm_display_mode *mode); }; +int dw_hdmi_probe(struct platform_device *pdev, + const struct dw_hdmi_plat_data *plat_data); +void dw_hdmi_remove(struct platform_device *pdev); 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); -- cgit v1.3.1 From 1acc6bdeee1ef2ecac3ba070a403827ab8f16be5 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 17 Jan 2017 10:29:01 +0200 Subject: drm: bridge: dw-hdmi: Remove PHY configuration resolution parameter The current code hard codes the call of hdmi_phy_configure() to be 8bpp and provides extraneous error checking to verify that this hardcoded value is correct. Simplify the implementation by removing the argument. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-12-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 107fea49c4c6..b4fb0bd78910 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -930,31 +930,14 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } -static int hdmi_phy_configure(struct dw_hdmi *hdmi, - unsigned char res, int cscon) +static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) { - unsigned res_idx; u8 val, msec; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; - switch (res) { - case 0: /* color resolution 0 is 8 bit colour depth */ - case 8: - res_idx = DW_HDMI_RES_8; - break; - case 10: - res_idx = DW_HDMI_RES_10; - break; - case 12: - res_idx = DW_HDMI_RES_12; - break; - default: - return -EINVAL; - } - /* PLL/MPLL Cfg - always match on final entry */ for (; mpll_config->mpixelclock != ~0UL; mpll_config++) if (hdmi->hdmi_data.video_mode.mpixelclock <= @@ -1004,11 +987,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); - hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06); - hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15); + hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, 0x15); /* CURRCTRL */ - hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10); + hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], 0x10); hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); @@ -1068,7 +1051,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) dw_hdmi_phy_enable_powerdown(hdmi, true); /* Enable CSC */ - ret = hdmi_phy_configure(hdmi, 8, cscon); + ret = hdmi_phy_configure(hdmi, cscon); if (ret) return ret; } -- cgit v1.3.1 From f4104e8fe12c173fbba5e7e30b846e09eeb5bfbd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:02 +0200 Subject: drm: bridge: dw-hdmi: Rename CONF0 SPARECTRL bit to SVSRET The bit is documented in a Rockchip BSP as #define m_SVSRET_SIG (1 << 5) /* depend on PHY_MHL_COMB0=1 */ This is confirmed by a Renesas platform, which uses a 2.0 DWC HDMI TX as the RK3288. Rename the bit accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-13-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 8 ++++---- drivers/gpu/drm/bridge/dw-hdmi.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index b4fb0bd78910..06c252f560ad 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -895,11 +895,11 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_ENTMDS_MASK); } -static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable) +static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable) { hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, - HDMI_PHY_CONF0_SPARECTRL_OFFSET, - HDMI_PHY_CONF0_SPARECTRL_MASK); + HDMI_PHY_CONF0_SVSRET_OFFSET, + HDMI_PHY_CONF0_SVSRET_MASK); } static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable) @@ -1014,7 +1014,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) dw_hdmi_phy_gen2_pddq(hdmi, 0); if (hdmi->dev_type == RK3288_HDMI) - dw_hdmi_phy_enable_spare(hdmi, 1); + dw_hdmi_phy_enable_svsret(hdmi, 1); /*Wait for PHY PLL lock */ msec = 5; diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 55135bbd0c16..08235aef2fa3 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -847,8 +847,8 @@ enum { HDMI_PHY_CONF0_PDZ_OFFSET = 7, HDMI_PHY_CONF0_ENTMDS_MASK = 0x40, HDMI_PHY_CONF0_ENTMDS_OFFSET = 6, - HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20, - HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5, + HDMI_PHY_CONF0_SVSRET_MASK = 0x20, + HDMI_PHY_CONF0_SVSRET_OFFSET = 5, HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10, HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4, HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8, -- cgit v1.3.1 From 0527e12e8264ae96b1fcc550b4a9e5940f4ffc30 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:03 +0200 Subject: drm: bridge: dw-hdmi: Reject invalid product IDs The DWC HDMI TX can be recognized by the two product identification registers. If the registers don't read as expect the IP will be very different than what the driver has been designed for, or will be misconfigured in a way that makes it non-operational (invalid memory address, incorrect clocks, ...). We should reject this situation with an error. While this isn't critical for proper operation with supported IPs at the moment, the driver will soon gain automatic device-specific handling based on runtime device identification. This change makes it easier to implement that without having to default to a random guess in case the device can't be identified. While at it print a readable version number in the device identification message instead of raw register values. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-14-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 25 +++++++++++++++++++------ drivers/gpu/drm/bridge/dw-hdmi.h | 8 ++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 06c252f560ad..1809247745b8 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1832,6 +1832,9 @@ __dw_hdmi_probe(struct platform_device *pdev, int irq; int ret; u32 val = 1; + u16 version; + u8 prod_id0; + u8 prod_id1; u8 config0; u8 config1; @@ -1914,12 +1917,22 @@ __dw_hdmi_probe(struct platform_device *pdev, } /* Product and revision IDs */ - dev_info(dev, - "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", - hdmi_readb(hdmi, HDMI_DESIGN_ID), - hdmi_readb(hdmi, HDMI_REVISION_ID), - hdmi_readb(hdmi, HDMI_PRODUCT_ID0), - hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); + version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8) + | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0); + prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0); + prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1); + + if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX || + (prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) { + dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n", + version, prod_id0, prod_id1); + ret = -ENODEV; + goto err_iahb; + } + + dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n", + version >> 12, version & 0xfff, + prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without"); initialize_hdmi_ih_mutes(hdmi); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 08235aef2fa3..91d7fabbd6e5 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -545,6 +545,14 @@ #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 enum { +/* PRODUCT_ID0 field values */ + HDMI_PRODUCT_ID0_HDMI_TX = 0xa0, + +/* PRODUCT_ID1 field values */ + HDMI_PRODUCT_ID1_HDCP = 0xc0, + HDMI_PRODUCT_ID1_HDMI_RX = 0x02, + HDMI_PRODUCT_ID1_HDMI_TX = 0x01, + /* CONFIG0_ID field values */ HDMI_CONFIG0_I2S = 0x10, -- cgit v1.3.1 From 0c674948b7f4e4ffc19ba5af65a274e945c0c689 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:04 +0200 Subject: drm: bridge: dw-hdmi: Detect AHB audio DMA using correct register Bit 0 in CONFIG1_ID tells whether the IP core uses an AHB slave interface for control. The correct way to identify AHB audio DMA support is through bit 1 in CONFIG3_ID. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-15-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 6 +++--- drivers/gpu/drm/bridge/dw-hdmi.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 1809247745b8..730a7558d4d4 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1836,7 +1836,7 @@ __dw_hdmi_probe(struct platform_device *pdev, u8 prod_id0; u8 prod_id1; u8 config0; - u8 config1; + u8 config3; hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) @@ -1988,9 +1988,9 @@ __dw_hdmi_probe(struct platform_device *pdev, pdevinfo.id = PLATFORM_DEVID_AUTO; config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); - config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID); + config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); - if (config1 & HDMI_CONFIG1_AHB) { + if (config3 & HDMI_CONFIG3_AHBAUDDMA) { struct dw_hdmi_audio_data audio; audio.phys = iores->start; diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 91d7fabbd6e5..a4fd64a203c9 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -559,6 +559,10 @@ enum { /* CONFIG1_ID field values */ HDMI_CONFIG1_AHB = 0x01, +/* CONFIG3_ID field values */ + HDMI_CONFIG3_AHBAUDDMA = 0x02, + HDMI_CONFIG3_GPAUD = 0x01, + /* IH_FC_INT2 field values */ HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03, HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, -- cgit v1.3.1 From be41fc55f1aa3c9ae0eb9e0b384db5150eca055f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:05 +0200 Subject: drm: bridge: dw-hdmi: Handle overflow workaround based on device version Use the device version queried at runtime instead of the device type provided through platform data to handle the overflow workaround. This will make support of other SoCs integrating the same HDMI TX controller version easier. Among the supported platforms only i.MX6DL and i.MX6Q have been identified as needing the workaround. Disabling it on Rockchip RK3288 (which integrates a v2.00a controller) didn't produce any error or artifact. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-16-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 46 ++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 730a7558d4d4..f4faa14213e5 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -117,8 +117,10 @@ struct dw_hdmi { struct drm_connector connector; struct drm_bridge bridge; - struct platform_device *audio; enum dw_hdmi_devtype dev_type; + unsigned int version; + + struct platform_device *audio; struct device *dev; struct clk *isfr_clk; struct clk *iahb_clk; @@ -1323,19 +1325,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) /* Workaround to clear the overflow condition */ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) { - int count; + unsigned int count; + unsigned int i; u8 val; - /* TMDS software reset */ - hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ); + /* + * Under some circumstances the Frame Composer arithmetic unit can miss + * an FC register write due to being busy processing the previous one. + * The issue can be worked around by issuing a TMDS software reset and + * then write one of the FC registers several times. + * + * The number of iterations matters and depends on the HDMI TX revision + * (and possibly on the platform). So far only i.MX6Q (v1.30a) and + * i.MX6DL (v1.31a) have been identified as needing the workaround, with + * 4 and 1 iterations respectively. + */ - val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF); - if (hdmi->dev_type == IMX6DL_HDMI) { - hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); + switch (hdmi->version) { + case 0x130a: + count = 4; + break; + case 0x131a: + count = 1; + break; + default: return; } - for (count = 0; count < 4; count++) + /* TMDS software reset */ + hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ); + + val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF); + for (i = 0; i < count; i++) hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); } @@ -1832,7 +1853,6 @@ __dw_hdmi_probe(struct platform_device *pdev, int irq; int ret; u32 val = 1; - u16 version; u8 prod_id0; u8 prod_id1; u8 config0; @@ -1917,21 +1937,21 @@ __dw_hdmi_probe(struct platform_device *pdev, } /* Product and revision IDs */ - version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8) - | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0); + hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8) + | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0); prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0); prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1); if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX || (prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) { dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n", - version, prod_id0, prod_id1); + hdmi->version, prod_id0, prod_id1); ret = -ENODEV; goto err_iahb; } dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n", - version >> 12, version & 0xfff, + hdmi->version >> 12, hdmi->version & 0xfff, prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without"); initialize_hdmi_ih_mutes(hdmi); -- cgit v1.3.1 From faba6c3cff177689aec132291b1cf537831d9a2e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:06 +0200 Subject: drm: bridge: dw-hdmi: Detect PHY type at runtime Detect the PHY type and use it to handle the PHY type-specific SVSRET signal. Signed-off-by: Laurent Pinchart Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-17-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 68 ++++++++++++++++++++++++++++++++++++++-- include/drm/bridge/dw_hdmi.h | 10 ++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index f4faa14213e5..ef4f2f96ed2c 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -113,6 +113,12 @@ struct dw_hdmi_i2c { bool is_regaddr; }; +struct dw_hdmi_phy_data { + enum dw_hdmi_phy_type type; + const char *name; + bool has_svsret; +}; + struct dw_hdmi { struct drm_connector connector; struct drm_bridge bridge; @@ -134,7 +140,9 @@ struct dw_hdmi { u8 edid[HDMI_EDID_LEN]; bool cable_plugin; + const struct dw_hdmi_phy_data *phy; bool phy_enabled; + struct drm_display_mode previous_mode; struct i2c_adapter *ddc; @@ -1015,7 +1023,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) dw_hdmi_phy_gen2_txpwron(hdmi, 1); dw_hdmi_phy_gen2_pddq(hdmi, 0); - if (hdmi->dev_type == RK3288_HDMI) + /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */ + if (hdmi->phy->has_svsret) dw_hdmi_phy_enable_svsret(hdmi, 1); /*Wait for PHY PLL lock */ @@ -1840,6 +1849,54 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static const struct dw_hdmi_phy_data dw_hdmi_phys[] = { + { + .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, + .name = "DWC HDMI TX PHY", + }, { + .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, + .name = "DWC MHL PHY + HEAC PHY", + .has_svsret = true, + }, { + .type = DW_HDMI_PHY_DWC_MHL_PHY, + .name = "DWC MHL PHY", + .has_svsret = true, + }, { + .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, + .name = "DWC HDMI 3D TX PHY + HEAC PHY", + }, { + .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, + .name = "DWC HDMI 3D TX PHY", + }, { + .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, + .name = "DWC HDMI 2.0 TX PHY", + .has_svsret = true, + } +}; + +static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) +{ + unsigned int i; + u8 phy_type; + + phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); + + for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) { + if (dw_hdmi_phys[i].type == phy_type) { + hdmi->phy = &dw_hdmi_phys[i]; + return 0; + } + } + + if (phy_type == DW_HDMI_PHY_VENDOR_PHY) + dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n"); + else + dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", + phy_type); + + return -ENODEV; +} + static struct dw_hdmi * __dw_hdmi_probe(struct platform_device *pdev, const struct dw_hdmi_plat_data *plat_data) @@ -1950,9 +2007,14 @@ __dw_hdmi_probe(struct platform_device *pdev, goto err_iahb; } - dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n", + ret = dw_hdmi_detect_phy(hdmi); + if (ret < 0) + goto err_iahb; + + dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n", hdmi->version >> 12, hdmi->version & 0xfff, - prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without"); + prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without", + hdmi->phy->name); initialize_hdmi_ih_mutes(hdmi); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 3bb22a849830..b080a171a23f 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -27,6 +27,16 @@ enum dw_hdmi_devtype { RK3288_HDMI, }; +enum dw_hdmi_phy_type { + DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00, + DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2, + DW_HDMI_PHY_DWC_MHL_PHY = 0xc2, + DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2, + DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2, + DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3, + DW_HDMI_PHY_VENDOR_PHY = 0xfe, +}; + struct dw_hdmi_mpll_config { unsigned long mpixelclock; struct { -- cgit v1.3.1 From f0e7f2f3b6333a02dd7cb89822e6330631c9a3e3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:07 +0200 Subject: drm: bridge: dw-hdmi: Define and use macros for PHY register addresses Replace the hardcoded register address numerical values with macros to clarify the code. This change has been tested by comparing the assembly code before and after the change. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-18-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 35 ++++++++++++--------- drivers/gpu/drm/bridge/dw-hdmi.h | 66 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index ef4f2f96ed2c..6e605fd910ef 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -997,21 +997,26 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); - hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, 0x06); - hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, 0x15); - - /* CURRCTRL */ - hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], 0x10); - - hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ - hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); - - hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19); /* TXTERM */ - hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */ - hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */ - - /* REMOVE CLK TERM */ - hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ + hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, + HDMI_3D_TX_PHY_CPCE_CTRL); + hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, + HDMI_3D_TX_PHY_GMPCTRL); + hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], + HDMI_3D_TX_PHY_CURRCTRL); + + hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); + hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK, + HDMI_3D_TX_PHY_MSM_CTRL); + + hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM); + hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, + HDMI_3D_TX_PHY_CKSYMTXCTRL); + hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, + HDMI_3D_TX_PHY_VLEVCTRL); + + /* Override and disable clock termination. */ + hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE, + HDMI_3D_TX_PHY_CKCALCTRL); dw_hdmi_phy_enable_powerdown(hdmi, false); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index a4fd64a203c9..f3c149c88d71 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -1085,4 +1085,70 @@ enum { HDMI_I2CM_CTLINT_ARB_MASK = 0x4, }; +/* + * HDMI 3D TX PHY registers + */ +#define HDMI_3D_TX_PHY_PWRCTRL 0x00 +#define HDMI_3D_TX_PHY_SERDIVCTRL 0x01 +#define HDMI_3D_TX_PHY_SERCKCTRL 0x02 +#define HDMI_3D_TX_PHY_SERCKKILLCTRL 0x03 +#define HDMI_3D_TX_PHY_TXRESCTRL 0x04 +#define HDMI_3D_TX_PHY_CKCALCTRL 0x05 +#define HDMI_3D_TX_PHY_CPCE_CTRL 0x06 +#define HDMI_3D_TX_PHY_TXCLKMEASCTRL 0x07 +#define HDMI_3D_TX_PHY_TXMEASCTRL 0x08 +#define HDMI_3D_TX_PHY_CKSYMTXCTRL 0x09 +#define HDMI_3D_TX_PHY_CMPSEQCTRL 0x0a +#define HDMI_3D_TX_PHY_CMPPWRCTRL 0x0b +#define HDMI_3D_TX_PHY_CMPMODECTRL 0x0c +#define HDMI_3D_TX_PHY_MEASCTRL 0x0d +#define HDMI_3D_TX_PHY_VLEVCTRL 0x0e +#define HDMI_3D_TX_PHY_D2ACTRL 0x0f +#define HDMI_3D_TX_PHY_CURRCTRL 0x10 +#define HDMI_3D_TX_PHY_DRVANACTRL 0x11 +#define HDMI_3D_TX_PHY_PLLMEASCTRL 0x12 +#define HDMI_3D_TX_PHY_PLLPHBYCTRL 0x13 +#define HDMI_3D_TX_PHY_GRP_CTRL 0x14 +#define HDMI_3D_TX_PHY_GMPCTRL 0x15 +#define HDMI_3D_TX_PHY_MPLLMEASCTRL 0x16 +#define HDMI_3D_TX_PHY_MSM_CTRL 0x17 +#define HDMI_3D_TX_PHY_SCRPB_STATUS 0x18 +#define HDMI_3D_TX_PHY_TXTERM 0x19 +#define HDMI_3D_TX_PHY_PTRPT_ENBL 0x1a +#define HDMI_3D_TX_PHY_PATTERNGEN 0x1b +#define HDMI_3D_TX_PHY_SDCAP_MODE 0x1c +#define HDMI_3D_TX_PHY_SCOPEMODE 0x1d +#define HDMI_3D_TX_PHY_DIGTXMODE 0x1e +#define HDMI_3D_TX_PHY_STR_STATUS 0x1f +#define HDMI_3D_TX_PHY_SCOPECNT0 0x20 +#define HDMI_3D_TX_PHY_SCOPECNT1 0x21 +#define HDMI_3D_TX_PHY_SCOPECNT2 0x22 +#define HDMI_3D_TX_PHY_SCOPECNTCLK 0x23 +#define HDMI_3D_TX_PHY_SCOPESAMPLE 0x24 +#define HDMI_3D_TX_PHY_SCOPECNTMSB01 0x25 +#define HDMI_3D_TX_PHY_SCOPECNTMSB2CK 0x26 + +/* HDMI_3D_TX_PHY_CKCALCTRL values */ +#define HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE BIT(15) + +/* HDMI_3D_TX_PHY_MSM_CTRL values */ +#define HDMI_3D_TX_PHY_MSM_CTRL_MPLL_PH_SEL_CK BIT(13) +#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_CLK_REF_MPLL (0 << 1) +#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_OFF (1 << 1) +#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_PCLK (2 << 1) +#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK (3 << 1) +#define HDMI_3D_TX_PHY_MSM_CTRL_SCOPE_CK_SEL BIT(0) + +/* HDMI_3D_TX_PHY_PTRPT_ENBL values */ +#define HDMI_3D_TX_PHY_PTRPT_ENBL_OVERRIDE BIT(15) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT2 BIT(8) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT1 BIT(7) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT0 BIT(6) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_CK_REF_ENB BIT(5) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_RCAL_ENB BIT(4) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_CLK_ALIGN_ENB BIT(3) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_READY BIT(2) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_CKO_WORD_ENB BIT(1) +#define HDMI_3D_TX_PHY_PTRPT_ENBL_REFCLK_ENB BIT(0) + #endif /* __DW_HDMI_H__ */ -- cgit v1.3.1 From 54d72737b098f3597c57693e1aa96699a21b11fe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:08 +0200 Subject: drm: bridge: dw-hdmi: Fix the name of the PHY reset macros The PHY reset signal is controlled by bit PHYRSTZ in the MC_PHYRSTZ register. The signal is active low on Gen1 PHYs and active high on Gen2 PHYs. The driver toggles the signal high then low, which is correct for all currently supported platforms, but the register values macros are incorrectly named. Replace them with a single macro named after the bit, and add a comment to the source code to explain the behaviour. The driver's behaviour isn't changed by this rename, the code will still need to be fixed to support Gen1 PHYs. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-19-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 6 +++--- drivers/gpu/drm/bridge/dw-hdmi.h | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 6e605fd910ef..93e8816f1f78 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -986,9 +986,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) /* gen2 pddq */ dw_hdmi_phy_gen2_pddq(hdmi, 1); - /* PHY reset */ - hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); - hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ); + /* PHY reset. The reset signal is active high on Gen2 PHYs. */ + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ); + hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ); hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index f3c149c88d71..325b0b8ae639 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -989,8 +989,7 @@ enum { HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0, /* MC_PHYRSTZ field values */ - HDMI_MC_PHYRSTZ_ASSERT = 0x0, - HDMI_MC_PHYRSTZ_DEASSERT = 0x1, + HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01, /* MC_HEACPHY_RST field values */ HDMI_MC_HEACPHY_RST_ASSERT = 0x1, -- cgit v1.3.1 From 2668db37888ff63282147b00dcf54fa491831df3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:09 +0200 Subject: drm: bridge: dw-hdmi: Assert SVSRET before resetting the PHY According to the PHY IP core vendor, the SVSRET signal must be asserted before resetting the PHY. Tests on RK3288 and R-Car Gen3 showed no regression, the change should thus be safe. Signed-off-by: Laurent Pinchart Reviewed-by: Jose Abreu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-20-laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/bridge/dw-hdmi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 93e8816f1f78..4fda0717e789 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -986,6 +986,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) /* gen2 pddq */ dw_hdmi_phy_gen2_pddq(hdmi, 1); + /* Leave low power consumption mode by asserting SVSRET. */ + if (hdmi->phy->has_svsret) + dw_hdmi_phy_enable_svsret(hdmi, 1); + /* PHY reset. The reset signal is active high on Gen2 PHYs. */ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ); hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ); @@ -1028,11 +1032,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) dw_hdmi_phy_gen2_txpwron(hdmi, 1); dw_hdmi_phy_gen2_pddq(hdmi, 0); - /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */ - if (hdmi->phy->has_svsret) - dw_hdmi_phy_enable_svsret(hdmi, 1); - - /*Wait for PHY PLL lock */ + /* Wait for PHY PLL lock */ msec = 5; do { val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; -- cgit v1.3.1 From 01f8c951c25f9a87f2e9dbc09ceca274e80fff4e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 17 Jan 2017 10:29:10 +0200 Subject: dt-bindings: display: dw-hdmi: Clean up DT bindings documentation Make it clear that the core bridge/dw_hdmi.txt document isn't a device tree binding by itself but is meant to be referenced by platform device tree bindings, and update the Rockchip and Freescale DWC HDMI TX bindings to reference it. Signed-off-by: Laurent Pinchart Acked-by: Rob Herring Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-21-laurent.pinchart+renesas@ideasonboard.com --- .../devicetree/bindings/display/bridge/dw_hdmi.txt | 85 +++++++++------------- .../devicetree/bindings/display/imx/hdmi.txt | 51 +++++++------ .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 43 +++++++---- 3 files changed, 91 insertions(+), 88 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt index 5e9a84d6e5f1..33bf981fbe33 100644 --- a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt +++ b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt @@ -1,52 +1,33 @@ -DesignWare HDMI bridge bindings - -Required properties: -- compatible: platform specific such as: - * "snps,dw-hdmi-tx" - * "fsl,imx6q-hdmi" - * "fsl,imx6dl-hdmi" - * "rockchip,rk3288-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, - as described in Documentation/devicetree/bindings/clock/clock-bindings.txt, - the clocks are soc specific, the clock-names should be "iahb", "isfr" --port@[X]: SoC specific port nodes with endpoint definitions as defined - in Documentation/devicetree/bindings/media/video-interfaces.txt, - please refer to the SoC specific binding document: - * Documentation/devicetree/bindings/display/imx/hdmi.txt - * Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt - -Optional properties -- reg-io-width: the width of the reg:1,4, default set to 1 if not present -- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing, - if the property is omitted, a functionally reduced I2C bus - controller on DW HDMI is probed -- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" - -Example: - hdmi: hdmi@0120000 { - compatible = "fsl,imx6q-hdmi"; - reg = <0x00120000 0x9000>; - interrupts = <0 115 0x04>; - gpr = <&gpr>; - clocks = <&clks 123>, <&clks 124>; - clock-names = "iahb", "isfr"; - ddc-i2c-bus = <&i2c2>; - - port@0 { - reg = <0>; - - hdmi_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_hdmi>; - }; - }; - - port@1 { - reg = <1>; - - hdmi_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_hdmi>; - }; - }; - }; +Synopsys DesignWare HDMI TX Encoder +=================================== + +This document defines device tree properties for the Synopsys DesignWare HDMI +TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding +specification by itself but is meant to be referenced by platform-specific +device tree bindings. + +When referenced from platform device tree bindings the properties defined in +this document are defined as follows. The platform device tree bindings are +responsible for defining whether each property is required or optional. + +- reg: Memory mapped base address and length of the DWC HDMI TX registers. + +- reg-io-width: Width of the registers specified by the reg property. The + value is expressed in bytes and must be equal to 1 or 4 if specified. The + register width defaults to 1 if the property is not present. + +- interrupts: Reference to the DWC HDMI TX interrupt. + +- clocks: References to all the clocks specified in the clock-names property + as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt. + +- clock-names: The DWC HDMI TX uses the following clocks. + + - "iahb" is the bus clock for either AHB and APB (mandatory). + - "isfr" is the internal register configuration clock (mandatory). + - "cec" is the HDMI CEC controller main clock (optional). + +- ports: The connectivity of the DWC HDMI TX with the rest of the system is + expressed in using ports as specified in the device graph bindings defined + in Documentation/devicetree/bindings/graph.txt. The numbering of the ports + is platform-specific. diff --git a/Documentation/devicetree/bindings/display/imx/hdmi.txt b/Documentation/devicetree/bindings/display/imx/hdmi.txt index 1b756cf9afb0..66a8f86e5d12 100644 --- a/Documentation/devicetree/bindings/display/imx/hdmi.txt +++ b/Documentation/devicetree/bindings/display/imx/hdmi.txt @@ -1,29 +1,36 @@ -Device-Tree bindings for HDMI Transmitter +Freescale i.MX6 DWC HDMI TX Encoder +=================================== -HDMI Transmitter -================ +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with a companion PHY IP. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. -The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP -with accompanying PHY IP. Required properties: - - #address-cells : should be <1> - - #size-cells : should be <0> - - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi". - - gpr : should be <&gpr>. - The phandle points to the iomuxc-gpr region containing the HDMI - multiplexer control register. - - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described - in Documentation/devicetree/bindings/clock/clock-bindings.txt and - Documentation/devicetree/bindings/clock/imx6q-clock.txt. - - port@[0-4]: Up to four port nodes with endpoint definitions as defined in - Documentation/devicetree/bindings/media/video-interfaces.txt, - corresponding to the four inputs to the HDMI multiplexer. - -Optional properties: - - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - -example: + +- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi". +- reg: See dw_hdmi.txt. +- interrupts: HDMI interrupt number +- clocks: See dw_hdmi.txt. +- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. +- ports: See dw_hdmi.txt. The DWC HDMI shall have between one and four ports, + numbered 0 to 3, corresponding to the four inputs of the HDMI multiplexer. + Each port shall have a single endpoint. +- gpr : Shall contain a phandle to the iomuxc-gpr region containing the HDMI + multiplexer control register. + +Optional properties + +- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master + or the functionally-reduced I2C master contained in the DWC HDMI. When + connected to a system I2C master this property contains a phandle to that + I2C master controller. + + +Example: gpr: iomuxc-gpr@020e0000 { /* ... */ diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 668091f27674..046076c6b277 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -1,24 +1,39 @@ -Rockchip specific extensions to the Synopsys Designware HDMI -================================ +Rockchip DWC HDMI TX Encoder +============================ + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with a companion PHY IP. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + Required properties: -- compatible: "rockchip,rk3288-dw-hdmi"; -- reg: Physical base address and length of the controller's registers. -- clocks: phandle to hdmi iahb and isfr clocks. -- clock-names: should be "iahb" "isfr" -- rockchip,grf: this soc should set GRF regs to mux vopl/vopb. + +- compatible: Shall contain "rockchip,rk3288-dw-hdmi". +- reg: See dw_hdmi.txt. +- reg-io-width: See dw_hdmi.txt. Shall be 4. - interrupts: HDMI interrupt number -- ports: contain a port node with endpoint definitions as defined in - Documentation/devicetree/bindings/media/video-interfaces.txt. For - vopb,set the reg = <0> and set the reg = <1> for vopl. -- reg-io-width: the width of the reg:1,4, the value should be 4 on - rk3288 platform +- clocks: See dw_hdmi.txt. +- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. +- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0 + corresponding to the video input of the controller. The port shall have two + endpoints, numbered 0 and 1, connected respectively to the vopb and vopl. +- rockchip,grf: Shall reference the GRF to mux vopl/vopb. Optional properties -- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing -- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" + +- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master + or the functionally-reduced I2C master contained in the DWC HDMI. When + connected to a system I2C master this property contains a phandle to that + I2C master controller. +- clock-names: See dw_hdmi.txt. The "cec" clock is optional. +- clock-names: May contain "cec" as defined in dw_hdmi.txt. + Example: + hdmi: hdmi@ff980000 { compatible = "rockchip,rk3288-dw-hdmi"; reg = <0xff980000 0x20000>; -- cgit v1.3.1 From a3c764e9884aad26176f149a7490daac978dd209 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:40 +0800 Subject: drm: exynos: use crtc helper drm_crtc_from_index() Use drm_crtc_from_index() to find drm_crtc for given index, so that we do not need to maintain a pointer array in struct exynos_drm_private. Signed-off-by: Shawn Guo Cc: Inki Dae Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-2-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ------ drivers/gpu/drm/exynos/exynos_drm_drv.h | 10 ++-------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 2530bf57716a..309c8ee52524 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -109,9 +109,6 @@ static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct exynos_drm_private *private = crtc->dev->dev_private; - - private->crtc[exynos_crtc->pipe] = NULL; drm_crtc_cleanup(crtc); kfree(exynos_crtc); @@ -134,7 +131,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, void *ctx) { struct exynos_drm_crtc *exynos_crtc; - struct exynos_drm_private *private = drm_dev->dev_private; struct drm_crtc *crtc; int ret; @@ -149,8 +145,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, crtc = &exynos_crtc->base; - private->crtc[pipe] = crtc; - ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, &exynos_crtc_funcs, NULL); if (ret < 0) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 80c4d5b81689..cf6e08cb35a7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -211,12 +211,6 @@ struct drm_exynos_file_private { struct exynos_drm_private { struct drm_fb_helper *fb_helper; - /* - * created crtc object would be contained at this array and - * this array is used to be aware of which crtc did it request vblank. - */ - struct drm_crtc *crtc[MAX_CRTC]; - struct device *dma_dev; void *mapping; @@ -231,9 +225,9 @@ struct exynos_drm_private { static inline struct exynos_drm_crtc * exynos_drm_crtc_from_pipe(struct drm_device *dev, int pipe) { - struct exynos_drm_private *private = dev->dev_private; + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); - return to_exynos_crtc(private->crtc[pipe]); + return to_exynos_crtc(crtc); } static inline struct device *to_dma_dev(struct drm_device *dev) -- cgit v1.3.1 From b8bf6836bf00419e9b714ea70fbd8315b118c3bf Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:41 +0800 Subject: drm: kirin: use crtc helper drm_crtc_from_index() Use drm_crtc_from_index() to find drm_crtc for given index, so that we do not need to maintain a pointer array in struct kirin_drm_private. Reviewed-by: Xinliang Liu Signed-off-by: Shawn Guo Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-3-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 10 ++++------ drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 307d460ab684..9a0678a33e0d 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -304,8 +304,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc) static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe) { - struct kirin_drm_private *priv = dev->dev_private; - struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]); + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + struct ade_crtc *acrtc = to_ade_crtc(crtc); struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; @@ -320,8 +320,8 @@ static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe) static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe) { - struct kirin_drm_private *priv = dev->dev_private; - struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]); + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + struct ade_crtc *acrtc = to_ade_crtc(crtc); struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; @@ -575,7 +575,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = { static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *plane) { - struct kirin_drm_private *priv = dev->dev_private; struct device_node *port; int ret; @@ -599,7 +598,6 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, } drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); - priv->crtc[drm_crtc_index(crtc)] = crtc; return 0; } diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index a0bb217c4c64..7f60c64915d9 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -20,7 +20,6 @@ struct kirin_dc_ops { }; struct kirin_drm_private { - struct drm_crtc *crtc[MAX_CRTC]; #ifdef CONFIG_DRM_FBDEV_EMULATION struct drm_fbdev_cma *fbdev; #endif -- cgit v1.3.1 From ffec8925836caf1e91dce9c37c322c363eef58b3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:42 +0800 Subject: drm: mediatek: use crtc helper drm_crtc_from_index() Use drm_crtc_from_index() to find drm_crtc for given index, so that we do not need to maintain a pointer array in struct mtk_drm_private. Signed-off-by: Shawn Guo Cc: CK Hu Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-4-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 9 ++++----- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 01a21dd835b5..a73de1e669c2 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -170,8 +170,8 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe) { - struct mtk_drm_private *priv = drm->dev_private; - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]); + struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe); + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base); @@ -181,8 +181,8 @@ int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe) void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe) { - struct mtk_drm_private *priv = drm->dev_private; - struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]); + struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe); + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; mtk_ddp_comp_disable_vblank(ovl); @@ -588,7 +588,6 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, goto unprepare; drm_mode_crtc_set_gamma_size(&mtk_crtc->base, MTK_LUT_SIZE); drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, false, MTK_LUT_SIZE); - priv->crtc[pipe] = &mtk_crtc->base; priv->num_pipes++; return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index aa9389446785..df322a7a5fcb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -32,7 +32,6 @@ struct mtk_drm_private { struct drm_device *drm; struct device *dma_dev; - struct drm_crtc *crtc[MAX_CRTC]; unsigned int num_pipes; struct device_node *mutex_node; -- cgit v1.3.1 From ea441bd33f93aa7f6f404c8877e6d3313a4dbdbe Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:43 +0800 Subject: drm: nouveau: use crtc helper drm_crtc_from_index() Use drm_crtc_from_index() to find drm_crtc for given index. Signed-off-by: Shawn Guo Cc: Ben Skeggs Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-5-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/nouveau/nouveau_display.c | 33 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index add353e230f4..6b570079d185 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -58,27 +58,30 @@ int nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe) { struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - if (nv_crtc->index == pipe) { - nvif_notify_get(&nv_crtc->vblank); - return 0; - } - } - return -EINVAL; + struct nouveau_crtc *nv_crtc; + + crtc = drm_crtc_from_index(dev, pipe); + if (!crtc) + return -EINVAL; + + nv_crtc = nouveau_crtc(crtc); + nvif_notify_get(&nv_crtc->vblank); + + return 0; } void nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe) { struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - if (nv_crtc->index == pipe) { - nvif_notify_put(&nv_crtc->vblank); - return; - } - } + struct nouveau_crtc *nv_crtc; + + crtc = drm_crtc_from_index(dev, pipe); + if (!crtc) + return; + + nv_crtc = nouveau_crtc(crtc); + nvif_notify_put(&nv_crtc->vblank); } static inline int -- cgit v1.3.1 From 75bcb0545b56eab2d69dbccf95ff7505b7114e5d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:44 +0800 Subject: drm: tegra: use crtc helper drm_crtc_from_index() Function tegra_crtc_from_pipe() does the exactly same thing as what crtc helper drm_crtc_from_index() provides. Use the helper to save some code. Signed-off-by: Shawn Guo Cc: Thierry Reding Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-6-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/tegra/drm.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 0f4eacb0af4f..2d57f6278db1 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -804,23 +804,10 @@ static const struct file_operations tegra_drm_fops = { .llseek = noop_llseek, }; -static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, - unsigned int pipe) -{ - struct drm_crtc *crtc; - - list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { - if (pipe == drm_crtc_index(crtc)) - return crtc; - } - - return NULL; -} - static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, unsigned int pipe) { - struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); if (!crtc) @@ -831,7 +818,7 @@ static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) { - struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); if (!crtc) @@ -844,7 +831,7 @@ static int tegra_drm_enable_vblank(struct drm_device *drm, unsigned int pipe) static void tegra_drm_disable_vblank(struct drm_device *drm, unsigned int pipe) { - struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + struct drm_crtc *crtc = drm_crtc_from_index(drm, pipe); struct tegra_dc *dc = to_tegra_dc(crtc); if (crtc) -- cgit v1.3.1 From c77b9abf3c5ae86dcb0e414d55d42fb213e51b2a Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 9 Jan 2017 19:25:45 +0800 Subject: drm: vc4: use crtc helper drm_crtc_from_index() Use drm_crtc_from_index() to find drm_crtc for given index, so that we do not need to maintain a pointer array in struct vc4_dev. Signed-off-by: Shawn Guo Cc: Eric Anholt Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1483961145-18453-7-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/vc4/vc4_crtc.c | 17 +++++++---------- drivers/gpu/drm/vc4/vc4_drv.h | 1 - 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index a0fd3e66bc4b..75b708b36890 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -156,7 +156,8 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, const struct drm_display_mode *mode) { struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); u32 val; int fifo_lines; int vblank_lines; @@ -272,9 +273,7 @@ int vc4_crtc_get_vblank_timestamp(struct drm_device *dev, unsigned int crtc_id, int *max_error, struct timeval *vblank_time, unsigned flags) { - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; - struct drm_crtc *crtc = &vc4_crtc->base; + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); struct drm_crtc_state *state = crtc->state; /* Helper routine in DRM core does all the work: */ @@ -652,8 +651,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id) { - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); CRTC_WRITE(PV_INTEN, PV_INT_VFP_START); @@ -662,8 +661,8 @@ int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id) void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id) { - struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc *vc4_crtc = vc4->crtc[crtc_id]; + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); CRTC_WRITE(PV_INTEN, 0); } @@ -937,7 +936,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_crtc *vc4_crtc; struct drm_crtc *crtc; struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp; @@ -975,7 +973,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) &vc4_crtc_funcs, NULL); drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); primary_plane->crtc = crtc; - vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc; vc4_crtc->channel = vc4_crtc->data->hvs_channel; drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 489956efbff8..affcdeb70aa9 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -16,7 +16,6 @@ struct vc4_dev { struct vc4_hdmi *hdmi; struct vc4_hvs *hvs; - struct vc4_crtc *crtc[3]; struct vc4_v3d *v3d; struct vc4_dpi *dpi; struct vc4_vec *vec; -- cgit v1.3.1 From 518cb7057a59b9441336d2e88a396d52b6ab0cce Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 16 Jan 2017 16:52:47 -0800 Subject: drm/bridge: adv7511: Use work_struct to defer hotplug handing to out of irq context I was recently seeing issues with EDID probing, where the logic to wait for the EDID read bit to be set by the IRQ wasn't happening and the code would time out and fail. Digging deeper, I found this was due to the fact that IRQs were disabled as we were running in IRQ context from the HPD signal. Thus this patch changes the logic to handle the HPD signal via a work_struct so we can be out of irq context. With this patch, the EDID probing on hotplug does not time out. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Reviewed-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-2-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 2 ++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 039147fde7b0..fe18a5d2d84b 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -318,6 +318,8 @@ struct adv7511 { bool edid_read; wait_queue_head_t wq; + struct work_struct hpd_work; + struct drm_bridge bridge; struct drm_connector connector; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 70b426925604..ce5c19c829b9 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -402,6 +402,13 @@ static bool adv7511_hpd(struct adv7511 *adv7511) return false; } +static void adv7511_hpd_work(struct work_struct *work) +{ + struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); + + drm_helper_hpd_irq_event(adv7511->connector.dev); +} + static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) { unsigned int irq0, irq1; @@ -419,7 +426,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) - drm_helper_hpd_irq_event(adv7511->connector.dev); + schedule_work(&adv7511->hpd_work); if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { adv7511->edid_read = true; @@ -1070,6 +1077,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) goto err_i2c_unregister_edid; } + INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); + if (i2c->irq) { init_waitqueue_head(&adv7511->wq); -- cgit v1.3.1 From 6d5104c5a6b56385426e15047050584794bb6254 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 16 Jan 2017 16:52:48 -0800 Subject: drm/bridge: adv7511: Switch to using drm_kms_helper_hotplug_event() In chasing down a previous issue with EDID probing from calling drm_helper_hpd_irq_event() from irq context, Laurent noticed that the DRM documentation suggests that drm_kms_helper_hotplug_event() should be used instead. Thus this patch replaces drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event(), which requires we update the connector.status entry and only call _hotplug_event() when the status changes. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Reviewed-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-3-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index ce5c19c829b9..60773387fcdf 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -405,8 +405,22 @@ static bool adv7511_hpd(struct adv7511 *adv7511) static void adv7511_hpd_work(struct work_struct *work) { struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work); + enum drm_connector_status status; + unsigned int val; + int ret; - drm_helper_hpd_irq_event(adv7511->connector.dev); + ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); + if (ret < 0) + status = connector_status_disconnected; + else if (val & ADV7511_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + + if (adv7511->connector.status != status) { + adv7511->connector.status = status; + drm_kms_helper_hotplug_event(adv7511->connector.dev); + } } static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd) -- cgit v1.3.1 From 40d86d2d22b04c2b2e48e2fe7054b85cf5021f25 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 16 Jan 2017 16:52:49 -0800 Subject: drm/bridge: adv7511: Enable HPD interrupts to support hotplug and improve monitor detection On some adv7511 implementations, we can get some spurious disconnect signals which can cause monitor probing to fail. This patch enables HPD (hot plug detect) interrupt support which allows the monitor to be properly re-initialized when the spurious disconnect signal goes away. This also enables proper hotplug support. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Acked-by: Laurent Pinchart Tested-by: Laurent Pinchart Originally-by: Archit Taneja [jstultz: Added proper commit message] Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-4-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 60773387fcdf..72939d429da6 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -338,7 +338,7 @@ static void adv7511_power_on(struct adv7511 *adv7511) * Still, let's be safe and stick to the documentation. */ regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), - ADV7511_INT0_EDID_READY); + ADV7511_INT0_EDID_READY | ADV7511_INT0_HPD); regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), ADV7511_INT1_DDC_ERROR); } @@ -846,6 +846,10 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge) if (adv->type == ADV7533) ret = adv7533_attach_dsi(adv); + if (adv->i2c_main->irq) + regmap_write(adv->regmap, ADV7511_REG_INT_ENABLE(0), + ADV7511_INT0_HPD); + return ret; } -- cgit v1.3.1 From 651e4769ba2a9f20c4b8a823ae2727bf7fa9c9f0 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 16 Jan 2017 16:52:50 -0800 Subject: drm/bridge: adv7511: Rework adv7511_power_on/off() so they can be reused internally In chasing down issues with EDID probing, I found some duplicated but incomplete logic used to power the chip on and off. This patch refactors the adv7511_power_on/off functions, so they can be used for internal needs. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-5-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 72939d429da6..545ceff5890f 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -325,7 +325,7 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; } -static void adv7511_power_on(struct adv7511 *adv7511) +static void __adv7511_power_on(struct adv7511 *adv7511) { adv7511->current_edid_segment = -1; @@ -354,6 +354,11 @@ static void adv7511_power_on(struct adv7511 *adv7511) regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, ADV7511_REG_POWER2_HPD_SRC_MASK, ADV7511_REG_POWER2_HPD_SRC_NONE); +} + +static void adv7511_power_on(struct adv7511 *adv7511) +{ + __adv7511_power_on(adv7511); /* * Most of the registers are reset during power down or when HPD is low. @@ -362,21 +367,23 @@ static void adv7511_power_on(struct adv7511 *adv7511) if (adv7511->type == ADV7533) adv7533_dsi_power_on(adv7511); - adv7511->powered = true; } -static void adv7511_power_off(struct adv7511 *adv7511) +static void __adv7511_power_off(struct adv7511 *adv7511) { /* TODO: setup additional power down modes */ regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); regcache_mark_dirty(adv7511->regmap); +} +static void adv7511_power_off(struct adv7511 *adv7511) +{ + __adv7511_power_off(adv7511); if (adv7511->type == ADV7533) adv7533_dsi_power_off(adv7511); - adv7511->powered = false; } -- cgit v1.3.1 From 4226d9b127cf4758ba0e07931b3f0d59f1b1a50c Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 16 Jan 2017 16:52:51 -0800 Subject: drm/bridge: adv7511: Reuse __adv7511_power_on/off() when probing EDID Thus this patch changes the EDID probing logic so that we re-use the __adv7511_power_on/off() calls instead of duplciating logic. This does change behavior slightly as it adds the HPD signal pulse to the EDID probe path, but Archit has had a patch to add HPD signal pulse to the EDID probe path before, so this should address the cases where that helped. Another difference is that regcache_mark_dirty() is also called in the power off path once EDID is probed. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Reviewed-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-6-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 545ceff5890f..17b9e98b151b 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -573,24 +573,13 @@ static int adv7511_get_modes(struct adv7511 *adv7511, unsigned int count; /* Reading the EDID only works if the device is powered */ - if (!adv7511->powered) { - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, 0); - if (adv7511->i2c_main->irq) { - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0), - ADV7511_INT0_EDID_READY); - regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1), - ADV7511_INT1_DDC_ERROR); - } - adv7511->current_edid_segment = -1; - } + if (!adv7511->powered) + __adv7511_power_on(adv7511); edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); if (!adv7511->powered) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, - ADV7511_POWER_POWER_DOWN); + __adv7511_power_off(adv7511); kfree(adv7511->edid); adv7511->edid = edid; -- cgit v1.3.1 From 3587c856675c45809010c2cee5b21096f6e8e938 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 16 Jan 2017 16:52:52 -0800 Subject: drm/bridge: adv7511: Re-write the i2c address before EDID probing I've found that by just turning the chip on and off via the POWER_DOWN register, I end up getting i2c_transfer errors on HiKey. Investigating further, it turns out that some of the register state in hardware is getting lost, as the device registers are reset when the chip is powered down. Thus this patch simply re-writes the i2c address to the ADV7511_REG_EDID_I2C_ADDR register to ensure its properly set before we try to read the EDID data. Cc: David Airlie Cc: Archit Taneja Cc: Wolfram Sang Cc: Lars-Peter Clausen Cc: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org Reviewed-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1484614372-15342-7-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 17b9e98b151b..f75ab6278113 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -573,9 +573,17 @@ static int adv7511_get_modes(struct adv7511 *adv7511, unsigned int count; /* Reading the EDID only works if the device is powered */ - if (!adv7511->powered) + if (!adv7511->powered) { + unsigned int edid_i2c_addr = + (adv7511->i2c_main->addr << 1) + 4; + __adv7511_power_on(adv7511); + /* Reset the EDID_I2C_ADDR register as it might be cleared */ + regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, + edid_i2c_addr); + } + edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); if (!adv7511->powered) -- cgit v1.3.1 From 2b65d5677a797f8b53e97548003d1f38677fee81 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Thu, 19 Jan 2017 11:48:05 -0200 Subject: drm: qxl: Open code probing sequence for qxl This avoids using the deprecated drm_get_pci_dev() and load() hook interfaces in the qxl driver. The only tricky part is to ensure TTM debugfs initialization happens after the debugfs root node is created, which is done by moving that code into the debufs_init() hook. Tested on qemu with igt and running a WM on top of X. Changes since v1: - Drop verification for primary minor in qxl_debugsfs_init. Changes since V2: - Put new header together with other debugfs headers. Signed-off-by: Gabriel Krisman Bertazi Cc: Dave Airlie Cc: Daniel Vetter Cc: Gustavo Padovan Signed-off-by: Gustavo Padovan Link: http://patchwork.freedesktop.org/patch/msgid/20170119134806.8926-1-krisman@collabora.co.uk --- drivers/gpu/drm/qxl/qxl_debugfs.c | 10 +++++++ drivers/gpu/drm/qxl/qxl_drv.c | 58 +++++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/qxl/qxl_drv.h | 6 +++- drivers/gpu/drm/qxl/qxl_kms.c | 40 ++------------------------- drivers/gpu/drm/qxl/qxl_ttm.c | 8 +----- 5 files changed, 74 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index 241af9131dc8..057b2b547cac 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -84,8 +84,18 @@ int qxl_debugfs_init(struct drm_minor *minor) { #if defined(CONFIG_DEBUG_FS) + int r; + struct qxl_device *dev = + (struct qxl_device *) minor->dev->dev_private; + drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, minor->debugfs_root, minor); + + r = qxl_ttm_debugfs_init(dev); + if (r) { + DRM_ERROR("Failed to init TTM debugfs\n"); + return r; + } #endif return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 460bbceae297..7cc29027a612 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -62,12 +62,67 @@ static struct pci_driver qxl_pci_driver; static int qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct drm_device *drm; + struct qxl_device *qdev; + int ret; + if (pdev->revision < 4) { DRM_ERROR("qxl too old, doesn't support client_monitors_config," " use xf86-video-qxl in user mode"); return -EINVAL; /* TODO: ENODEV ? */ } - return drm_get_pci_dev(pdev, ent, &qxl_driver); + + drm = drm_dev_alloc(&qxl_driver, &pdev->dev); + if (IS_ERR(drm)) + return -ENOMEM; + + qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); + if (!qdev) { + ret = -ENOMEM; + goto free_drm_device; + } + + ret = pci_enable_device(pdev); + if (ret) + goto free_drm_device; + + drm->pdev = pdev; + pci_set_drvdata(pdev, drm); + drm->dev_private = qdev; + + ret = qxl_device_init(qdev, drm, pdev, ent->driver_data); + if (ret) + goto disable_pci; + + ret = drm_vblank_init(drm, 1); + if (ret) + goto unload; + + ret = qxl_modeset_init(qdev); + if (ret) + goto vblank_cleanup; + + drm_kms_helper_poll_init(qdev->ddev); + + /* Complete initialization. */ + ret = drm_dev_register(drm, ent->driver_data); + if (ret) + goto modeset_cleanup; + + return 0; + +modeset_cleanup: + qxl_modeset_fini(qdev); +vblank_cleanup: + drm_vblank_cleanup(drm); +unload: + qxl_device_fini(qdev); +disable_pci: + pci_disable_device(pdev); +free_drm_device: + kfree(qdev); + kfree(drm); + return ret; } static void @@ -230,7 +285,6 @@ static struct pci_driver qxl_pci_driver = { static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, - .load = qxl_driver_load, .unload = qxl_driver_unload, .get_vblank_counter = qxl_noop_get_vblank_counter, .enable_vblank = qxl_noop_enable_vblank, diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 883d8639c04e..83201988394f 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -336,7 +336,10 @@ __printf(2,3) void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...); extern const struct drm_ioctl_desc qxl_ioctls[]; extern int qxl_max_ioctl; -int qxl_driver_load(struct drm_device *dev, unsigned long flags); +int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev, + struct pci_dev *pdev, unsigned long flags); +void qxl_device_fini(struct qxl_device *qdev); + void qxl_driver_unload(struct drm_device *dev); int qxl_modeset_init(struct qxl_device *qdev); @@ -531,6 +534,7 @@ int qxl_garbage_collect(struct qxl_device *qdev); int qxl_debugfs_init(struct drm_minor *minor); void qxl_debugfs_takedown(struct drm_minor *minor); +int qxl_ttm_debugfs_init(struct qxl_device *qdev); /* qxl_prime.c */ int qxl_gem_prime_pin(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index b2491407b616..6848057d0917 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -115,7 +115,7 @@ static void qxl_gc_work(struct work_struct *work) qxl_garbage_collect(qdev); } -static int qxl_device_init(struct qxl_device *qdev, +int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev, struct pci_dev *pdev, unsigned long flags) @@ -263,7 +263,7 @@ static int qxl_device_init(struct qxl_device *qdev, return 0; } -static void qxl_device_fini(struct qxl_device *qdev) +void qxl_device_fini(struct qxl_device *qdev) { if (qdev->current_release_bo[0]) qxl_bo_unref(&qdev->current_release_bo[0]); @@ -300,39 +300,3 @@ void qxl_driver_unload(struct drm_device *dev) kfree(qdev); dev->dev_private = NULL; } - -int qxl_driver_load(struct drm_device *dev, unsigned long flags) -{ - struct qxl_device *qdev; - int r; - - qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); - if (qdev == NULL) - return -ENOMEM; - - dev->dev_private = qdev; - - r = qxl_device_init(qdev, dev, dev->pdev, flags); - if (r) - goto out; - - r = drm_vblank_init(dev, 1); - if (r) - goto unload; - - r = qxl_modeset_init(qdev); - if (r) - goto unload; - - drm_kms_helper_poll_init(qdev->ddev); - - return 0; -unload: - qxl_driver_unload(dev); - -out: - kfree(qdev); - return r; -} - - diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 1b096c5252ad..bc1c896bc5e1 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -35,7 +35,6 @@ #include "qxl_object.h" #include -static int qxl_ttm_debugfs_init(struct qxl_device *qdev); static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) { @@ -436,11 +435,6 @@ int qxl_ttm_init(struct qxl_device *qdev) ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); DRM_INFO("qxl: %uM of Surface memory size\n", (unsigned)qdev->surfaceram_size / (1024 * 1024)); - r = qxl_ttm_debugfs_init(qdev); - if (r) { - DRM_ERROR("Failed to init debugfs\n"); - return r; - } return 0; } @@ -473,7 +467,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data) } #endif -static int qxl_ttm_debugfs_init(struct qxl_device *qdev) +int qxl_ttm_debugfs_init(struct qxl_device *qdev) { #if defined(CONFIG_DEBUG_FS) static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; -- cgit v1.3.1 From 6f897f51c4181397bf811d260eb7fef8d7ccd14f Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Thu, 19 Jan 2017 11:48:06 -0200 Subject: drm: qxl: Open code teardown function for qxl This avoids using the deprecated drm_put_dev() and unload() hook interfaces in the qxl driver. Signed-off-by: Gabriel Krisman Bertazi Cc: Dave Airlie Cc: Daniel Vetter Cc: Gustavo Padovan Signed-off-by: Gustavo Padovan Link: http://patchwork.freedesktop.org/patch/msgid/20170119134806.8926-2-krisman@collabora.co.uk --- drivers/gpu/drm/qxl/qxl_drv.c | 11 +++++++++-- drivers/gpu/drm/qxl/qxl_drv.h | 2 -- drivers/gpu/drm/qxl/qxl_kms.c | 16 ---------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 7cc29027a612..6e0f8a2d8ac9 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -129,8 +129,16 @@ static void qxl_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); + struct qxl_device *qdev = dev->dev_private; + + drm_dev_unregister(dev); + + qxl_modeset_fini(qdev); + qxl_device_fini(qdev); - drm_put_dev(dev); + dev->dev_private = NULL; + kfree(qdev); + drm_dev_unref(dev); } static const struct file_operations qxl_fops = { @@ -285,7 +293,6 @@ static struct pci_driver qxl_pci_driver = { static struct drm_driver qxl_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, - .unload = qxl_driver_unload, .get_vblank_counter = qxl_noop_get_vblank_counter, .enable_vblank = qxl_noop_enable_vblank, .disable_vblank = qxl_noop_disable_vblank, diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 83201988394f..0d877fa61162 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -340,8 +340,6 @@ int qxl_device_init(struct qxl_device *qdev, struct drm_device *ddev, struct pci_dev *pdev, unsigned long flags); void qxl_device_fini(struct qxl_device *qdev); -void qxl_driver_unload(struct drm_device *dev); - int qxl_modeset_init(struct qxl_device *qdev); void qxl_modeset_fini(struct qxl_device *qdev); diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 6848057d0917..d0666f5dccd6 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -284,19 +284,3 @@ void qxl_device_fini(struct qxl_device *qdev) qdev->mode_info.num_modes = 0; qxl_debugfs_remove_files(qdev); } - -void qxl_driver_unload(struct drm_device *dev) -{ - struct qxl_device *qdev = dev->dev_private; - - if (qdev == NULL) - return; - - drm_vblank_cleanup(dev); - - qxl_modeset_fini(qdev); - qxl_device_fini(qdev); - - kfree(qdev); - dev->dev_private = NULL; -} -- cgit v1.3.1