From 8a357d10043c75e980e7fcdb60d2b913491564af Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 28 Oct 2016 10:10:50 +0200 Subject: [PATCH 01/33] drm: Nerf DRM_CONTROL nodes Looking at the ioctl permission checks I noticed that it's impossible to import gem buffers into a control nodes, and fd2handle/handle2fd also don't work, so no joy with dma-bufs. The only way to do anything with a control node is by drawing stuff into a dumb buffer and displaying that. I suspect control nodes are an entirely unused thing, and a cursory check shows that there does not seem to be any callers of drmOpenControl nor of the other drmOpen functions using DRM_MODE_CONTROL. Since I don't like dead uabi, let's remove it. But since this would be a really big change I think it's better to start out small by simply not registering anything. We can garbage-collect the dead code later on, once we're sure it's really not used anywhere. Acked-by: Dave Airlie Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161028081050.1042-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_drv.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6dbb98649795..cc6c2530764b 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -507,12 +507,6 @@ int drm_dev_init(struct drm_device *dev, goto err_free; } - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL); - if (ret) - goto err_minors; - } - if (drm_core_check_feature(dev, DRIVER_RENDER)) { ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); if (ret) From d52ea7e3d493840e459099d5af668ed5029d66de Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Nov 2016 15:08:17 +0100 Subject: [PATCH 02/33] MAINTAINERS: Add drm-misc KS happened, time to make this official! Well, scripting work to make this all happen is still ongoing, but I'm trying to at least keep the new tree semi-in-sync with the temporary topic/drm-misc branch in the drm-intel.git repo. So for now still no new committers, and existing ones still need to push to topic/drm-misc in drm-intel.git. Big kudos to Jani&Sean for volunteering as co-maintainers! v2: Restrict patterns a bit to avoid all the driver spam. Cc: Daniel Vetter Cc: Jani Nikula Cc: Sean Paul Acked-by: Sean Paul Acked-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161116140819.31165-1-daniel.vetter@ffwll.ch --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 02f20dba7055..f1f0a3983be8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4022,6 +4022,18 @@ F: Documentation/gpu/ F: include/drm/ F: include/uapi/drm/ +DRM DRIVERS AND MISC GPU PATCHES +M: Daniel Vetter +M: Jani Nikula +M: Sean Paul +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/gpu/ +F: drivers/gpu/vga/ +F: drivers/gpu/drm/* +F: include/drm/drm* +F: include/uapi/drm/drm* + DRM DRIVER FOR AST SERVER GRAPHICS CHIPS M: Dave Airlie S: Odd Fixes From 5620f47dface9dfe2f9282892dd9e04101691d92 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Nov 2016 15:08:19 +0100 Subject: [PATCH 03/33] MAINTAINERS: Add Archit as drm bridge maintainer Again something that's in the drm-misc fold. Cc: Archit Taneja Acked-by: Archit Taneja Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161116140819.31165-3-daniel.vetter@ffwll.ch --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f1f0a3983be8..e65f435b80f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4039,6 +4039,12 @@ M: Dave Airlie S: Odd Fixes F: drivers/gpu/drm/ast/ +DRM DRIVERS FOR BRIDGE CHIPS +M: Archit Taneja +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/gpu/drm/bridge/ + DRM DRIVER FOR BOCHS VIRTUAL GPU M: Gerd Hoffmann S: Odd Fixes From af948a25ecb2141b26138d52457f4742be0b497d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 16 Nov 2016 23:42:31 +0800 Subject: [PATCH 04/33] drm/bridge: dumb-vga-dac: Support a VDD regulator supply Some dumb VGA DACs are active components which require external power. Add support for specifying a regulator as its power supply. Signed-off-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20161116154232.872-2-wens@csie.org --- .../bindings/display/bridge/dumb-vga-dac.txt | 2 ++ drivers/gpu/drm/bridge/dumb-vga-dac.c | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt index 003bc246a270..164cbb15f04c 100644 --- a/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt +++ b/Documentation/devicetree/bindings/display/bridge/dumb-vga-dac.txt @@ -16,6 +16,8 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt. - Video port 0 for RGB input - Video port 1 for VGA output +Optional properties: +- vdd-supply: Power supply for DAC Example ------- diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index afec232185a7..e5706981c934 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -23,6 +24,7 @@ struct dumb_vga { struct drm_connector connector; struct i2c_adapter *ddc; + struct regulator *vdd; }; static inline struct dumb_vga * @@ -124,8 +126,30 @@ static int dumb_vga_attach(struct drm_bridge *bridge) return 0; } +static void dumb_vga_enable(struct drm_bridge *bridge) +{ + struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); + int ret = 0; + + if (vga->vdd) + ret = regulator_enable(vga->vdd); + + if (ret) + DRM_ERROR("Failed to enable vdd regulator: %d\n", ret); +} + +static void dumb_vga_disable(struct drm_bridge *bridge) +{ + struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); + + if (vga->vdd) + regulator_disable(vga->vdd); +} + static const struct drm_bridge_funcs dumb_vga_bridge_funcs = { .attach = dumb_vga_attach, + .enable = dumb_vga_enable, + .disable = dumb_vga_disable, }; static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev) @@ -169,6 +193,15 @@ static int dumb_vga_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, vga); + vga->vdd = devm_regulator_get_optional(&pdev->dev, "vdd"); + if (IS_ERR(vga->vdd)) { + ret = PTR_ERR(vga->vdd); + if (ret == -EPROBE_DEFER) + return -EPROBE_DEFER; + vga->vdd = NULL; + dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret); + } + vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev); if (IS_ERR(vga->ddc)) { if (PTR_ERR(vga->ddc) == -ENODEV) { From 0b46fcdb082cc6bdc7871a674a0041509cd21eb3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 16 Nov 2016 15:08:18 +0100 Subject: [PATCH 05/33] MAINTAINERS: Move dma-buf to drm-misc git Sumit still takes care about dma-buf, but we've merged the trees together since way too much overlap. And Gustavo is also part of the drm-misc team to be able to help out. Cc: Sumit Semwal Cc: Gustavo Padovan Acked-by: Sumit Semwal Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161116140819.31165-2-daniel.vetter@ffwll.ch --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e65f435b80f3..61979cf461e7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3911,7 +3911,7 @@ F: include/linux/dma-buf* F: include/linux/reservation.h F: include/linux/*fence.h F: Documentation/dma-buf-sharing.txt -T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git +T: git git://anongit.freedesktop.org/drm/drm-misc SYNC FILE FRAMEWORK M: Sumit Semwal @@ -3924,7 +3924,7 @@ F: drivers/dma-buf/sw_sync.c F: include/linux/sync_file.h F: include/uapi/linux/sync_file.h F: Documentation/sync_file.txt -T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git +T: git git://anongit.freedesktop.org/drm/drm-misc DMA GENERIC OFFLOAD ENGINE SUBSYSTEM M: Vinod Koul From bae781b259269590109e8a4a8227331362b88212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 16 Nov 2016 13:33:16 +0200 Subject: [PATCH 06/33] drm: Nuke modifier[1-3] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It has been suggested that having per-plane modifiers is making life more difficult for userspace, so let's just retire modifier[1-3] and use modifier[0] to apply to the entire framebuffer. Obviosuly this means that if individual planes need different tiling layouts and whatnot we will need a new modifier for each combination of planes with different tiling layouts. For a bit of extra backwards compatilbilty the kernel will allow non-zero modifier[1+] but it require that they will match modifier[0]. This in case there's existing userspace out there that sets modifier[1+] to something non-zero with planar formats. Mostly a cocci job, with a bit of manual stuff mixed in. @@ struct drm_framebuffer *fb; expression E; @@ - fb->modifier[E] + fb->modifier @@ struct drm_framebuffer fb; expression E; @@ - fb.modifier[E] + fb.modifier Cc: Kristian Høgsberg Cc: Ben Widawsky Cc: Rob Clark Cc: Daniel Vetter Cc: Tomeu Vizoso Cc: dczaplejewicz@collabora.co.uk Suggested-by: Kristian Høgsberg Acked-by: Ben Widawsky Acked-by: Daniel Stone Acked-by: Rob Clark Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479295996-26246-1-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_framebuffer.c | 7 +++ drivers/gpu/drm/drm_modeset_helper.c | 2 +- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/intel_atomic_plane.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 72 +++++++++++------------ drivers/gpu/drm/i915/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 22 +++---- drivers/gpu/drm/i915/intel_sprite.c | 14 ++--- drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | 2 +- include/drm/drm_framebuffer.h | 4 +- include/uapi/drm/drm_mode.h | 13 ++-- 12 files changed, 79 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index b476ec585547..85466cc67819 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -965,12 +965,12 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "\t\tformat=%s\n", drm_get_format_name(fb->pixel_format, &format_name)); + drm_printf(p, "\t\t\tmodifier=0x%llx\n", fb->modifier); drm_printf(p, "\t\tsize=%dx%d\n", fb->width, fb->height); drm_printf(p, "\t\tlayers:\n"); for (i = 0; i < n; i++) { drm_printf(p, "\t\t\tpitch[%d]=%u\n", i, fb->pitches[i]); drm_printf(p, "\t\t\toffset[%d]=%u\n", i, fb->offsets[i]); - drm_printf(p, "\t\t\tmodifier[%d]=0x%llx\n", i, fb->modifier[i]); } } drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 06ad3d1350c4..cbf0c893f426 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -177,6 +177,13 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) return -EINVAL; } + if (r->flags & DRM_MODE_FB_MODIFIERS && + r->modifier[i] != r->modifier[0]) { + DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", + r->modifier[i], i); + return -EINVAL; + } + /* modifier specific checks: */ switch (r->modifier[i]) { case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 2f452b3dd40e..633355e02398 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -93,8 +93,8 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, for (i = 0; i < 4; i++) { fb->pitches[i] = mode_cmd->pitches[i]; fb->offsets[i] = mode_cmd->offsets[i]; - fb->modifier[i] = mode_cmd->modifier[i]; } + fb->modifier = mode_cmd->modifier[0]; fb->pixel_format = mode_cmd->pixel_format; fb->flags = mode_cmd->flags; } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7166a1a6265d..6b159bab42b0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1896,7 +1896,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fbdev_fb->base.height, fbdev_fb->base.depth, fbdev_fb->base.bits_per_pixel, - fbdev_fb->base.modifier[0], + fbdev_fb->base.modifier, drm_framebuffer_read_refcount(&fbdev_fb->base)); describe_obj(m, fbdev_fb->obj); seq_putc(m, '\n'); @@ -1914,7 +1914,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.height, fb->base.depth, fb->base.bits_per_pixel, - fb->base.modifier[0], + fb->base.modifier, drm_framebuffer_read_refcount(&fb->base)); describe_obj(m, fb->obj); seq_putc(m, '\n'); diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 984a6b75c118..71ab735cb82b 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -143,8 +143,8 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (state->fb && drm_rotation_90_or_270(state->rotation)) { struct drm_format_name_buf format_name; - if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { + if (state->fb->modifier != I915_FORMAT_MOD_Y_TILED && + state->fb->modifier != I915_FORMAT_MOD_Yf_TILED) { DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6fd6283fa1f8..c63ba7f435bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2195,7 +2195,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation) WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); + alignment = intel_surf_alignment(dev_priv, fb->modifier); intel_fill_fb_ggtt_view(&view, fb, rotation); @@ -2356,13 +2356,13 @@ static u32 intel_adjust_tile_offset(int *x, int *y, WARN_ON(new_offset > old_offset); - if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) { + if (fb->modifier != DRM_FORMAT_MOD_NONE) { unsigned int tile_size, tile_width, tile_height; unsigned int pitch_tiles; tile_size = intel_tile_size(dev_priv); intel_tile_dims(dev_priv, &tile_width, &tile_height, - fb->modifier[plane], cpp); + fb->modifier, cpp); if (drm_rotation_90_or_270(rotation)) { pitch_tiles = pitch / tile_height; @@ -2405,7 +2405,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, unsigned int rotation, u32 alignment) { - uint64_t fb_modifier = fb->modifier[plane]; + uint64_t fb_modifier = fb->modifier; unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane); u32 offset, offset_aligned; @@ -2464,7 +2464,7 @@ u32 intel_compute_tile_offset(int *x, int *y, if (fb->pixel_format == DRM_FORMAT_NV12 && plane == 1) alignment = 4096; else - alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]); + alignment = intel_surf_alignment(dev_priv, fb->modifier); return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch, rotation, alignment); @@ -2546,13 +2546,13 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, DRM_ROTATE_0, tile_size); offset /= tile_size; - if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) { + if (fb->modifier != DRM_FORMAT_MOD_NONE) { unsigned int tile_width, tile_height; unsigned int pitch_tiles; struct drm_rect r; intel_tile_dims(dev_priv, &tile_width, &tile_height, - fb->modifier[i], cpp); + fb->modifier, cpp); rot_info->plane[i].offset = offset; rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp); @@ -2711,7 +2711,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, mode_cmd.width = fb->width; mode_cmd.height = fb->height; mode_cmd.pitches[0] = fb->pitches[0]; - mode_cmd.modifier[0] = fb->modifier[0]; + mode_cmd.modifier[0] = fb->modifier; mode_cmd.flags = DRM_MODE_FB_MODIFIERS; if (intel_framebuffer_init(dev, to_intel_framebuffer(fb), @@ -2841,7 +2841,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane, { int cpp = drm_format_plane_cpp(fb->pixel_format, plane); - switch (fb->modifier[plane]) { + switch (fb->modifier) { case DRM_FORMAT_MOD_NONE: case I915_FORMAT_MOD_X_TILED: switch (cpp) { @@ -2872,7 +2872,7 @@ static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane, } break; default: - MISSING_CASE(fb->modifier[plane]); + MISSING_CASE(fb->modifier); } return 2048; @@ -2900,7 +2900,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) intel_add_fb_offsets(&x, &y, plane_state, 0); offset = intel_compute_tile_offset(&x, &y, plane_state, 0); - alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); + alignment = intel_surf_alignment(dev_priv, fb->modifier); /* * AUX surface offset is specified as the distance from the @@ -2917,7 +2917,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) * * TODO: linear and Y-tiled seem fine, Yf untested, */ - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) { + if (fb->modifier == I915_FORMAT_MOD_X_TILED) { int cpp = drm_format_plane_cpp(fb->pixel_format, 0); while ((x + w) * cpp > fb->pitches[0]) { @@ -3067,7 +3067,7 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, } if (INTEL_GEN(dev_priv) >= 4 && - fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + fb->modifier == I915_FORMAT_MOD_X_TILED) dspcntr |= DISPPLANE_TILED; if (IS_G4X(dev_priv)) @@ -3169,7 +3169,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, BUG(); } - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dspcntr |= DISPPLANE_TILED; if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) @@ -3278,9 +3278,9 @@ u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, if (drm_rotation_90_or_270(rotation)) { int cpp = drm_format_plane_cpp(fb->pixel_format, plane); - stride /= intel_tile_height(dev_priv, fb->modifier[0], cpp); + stride /= intel_tile_height(dev_priv, fb->modifier, cpp); } else { - stride /= intel_fb_stride_alignment(dev_priv, fb->modifier[0], + stride /= intel_fb_stride_alignment(dev_priv, fb->modifier, fb->pixel_format); } @@ -3399,7 +3399,7 @@ static void skylake_update_primary_plane(struct drm_plane *plane, PLANE_CTL_PIPE_CSC_ENABLE; plane_ctl |= skl_plane_ctl_format(fb->pixel_format); - plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier); plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; plane_ctl |= skl_plane_ctl_rotation(rotation); @@ -8730,7 +8730,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { if (val & DISPPLANE_TILED) { plane_config->tiling = I915_TILING_X; - fb->modifier[0] = I915_FORMAT_MOD_X_TILED; + fb->modifier = I915_FORMAT_MOD_X_TILED; } } @@ -8759,7 +8759,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, aligned_height = intel_fb_align_height(dev, fb->height, fb->pixel_format, - fb->modifier[0]); + fb->modifier); plane_config->size = fb->pitches[0] * aligned_height; @@ -9773,17 +9773,17 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, tiling = val & PLANE_CTL_TILED_MASK; switch (tiling) { case PLANE_CTL_TILED_LINEAR: - fb->modifier[0] = DRM_FORMAT_MOD_NONE; + fb->modifier = DRM_FORMAT_MOD_NONE; break; case PLANE_CTL_TILED_X: plane_config->tiling = I915_TILING_X; - fb->modifier[0] = I915_FORMAT_MOD_X_TILED; + fb->modifier = I915_FORMAT_MOD_X_TILED; break; case PLANE_CTL_TILED_Y: - fb->modifier[0] = I915_FORMAT_MOD_Y_TILED; + fb->modifier = I915_FORMAT_MOD_Y_TILED; break; case PLANE_CTL_TILED_YF: - fb->modifier[0] = I915_FORMAT_MOD_Yf_TILED; + fb->modifier = I915_FORMAT_MOD_Yf_TILED; break; default: MISSING_CASE(tiling); @@ -9800,13 +9800,13 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, fb->width = ((val >> 0) & 0x1fff) + 1; val = I915_READ(PLANE_STRIDE(pipe, 0)); - stride_mult = intel_fb_stride_alignment(dev_priv, fb->modifier[0], + stride_mult = intel_fb_stride_alignment(dev_priv, fb->modifier, fb->pixel_format); fb->pitches[0] = (val & 0x3ff) * stride_mult; aligned_height = intel_fb_align_height(dev, fb->height, fb->pixel_format, - fb->modifier[0]); + fb->modifier); plane_config->size = fb->pitches[0] * aligned_height; @@ -9874,7 +9874,7 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { if (val & DISPPLANE_TILED) { plane_config->tiling = I915_TILING_X; - fb->modifier[0] = I915_FORMAT_MOD_X_TILED; + fb->modifier = I915_FORMAT_MOD_X_TILED; } } @@ -9903,7 +9903,7 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc, aligned_height = intel_fb_align_height(dev, fb->height, fb->pixel_format, - fb->modifier[0]); + fb->modifier); plane_config->size = fb->pitches[0] * aligned_height; @@ -11818,7 +11818,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev, MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0]); intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset | - intel_fb_modifier_to_tiling(fb->modifier[0])); + intel_fb_modifier_to_tiling(fb->modifier)); /* XXX Enabling the panel-fitter across page-flip is so far * untested on non-native modes, so ignore it for now. @@ -11851,7 +11851,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0] | - intel_fb_modifier_to_tiling(fb->modifier[0])); + intel_fb_modifier_to_tiling(fb->modifier)); intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset); /* Contrary to the suggestions in the documentation, @@ -11957,7 +11957,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); intel_ring_emit(ring, fb->pitches[0] | - intel_fb_modifier_to_tiling(fb->modifier[0])); + intel_fb_modifier_to_tiling(fb->modifier)); intel_ring_emit(ring, intel_crtc->flip_work->gtt_offset); intel_ring_emit(ring, (MI_NOOP)); @@ -12003,7 +12003,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc, ctl = I915_READ(PLANE_CTL(pipe, 0)); ctl &= ~PLANE_CTL_TILED_MASK; - switch (fb->modifier[0]) { + switch (fb->modifier) { case DRM_FORMAT_MOD_NONE: break; case I915_FORMAT_MOD_X_TILED: @@ -12016,7 +12016,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc, ctl |= PLANE_CTL_TILED_YF; break; default: - MISSING_CASE(fb->modifier[0]); + MISSING_CASE(fb->modifier); } /* @@ -12041,7 +12041,7 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc, dspcntr = I915_READ(reg); - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dspcntr |= DISPPLANE_TILED; else dspcntr &= ~DISPPLANE_TILED; @@ -12256,7 +12256,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { engine = dev_priv->engine[BCS]; - if (fb->modifier[0] != old_fb->modifier[0]) + if (fb->modifier != old_fb->modifier) /* vlv: DISPLAY_FLIP fails to change tiling */ engine = NULL; } else if (IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv)) { @@ -12412,7 +12412,7 @@ static bool intel_wm_need_update(struct drm_plane *plane, if (!cur->base.fb || !new->base.fb) return false; - if (cur->base.fb->modifier[0] != new->base.fb->modifier[0] || + if (cur->base.fb->modifier != new->base.fb->modifier || cur->base.rotation != new->base.rotation || drm_rect_width(&new->base.src) != drm_rect_width(&cur->base.src) || drm_rect_height(&new->base.src) != drm_rect_height(&cur->base.src) || @@ -15106,7 +15106,7 @@ intel_check_cursor_plane(struct drm_plane *plane, return -ENOMEM; } - if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) { + if (fb->modifier != DRM_FORMAT_MOD_NONE) { DRM_DEBUG_KMS("cursor cannot be tiled\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index e87221bba475..977e39722894 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -633,7 +633,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay; cur_size = intel_fb_align_height(dev, cur_size, fb->base.pixel_format, - fb->base.modifier[0]); + fb->base.modifier); cur_size *= fb->base.pitches[0]; DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n", pipe_name(intel_crtc->pipe), diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cc9e0c0f445f..6f516491a172 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3063,7 +3063,7 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state) latency = dev_priv->wm.skl_latency[level]; if (skl_needs_memory_bw_wa(intel_state) && - plane->base.state->fb->modifier[0] == + plane->base.state->fb->modifier == I915_FORMAT_MOD_X_TILED) latency += 15; @@ -3319,8 +3319,8 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, return 0; /* For Non Y-tile return 8-blocks */ - if (fb->modifier[0] != I915_FORMAT_MOD_Y_TILED && - fb->modifier[0] != I915_FORMAT_MOD_Yf_TILED) + if (fb->modifier != I915_FORMAT_MOD_Y_TILED && + fb->modifier != I915_FORMAT_MOD_Yf_TILED) return 8; src_w = drm_rect_width(&intel_pstate->base.src) >> 16; @@ -3589,7 +3589,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, return 0; } - if (apply_memory_bw_wa && fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (apply_memory_bw_wa && fb->modifier == I915_FORMAT_MOD_X_TILED) latency += 15; width = drm_rect_width(&intel_pstate->base.src) >> 16; @@ -3625,12 +3625,12 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, } plane_bytes_per_line = width * cpp; - if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { + if (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED) { plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line * y_min_scanlines, 512); plane_blocks_per_line /= y_min_scanlines; - } else if (fb->modifier[0] == DRM_FORMAT_MOD_NONE) { + } else if (fb->modifier == DRM_FORMAT_MOD_NONE) { plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512) + 1; } else { @@ -3647,8 +3647,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, if (apply_memory_bw_wa) y_tile_minimum *= 2; - if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { + if (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED) { selected_result = max(method2, y_tile_minimum); } else { if ((cpp * cstate->base.adjusted_mode.crtc_htotal / 512 < 1) && @@ -3664,8 +3664,8 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line); if (level >= 1 && level <= 7) { - if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { + if (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED) { res_blocks += y_tile_minimum; res_lines += y_min_scanlines; } else { diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0e9aac2e3eae..ca02855435d9 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -229,7 +229,7 @@ skl_update_plane(struct drm_plane *drm_plane, PLANE_CTL_PIPE_CSC_ENABLE; plane_ctl |= skl_plane_ctl_format(fb->pixel_format); - plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier); plane_ctl |= skl_plane_ctl_rotation(rotation); @@ -424,7 +424,7 @@ vlv_update_plane(struct drm_plane *dplane, */ sprctl |= SP_GAMMA_ENABLE; - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SP_TILED; /* Sizes are 0 based */ @@ -460,7 +460,7 @@ vlv_update_plane(struct drm_plane *dplane, I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); else I915_WRITE(SPLINOFF(pipe, plane), linear_offset); @@ -543,7 +543,7 @@ ivb_update_plane(struct drm_plane *plane, */ sprctl |= SPRITE_GAMMA_ENABLE; - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) sprctl |= SPRITE_TILED; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) @@ -596,7 +596,7 @@ ivb_update_plane(struct drm_plane *plane, * register */ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) I915_WRITE(SPROFFSET(pipe), (y << 16) | x); - else if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + else if (fb->modifier == I915_FORMAT_MOD_X_TILED) I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); else I915_WRITE(SPRLINOFF(pipe), linear_offset); @@ -681,7 +681,7 @@ ilk_update_plane(struct drm_plane *plane, */ dvscntr |= DVS_GAMMA_ENABLE; - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) dvscntr |= DVS_TILED; if (IS_GEN6(dev_priv)) @@ -723,7 +723,7 @@ ilk_update_plane(struct drm_plane *plane, I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); - if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) + if (fb->modifier == I915_FORMAT_MOD_X_TILED) I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); else I915_WRITE(DVSLINOFF(pipe), linear_offset); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 3903dbcda763..911e4690d36a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -40,7 +40,7 @@ enum mdp4_frame_format mdp4_get_frame_format(struct drm_framebuffer *fb) { bool is_tile = false; - if (fb->modifier[1] == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE) + if (fb->modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE) is_tile = true; if (fb->pixel_format == DRM_FORMAT_NV12 && is_tile) diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index f5ae1f436a4b..b3141a0e609b 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -149,12 +149,12 @@ struct drm_framebuffer { */ unsigned int offsets[4]; /** - * @modifier: Data layout modifier, per buffer. This is used to describe + * @modifier: Data layout modifier. This is used to describe * tiling, or also special layouts (like compression) of auxiliary * buffers. For userspace created object this is copied from * drm_mode_fb_cmd2. */ - uint64_t modifier[4]; + uint64_t modifier; /** * @width: Logical width of the visible area of the framebuffer, in * pixels. diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index ebf622f5b238..728790b92354 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -408,17 +408,20 @@ struct drm_mode_fb_cmd2 { * offsets[1]. Note that offsets[0] will generally * be 0 (but this is not required). * - * To accommodate tiled, compressed, etc formats, a per-plane + * To accommodate tiled, compressed, etc formats, a * modifier can be specified. The default value of zero * indicates "native" format as specified by the fourcc. - * Vendor specific modifier token. This allows, for example, - * different tiling/swizzling pattern on different planes. - * See discussion above of DRM_FORMAT_MOD_xxx. + * Vendor specific modifier token. Note that even though + * it looks like we have a modifier per-plane, we in fact + * do not. The modifier for each plane must be identical. + * Thus all combinations of different data layouts for + * multi plane formats must be enumerated as separate + * modifiers. */ __u32 handles[4]; __u32 pitches[4]; /* pitch for each plane */ __u32 offsets[4]; /* offset of each plane */ - __u64 modifier[4]; /* ie, tiling, compressed (per plane) */ + __u64 modifier[4]; /* ie, tiling, compress */ }; #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 From 27bfa74b9029a4205b16ec8c3a7090287e6e9995 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 17 Nov 2016 12:29:08 +0200 Subject: [PATCH 07/33] drm: also move DSI panels to the front of the connector list We've overlooked adding DSI panels to the front of the connector list. This seems to be the right thing to do, and I suspect this might fix some issues, although I currently have no evidence to support this. v2: also git add the comment change Cc: Daniel Vetter Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479378548-32695-1-git-send-email-jani.nikula@intel.com --- drivers/gpu/drm/drm_modeset_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 633355e02398..cc232ac6c950 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -38,7 +38,7 @@ * Some userspace presumes that the first connected connector is the main * display, where it's supposed to display e.g. the login screen. For * laptops, this should be the main panel. Use this function to sort all - * (eDP/LVDS) panels to the front of the connector list, instead of + * (eDP/LVDS/DSI) panels to the front of the connector list, instead of * painstakingly trying to initialize them in the right order. */ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) @@ -51,7 +51,8 @@ void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || - connector->connector_type == DRM_MODE_CONNECTOR_eDP) + connector->connector_type == DRM_MODE_CONNECTOR_eDP || + connector->connector_type == DRM_MODE_CONNECTOR_DSI) list_move_tail(&connector->head, &panel_list); } From 4ada6f228404921d6ce661edc7a0c84f1ada1a1a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 17 Nov 2016 09:56:48 +0100 Subject: [PATCH 08/33] drm: document standard connector properties There's a really big pile of additional connector properties, a lot of them standardized. But they're all for specific outputs (panels, TV, scaling, ...) so I left them out for now since this is enough for a start. I typed this to give Manasi a place to add her new link status property documentation. v2: forgot to git add all the bits (Manasi). v3: Be more epxlicit about integrated tiled panels (Archit) Cc: Manasi Navare Cc: Archit Taneja Reviewed-by: Archit Taneja Reviewed-by: Manasi Navare Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161117085648.26646-1-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 6 +++++ drivers/gpu/drm/drm_connector.c | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 568f3c2b6e46..f19757b1736a 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -260,6 +260,12 @@ Property Types and Blob Property Support .. kernel-doc:: drivers/gpu/drm/drm_property.c :export: +Standard Connector Properties +----------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_connector.c + :doc: standard connector properties + Plane Composition Properties ---------------------------- diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index b5c6a8ee831e..5a4526289392 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -588,6 +588,50 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, drm_tv_subconnector_enum_list) +/** + * DOC: standard connector properties + * + * DRM connectors have a few standardized properties: + * + * EDID: + * Blob property which contains the current EDID read from the sink. This + * is useful to parse sink identification information like vendor, model + * and serial. Drivers should update this property by calling + * drm_mode_connector_update_edid_property(), usually after having parsed + * the EDID using drm_add_edid_modes(). Userspace cannot change this + * property. + * DPMS: + * Legacy property for setting the power state of the connector. For atomic + * drivers this is only provided for backwards compatibility with existing + * drivers, it remaps to controlling the "ACTIVE" property on the CRTC the + * connector is linked to. Drivers should never set this property directly, + * it is handled by the DRM core by calling the ->dpms() callback in + * &drm_connector_funcs. Atomic drivers should implement this hook using + * drm_atomic_helper_connector_dpms(). This is the only property standard + * connector property that userspace can change. + * PATH: + * Connector path property to identify how this sink is physically + * connected. Used by DP MST. This should be set by calling + * drm_mode_connector_set_path_property(), in the case of DP MST with the + * path property the MST manager created. Userspace cannot change this + * property. + * TILE: + * Connector tile group property to indicate how a set of DRM connector + * compose together into one logical screen. This is used by both high-res + * external screens (often only using a single cable, but exposing multiple + * DP MST sinks), or high-res integrated panels (like dual-link DSI) which + * are not gen-locked. Note that for tiled panels which are genlocked, like + * dual-link LVDS or dual-link DSI, the driver should try to not expose the + * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers + * should update this value using drm_mode_connector_set_tile_property(). + * Userspace cannot change this property. + * + * Connectors also have one standardized atomic property: + * + * CRTC_ID: + * Mode object ID of the &drm_crtc this connector should be connected to. + */ + int drm_connector_create_standard_properties(struct drm_device *dev) { struct drm_property *prop; From 069cad6d02fef7924fb942b37a6c17dd02a79f7f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 18 Nov 2016 17:26:43 +0900 Subject: [PATCH 09/33] Revert "dma-buf/sync-file: Avoid enable fence signaling if poll(.timeout=0)" This reverts commit ecebca79f6976ddaddfd054d699272515869ea28. Do not enable fence callback on poll() when using fence_array causes the fence_array to not signal. For now we will revert the change and enable signaling everytime time poll is called with timeout=0 as well. Cc: Chris Wilson Signed-off-by: Gustavo Padovan Acked-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479457603-30758-1-git-send-email-gustavo@padovan.org --- drivers/dma-buf/sync_file.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 69d8ef98d34c..6d802f2d2881 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -308,8 +308,7 @@ static unsigned int sync_file_poll(struct file *file, poll_table *wait) poll_wait(file, &sync_file->wq, wait); - if (!poll_does_not_wait(wait) && - !test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { + if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) { if (dma_fence_add_callback(sync_file->fence, &sync_file->cb, fence_check_cb_func) < 0) wake_up_all(&sync_file->wq); From a75d68f62106fe66c4b8b96c0ee7155bdafc6f06 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 17 Nov 2016 11:47:58 -0600 Subject: [PATCH 10/33] vgaarb: Use dev_printk() when possible Use dev_printk() when possible. This makes messages more consistent with other device-related messages and, in some cases, adds useful information. This changes messages like this: vgaarb: failed to allocate pci device vgaarb: setting as boot device: PCI:0000:01:00.0 vgaarb: device added: PCI:0000:01:00.0,decodes=io+mem,owns=io+mem,locks=none vgaarb: bridge control possible 0000:01:00.0 to this: pci 0000:01:00.0: vgaarb: failed to allocate VGA arbiter data pci 0000:01:00.0: vgaarb: setting as boot VGA device pci 0000:01:00.0: vgaarb: VGA device added: decodes=io+mem,owns=io+mem,locks=none pci 0000:01:00.0: vgaarb: bridge control possible No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161117174758.16810.67625.stgit@bhelgaas-glaptop.roam.corp.google.com --- drivers/gpu/vga/vgaarb.c | 66 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 77657a8c0cd4..3625ad12c29f 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -31,6 +31,10 @@ #define pr_fmt(fmt) "vgaarb: " fmt +#define vgaarb_dbg(dev, fmt, arg...) dev_dbg(dev, "vgaarb: " fmt, ##arg) +#define vgaarb_info(dev, fmt, arg...) dev_info(dev, "vgaarb: " fmt, ##arg) +#define vgaarb_err(dev, fmt, arg...) dev_err(dev, "vgaarb: " fmt, ##arg) + #include #include #include @@ -188,6 +192,7 @@ static void vga_check_first_use(void) static struct vga_device *__vga_tryget(struct vga_device *vgadev, unsigned int rsrc) { + struct device *dev = &vgadev->pdev->dev; unsigned int wants, legacy_wants, match; struct vga_device *conflict; unsigned int pci_bits; @@ -203,8 +208,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) rsrc |= VGA_RSRC_LEGACY_MEM; - pr_debug("%s: %d\n", __func__, rsrc); - pr_debug("%s: owns: %d\n", __func__, vgadev->owns); + vgaarb_dbg(dev, "%s: %d\n", __func__, rsrc); + vgaarb_dbg(dev, "%s: owns: %d\n", __func__, vgadev->owns); /* Check what resources we need to acquire */ wants = rsrc & ~vgadev->owns; @@ -336,9 +341,10 @@ lock_them: static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) { + struct device *dev = &vgadev->pdev->dev; unsigned int old_locks = vgadev->locks; - pr_debug("%s\n", __func__); + vgaarb_dbg(dev, "%s\n", __func__); /* Update our counters, and account for equivalent legacy resources * if we decode them @@ -611,7 +617,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) /* Allocate structure */ vgadev = kzalloc(sizeof(struct vga_device), GFP_KERNEL); if (vgadev == NULL) { - pr_err("failed to allocate pci device\n"); + vgaarb_err(&pdev->dev, "failed to allocate VGA arbiter data\n"); /* * What to do on allocation failure ? For now, let's just do * nothing, I'm not sure there is anything saner to be done. @@ -663,7 +669,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) */ if (vga_default == NULL && ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK)) { - pr_info("setting as boot device: PCI:%s\n", pci_name(pdev)); + vgaarb_info(&pdev->dev, "setting as boot VGA device\n"); vga_set_default_device(pdev); } @@ -672,8 +678,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) /* Add to the list */ list_add(&vgadev->list, &vga_list); vga_count++; - pr_info("device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n", - pci_name(pdev), + vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n", vga_iostate_to_str(vgadev->decodes), vga_iostate_to_str(vgadev->owns), vga_iostate_to_str(vgadev->locks)); @@ -725,6 +730,7 @@ bail: static inline void vga_update_device_decodes(struct vga_device *vgadev, int new_decodes) { + struct device *dev = &vgadev->pdev->dev; int old_decodes, decodes_removed, decodes_unlocked; old_decodes = vgadev->decodes; @@ -732,8 +738,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev, decodes_unlocked = vgadev->locks & decodes_removed; vgadev->decodes = new_decodes; - pr_info("device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n", - pci_name(vgadev->pdev), + vgaarb_info(dev, "changed VGA decodes: olddecodes=%s,decodes=%s:owns=%s\n", vga_iostate_to_str(old_decodes), vga_iostate_to_str(vgadev->decodes), vga_iostate_to_str(vgadev->owns)); @@ -754,7 +759,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev, if (!(old_decodes & VGA_RSRC_LEGACY_MASK) && new_decodes & VGA_RSRC_LEGACY_MASK) vga_decode_count++; - pr_debug("decoding count now is: %d\n", vga_decode_count); + vgaarb_dbg(dev, "decoding count now is: %d\n", vga_decode_count); } static void __vga_set_legacy_decoding(struct pci_dev *pdev, @@ -1184,24 +1189,25 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, ret_val = -EPROTO; goto done; } - pr_debug("%s ==> %x:%x:%x.%x\n", curr_pos, - domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); - pr_debug("pdev %p\n", pdev); if (!pdev) { - pr_err("invalid PCI address %x:%x:%x\n", - domain, bus, devfn); + pr_err("invalid PCI address %04x:%02x:%02x.%x\n", + domain, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn)); ret_val = -ENODEV; goto done; } + + pr_debug("%s ==> %04x:%02x:%02x.%x pdev %p\n", curr_pos, + domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + pdev); } vgadev = vgadev_find(pdev); pr_debug("vgadev %p\n", vgadev); if (vgadev == NULL) { if (pdev) { - pr_err("this pci device is not a vga device\n"); + vgaarb_err(&pdev->dev, "not a VGA device\n"); pci_dev_put(pdev); } @@ -1221,7 +1227,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, } } if (i == MAX_USER_CARDS) { - pr_err("maximum user cards (%d) number reached!\n", + vgaarb_err(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", MAX_USER_CARDS); pci_dev_put(pdev); /* XXX: which value to return? */ @@ -1310,8 +1316,8 @@ static int vga_arb_release(struct inode *inode, struct file *file) uc = &priv->cards[i]; if (uc->pdev == NULL) continue; - pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n", - uc->io_cnt, uc->mem_cnt); + vgaarb_dbg(&uc->pdev->dev, "uc->io_cnt == %d, uc->mem_cnt == %d\n", + uc->io_cnt, uc->mem_cnt); while (uc->io_cnt--) vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); while (uc->mem_cnt--) @@ -1364,7 +1370,7 @@ static int pci_notify(struct notifier_block *nb, unsigned long action, struct pci_dev *pdev = to_pci_dev(dev); bool notify = false; - pr_debug("%s\n", __func__); + vgaarb_dbg(dev, "%s\n", __func__); /* For now we're only intereted in devices added and removed. I didn't * test this thing here, so someone needs to double check for the @@ -1401,6 +1407,7 @@ static int __init vga_arb_device_init(void) int rc; struct pci_dev *pdev; struct vga_device *vgadev; + struct device *dev; rc = misc_register(&vga_arb_device); if (rc < 0) @@ -1416,8 +1423,6 @@ static int __init vga_arb_device_init(void) PCI_ANY_ID, pdev)) != NULL) vga_arbiter_add_pci_device(pdev); - pr_info("loaded\n"); - list_for_each_entry(vgadev, &vga_list, list) { #if defined(CONFIG_X86) || defined(CONFIG_IA64) /* @@ -1433,6 +1438,7 @@ static int __init vga_arb_device_init(void) int i; limit = screen_info.lfb_base + screen_info.lfb_size; + dev = &vgadev->pdev->dev; /* Does firmware framebuffer belong to us? */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { @@ -1451,21 +1457,19 @@ static int __init vga_arb_device_init(void) continue; if (!vga_default_device()) - pr_info("setting as boot device: PCI:%s\n", - pci_name(vgadev->pdev)); + vgaarb_info(dev, "setting as boot device\n"); else if (vgadev->pdev != vga_default_device()) - pr_info("overriding boot device: PCI:%s\n", - pci_name(vgadev->pdev)); + vgaarb_info(dev, "overriding boot device\n"); vga_set_default_device(vgadev->pdev); } #endif if (vgadev->bridge_has_one_vga) - pr_info("bridge control possible %s\n", - pci_name(vgadev->pdev)); + vgaarb_info(dev, "bridge control possible\n"); else - pr_info("no bridge control possible %s\n", - pci_name(vgadev->pdev)); + vgaarb_info(dev, "no bridge control possible\n"); } + + pr_info("loaded\n"); return rc; } subsys_initcall(vga_arb_device_init); From cf590b8732701778c067ed4dff579fa2d7ac251e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 18 Nov 2016 08:11:58 -0600 Subject: [PATCH 11/33] vgaarb: Downgrade userspace-triggerable messages to debug To avoid userspace-triggerable dmesg spam, downgrade messages in the sysfs write parsing code to debug level. Signed-off-by: Bjorn Helgaas Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161118141158.32415.71438.stgit@bhelgaas-glaptop.roam.corp.google.com --- drivers/gpu/vga/vgaarb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 3625ad12c29f..b3d27182edd9 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1191,9 +1191,9 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, } pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); if (!pdev) { - pr_err("invalid PCI address %04x:%02x:%02x.%x\n", - domain, bus, PCI_SLOT(devfn), - PCI_FUNC(devfn)); + pr_debug("invalid PCI address %04x:%02x:%02x.%x\n", + domain, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn)); ret_val = -ENODEV; goto done; } @@ -1207,7 +1207,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, pr_debug("vgadev %p\n", vgadev); if (vgadev == NULL) { if (pdev) { - vgaarb_err(&pdev->dev, "not a VGA device\n"); + vgaarb_dbg(&pdev->dev, "not a VGA device\n"); pci_dev_put(pdev); } @@ -1227,7 +1227,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, } } if (i == MAX_USER_CARDS) { - vgaarb_err(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", + vgaarb_dbg(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", MAX_USER_CARDS); pci_dev_put(pdev); /* XXX: which value to return? */ From 8c0b55e22aff84cb6938a993d86c3ce02006236e Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Thu, 17 Nov 2016 11:41:29 +0000 Subject: [PATCH 12/33] drm/atomic: cleanup debugfs entries on un-registering the driver. Cleanup the debugfs entries created by commit 6559c901cb48: drm/atomic: add debugfs file to dump out atomic state when the driver's minor gets un-registered. Without it, DRM drivers compiled as modules cannot be rmmod-ed and modprobed again. Tested-by: Brian Starkey Signed-off-by: Liviu Dudau Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/20161117114129.2627-1-Liviu.Dudau@arm.com Fixes: 6559c901cb48 ("drm/atomic: add debugfs file to dump out atomic state") --- drivers/gpu/drm/drm_atomic.c | 7 +++++++ drivers/gpu/drm/drm_debugfs.c | 9 +++++++++ include/drm/drm_atomic.h | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 85466cc67819..ccbffaf14de0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1686,6 +1686,13 @@ int drm_atomic_debugfs_init(struct drm_minor *minor) ARRAY_SIZE(drm_atomic_debugfs_list), minor->debugfs_root, minor); } + +int drm_atomic_debugfs_cleanup(struct drm_minor *minor) +{ + return drm_debugfs_remove_files(drm_atomic_debugfs_list, + ARRAY_SIZE(drm_atomic_debugfs_list), + minor); +} #endif /* diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 206a4fe7ea26..2e3e46a53805 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -228,6 +228,7 @@ EXPORT_SYMBOL(drm_debugfs_remove_files); int drm_debugfs_cleanup(struct drm_minor *minor) { struct drm_device *dev = minor->dev; + int ret; if (!minor->debugfs_root) return 0; @@ -235,6 +236,14 @@ int drm_debugfs_cleanup(struct drm_minor *minor) if (dev->driver->debugfs_cleanup) dev->driver->debugfs_cleanup(minor); + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + ret = drm_atomic_debugfs_cleanup(minor); + if (ret) { + DRM_ERROR("DRM: Failed to remove atomic debugfs entries\n"); + return ret; + } + } + drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES, minor); debugfs_remove(minor->debugfs_root); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index c0eaec70a203..5d5f85db43f0 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -372,6 +372,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); #ifdef CONFIG_DEBUG_FS struct drm_minor; int drm_atomic_debugfs_init(struct drm_minor *minor); +int drm_atomic_debugfs_cleanup(struct drm_minor *minor); #endif #define for_each_connector_in_state(__state, connector, connector_state, __i) \ From 9a83a71ac0d57ceffa32cbbb438ded055ab77887 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 22 Nov 2016 09:11:28 +0900 Subject: [PATCH 13/33] drm/fences: add DOC: for explicit fencing Document IN_FENCE_FD and OUT_FENCE_PTR properties. v2: incorporate comments from Daniel Vetter Signed-off-by: Gustavo Padovan [danvet: s/async/nonblocking/ atomic commits.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479773488-15048-1-git-send-email-gustavo@padovan.org --- Documentation/gpu/drm-kms.rst | 6 ++++ drivers/gpu/drm/drm_atomic.c | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index f19757b1736a..0ef21076012b 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -293,6 +293,12 @@ Tile Group Property .. kernel-doc:: drivers/gpu/drm/drm_connector.c :doc: Tile group +Explicit Fencing Properties +--------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_atomic.c + :doc: explicit fencing properties + Existing KMS Properties ----------------------- diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index ccbffaf14de0..89737e42fa83 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1816,6 +1816,58 @@ void drm_atomic_clean_old_fb(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_clean_old_fb); +/** + * DOC: explicit fencing properties + * + * Explicit fencing allows userspace to control the buffer synchronization + * between devices. A Fence or a group of fences are transfered to/from + * userspace using Sync File fds and there are two DRM properties for that. + * IN_FENCE_FD on each DRM Plane to send fences to the kernel and + * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel. + * + * As a contrast, with implicit fencing the kernel keeps track of any + * ongoing rendering, and automatically ensures that the atomic update waits + * for any pending rendering to complete. For shared buffers represented with + * a struct &dma_buf this is tracked in &reservation_object structures. + * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), + * whereas explicit fencing is what Android wants. + * + * "IN_FENCE_FD”: + * Use this property to pass a fence that DRM should wait on before + * proceeding with the Atomic Commit request and show the framebuffer for + * the plane on the screen. The fence can be either a normal fence or a + * merged one, the sync_file framework will handle both cases and use a + * fence_array if a merged fence is received. Passing -1 here means no + * fences to wait on. + * + * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag + * it will only check if the Sync File is a valid one. + * + * On the driver side the fence is stored on the @fence parameter of + * struct &drm_plane_state. Drivers which also support implicit fencing + * should set the implicit fence using drm_atomic_set_fence_for_plane(), + * to make sure there's consistent behaviour between drivers in precedence + * of implicit vs. explicit fencing. + * + * "OUT_FENCE_PTR”: + * Use this property to pass a file descriptor pointer to DRM. Once the + * Atomic Commit request call returns OUT_FENCE_PTR will be filled with + * the file descriptor number of a Sync File. This Sync File contains the + * CRTC fence that will be signaled when all framebuffers present on the + * Atomic Commit * request for that given CRTC are scanned out on the + * screen. + * + * The Atomic Commit request fails if a invalid pointer is passed. If the + * Atomic Commit request fails for any other reason the out fence fd + * returned will be -1. On a Atomic Commit with the + * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1. + * + * Note that out-fences don't have a special interface to drivers and are + * internally represented by a struct &drm_pending_vblank_event in struct + * &drm_crtc_state, which is also used by the nonblocking atomic commit + * helpers and for the DRM event handling for existing userspace. + */ + static struct dma_fence *get_crtc_fence(struct drm_crtc *crtc) { struct dma_fence *fence; From 1ea0c02e7018fdefbfc4333c733ce27c2bb70eff Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 21 Nov 2016 18:18:02 +0100 Subject: [PATCH 14/33] drm/atomic: Unconfuse the old_state mess in commmit_tail I totally butcherd the job on typing the kernel-doc for these, and no one realized. Noticed by Russell. Maarten has a more complete approach to this confusion, by making it more explicit what the new/old state is, instead of this magic switching behaviour. v2: - Liviu pointed out that wait_for_fences is even more magic. Leave that as @state, and document @pre_swap better. - While at it, patch in header for the reference section. - Fix spelling issues Russell noticed. v3: Fix up the @pre_swap note (Liviu): Also s/synchronous/blocking/, since async flip is something else than non-blocking. Cc: Liviu Dudau Reported-by: Russell King - ARM Linux Cc: Russell King - ARM Linux Fixes: 9f2a7950e77a ("drm/atomic-helper: nonblocking commit support") Cc: Gustavo Padovan Cc: Maarten Lankhorst Cc: Tomeu Vizoso Cc: Daniel Stone Reviewed-by: Liviu Dudau Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161121171802.24147-1-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 3 + drivers/gpu/drm/drm_atomic_helper.c | 78 +++++++++++++----------- include/drm/drm_modeset_helper_vtables.h | 12 ++-- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 4ca77f675967..03040aa14fe8 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -63,6 +63,9 @@ Atomic State Reset and Initialization .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c :doc: atomic state reset and initialization +Helper Functions Reference +-------------------------- + .. kernel-doc:: include/drm/drm_atomic_helper.h :internal: diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0b16587cdc62..494680c9056e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1006,13 +1006,21 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state * @dev: DRM device * @state: atomic state object with old state structures - * @pre_swap: if true, do an interruptible wait + * @pre_swap: If true, do an interruptible wait, and @state is the new state. + * Otherwise @state is the old state. * * For implicit sync, driver should fish the exclusive fence out from the * incoming fb's and stash it in the drm_plane_state. This is called after * drm_atomic_helper_swap_state() so it uses the current plane state (and * just uses the atomic state to find the changed planes) * + * Note that @pre_swap is needed since the point where we block for fences moves + * around depending upon whether an atomic commit is blocking or + * non-blocking. For async commit all waiting needs to happen after + * drm_atomic_helper_swap_state() is called, but for synchronous commits we want + * to wait **before** we do anything that can't be easily rolled back. That is + * before we call drm_atomic_helper_swap_state(). + * * Returns zero if success or < 0 if dma_fence_wait() fails. */ int drm_atomic_helper_wait_for_fences(struct drm_device *dev, @@ -1147,7 +1155,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); /** * drm_atomic_helper_commit_tail - commit atomic update to hardware - * @state: new modeset state to be committed + * @old_state: atomic state object with old state structures * * This is the default implemenation for the ->atomic_commit_tail() hook of the * &drm_mode_config_helper_funcs vtable. @@ -1158,53 +1166,53 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * * For drivers supporting runtime PM the recommended sequence is instead :: * - * drm_atomic_helper_commit_modeset_disables(dev, state); + * drm_atomic_helper_commit_modeset_disables(dev, old_state); * - * drm_atomic_helper_commit_modeset_enables(dev, state); + * drm_atomic_helper_commit_modeset_enables(dev, old_state); * - * drm_atomic_helper_commit_planes(dev, state, + * drm_atomic_helper_commit_planes(dev, old_state, * DRM_PLANE_COMMIT_ACTIVE_ONLY); * * for committing the atomic update to hardware. See the kerneldoc entries for * these three functions for more details. */ -void drm_atomic_helper_commit_tail(struct drm_atomic_state *state) +void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; + struct drm_device *dev = old_state->dev; - drm_atomic_helper_commit_modeset_disables(dev, state); + drm_atomic_helper_commit_modeset_disables(dev, old_state); - drm_atomic_helper_commit_planes(dev, state, 0); + drm_atomic_helper_commit_planes(dev, old_state, 0); - drm_atomic_helper_commit_modeset_enables(dev, state); + drm_atomic_helper_commit_modeset_enables(dev, old_state); - drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_commit_hw_done(old_state); - drm_atomic_helper_wait_for_vblanks(dev, state); + drm_atomic_helper_wait_for_vblanks(dev, old_state); - drm_atomic_helper_cleanup_planes(dev, state); + drm_atomic_helper_cleanup_planes(dev, old_state); } EXPORT_SYMBOL(drm_atomic_helper_commit_tail); -static void commit_tail(struct drm_atomic_state *state) +static void commit_tail(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; + struct drm_device *dev = old_state->dev; struct drm_mode_config_helper_funcs *funcs; funcs = dev->mode_config.helper_private; - drm_atomic_helper_wait_for_fences(dev, state, false); + drm_atomic_helper_wait_for_fences(dev, old_state, false); - drm_atomic_helper_wait_for_dependencies(state); + drm_atomic_helper_wait_for_dependencies(old_state); if (funcs && funcs->atomic_commit_tail) - funcs->atomic_commit_tail(state); + funcs->atomic_commit_tail(old_state); else - drm_atomic_helper_commit_tail(state); + drm_atomic_helper_commit_tail(old_state); - drm_atomic_helper_commit_cleanup_done(state); + drm_atomic_helper_commit_cleanup_done(old_state); - drm_atomic_state_put(state); + drm_atomic_state_put(old_state); } static void commit_work(struct work_struct *work) @@ -1498,10 +1506,10 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) /** * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits - * @state: new modeset state to be committed + * @old_state: atomic state object with old state structures * * This function waits for all preceeding commits that touch the same CRTC as - * @state to both be committed to the hardware (as signalled by + * @old_state to both be committed to the hardware (as signalled by * drm_atomic_helper_commit_hw_done) and executed by the hardware (as signalled * by calling drm_crtc_vblank_send_event on the event member of * &drm_crtc_state). @@ -1509,7 +1517,7 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc) * This is part of the atomic helper support for nonblocking commits, see * drm_atomic_helper_setup_commit() for an overview. */ -void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state) +void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -1517,7 +1525,7 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state) int i; long ret; - for_each_crtc_in_state(state, crtc, crtc_state, i) { + for_each_crtc_in_state(old_state, crtc, crtc_state, i) { spin_lock(&crtc->commit_lock); commit = preceeding_commit(crtc); if (commit) @@ -1548,7 +1556,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); /** * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit - * @state: new modeset state to be committed + * @old_state: atomic state object with old state structures * * This function is used to signal completion of the hardware commit step. After * this step the driver is not allowed to read or change any permanent software @@ -1561,15 +1569,15 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); * This is part of the atomic helper support for nonblocking commits, see * drm_atomic_helper_setup_commit() for an overview. */ -void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state) +void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_crtc_commit *commit; int i; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - commit = state->crtcs[i].commit; + for_each_crtc_in_state(old_state, crtc, crtc_state, i) { + commit = old_state->crtcs[i].commit; if (!commit) continue; @@ -1584,16 +1592,16 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); /** * drm_atomic_helper_commit_cleanup_done - signal completion of commit - * @state: new modeset state to be committed + * @old_state: atomic state object with old state structures * - * This signals completion of the atomic update @state, including any cleanup - * work. If used, it must be called right before calling + * This signals completion of the atomic update @old_state, including any + * cleanup work. If used, it must be called right before calling * drm_atomic_state_put(). * * This is part of the atomic helper support for nonblocking commits, see * drm_atomic_helper_setup_commit() for an overview. */ -void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state) +void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -1601,8 +1609,8 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state) int i; long ret; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - commit = state->crtcs[i].commit; + for_each_crtc_in_state(old_state, crtc, crtc_state, i) { + commit = old_state->crtcs[i].commit; if (WARN_ON(!commit)) continue; diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 72478cf82147..69c3974bf133 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -999,10 +999,14 @@ struct drm_mode_config_helper_funcs { * to implement blocking and nonblocking commits easily. It is not used * by the atomic helpers * - * This hook should first commit the given atomic state to the hardware. - * But drivers can add more waiting calls at the start of their - * implementation, e.g. to wait for driver-internal request for implicit - * syncing, before starting to commit the update to the hardware. + * This function is called when the new atomic state has already been + * swapped into the various state pointers. The passed in state + * therefore contains copies of the old/previous state. This hook should + * commit the new state into hardware. Note that the helpers have + * already waited for preceeding atomic commits and fences, but drivers + * can add more waiting calls at the start of their implementation, e.g. + * to wait for driver-internal request for implicit syncing, before + * starting to commit the update to the hardware. * * After the atomic update is committed to the hardware this hook needs * to call drm_atomic_helper_commit_hw_done(). Then wait for the upate From ed2ab35ef1a1f7d42b5dc0d130d359cc0f5e3d9d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 22 Nov 2016 15:34:19 +0100 Subject: [PATCH 15/33] vgaarb: use valid dev pointer in vgaarb_info() We now pass the device to the debug messages, but on non-x86, this is an invalid pointer in vga_arb_device_init: drivers/gpu/vga/vgaarb.c: In function 'vga_arb_device_init': drivers/gpu/vga/vgaarb.c:1467:4: error: 'dev' may be used uninitialized in this function [-Werror=maybe-uninitialized] This moves the initialization of the dev pointer outside of the architecture #ifdef. Fixes: a75d68f62106 ("vgaarb: Use dev_printk() when possible") Signed-off-by: Arnd Bergmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161122143445.1896558-1-arnd@arndb.de --- drivers/gpu/vga/vgaarb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index b3d27182edd9..0f5b2dd24507 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1407,7 +1407,6 @@ static int __init vga_arb_device_init(void) int rc; struct pci_dev *pdev; struct vga_device *vgadev; - struct device *dev; rc = misc_register(&vga_arb_device); if (rc < 0) @@ -1424,6 +1423,7 @@ static int __init vga_arb_device_init(void) vga_arbiter_add_pci_device(pdev); list_for_each_entry(vgadev, &vga_list, list) { + struct device *dev = &vgadev->pdev->dev; #if defined(CONFIG_X86) || defined(CONFIG_IA64) /* * Override vga_arbiter_add_pci_device()'s I/O based detection @@ -1438,7 +1438,6 @@ static int __init vga_arb_device_init(void) int i; limit = screen_info.lfb_base + screen_info.lfb_size; - dev = &vgadev->pdev->dev; /* Does firmware framebuffer belong to us? */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { From b7a2a2306a019ae87e2c4d92cc6821185a4ab105 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 23 Nov 2016 15:31:32 +0100 Subject: [PATCH 16/33] MAINTAINERS: Add link to drm-misc documentation Cc: Jani Nikula Cc: Sean Paul Acked-by: Jani Nikula Acked-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161123143132.29006-1-daniel.vetter@ffwll.ch --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 61979cf461e7..3862af19b9a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4026,6 +4026,7 @@ DRM DRIVERS AND MISC GPU PATCHES M: Daniel Vetter M: Jani Nikula M: Sean Paul +W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/gpu/ From 6a8a66eda17ea6b4970f0c4724958eeababc6ae8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 23 Nov 2016 20:23:27 +0100 Subject: [PATCH 17/33] drm/doc: Fix links in drm_property.c One of the functions was missing () to make the autolinks work, unfortunately copy-pasted a few times all over. Cc: Manasi Navare Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161123192327.28819-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_property.c | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index a4d81cf4ffa0..d1e50ac6f72b 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -65,9 +65,9 @@ static bool drm_property_type_valid(struct drm_property *property) * @num_values: number of pre-defined values * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Returns: * A pointer to the newly created property on success, NULL on failure. @@ -125,9 +125,9 @@ EXPORT_SYMBOL(drm_property_create); * @num_values: number of pre-defined values * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Userspace is only allowed to set one of the predefined values for enumeration * properties. @@ -173,9 +173,9 @@ EXPORT_SYMBOL(drm_property_create_enum); * @supported_bits: bitmask of all supported enumeration values * * This creates a new bitmask drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Compared to plain enumeration properties userspace is allowed to set any * or'ed together combination of the predefined property bitflag values @@ -245,9 +245,9 @@ static struct drm_property *property_create_range(struct drm_device *dev, * @max: maximum value of the property * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Userspace is allowed to set any unsigned integer value in the (min, max) * range inclusive. @@ -273,9 +273,9 @@ EXPORT_SYMBOL(drm_property_create_range); * @max: maximum value of the property * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Userspace is allowed to set any signed integer value in the (min, max) * range inclusive. @@ -300,9 +300,9 @@ EXPORT_SYMBOL(drm_property_create_signed_range); * @type: object type from DRM_MODE_OBJECT_* defines * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * Userspace is only allowed to set this to any property value of the given * @type. Only useful for atomic properties, which is enforced. @@ -338,9 +338,9 @@ EXPORT_SYMBOL(drm_property_create_object); * @name: name of the property * * This creates a new generic drm property which can then be attached to a drm - * object with drm_object_attach_property. The returned property object must be - * freed with drm_property_destroy(), which is done automatically when calling - * drm_mode_config_cleanup(). + * object with drm_object_attach_property(). The returned property object must + * be freed with drm_property_destroy(), which is done automatically when + * calling drm_mode_config_cleanup(). * * This is implemented as a ranged property with only {0, 1} as valid values. * From 522e85dd8677e9cca40c3ae773f171e6a9eece31 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Nov 2016 14:11:14 +0000 Subject: [PATCH 18/33] drm: Define drm_mm_for_each_node_in_range() Some clients would like to iterate over every node within a certain range. Make a nice little macro for them to hide the mixing of the rbtree search and linear walk. v2: Blurb Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161123141118.23876-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 11 ++--------- include/drm/drm_mm.h | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 632473beb40c..f8eebbde376e 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -174,19 +174,12 @@ INTERVAL_TREE_DEFINE(struct drm_mm_node, rb, START, LAST, static inline, drm_mm_interval_tree) struct drm_mm_node * -drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last) +__drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last) { return drm_mm_interval_tree_iter_first(&mm->interval_tree, start, last); } -EXPORT_SYMBOL(drm_mm_interval_first); - -struct drm_mm_node * -drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last) -{ - return drm_mm_interval_tree_iter_next(node, start, last); -} -EXPORT_SYMBOL(drm_mm_interval_next); +EXPORT_SYMBOL(__drm_mm_interval_first); static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, struct drm_mm_node *node) diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 41ddafe92b2f..6add455c651b 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -308,10 +308,26 @@ void drm_mm_takedown(struct drm_mm *mm); bool drm_mm_clean(struct drm_mm *mm); struct drm_mm_node * -drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last); +__drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last); -struct drm_mm_node * -drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last); +/** + * drm_mm_for_each_node_in_range - iterator to walk over a range of + * allocated nodes + * @node: drm_mm_node structure to assign to in each iteration step + * @mm: drm_mm allocator to walk + * @start: starting offset, the first node will overlap this + * @end: ending offset, the last node will start before this (but may overlap) + * + * This iterator walks over all nodes in the range allocator that lie + * between @start and @end. It is implemented similarly to list_for_each(), + * but using the internal interval tree to accelerate the search for the + * starting node, and so not safe against removal of elements. It assumes + * that @end is within (or is the upper limit of) the drm_mm allocator. + */ +#define drm_mm_for_each_node_in_range(node, mm, start, end) \ + for (node = __drm_mm_interval_first((mm), (start), (end)-1); \ + node && node->start < (end); \ + node = list_next_entry(node, node_list)) \ void drm_mm_init_scan(struct drm_mm *mm, u64 size, From 2db86dfcefbb7f6d7586dbd16a0b2819a2aad149 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Nov 2016 14:11:15 +0000 Subject: [PATCH 19/33] drm: Check against color expansion in drm_mm_reserve_node() Use the color_adjust callback when reserving a node to check if inserting a node into this hole requires any additional space, and so if that space then conflicts with an existing allocation. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161123141118.23876-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index f8eebbde376e..025dcd8cadcb 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -306,6 +306,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) u64 end = node->start + node->size; struct drm_mm_node *hole; u64 hole_start, hole_end; + u64 adj_start, adj_end; if (WARN_ON(node->size == 0)) return -EINVAL; @@ -327,9 +328,13 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) if (!hole->hole_follows) return -ENOSPC; - hole_start = __drm_mm_hole_node_start(hole); - hole_end = __drm_mm_hole_node_end(hole); - if (hole_start > node->start || hole_end < end) + adj_start = hole_start = __drm_mm_hole_node_start(hole); + adj_end = hole_end = __drm_mm_hole_node_end(hole); + + if (mm->color_adjust) + mm->color_adjust(hole, node->color, &adj_start, &adj_end); + + if (adj_start > node->start || adj_end < end) return -ENOSPC; node->mm = mm; From 2761ba6c0925ca9c5b917a95f68135d9dce443fb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2016 01:00:57 +0000 Subject: [PATCH 20/33] drm: bridge: add DesignWare HDMI I2S audio support Current dw-hdmi is supporting sound via AHB bus, but it has I2S audio feature too. This patch adds I2S audio support to dw-hdmi. This HDMI I2S is supported by using ALSA SoC common HDMI encoder driver. Tested-by: Jose Abreu Acked-by: Russell King Signed-off-by: Kuninori Morimoto Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/8737j2bxba.wl%kuninori.morimoto.gx@renesas.com --- drivers/gpu/drm/bridge/Kconfig | 8 ++ drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/dw-hdmi-audio.h | 7 + drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 141 +++++++++++++++++++++ drivers/gpu/drm/bridge/dw-hdmi.c | 22 +++- drivers/gpu/drm/bridge/dw-hdmi.h | 20 +++ 6 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index bd6acc829f97..8bce72f7562d 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -39,6 +39,14 @@ config DRM_DW_HDMI_AHB_AUDIO Designware HDMI block. This is used in conjunction with the i.MX6 HDMI driver. +config DRM_DW_HDMI_I2S_AUDIO + tristate "Synopsis Designware I2S Audio interface" + depends on DRM_DW_HDMI + select SND_SOC_HDMI_CODEC + help + Support the I2S Audio interface which is part of the Synopsis + Designware HDMI block. + config DRM_NXP_PTN3460 tristate "NXP PTN3460 DP/LVDS bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 97ed1a5fea9a..1439ad84ccb7 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o +obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o diff --git a/drivers/gpu/drm/bridge/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h index 91f631beecc7..fd1f745c6073 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h +++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h @@ -11,4 +11,11 @@ struct dw_hdmi_audio_data { u8 *eld; }; +struct dw_hdmi_i2s_audio_data { + struct dw_hdmi *hdmi; + + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); + u8 (*read)(struct dw_hdmi *hdmi, int offset); +}; + #endif diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c new file mode 100644 index 000000000000..aaf287d2e91d --- /dev/null +++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c @@ -0,0 +1,141 @@ +/* + * dw-hdmi-i2s-audio.c + * + * Copyright (c) 2016 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include + +#include "dw-hdmi.h" +#include "dw-hdmi-audio.h" + +#define DRIVER_NAME "dw-hdmi-i2s-audio" + +static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio, + u8 val, int offset) +{ + struct dw_hdmi *hdmi = audio->hdmi; + + audio->write(hdmi, val, offset); +} + +static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset) +{ + struct dw_hdmi *hdmi = audio->hdmi; + + return audio->read(hdmi, offset); +} + +static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + struct dw_hdmi *hdmi = audio->hdmi; + u8 conf0 = 0; + u8 conf1 = 0; + u8 inputclkfs = 0; + + /* it cares I2S only */ + if ((fmt->fmt != HDMI_I2S) || + (fmt->bit_clk_master | fmt->frame_clk_master)) { + dev_err(dev, "unsupported format/settings\n"); + return -EINVAL; + } + + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; + conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; + + switch (hparms->sample_width) { + case 16: + conf1 = HDMI_AUD_CONF1_WIDTH_16; + break; + case 24: + case 32: + conf1 = HDMI_AUD_CONF1_WIDTH_24; + break; + } + + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); + hdmi_write(audio, conf0, HDMI_AUD_CONF0); + hdmi_write(audio, conf1, HDMI_AUD_CONF1); + + dw_hdmi_audio_enable(hdmi); + + return 0; +} + +static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + struct dw_hdmi *hdmi = audio->hdmi; + + dw_hdmi_audio_disable(hdmi); + + hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); +} + +static struct hdmi_codec_ops dw_hdmi_i2s_ops = { + .hw_params = dw_hdmi_i2s_hw_params, + .audio_shutdown = dw_hdmi_i2s_audio_shutdown, +}; + +static int snd_dw_hdmi_probe(struct platform_device *pdev) +{ + struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data; + struct platform_device_info pdevinfo; + struct hdmi_codec_pdata pdata; + struct platform_device *platform; + + pdata.ops = &dw_hdmi_i2s_ops; + pdata.i2s = 1; + pdata.max_i2s_channels = 6; + pdata.data = audio; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.parent = pdev->dev.parent; + pdevinfo.id = PLATFORM_DEVID_AUTO; + pdevinfo.name = HDMI_CODEC_DRV_NAME; + pdevinfo.data = &pdata; + pdevinfo.size_data = sizeof(pdata); + pdevinfo.dma_mask = DMA_BIT_MASK(32); + + platform = platform_device_register_full(&pdevinfo); + if (IS_ERR(platform)) + return PTR_ERR(platform); + + dev_set_drvdata(&pdev->dev, platform); + + return 0; +} + +static int snd_dw_hdmi_remove(struct platform_device *pdev) +{ + struct platform_device *platform = dev_get_drvdata(&pdev->dev); + + platform_device_unregister(platform); + + return 0; +} + +static struct platform_driver snd_dw_hdmi_driver = { + .probe = snd_dw_hdmi_probe, + .remove = snd_dw_hdmi_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(snd_dw_hdmi_driver); + +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index b71088dab268..235ce7d1583d 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1871,10 +1871,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master, struct device_node *np = dev->of_node; struct platform_device_info pdevinfo; struct device_node *ddc_node; - struct dw_hdmi_audio_data audio; struct dw_hdmi *hdmi; int ret; u32 val = 1; + u8 config0; + u8 config1; hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) @@ -2011,7 +2012,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master, pdevinfo.parent = dev; pdevinfo.id = PLATFORM_DEVID_AUTO; - if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) { + config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID); + config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID); + + if (config1 & HDMI_CONFIG1_AHB) { + struct dw_hdmi_audio_data audio; + audio.phys = iores->start; audio.base = hdmi->regs; audio.irq = irq; @@ -2023,6 +2029,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master, pdevinfo.size_data = sizeof(audio); pdevinfo.dma_mask = DMA_BIT_MASK(32); hdmi->audio = platform_device_register_full(&pdevinfo); + } else if (config0 & HDMI_CONFIG0_I2S) { + struct dw_hdmi_i2s_audio_data audio; + + audio.hdmi = hdmi; + audio.write = hdmi_writeb; + audio.read = hdmi_readb; + + pdevinfo.name = "dw-hdmi-i2s-audio"; + pdevinfo.data = &audio; + pdevinfo.size_data = sizeof(audio); + pdevinfo.dma_mask = DMA_BIT_MASK(32); + hdmi->audio = platform_device_register_full(&pdevinfo); } /* Reset HDMI DDC I2C master controller and mute I2CM interrupts */ diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 6aadc840e888..55135bbd0c16 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -545,6 +545,9 @@ #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 enum { +/* CONFIG0_ID field values */ + HDMI_CONFIG0_I2S = 0x10, + /* CONFIG1_ID field values */ HDMI_CONFIG1_AHB = 0x01, @@ -891,6 +894,17 @@ enum { HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08, HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04, +/* AUD_CONF0 field values */ + HDMI_AUD_CONF0_SW_RESET = 0x80, + HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F, + +/* AUD_CONF1 field values */ + HDMI_AUD_CONF1_MODE_I2S = 0x00, + HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02, + HDMI_AUD_CONF1_MODE_LEFT_J = 0x04, + HDMI_AUD_CONF1_WIDTH_16 = 0x10, + HDMI_AUD_CONF1_WIDTH_24 = 0x18, + /* AUD_CTS3 field values */ HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5, HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0, @@ -905,6 +919,12 @@ enum { HDMI_AUD_CTS3_CTS_MANUAL = 0x10, HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f, +/* HDMI_AUD_INPUTCLKFS field values */ + HDMI_AUD_INPUTCLKFS_128FS = 0, + HDMI_AUD_INPUTCLKFS_256FS = 1, + HDMI_AUD_INPUTCLKFS_512FS = 2, + HDMI_AUD_INPUTCLKFS_64FS = 4, + /* AHB_DMA_CONF0 field values */ HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7, HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80, From 0a4c9ffbd47669d1a0534dbbd45c2855531a6e7d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Nov 2016 14:35:45 +0300 Subject: [PATCH 21/33] drm/hisilicon/hibmc: Checking for NULL instead of IS_ERR() The drm_dev_alloc() function returns error pointers. It never returns NULLs. Fixes: 5e0df3a08f3d ("drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver") Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161124113545.GP17225@mwanda --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 73ba8b05f1da..d94e3495c9b2 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -377,9 +377,9 @@ static int hibmc_pci_probe(struct pci_dev *pdev, int ret; dev = drm_dev_alloc(&hibmc_driver, &pdev->dev); - if (!dev) { + if (IS_ERR(dev)) { DRM_ERROR("failed to allocate drm_device\n"); - return -ENOMEM; + return PTR_ERR(dev); } dev->pdev = pdev; From b61abd49c5dd07d3b97b638128982c3feef99a93 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 24 Nov 2016 17:30:26 +0100 Subject: [PATCH 22/33] drm/hisilicon/hibmc: mark PM functions __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM_SLEEP is disabled, we get a harmless warning drm/hisilicon/hibmc/hibmc_drm_drv.c:115:12: error: ‘hibmc_pm_resume’ defined but not used [-Werror=unused-function] drm/hisilicon/hibmc/hibmc_drm_drv.c:97:12: error: ‘hibmc_pm_suspend’ defined but not used [-Werror=unused-function] Marking the functions as __maybe_unused avoids the warning without having to add an #ifdef. Fixes: 5e0df3a08f3d ("drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver") Signed-off-by: Arnd Bergmann Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161124163107.3914495-1-arnd@arndb.de --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index d94e3495c9b2..7e2043f4348c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -94,7 +94,7 @@ static struct drm_driver hibmc_driver = { .irq_handler = hibmc_drm_interrupt, }; -static int hibmc_pm_suspend(struct device *dev) +static int __maybe_unused hibmc_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); @@ -112,7 +112,7 @@ static int hibmc_pm_suspend(struct device *dev) return 0; } -static int hibmc_pm_resume(struct device *dev) +static int __maybe_unused hibmc_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); From 218adc17b0d362331f2df37304ba467881241d80 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 25 Nov 2016 12:34:27 +0000 Subject: [PATCH 23/33] drm: Fixup kernel doc for driver->gem_create_object Silences ./include/drm/drm_drv.h:295: warning: Incorrect use of kernel-doc format Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161125123427.15188-1-chris@chris-wilson.co.uk --- include/drm/drm_drv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index aad8bbacd1f0..52bf44e2b5cc 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -291,6 +291,8 @@ struct drm_driver { void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); /** + * @gem_create_object: constructor for gem objects + * * Hook for allocating the GEM object struct, for use by core * helpers. */ From 8b2fb7b6518d143b382c3490d4a90f8676259ef9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 27 Nov 2016 11:16:23 +0000 Subject: [PATCH 24/33] drm: Fix conflicting macro parameter in drm_mm_for_each_node_in_range() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit start is being used as both a macro parameter and as a member of struct drm_mm_node (node->start). This causes a conflict as cpp then tries to replace node->start with the passed in string for "start". Work just fine so long as you also happened to using local variables called start! Fixes: 522e85dd8677 ("drm: Define drm_mm_for_each_node_in_range()") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Christian König . [danvet: Fixup kerneldoc.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161127111623.11124-1-chris@chris-wilson.co.uk --- include/drm/drm_mm.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 6add455c651b..0b8371795aeb 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -313,10 +313,10 @@ __drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last); /** * drm_mm_for_each_node_in_range - iterator to walk over a range of * allocated nodes - * @node: drm_mm_node structure to assign to in each iteration step - * @mm: drm_mm allocator to walk - * @start: starting offset, the first node will overlap this - * @end: ending offset, the last node will start before this (but may overlap) + * @node__: drm_mm_node structure to assign to in each iteration step + * @mm__: drm_mm allocator to walk + * @start__: starting offset, the first node will overlap this + * @end__: ending offset, the last node will start before this (but may overlap) * * This iterator walks over all nodes in the range allocator that lie * between @start and @end. It is implemented similarly to list_for_each(), @@ -324,10 +324,10 @@ __drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last); * starting node, and so not safe against removal of elements. It assumes * that @end is within (or is the upper limit of) the drm_mm allocator. */ -#define drm_mm_for_each_node_in_range(node, mm, start, end) \ - for (node = __drm_mm_interval_first((mm), (start), (end)-1); \ - node && node->start < (end); \ - node = list_next_entry(node, node_list)) \ +#define drm_mm_for_each_node_in_range(node__, mm__, start__, end__) \ + for (node__ = __drm_mm_interval_first((mm__), (start__), (end__)-1); \ + node__ && node__->start < (end__); \ + node__ = list_next_entry(node__, node_list)) void drm_mm_init_scan(struct drm_mm *mm, u64 size, From 75df62478c84e101e0c4141e4e6c3ed10163de1f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 27 Nov 2016 17:09:08 +0000 Subject: [PATCH 25/33] drm: Use u64_to_user_ptr() helper for blob ioctls Remove the ugly sparse casts by using the helper u64_to_user_ptr() instead. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161127170910.29106-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_property.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index d1e50ac6f72b..24be69d29964 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -729,7 +729,6 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, struct drm_mode_get_blob *out_resp = data; struct drm_property_blob *blob; int ret = 0; - void __user *blob_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -739,8 +738,9 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, return -ENOENT; if (out_resp->length == blob->length) { - blob_ptr = (void __user *)(unsigned long)out_resp->data; - if (copy_to_user(blob_ptr, blob->data, blob->length)) { + if (copy_to_user(u64_to_user_ptr(out_resp->data), + blob->data, + blob->length)) { ret = -EFAULT; goto unref; } @@ -757,7 +757,6 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, { struct drm_mode_create_blob *out_resp = data; struct drm_property_blob *blob; - void __user *blob_ptr; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -767,8 +766,9 @@ int drm_mode_createblob_ioctl(struct drm_device *dev, if (IS_ERR(blob)) return PTR_ERR(blob); - blob_ptr = (void __user *)(unsigned long)out_resp->data; - if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { + if (copy_from_user(blob->data, + u64_to_user_ptr(out_resp->data), + out_resp->length)) { ret = -EFAULT; goto out_blob; } From a2ec1c132a593ac4f05eb8d02834c4675a4aea07 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 27 Nov 2016 17:09:09 +0000 Subject: [PATCH 26/33] drm: Avoid NULL dereference for DRM_LEGACY debug message smatch warns: drivers/gpu/drm/drm_lock.c:188 drm_legacy_lock() warn: variable dereferenced before check 'master->lock.hw_lock' (see line 177) Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161127170910.29106-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_lock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index c901f3c5b269..32d43f86a8f2 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -176,7 +176,8 @@ int drm_legacy_lock(struct drm_device *dev, void *data, DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", lock->context, task_pid_nr(current), - master->lock.hw_lock->lock, lock->flags); + master->lock.hw_lock ? master->lock.hw_lock->lock : -1, + lock->flags); add_wait_queue(&master->lock.lock_queue, &entry); spin_lock_bh(&master->lock.spinlock); From c96521eebc24d49eb109013dcdae08c0c37e4f1e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 27 Nov 2016 17:09:10 +0000 Subject: [PATCH 27/33] drm: Fix shift operations for drm_fb_helper::drm_target_preferred() smatch correctly warns: drivers/gpu/drm/drm_fb_helper.c:1960 drm_target_preferred() warn: should '1 << i' be a 64 bit type? drivers/gpu/drm/drm_fb_helper.c:2001 drm_target_preferred() warn: should '1 << i' be a 64 bit type? Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 14547817566d..1f26634f53d8 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1959,19 +1959,20 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, bool *enabled, int width, int height) { struct drm_fb_helper_connector *fb_helper_conn; - int i; - uint64_t conn_configured = 0, mask; + const u64 mask = BIT_ULL(fb_helper->connector_count) - 1; + u64 conn_configured = 0; int tile_pass = 0; - mask = (1 << fb_helper->connector_count) - 1; + int i; + retry: for (i = 0; i < fb_helper->connector_count; i++) { fb_helper_conn = fb_helper->connector_info[i]; - if (conn_configured & (1 << i)) + if (conn_configured & BIT_ULL(i)) continue; if (enabled[i] == false) { - conn_configured |= (1 << i); + conn_configured |= BIT_ULL(i); continue; } @@ -2012,7 +2013,7 @@ retry: } DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : "none"); - conn_configured |= (1 << i); + conn_configured |= BIT_ULL(i); } if ((conn_configured & mask) != mask) { From 63926ba85fdf943da8e08553acae98be3056fef9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 25 Nov 2016 21:53:11 +0100 Subject: [PATCH 28/33] drm: bridge: dw-hdmi: add ASoC dependency The newly added sound driver depends on SND_SOC_HDMI_CODEC, which in turn only makes sense when ASoC is enabled, as shown by this warning: warning: (DRM_MSM && DRM_STI && DRM_MEDIATEK_HDMI && DRM_I2C_NXP_TDA998X && DRM_DW_HDMI_I2S_AUDIO) selects SND_SOC_HDMI_CODEC which has unmet direct dependencies (SOUND && !M68K && !UML && SND && SND_SOC) Since the audio driver is probably useless without the audio subsystem, adding a dependency here seems the right solution. Fixes: 2761ba6c0925 ("drm: bridge: add DesignWare HDMI I2S audio support") Acked-by: Kuninori Morimoto Signed-off-by: Arnd Bergmann Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20161125205411.1157522-1-arnd@arndb.de --- drivers/gpu/drm/bridge/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 8bce72f7562d..29755bc32aab 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -41,6 +41,7 @@ config DRM_DW_HDMI_AHB_AUDIO config DRM_DW_HDMI_I2S_AUDIO tristate "Synopsis Designware I2S Audio interface" + depends on SND_SOC depends on DRM_DW_HDMI select SND_SOC_HDMI_CODEC help From 79b95552336478b0465b74a1bda1f74239f5da3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Nov 2016 19:47:02 +0200 Subject: [PATCH 29/33] drm/atomic: Constify drm_atomic_crtc_needs_modeset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_atomic_crtc_needs_modeset() doesn't change the passed in crtc state, so pass it as const. Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1480009622-28127-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- include/drm/drm_atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 5d5f85db43f0..d6d241f63b9f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -418,7 +418,7 @@ int drm_atomic_debugfs_cleanup(struct drm_minor *minor); * should clear mode_changed during its ->atomic_check. */ static inline bool -drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) +drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) { return state->mode_changed || state->active_changed || state->connectors_changed; From c45a4e46570aa18f6128a2a44243c5d142a8e411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 3 Nov 2016 14:53:29 +0200 Subject: [PATCH 30/33] drm/edid: Consider alternate cea timings to be the same VIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CEA-861 specifies that the vertical front porch may vary by one or two lines for specific VICs. Up to now we've only considered a mode to match the VIC if it matched the shortest possible vertical front porch length (as that is the variant we store in cea_modes[]). Let's allow our VIC matching to work with the other timings variants as well so that that we'll send out the correct VIC if the variant actually used isn't the one with the shortest vertical front porch. Cc: Shashank Sharma Cc: Andrzej Hajda Cc: Adam Jackson Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1478177609-16762-2-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Andrzej Hajda --- drivers/gpu/drm/drm_edid.c | 66 +++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7eec18925b70..728990fee4ef 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2613,6 +2613,41 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) return clock; } +static bool +cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode) +{ + /* + * For certain VICs the spec allows the vertical + * front porch to vary by one or two lines. + * + * cea_modes[] stores the variant with the shortest + * vertical front porch. We can adjust the mode to + * get the other variants by simply increasing the + * vertical front porch length. + */ + BUILD_BUG_ON(edid_cea_modes[8].vtotal != 262 || + edid_cea_modes[9].vtotal != 262 || + edid_cea_modes[12].vtotal != 262 || + edid_cea_modes[13].vtotal != 262 || + edid_cea_modes[23].vtotal != 312 || + edid_cea_modes[24].vtotal != 312 || + edid_cea_modes[27].vtotal != 312 || + edid_cea_modes[28].vtotal != 312); + + if (((vic == 8 || vic == 9 || + vic == 12 || vic == 13) && mode->vtotal < 263) || + ((vic == 23 || vic == 24 || + vic == 27 || vic == 28) && mode->vtotal < 314)) { + mode->vsync_start++; + mode->vsync_end++; + mode->vtotal++; + + return true; + } + + return false; +} + static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match, unsigned int clock_tolerance) { @@ -2622,19 +2657,21 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m return 0; for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - const struct drm_display_mode *cea_mode = &edid_cea_modes[vic]; + struct drm_display_mode cea_mode = edid_cea_modes[vic]; unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ - clock1 = cea_mode->clock; - clock2 = cea_mode_alternate_clock(cea_mode); + clock1 = cea_mode.clock; + clock2 = cea_mode_alternate_clock(&cea_mode); if (abs(to_match->clock - clock1) > clock_tolerance && abs(to_match->clock - clock2) > clock_tolerance) continue; - if (drm_mode_equal_no_clocks(to_match, cea_mode)) - return vic; + do { + if (drm_mode_equal_no_clocks_no_stereo(to_match, &cea_mode)) + return vic; + } while (cea_mode_alternate_timings(vic, &cea_mode)); } return 0; @@ -2655,18 +2692,23 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) return 0; for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - const struct drm_display_mode *cea_mode = &edid_cea_modes[vic]; + struct drm_display_mode cea_mode = edid_cea_modes[vic]; unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ - clock1 = cea_mode->clock; - clock2 = cea_mode_alternate_clock(cea_mode); + clock1 = cea_mode.clock; + clock2 = cea_mode_alternate_clock(&cea_mode); - if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || - KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && - drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode)) - return vic; + if (KHZ2PICOS(to_match->clock) != KHZ2PICOS(clock1) && + KHZ2PICOS(to_match->clock) != KHZ2PICOS(clock2)) + continue; + + do { + if (drm_mode_equal_no_clocks_no_stereo(to_match, &cea_mode)) + return vic; + } while (cea_mode_alternate_timings(vic, &cea_mode)); } + return 0; } EXPORT_SYMBOL(drm_match_cea_mode); From 53c515befe2864173ac5acb5c248587ce24d245e Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 28 Nov 2016 17:22:31 -0800 Subject: [PATCH 31/33] drm/bridge: adv7511: Add Audio support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support to Audio for both adv7511 and adv7533 bridge chips. This patch was originally from [1] by Lars-Peter Clausen and was adapted by Archit Taneja and Srinivas Kandagatla . Then I heavily reworked it to use the hdmi-codec driver. And also folded in some audio packet initialization done by Andy Green . So credit to them, but blame to me. [1] https://github.com/analogdevicesinc/linux/blob/xcomm_zynq/drivers/gpu/drm/i2c/adv7511_audio.c Cc: David Airlie Cc: Archit Taneja Cc: Laurent Pinchart Cc: Wolfram Sang Cc: Srinivas Kandagatla Cc: "Ville Syrjälä" Cc: Boris Brezillon Cc: Andy Green Cc: Dave Long Cc: Guodong Xu Cc: Zhangfei Gao Cc: Mark Brown Cc: Lars-Peter Clausen Cc: Jose Abreu Cc: Kuninori Morimoto Cc: dri-devel@lists.freedesktop.org Acked-by: Lars-Peter Clausen Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1480382552-28219-2-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/Kconfig | 8 + drivers/gpu/drm/bridge/adv7511/Makefile | 1 + drivers/gpu/drm/bridge/adv7511/adv7511.h | 16 ++ .../gpu/drm/bridge/adv7511/adv7511_audio.c | 213 ++++++++++++++++++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 4 + 5 files changed, 242 insertions(+) create mode 100644 drivers/gpu/drm/bridge/adv7511/adv7511_audio.c diff --git a/drivers/gpu/drm/bridge/adv7511/Kconfig b/drivers/gpu/drm/bridge/adv7511/Kconfig index d2b0499ab7d7..2fed567f9943 100644 --- a/drivers/gpu/drm/bridge/adv7511/Kconfig +++ b/drivers/gpu/drm/bridge/adv7511/Kconfig @@ -6,6 +6,14 @@ config DRM_I2C_ADV7511 help Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. +config DRM_I2C_ADV7511_AUDIO + bool "ADV7511 HDMI Audio driver" + depends on DRM_I2C_ADV7511 && SND_SOC + select SND_SOC_HDMI_CODEC + help + Support the ADV7511 HDMI Audio interface. This is used in + conjunction with the AV7511 HDMI driver. + config DRM_I2C_ADV7533 bool "ADV7533 encoder" depends on DRM_I2C_ADV7511 diff --git a/drivers/gpu/drm/bridge/adv7511/Makefile b/drivers/gpu/drm/bridge/adv7511/Makefile index 9019327fff4c..5ba675534f6e 100644 --- a/drivers/gpu/drm/bridge/adv7511/Makefile +++ b/drivers/gpu/drm/bridge/adv7511/Makefile @@ -1,3 +1,4 @@ adv7511-y := adv7511_drv.o +adv7511-$(CONFIG_DRM_I2C_ADV7511_AUDIO) += adv7511_audio.o adv7511-$(CONFIG_DRM_I2C_ADV7533) += adv7533.o obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 161c923d6162..992d76ce02bb 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -309,6 +309,8 @@ struct adv7511 { struct drm_display_mode curr_mode; unsigned int f_tmds; + unsigned int f_audio; + unsigned int audio_source; unsigned int current_edid_segment; uint8_t edid_buf[256]; @@ -334,6 +336,7 @@ struct adv7511 { bool use_timing_gen; enum adv7511_type type; + struct platform_device *audio_pdev; }; #ifdef CONFIG_DRM_I2C_ADV7533 @@ -389,4 +392,17 @@ static inline int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) } #endif +#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO +int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511); +void adv7511_audio_exit(struct adv7511 *adv7511); +#else /*CONFIG_DRM_I2C_ADV7511_AUDIO */ +static inline int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) +{ + return 0; +} +static inline void adv7511_audio_exit(struct adv7511 *adv7511) +{ +} +#endif /* CONFIG_DRM_I2C_ADV7511_AUDIO */ + #endif /* __DRM_I2C_ADV7511_H__ */ diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c new file mode 100644 index 000000000000..cf92ebfe6ab7 --- /dev/null +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c @@ -0,0 +1,213 @@ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * Copyright (c) 2016, Linaro Limited + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include + +#include "adv7511.h" + +static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs, + unsigned int *cts, unsigned int *n) +{ + switch (fs) { + case 32000: + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + *n = 6144; + break; + } + + *cts = ((f_tmds * *n) / (128 * fs)) * 1000; +} + +static int adv7511_update_cts_n(struct adv7511 *adv7511) +{ + unsigned int cts = 0; + unsigned int n = 0; + + adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n); + + regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf); + regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff); + + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0, + (cts >> 16) & 0xf); + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1, + (cts >> 8) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2, + cts & 0xff); + + return 0; +} + +int adv7511_hdmi_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +{ + struct adv7511 *adv7511 = dev_get_drvdata(dev); + unsigned int audio_source, i2s_format = 0; + unsigned int invert_clock; + unsigned int rate; + unsigned int len; + + switch (hparms->sample_rate) { + case 32000: + rate = ADV7511_SAMPLE_FREQ_32000; + break; + case 44100: + rate = ADV7511_SAMPLE_FREQ_44100; + break; + case 48000: + rate = ADV7511_SAMPLE_FREQ_48000; + break; + case 88200: + rate = ADV7511_SAMPLE_FREQ_88200; + break; + case 96000: + rate = ADV7511_SAMPLE_FREQ_96000; + break; + case 176400: + rate = ADV7511_SAMPLE_FREQ_176400; + break; + case 192000: + rate = ADV7511_SAMPLE_FREQ_192000; + break; + default: + return -EINVAL; + } + + switch (hparms->sample_width) { + case 16: + len = ADV7511_I2S_SAMPLE_LEN_16; + break; + case 18: + len = ADV7511_I2S_SAMPLE_LEN_18; + break; + case 20: + len = ADV7511_I2S_SAMPLE_LEN_20; + break; + case 24: + len = ADV7511_I2S_SAMPLE_LEN_24; + break; + default: + return -EINVAL; + } + + switch (fmt->fmt) { + case HDMI_I2S: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_I2S; + break; + case HDMI_RIGHT_J: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_RIGHT_J; + break; + case HDMI_LEFT_J: + audio_source = ADV7511_AUDIO_SOURCE_I2S; + i2s_format = ADV7511_I2S_FORMAT_LEFT_J; + break; + default: + return -EINVAL; + } + + invert_clock = fmt->bit_clk_inv; + + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70, + audio_source << 4); + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6), + invert_clock << 6); + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03, + i2s_format); + + adv7511->audio_source = audio_source; + + adv7511->f_audio = hparms->sample_rate; + + adv7511_update_cts_n(adv7511); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3, + ADV7511_AUDIO_CFG3_LEN_MASK, len); + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, + ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4); + regmap_write(adv7511->regmap, 0x73, 0x1); + + return 0; +} + +static int audio_startup(struct device *dev, void *data) +{ + struct adv7511 *adv7511 = dev_get_drvdata(dev); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, + BIT(7), 0); + + /* hide Audio infoframe updates */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(5), BIT(5)); + /* enable N/CTS, enable Audio sample packets */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + BIT(5), BIT(5)); + /* enable N/CTS */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + BIT(6), BIT(6)); + /* not copyrighted */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1, + BIT(5), BIT(5)); + /* enable audio infoframes */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + BIT(3), BIT(3)); + /* AV mute disable */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0), + BIT(7) | BIT(6), BIT(7)); + /* use Audio infoframe updated info */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(1), + BIT(5), 0); + return 0; +} + +static void audio_shutdown(struct device *dev, void *data) +{ +} + +static const struct hdmi_codec_ops adv7511_codec_ops = { + .hw_params = adv7511_hdmi_hw_params, + .audio_shutdown = audio_shutdown, + .audio_startup = audio_startup, +}; + +static struct hdmi_codec_pdata codec_data = { + .ops = &adv7511_codec_ops, + .max_i2s_channels = 2, + .i2s = 1, +}; + +int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511) +{ + adv7511->audio_pdev = platform_device_register_data(dev, + HDMI_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_data, + sizeof(codec_data)); + return PTR_ERR_OR_ZERO(adv7511->audio_pdev); +} + +void adv7511_audio_exit(struct adv7511 *adv7511) +{ + if (adv7511->audio_pdev) { + platform_device_unregister(adv7511->audio_pdev); + adv7511->audio_pdev = NULL; + } +} diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 8ed3906dd411..8dba729f6ef9 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1037,6 +1037,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) goto err_unregister_cec; } + adv7511_audio_init(dev, adv7511); + return 0; err_unregister_cec: @@ -1058,6 +1060,8 @@ static int adv7511_remove(struct i2c_client *i2c) drm_bridge_remove(&adv7511->bridge); + adv7511_audio_exit(adv7511); + i2c_unregister_device(adv7511->i2c_edid); kfree(adv7511->edid); From b2383fa3592061cda53b1650bf538b1d82add816 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Nov 2016 17:22:32 -0800 Subject: [PATCH 32/33] drm/bridge: adv7511: Enable the audio data and clock pads on adv7533 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables the Audio Data and Clock pads to the adv7533 bridge. Without this patch audio can not be played. Cc: David Airlie Cc: Archit Taneja Cc: Laurent Pinchart Cc: Wolfram Sang Cc: Srinivas Kandagatla Cc: "Ville Syrjälä" Cc: Boris Brezillon Cc: Andy Green Cc: Dave Long Cc: Guodong Xu Cc: Zhangfei Gao Cc: Mark Brown Cc: Lars-Peter Clausen Cc: Jose Abreu Cc: Kuninori Morimoto Cc: dri-devel@lists.freedesktop.org Signed-off-by: Srinivas Kandagatla Signed-off-by: John Stultz Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1480382552-28219-3-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/bridge/adv7511/adv7533.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index d7f7b7ce8ebe..8b210373cfa2 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -29,6 +29,7 @@ static const struct reg_sequence adv7533_cec_fixed_registers[] = { { 0x17, 0xd0 }, { 0x24, 0x20 }, { 0x57, 0x11 }, + { 0x05, 0xc8 }, }; static const struct regmap_config adv7533_cec_regmap_config = { From 389f78b361fcdc52a9dbb5382c3922d80b52ed9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 25 Nov 2016 15:32:30 +0000 Subject: [PATCH 33/33] drm: Introduce drm_framebuffer_assign() In a couple of places currently, and with the intent to add more, we update a pointer to a framebuffer to hold a new fb reference (evicting the old). Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161125153231.13255-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_atomic.c | 8 ++------ include/drm/drm_framebuffer.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 89737e42fa83..19d7bcb88217 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1246,18 +1246,14 @@ void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb) { - if (plane_state->fb) - drm_framebuffer_unreference(plane_state->fb); - if (fb) - drm_framebuffer_reference(fb); - plane_state->fb = fb; - if (fb) DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n", fb->base.id, plane_state); else DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n", plane_state); + + drm_framebuffer_assign(&plane_state->fb, fb); } EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index b3141a0e609b..1ddfa2928802 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -251,6 +251,24 @@ static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) } /** + * drm_framebuffer_assign - store a reference to the fb + * @p: location to store framebuffer + * @fb: new framebuffer (maybe NULL) + * + * This functions sets the location to store a reference to the framebuffer, + * unreferencing the framebuffer that was previously stored in that location. + */ +static inline void drm_framebuffer_assign(struct drm_framebuffer **p, + struct drm_framebuffer *fb) +{ + if (fb) + drm_framebuffer_reference(fb); + if (*p) + drm_framebuffer_unreference(*p); + *p = fb; +} + +/* * drm_for_each_fb - iterate over all framebuffers * @fb: the loop cursor * @dev: the DRM device