diff options
Diffstat (limited to 'drivers')
83 files changed, 943 insertions, 633 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 2f6614c9a229..2c3cab066871 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -245,6 +245,7 @@ config DMA_SHARED_BUFFER bool default n select ANON_INODES + select IRQ_WORK help This option enables the framework for buffer-sharing between multiple drivers. A buffer is associated with a file using driver diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index bc1cb284111c..058805b6d164 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -351,13 +351,13 @@ static inline int is_dma_buf_file(struct file *file) * * 2. Userspace passes this file-descriptors to all drivers it wants this buffer * to share with: First the filedescriptor is converted to a &dma_buf using - * dma_buf_get(). The the buffer is attached to the device using + * dma_buf_get(). Then the buffer is attached to the device using * dma_buf_attach(). * * Up to this stage the exporter is still free to migrate or reallocate the * backing storage. * - * 3. Once the buffer is attached to all devices userspace can inniate DMA + * 3. Once the buffer is attached to all devices userspace can initiate DMA * access to the shared buffer. In the kernel this is done by calling * dma_buf_map_attachment() and dma_buf_unmap_attachment(). * @@ -617,7 +617,7 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR * on error. May return -EINTR if it is interrupted by a signal. * - * A mapping must be unmapped again using dma_buf_map_attachment(). Note that + * A mapping must be unmapped by using dma_buf_unmap_attachment(). Note that * the underlying backing storage is pinned for as long as a mapping exists, * therefore users/importers should not hold onto a mapping for undue amounts of * time. @@ -1179,8 +1179,7 @@ static int dma_buf_init_debugfs(void) static void dma_buf_uninit_debugfs(void) { - if (dma_buf_debugfs_dir) - debugfs_remove_recursive(dma_buf_debugfs_dir); + debugfs_remove_recursive(dma_buf_debugfs_dir); } #else static inline int dma_buf_init_debugfs(void) diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 0350829ba62e..dd1edfb27b61 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -31,6 +31,14 @@ static const char *dma_fence_array_get_timeline_name(struct dma_fence *fence) return "unbound"; } +static void irq_dma_fence_array_work(struct irq_work *wrk) +{ + struct dma_fence_array *array = container_of(wrk, typeof(*array), work); + + dma_fence_signal(&array->base); + dma_fence_put(&array->base); +} + static void dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) { @@ -39,8 +47,9 @@ static void dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_array *array = array_cb->array; if (atomic_dec_and_test(&array->num_pending)) - dma_fence_signal(&array->base); - dma_fence_put(&array->base); + irq_work_queue(&array->work); + else + dma_fence_put(&array->base); } static bool dma_fence_array_enable_signaling(struct dma_fence *fence) @@ -136,6 +145,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, spin_lock_init(&array->lock); dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock, context, seqno); + init_irq_work(&array->work, irq_dma_fence_array_work); array->num_fences = num_fences; atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences); diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index b44d9d7db347..b759a569b7b8 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -104,7 +104,8 @@ reservation_object_add_shared_inplace(struct reservation_object *obj, struct reservation_object_list *fobj, struct dma_fence *fence) { - u32 i; + struct dma_fence *signaled = NULL; + u32 i, signaled_idx; dma_fence_get(fence); @@ -126,17 +127,28 @@ reservation_object_add_shared_inplace(struct reservation_object *obj, dma_fence_put(old_fence); return; } + + if (!signaled && dma_fence_is_signaled(old_fence)) { + signaled = old_fence; + signaled_idx = i; + } } /* * memory barrier is added by write_seqcount_begin, * fobj->shared_count is protected by this lock too */ - RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); - fobj->shared_count++; + if (signaled) { + RCU_INIT_POINTER(fobj->shared[signaled_idx], fence); + } else { + RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); + fobj->shared_count++; + } write_seqcount_end(&obj->seq); preempt_enable(); + + dma_fence_put(signaled); } static void @@ -145,8 +157,7 @@ reservation_object_add_shared_replace(struct reservation_object *obj, struct reservation_object_list *fobj, struct dma_fence *fence) { - unsigned i; - struct dma_fence *old_fence = NULL; + unsigned i, j, k; dma_fence_get(fence); @@ -162,24 +173,21 @@ reservation_object_add_shared_replace(struct reservation_object *obj, * references from the old struct are carried over to * the new. */ - fobj->shared_count = old->shared_count; - - for (i = 0; i < old->shared_count; ++i) { + for (i = 0, j = 0, k = fobj->shared_max; i < old->shared_count; ++i) { struct dma_fence *check; check = rcu_dereference_protected(old->shared[i], reservation_object_held(obj)); - if (!old_fence && check->context == fence->context) { - old_fence = check; - RCU_INIT_POINTER(fobj->shared[i], fence); - } else - RCU_INIT_POINTER(fobj->shared[i], check); - } - if (!old_fence) { - RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); - fobj->shared_count++; + if (check->context == fence->context || + dma_fence_is_signaled(check)) + RCU_INIT_POINTER(fobj->shared[--k], check); + else + RCU_INIT_POINTER(fobj->shared[j++], check); } + fobj->shared_count = j; + RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); + fobj->shared_count++; done: preempt_disable(); @@ -192,10 +200,18 @@ done: write_seqcount_end(&obj->seq); preempt_enable(); - if (old) - kfree_rcu(old, rcu); + if (!old) + return; - dma_fence_put(old_fence); + /* Drop the references to the signaled fences */ + for (i = k; i < fobj->shared_max; ++i) { + struct dma_fence *f; + + f = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(obj)); + dma_fence_put(f); + } + kfree_rcu(old, rcu); } /** @@ -318,7 +334,7 @@ retry: continue; } - dst_list->shared[dst_list->shared_count++] = fence; + rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence); } } else { dst_list = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index df9cbc78e168..8ca3783f2deb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -358,7 +358,6 @@ static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector) if (amdgpu_connector->edid) { drm_mode_connector_update_edid_property(connector, amdgpu_connector->edid); ret = drm_add_edid_modes(connector, amdgpu_connector->edid); - drm_edid_to_eld(connector, amdgpu_connector->edid); return ret; } drm_mode_connector_update_edid_property(connector, NULL); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f71fe6d2ddda..c324c3b76fac 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3333,8 +3333,6 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, amdgpu_dm_connector->num_modes = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); - amdgpu_dm_get_native_mode(connector); } else { amdgpu_dm_connector->num_modes = 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index f8efb98b1fa7..707928b88448 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -177,12 +177,7 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { static int dm_connector_update_modes(struct drm_connector *connector, struct edid *edid) { - int ret; - - ret = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); - - return ret; + return drm_add_edid_modes(connector, edid); } static int dm_dp_mst_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c index 074fd4ea7ece..f067de4e1e82 100644 --- a/drivers/gpu/drm/arc/arcpgu_drv.c +++ b/drivers/gpu/drm/arc/arcpgu_drv.c @@ -155,7 +155,6 @@ static int arcpgu_show_pxlclock(struct seq_file *m, void *arg) static struct drm_info_list arcpgu_debugfs_list[] = { { "clocks", arcpgu_show_pxlclock, 0 }, - { "fb", drm_fb_cma_debugfs_show, 0 }, }; static int arcpgu_debugfs_init(struct drm_minor *minor) @@ -180,6 +179,7 @@ static struct drm_driver arcpgu_drm_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_print_info = drm_gem_cma_print_info, .gem_vm_ops = &drm_gem_cma_vm_ops, .gem_prime_export = drm_gem_prime_export, .gem_prime_import = drm_gem_prime_import, diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 5a5427bbd70e..630721f429f7 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -252,10 +252,10 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - return drm_plane_helper_check_state(state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true); + return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); } static void hdlcd_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 0afb53b1f4e9..feaa8bc3d7b7 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -231,7 +231,6 @@ static int hdlcd_show_pxlclock(struct seq_file *m, void *arg) static struct drm_info_list hdlcd_debugfs_list[] = { { "interrupt_count", hdlcd_show_underrun_count, 0 }, { "clocks", hdlcd_show_pxlclock, 0 }, - { "fb", drm_fb_cma_debugfs_show, 0 }, }; static int hdlcd_debugfs_init(struct drm_minor *minor) @@ -253,6 +252,7 @@ static struct drm_driver hdlcd_driver = { .irq_postinstall = hdlcd_irq_postinstall, .irq_uninstall = hdlcd_irq_uninstall, .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_print_info = drm_gem_cma_print_info, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index e7419797bbd1..33c5ef96ced0 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -150,7 +150,8 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - ret = drm_plane_helper_check_state(state, &clip, 0, INT_MAX, true, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + 0, INT_MAX, true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 9385eb0b1ee4..ed12a7ddd64a 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -977,8 +977,6 @@ static int anx78xx_get_modes(struct drm_connector *connector) } num_modes = drm_add_edid_modes(connector, anx78xx->edid); - /* Store the ELD */ - drm_edid_to_eld(connector, anx78xx->edid); unlock: mutex_unlock(&anx78xx->lock); diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index b7eb704d0a8a..86789f8918a4 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -1169,8 +1169,18 @@ static void sii8620_set_infoframes(struct sii8620 *ctx) sii8620_write_buf(ctx, REG_TPI_INFO_B0, buf, ret); } -static void sii8620_start_hdmi(struct sii8620 *ctx) +static void sii8620_start_video(struct sii8620 *ctx) { + if (!sii8620_is_mhl3(ctx)) + sii8620_stop_video(ctx); + + if (ctx->sink_type == SINK_DVI && !sii8620_is_mhl3(ctx)) { + sii8620_write(ctx, REG_RX_HDMI_CTRL2, + VAL_RX_HDMI_CTRL2_DEFVAL); + sii8620_write(ctx, REG_TPI_SC, 0); + return; + } + sii8620_write_seq_static(ctx, REG_RX_HDMI_CTRL2, VAL_RX_HDMI_CTRL2_DEFVAL | BIT_RX_HDMI_CTRL2_USE_AV_MUTE, @@ -1229,21 +1239,6 @@ static void sii8620_start_hdmi(struct sii8620 *ctx) sii8620_set_infoframes(ctx); } -static void sii8620_start_video(struct sii8620 *ctx) -{ - if (!sii8620_is_mhl3(ctx)) - sii8620_stop_video(ctx); - - switch (ctx->sink_type) { - case SINK_HDMI: - sii8620_start_hdmi(ctx); - break; - case SINK_DVI: - default: - break; - } -} - static void sii8620_disable_hpd(struct sii8620 *ctx) { sii8620_setbits(ctx, REG_EDID_CTRL, BIT_EDID_CTRL_EDID_PRIME_VALID, 0); @@ -1945,8 +1940,13 @@ static void sii8620_irq_scdt(struct sii8620 *ctx) if (stat & BIT_INTR_SCDT_CHANGE) { u8 cstat = sii8620_readb(ctx, REG_TMDS_CSTAT_P3); - if (cstat & BIT_TMDS_CSTAT_P3_SCDT) - sii8620_scdt_high(ctx); + if (cstat & BIT_TMDS_CSTAT_P3_SCDT) { + if (ctx->sink_type == SINK_HDMI) + /* enable infoframe interrupt */ + sii8620_scdt_high(ctx); + else + sii8620_start_video(ctx); + } } sii8620_write(ctx, REG_INTR5, stat); @@ -2191,6 +2191,19 @@ static void sii8620_detach(struct drm_bridge *bridge) rc_unregister_device(ctx->rc_dev); } +static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct sii8620 *ctx = bridge_to_sii8620(bridge); + bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] & + MHL_DCAP_VID_LINK_PPIXEL; + unsigned int max_pclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : + MHL1_MAX_LCLK; + max_pclk /= can_pack ? 2 : 3; + + return (mode->clock > max_pclk) ? MODE_CLOCK_HIGH : MODE_OK; +} + static bool sii8620_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -2220,8 +2233,9 @@ end: union hdmi_infoframe frm; u8 mhl_vic[] = { 0, 95, 94, 93, 98 }; + /* FIXME: We need the connector here */ drm_hdmi_vendor_infoframe_from_display_mode( - &frm.vendor.hdmi, adjusted_mode); + &frm.vendor.hdmi, NULL, adjusted_mode); vic = frm.vendor.hdmi.vic; if (vic >= ARRAY_SIZE(mhl_vic)) vic = 0; @@ -2238,6 +2252,7 @@ static const struct drm_bridge_funcs sii8620_bridge_funcs = { .attach = sii8620_attach, .detach = sii8620_detach, .mode_fixup = sii8620_mode_fixup, + .mode_valid = sii8620_mode_valid, }; static int sii8620_probe(struct i2c_client *client, diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index b72259bf6e2f..a38db40ce990 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1438,7 +1438,9 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, u8 buffer[10]; ssize_t err; - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode); + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, + &hdmi->connector, + mode); if (err < 0) /* * Going into that statement does not means vendor infoframe @@ -1911,8 +1913,6 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); ret = drm_add_edid_modes(connector, edid); - /* Store the ELD */ - drm_edid_to_eld(connector, edid); kfree(edid); } else { dev_dbg(hdmi->dev, "failed to get edid\n"); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8636e7eeb731..08ab7d6aea65 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -6,6 +6,8 @@ * * Copyright (C) 2016 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> * + * Copyright (C) 2016 Zodiac Inflight Innovations + * * Initially based on: drivers/gpu/drm/i2c/tda998x_drv.c * * Copyright (C) 2012 Texas Instruments diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index b5f528543956..26df1e8cd490 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -13,6 +13,14 @@ #include "cirrus_drv.h" +static int cirrus_create_handle(struct drm_framebuffer *fb, + struct drm_file* file_priv, + unsigned int* handle) +{ + struct cirrus_framebuffer *cirrus_fb = to_cirrus_framebuffer(fb); + + return drm_gem_handle_create(file_priv, cirrus_fb->obj, handle); +} static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb) { @@ -24,6 +32,7 @@ static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb) } static const struct drm_framebuffer_funcs cirrus_fb_funcs = { + .create_handle = cirrus_create_handle, .destroy = cirrus_user_framebuffer_destroy, }; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c2da5585e201..37445d50816a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -33,6 +33,7 @@ #include <linux/sync_file.h> #include "drm_crtc_internal.h" +#include "drm_internal.h" void __drm_crtc_commit_free(struct kref *kref) { @@ -907,11 +908,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->src_h > fb_height || state->src_y > fb_height - state->src_h) { DRM_DEBUG_ATOMIC("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, - state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); + state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10, + state->fb->width, state->fb->height); return -ENOSPC; } @@ -934,21 +936,8 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "plane[%u]: %s\n", plane->base.id, plane->name); drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); drm_printf(p, "\tfb=%u\n", state->fb ? state->fb->base.id : 0); - if (state->fb) { - struct drm_framebuffer *fb = state->fb; - int i, n = fb->format->num_planes; - struct drm_format_name_buf format_name; - - drm_printf(p, "\t\tformat=%s\n", - drm_get_format_name(fb->format->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]); - } - } + if (state->fb) + drm_framebuffer_print_info(p, 2, state->fb); drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); drm_printf(p, "\trotation=%x\n", state->rotation); @@ -1808,7 +1797,7 @@ int drm_atomic_debugfs_init(struct drm_minor *minor) #endif /* - * The big monstor ioctl + * The big monster ioctl */ static struct drm_pending_vblank_event *create_vblank_event( diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b16f1d69a0bb..ab4032167094 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -696,6 +696,100 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** + * drm_atomic_helper_check_plane_state() - Check plane state for validity + * @plane_state: plane state to check + * @crtc_state: crtc state to check + * @clip: integer clipping coordinates + * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point + * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point + * @can_position: is it legal to position the plane such that it + * doesn't cover the entire crtc? This will generally + * only be false for primary planes. + * @can_update_disabled: can the plane be updated while the crtc + * is disabled? + * + * Checks that a desired plane update is valid, and updates various + * bits of derived state (clipped coordinates etc.). Drivers that provide + * their own plane handling rather than helper-provided implementations may + * still wish to call this function to avoid duplication of error checking + * code. + * + * RETURNS: + * Zero if update appears valid, error code on failure + */ +int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, + const struct drm_crtc_state *crtc_state, + const struct drm_rect *clip, + int min_scale, + int max_scale, + bool can_position, + bool can_update_disabled) +{ + struct drm_framebuffer *fb = plane_state->fb; + struct drm_rect *src = &plane_state->src; + struct drm_rect *dst = &plane_state->dst; + unsigned int rotation = plane_state->rotation; + int hscale, vscale; + + WARN_ON(plane_state->crtc && plane_state->crtc != crtc_state->crtc); + + *src = drm_plane_state_src(plane_state); + *dst = drm_plane_state_dest(plane_state); + + if (!fb) { + plane_state->visible = false; + return 0; + } + + /* crtc should only be NULL when disabling (i.e., !fb) */ + if (WARN_ON(!plane_state->crtc)) { + plane_state->visible = false; + return 0; + } + + if (!crtc_state->enable && !can_update_disabled) { + DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n"); + return -EINVAL; + } + + drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); + + /* Check scaling */ + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); + if (hscale < 0 || vscale < 0) { + DRM_DEBUG_KMS("Invalid scaling of plane\n"); + drm_rect_debug_print("src: ", &plane_state->src, true); + drm_rect_debug_print("dst: ", &plane_state->dst, false); + return -ERANGE; + } + + plane_state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); + + if (!plane_state->visible) + /* + * Plane isn't visible; some drivers can handle this + * so we just return success here. Drivers that can't + * (including those that use the primary plane helper's + * update function) will return an error from their + * update_plane handler. + */ + return 0; + + if (!can_position && !drm_rect_equals(dst, clip)) { + DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); + drm_rect_debug_print("dst: ", dst, false); + drm_rect_debug_print("clip: ", clip, false); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); + +/** * drm_atomic_helper_check_planes - validate state object for planes changes * @dev: DRM device * @state: the driver state object @@ -907,6 +1001,12 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * * Drivers can use this for building their own atomic commit if they don't have * a pure helper-based modeset implementation. + * + * Since these updates are not synchronized with lockings, only code paths + * called from &drm_mode_config_helper_funcs.atomic_commit_tail can look at the + * legacy state filled out by this helper. Defacto this means this helper and + * the legacy state pointers are only really useful for transitioning an + * existing driver to the atomic world. */ void drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, @@ -1787,11 +1887,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, !try_wait_for_completion(&old_conn_state->commit->flip_done)) return -EBUSY; - /* commit tracked through new_crtc_state->commit, no need to do it explicitly */ - if (new_conn_state->crtc) - continue; - - commit = crtc_or_fake_commit(state, old_conn_state->crtc); + /* Always track connectors explicitly for e.g. link retraining. */ + commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc); if (!commit) return -ENOMEM; @@ -1805,10 +1902,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, !try_wait_for_completion(&old_plane_state->commit->flip_done)) return -EBUSY; - /* - * Unlike connectors, always track planes explicitly for - * async pageflip support. - */ + /* Always track planes explicitly for async pageflip support. */ commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc); if (!commit) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index c1807d5754b2..b2482818fee8 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -158,6 +158,14 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, } } + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_framebuffer_debugfs_init(minor); + if (ret) { + DRM_ERROR("Failed to create framebuffer debugfs file\n"); + return ret; + } + } + if (dev->driver->debugfs_init) { ret = dev->driver->debugfs_init(minor); if (ret) { diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index b3d68964b407..adf79be42c1e 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1097,7 +1097,6 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE; aux->ddc.dev.parent = aux->dev; - aux->ddc.dev.of_node = aux->dev->of_node; strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev), sizeof(aux->ddc.name)); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index a934fd5e7e55..9acc1e157813 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -75,53 +75,6 @@ static bool drm_core_init_complete = false; static struct dentry *drm_debugfs_root; -#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV" - -void drm_dev_printk(const struct device *dev, const char *level, - unsigned int category, const char *function_name, - const char *prefix, const char *format, ...) -{ - struct va_format vaf; - va_list args; - - if (category != DRM_UT_NONE && !(drm_debug & category)) - return; - - va_start(args, format); - vaf.fmt = format; - vaf.va = &args; - - if (dev) - dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, - &vaf); - else - printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); - - va_end(args); -} -EXPORT_SYMBOL(drm_dev_printk); - -void drm_printk(const char *level, unsigned int category, - const char *format, ...) -{ - struct va_format vaf; - va_list args; - - if (category != DRM_UT_NONE && !(drm_debug & category)) - return; - - va_start(args, format); - vaf.fmt = format; - vaf.va = &args; - - printk("%s" "[" DRM_NAME ":%ps]%s %pV", - level, __builtin_return_address(0), - strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf); - - va_end(args); -} -EXPORT_SYMBOL(drm_printk); - /* * DRM Minors * A DRM device can provide several char-dev interfaces on the DRM-Major. Each diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5dfe14763871..524eace3d460 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3398,6 +3398,7 @@ static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, const u8 *video_db, u8 video_len) { + struct drm_display_info *info = &connector->display_info; int modes = 0, offset = 0, i, multi_present = 0, multi_len; u8 vic_len, hdmi_3d_len = 0; u16 mask; @@ -3525,6 +3526,8 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, } out: + if (modes > 0) + info->has_hdmi_infoframe = true; return modes; } @@ -3761,8 +3764,8 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) { u8 len = cea_db_payload_len(db); - if (len >= 6) - connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ + if (len >= 6 && (db[6] & (1 << 7))) + connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_SUPPORTS_AI; if (len >= 8) { connector->latency_present[0] = db[8] >> 7; connector->latency_present[1] = (db[8] >> 6) & 1; @@ -3834,16 +3837,27 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize) } EXPORT_SYMBOL(drm_edid_get_monitor_name); -/** +static void clear_eld(struct drm_connector *connector) +{ + memset(connector->eld, 0, sizeof(connector->eld)); + + connector->latency_present[0] = false; + connector->latency_present[1] = false; + connector->video_latency[0] = 0; + connector->audio_latency[0] = 0; + connector->video_latency[1] = 0; + connector->audio_latency[1] = 0; +} + +/* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink * @edid: EDID to parse * * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The - * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to - * fill in. + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. */ -void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) +static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { uint8_t *eld = connector->eld; u8 *cea; @@ -3852,14 +3866,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) int mnl; int dbl; - memset(eld, 0, sizeof(connector->eld)); - - connector->latency_present[0] = false; - connector->latency_present[1] = false; - connector->video_latency[0] = 0; - connector->audio_latency[0] = 0; - connector->video_latency[1] = 0; - connector->audio_latency[1] = 0; + clear_eld(connector); if (!edid) return; @@ -3870,17 +3877,18 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) return; } - mnl = get_monitor_name(edid, eld + 20); + mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); + DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); - eld[4] = (cea[1] << 5) | mnl; - DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20); + eld[DRM_ELD_CEA_EDID_VER_MNL] = cea[1] << DRM_ELD_CEA_EDID_VER_SHIFT; + eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; - eld[0] = 2 << 3; /* ELD version: 2 */ + eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D; - eld[16] = edid->mfg_id[0]; - eld[17] = edid->mfg_id[1]; - eld[18] = edid->prod_code[0]; - eld[19] = edid->prod_code[1]; + eld[DRM_ELD_MANUFACTURER_NAME0] = edid->mfg_id[0]; + eld[DRM_ELD_MANUFACTURER_NAME1] = edid->mfg_id[1]; + eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0]; + eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1]; if (cea_revision(cea) >= 3) { int i, start, end; @@ -3901,14 +3909,14 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) /* Audio Data Block, contains SADs */ sad_count = min(dbl / 3, 15 - total_sad_count); if (sad_count >= 1) - memcpy(eld + 20 + mnl + total_sad_count * 3, + memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)], &db[1], sad_count * 3); total_sad_count += sad_count; break; case SPEAKER_BLOCK: /* Speaker Allocation Data Block */ if (dbl >= 1) - eld[7] = db[1]; + eld[DRM_ELD_SPEAKER] = db[1]; break; case VENDOR_BLOCK: /* HDMI Vendor-Specific Data Block */ @@ -3920,7 +3928,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) } } } - eld[5] |= total_sad_count << 4; + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= total_sad_count << DRM_ELD_SAD_COUNT_SHIFT; + + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP; + else + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI; eld[DRM_ELD_BASELINE_ELD_LEN] = DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); @@ -3928,7 +3942,6 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", drm_eld_size(eld), total_sad_count); } -EXPORT_SYMBOL(drm_edid_to_eld); /** * drm_edid_to_sad - extracts SADs from EDID @@ -4238,6 +4251,8 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, struct drm_display_info *display = &connector->display_info; struct drm_hdmi_info *hdmi = &display->hdmi; + display->has_hdmi_infoframe = true; + if (hf_vsdb[6] & 0x80) { hdmi->scdc.supported = true; if (hf_vsdb[6] & 0x40) @@ -4411,6 +4426,7 @@ static void drm_add_display_info(struct drm_connector *connector, info->cea_rev = 0; info->max_tmds_clock = 0; info->dvi_dual = false; + info->has_hdmi_infoframe = false; info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); @@ -4608,8 +4624,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, * @edid: EDID data * * Add the specified modes to the connector's mode list. Also fills out the - * &drm_display_info structure in @connector with any information which can be - * derived from the edid. + * &drm_display_info structure and ELD in @connector with any information which + * can be derived from the edid. * * Return: The number of modes added or 0 if we couldn't find any. */ @@ -4619,9 +4635,11 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) u32 quirks; if (edid == NULL) { + clear_eld(connector); return 0; } if (!drm_edid_is_valid(edid)) { + clear_eld(connector); dev_warn(connector->dev->dev, "%s: EDID invalid.\n", connector->name); return 0; @@ -4629,6 +4647,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) quirks = edid_get_quirks(edid); + drm_edid_to_eld(connector, edid); + /* * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. * To avoid multiple parsing of same block, lets parse that map @@ -4904,6 +4924,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with * data from a DRM display mode * @frame: HDMI vendor infoframe + * @connector: the connector * @mode: DRM display mode * * Note that there's is a need to send HDMI vendor infoframes only when using a @@ -4914,8 +4935,15 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) */ int drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, + struct drm_connector *connector, const struct drm_display_mode *mode) { + /* + * FIXME: sil-sii8620 doesn't have a connector around when + * we need one, so we have to be prepared for a NULL connector. + */ + bool has_hdmi_infoframe = connector ? + connector->display_info.has_hdmi_infoframe : false; int err; u32 s3d_flags; u8 vic; @@ -4923,11 +4951,21 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, if (!frame || !mode) return -EINVAL; + if (!has_hdmi_infoframe) + return -EINVAL; + vic = drm_match_hdmi_mode(mode); s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; - if (!vic && !s3d_flags) - return -EINVAL; + /* + * Even if it's not absolutely necessary to send the infoframe + * (ie.vic==0 and s3d_struct==0) we will still send it if we + * know that the sink can handle it. This is based on a + * suggestion in HDMI 2.0 Appendix F. Apparently some sinks + * have trouble realizing that they shuld switch from 3D to 2D + * mode if the source simply stops sending the infoframe when + * it wants to switch from 3D to 2D. + */ if (vic && s3d_flags) return -EINVAL; @@ -4936,10 +4974,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, if (err < 0) return err; - if (vic) - frame->vic = vic; - else - frame->s3d_struct = s3d_structure_from_display_mode(mode); + frame->vic = vic; + frame->s3d_struct = s3d_structure_from_display_mode(mode); return 0; } diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 0e3c14174d08..35b56dfba929 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -130,43 +130,6 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); -#ifdef CONFIG_DEBUG_FS -static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m) -{ - int i; - - seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, - (char *)&fb->format->format); - - for (i = 0; i < fb->format->num_planes; i++) { - seq_printf(m, " %d: offset=%d pitch=%d, obj: ", - i, fb->offsets[i], fb->pitches[i]); - drm_gem_cma_describe(drm_fb_cma_get_gem_obj(fb, i), m); - } -} - -/** - * drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects - * in debugfs. - * @m: output file - * @arg: private data for the callback - */ -int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - struct drm_framebuffer *fb; - - mutex_lock(&dev->mode_config.fb_lock); - drm_for_each_fb(fb, dev) - drm_fb_cma_describe(fb, m); - mutex_unlock(&dev->mode_config.fb_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show); -#endif - static int drm_fb_cma_mmap(struct fb_info *info, struct vm_area_struct *vma) { return dma_mmap_writecombine(info->device, vma, info->screen_base, diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e56166334455..09919e8d67f9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -150,6 +150,9 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, { int err; + if (!fb_helper) + return 0; + mutex_lock(&fb_helper->lock); err = __drm_fb_helper_add_one_connector(fb_helper, connector); mutex_unlock(&fb_helper->lock); @@ -161,7 +164,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_one_connector); /** * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev * emulation helper - * @fb_helper: fbdev initialized with drm_fb_helper_init + * @fb_helper: fbdev initialized with drm_fb_helper_init, can be NULL * * This functions adds all the available connectors for use with the given * fb_helper. This is a separate step to allow drivers to freely assign @@ -179,7 +182,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) struct drm_connector_list_iter conn_iter; int i, ret = 0; - if (!drm_fbdev_emulation) + if (!drm_fbdev_emulation || !fb_helper) return 0; mutex_lock(&fb_helper->lock); @@ -245,6 +248,9 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, { int err; + if (!fb_helper) + return 0; + mutex_lock(&fb_helper->lock); err = __drm_fb_helper_remove_one_connector(fb_helper, connector); mutex_unlock(&fb_helper->lock); @@ -484,7 +490,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) /** * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration - * @fb_helper: fbcon to restore + * @fb_helper: driver-allocated fbdev helper, can be NULL * * This should be called from driver's drm &drm_driver.lastclose callback * when implementing an fbcon on top of kms using this helper. This ensures that @@ -498,7 +504,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) bool do_delayed; int ret; - if (!drm_fbdev_emulation) + if (!drm_fbdev_emulation || !fb_helper) return -ENODEV; if (READ_ONCE(fb_helper->deferred_setup)) @@ -793,8 +799,10 @@ int drm_fb_helper_init(struct drm_device *dev, struct drm_mode_config *config = &dev->mode_config; int i; - if (!drm_fbdev_emulation) + if (!drm_fbdev_emulation) { + dev->fb_helper = fb_helper; return 0; + } if (!max_conn_count) return -EINVAL; @@ -829,6 +837,8 @@ int drm_fb_helper_init(struct drm_device *dev, i++; } + dev->fb_helper = fb_helper; + return 0; out_free: drm_fb_helper_crtc_free(fb_helper); @@ -883,7 +893,7 @@ EXPORT_SYMBOL(drm_fb_helper_alloc_fbi); /** * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device - * @fb_helper: driver-allocated fbdev helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * * A wrapper around unregister_framebuffer, to release the fb_info * framebuffer device. This must be called before releasing all resources for @@ -898,7 +908,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi); /** * drm_fb_helper_fini - finialize a &struct drm_fb_helper - * @fb_helper: driver-allocated fbdev helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * * This cleans up all remaining resources associated with @fb_helper. Must be * called after drm_fb_helper_unlink_fbi() was called. @@ -907,7 +917,12 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) { struct fb_info *info; - if (!drm_fbdev_emulation || !fb_helper) + if (!fb_helper) + return; + + fb_helper->dev->fb_helper = NULL; + + if (!drm_fbdev_emulation) return; cancel_work_sync(&fb_helper->resume_work); @@ -937,7 +952,7 @@ EXPORT_SYMBOL(drm_fb_helper_fini); /** * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer - * @fb_helper: driver-allocated fbdev helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * * A wrapper around unlink_framebuffer implemented by fbdev core */ @@ -1138,7 +1153,7 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); /** * drm_fb_helper_set_suspend - wrapper around fb_set_suspend - * @fb_helper: driver-allocated fbdev helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * @suspend: whether to suspend or resume * * A wrapper around fb_set_suspend implemented by fbdev core. @@ -1155,7 +1170,7 @@ EXPORT_SYMBOL(drm_fb_helper_set_suspend); /** * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also * takes the console lock - * @fb_helper: driver-allocated fbdev helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * @suspend: whether to suspend or resume * * A wrapper around fb_set_suspend() that takes the console lock. If the lock @@ -2576,7 +2591,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config); /** * drm_fb_helper_hotplug_event - respond to a hotplug notification by * probing all the outputs attached to the fb - * @fb_helper: the drm_fb_helper + * @fb_helper: driver-allocated fbdev helper, can be NULL * * Scan the connectors attached to the fb_helper and try to put together a * setup after notification of a change in output configuration. @@ -2598,7 +2613,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { int err = 0; - if (!drm_fbdev_emulation) + if (!drm_fbdev_emulation || !fb_helper) return 0; mutex_lock(&fb_helper->lock); @@ -2626,6 +2641,34 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); +/** + * drm_fb_helper_lastclose - DRM driver lastclose helper for fbdev emulation + * @dev: DRM device + * + * This function can be used as the &drm_driver->lastclose callback for drivers + * that only need to call drm_fb_helper_restore_fbdev_mode_unlocked(). + */ +void drm_fb_helper_lastclose(struct drm_device *dev) +{ + drm_fb_helper_restore_fbdev_mode_unlocked(dev->fb_helper); +} +EXPORT_SYMBOL(drm_fb_helper_lastclose); + +/** + * drm_fb_helper_output_poll_changed - DRM mode config \.output_poll_changed + * helper for fbdev emulation + * @dev: DRM device + * + * This function can be used as the + * &drm_mode_config_funcs.output_poll_changed callback for drivers that only + * need to call drm_fb_helper_hotplug_event(). + */ +void drm_fb_helper_output_poll_changed(struct drm_device *dev) +{ + drm_fb_helper_hotplug_event(dev->fb_helper); +} +EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); + /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) * but the module doesn't depend on any fb console symbols. At least * attempt to load fbcon to avoid leaving the system without a usable console. diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 279c1035c12d..d63d4c2ac4c8 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -25,7 +25,9 @@ #include <drm/drm_auth.h> #include <drm/drm_framebuffer.h> #include <drm/drm_atomic.h> +#include <drm/drm_print.h> +#include "drm_internal.h" #include "drm_crtc_internal.h" /** @@ -78,11 +80,12 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, src_h > fb_height || src_y > fb_height - src_h) { DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, - src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); + src_y >> 16, ((src_y & 0xffff) * 15625) >> 10, + fb->width, fb->height); return -ENOSPC; } @@ -766,14 +769,18 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) struct drm_plane *plane; struct drm_connector *conn; struct drm_connector_state *conn_state; - int i, ret = 0; + int i, ret; unsigned plane_mask; + bool disable_crtcs = false; - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - +retry_disable: drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(dev); + if (!state) { + ret = -ENOMEM; + goto out; + } state->acquire_ctx = &ctx; retry: @@ -794,7 +801,7 @@ retry: goto unlock; } - if (plane_state->crtc->primary == plane) { + if (disable_crtcs && plane_state->crtc->primary == plane) { struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); @@ -819,6 +826,7 @@ retry: plane->old_fb = plane->fb; } + /* This list is only filled when disable_crtcs is set. */ for_each_new_connector_in_state(state, conn, conn_state, i) { ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); @@ -841,9 +849,15 @@ unlock: drm_atomic_state_put(state); +out: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + if (ret == -EINVAL && !disable_crtcs) { + disable_crtcs = true; + goto retry_disable; + } + return ret; } @@ -957,3 +971,60 @@ int drm_framebuffer_plane_height(int height, return fb_plane_height(height, fb->format, plane); } EXPORT_SYMBOL(drm_framebuffer_plane_height); + +void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_framebuffer *fb) +{ + struct drm_format_name_buf format_name; + unsigned int i; + + drm_printf_indent(p, indent, "refcount=%u\n", + drm_framebuffer_read_refcount(fb)); + drm_printf_indent(p, indent, "format=%s\n", + drm_get_format_name(fb->format->format, &format_name)); + drm_printf_indent(p, indent, "modifier=0x%llx\n", fb->modifier); + drm_printf_indent(p, indent, "size=%ux%u\n", fb->width, fb->height); + drm_printf_indent(p, indent, "layers:\n"); + + for (i = 0; i < fb->format->num_planes; i++) { + drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i, + drm_framebuffer_plane_width(fb->width, fb, i), + drm_framebuffer_plane_height(fb->height, fb, i)); + drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]); + drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]); + drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i, + fb->obj[i] ? "" : "(null)"); + if (fb->obj[i]) + drm_gem_print_info(p, indent + 2, fb->obj[i]); + } +} + +#ifdef CONFIG_DEBUG_FS +static int drm_framebuffer_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + struct drm_framebuffer *fb; + + mutex_lock(&dev->mode_config.fb_lock); + drm_for_each_fb(fb, dev) { + drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); + drm_framebuffer_print_info(&p, 1, fb); + } + mutex_unlock(&dev->mode_config.fb_lock); + + return 0; +} + +static const struct drm_info_list drm_framebuffer_debugfs_list[] = { + { "framebuffer", drm_framebuffer_info, 0 }, +}; + +int drm_framebuffer_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(drm_framebuffer_debugfs_list, + ARRAY_SIZE(drm_framebuffer_debugfs_list), + minor->debugfs_root, minor); +} +#endif diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 55d6182555c7..01f8d9481211 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -40,6 +40,7 @@ #include <drm/drmP.h> #include <drm/drm_vma_manager.h> #include <drm/drm_gem.h> +#include <drm/drm_print.h> #include "drm_internal.h" /** @file drm_gem.c @@ -348,7 +349,7 @@ EXPORT_SYMBOL_GPL(drm_gem_dumb_map_offset); * @file: drm file-private structure to remove the dumb handle from * @dev: corresponding drm_device * @handle: the dumb handle to remove - * + * * This implements the &drm_driver.dumb_destroy kms driver callback for drivers * which use gem to manage their backing storage. */ @@ -365,7 +366,7 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy); * @file_priv: drm file-private structure to register the handle for * @obj: object to register * @handlep: pointer to return the created handle to the caller - * + * * This expects the &drm_device.object_name_lock to be held already and will * drop it before returning. Used to avoid races in establishing new handles * when importing an object from either an flink name or a dma-buf. @@ -1040,3 +1041,19 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } EXPORT_SYMBOL(drm_gem_mmap); + +void drm_gem_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj) +{ + drm_printf_indent(p, indent, "name=%d\n", obj->name); + drm_printf_indent(p, indent, "refcount=%u\n", + kref_read(&obj->refcount)); + drm_printf_indent(p, indent, "start=%08lx\n", + drm_vma_node_start(&obj->vma_node)); + drm_printf_indent(p, indent, "size=%zu\n", obj->size); + drm_printf_indent(p, indent, "imported=%s\n", + obj->import_attach ? "yes" : "no"); + + if (obj->dev->driver->gem_print_info) + obj->dev->driver->gem_print_info(p, indent, obj); +} diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 020e7668dfab..80a5115c3846 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -397,31 +397,24 @@ unsigned long drm_gem_cma_get_unmapped_area(struct file *filp, EXPORT_SYMBOL_GPL(drm_gem_cma_get_unmapped_area); #endif -#ifdef CONFIG_DEBUG_FS /** - * drm_gem_cma_describe - describe a CMA GEM object for debugfs - * @cma_obj: CMA GEM object - * @m: debugfs file handle + * drm_gem_cma_print_info() - Print &drm_gem_cma_object info for debugfs + * @p: DRM printer + * @indent: Tab indentation level + * @obj: GEM object * - * This function can be used to dump a human-readable representation of the - * CMA GEM object into a synthetic file. + * This function can be used as the &drm_driver->gem_print_info callback. + * It prints paddr and vaddr for use in e.g. debugfs output. */ -void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, - struct seq_file *m) +void drm_gem_cma_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj) { - struct drm_gem_object *obj = &cma_obj->base; - uint64_t off; - - off = drm_vma_node_start(&obj->vma_node); - - seq_printf(m, "%2d (%2d) %08llx %pad %p %zu", - obj->name, kref_read(&obj->refcount), - off, &cma_obj->paddr, cma_obj->vaddr, obj->size); + const struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); - seq_printf(m, "\n"); + drm_printf_indent(p, indent, "paddr=%pad\n", &cma_obj->paddr); + drm_printf_indent(p, indent, "vaddr=%p\n", cma_obj->vaddr); } -EXPORT_SYMBOL_GPL(drm_gem_cma_describe); -#endif +EXPORT_SYMBOL(drm_gem_cma_print_info); /** * drm_gem_cma_prime_get_sg_table - provide a scatter/gather table of pinned @@ -482,8 +475,26 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, { struct drm_gem_cma_object *cma_obj; - if (sgt->nents != 1) - return ERR_PTR(-EINVAL); + if (sgt->nents != 1) { + /* check if the entries in the sg_table are contiguous */ + dma_addr_t next_addr = sg_dma_address(sgt->sgl); + struct scatterlist *s; + unsigned int i; + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + /* + * sg_dma_address(s) is only valid for entries + * that have sg_dma_len(s) != 0 + */ + if (!sg_dma_len(s)) + continue; + + if (sg_dma_address(s) != next_addr) + return ERR_PTR(-EINVAL); + + next_addr = sg_dma_address(s) + sg_dma_len(s); + } + } /* Create a CMA GEM buffer. */ cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index c9d5a6cd4d41..b72242e93ea4 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -111,6 +111,8 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); +void drm_gem_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj); /* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) @@ -178,3 +180,8 @@ int drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, struct drm_file *file_private); int drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, struct drm_file *file_private); + +/* drm_framebuffer.c */ +void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, + const struct drm_framebuffer *fb); +int drm_framebuffer_debugfs_init(struct drm_minor *minor); diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 61a1c8ea74bc..eb86bc3f753b 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -92,7 +92,7 @@ * some basic allocator dumpers for debugging. * * Note that this range allocator is not thread-safe, drivers need to protect - * modifications with their on locking. The idea behind this is that for a full + * modifications with their own locking. The idea behind this is that for a full * memory manager additional data needs to be protected anyway, hence internal * locking would be fully redundant. */ diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 759ed93f4ba8..f1be8cd4e387 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -100,97 +100,6 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, } /** - * drm_plane_helper_check_state() - Check plane state for validity - * @state: plane state to check - * @clip: integer clipping coordinates - * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point - * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point - * @can_position: is it legal to position the plane such that it - * doesn't cover the entire crtc? This will generally - * only be false for primary planes. - * @can_update_disabled: can the plane be updated while the crtc - * is disabled? - * - * Checks that a desired plane update is valid, and updates various - * bits of derived state (clipped coordinates etc.). Drivers that provide - * their own plane handling rather than helper-provided implementations may - * still wish to call this function to avoid duplication of error checking - * code. - * - * RETURNS: - * Zero if update appears valid, error code on failure - */ -int drm_plane_helper_check_state(struct drm_plane_state *state, - const struct drm_rect *clip, - int min_scale, - int max_scale, - bool can_position, - bool can_update_disabled) -{ - struct drm_crtc *crtc = state->crtc; - struct drm_framebuffer *fb = state->fb; - struct drm_rect *src = &state->src; - struct drm_rect *dst = &state->dst; - unsigned int rotation = state->rotation; - int hscale, vscale; - - *src = drm_plane_state_src(state); - *dst = drm_plane_state_dest(state); - - if (!fb) { - state->visible = false; - return 0; - } - - /* crtc should only be NULL when disabling (i.e., !fb) */ - if (WARN_ON(!crtc)) { - state->visible = false; - return 0; - } - - if (!crtc->enabled && !can_update_disabled) { - DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n"); - return -EINVAL; - } - - drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation); - - /* Check scaling */ - hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); - vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); - if (hscale < 0 || vscale < 0) { - DRM_DEBUG_KMS("Invalid scaling of plane\n"); - drm_rect_debug_print("src: ", &state->src, true); - drm_rect_debug_print("dst: ", &state->dst, false); - return -ERANGE; - } - - state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); - - drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); - - if (!state->visible) - /* - * Plane isn't visible; some drivers can handle this - * so we just return success here. Drivers that can't - * (including those that use the primary plane helper's - * update function) will return an error from their - * update_plane handler. - */ - return 0; - - if (!can_position && !drm_rect_equals(dst, clip)) { - DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); - drm_rect_debug_print("dst: ", dst, false); - drm_rect_debug_print("clip: ", clip, false); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(drm_plane_helper_check_state); - -/** * drm_plane_helper_check_update() - Check plane update for validity * @plane: plane object to update * @crtc: owning CRTC of owning plane @@ -230,7 +139,7 @@ int drm_plane_helper_check_update(struct drm_plane *plane, bool can_update_disabled, bool *visible) { - struct drm_plane_state state = { + struct drm_plane_state plane_state = { .plane = plane, .crtc = crtc, .fb = fb, @@ -245,18 +154,22 @@ int drm_plane_helper_check_update(struct drm_plane *plane, .rotation = rotation, .visible = *visible, }; + struct drm_crtc_state crtc_state = { + .crtc = crtc, + .enable = crtc->enabled, + }; int ret; - ret = drm_plane_helper_check_state(&state, clip, - min_scale, max_scale, - can_position, - can_update_disabled); + ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, + clip, min_scale, max_scale, + can_position, + can_update_disabled); if (ret) return ret; - *src = state.src; - *dst = state.dst; - *visible = state.visible; + *src = plane_state.src; + *dst = plane_state.dst; + *visible = plane_state.visible; return 0; } diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 74c466aca622..781518fd88e3 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -23,6 +23,8 @@ * Rob Clark <robdclark@gmail.com> */ +#define DEBUG /* for pr_debug() */ + #include <stdarg.h> #include <linux/seq_file.h> #include <drm/drmP.h> @@ -53,13 +55,57 @@ EXPORT_SYMBOL(__drm_printfn_debug); */ void drm_printf(struct drm_printer *p, const char *f, ...) { - struct va_format vaf; va_list args; va_start(args, f); - vaf.fmt = f; - vaf.va = &args; - p->printfn(p, &vaf); + drm_vprintf(p, f, &args); va_end(args); } EXPORT_SYMBOL(drm_printf); + +#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV" + +void drm_dev_printk(const struct device *dev, const char *level, + unsigned int category, const char *function_name, + const char *prefix, const char *format, ...) +{ + struct va_format vaf; + va_list args; + + if (category != DRM_UT_NONE && !(drm_debug & category)) + return; + + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + if (dev) + dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, + &vaf); + else + printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); + + va_end(args); +} +EXPORT_SYMBOL(drm_dev_printk); + +void drm_printk(const char *level, unsigned int category, + const char *format, ...) +{ + struct va_format vaf; + va_list args; + + if (category != DRM_UT_NONE && !(drm_debug & category)) + return; + + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + printk("%s" "[" DRM_NAME ":%ps]%s %pV", + level, __builtin_return_address(0), + strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf); + + va_end(args); +} +EXPORT_SYMBOL(drm_printk); diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index dc9fd109de14..9f3b1c94802b 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -103,10 +103,11 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - ret = drm_plane_helper_check_state(plane_state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true); + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index f776fc1cc543..9b733c510cbf 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -106,7 +106,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, * callback when a fence has already been set. */ if (syncobj->fence) { - *fence = dma_fence_get(syncobj->fence); + *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock))); ret = 1; } else { *fence = NULL; @@ -168,8 +169,9 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, spin_lock(&syncobj->lock); - old_fence = syncobj->fence; - syncobj->fence = fence; + old_fence = rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock)); + rcu_assign_pointer(syncobj->fence, fence); if (fence != old_fence) { list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) { @@ -659,7 +661,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj, container_of(cb, struct syncobj_wait_entry, syncobj_cb); /* This happens inside the syncobj lock */ - wait->fence = dma_fence_get(syncobj->fence); + wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock))); wake_up_process(wait->task); } diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 3717b3df34a4..32d9bcf5be7f 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -663,14 +663,16 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos), mode->crtc_clock); - /* save this only for debugging purposes */ - ts_etime = ktime_to_timespec64(etime); - ts_vblank_time = ktime_to_timespec64(*vblank_time); /* Subtract time delta from raw timestamp to get final * vblank_time timestamp for end of vblank. */ - etime = ktime_sub_ns(etime, delta_ns); - *vblank_time = etime; + *vblank_time = ktime_sub_ns(etime, delta_ns); + + if ((drm_debug & DRM_UT_VBL) == 0) + return true; + + ts_etime = ktime_to_timespec64(etime); + ts_vblank_time = ktime_to_timespec64(*vblank_time); DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n", pipe, hpos, vpos, diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 28f1226576f8..23c749c05b5a 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -203,21 +203,16 @@ EXPORT_SYMBOL(drm_vma_offset_lookup_locked); int drm_vma_offset_add(struct drm_vma_offset_manager *mgr, struct drm_vma_offset_node *node, unsigned long pages) { - int ret; + int ret = 0; write_lock(&mgr->vm_lock); - if (drm_mm_node_allocated(&node->vm_node)) { - ret = 0; - goto out_unlock; - } + if (!drm_mm_node_allocated(&node->vm_node)) + ret = drm_mm_insert_node(&mgr->vm_addr_space_mm, + &node->vm_node, pages); - ret = drm_mm_insert_node(&mgr->vm_addr_space_mm, &node->vm_node, pages); - if (ret) - goto out_unlock; - -out_unlock: write_unlock(&mgr->vm_lock); + return ret; } EXPORT_SYMBOL(drm_vma_offset_add); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 82d1b7e2febe..a4b75a46f946 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -829,7 +829,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) DRM_INFO("%s: invalid AVI infoframe (%d)\n", __func__, ret); } - ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi, m); + ret = drm_hdmi_vendor_infoframe_from_display_mode(&frm.vendor.hdmi, + &hdata->connector, m); if (!ret) ret = hdmi_vendor_infoframe_pack(&frm.vendor.hdmi, buf, sizeof(buf)); diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 0eaf11c19939..ccb161c73a59 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -395,7 +395,7 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) psb_mmu_clflush(pd->driver, (void *)&v[pt->index]); atomic_set(&pd->driver->needs_tlbflush, 1); } - kunmap_atomic(pt->v); + kunmap_atomic(v); spin_unlock(&pd->driver->lock); psb_mmu_free_pt(pt); return; diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 37a3be71acd9..8f5cc1f471cd 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -527,4 +527,4 @@ module_exit(psb_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 821497dbd3fc..4918efc57b7a 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -36,7 +36,6 @@ #include "mmu.h" #define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others" -#define DRIVER_LICENSE "GPL" #define DRIVER_NAME "gma500" #define DRIVER_DESC "DRM driver for the Intel GMA500, GMA600, GMA3600, GMA3650" diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 127815253a84..cd3f0873bbdd 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1100,7 +1100,6 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 878acc432a4b..e0fffd883b54 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9314,11 +9314,12 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, u32 offset; int ret; - ret = drm_plane_helper_check_state(&plane_state->base, - &plane_state->clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + ret = drm_atomic_helper_check_plane_state(&plane_state->base, + &crtc_state->base, + &plane_state->clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); if (ret) return ret; @@ -12794,10 +12795,11 @@ intel_check_primary_plane(struct intel_plane *plane, can_position = true; } - ret = drm_plane_helper_check_state(&state->base, - &state->clip, - min_scale, max_scale, - can_position, true); + ret = drm_atomic_helper_check_plane_state(&state->base, + &crtc_state->base, + &state->clip, + min_scale, max_scale, + can_position, true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 158438bb0389..65260fb35d2a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5868,7 +5868,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (drm_add_edid_modes(connector, edid)) { drm_mode_connector_update_edid_property(connector, edid); - drm_edid_to_eld(connector, edid); } else { kfree(edid); edid = ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4dea833f9d1b..e039702c1907 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -513,12 +513,14 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) { union hdmi_infoframe frame; int ret; ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, + conn_state->connector, &crtc_state->base.adjusted_mode); if (ret < 0) return; @@ -585,7 +587,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, crtc_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state) @@ -726,7 +728,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, crtc_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } static void cpt_set_infoframes(struct drm_encoder *encoder, @@ -769,7 +771,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, crtc_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } static void vlv_set_infoframes(struct drm_encoder *encoder, @@ -822,7 +824,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, crtc_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } static void hsw_set_infoframes(struct drm_encoder *encoder, @@ -855,7 +857,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_avi_infoframe(encoder, crtc_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state); + intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 28a778b785ac..4e43f873c889 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -57,7 +57,6 @@ int intel_connector_update_modes(struct drm_connector *connector, drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); intel_connector_update_eld_conn_type(connector); diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 247c60e6bed2..5a67daedcf4d 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -342,10 +342,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, clip.y1 = 0; clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - ret = drm_plane_helper_check_state(state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - can_position, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + can_position, true); if (ret) return ret; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 6f121891430f..5ef898b93d8d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -111,10 +111,10 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->mode.hdisplay; clip.y2 = crtc_state->mode.vdisplay; - return drm_plane_helper_check_state(state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); } static void mtk_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 3ff502771ba2..59a11026dceb 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1054,7 +1054,8 @@ static int mtk_hdmi_setup_vendor_specific_infoframe(struct mtk_hdmi *hdmi, u8 buffer[10]; ssize_t err; - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode); + err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, + &hdmi->conn, mode); if (err) { dev_err(hdmi->dev, "Failed to get vendor infoframe from mode: %zd\n", err); @@ -1222,7 +1223,6 @@ static int mtk_hdmi_conn_get_modes(struct drm_connector *conn) drm_mode_connector_update_edid_property(conn, edid); ret = drm_add_edid_modes(conn, edid); - drm_edid_to_eld(conn, edid); kfree(edid); return ret; } diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 17e96fa47868..d0a6ac8390f3 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -61,10 +61,10 @@ static int meson_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->mode.hdisplay; clip.y2 = crtc_state->mode.vdisplay; - return drm_plane_helper_check_state(state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); } /* Takes a fixed 16.16 number and converts it to integer. */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index be50445f9901..ee41423baeb7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -327,8 +327,9 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state, min_scale = FRAC_16_16(1, 8); max_scale = FRAC_16_16(8, 1); - ret = drm_plane_helper_check_state(state, &clip, min_scale, - max_scale, true, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + min_scale, max_scale, + true, true); if (ret) return ret; @@ -505,8 +506,9 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane, min_scale = FRAC_16_16(1, 8); max_scale = FRAC_16_16(8, 1); - ret = drm_plane_helper_check_state(state, &clip, min_scale, - max_scale, true, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + min_scale, max_scale, + true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 584466ef688f..65336948e807 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1143,10 +1143,11 @@ nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, { int ret; - ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, + &asyw->clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); asyh->curs.visible = asyw->state.visible; if (ret || !asyh->curs.visible) return ret; @@ -1432,10 +1433,11 @@ nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, if (!fb->format->depth) return -EINVAL; - ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true); + ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, + &asyw->clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); if (ret) return ret; @@ -2688,7 +2690,6 @@ nv50_audio_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) if (!drm_detect_monitor_audio(nv_connector->edid)) return; - drm_edid_to_eld(&nv_connector->base, nv_connector->edid); memcpy(args.data, nv_connector->base.eld, sizeof(args.data)); nvif_mthd(disp->disp, 0, &args, @@ -2755,7 +2756,8 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17); } - ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, mode); + ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, + &nv_connector->base, mode); if (!ret) { /* We have a Vendor InfoFrame, populate it to the display */ args.pwr.vendor_infoframe_length @@ -3064,10 +3066,8 @@ nv50_mstc_get_modes(struct drm_connector *connector) mstc->edid = drm_dp_mst_get_edid(&mstc->connector, mstc->port->mgr, mstc->port); drm_mode_connector_update_edid_property(&mstc->connector, mstc->edid); - if (mstc->edid) { + if (mstc->edid) ret = drm_add_edid_modes(&mstc->connector, mstc->edid); - drm_edid_to_eld(&mstc->connector, mstc->edid); - } if (!mstc->connector.display_info.bpc) mstc->connector.display_info.bpc = 8; diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c index 890fd6ff397c..d964d454e4ae 100644 --- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c @@ -221,7 +221,7 @@ static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel) return container_of(panel, struct rpi_touchscreen, base); } -static u8 rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) +static int rpi_touchscreen_i2c_read(struct rpi_touchscreen *ts, u8 reg) { return i2c_smbus_read_byte_data(ts->i2c, reg); } diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index b7c4709f7b34..5591984a392b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1356,6 +1356,38 @@ static const struct panel_desc lg_lp129qe = { }, }; +static const struct drm_display_mode mitsubishi_aa070mc01_mode = { + .clock = 30400, + .hdisplay = 800, + .hsync_start = 800 + 0, + .hsync_end = 800 + 1, + .htotal = 800 + 0 + 1 + 160, + .vdisplay = 480, + .vsync_start = 480 + 0, + .vsync_end = 480 + 48 + 1, + .vtotal = 480 + 48 + 1 + 0, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, +}; + +static const struct panel_desc mitsubishi_aa070mc01 = { + .modes = &mitsubishi_aa070mc01_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 152, + .height = 91, + }, + + .delay = { + .enable = 200, + .unprepare = 200, + .disable = 400, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, +}; + static const struct display_timing nec_nl12880bc20_05_timing = { .pixelclock = { 67000000, 71000000, 75000000 }, .hactive = { 1280, 1280, 1280 }, @@ -1837,6 +1869,30 @@ static const struct panel_desc tianma_tm070jdhg30 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, }; +static const struct display_timing tianma_tm070rvhg71_timing = { + .pixelclock = { 27700000, 29200000, 39600000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 12, 40, 212 }, + .hback_porch = { 88, 88, 88 }, + .hsync_len = { 1, 1, 40 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 1, 13, 88 }, + .vback_porch = { 32, 32, 32 }, + .vsync_len = { 1, 1, 3 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc tianma_tm070rvhg71 = { + .timings = &tianma_tm070rvhg71_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 154, + .height = 86, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, +}; + static const struct drm_display_mode toshiba_lt089ac29000_mode = { .clock = 79500, .hdisplay = 1280, @@ -2086,6 +2142,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "lg,lp129qe", .data = &lg_lp129qe, }, { + .compatible = "mitsubishi,aa070mc01-ca1", + .data = &mitsubishi_aa070mc01, + }, { .compatible = "nec,nl12880bc20-05", .data = &nec_nl12880bc20_05, }, { @@ -2143,6 +2202,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "tianma,tm070jdhg30", .data = &tianma_tm070jdhg30, }, { + .compatible = "tianma,tm070rvhg71", + .data = &tianma_tm070rvhg71, + }, { .compatible = "toshiba,lt089ac29000", .data = &toshiba_lt089ac29000, }, { diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index ab4823875311..586ecd6e0e45 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -123,11 +123,8 @@ int qxl_mmap(struct file *filp, struct vm_area_struct *vma) struct qxl_device *qdev; int r; - if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { - pr_info("%s: vma->vm_pgoff (%ld) < DRM_FILE_PAGE_OFFSET\n", - __func__, vma->vm_pgoff); + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) return -EINVAL; - } file_priv = filp->private_data; qdev = file_priv->minor->dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 59dcefb2df3b..5012f5e47a1e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -392,7 +392,6 @@ static int radeon_ddc_get_modes(struct drm_connector *connector) if (radeon_connector->edid) { drm_mode_connector_update_edid_property(connector, radeon_connector->edid); ret = drm_add_edid_modes(connector, radeon_connector->edid); - drm_edid_to_eld(connector, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(connector, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 2917ea1b667e..183b4b482138 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -197,7 +197,6 @@ static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector) if (radeon_connector->edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); - drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 93b7102dd008..1262120a3834 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -267,11 +267,10 @@ static struct drm_encoder_funcs rockchip_dp_encoder_funcs = { .destroy = rockchip_dp_drm_encoder_destroy, }; -static int rockchip_dp_init(struct rockchip_dp_device *dp) +static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) { struct device *dev = dp->dev; struct device_node *np = dev->of_node; - int ret; dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(dp->grf)) { @@ -301,19 +300,6 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) return PTR_ERR(dp->rst); } - ret = clk_prepare_enable(dp->pclk); - if (ret < 0) { - DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); - return ret; - } - - ret = rockchip_dp_pre_init(dp); - if (ret < 0) { - DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret); - clk_disable_unprepare(dp->pclk); - return ret; - } - return 0; } @@ -359,10 +345,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, if (!dp_data) return -ENODEV; - ret = rockchip_dp_init(dp); - if (ret < 0) - return ret; - dp->data = dp_data; dp->drm_dev = drm_dev; @@ -396,7 +378,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, rockchip_drm_psr_unregister(&dp->encoder); analogix_dp_unbind(dev, master, data); - clk_disable_unprepare(dp->pclk); } static const struct component_ops rockchip_dp_component_ops = { @@ -412,7 +393,7 @@ static int rockchip_dp_probe(struct platform_device *pdev) int ret; ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); - if (ret) + if (ret < 0) return ret; dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); @@ -420,9 +401,12 @@ static int rockchip_dp_probe(struct platform_device *pdev) return -ENOMEM; dp->dev = dev; - dp->plat_data.panel = panel; + ret = rockchip_dp_of_probe(dp); + if (ret < 0) + return ret; + /* * We just use the drvdata until driver run into component * add function, and then we would set drvdata to null, so diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 275844d0d0ec..ec999d9f15f6 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -276,11 +276,9 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) dp->sink_has_audio = drm_detect_monitor_audio(edid); ret = drm_add_edid_modes(connector, edid); - if (ret) { + if (ret) drm_mode_connector_update_edid_property(connector, edid); - drm_edid_to_eld(connector, edid); - } } mutex_unlock(&dp->lock); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index ee584d87111f..fab30927a889 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -282,6 +282,7 @@ static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi, int rc; rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, + &hdmi->connector, mode); return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 19128b4dea54..ba7505292b78 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -659,9 +659,9 @@ static int vop_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - ret = drm_plane_helper_check_state(state, &clip, - min_scale, max_scale, - true, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + min_scale, max_scale, + true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 4a39049e901a..2e4eea3459fe 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -149,6 +149,34 @@ static const struct vop_data rk3036_vop = { .win_size = ARRAY_SIZE(rk3036_vop_win_data), }; +static const struct vop_win_phy rk3126_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1), + .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6), + .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19), + .dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), +}; + +static const struct vop_win_data rk3126_vop_win_data[] = { + { .base = 0x00, .phy = &rk3036_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3126_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_data rk3126_vop = { + .intr = &rk3036_intr, + .common = &rk3036_common, + .modeset = &rk3036_modeset, + .output = &rk3036_output, + .win = rk3126_vop_win_data, + .win_size = ARRAY_SIZE(rk3126_vop_win_data), +}; + static const struct vop_scl_extension rk3288_win_full_scl_ext = { .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), @@ -510,6 +538,8 @@ static const struct vop_data rk3328_vop = { static const struct of_device_id vop_driver_dt_match[] = { { .compatible = "rockchip,rk3036-vop", .data = &rk3036_vop }, + { .compatible = "rockchip,rk3126-vop", + .data = &rk3126_vop }, { .compatible = "rockchip,rk3288-vop", .data = &rk3288_vop }, { .compatible = "rockchip,rk3368-vop", diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 4a4799ff65de..f81b510ea99c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -878,4 +878,10 @@ #define RK3036_HWC_LUT_ADDR 0x800 /* rk3036 register definition end */ +/* rk3126 register definition */ +#define RK3126_WIN1_MST 0x4c +#define RK3126_WIN1_DSP_INFO 0x50 +#define RK3126_WIN1_DSP_ST 0x54 +/* rk3126 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */ diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c index 86eb4c185a28..7cc935d7b7aa 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/selftests/test-drm_mm.c @@ -682,6 +682,8 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); DRM_MM_BUG_ON(!drm_mm_clean(&mm)); + + cond_resched(); } ret = 0; @@ -944,6 +946,8 @@ static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); DRM_MM_BUG_ON(!drm_mm_clean(&mm)); + + cond_resched(); } ret = 0; @@ -1068,6 +1072,7 @@ static int igt_align(void *ignored) drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); DRM_MM_BUG_ON(!drm_mm_clean(&mm)); + cond_resched(); } diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index acd72865feac..cca4b3c9aeb5 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig @@ -8,5 +8,6 @@ config DRM_STI select DRM_PANEL select FW_LOADER select SND_SOC_HDMI_CODEC if SND_SOC + select OF help Choose this option to enable DRM on STM stiH4xx chipset diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 30f02d2fdd03..4ea1cc1c032e 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -515,7 +515,9 @@ static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi) DRM_DEBUG_DRIVER("\n"); - ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode); + ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, + hdmi->drm_connector, + mode); if (ret < 0) { /* * Going into that statement does not means vendor infoframe @@ -976,7 +978,6 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) count = drm_add_edid_modes(connector, edid); drm_mode_connector_update_edid_property(connector, edid); - drm_edid_to_eld(connector, edid); kfree(edid); return count; @@ -1414,6 +1415,11 @@ static int sti_hdmi_probe(struct platform_device *pdev) init_waitqueue_head(&hdmi->wait_event); hdmi->irq = platform_get_irq_byname(pdev, "irq"); + if (hdmi->irq < 0) { + DRM_ERROR("Cannot get HDMI irq\n"); + ret = hdmi->irq; + goto release_adapter; + } ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq, hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi); diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index 2dcba1d3a122..3aa2fa6f2228 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/notifier.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <drm/drmP.h> @@ -72,8 +73,6 @@ #define AWG_DELAY_ED (-8) #define AWG_DELAY_SD (-7) -static LIST_HEAD(vtg_lookup); - /* * STI VTG register offset structure * @@ -123,42 +122,31 @@ struct sti_vtg_sync_params { /** * STI VTG structure * - * @dev: pointer to device driver - * @np: device node * @regs: register mapping * @sync_params: synchronisation parameters used to generate timings * @irq: VTG irq * @irq_status: store the IRQ status value * @notifier_list: notifier callback * @crtc: the CRTC for vblank event - * @link: List node to link the structure in lookup list */ struct sti_vtg { - struct device *dev; - struct device_node *np; void __iomem *regs; struct sti_vtg_sync_params sync_params[VTG_MAX_SYNC_OUTPUT]; int irq; u32 irq_status; struct raw_notifier_head notifier_list; struct drm_crtc *crtc; - struct list_head link; }; -static void vtg_register(struct sti_vtg *vtg) -{ - list_add_tail(&vtg->link, &vtg_lookup); -} - struct sti_vtg *of_vtg_find(struct device_node *np) { - struct sti_vtg *vtg; + struct platform_device *pdev; - list_for_each_entry(vtg, &vtg_lookup, link) { - if (vtg->np == np) - return vtg; - } - return NULL; + pdev = of_find_device_by_node(np); + if (!pdev) + return NULL; + + return (struct sti_vtg *)platform_get_drvdata(pdev); } static void vtg_reset(struct sti_vtg *vtg) @@ -397,9 +385,6 @@ static int vtg_probe(struct platform_device *pdev) if (!vtg) return -ENOMEM; - vtg->dev = dev; - vtg->np = pdev->dev.of_node; - /* Get Memory ressources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -428,16 +413,10 @@ static int vtg_probe(struct platform_device *pdev) return ret; } - vtg_register(vtg); platform_set_drvdata(pdev, vtg); - DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev)); - - return 0; -} + DRM_INFO("%s %s\n", __func__, dev_name(dev)); -static int vtg_remove(struct platform_device *pdev) -{ return 0; } @@ -454,7 +433,6 @@ struct platform_driver sti_vtg_driver = { .of_match_table = vtg_of_match, }, .probe = vtg_probe, - .remove = vtg_remove, }; MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index e5b6310240fe..3e8b9ed7e8b3 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -129,7 +129,7 @@ static int dsi_pll_get_params(int clkin_khz, int clkout_khz, int fvco_min, fvco_max, delta, best_delta; /* all in khz */ /* Early checks preventing division by 0 & odd results */ - if ((clkin_khz <= 0) || (clkout_khz <= 0)) + if (clkin_khz <= 0 || clkout_khz <= 0) return -EINVAL; fvco_min = LANE_MIN_KBPS * 2 * ODF_MAX; @@ -155,7 +155,7 @@ static int dsi_pll_get_params(int clkin_khz, int clkout_khz, for (o = ODF_MIN; o <= ODF_MAX; o *= 2) { n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz); /* Check ndiv according to vco range */ - if ((n < n_min) || (n > n_max)) + if (n < n_min || n > n_max) continue; /* Check if new delta is better & saves parameters */ delta = dsi_pll_get_clkout_khz(clkin_khz, i, n, o) - @@ -342,7 +342,7 @@ static struct platform_driver dw_mipi_dsi_stm_driver = { .remove = dw_mipi_dsi_stm_remove, .driver = { .of_match_table = dw_mipi_dsi_stm_dt_ids, - .name = "dw_mipi_dsi-stm", + .name = "stm32-display-dsi", }, }; diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 735c9081202a..35e884239f60 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -33,6 +33,8 @@ #define MAX_IRQ 4 +#define MAX_ENDPOINTS 2 + #define HWVER_10200 0x010200 #define HWVER_10300 0x010300 #define HWVER_20101 0x020101 @@ -556,7 +558,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, src_h = state->src_h >> 16; /* Reject scaling */ - if ((src_w != state->crtc_w) || (src_h != state->crtc_h)) { + if (src_w != state->crtc_w || src_h != state->crtc_h) { DRM_ERROR("Scaling is not supported"); return -EINVAL; } @@ -856,18 +858,33 @@ int ltdc_load(struct drm_device *ddev) struct ltdc_device *ldev = ddev->dev_private; struct device *dev = ddev->dev; struct device_node *np = dev->of_node; - struct drm_bridge *bridge; - struct drm_panel *panel; + struct drm_bridge *bridge[MAX_ENDPOINTS] = {NULL}; + struct drm_panel *panel[MAX_ENDPOINTS] = {NULL}; struct drm_crtc *crtc; struct reset_control *rstc; struct resource *res; - int irq, ret, i; + int irq, ret, i, endpoint_not_ready = -ENODEV; DRM_DEBUG_DRIVER("\n"); - ret = drm_of_find_panel_or_bridge(np, 0, 0, &panel, &bridge); - if (ret) - return ret; + /* Get endpoints if any */ + for (i = 0; i < MAX_ENDPOINTS; i++) { + ret = drm_of_find_panel_or_bridge(np, 0, i, &panel[i], + &bridge[i]); + + /* + * If at least one endpoint is ready, continue probing, + * else if at least one endpoint is -EPROBE_DEFER and + * there is no previous ready endpoints, defer probing. + */ + if (!ret) + endpoint_not_ready = 0; + else if (ret == -EPROBE_DEFER && endpoint_not_ready) + endpoint_not_ready = -EPROBE_DEFER; + } + + if (endpoint_not_ready) + return endpoint_not_ready; rstc = devm_reset_control_get_exclusive(dev, NULL); @@ -928,19 +945,25 @@ int ltdc_load(struct drm_device *ddev) DRM_INFO("ltdc hw version 0x%08x - ready\n", ldev->caps.hw_version); - if (panel) { - bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DPI); - if (IS_ERR(bridge)) { - DRM_ERROR("Failed to create panel-bridge\n"); - ret = PTR_ERR(bridge); - goto err; + /* Add endpoints panels or bridges if any */ + for (i = 0; i < MAX_ENDPOINTS; i++) { + if (panel[i]) { + bridge[i] = drm_panel_bridge_add(panel[i], + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(bridge[i])) { + DRM_ERROR("panel-bridge endpoint %d\n", i); + ret = PTR_ERR(bridge[i]); + goto err; + } } - } - ret = ltdc_encoder_init(ddev, bridge); - if (ret) { - DRM_ERROR("Failed to init encoder\n"); - goto err; + if (bridge[i]) { + ret = ltdc_encoder_init(ddev, bridge[i]); + if (ret) { + DRM_ERROR("init encoder endpoint %d\n", i); + goto err; + } + } } crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL); @@ -968,7 +991,8 @@ int ltdc_load(struct drm_device *ddev) return 0; err: - drm_panel_bridge_remove(bridge); + for (i = 0; i < MAX_ENDPOINTS; i++) + drm_panel_bridge_remove(bridge[i]); clk_disable_unprepare(ldev->pixel_clk); @@ -978,10 +1002,12 @@ err: void ltdc_unload(struct drm_device *ddev) { struct ltdc_device *ldev = ddev->dev_private; + int i; DRM_DEBUG_DRIVER("\n"); - drm_of_panel_bridge_remove(ddev->dev->of_node, 0, 0); + for (i = 0; i < MAX_ENDPOINTS; i++) + drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); clk_disable_unprepare(ldev->pixel_clk); } diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 24a5ef4f5bb8..fc70351b9017 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -491,8 +491,8 @@ static int tegra_plane_state_add(struct tegra_plane *plane, clip.y2 = crtc_state->mode.vdisplay; /* Check plane state for visibility and calculate clipping bounds */ - err = drm_plane_helper_check_state(state, &clip, 0, INT_MAX, - true, true); + err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + 0, INT_MAX, true, true); if (err < 0) return err; diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 1cfbacea8113..24f8a3b712b4 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -39,7 +39,6 @@ int tegra_output_connector_get_modes(struct drm_connector *connector) if (edid) { err = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 72ce063aa0d8..bc4feb3a84b9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -507,7 +507,6 @@ static int tilcdc_mm_show(struct seq_file *m, void *arg) static struct drm_info_list tilcdc_debugfs_list[] = { { "regs", tilcdc_regs_show, 0 }, { "mm", tilcdc_mm_show, 0 }, - { "fb", drm_fb_cma_debugfs_show, 0 }, }; static int tilcdc_debugfs_init(struct drm_minor *minor) @@ -541,6 +540,7 @@ static struct drm_driver tilcdc_driver = { .lastclose = tilcdc_lastclose, .irq_handler = tilcdc_irq, .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_print_info = drm_gem_cma_print_info, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c index bd6cce093a85..bf96072d1b97 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c @@ -414,11 +414,9 @@ tinydrm_dbg_spi_print(struct spi_device *spi, struct spi_transfer *tr, void _tinydrm_dbg_spi_message(struct spi_device *spi, struct spi_message *m) { struct spi_transfer *tmp; - struct list_head *pos; int i = 0; - list_for_each(pos, &m->transfers) { - tmp = list_entry(pos, struct spi_transfer, transfer_list); + list_for_each_entry(tmp, &m->transfers, transfer_list) { if (tmp->tx_buf) tinydrm_dbg_spi_print(spi, tmp, tmp->tx_buf, i, true); diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index d43e992ab432..347f9b226f26 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c @@ -961,10 +961,6 @@ static const struct file_operations mipi_dbi_debugfs_command_fops = { .write = mipi_dbi_debugfs_command_write, }; -static const struct drm_info_list mipi_dbi_debugfs_list[] = { - { "fb", drm_fb_cma_debugfs_show, 0 }, -}; - /** * mipi_dbi_debugfs_init - Create debugfs entries * @minor: DRM minor @@ -987,9 +983,7 @@ int mipi_dbi_debugfs_init(struct drm_minor *minor) debugfs_create_file("command", mode, minor->debugfs_root, mipi, &mipi_dbi_debugfs_command_fops); - return drm_debugfs_create_files(mipi_dbi_debugfs_list, - ARRAY_SIZE(mipi_dbi_debugfs_list), - minor->debugfs_root, minor); + return 0; } EXPORT_SYMBOL(mipi_dbi_debugfs_init); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 0b2088264039..984501e3f0b0 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -287,7 +287,6 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); kfree(edid); return ret; @@ -695,7 +694,22 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) } } +static enum drm_mode_status +vc4_hdmi_encoder_mode_valid(struct drm_encoder *crtc, + const struct drm_display_mode *mode) +{ + /* HSM clock must be 108% of the pixel clock. Additionally, + * the AXI clock needs to be at least 25% of pixel clock, but + * HSM ends up being the limiting factor. + */ + if (mode->clock > HSM_CLOCK_FREQ / (1000 * 108 / 100)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { + .mode_valid = vc4_hdmi_encoder_mode_valid, .disable = vc4_hdmi_encoder_disable, .enable = vc4_hdmi_encoder_enable, }; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 423a23ed8fc2..515f97997624 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -86,7 +86,6 @@ static const struct hvs_format { u32 hvs; /* HVS_FORMAT_* */ u32 pixel_order; bool has_alpha; - bool flip_cbcr; } hvs_formats[] = { { .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, @@ -121,30 +120,52 @@ static const struct hvs_format { .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false, }, { + .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, + .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false, + }, + { + .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, + .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false, + }, + { .drm = DRM_FORMAT_YUV422, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCBCR, }, { .drm = DRM_FORMAT_YVU422, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, - .flip_cbcr = true, + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, }, { .drm = DRM_FORMAT_YUV420, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCBCR, }, { .drm = DRM_FORMAT_YVU420, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, - .flip_cbcr = true, + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, }, { .drm = DRM_FORMAT_NV12, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCBCR, + }, + { + .drm = DRM_FORMAT_NV21, + .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, }, { .drm = DRM_FORMAT_NV16, .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCBCR, + }, + { + .drm = DRM_FORMAT_NV61, + .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, }, }; @@ -617,15 +638,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * The pointers may be any byte address. */ vc4_state->ptr0_offset = vc4_state->dlist_count; - if (!format->flip_cbcr) { - for (i = 0; i < num_planes; i++) - vc4_dlist_write(vc4_state, vc4_state->offsets[i]); - } else { - WARN_ON_ONCE(num_planes != 3); - vc4_dlist_write(vc4_state, vc4_state->offsets[0]); - vc4_dlist_write(vc4_state, vc4_state->offsets[2]); - vc4_dlist_write(vc4_state, vc4_state->offsets[1]); - } + for (i = 0; i < num_planes; i++) + vc4_dlist_write(vc4_state, vc4_state->offsets[i]); /* Pointer Context Word 0/1/2: Written by the HVS */ for (i = 0; i < num_planes; i++) diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h index 9873942ca8f4..6d1ae834484c 100644 --- a/drivers/gpu/drm/via/via_drv.h +++ b/drivers/gpu/drm/via/via_drv.h @@ -74,9 +74,9 @@ typedef struct drm_via_private { volatile uint32_t *last_pause_ptr; volatile uint32_t *hw_addr_ptr; drm_via_ring_buffer_t ring; - struct timeval last_vblank; + ktime_t last_vblank; int last_vblank_valid; - unsigned usec_per_vblank; + ktime_t nsec_per_vblank; atomic_t vbl_received; drm_via_state_t hc_state; char pci_buf[VIA_PCI_BUF_SIZE]; diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index ea8172c747a2..c96830ccc0ec 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -88,13 +88,6 @@ static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; -static unsigned time_diff(struct timeval *now, struct timeval *then) -{ - return (now->tv_usec >= then->tv_usec) ? - now->tv_usec - then->tv_usec : - 1000000 - (then->tv_usec - now->tv_usec); -} - u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { drm_via_private_t *dev_priv = dev->dev_private; @@ -111,7 +104,7 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg) drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; int handled = 0; - struct timeval cur_vblank; + ktime_t cur_vblank; drm_via_irq_t *cur_irq = dev_priv->via_irqs; int i; @@ -119,18 +112,18 @@ irqreturn_t via_driver_irq_handler(int irq, void *arg) if (status & VIA_IRQ_VBLANK_PENDING) { atomic_inc(&dev_priv->vbl_received); if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { - do_gettimeofday(&cur_vblank); + cur_vblank = ktime_get(); if (dev_priv->last_vblank_valid) { - dev_priv->usec_per_vblank = - time_diff(&cur_vblank, - &dev_priv->last_vblank) >> 4; + dev_priv->nsec_per_vblank = + ktime_sub(cur_vblank, + dev_priv->last_vblank) >> 4; } dev_priv->last_vblank = cur_vblank; dev_priv->last_vblank_valid = 1; } if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { - DRM_DEBUG("US per vblank is: %u\n", - dev_priv->usec_per_vblank); + DRM_DEBUG("nsec per vblank is: %llu\n", + ktime_to_ns(dev_priv->nsec_per_vblank)); } drm_handle_vblank(dev, 0); handled = 1; @@ -350,7 +343,7 @@ void via_driver_irq_uninstall(struct drm_device *dev) int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_via_irqwait_t *irqwait = data; - struct timeval now; + struct timespec64 now; int ret = 0; drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; drm_via_irq_t *cur_irq = dev_priv->via_irqs; @@ -384,9 +377,9 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence, &irqwait->request.sequence); - do_gettimeofday(&now); + ktime_get_ts64(&now); irqwait->reply.tval_sec = now.tv_sec; - irqwait->reply.tval_usec = now.tv_usec; + irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC; return ret; } diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 41b0930f7968..19114a3c5ee4 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -71,7 +71,19 @@ virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer *fb, return virtio_gpu_surface_dirty(virtio_gpu_fb, clips, num_clips); } +static int +virtio_gpu_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct virtio_gpu_framebuffer *virtio_gpu_fb = + to_virtio_gpu_framebuffer(fb); + + return drm_gem_handle_create(file_priv, virtio_gpu_fb->obj, handle); +} + static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = { + .create_handle = virtio_gpu_framebuffer_create_handle, .destroy = virtio_gpu_user_framebuffer_destroy, .dirty = virtio_gpu_framebuffer_surface_dirty, }; diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 0528edb4a2bf..461f81aa1bbe 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -261,7 +261,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, ret = virtio_gpu_object_attach(vgdev, qobj, res_id, NULL); } else { /* use a gem reference since unref list undoes them */ - drm_gem_object_reference(&qobj->gem_base); + drm_gem_object_get(&qobj->gem_base); mainbuf.bo = &qobj->tbo; list_add(&mainbuf.head, &validate_list); diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 6400506a06b0..65060c08522d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -272,20 +272,18 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_fpriv *vfpriv; uint32_t id; - char dbgname[64], tmpname[TASK_COMM_LEN]; + char dbgname[TASK_COMM_LEN]; /* can't create contexts without 3d renderer */ if (!vgdev->has_virgl_3d) return 0; - get_task_comm(tmpname, current); - snprintf(dbgname, sizeof(dbgname), "%s", tmpname); - dbgname[63] = 0; /* allocate a virt GPU context for this opener */ vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL); if (!vfpriv) return -ENOMEM; + get_task_comm(dbgname, current); virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id); vfpriv->ctx_id = id; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0545740b3724..a2a93d7e2a04 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -441,31 +441,23 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { + struct drm_crtc_state *crtc_state = NULL; struct drm_framebuffer *new_fb = state->fb; - bool visible; - - struct drm_rect src = { - .x1 = state->src_x, - .y1 = state->src_y, - .x2 = state->src_x + state->src_w, - .y2 = state->src_y + state->src_h, - }; - struct drm_rect dest = { - .x1 = state->crtc_x, - .y1 = state->crtc_y, - .x2 = state->crtc_x + state->crtc_w, - .y2 = state->crtc_y + state->crtc_h, - }; - struct drm_rect clip = dest; + struct drm_rect clip = {}; int ret; - ret = drm_plane_helper_check_update(plane, state->crtc, new_fb, - &src, &dest, &clip, - DRM_MODE_ROTATE_0, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true, &visible); + if (state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); + + if (crtc_state && crtc_state->enable) { + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + } + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); if (!ret && new_fb) { struct drm_crtc *crtc = state->crtc; @@ -476,12 +468,6 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, vcs = vmw_connector_state_to_vcs(du->connector.state); - if ((dest.x2 > new_fb->width || - dest.y2 > new_fb->height)) { - DRM_ERROR("CRTC area outside of framebuffer\n"); - return -EINVAL; - } - /* Only one active implicit framebuffer at a time. */ mutex_lock(&dev_priv->global_kms_state_mutex); if (vcs->is_implicit && dev_priv->implicit_fb && diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index b8abb1b496ff..13ea90f7a185 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -108,6 +108,7 @@ static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi, int ret; ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, + &hdmi->connector, mode); if (ret) { DRM_DEV_ERROR(hdmi->dev, "failed to get vendor infoframe: %d\n", diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index 18e763493264..68fd2e2dc78a 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c @@ -80,9 +80,9 @@ static int zx_vl_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - return drm_plane_helper_check_state(plane_state, &clip, - min_scale, max_scale, - true, true); + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + &clip, min_scale, max_scale, + true, true); } static int zx_vl_get_fmt(uint32_t format) @@ -315,10 +315,11 @@ static int zx_gl_plane_atomic_check(struct drm_plane *plane, clip.x2 = crtc_state->adjusted_mode.hdisplay; clip.y2 = crtc_state->adjusted_mode.vdisplay; - return drm_plane_helper_check_state(plane_state, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true); + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); } static int zx_gl_get_fmt(uint32_t format) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 1cf907ecded4..111a0ab6280a 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -321,6 +321,17 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) } EXPORT_SYMBOL(hdmi_vendor_infoframe_init); +static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame) +{ + /* for side by side (half) we also need to provide 3D_Ext_Data */ + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) + return 6; + else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) + return 5; + else + return 4; +} + /** * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer * @frame: HDMI infoframe @@ -341,19 +352,11 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, u8 *ptr = buffer; size_t length; - /* empty info frame */ - if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID) - return -EINVAL; - /* only one of those can be supplied */ if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) return -EINVAL; - /* for side by side (half) we also need to provide 3D_Ext_Data */ - if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) - frame->length = 6; - else - frame->length = 5; + frame->length = hdmi_vendor_infoframe_length(frame); length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; @@ -372,14 +375,16 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, ptr[5] = 0x0c; ptr[6] = 0x00; - if (frame->vic) { - ptr[7] = 0x1 << 5; /* video format */ - ptr[8] = frame->vic; - } else { + if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) { ptr[7] = 0x2 << 5; /* video format */ ptr[8] = (frame->s3d_struct & 0xf) << 4; if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) ptr[9] = (frame->s3d_ext_data & 0xf) << 4; + } else if (frame->vic) { + ptr[7] = 0x1 << 5; /* video format */ + ptr[8] = frame->vic; + } else { + ptr[7] = 0x0 << 5; /* video format */ } hdmi_infoframe_set_checksum(buffer, length); @@ -1165,7 +1170,7 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || ptr[1] != 1 || - (ptr[2] != 5 && ptr[2] != 6)) + (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6)) return -EINVAL; length = ptr[2]; @@ -1193,16 +1198,22 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, hvf->length = length; - if (hdmi_video_format == 0x1) { - hvf->vic = ptr[4]; - } else if (hdmi_video_format == 0x2) { + if (hdmi_video_format == 0x2) { + if (length != 5 && length != 6) + return -EINVAL; hvf->s3d_struct = ptr[4] >> 4; if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) { - if (length == 6) - hvf->s3d_ext_data = ptr[5] >> 4; - else + if (length != 6) return -EINVAL; + hvf->s3d_ext_data = ptr[5] >> 4; } + } else if (hdmi_video_format == 0x1) { + if (length != 5) + return -EINVAL; + hvf->vic = ptr[4]; + } else { + if (length != 4) + return -EINVAL; } return 0; |