From 8faff37409fb47d86c839bb2da9f2cff371a3ef1 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 12 Sep 2018 14:47:35 +0200 Subject: drm/bridge: dw-hdmi: allow forcing vendor phy-type In some IP implementations the reading of the phy-type may be broken. One example are the Rockchip rk3228 and rk3328 socs that use a separate vendor-type phy from Innosilicon but still report the HDMI20_TX type. So allow the glue driver to force the vendor-phy for these cases. In the future it may be necessary to allow forcing other types, but for now we'll keep it simply to the case actually seen in the wild. changes in v3: - only allow forcing vendor type, as suggested by Laurent Signed-off-by: Heiko Stuebner Tested-by: Robin Murphy Reviewed-by: Andrzej Hajda Reviewed-by: Zheng Yang Link: https://patchwork.freedesktop.org/patch/msgid/20180912124740.20343-2-heiko@sntech.de Link: https://patchwork.freedesktop.org/patch/msgid/20180912124740.20343-3-heiko@sntech.de --- include/drm/bridge/dw_hdmi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/drm') diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index ccb5aa8468e0..9c56412bb2cf 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -133,6 +133,7 @@ struct dw_hdmi_plat_data { const struct dw_hdmi_phy_ops *phy_ops; const char *phy_name; void *phy_data; + unsigned int phy_force_vendor; /* Synopsys PHY support */ const struct dw_hdmi_mpll_config *mpll_cfg; -- cgit v1.2.3 From 4db4b85014df7fa3c91a2e9330ca446ac9b3b882 Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Tue, 2 Oct 2018 14:50:55 -0700 Subject: drm: Fix kernel doc for DRM_MODE_PROP_IMMUTABLE This patch explains the DRM_MODE_PROP_IMMUTABLE flag a bit better by telling which function to call if kernel wants to update drm object's immutable properties. Suggested-by: Daniel Vetter Cc: Daniel Vetter Signed-off-by: Manasi Navare Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181002215055.8652-1-manasi.d.navare@intel.com --- include/drm/drm_property.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/drm') diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 5b9efff35d6d..4a0a80d658c7 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -153,7 +153,8 @@ struct drm_property { * userspace. The kernel is allowed to update the value of these * properties. This is generally used to expose probe state to * userspace, e.g. the EDID, or the connector path property on DP - * MST sinks. + * MST sinks. Kernel can update the value of an immutable property + * by calling drm_object_property_set_value(). */ uint32_t flags; -- cgit v1.2.3 From 6b7e2d5c30322e6f30fcffb592615906ce9d3c6a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 2 Oct 2018 13:10:40 +0200 Subject: drm: add drm_connector_attach_edid_property() drm_connector_init doesn't attach the edid property for some connector types, drm_connector_attach_edid_property() can be used to enable the edid property in these cases. Signed-off-by: Gerd Hoffmann Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20181002111041.17053-2-kraxel@redhat.com --- drivers/gpu/drm/drm_connector.c | 23 ++++++++++++++++++++--- include/drm/drm_connector.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 1e40e5decbe9..5d01414ec9f7 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -260,9 +260,7 @@ int drm_connector_init(struct drm_device *dev, if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - drm_object_attach_property(&connector->base, - config->edid_property, - 0); + drm_connector_attach_edid_property(connector); drm_object_attach_property(&connector->base, config->dpms_property, 0); @@ -294,6 +292,25 @@ out_put: } EXPORT_SYMBOL(drm_connector_init); +/** + * drm_connector_attach_edid_property - attach edid property. + * @dev: DRM device + * @connector: the connector + * + * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a + * edid property attached by default. This function can be used to + * explicitly enable the edid property in these cases. + */ +void drm_connector_attach_edid_property(struct drm_connector *connector) +{ + struct drm_mode_config *config = &connector->dev->mode_config; + + drm_object_attach_property(&connector->base, + config->edid_property, + 0); +} +EXPORT_SYMBOL(drm_connector_attach_edid_property); + /** * drm_connector_attach_encoder - attach a connector to an encoder * @connector: connector to attach diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 91a877fa00cb..5b3cf909fd5e 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1084,6 +1084,7 @@ int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type); +void drm_connector_attach_edid_property(struct drm_connector *connector); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); int drm_connector_attach_encoder(struct drm_connector *connector, -- cgit v1.2.3 From 9e37ee7913b44b1fbaea327111ad991c7315d245 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Oct 2018 09:36:36 +0200 Subject: drm/vblank: Remove old-style comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somehow I forgot a few when typing all the shiny new kerneldoc. Drop them. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181005073636.27291-1-daniel.vetter@ffwll.ch --- include/drm/drm_vblank.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index d25a9603ab57..6ad9630d4f48 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -95,7 +95,7 @@ struct drm_vblank_crtc { /** * @queue: Wait queue for vblank waiters. */ - wait_queue_head_t queue; /**< VBLANK wait queue */ + wait_queue_head_t queue; /** * @disable_timer: Disable timer for the delayed vblank disabling * hysteresis logic. Vblank disabling is controlled through the @@ -107,7 +107,7 @@ struct drm_vblank_crtc { /** * @seqlock: Protect vblank count and time. */ - seqlock_t seqlock; /* protects vblank count and time */ + seqlock_t seqlock; /** * @count: Current software vblank counter. @@ -123,7 +123,7 @@ struct drm_vblank_crtc { * this refcount reaches 0 can the hardware interrupt be disabled using * @disable_timer. */ - atomic_t refcount; /* number of users of vblank interruptsper crtc */ + atomic_t refcount; /** * @last: Protected by &drm_device.vbl_lock, used for wraparound handling. */ @@ -136,7 +136,7 @@ struct drm_vblank_crtc { * call drm_crtc_vblank_off() and drm_crtc_vblank_on(), which explicitly * save and restore the vblank count. */ - unsigned int inmodeset; /* Display driver is setting mode */ + unsigned int inmodeset; /** * @pipe: drm_crtc_index() of the &drm_crtc corresponding to this * structure. -- cgit v1.2.3 From 03189d5bf7781086b2df97cdcf53324832840471 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Aug 2018 18:47:48 +0100 Subject: drm: Remove defunct dma_buf_kmap stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 09ea0dfbf972 ("dma-buf: make map_atomic and map function pointers optional"), we no longer need to provide stub no-op functions as the core now provides them directly. References: 09ea0dfbf972 ("dma-buf: make map_atomic and map function pointers optional") Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Gerd Hoffmann Cc: Alex Deucher Cc: "Christian König" Reviewed-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180807174748.4503-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 2 -- drivers/gpu/drm/drm_prime.c | 30 ------------------------------ include/drm/drm_prime.h | 3 --- 3 files changed, 35 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index e45e929aaab5..3e44d889f7af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -339,8 +339,6 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = { .unmap_dma_buf = drm_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, .begin_cpu_access = amdgpu_gem_begin_cpu_access, - .map = drm_gem_dmabuf_kmap, - .unmap = drm_gem_dmabuf_kunmap, .mmap = drm_gem_dmabuf_mmap, .vmap = drm_gem_dmabuf_vmap, .vunmap = drm_gem_dmabuf_vunmap, diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 3f0205fc0a1a..8d54d51a6b6b 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -433,34 +433,6 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) } EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); -/** - * drm_gem_dmabuf_kmap - map implementation for GEM - * @dma_buf: buffer to be mapped - * @page_num: page number within the buffer - * - * Not implemented. This can be used as the &dma_buf_ops.map callback. - */ -void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) -{ - return NULL; -} -EXPORT_SYMBOL(drm_gem_dmabuf_kmap); - -/** - * drm_gem_dmabuf_kunmap - unmap implementation for GEM - * @dma_buf: buffer to be unmapped - * @page_num: page number within the buffer - * @addr: virtual address of the buffer - * - * Not implemented. This can be used as the &dma_buf_ops.unmap callback. - */ -void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, - void *addr) -{ - -} -EXPORT_SYMBOL(drm_gem_dmabuf_kunmap); - /** * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM * @dma_buf: buffer to be mapped @@ -489,8 +461,6 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { .map_dma_buf = drm_gem_map_dma_buf, .unmap_dma_buf = drm_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, - .map = drm_gem_dmabuf_kmap, - .unmap = drm_gem_dmabuf_kunmap, .mmap = drm_gem_dmabuf_mmap, .vmap = drm_gem_dmabuf_vmap, .vunmap = drm_gem_dmabuf_vunmap, diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index d716d653b096..e2032fbc0f08 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -93,9 +93,6 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir); void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf); void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr); -void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num); -void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, - void *addr); int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma); int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, -- cgit v1.2.3 From 297e30b5d9b6ddaa53da3026b4a762aa22e10fb0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:27 +0200 Subject: drm/atomic-helper: Unexport drm_atomic_helper_best_encoder It's the default. The exported version was kinda a transition state, before we made this the default. To stop new atomic drivers from using it (instead of just relying on the default) let's unexport it. v2: rename the default implementation to a more fitting name and add a comment (Laurent) Signed-off-by: Daniel Vetter Cc: Gustavo Padovan Cc: Maarten Lankhorst Cc: Sean Paul Cc: David Airlie Cc: VMware Graphics Cc: Sinclair Yeh Cc: Thomas Hellstrom Cc: Archit Taneja Cc: Neil Armstrong Cc: Laurent Pinchart Cc: Hans Verkuil Cc: Daniel Vetter Cc: Russell King Cc: Jernej Skrabec Cc: Jani Nikula Cc: Pierre-Hugues Husson Cc: Fabio Estevam Reviewed-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-3-daniel.vetter@ffwll.ch --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 - drivers/gpu/drm/drm_atomic_helper.c | 32 +++++++++++++------------------ drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 1 - include/drm/drm_atomic_helper.h | 2 -- 6 files changed, 13 insertions(+), 25 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ac37c50d6c4b..5ac979d3450b 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1957,7 +1957,6 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = { static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .get_modes = dw_hdmi_connector_get_modes, - .best_encoder = drm_atomic_helper_best_encoder, }; static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e49b22381048..8acd89d2d1b3 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -92,6 +92,17 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state, } } +/* + * For connectors that support multiple encoders, either the + * .atomic_best_encoder() or .best_encoder() operation must be implemented. + */ +static struct drm_encoder * +pick_single_encoder_for_connector(struct drm_connector *connector) +{ + WARN_ON(connector->encoder_ids[1]); + return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]); +} + static int handle_conflicting_encoders(struct drm_atomic_state *state, bool disable_conflicting_encoders) { @@ -119,7 +130,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, else if (funcs->best_encoder) new_encoder = funcs->best_encoder(connector); else - new_encoder = drm_atomic_helper_best_encoder(connector); + new_encoder = pick_single_encoder_for_connector(connector); if (new_encoder) { if (encoder_mask & drm_encoder_mask(new_encoder)) { @@ -316,7 +327,7 @@ update_connector_routing(struct drm_atomic_state *state, else if (funcs->best_encoder) new_encoder = funcs->best_encoder(connector); else - new_encoder = drm_atomic_helper_best_encoder(connector); + new_encoder = pick_single_encoder_for_connector(connector); if (!new_encoder) { DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n", @@ -3389,23 +3400,6 @@ fail: } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); -/** - * drm_atomic_helper_best_encoder - Helper for - * &drm_connector_helper_funcs.best_encoder callback - * @connector: Connector control structure - * - * This is a &drm_connector_helper_funcs.best_encoder callback helper for - * connectors that support exactly 1 encoder, statically determined at driver - * init time. - */ -struct drm_encoder * -drm_atomic_helper_best_encoder(struct drm_connector *connector) -{ - WARN_ON(connector->encoder_ids[1]); - return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]); -} -EXPORT_SYMBOL(drm_atomic_helper_best_encoder); - /** * DOC: atomic state reset and initialization * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 723578117191..4b5378495eea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -274,7 +274,6 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = { static const struct drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; /* diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index ad0de7f0cd60..4c68ad6f3605 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -389,7 +389,6 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = { static const struct drm_connector_helper_funcs vmw_sou_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index f30e839f7bfd..e28bb08114a5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1037,7 +1037,6 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = { static const struct drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { - .best_encoder = drm_atomic_helper_best_encoder, }; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 657af7b39379..e60c4f0f8827 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -144,8 +144,6 @@ int drm_atomic_helper_page_flip_target( uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx); -struct drm_encoder * -drm_atomic_helper_best_encoder(struct drm_connector *connector); /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); -- cgit v1.2.3 From 9ef8a9dc4b21821d6c397186462fb5e571786b0a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:28 +0200 Subject: drm: Extract drm_atomic_state_helper.[hc] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have a separate overview doc for this, makes sense to untangle it from the overall atomic helpers. v2: Rebase v3: Rebase more. Acked-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-4-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 19 +- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_atomic_helper.c | 566 ---------------------------- drivers/gpu/drm/drm_atomic_state_helper.c | 601 ++++++++++++++++++++++++++++++ include/drm/drm_atomic_helper.h | 44 +-- include/drm/drm_atomic_state_helper.h | 80 ++++ 6 files changed, 698 insertions(+), 615 deletions(-) create mode 100644 drivers/gpu/drm/drm_atomic_state_helper.c create mode 100644 include/drm/drm_atomic_state_helper.h (limited to 'include/drm') diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index f9cfcdcdf024..4b4dc236ef6f 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -59,19 +59,28 @@ Implementing Asynchronous Atomic Commit .. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c :doc: implementing nonblocking commit +Helper Functions Reference +-------------------------- + +.. kernel-doc:: include/drm/drm_atomic_helper.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c + :export: + Atomic State Reset and Initialization ------------------------------------- -.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c :doc: atomic state reset and initialization -Helper Functions Reference --------------------------- +Atomic State Helper Reference +----------------------------- -.. kernel-doc:: include/drm/drm_atomic_helper.h +.. kernel-doc:: include/drm/drm_atomic_state_helper.h :internal: -.. kernel-doc:: drivers/gpu/drm/drm_atomic_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c :export: Simple KMS Helper Reference diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index bc6a16a3c36e..576ba985e138 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -36,7 +36,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ drm_simple_kms_helper.o drm_modeset_helper.o \ - drm_scdc_helper.o drm_gem_framebuffer_helper.o + drm_scdc_helper.o drm_gem_framebuffer_helper.o \ + drm_atomic_state_helper.o drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8acd89d2d1b3..6f66777dca4b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3399,569 +3399,3 @@ fail: return ret; } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); - -/** - * DOC: atomic state reset and initialization - * - * Both the drm core and the atomic helpers assume that there is always the full - * and correct atomic software state for all connectors, CRTCs and planes - * available. Which is a bit a problem on driver load and also after system - * suspend. One way to solve this is to have a hardware state read-out - * infrastructure which reconstructs the full software state (e.g. the i915 - * driver). - * - * The simpler solution is to just reset the software state to everything off, - * which is easiest to do by calling drm_mode_config_reset(). To facilitate this - * the atomic helpers provide default reset implementations for all hooks. - * - * On the upside the precise state tracking of atomic simplifies system suspend - * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe - * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume(). - * For other drivers the building blocks are split out, see the documentation - * for these functions. - */ - -/** - * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs - * @crtc: drm CRTC - * - * Resets the atomic state for @crtc by freeing the state pointer (which might - * be NULL, e.g. at driver load time) and allocating a new empty state object. - */ -void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) -{ - if (crtc->state) - __drm_atomic_helper_crtc_destroy_state(crtc->state); - - kfree(crtc->state); - crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); - - if (crtc->state) - crtc->state->crtc = crtc; -} -EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); - -/** - * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state - * @crtc: CRTC object - * @state: atomic CRTC state - * - * Copies atomic state from a CRTC's current state and resets inferred values. - * This is useful for drivers that subclass the CRTC state. - */ -void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - memcpy(state, crtc->state, sizeof(*state)); - - if (state->mode_blob) - drm_property_blob_get(state->mode_blob); - if (state->degamma_lut) - drm_property_blob_get(state->degamma_lut); - if (state->ctm) - drm_property_blob_get(state->ctm); - if (state->gamma_lut) - drm_property_blob_get(state->gamma_lut); - state->mode_changed = false; - state->active_changed = false; - state->planes_changed = false; - state->connectors_changed = false; - state->color_mgmt_changed = false; - state->zpos_changed = false; - state->commit = NULL; - state->event = NULL; - state->pageflip_flags = 0; -} -EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); - -/** - * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook - * @crtc: drm CRTC - * - * Default CRTC state duplicate hook for drivers which don't have their own - * subclassed CRTC state structure. - */ -struct drm_crtc_state * -drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) -{ - struct drm_crtc_state *state; - - if (WARN_ON(!crtc->state)) - return NULL; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state) - __drm_atomic_helper_crtc_duplicate_state(crtc, state); - - return state; -} -EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); - -/** - * __drm_atomic_helper_crtc_destroy_state - release CRTC state - * @state: CRTC state object to release - * - * Releases all resources stored in the CRTC state without actually freeing - * the memory of the CRTC state. This is useful for drivers that subclass the - * CRTC state. - */ -void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) -{ - if (state->commit) { - /* - * In the event that a non-blocking commit returns - * -ERESTARTSYS before the commit_tail work is queued, we will - * have an extra reference to the commit object. Release it, if - * the event has not been consumed by the worker. - * - * state->event may be freed, so we can't directly look at - * state->event->base.completion. - */ - if (state->event && state->commit->abort_completion) - drm_crtc_commit_put(state->commit); - - kfree(state->commit->event); - state->commit->event = NULL; - - drm_crtc_commit_put(state->commit); - } - - drm_property_blob_put(state->mode_blob); - drm_property_blob_put(state->degamma_lut); - drm_property_blob_put(state->ctm); - drm_property_blob_put(state->gamma_lut); -} -EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); - -/** - * drm_atomic_helper_crtc_destroy_state - default state destroy hook - * @crtc: drm CRTC - * @state: CRTC state object to release - * - * Default CRTC state destroy hook for drivers which don't have their own - * subclassed CRTC state structure. - */ -void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - __drm_atomic_helper_crtc_destroy_state(state); - kfree(state); -} -EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); - -/** - * __drm_atomic_helper_plane_reset - resets planes state to default values - * @plane: plane object, must not be NULL - * @state: atomic plane state, must not be NULL - * - * Initializes plane state to default. This is useful for drivers that subclass - * the plane state. - */ -void __drm_atomic_helper_plane_reset(struct drm_plane *plane, - struct drm_plane_state *state) -{ - state->plane = plane; - state->rotation = DRM_MODE_ROTATE_0; - - state->alpha = DRM_BLEND_ALPHA_OPAQUE; - state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; - - plane->state = state; -} -EXPORT_SYMBOL(__drm_atomic_helper_plane_reset); - -/** - * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes - * @plane: drm plane - * - * Resets the atomic state for @plane by freeing the state pointer (which might - * be NULL, e.g. at driver load time) and allocating a new empty state object. - */ -void drm_atomic_helper_plane_reset(struct drm_plane *plane) -{ - if (plane->state) - __drm_atomic_helper_plane_destroy_state(plane->state); - - kfree(plane->state); - plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); - if (plane->state) - __drm_atomic_helper_plane_reset(plane, plane->state); -} -EXPORT_SYMBOL(drm_atomic_helper_plane_reset); - -/** - * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state - * @plane: plane object - * @state: atomic plane state - * - * Copies atomic state from a plane's current state. This is useful for - * drivers that subclass the plane state. - */ -void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - memcpy(state, plane->state, sizeof(*state)); - - if (state->fb) - drm_framebuffer_get(state->fb); - - state->fence = NULL; - state->commit = NULL; -} -EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); - -/** - * drm_atomic_helper_plane_duplicate_state - default state duplicate hook - * @plane: drm plane - * - * Default plane state duplicate hook for drivers which don't have their own - * subclassed plane state structure. - */ -struct drm_plane_state * -drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) -{ - struct drm_plane_state *state; - - if (WARN_ON(!plane->state)) - return NULL; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state) - __drm_atomic_helper_plane_duplicate_state(plane, state); - - return state; -} -EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); - -/** - * __drm_atomic_helper_plane_destroy_state - release plane state - * @state: plane state object to release - * - * Releases all resources stored in the plane state without actually freeing - * the memory of the plane state. This is useful for drivers that subclass the - * plane state. - */ -void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) -{ - if (state->fb) - drm_framebuffer_put(state->fb); - - if (state->fence) - dma_fence_put(state->fence); - - if (state->commit) - drm_crtc_commit_put(state->commit); -} -EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); - -/** - * drm_atomic_helper_plane_destroy_state - default state destroy hook - * @plane: drm plane - * @state: plane state object to release - * - * Default plane state destroy hook for drivers which don't have their own - * subclassed plane state structure. - */ -void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state) -{ - __drm_atomic_helper_plane_destroy_state(state); - kfree(state); -} -EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); - -/** - * __drm_atomic_helper_connector_reset - reset state on connector - * @connector: drm connector - * @conn_state: connector state to assign - * - * Initializes the newly allocated @conn_state and assigns it to - * the &drm_conector->state pointer of @connector, usually required when - * initializing the drivers or when called from the &drm_connector_funcs.reset - * hook. - * - * This is useful for drivers that subclass the connector state. - */ -void -__drm_atomic_helper_connector_reset(struct drm_connector *connector, - struct drm_connector_state *conn_state) -{ - if (conn_state) - conn_state->connector = connector; - - connector->state = conn_state; -} -EXPORT_SYMBOL(__drm_atomic_helper_connector_reset); - -/** - * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors - * @connector: drm connector - * - * Resets the atomic state for @connector by freeing the state pointer (which - * might be NULL, e.g. at driver load time) and allocating a new empty state - * object. - */ -void drm_atomic_helper_connector_reset(struct drm_connector *connector) -{ - struct drm_connector_state *conn_state = - kzalloc(sizeof(*conn_state), GFP_KERNEL); - - if (connector->state) - __drm_atomic_helper_connector_destroy_state(connector->state); - - kfree(connector->state); - __drm_atomic_helper_connector_reset(connector, conn_state); -} -EXPORT_SYMBOL(drm_atomic_helper_connector_reset); - -/** - * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state - * @connector: connector object - * @state: atomic connector state - * - * Copies atomic state from a connector's current state. This is useful for - * drivers that subclass the connector state. - */ -void -__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, - struct drm_connector_state *state) -{ - memcpy(state, connector->state, sizeof(*state)); - if (state->crtc) - drm_connector_get(connector); - state->commit = NULL; - - /* Don't copy over a writeback job, they are used only once */ - state->writeback_job = NULL; -} -EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); - -/** - * drm_atomic_helper_connector_duplicate_state - default state duplicate hook - * @connector: drm connector - * - * Default connector state duplicate hook for drivers which don't have their own - * subclassed connector state structure. - */ -struct drm_connector_state * -drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) -{ - struct drm_connector_state *state; - - if (WARN_ON(!connector->state)) - return NULL; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state) - __drm_atomic_helper_connector_duplicate_state(connector, state); - - return state; -} -EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); - -/** - * drm_atomic_helper_duplicate_state - duplicate an atomic state object - * @dev: DRM device - * @ctx: lock acquisition context - * - * Makes a copy of the current atomic state by looping over all objects and - * duplicating their respective states. This is used for example by suspend/ - * resume support code to save the state prior to suspend such that it can - * be restored upon resume. - * - * Note that this treats atomic state as persistent between save and restore. - * Drivers must make sure that this is possible and won't result in confusion - * or erroneous behaviour. - * - * Note that if callers haven't already acquired all modeset locks this might - * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). - * - * Returns: - * A pointer to the copy of the atomic state object on success or an - * ERR_PTR()-encoded error code on failure. - * - * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() - */ -struct drm_atomic_state * -drm_atomic_helper_duplicate_state(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_atomic_state *state; - struct drm_connector *conn; - struct drm_connector_list_iter conn_iter; - struct drm_plane *plane; - struct drm_crtc *crtc; - int err = 0; - - state = drm_atomic_state_alloc(dev); - if (!state) - return ERR_PTR(-ENOMEM); - - state->acquire_ctx = ctx; - - drm_for_each_crtc(crtc, dev) { - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - err = PTR_ERR(crtc_state); - goto free; - } - } - - drm_for_each_plane(plane, dev) { - struct drm_plane_state *plane_state; - - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - err = PTR_ERR(plane_state); - goto free; - } - } - - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(conn, &conn_iter) { - struct drm_connector_state *conn_state; - - conn_state = drm_atomic_get_connector_state(state, conn); - if (IS_ERR(conn_state)) { - err = PTR_ERR(conn_state); - drm_connector_list_iter_end(&conn_iter); - goto free; - } - } - drm_connector_list_iter_end(&conn_iter); - - /* clear the acquire context so that it isn't accidentally reused */ - state->acquire_ctx = NULL; - -free: - if (err < 0) { - drm_atomic_state_put(state); - state = ERR_PTR(err); - } - - return state; -} -EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); - -/** - * __drm_atomic_helper_connector_destroy_state - release connector state - * @state: connector state object to release - * - * Releases all resources stored in the connector state without actually - * freeing the memory of the connector state. This is useful for drivers that - * subclass the connector state. - */ -void -__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) -{ - if (state->crtc) - drm_connector_put(state->connector); - - if (state->commit) - drm_crtc_commit_put(state->commit); -} -EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); - -/** - * drm_atomic_helper_connector_destroy_state - default state destroy hook - * @connector: drm connector - * @state: connector state object to release - * - * Default connector state destroy hook for drivers which don't have their own - * subclassed connector state structure. - */ -void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, - struct drm_connector_state *state) -{ - __drm_atomic_helper_connector_destroy_state(state); - kfree(state); -} -EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); - -/** - * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table - * @crtc: CRTC object - * @red: red correction table - * @green: green correction table - * @blue: green correction table - * @size: size of the tables - * @ctx: lock acquire context - * - * Implements support for legacy gamma correction table for drivers - * that support color management through the DEGAMMA_LUT/GAMMA_LUT - * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for - * how the atomic color management and gamma tables work. - */ -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_device *dev = crtc->dev; - struct drm_atomic_state *state; - struct drm_crtc_state *crtc_state; - struct drm_property_blob *blob = NULL; - struct drm_color_lut *blob_data; - int i, ret = 0; - bool replaced; - - state = drm_atomic_state_alloc(crtc->dev); - if (!state) - return -ENOMEM; - - blob = drm_property_create_blob(dev, - sizeof(struct drm_color_lut) * size, - NULL); - if (IS_ERR(blob)) { - ret = PTR_ERR(blob); - blob = NULL; - goto fail; - } - - /* Prepare GAMMA_LUT with the legacy values. */ - blob_data = blob->data; - for (i = 0; i < size; i++) { - blob_data[i].red = red[i]; - blob_data[i].green = green[i]; - blob_data[i].blue = blue[i]; - } - - state->acquire_ctx = ctx; - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto fail; - } - - /* Reset DEGAMMA_LUT and CTM properties. */ - replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); - replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); - replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); - crtc_state->color_mgmt_changed |= replaced; - - ret = drm_atomic_commit(state); - -fail: - drm_atomic_state_put(state); - drm_property_blob_put(blob); - return ret; -} -EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); - -/** - * __drm_atomic_helper_private_duplicate_state - copy atomic private state - * @obj: CRTC object - * @state: new private object state - * - * Copies atomic state from a private objects's current state and resets inferred values. - * This is useful for drivers that subclass the private state. - */ -void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, - struct drm_private_state *state) -{ - memcpy(state, obj->state, sizeof(*state)); -} -EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state); diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c new file mode 100644 index 000000000000..3ba996069d69 --- /dev/null +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2018 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Rob Clark + * Daniel Vetter + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * DOC: atomic state reset and initialization + * + * Both the drm core and the atomic helpers assume that there is always the full + * and correct atomic software state for all connectors, CRTCs and planes + * available. Which is a bit a problem on driver load and also after system + * suspend. One way to solve this is to have a hardware state read-out + * infrastructure which reconstructs the full software state (e.g. the i915 + * driver). + * + * The simpler solution is to just reset the software state to everything off, + * which is easiest to do by calling drm_mode_config_reset(). To facilitate this + * the atomic helpers provide default reset implementations for all hooks. + * + * On the upside the precise state tracking of atomic simplifies system suspend + * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe + * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume(). + * For other drivers the building blocks are split out, see the documentation + * for these functions. + */ + +/** + * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs + * @crtc: drm CRTC + * + * Resets the atomic state for @crtc by freeing the state pointer (which might + * be NULL, e.g. at driver load time) and allocating a new empty state object. + */ +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) +{ + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc->state); + + kfree(crtc->state); + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); + + if (crtc->state) + crtc->state->crtc = crtc; +} +EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); + +/** + * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state + * @crtc: CRTC object + * @state: atomic CRTC state + * + * Copies atomic state from a CRTC's current state and resets inferred values. + * This is useful for drivers that subclass the CRTC state. + */ +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + memcpy(state, crtc->state, sizeof(*state)); + + if (state->mode_blob) + drm_property_blob_get(state->mode_blob); + if (state->degamma_lut) + drm_property_blob_get(state->degamma_lut); + if (state->ctm) + drm_property_blob_get(state->ctm); + if (state->gamma_lut) + drm_property_blob_get(state->gamma_lut); + state->mode_changed = false; + state->active_changed = false; + state->planes_changed = false; + state->connectors_changed = false; + state->color_mgmt_changed = false; + state->zpos_changed = false; + state->commit = NULL; + state->event = NULL; + state->pageflip_flags = 0; +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); + +/** + * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook + * @crtc: drm CRTC + * + * Default CRTC state duplicate hook for drivers which don't have their own + * subclassed CRTC state structure. + */ +struct drm_crtc_state * +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct drm_crtc_state *state; + + if (WARN_ON(!crtc->state)) + return NULL; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_duplicate_state(crtc, state); + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); + +/** + * __drm_atomic_helper_crtc_destroy_state - release CRTC state + * @state: CRTC state object to release + * + * Releases all resources stored in the CRTC state without actually freeing + * the memory of the CRTC state. This is useful for drivers that subclass the + * CRTC state. + */ +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state) +{ + if (state->commit) { + /* + * In the event that a non-blocking commit returns + * -ERESTARTSYS before the commit_tail work is queued, we will + * have an extra reference to the commit object. Release it, if + * the event has not been consumed by the worker. + * + * state->event may be freed, so we can't directly look at + * state->event->base.completion. + */ + if (state->event && state->commit->abort_completion) + drm_crtc_commit_put(state->commit); + + kfree(state->commit->event); + state->commit->event = NULL; + + drm_crtc_commit_put(state->commit); + } + + drm_property_blob_put(state->mode_blob); + drm_property_blob_put(state->degamma_lut); + drm_property_blob_put(state->ctm); + drm_property_blob_put(state->gamma_lut); +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); + +/** + * drm_atomic_helper_crtc_destroy_state - default state destroy hook + * @crtc: drm CRTC + * @state: CRTC state object to release + * + * Default CRTC state destroy hook for drivers which don't have their own + * subclassed CRTC state structure. + */ +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(state); +} +EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); + +/** + * __drm_atomic_helper_plane_reset - resets planes state to default values + * @plane: plane object, must not be NULL + * @state: atomic plane state, must not be NULL + * + * Initializes plane state to default. This is useful for drivers that subclass + * the plane state. + */ +void __drm_atomic_helper_plane_reset(struct drm_plane *plane, + struct drm_plane_state *state) +{ + state->plane = plane; + state->rotation = DRM_MODE_ROTATE_0; + + state->alpha = DRM_BLEND_ALPHA_OPAQUE; + state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; + + plane->state = state; +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_reset); + +/** + * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes + * @plane: drm plane + * + * Resets the atomic state for @plane by freeing the state pointer (which might + * be NULL, e.g. at driver load time) and allocating a new empty state object. + */ +void drm_atomic_helper_plane_reset(struct drm_plane *plane) +{ + if (plane->state) + __drm_atomic_helper_plane_destroy_state(plane->state); + + kfree(plane->state); + plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL); + if (plane->state) + __drm_atomic_helper_plane_reset(plane, plane->state); +} +EXPORT_SYMBOL(drm_atomic_helper_plane_reset); + +/** + * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state + * @plane: plane object + * @state: atomic plane state + * + * Copies atomic state from a plane's current state. This is useful for + * drivers that subclass the plane state. + */ +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + memcpy(state, plane->state, sizeof(*state)); + + if (state->fb) + drm_framebuffer_get(state->fb); + + state->fence = NULL; + state->commit = NULL; +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); + +/** + * drm_atomic_helper_plane_duplicate_state - default state duplicate hook + * @plane: drm plane + * + * Default plane state duplicate hook for drivers which don't have their own + * subclassed plane state structure. + */ +struct drm_plane_state * +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) +{ + struct drm_plane_state *state; + + if (WARN_ON(!plane->state)) + return NULL; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_duplicate_state(plane, state); + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); + +/** + * __drm_atomic_helper_plane_destroy_state - release plane state + * @state: plane state object to release + * + * Releases all resources stored in the plane state without actually freeing + * the memory of the plane state. This is useful for drivers that subclass the + * plane state. + */ +void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) +{ + if (state->fb) + drm_framebuffer_put(state->fb); + + if (state->fence) + dma_fence_put(state->fence); + + if (state->commit) + drm_crtc_commit_put(state->commit); +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); + +/** + * drm_atomic_helper_plane_destroy_state - default state destroy hook + * @plane: drm plane + * @state: plane state object to release + * + * Default plane state destroy hook for drivers which don't have their own + * subclassed plane state structure. + */ +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + __drm_atomic_helper_plane_destroy_state(state); + kfree(state); +} +EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); + +/** + * __drm_atomic_helper_connector_reset - reset state on connector + * @connector: drm connector + * @conn_state: connector state to assign + * + * Initializes the newly allocated @conn_state and assigns it to + * the &drm_conector->state pointer of @connector, usually required when + * initializing the drivers or when called from the &drm_connector_funcs.reset + * hook. + * + * This is useful for drivers that subclass the connector state. + */ +void +__drm_atomic_helper_connector_reset(struct drm_connector *connector, + struct drm_connector_state *conn_state) +{ + if (conn_state) + conn_state->connector = connector; + + connector->state = conn_state; +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_reset); + +/** + * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors + * @connector: drm connector + * + * Resets the atomic state for @connector by freeing the state pointer (which + * might be NULL, e.g. at driver load time) and allocating a new empty state + * object. + */ +void drm_atomic_helper_connector_reset(struct drm_connector *connector) +{ + struct drm_connector_state *conn_state = + kzalloc(sizeof(*conn_state), GFP_KERNEL); + + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(connector->state); + __drm_atomic_helper_connector_reset(connector, conn_state); +} +EXPORT_SYMBOL(drm_atomic_helper_connector_reset); + +/** + * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state + * @connector: connector object + * @state: atomic connector state + * + * Copies atomic state from a connector's current state. This is useful for + * drivers that subclass the connector state. + */ +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + memcpy(state, connector->state, sizeof(*state)); + if (state->crtc) + drm_connector_get(connector); + state->commit = NULL; + + /* Don't copy over a writeback job, they are used only once */ + state->writeback_job = NULL; +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); + +/** + * drm_atomic_helper_connector_duplicate_state - default state duplicate hook + * @connector: drm connector + * + * Default connector state duplicate hook for drivers which don't have their own + * subclassed connector state structure. + */ +struct drm_connector_state * +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) +{ + struct drm_connector_state *state; + + if (WARN_ON(!connector->state)) + return NULL; + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_connector_duplicate_state(connector, state); + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); + +/** + * drm_atomic_helper_duplicate_state - duplicate an atomic state object + * @dev: DRM device + * @ctx: lock acquisition context + * + * Makes a copy of the current atomic state by looping over all objects and + * duplicating their respective states. This is used for example by suspend/ + * resume support code to save the state prior to suspend such that it can + * be restored upon resume. + * + * Note that this treats atomic state as persistent between save and restore. + * Drivers must make sure that this is possible and won't result in confusion + * or erroneous behaviour. + * + * Note that if callers haven't already acquired all modeset locks this might + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). + * + * Returns: + * A pointer to the copy of the atomic state object on success or an + * ERR_PTR()-encoded error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() + */ +struct drm_atomic_state * +drm_atomic_helper_duplicate_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + struct drm_plane *plane; + struct drm_crtc *crtc; + int err = 0; + + state = drm_atomic_state_alloc(dev); + if (!state) + return ERR_PTR(-ENOMEM); + + state->acquire_ctx = ctx; + + drm_for_each_crtc(crtc, dev) { + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + err = PTR_ERR(crtc_state); + goto free; + } + } + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + err = PTR_ERR(plane_state); + goto free; + } + } + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + struct drm_connector_state *conn_state; + + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + err = PTR_ERR(conn_state); + drm_connector_list_iter_end(&conn_iter); + goto free; + } + } + drm_connector_list_iter_end(&conn_iter); + + /* clear the acquire context so that it isn't accidentally reused */ + state->acquire_ctx = NULL; + +free: + if (err < 0) { + drm_atomic_state_put(state); + state = ERR_PTR(err); + } + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); + +/** + * __drm_atomic_helper_connector_destroy_state - release connector state + * @state: connector state object to release + * + * Releases all resources stored in the connector state without actually + * freeing the memory of the connector state. This is useful for drivers that + * subclass the connector state. + */ +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) +{ + if (state->crtc) + drm_connector_put(state->connector); + + if (state->commit) + drm_crtc_commit_put(state->commit); +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); + +/** + * drm_atomic_helper_connector_destroy_state - default state destroy hook + * @connector: drm connector + * @state: connector state object to release + * + * Default connector state destroy hook for drivers which don't have their own + * subclassed connector state structure. + */ +void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + __drm_atomic_helper_connector_destroy_state(state); + kfree(state); +} +EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); + +/** + * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table + * @crtc: CRTC object + * @red: red correction table + * @green: green correction table + * @blue: green correction table + * @size: size of the tables + * @ctx: lock acquire context + * + * Implements support for legacy gamma correction table for drivers + * that support color management through the DEGAMMA_LUT/GAMMA_LUT + * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for + * how the atomic color management and gamma tables work. + */ +int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_device *dev = crtc->dev; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_property_blob *blob = NULL; + struct drm_color_lut *blob_data; + int i, ret = 0; + bool replaced; + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return -ENOMEM; + + blob = drm_property_create_blob(dev, + sizeof(struct drm_color_lut) * size, + NULL); + if (IS_ERR(blob)) { + ret = PTR_ERR(blob); + blob = NULL; + goto fail; + } + + /* Prepare GAMMA_LUT with the legacy values. */ + blob_data = blob->data; + for (i = 0; i < size; i++) { + blob_data[i].red = red[i]; + blob_data[i].green = green[i]; + blob_data[i].blue = blue[i]; + } + + state->acquire_ctx = ctx; + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + /* Reset DEGAMMA_LUT and CTM properties. */ + replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); + replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); + replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); + crtc_state->color_mgmt_changed |= replaced; + + ret = drm_atomic_commit(state); + +fail: + drm_atomic_state_put(state); + drm_property_blob_put(blob); + return ret; +} +EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); + +/** + * __drm_atomic_helper_private_duplicate_state - copy atomic private state + * @obj: CRTC object + * @state: new private object state + * + * Copies atomic state from a private objects's current state and resets inferred values. + * This is useful for drivers that subclass the private state. + */ +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + memcpy(state, obj->state, sizeof(*state)); +} +EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index e60c4f0f8827..25ca0097563e 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -31,6 +31,7 @@ #include #include #include +#include #include struct drm_atomic_state; @@ -145,49 +146,6 @@ int drm_atomic_helper_page_flip_target( uint32_t target, struct drm_modeset_acquire_ctx *ctx); -/* default implementations for state handling */ -void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); -void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, - struct drm_crtc_state *state); -struct drm_crtc_state * -drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); -void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); -void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, - struct drm_crtc_state *state); - -void __drm_atomic_helper_plane_reset(struct drm_plane *plane, - struct drm_plane_state *state); -void drm_atomic_helper_plane_reset(struct drm_plane *plane); -void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, - struct drm_plane_state *state); -struct drm_plane_state * -drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); -void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); -void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, - struct drm_plane_state *state); - -void __drm_atomic_helper_connector_reset(struct drm_connector *connector, - struct drm_connector_state *conn_state); -void drm_atomic_helper_connector_reset(struct drm_connector *connector); -void -__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, - struct drm_connector_state *state); -struct drm_connector_state * -drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); -struct drm_atomic_state * -drm_atomic_helper_duplicate_state(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx); -void -__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); -void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, - struct drm_connector_state *state); -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx); -void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, - struct drm_private_state *state); - /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * @plane: the loop cursor diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h new file mode 100644 index 000000000000..5b82ccfdb502 --- /dev/null +++ b/include/drm/drm_atomic_state_helper.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Rob Clark + * Daniel Vetter + */ + +#include + +struct drm_crtc; +struct drm_crtc_state; +struct drm_plane; +struct drm_plane_state; +struct drm_connector; +struct drm_connector_state; +struct drm_private_obj; +struct drm_private_state; +struct drm_modeset_acquire_ctx; +struct drm_device; + +void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); +struct drm_crtc_state * +drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state); +void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); + +void __drm_atomic_helper_plane_reset(struct drm_plane *plane, + struct drm_plane_state *state); +void drm_atomic_helper_plane_reset(struct drm_plane *plane); +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state); +struct drm_plane_state * +drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); +void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state); +void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); + +void __drm_atomic_helper_connector_reset(struct drm_connector *connector, + struct drm_connector_state *conn_state); +void drm_atomic_helper_connector_reset(struct drm_connector *connector); +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state); +struct drm_connector_state * +drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); +struct drm_atomic_state * +drm_atomic_helper_duplicate_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); +void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state); +int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + uint32_t size, + struct drm_modeset_acquire_ctx *ctx); +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, + struct drm_private_state *state); -- cgit v1.2.3 From ec9b0a9e2c9e2543aa391c6006fde3f9b6e54576 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:31 +0200 Subject: drm/atomic: Improve docs for drm_atomic_state->allow_modeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Motivated by vmwgfx digging around in core uapi bits it shouldn't dig around in. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-7-daniel.vetter@ffwll.ch --- include/drm/drm_atomic.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'include/drm') diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index d6adebcd6ea4..c09ecaf43825 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -254,7 +254,6 @@ struct __drm_private_objs_state { * struct drm_atomic_state - the global state object for atomic updates * @ref: count of all references to this state (will not be freed until zero) * @dev: parent DRM device - * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics * @async_update: hint for asynchronous plane update * @planes: pointer to array of structures with per-plane data @@ -273,6 +272,15 @@ struct drm_atomic_state { struct kref ref; struct drm_device *dev; + + /** + * @allow_modeset: + * + * Allow full modeset. This is used by the ATOMIC IOCTL handler to + * implement the DRM_MODE_ATOMIC_ALLOW_MODESET flag. Drivers should + * never consult this flag, instead looking at the output of + * drm_atomic_crtc_needs_modeset(). + */ bool allow_modeset : 1; bool legacy_cursor_update : 1; bool async_update : 1; -- cgit v1.2.3 From 21ebe615c16994f340fe2b6735aad31fd1d0014c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:40 +0200 Subject: drm: Remove transitional helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With armada the last bigger driver that realistically needed these to convert from legacy kms to atomic is converted. These helpers have been broken more often than not the past 2 years, and as this little patch series shows, tricked a bunch of people into using the wrong helpers for their functions. Aside: I think a lot more drivers should be using the device-level drm_atomic_helper_shutdown/suspend/resume helpers and related functions. In almost all the cases they get things exactly right. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-16-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc_helper.c | 115 ---------------------- drivers/gpu/drm/drm_plane_helper.c | 197 ------------------------------------- include/drm/drm_crtc_helper.h | 6 -- include/drm/drm_plane_helper.h | 14 --- 4 files changed, 332 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ce75e9506e85..a3c81850e755 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -984,118 +984,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev) drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_helper_resume_force_mode); - -/** - * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers - * @crtc: DRM CRTC - * @mode: DRM display mode which userspace requested - * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks - * @x: x offset of the CRTC scanout area on the underlying framebuffer - * @y: y offset of the CRTC scanout area on the underlying framebuffer - * @old_fb: previous framebuffer - * - * This function implements a callback useable as the ->mode_set callback - * required by the CRTC helpers. Besides the atomic plane helper functions for - * the primary plane the driver must also provide the ->mode_set_nofb callback - * to set up the CRTC. - * - * This is a transitional helper useful for converting drivers to the atomic - * interfaces. - */ -int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_crtc_state *crtc_state; - const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - int ret; - - if (crtc->funcs->atomic_duplicate_state) - crtc_state = crtc->funcs->atomic_duplicate_state(crtc); - else { - if (!crtc->state) - drm_atomic_helper_crtc_reset(crtc); - - crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); - } - - if (!crtc_state) - return -ENOMEM; - - crtc_state->planes_changed = true; - crtc_state->mode_changed = true; - ret = drm_atomic_set_mode_for_crtc(crtc_state, mode); - if (ret) - goto out; - drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode); - - if (crtc_funcs->atomic_check) { - ret = crtc_funcs->atomic_check(crtc, crtc_state); - if (ret) - goto out; - } - - swap(crtc->state, crtc_state); - - crtc_funcs->mode_set_nofb(crtc); - - ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb); - -out: - if (crtc_state) { - if (crtc->funcs->atomic_destroy_state) - crtc->funcs->atomic_destroy_state(crtc, crtc_state); - else - drm_atomic_helper_crtc_destroy_state(crtc, crtc_state); - } - - return ret; -} -EXPORT_SYMBOL(drm_helper_crtc_mode_set); - -/** - * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers - * @crtc: DRM CRTC - * @x: x offset of the CRTC scanout area on the underlying framebuffer - * @y: y offset of the CRTC scanout area on the underlying framebuffer - * @old_fb: previous framebuffer - * - * This function implements a callback useable as the ->mode_set_base used - * required by the CRTC helpers. The driver must provide the atomic plane helper - * functions for the primary plane. - * - * This is a transitional helper useful for converting drivers to the atomic - * interfaces. - */ -int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_plane_state *plane_state; - struct drm_plane *plane = crtc->primary; - - if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); - else { - if (!plane->state) - drm_atomic_helper_plane_reset(plane); - - plane_state = drm_atomic_helper_plane_duplicate_state(plane); - } - if (!plane_state) - return -ENOMEM; - plane_state->plane = plane; - - plane_state->crtc = crtc; - drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb); - plane_state->crtc_x = 0; - plane_state->crtc_y = 0; - plane_state->crtc_h = crtc->mode.vdisplay; - plane_state->crtc_w = crtc->mode.hdisplay; - plane_state->src_x = x << 16; - plane_state->src_y = y << 16; - plane_state->src_h = crtc->mode.vdisplay << 16; - plane_state->src_w = crtc->mode.hdisplay << 16; - - return drm_plane_helper_commit(plane, plane_state, old_fb); -} -EXPORT_SYMBOL(drm_helper_crtc_mode_set_base); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index a393756b664e..965286231600 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -336,200 +336,3 @@ const struct drm_plane_funcs drm_primary_helper_funcs = { .destroy = drm_primary_helper_destroy, }; EXPORT_SYMBOL(drm_primary_helper_funcs); - -int drm_plane_helper_commit(struct drm_plane *plane, - struct drm_plane_state *plane_state, - struct drm_framebuffer *old_fb) -{ - const struct drm_plane_helper_funcs *plane_funcs; - struct drm_crtc *crtc[2]; - const struct drm_crtc_helper_funcs *crtc_funcs[2]; - int i, ret = 0; - - plane_funcs = plane->helper_private; - - /* Since this is a transitional helper we can't assume that plane->state - * is always valid. Hence we need to use plane->crtc instead of - * plane->state->crtc as the old crtc. */ - crtc[0] = plane->crtc; - crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL; - - for (i = 0; i < 2; i++) - crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL; - - if (plane_funcs->atomic_check) { - ret = plane_funcs->atomic_check(plane, plane_state); - if (ret) - goto out; - } - - if (plane_funcs->prepare_fb && plane_state->fb != old_fb) { - ret = plane_funcs->prepare_fb(plane, - plane_state); - if (ret) - goto out; - } - - /* Point of no return, commit sw state. */ - swap(plane->state, plane_state); - - for (i = 0; i < 2; i++) { - if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) - crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state); - } - - /* - * Drivers may optionally implement the ->atomic_disable callback, so - * special-case that here. - */ - if (drm_atomic_plane_disabling(plane_state, plane->state) && - plane_funcs->atomic_disable) - plane_funcs->atomic_disable(plane, plane_state); - else - plane_funcs->atomic_update(plane, plane_state); - - for (i = 0; i < 2; i++) { - if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) - crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state); - } - - /* - * If we only moved the plane and didn't change fb's, there's no need to - * wait for vblank. - */ - if (plane->state->fb == old_fb) - goto out; - - for (i = 0; i < 2; i++) { - if (!crtc[i]) - continue; - - if (crtc[i]->cursor == plane) - continue; - - /* There's no other way to figure out whether the crtc is running. */ - ret = drm_crtc_vblank_get(crtc[i]); - if (ret == 0) { - drm_crtc_wait_one_vblank(crtc[i]); - drm_crtc_vblank_put(crtc[i]); - } - - ret = 0; - } - - if (plane_funcs->cleanup_fb) - plane_funcs->cleanup_fb(plane, plane_state); -out: - if (plane->funcs->atomic_destroy_state) - plane->funcs->atomic_destroy_state(plane, plane_state); - else - drm_atomic_helper_plane_destroy_state(plane, plane_state); - - return ret; -} - -/** - * drm_plane_helper_update() - Transitional helper for plane update - * @plane: plane object to update - * @crtc: owning CRTC of owning plane - * @fb: framebuffer to flip onto plane - * @crtc_x: x offset of primary plane on crtc - * @crtc_y: y offset of primary plane on crtc - * @crtc_w: width of primary plane rectangle on crtc - * @crtc_h: height of primary plane rectangle on crtc - * @src_x: x offset of @fb for panning - * @src_y: y offset of @fb for panning - * @src_w: width of source rectangle in @fb - * @src_h: height of source rectangle in @fb - * @ctx: lock acquire context, not used here - * - * Provides a default plane update handler using the atomic plane update - * functions. It is fully left to the driver to check plane constraints and - * handle corner-cases like a fully occluded or otherwise invisible plane. - * - * This is useful for piecewise transitioning of a driver to the atomic helpers. - * - * RETURNS: - * Zero on success, error code on failure - */ -int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_plane_state *plane_state; - - if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); - else { - if (!plane->state) - drm_atomic_helper_plane_reset(plane); - - plane_state = drm_atomic_helper_plane_duplicate_state(plane); - } - if (!plane_state) - return -ENOMEM; - plane_state->plane = plane; - - plane_state->crtc = crtc; - drm_atomic_set_fb_for_plane(plane_state, fb); - plane_state->crtc_x = crtc_x; - plane_state->crtc_y = crtc_y; - plane_state->crtc_h = crtc_h; - plane_state->crtc_w = crtc_w; - plane_state->src_x = src_x; - plane_state->src_y = src_y; - plane_state->src_h = src_h; - plane_state->src_w = src_w; - - return drm_plane_helper_commit(plane, plane_state, plane->fb); -} -EXPORT_SYMBOL(drm_plane_helper_update); - -/** - * drm_plane_helper_disable() - Transitional helper for plane disable - * @plane: plane to disable - * @ctx: lock acquire context, not used here - * - * Provides a default plane disable handler using the atomic plane update - * functions. It is fully left to the driver to check plane constraints and - * handle corner-cases like a fully occluded or otherwise invisible plane. - * - * This is useful for piecewise transitioning of a driver to the atomic helpers. - * - * RETURNS: - * Zero on success, error code on failure - */ -int drm_plane_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_plane_state *plane_state; - struct drm_framebuffer *old_fb; - - /* crtc helpers love to call disable functions for already disabled hw - * functions. So cope with that. */ - if (!plane->crtc) - return 0; - - if (plane->funcs->atomic_duplicate_state) - plane_state = plane->funcs->atomic_duplicate_state(plane); - else { - if (!plane->state) - drm_atomic_helper_plane_reset(plane); - - plane_state = drm_atomic_helper_plane_duplicate_state(plane); - } - if (!plane_state) - return -ENOMEM; - plane_state->plane = plane; - - plane_state->crtc = NULL; - old_fb = plane_state->fb; - drm_atomic_set_fb_for_plane(plane_state, NULL); - - return drm_plane_helper_commit(plane, plane_state, old_fb); -} -EXPORT_SYMBOL(drm_plane_helper_disable); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 6914633037a5..d65f034843ce 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -57,12 +57,6 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode); void drm_helper_resume_force_mode(struct drm_device *dev); -int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb); -int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb); - /* drm_probe_helper.c */ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 26cee2934781..1999781781c7 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -62,18 +62,4 @@ int drm_primary_helper_disable(struct drm_plane *plane, void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; -int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx); -int drm_plane_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); - -/* For use by drm_crtc_helper.c */ -int drm_plane_helper_commit(struct drm_plane *plane, - struct drm_plane_state *plane_state, - struct drm_framebuffer *old_fb); #endif -- cgit v1.2.3 From 6b6fce62f65c19590bee8102f7946a26eaf0b054 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Oct 2018 11:47:32 +0200 Subject: drm: Unexport primary plane helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well except the destroy helper, which isn't really a primary helper but generally useful, if mislabelled. v2: Keep some of the nice comments about the limitations of the primarmy plane helpers, and put them into the kerneldoc for drm_crtc_init() (Sam). Reviewed-by: Ville Syrjälä Cc: Sam Ravnborg Cc: Ville Syrjälä Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181005094732.31353-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_modeset_helper.c | 15 +++++++ drivers/gpu/drm/drm_plane_helper.c | 85 +++++------------------------------- include/drm/drm_plane_helper.h | 10 ----- 3 files changed, 26 insertions(+), 84 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index f1c24ab0ef09..9150fa385bba 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -146,6 +146,21 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev) * Initialize a CRTC object with a default helper-provided primary plane and no * cursor plane. * + * Note that we make some assumptions about hardware limitations that may not be + * true for all hardware: + * + * 1. Primary plane cannot be repositioned. + * 2. Primary plane cannot be scaled. + * 3. Primary plane must cover the entire CRTC. + * 4. Subpixel positioning is not supported. + * 5. The primary plane must always be on if the CRTC is enabled. + * + * This is purely a backwards compatibility helper for old drivers. Drivers + * should instead implement their own primary plane. Atomic drivers must do so. + * Drivers with the above hardware restriction can look into using &struct + * drm_simple_display_pipe, which encapsulates the above limitations into a nice + * interface. + * * Returns: * Zero on success, error code on failure. */ diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 965286231600..06c761db6e80 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -42,11 +42,8 @@ * primary plane support on top of the normal CRTC configuration interface. * Since the legacy &drm_mode_config_funcs.set_config interface ties the primary * plane together with the CRTC state this does not allow userspace to disable - * the primary plane itself. To avoid too much duplicated code use - * drm_plane_helper_check_update() which can be used to enforce the same - * restrictions as primary planes had thus. The default primary plane only - * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached - * framebuffer. + * the primary plane itself. The default primary plane only expose XRBG8888 and + * ARGB8888 as valid pixel formats for the attached framebuffer. * * Drivers are highly recommended to implement proper support for primary * planes, and newly merged drivers must not rely upon these transitional @@ -175,50 +172,13 @@ int drm_plane_helper_check_update(struct drm_plane *plane, } EXPORT_SYMBOL(drm_plane_helper_check_update); -/** - * drm_primary_helper_update() - Helper for primary plane update - * @plane: plane object to update - * @crtc: owning CRTC of owning plane - * @fb: framebuffer to flip onto plane - * @crtc_x: x offset of primary plane on crtc - * @crtc_y: y offset of primary plane on crtc - * @crtc_w: width of primary plane rectangle on crtc - * @crtc_h: height of primary plane rectangle on crtc - * @src_x: x offset of @fb for panning - * @src_y: y offset of @fb for panning - * @src_w: width of source rectangle in @fb - * @src_h: height of source rectangle in @fb - * @ctx: lock acquire context, not used here - * - * Provides a default plane update handler for primary planes. This is handler - * is called in response to a userspace SetPlane operation on the plane with a - * non-NULL framebuffer. We call the driver's modeset handler to update the - * framebuffer. - * - * SetPlane() on a primary plane of a disabled CRTC is not supported, and will - * return an error. - * - * Note that we make some assumptions about hardware limitations that may not be - * true for all hardware -- - * - * 1. Primary plane cannot be repositioned. - * 2. Primary plane cannot be scaled. - * 3. Primary plane must cover the entire CRTC. - * 4. Subpixel positioning is not supported. - * - * Drivers for hardware that don't have these restrictions can provide their - * own implementation rather than using this helper. - * - * RETURNS: - * Zero on success, error code on failure - */ -int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) +static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_mode_set set = { .crtc = crtc, @@ -285,35 +245,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, kfree(connector_list); return ret; } -EXPORT_SYMBOL(drm_primary_helper_update); -/** - * drm_primary_helper_disable() - Helper for primary plane disable - * @plane: plane to disable - * @ctx: lock acquire context, not used here - * - * Provides a default plane disable handler for primary planes. This is handler - * is called in response to a userspace SetPlane operation on the plane with a - * NULL framebuffer parameter. It unconditionally fails the disable call with - * -EINVAL the only way to disable the primary plane without driver support is - * to disable the entire CRTC. Which does not match the plane - * &drm_plane_funcs.disable_plane hook. - * - * Note that some hardware may be able to disable the primary plane without - * disabling the whole CRTC. Drivers for such hardware should provide their - * own disable handler that disables just the primary plane (and they'll likely - * need to provide their own update handler as well to properly re-enable a - * disabled primary plane). - * - * RETURNS: - * Unconditionally returns -EINVAL. - */ -int drm_primary_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx) +static int drm_primary_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { return -EINVAL; } -EXPORT_SYMBOL(drm_primary_helper_disable); /** * drm_primary_helper_destroy() - Helper for primary plane destruction diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 1999781781c7..fb086aa4daa2 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -49,16 +49,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane, bool can_position, bool can_update_disabled, bool *visible); -int drm_primary_helper_update(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx); -int drm_primary_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; -- cgit v1.2.3 From 84c0851794d40b1f438343b371bb0eaa8d36a4a3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:42 +0200 Subject: drm: Unexport drm_plane_helper_check_update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's for legacy drivers only (atomic ones should use drm_atomic_helper_check_plane_state() instead), and there's no users left except the one in the primary plane helpers. Signed-off-by: Daniel Vetter Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-18-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane_helper.c | 49 +++++++++----------------------------- include/drm/drm_plane_helper.h | 11 --------- 2 files changed, 11 insertions(+), 49 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 06c761db6e80..0fff72dcd06d 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -97,43 +97,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, return count; } -/** - * drm_plane_helper_check_update() - Check plane update for validity - * @plane: plane object to update - * @crtc: owning CRTC of owning plane - * @fb: framebuffer to flip onto plane - * @src: source coordinates in 16.16 fixed point - * @dst: integer destination coordinates - * @rotation: plane rotation - * @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? - * @visible: output parameter indicating whether plane is still visible after - * clipping - * - * Checks that a desired plane update is valid. 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_update(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_rect *src, - struct drm_rect *dst, - unsigned int rotation, - int min_scale, - int max_scale, - bool can_position, - bool can_update_disabled, - bool *visible) +static int drm_plane_helper_check_update(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_rect *src, + struct drm_rect *dst, + unsigned int rotation, + int min_scale, + int max_scale, + bool can_position, + bool can_update_disabled, + bool *visible) { struct drm_plane_state plane_state = { .plane = plane, @@ -170,7 +144,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane, return 0; } -EXPORT_SYMBOL(drm_plane_helper_check_update); static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index fb086aa4daa2..331ebd60b3a3 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -38,17 +38,6 @@ */ #define DRM_PLANE_HELPER_NO_SCALING (1<<16) -int drm_plane_helper_check_update(struct drm_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_rect *src, - struct drm_rect *dest, - unsigned int rotation, - int min_scale, - int max_scale, - bool can_position, - bool can_update_disabled, - bool *visible); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; -- cgit v1.2.3 From 649fdce23cdf516e69aa8c18f4b44c62127f0e83 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 15 Oct 2018 16:55:47 +0800 Subject: drm: add flags to drm_syncobj_find_fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flags can be used by driver to decide whether need to block wait submission. Signed-off-by: Chunming Zhou SIgned-off-by: Christian König Reviewed-by: Christian König Link: https://patchwork.kernel.org/patch/10641339/ --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/drm_syncobj.c | 4 ++-- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++-- drivers/gpu/drm/vc4/vc4_gem.c | 2 +- include/drm/drm_syncobj.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 663043c8f0f5..8e9a65a15875 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1104,7 +1104,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p, { int r; struct dma_fence *fence; - r = drm_syncobj_find_fence(p->filp, handle, 0, &fence); + r = drm_syncobj_find_fence(p->filp, handle, 0, 0, &fence); if (r) return r; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 5bcb3ef9b256..094513125153 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -224,7 +224,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) * dma_fence_put(). */ int drm_syncobj_find_fence(struct drm_file *file_private, - u32 handle, u64 point, + u32 handle, u64 point, u64 flags, struct dma_fence **fence) { struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); @@ -495,7 +495,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private, if (fd < 0) return fd; - ret = drm_syncobj_find_fence(file_private, handle, 0, &fence); + ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence); if (ret) goto err_put_fd; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 2814c72cb090..e688369ca82b 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -522,12 +522,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, kref_init(&exec->refcount); ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl, - 0, &exec->bin.in_fence); + 0, 0, &exec->bin.in_fence); if (ret == -EINVAL) goto fail; ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl, - 0, &exec->render.in_fence); + 0, 0, &exec->render.in_fence); if (ret == -EINVAL) goto fail; diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 5b22e996af6c..251198194c38 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data, if (args->in_sync) { ret = drm_syncobj_find_fence(file_priv, args->in_sync, - 0, &in_fence); + 0, 0, &in_fence); if (ret) goto fail; diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 425432b85a87..2eda44def639 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -134,7 +134,7 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, struct dma_fence *fence); int drm_syncobj_find_fence(struct drm_file *file_private, - u32 handle, u64 point, + u32 handle, u64 point, u64 flags, struct dma_fence **fence); void drm_syncobj_free(struct kref *kref); int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, -- cgit v1.2.3 From 48197bc564c7a1888c86024a1ba4f956e0ec2300 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Thu, 18 Oct 2018 14:18:36 +0800 Subject: drm: add syncobj timeline support v9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side: This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the following operations: * CPU query - A host operation that allows querying the payload of the timeline syncobj. * CPU wait - A host operation that allows a blocking wait for a timeline syncobj to reach a specified value. * Device wait - A device operation that allows waiting for a timeline syncobj to reach a specified value. * Device signal - A device operation that allows advancing the timeline syncobj to a specified value. v1: Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design: Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N]. b. wait PT design: Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that. v2: 1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian) 2. move unexposed denitions to .c file. (Daniel Vetter) 3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian) 4. split up the change to drm_syncobj_replace_fence() in a separate patch. 5. drop the submission_fence implementation and instead use wait_event() for that. (Christian) 6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter) v3: 1. replace normal syncobj with timeline implemenation. (Vetter and Christian) a. normal syncobj signal op will create a signal PT to tail of signal pt list. b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT. 2. many bug fix and clean up 3. stub fence moving is moved to other patch. v4: 1. fix RB tree loop with while(node=rb_first(...)). (Christian) 2. fix syncobj lifecycle. (Christian) 3. only enable_signaling when there is wait_pt. (Christian) 4. fix timeline path issues. 5. write a timeline test in libdrm v5: (Christian) 1. semaphore is called syncobj in kernel side. 2. don't need 'timeline' characters in some function name. 3. keep syncobj cb. v6: (Christian) 1. merge syncobj_timeline to syncobj structure. 2. simplify some check sentences. 3. some misc change. 4. fix CTS failed issue. v7: (Christian) 1. error handling when creating signal pt. 2. remove timeline naming in func. 3. export flags in find_fence. 4. allow reset timeline. v8: 1. use wait_event_interruptible without timeout 2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY v9: 1. rename signal_pt->base to signal_pt->fence_array to avoid misleading 2. improve kerneldoc individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9 Signed-off-by: Chunming Zhou Signed-off-by: Christian König Cc: Christian Konig Cc: Dave Airlie Cc: Daniel Rakos Cc: Daniel Vetter Cc: Bas Nieuwenhuizen Cc: Jason Ekstrand Reviewed-by: Christian König Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/257258/ --- drivers/gpu/drm/drm_syncobj.c | 306 +++++++++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- include/drm/drm_syncobj.h | 67 +++---- include/uapi/drm/drm.h | 1 + 4 files changed, 301 insertions(+), 75 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index e2c5b3ca4824..57bf6006394d 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -56,6 +56,9 @@ #include "drm_internal.h" #include +/* merge normal syncobj to timeline syncobj, the point interval is 1 */ +#define DRM_SYNCOBJ_BINARY_POINT 1 + struct drm_syncobj_stub_fence { struct dma_fence base; spinlock_t lock; @@ -71,6 +74,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { .get_timeline_name = drm_syncobj_stub_fence_get_name, }; +struct drm_syncobj_signal_pt { + struct dma_fence_array *fence_array; + u64 value; + struct list_head list; +}; /** * drm_syncobj_find - lookup and reference a sync object. @@ -113,8 +121,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, { int ret; - *fence = drm_syncobj_fence_get(syncobj); - if (*fence) + ret = drm_syncobj_search_fence(syncobj, 0, 0, fence); + if (!ret) return 1; spin_lock(&syncobj->lock); @@ -122,10 +130,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, * have the lock, try one more time just to be sure we don't add a * callback when a fence has already been set. */ - if (syncobj->fence) { - *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, - lockdep_is_held(&syncobj->lock))); - ret = 1; + if (!list_empty(&syncobj->signal_pt_list)) { + spin_unlock(&syncobj->lock); + drm_syncobj_search_fence(syncobj, 0, 0, fence); + if (*fence) + return 1; + spin_lock(&syncobj->lock); } else { *fence = NULL; drm_syncobj_add_callback_locked(syncobj, cb, func); @@ -153,6 +163,160 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, spin_unlock(&syncobj->lock); } +static void drm_syncobj_init(struct drm_syncobj *syncobj) +{ + spin_lock(&syncobj->lock); + syncobj->timeline_context = dma_fence_context_alloc(1); + syncobj->timeline = 0; + syncobj->signal_point = 0; + init_waitqueue_head(&syncobj->wq); + + INIT_LIST_HEAD(&syncobj->signal_pt_list); + spin_unlock(&syncobj->lock); +} + +static void drm_syncobj_fini(struct drm_syncobj *syncobj) +{ + struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp; + + spin_lock(&syncobj->lock); + list_for_each_entry_safe(signal_pt, tmp, + &syncobj->signal_pt_list, list) { + list_del(&signal_pt->list); + dma_fence_put(&signal_pt->fence_array->base); + kfree(signal_pt); + } + spin_unlock(&syncobj->lock); +} + +static struct dma_fence +*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj, + uint64_t point) +{ + struct drm_syncobj_signal_pt *signal_pt; + + if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) && + (point <= syncobj->timeline)) { + struct drm_syncobj_stub_fence *fence = + kzalloc(sizeof(struct drm_syncobj_stub_fence), + GFP_KERNEL); + + if (!fence) + return NULL; + spin_lock_init(&fence->lock); + dma_fence_init(&fence->base, + &drm_syncobj_stub_fence_ops, + &fence->lock, + syncobj->timeline_context, + point); + + dma_fence_signal(&fence->base); + return &fence->base; + } + + list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) { + if (point > signal_pt->value) + continue; + if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) && + (point != signal_pt->value)) + continue; + return dma_fence_get(&signal_pt->fence_array->base); + } + return NULL; +} + +static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj, + struct dma_fence *fence, + u64 point) +{ + struct drm_syncobj_signal_pt *signal_pt = + kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL); + struct drm_syncobj_signal_pt *tail_pt; + struct dma_fence **fences; + int num_fences = 0; + int ret = 0, i; + + if (!signal_pt) + return -ENOMEM; + if (!fence) + goto out; + + fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL); + if (!fences) { + ret = -ENOMEM; + goto out; + } + fences[num_fences++] = dma_fence_get(fence); + /* timeline syncobj must take this dependency */ + if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) { + spin_lock(&syncobj->lock); + if (!list_empty(&syncobj->signal_pt_list)) { + tail_pt = list_last_entry(&syncobj->signal_pt_list, + struct drm_syncobj_signal_pt, list); + fences[num_fences++] = + dma_fence_get(&tail_pt->fence_array->base); + } + spin_unlock(&syncobj->lock); + } + signal_pt->fence_array = dma_fence_array_create(num_fences, fences, + syncobj->timeline_context, + point, false); + if (!signal_pt->fence_array) { + ret = -ENOMEM; + goto fail; + } + + spin_lock(&syncobj->lock); + if (syncobj->signal_point >= point) { + DRM_WARN("A later signal is ready!"); + spin_unlock(&syncobj->lock); + goto exist; + } + signal_pt->value = point; + list_add_tail(&signal_pt->list, &syncobj->signal_pt_list); + syncobj->signal_point = point; + spin_unlock(&syncobj->lock); + wake_up_all(&syncobj->wq); + + return 0; +exist: + dma_fence_put(&signal_pt->fence_array->base); +fail: + for (i = 0; i < num_fences; i++) + dma_fence_put(fences[i]); + kfree(fences); +out: + kfree(signal_pt); + return ret; +} + +static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj) +{ + struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt; + + spin_lock(&syncobj->lock); + tail_pt = list_last_entry(&syncobj->signal_pt_list, + struct drm_syncobj_signal_pt, + list); + list_for_each_entry_safe(signal_pt, tmp, + &syncobj->signal_pt_list, list) { + if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY && + signal_pt == tail_pt) + continue; + if (dma_fence_is_signaled(&signal_pt->fence_array->base)) { + syncobj->timeline = signal_pt->value; + list_del(&signal_pt->list); + dma_fence_put(&signal_pt->fence_array->base); + kfree(signal_pt); + } else { + /*signal_pt is in order in list, from small to big, so + * the later must not be signal either */ + break; + } + } + + spin_unlock(&syncobj->lock); +} /** * drm_syncobj_replace_fence - replace fence in a sync object. * @syncobj: Sync object to replace fence in @@ -165,28 +329,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, struct dma_fence *fence) { - struct dma_fence *old_fence; - struct drm_syncobj_cb *cur, *tmp; - - if (fence) - dma_fence_get(fence); - - spin_lock(&syncobj->lock); - - old_fence = rcu_dereference_protected(syncobj->fence, - lockdep_is_held(&syncobj->lock)); - rcu_assign_pointer(syncobj->fence, fence); + u64 pt_value = point; + + drm_syncobj_garbage_collection(syncobj); + if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { + if (!fence) { + drm_syncobj_fini(syncobj); + drm_syncobj_init(syncobj); + return; + } + pt_value = syncobj->signal_point + + DRM_SYNCOBJ_BINARY_POINT; + } + drm_syncobj_create_signal_pt(syncobj, fence, pt_value); + if (fence) { + struct drm_syncobj_cb *cur, *tmp; - if (fence != old_fence) { + spin_lock(&syncobj->lock); list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) { list_del_init(&cur->node); cur->func(syncobj, cur); } + spin_unlock(&syncobj->lock); } - - spin_unlock(&syncobj->lock); - - dma_fence_put(old_fence); } EXPORT_SYMBOL(drm_syncobj_replace_fence); @@ -209,6 +374,64 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) return 0; } +static int +drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags, + struct dma_fence **fence) +{ + int ret = 0; + + if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { + ret = wait_event_interruptible(syncobj->wq, + point <= syncobj->signal_point); + if (ret < 0) + return ret; + } + spin_lock(&syncobj->lock); + *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point); + if (!*fence) + ret = -EINVAL; + spin_unlock(&syncobj->lock); + return ret; +} + +/** + * drm_syncobj_search_fence - lookup and reference the fence in a sync object or + * in a timeline point + * @syncobj: sync object pointer + * @point: timeline point + * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not + * @fence: out parameter for the fence + * + * if flags is DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, the function will block + * here until specific timeline points is reached. + * if not, you need a submit thread and block in userspace until all future + * timeline points have materialized, only then you can submit to the kernel, + * otherwise, function will fail to return fence. + * + * Returns 0 on success or a negative error value on failure. On success @fence + * contains a reference to the fence, which must be released by calling + * dma_fence_put(). + */ +int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, + u64 flags, struct dma_fence **fence) +{ + u64 pt_value = point; + + if (!syncobj) + return -ENOENT; + + drm_syncobj_garbage_collection(syncobj); + if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { + /*BINARY syncobj always wait on last pt */ + pt_value = syncobj->signal_point; + + if (pt_value == 0) + pt_value += DRM_SYNCOBJ_BINARY_POINT; + } + return drm_syncobj_point_get(syncobj, pt_value, flags, fence); +} +EXPORT_SYMBOL(drm_syncobj_search_fence); + /** * drm_syncobj_find_fence - lookup and reference the fence in a sync object * @file_private: drm file private pointer @@ -218,7 +441,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) * @fence: out parameter for the fence * * This is just a convenience function that combines drm_syncobj_find() and - * drm_syncobj_fence_get(). + * drm_syncobj_lookup_fence(). * * Returns 0 on success or a negative error value on failure. On success @fence * contains a reference to the fence, which must be released by calling @@ -229,15 +452,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private, struct dma_fence **fence) { struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); - int ret = 0; - - if (!syncobj) - return -ENOENT; + int ret; - *fence = drm_syncobj_fence_get(syncobj); - if (!*fence) { - ret = -EINVAL; - } + ret = drm_syncobj_search_fence(syncobj, point, flags, fence); drm_syncobj_put(syncobj); return ret; } @@ -254,7 +471,7 @@ void drm_syncobj_free(struct kref *kref) struct drm_syncobj *syncobj = container_of(kref, struct drm_syncobj, refcount); - drm_syncobj_replace_fence(syncobj, 0, NULL); + drm_syncobj_fini(syncobj); kfree(syncobj); } EXPORT_SYMBOL(drm_syncobj_free); @@ -284,6 +501,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, kref_init(&syncobj->refcount); INIT_LIST_HEAD(&syncobj->cb_list); spin_lock_init(&syncobj->lock); + if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) + syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE; + else + syncobj->type = DRM_SYNCOBJ_TYPE_BINARY; + drm_syncobj_init(syncobj); if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { ret = drm_syncobj_assign_null_handle(syncobj); @@ -566,7 +788,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data, return -EOPNOTSUPP; /* no valid flags yet */ - if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED) + if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED | + DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)) return -EINVAL; return drm_syncobj_create_as_handle(file_private, @@ -659,9 +882,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj, struct syncobj_wait_entry *wait = container_of(cb, struct syncobj_wait_entry, syncobj_cb); - /* This happens inside the syncobj lock */ - wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, - lockdep_is_held(&syncobj->lock))); + drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence); + wake_up_process(wait->task); } @@ -687,7 +909,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, signaled_count = 0; for (i = 0; i < count; ++i) { entries[i].task = current; - entries[i].fence = drm_syncobj_fence_get(syncobjs[i]); + drm_syncobj_search_fence(syncobjs[i], 0, 0, + &entries[i].fence); if (!entries[i].fence) { if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { continue; @@ -949,12 +1172,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; - for (i = 0; i < args->count_handles; i++) - drm_syncobj_replace_fence(syncobjs[i], 0, NULL); - + for (i = 0; i < args->count_handles; i++) { + drm_syncobj_fini(syncobjs[i]); + drm_syncobj_init(syncobjs[i]); + } drm_syncobj_array_free(syncobjs, args->count_handles); - return 0; + return ret; } int diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 22b4cb775576..6d99651c6c4b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -2152,7 +2152,7 @@ await_fence_array(struct i915_execbuffer *eb, if (!(flags & I915_EXEC_FENCE_WAIT)) continue; - fence = drm_syncobj_fence_get(syncobj); + drm_syncobj_search_fence(syncobj, 0, 0, &fence); if (!fence) return -EINVAL; diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 2eda44def639..5e8c5c027e09 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -30,10 +30,15 @@ struct drm_syncobj_cb; +enum drm_syncobj_type { + DRM_SYNCOBJ_TYPE_BINARY, + DRM_SYNCOBJ_TYPE_TIMELINE +}; + /** * struct drm_syncobj - sync object. * - * This structure defines a generic sync object which wraps a &dma_fence. + * This structure defines a generic sync object which is timeline based. */ struct drm_syncobj { /** @@ -41,19 +46,36 @@ struct drm_syncobj { */ struct kref refcount; /** - * @fence: - * NULL or a pointer to the fence bound to this object. - * - * This field should not be used directly. Use drm_syncobj_fence_get() - * and drm_syncobj_replace_fence() instead. + * @type: indicate syncobj type + */ + enum drm_syncobj_type type; + /** + * @wq: wait signal operation work queue + */ + wait_queue_head_t wq; + /** + * @timeline_context: fence context used by timeline */ - struct dma_fence __rcu *fence; + u64 timeline_context; /** - * @cb_list: List of callbacks to call when the &fence gets replaced. + * @timeline: syncobj timeline value, which indicates point is signaled. */ + u64 timeline; + /** + * @signal_point: which indicates the latest signaler point. + */ + u64 signal_point; + /** + * @signal_pt_list: signaler point list. + */ + struct list_head signal_pt_list; + + /** + * @cb_list: List of callbacks to call when the &fence gets replaced. + */ struct list_head cb_list; /** - * @lock: Protects &cb_list and write-locks &fence. + * @lock: Protects syncobj list and write-locks &fence. */ spinlock_t lock; /** @@ -68,7 +90,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj, /** * struct drm_syncobj_cb - callback for drm_syncobj_add_callback * @node: used by drm_syncob_add_callback to append this struct to - * &drm_syncobj.cb_list + * &drm_syncobj.cb_list * @func: drm_syncobj_func_t to call * * This struct will be initialized by drm_syncobj_add_callback, additional @@ -106,29 +128,6 @@ drm_syncobj_put(struct drm_syncobj *obj) kref_put(&obj->refcount, drm_syncobj_free); } -/** - * drm_syncobj_fence_get - get a reference to a fence in a sync object - * @syncobj: sync object. - * - * This acquires additional reference to &drm_syncobj.fence contained in @obj, - * if not NULL. It is illegal to call this without already holding a reference. - * No locks required. - * - * Returns: - * Either the fence of @obj or NULL if there's none. - */ -static inline struct dma_fence * -drm_syncobj_fence_get(struct drm_syncobj *syncobj) -{ - struct dma_fence *fence; - - rcu_read_lock(); - fence = dma_fence_get_rcu_safe(&syncobj->fence); - rcu_read_unlock(); - - return fence; -} - struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle); void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, @@ -142,5 +141,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, int drm_syncobj_get_handle(struct drm_file *file_private, struct drm_syncobj *syncobj, u32 *handle); int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd); +int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags, + struct dma_fence **fence); #endif diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 300f336633f2..cebdb2541eb7 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -717,6 +717,7 @@ struct drm_prime_handle { struct drm_syncobj_create { __u32 handle; #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) +#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1) __u32 flags; }; -- cgit v1.2.3 From 4c953d03970a39d034ee2c860bbd65f5970aa2ce Mon Sep 17 00:00:00 2001 From: Manasi Navare Date: Mon, 8 Oct 2018 17:23:51 -0700 Subject: drm/dp: Add definitions for eDP Rev 1.4a and 1.4b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VESA eDP 1.4 specification has separate fields defined in EDP_DPCD_REV for eDP 1.4a and 1.4b eDP revisions. This patch defines those. Found this when one of my eDP panels advertises eDP 1.4a (04h) in the EDP_DPCD_REV DPCD field. Cc: Jani Nikula Cc: Ville Syrjala Signed-off-by: Manasi Navare Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181009002351.23085-1-manasi.d.navare@intel.com --- include/drm/drm_dp_helper.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/drm') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 2a3843f248cf..9ad98e8d9ede 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -685,6 +685,8 @@ # define DP_EDP_12 0x01 # define DP_EDP_13 0x02 # define DP_EDP_14 0x03 +# define DP_EDP_14a 0x04 /* eDP 1.4a */ +# define DP_EDP_14b 0x05 /* eDP 1.4b */ #define DP_EDP_GENERAL_CAP_1 0x701 # define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0) -- cgit v1.2.3 From 9c71a6686bfa4bd8404d1bfa8f210b9901991fa9 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Fri, 19 Oct 2018 11:57:44 +0100 Subject: drm: fourcc: Convert drm_format_info kerneldoc to in-line member documentation In-line member documentation seems to be desired way of documenting structure members. This change had been suggested by Daniel Vetter here: https://lists.freedesktop.org/archives/dri-devel/2018-October/192176.html Signed-off-by: Alexandru Gheorghe Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20181019105752.17741-2-alexandru-cosmin.gheorghe@arm.com --- include/drm/drm_fourcc.h | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 865ef60c17af..345f11227e9e 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -52,25 +52,35 @@ struct drm_mode_fb_cmd2; /** * struct drm_format_info - information about a DRM format - * @format: 4CC format identifier (DRM_FORMAT_*) - * @depth: Color depth (number of bits per pixel excluding padding bits), - * valid for a subset of RGB formats only. This is a legacy field, do not - * use in new code and set to 0 for new formats. - * @num_planes: Number of color planes (1 to 3) - * @cpp: Number of bytes per pixel (per plane) - * @hsub: Horizontal chroma subsampling factor - * @vsub: Vertical chroma subsampling factor - * @has_alpha: Does the format embeds an alpha component? - * @is_yuv: Is it a YUV format? */ struct drm_format_info { + /** @format: 4CC format identifier (DRM_FORMAT_*) */ u32 format; + + /** + * @depth: + * + * Color depth (number of bits per pixel excluding padding bits), + * valid for a subset of RGB formats only. This is a legacy field, do + * not use in new code and set to 0 for new formats. + */ u8 depth; + + /** @num_planes: Number of color planes (1 to 3) */ u8 num_planes; + + /** @cpp: Number of bytes per pixel (per plane) */ u8 cpp[3]; + + /** @hsub: Horizontal chroma subsampling factor */ u8 hsub; + /** @vsub: Vertical chroma subsampling factor */ u8 vsub; + + /** @has_alpha: Does the format embeds an alpha component? */ bool has_alpha; + + /** @is_yuv: Is it a YUV format? */ bool is_yuv; }; -- cgit v1.2.3 From 43cf1fc0e27e2f7eeb5d6c15fd023813a5b49987 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Tue, 23 Oct 2018 17:37:45 +0800 Subject: drm: fix deadlock of syncobj v6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: add a mutex between sync_cb execution and free. v3: clearly separating the roles for pt_lock and cb_mutex (Chris) v4: the cb_mutex should be taken outside of the pt_lock around this if() block. (Chris) v5: fix a corner case v6: tidy drm_syncobj_fence_get_or_add_callback up. (Chris) Tested by syncobj_basic and syncobj_wait of igt. Signed-off-by: Chunming Zhou Cc: Daniel Vetter Cc: Chris Wilson Cc: Christian König Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Chris Wilson Signed-off-by: Christian König Link: https://patchwork.kernel.org/patch/10652893/ --- drivers/gpu/drm/drm_syncobj.c | 156 ++++++++++++++++++++---------------------- include/drm/drm_syncobj.h | 8 ++- 2 files changed, 81 insertions(+), 83 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 57bf6006394d..b7eaa603f368 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -106,6 +106,42 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, } EXPORT_SYMBOL(drm_syncobj_find); +static struct dma_fence +*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj, + uint64_t point) +{ + struct drm_syncobj_signal_pt *signal_pt; + + if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) && + (point <= syncobj->timeline)) { + struct drm_syncobj_stub_fence *fence = + kzalloc(sizeof(struct drm_syncobj_stub_fence), + GFP_KERNEL); + + if (!fence) + return NULL; + spin_lock_init(&fence->lock); + dma_fence_init(&fence->base, + &drm_syncobj_stub_fence_ops, + &fence->lock, + syncobj->timeline_context, + point); + + dma_fence_signal(&fence->base); + return &fence->base; + } + + list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) { + if (point > signal_pt->value) + continue; + if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) && + (point != signal_pt->value)) + continue; + return dma_fence_get(&signal_pt->fence_array->base); + } + return NULL; +} + static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, struct drm_syncobj_cb *cb, drm_syncobj_func_t func) @@ -114,115 +150,71 @@ static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, list_add_tail(&cb->node, &syncobj->cb_list); } -static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, - struct dma_fence **fence, - struct drm_syncobj_cb *cb, - drm_syncobj_func_t func) +static void drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, + struct dma_fence **fence, + struct drm_syncobj_cb *cb, + drm_syncobj_func_t func) { - int ret; + u64 pt_value = 0; - ret = drm_syncobj_search_fence(syncobj, 0, 0, fence); - if (!ret) - return 1; + if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { + /*BINARY syncobj always wait on last pt */ + pt_value = syncobj->signal_point; - spin_lock(&syncobj->lock); - /* We've already tried once to get a fence and failed. Now that we - * have the lock, try one more time just to be sure we don't add a - * callback when a fence has already been set. - */ - if (!list_empty(&syncobj->signal_pt_list)) { - spin_unlock(&syncobj->lock); - drm_syncobj_search_fence(syncobj, 0, 0, fence); - if (*fence) - return 1; - spin_lock(&syncobj->lock); - } else { - *fence = NULL; - drm_syncobj_add_callback_locked(syncobj, cb, func); - ret = 0; + if (pt_value == 0) + pt_value += DRM_SYNCOBJ_BINARY_POINT; } - spin_unlock(&syncobj->lock); - return ret; + mutex_lock(&syncobj->cb_mutex); + spin_lock(&syncobj->pt_lock); + *fence = drm_syncobj_find_signal_pt_for_point(syncobj, pt_value); + spin_unlock(&syncobj->pt_lock); + if (!*fence) + drm_syncobj_add_callback_locked(syncobj, cb, func); + mutex_unlock(&syncobj->cb_mutex); } void drm_syncobj_add_callback(struct drm_syncobj *syncobj, struct drm_syncobj_cb *cb, drm_syncobj_func_t func) { - spin_lock(&syncobj->lock); + mutex_lock(&syncobj->cb_mutex); drm_syncobj_add_callback_locked(syncobj, cb, func); - spin_unlock(&syncobj->lock); + mutex_unlock(&syncobj->cb_mutex); } void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, struct drm_syncobj_cb *cb) { - spin_lock(&syncobj->lock); + mutex_lock(&syncobj->cb_mutex); list_del_init(&cb->node); - spin_unlock(&syncobj->lock); + mutex_unlock(&syncobj->cb_mutex); } static void drm_syncobj_init(struct drm_syncobj *syncobj) { - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); syncobj->timeline_context = dma_fence_context_alloc(1); syncobj->timeline = 0; syncobj->signal_point = 0; init_waitqueue_head(&syncobj->wq); INIT_LIST_HEAD(&syncobj->signal_pt_list); - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); } static void drm_syncobj_fini(struct drm_syncobj *syncobj) { struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp; - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); list_for_each_entry_safe(signal_pt, tmp, &syncobj->signal_pt_list, list) { list_del(&signal_pt->list); dma_fence_put(&signal_pt->fence_array->base); kfree(signal_pt); } - spin_unlock(&syncobj->lock); -} - -static struct dma_fence -*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj, - uint64_t point) -{ - struct drm_syncobj_signal_pt *signal_pt; - - if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) && - (point <= syncobj->timeline)) { - struct drm_syncobj_stub_fence *fence = - kzalloc(sizeof(struct drm_syncobj_stub_fence), - GFP_KERNEL); - - if (!fence) - return NULL; - spin_lock_init(&fence->lock); - dma_fence_init(&fence->base, - &drm_syncobj_stub_fence_ops, - &fence->lock, - syncobj->timeline_context, - point); - - dma_fence_signal(&fence->base); - return &fence->base; - } - - list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) { - if (point > signal_pt->value) - continue; - if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) && - (point != signal_pt->value)) - continue; - return dma_fence_get(&signal_pt->fence_array->base); - } - return NULL; + spin_unlock(&syncobj->pt_lock); } static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj, @@ -249,14 +241,14 @@ static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj, fences[num_fences++] = dma_fence_get(fence); /* timeline syncobj must take this dependency */ if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) { - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); if (!list_empty(&syncobj->signal_pt_list)) { tail_pt = list_last_entry(&syncobj->signal_pt_list, struct drm_syncobj_signal_pt, list); fences[num_fences++] = dma_fence_get(&tail_pt->fence_array->base); } - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); } signal_pt->fence_array = dma_fence_array_create(num_fences, fences, syncobj->timeline_context, @@ -266,16 +258,16 @@ static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj, goto fail; } - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); if (syncobj->signal_point >= point) { DRM_WARN("A later signal is ready!"); - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); goto exist; } signal_pt->value = point; list_add_tail(&signal_pt->list, &syncobj->signal_pt_list); syncobj->signal_point = point; - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); wake_up_all(&syncobj->wq); return 0; @@ -294,7 +286,7 @@ static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj) { struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt; - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); tail_pt = list_last_entry(&syncobj->signal_pt_list, struct drm_syncobj_signal_pt, list); @@ -315,7 +307,7 @@ static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj) } } - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); } /** * drm_syncobj_replace_fence - replace fence in a sync object. @@ -344,13 +336,14 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, drm_syncobj_create_signal_pt(syncobj, fence, pt_value); if (fence) { struct drm_syncobj_cb *cur, *tmp; + LIST_HEAD(cb_list); - spin_lock(&syncobj->lock); + mutex_lock(&syncobj->cb_mutex); list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) { list_del_init(&cur->node); cur->func(syncobj, cur); } - spin_unlock(&syncobj->lock); + mutex_unlock(&syncobj->cb_mutex); } } EXPORT_SYMBOL(drm_syncobj_replace_fence); @@ -386,11 +379,11 @@ drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags, if (ret < 0) return ret; } - spin_lock(&syncobj->lock); + spin_lock(&syncobj->pt_lock); *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point); if (!*fence) ret = -EINVAL; - spin_unlock(&syncobj->lock); + spin_unlock(&syncobj->pt_lock); return ret; } @@ -500,7 +493,8 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, kref_init(&syncobj->refcount); INIT_LIST_HEAD(&syncobj->cb_list); - spin_lock_init(&syncobj->lock); + spin_lock_init(&syncobj->pt_lock); + mutex_init(&syncobj->cb_mutex); if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE; else diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 5e8c5c027e09..29244cbcd05e 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -75,9 +75,13 @@ struct drm_syncobj { */ struct list_head cb_list; /** - * @lock: Protects syncobj list and write-locks &fence. + * @pt_lock: Protects pt list. */ - spinlock_t lock; + spinlock_t pt_lock; + /** + * @cb_mutex: Protects syncobj cb list. + */ + struct mutex cb_mutex; /** * @file: A file backing for this syncobj. */ -- cgit v1.2.3 From 8dc830e4cf6eb529e66168c2604e00311e713d77 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 18 Sep 2018 22:09:03 +0530 Subject: drm/rcar-du: Convert drm_atomic_helper_suspend/resume() convert drm_atomic_helper_suspend/resume() to use drm_mode_config_helper_suspend/resume(). remove suspend_state field from the rcar_du_device structure as it is no more required. With this conversion, also drm_fbdev_cma_set_suspend_unlocked() will left with no consumer. So this function can be removed. Signed-off-by: Souptick Joarder Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180918163903.GA11172@jordon-HP-15-Notebook-PC --- drivers/gpu/drm/drm_fb_cma_helper.c | 18 ------------------ drivers/gpu/drm/rcar-du/rcar_du_drv.c | 21 ++------------------- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 - include/drm/drm_fb_cma_helper.h | 2 -- 4 files changed, 2 insertions(+), 40 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index d52344a03aa8..fc2b42dd3dc6 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -221,21 +221,3 @@ void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma) drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper); } EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event); - -/** - * drm_fbdev_cma_set_suspend_unlocked - wrapper around - * drm_fb_helper_set_suspend_unlocked - * @fbdev_cma: The drm_fbdev_cma struct, may be NULL - * @state: desired state, zero to resume, non-zero to suspend - * - * Calls drm_fb_helper_set_suspend, which is a wrapper around - * fb_set_suspend implemented by fbdev core. - */ -void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, - bool state) -{ - if (fbdev_cma) - drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper, - state); -} -EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 084f58df4a8c..7015974c247a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -404,32 +404,15 @@ static struct drm_driver rcar_du_driver = { static int rcar_du_pm_suspend(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev); - struct drm_atomic_state *state; - drm_kms_helper_poll_disable(rcdu->ddev); - drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true); - - state = drm_atomic_helper_suspend(rcdu->ddev); - if (IS_ERR(state)) { - drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false); - drm_kms_helper_poll_enable(rcdu->ddev); - return PTR_ERR(state); - } - - rcdu->suspend_state = state; - - return 0; + return drm_mode_config_helper_suspend(rcdu->ddev); } static int rcar_du_pm_resume(struct device *dev) { struct rcar_du_device *rcdu = dev_get_drvdata(dev); - drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state); - drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false); - drm_kms_helper_poll_enable(rcdu->ddev); - - return 0; + return drm_mode_config_helper_resume(rcdu->ddev); } #endif diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 143c037e2c0f..9f5563296c5a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -79,7 +79,6 @@ struct rcar_du_device { struct drm_device *ddev; struct drm_fbdev_cma *fbdev; - struct drm_atomic_state *suspend_state; struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS]; unsigned int num_crtcs; diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index 4a65f0d155b0..8dbbe1eece1b 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -26,8 +26,6 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); -void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma, - bool state); struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); -- cgit v1.2.3 From 6217f0ec7f111733f31b6ed158df2bf5a4ed28c4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Oct 2018 22:24:46 +0200 Subject: drm/doc: kerneldoc for quirk_addfb_prefer_xbgr_30bpp Shuts up warning noise. Reviewed-by: Alexandru Gheorghe Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181004202446.22905-22-daniel.vetter@ffwll.ch --- include/drm/drm_mode_config.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/drm') diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 928e4172a0bb..d643d268693e 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -809,6 +809,13 @@ struct drm_mode_config { /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; + + /** + * @quirk_addfb_prefer_xbgr_30bpp: + * + * Special hack for legacy ADDFB to keep nouveau userspace happy. Should + * only ever be set by the nouveau kernel driver. + */ bool quirk_addfb_prefer_xbgr_30bpp; /** -- cgit v1.2.3 From e982e3f02071473cd1211e26cbe74a56b5be0aa0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 23 Oct 2018 09:24:22 +0200 Subject: drm: dsi: Add lane clock rate fields to DSI device The DSI devices have a maximum operating frequency specified in their data sheet per the MIPI specification, and DSI hosts that can scale their frequency need this information to set their clock dividers right. As current panel drivers often lack this information, specify that setting it to zero will make the DSI host use some reasonable default. Reviewed-by: Andrzej Hajda Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20181023072422.25754-1-linus.walleij@linaro.org --- include/drm/drm_mipi_dsi.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/drm') diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 4fef19064b0f..491528f48cfb 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -168,6 +168,12 @@ struct mipi_dsi_device_info { * @format: pixel format for video mode * @lanes: number of active data lanes * @mode_flags: DSI operation mode related flags + * @hs_rate: maximum lane frequency for high speed mode in hertz, this should + * be set to the real limits of the hardware, zero is only accepted for + * legacy drivers + * @lp_rate: maximum lane frequency for low power mode in hertz, this should + * be set to the real limits of the hardware, zero is only accepted for + * legacy drivers */ struct mipi_dsi_device { struct mipi_dsi_host *host; @@ -178,6 +184,8 @@ struct mipi_dsi_device { unsigned int lanes; enum mipi_dsi_pixel_format format; unsigned long mode_flags; + unsigned long hs_rate; + unsigned long lp_rate; }; #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:" -- cgit v1.2.3 From f6764815358b57c520ea137599e8297479bded4c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 23 Oct 2018 19:12:47 -0400 Subject: drm/dp_mst: Remove all evil duplicate state pointers There's no reason to track the atomic state three times. Unfortunately, this is currently what we're doing, and even worse is that there is only one actually correct state pointer: the one in mst_state->base.state. mgr->state never seems to be used, along with the one in mst_state->state. This confused me for over 4 hours until I realized there was no magic behind these pointers. So, let's save everyone else from the trouble. Signed-off-by: Lyude Paul . Cc: Daniel Vetter Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181023231251.16883-3-lyude@redhat.com --- include/drm/drm_dp_mst_helper.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 7f78d26a0766..59f005b419cf 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -409,7 +409,6 @@ struct drm_dp_payload { struct drm_dp_mst_topology_state { struct drm_private_state base; int avail_slots; - struct drm_atomic_state *state; struct drm_dp_mst_topology_mgr *mgr; }; @@ -497,11 +496,6 @@ struct drm_dp_mst_topology_mgr { */ int pbn_div; - /** - * @state: State information for topology manager - */ - struct drm_dp_mst_topology_state *state; - /** * @funcs: Atomic helper callbacks */ -- cgit v1.2.3 From f2b0e264657061667be7df1575b82777cf622b73 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 1 Oct 2018 14:38:40 +0200 Subject: drm/bridge/synopsys: dsi: don't call __dw_mipi_dsi_probe from dw_mipi_dsi_bind __dw_mipi_dsi_probe() does all the grabbing of resources and does it using devm-helpers. So this is happening on each try of master bringup possibly slowing down things a lot. Drivers using the component framework may instead want to call dw_mipi_dsi_probe separately in their probe function to setup resources early. That way the dsi bus also gets created earlier and also not recreated on each bind-try, so that attached panels can load their modules and be probed way before the bridge-attach in the bind call. So drop the call to __dw_mipi_dsi_probe and modify the function to take a struct dw_mipi_dsi instead of the platform-device. Signed-off-by: Heiko Stuebner Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-3-heiko@sntech.de --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 15 +++------------ include/drm/bridge/dw_mipi_dsi.h | 5 +---- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 07cde255cab2..bb4aeca5c0f9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -966,31 +966,22 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); /* * Bind/unbind API, used from platforms based on the component framework. */ -struct dw_mipi_dsi * -dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder, - const struct dw_mipi_dsi_plat_data *plat_data) +int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder) { - struct dw_mipi_dsi *dsi; int ret; - dsi = __dw_mipi_dsi_probe(pdev, plat_data); - if (IS_ERR(dsi)) - return dsi; - ret = drm_bridge_attach(encoder, &dsi->bridge, NULL); if (ret) { - dw_mipi_dsi_remove(dsi); DRM_ERROR("Failed to initialize bridge with drm\n"); - return ERR_PTR(ret); + return ret; } - return dsi; + return ret; } EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) { - __dw_mipi_dsi_remove(dsi); } EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index d9c6d549f971..6d7f8eb5d9f2 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -35,10 +35,7 @@ struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev, const struct dw_mipi_dsi_plat_data *plat_data); void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi); -struct dw_mipi_dsi *dw_mipi_dsi_bind(struct platform_device *pdev, - struct drm_encoder *encoder, - const struct dw_mipi_dsi_plat_data - *plat_data); +int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder); void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi); #endif /* __DW_MIPI_DSI__ */ -- cgit v1.2.3 From 90910a6511238dd8d25ac007d97a2c0ddfa24e51 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 1 Oct 2018 14:38:41 +0200 Subject: drm/bridge/synopsys: dsi: add ability to have glue-specific attach and detach With the regular means of adding the dsi-component in probe it creates a race condition with the panel probing, as the panel device only gets created after the dsi-bus got created. When the panel-driver is build as a module it currently fails hard as the panel cannot be probed directly: dw_mipi_dsi_bind() __dw_mipi_dsi_probe() creates dsi bus creates panel device triggers panel module load panel not probed (module not loaded or panel probe slow) drm_bridge_attach fails with -EINVAL due to empty panel_bridge Additionally the panel probing can run concurrently with dsi bringup making it possible that the panel can already be found but dsi-attach hasn't finished running. To solve that cleanly we may want to only create the component after the panel has finished probing, by calling component_add from the host-attach dsi callback. As that is specific to glue drivers, add a new struct for host_ops so that glue drivers can tell the bridge to call specific functions after the common host-attach and before the common host-detach run. Suggested-by: Andrzej Hajda Reviewed-by: Andrzej Hajda Signed-off-by: Heiko Stuebner Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-4-heiko@sntech.de --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 15 +++++++++++++++ include/drm/bridge/dw_mipi_dsi.h | 8 ++++++++ 2 files changed, 23 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index bb4aeca5c0f9..3962e5d84e1e 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -270,6 +270,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct dw_mipi_dsi *dsi = host_to_dsi(host); + const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; struct drm_bridge *bridge; struct drm_panel *panel; int ret; @@ -300,6 +301,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, drm_bridge_add(&dsi->bridge); + if (pdata->host_ops && pdata->host_ops->attach) { + ret = pdata->host_ops->attach(pdata->priv_data, device); + if (ret < 0) + return ret; + } + return 0; } @@ -307,6 +314,14 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct dw_mipi_dsi *dsi = host_to_dsi(host); + const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; + int ret; + + if (pdata->host_ops && pdata->host_ops->detach) { + ret = pdata->host_ops->detach(pdata->priv_data, device); + if (ret < 0) + return ret; + } drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 6d7f8eb5d9f2..a9c03099cf3e 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -19,6 +19,13 @@ struct dw_mipi_dsi_phy_ops { unsigned int *lane_mbps); }; +struct dw_mipi_dsi_host_ops { + int (*attach)(void *priv_data, + struct mipi_dsi_device *dsi); + int (*detach)(void *priv_data, + struct mipi_dsi_device *dsi); +}; + struct dw_mipi_dsi_plat_data { void __iomem *base; unsigned int max_data_lanes; @@ -27,6 +34,7 @@ struct dw_mipi_dsi_plat_data { const struct drm_display_mode *mode); const struct dw_mipi_dsi_phy_ops *phy_ops; + const struct dw_mipi_dsi_host_ops *host_ops; void *priv_data; }; -- cgit v1.2.3 From 739838b5f88642dbef7f91dec4fcf8b7f9d0bc46 Mon Sep 17 00:00:00 2001 From: Nickey Yang Date: Mon, 1 Oct 2018 14:38:44 +0200 Subject: drm/bridge/synopsys: dsi: add dual-dsi support Allow to also drive a slave dw-mipi-dsi controller in a dual-dsi setup. This will require additional implementation-specific code to look up the slave instance and do specific setup. Also will probably need code in the specific crtcs as dual-dsi does not equal two separate dsi outputs. To activate, the implementation-specific code should set the slave using dw_mipi_dsi_set_slave() before calling __dw_mipi_dsi_bind(). v2: - expect real interface number of lanes - keep links to both master and slave v3: - remove unneeded separate variables - remove unneeded second slave settings - disable slave before master - lane-sum calculation comments Signed-off-by: Nickey Yang Signed-off-by: Heiko Stuebner Tested-by: Philippe Cornu Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-7-heiko@sntech.de --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 80 +++++++++++++++++++++++++-- include/drm/bridge/dw_mipi_dsi.h | 1 + 2 files changed, 75 insertions(+), 6 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 3962e5d84e1e..2f4b145b73af 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -230,9 +230,20 @@ struct dw_mipi_dsi { u32 format; unsigned long mode_flags; + struct dw_mipi_dsi *master; /* dual-dsi master ptr */ + struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */ + const struct dw_mipi_dsi_plat_data *plat_data; }; +/* + * Check if either a link to a master or slave is present + */ +static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi) +{ + return dsi->slave || dsi->master; +} + /* * The controller should generate 2 frames before * preparing the peripheral. @@ -456,10 +467,17 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, } dw_mipi_message_config(dsi, msg); + if (dsi->slave) + dw_mipi_message_config(dsi->slave, msg); ret = dw_mipi_dsi_write(dsi, &packet); if (ret) return ret; + if (dsi->slave) { + ret = dw_mipi_dsi_write(dsi->slave, &packet); + if (ret) + return ret; + } if (msg->rx_buf && msg->rx_len) { ret = dw_mipi_dsi_read(dsi, msg); @@ -598,7 +616,11 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, * DSI_VNPCR.NPSIZE... especially because this driver supports * non-burst video modes, see dw_mipi_dsi_video_mode_config()... */ - dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay)); + + dsi_write(dsi, DSI_VID_PKT_SIZE, + dw_mipi_is_dual_mode(dsi) ? + VID_PKT_SIZE(mode->hdisplay / 2) : + VID_PKT_SIZE(mode->hdisplay)); } static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) @@ -770,24 +792,43 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) */ dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); + if (dsi->slave) { + dw_mipi_dsi_disable(dsi->slave); + clk_disable_unprepare(dsi->slave->pclk); + pm_runtime_put(dsi->slave->dev); + } dw_mipi_dsi_disable(dsi); + clk_disable_unprepare(dsi->pclk); pm_runtime_put(dsi->dev); } -static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi) +{ + /* this instance is the slave, so add the master's lanes */ + if (dsi->master) + return dsi->master->lanes + dsi->lanes; + + /* this instance is the master, so add the slave's lanes */ + if (dsi->slave) + return dsi->lanes + dsi->slave->lanes; + + /* single-dsi, so no other instance to consider */ + return dsi->lanes; +} + +static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, + struct drm_display_mode *adjusted_mode) { - struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; void *priv_data = dsi->plat_data->priv_data; int ret; + u32 lanes = dw_mipi_dsi_get_lanes(dsi); clk_prepare_enable(dsi->pclk); ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags, - dsi->lanes, dsi->format, &dsi->lane_mbps); + lanes, dsi->format, &dsi->lane_mbps); if (ret) DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n"); @@ -819,12 +860,25 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, dw_mipi_dsi_set_mode(dsi, 0); } +static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); + + dw_mipi_dsi_mode_set(dsi, adjusted_mode); + if (dsi->slave) + dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); +} + static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); /* Switch to video mode for panel-bridge enable & panel enable */ dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); + if (dsi->slave) + dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); } static enum drm_mode_status @@ -961,6 +1015,20 @@ static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) pm_runtime_disable(dsi->dev); } +void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave) +{ + /* introduce controllers to each other */ + dsi->slave = slave; + dsi->slave->master = dsi; + + /* migrate settings for already attached displays */ + dsi->slave->lanes = dsi->lanes; + dsi->slave->channel = dsi->channel; + dsi->slave->format = dsi->format; + dsi->slave->mode_flags = dsi->mode_flags; +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave); + /* * Probe/remove API, used from platforms based on the DRM bridge API. */ diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index a9c03099cf3e..48a671e782ca 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -45,5 +45,6 @@ struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev, void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi); int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder); void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi); +void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave); #endif /* __DW_MIPI_DSI__ */ -- cgit v1.2.3 From 042bf753842ddbddcf3d4c29f21a8905d6a33e79 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Thu, 1 Nov 2018 17:02:05 +0000 Subject: drm/fourcc: Add char_per_block, block_w and block_h in drm_format_info For some pixel formats .cpp structure in drm_format info it's not enough to describe the peculiarities of the pixel layout, for example tiled formats or packed formats at bit level. What's implemented here is to add three new members to drm_format_info that could describe such formats: - char_per_block[3] - block_w[3] - block_h[3] char_per_block will be put in a union alongside cpp, for transparent compatibility with the existing format descriptions. Regarding, block_w and block_h they are intended to be used through their equivalent getters drm_format_info_block_width / drm_format_info_block_height, the reason of the getters is to abstract the fact that for normal formats block_w and block_h will be unset/0, but the methods will be returning 1. Additionally, convenience function drm_format_info_min_pitch had been added that computes the minimum required pitch for a given pixel format and buffer width. Using that the following drm core functions had been updated to generically handle both block and non-block formats: - drm_fb_cma_get_gem_addr: for block formats it will just return the beginning of the block. - framebuffer_check: Use the newly added drm_format_info_min_pitch. - drm_gem_fb_create_with_funcs: Use the newly added drm_format_info_min_pitch. - In places where is not expecting to handle block formats, like fbdev helpers I just added some warnings in case the block width/height are greater than 1. Changes since v3: - Add helper function for computing the minimum required pitch. - Improve/cleanup documentation Changes since v8: - Fixed build on 32bits arm architectures, with: - return DIV_ROUND_UP((u64)buffer_width * info->char_per_block[plane], + return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane], Reviewed-by: Brian Starkey Reviewed-by: Daniel Vetter Signed-off-by: Alexandru Gheorghe Link: https://patchwork.freedesktop.org/patch/msgid/20181101170055.5433-1-alexandru-cosmin.gheorghe@arm.com --- drivers/gpu/drm/drm_fb_cma_helper.c | 20 +++++++-- drivers/gpu/drm/drm_fb_helper.c | 6 +++ drivers/gpu/drm/drm_fourcc.c | 62 ++++++++++++++++++++++++++++ drivers/gpu/drm/drm_framebuffer.c | 6 +-- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 2 +- include/drm/drm_fourcc.h | 61 ++++++++++++++++++++++++++- 6 files changed, 148 insertions(+), 9 deletions(-) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index fc2b42dd3dc6..b07ab3f613e0 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -72,7 +72,9 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); /** - * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer + * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel + * formats where values are grouped in blocks this will get you the beginning of + * the block * @fb: The framebuffer * @state: Which state of drm plane * @plane: Which plane @@ -87,6 +89,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, struct drm_gem_cma_object *obj; dma_addr_t paddr; u8 h_div = 1, v_div = 1; + u32 block_w = drm_format_info_block_width(fb->format, plane); + u32 block_h = drm_format_info_block_height(fb->format, plane); + u32 block_size = fb->format->char_per_block[plane]; + u32 sample_x; + u32 sample_y; + u32 block_start_y; + u32 num_hblocks; obj = drm_fb_cma_get_gem_obj(fb, plane); if (!obj) @@ -99,8 +108,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, v_div = fb->format->vsub; } - paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div; - paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div; + sample_x = (state->src_x >> 16) / h_div; + sample_y = (state->src_y >> 16) / v_div; + block_start_y = (sample_y / block_h) * block_h; + num_hblocks = sample_x / block_w; + + paddr += fb->pitches[plane] * block_start_y; + paddr += block_size * num_hblocks; return paddr; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9b111e846847..8024524f0547 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1614,6 +1614,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, if (var->pixclock != 0 || in_dbg_master()) return -EINVAL; + if ((drm_format_info_block_width(fb->format, 0) > 1) || + (drm_format_info_block_height(fb->format, 0) > 1)) + return -EINVAL; + /* * Changes struct fb_var_screeninfo are currently not pushed back * to KMS, hence fail if different settings are requested. @@ -1988,6 +1992,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe { struct drm_framebuffer *fb = fb_helper->fb; + WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) || + (drm_format_info_block_height(fb->format, 0) > 1)); info->pseudo_palette = fb_helper->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 3934527e09dc..8c4a79b3a4ad 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -400,3 +400,65 @@ int drm_format_plane_height(int height, uint32_t format, int plane) return height / info->vsub; } EXPORT_SYMBOL(drm_format_plane_height); + +/** + * drm_format_info_block_width - width in pixels of block. + * @info: pixel format info + * @plane: plane index + * + * Returns: + * The width in pixels of a block, depending on the plane index. + */ +unsigned int drm_format_info_block_width(const struct drm_format_info *info, + int plane) +{ + if (!info || plane < 0 || plane >= info->num_planes) + return 0; + + if (!info->block_w[plane]) + return 1; + return info->block_w[plane]; +} +EXPORT_SYMBOL(drm_format_info_block_width); + +/** + * drm_format_info_block_height - height in pixels of a block + * @info: pixel format info + * @plane: plane index + * + * Returns: + * The height in pixels of a block, depending on the plane index. + */ +unsigned int drm_format_info_block_height(const struct drm_format_info *info, + int plane) +{ + if (!info || plane < 0 || plane >= info->num_planes) + return 0; + + if (!info->block_h[plane]) + return 1; + return info->block_h[plane]; +} +EXPORT_SYMBOL(drm_format_info_block_height); + +/** + * drm_format_info_min_pitch - computes the minimum required pitch in bytes + * @info: pixel format info + * @plane: plane index + * @buffer_width: buffer width in pixels + * + * Returns: + * The minimum required pitch in bytes for a buffer by taking into consideration + * the pixel format information and the buffer width. + */ +uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, + int plane, unsigned int buffer_width) +{ + if (!info || plane < 0 || plane >= info->num_planes) + return 0; + + return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane], + drm_format_info_block_width(info, plane) * + drm_format_info_block_height(info, plane)); +} +EXPORT_SYMBOL(drm_format_info_min_pitch); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 3bf729d0aae5..6aca8a1ccdb6 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -195,20 +195,20 @@ static int framebuffer_check(struct drm_device *dev, for (i = 0; i < info->num_planes; i++) { unsigned int width = fb_plane_width(r->width, info, i); unsigned int height = fb_plane_height(r->height, info, i); - unsigned int cpp = info->cpp[i]; + u64 min_pitch = drm_format_info_min_pitch(info, i, width); if (!r->handles[i]) { DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); return -EINVAL; } - if ((uint64_t) width * cpp > UINT_MAX) + if (min_pitch > UINT_MAX) return -ERANGE; if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) return -ERANGE; - if (r->pitches[i] < width * cpp) { + if (r->pitches[i] < min_pitch) { DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index ded7a379ac35..acb466d25afc 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -171,7 +171,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, } min_size = (height - 1) * mode_cmd->pitches[i] - + width * info->cpp[i] + + drm_format_info_min_pitch(info, i, width) + mode_cmd->offsets[i]; if (objs[i]->size < min_size) { diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 345f11227e9e..bcb389f04618 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -69,8 +69,59 @@ struct drm_format_info { /** @num_planes: Number of color planes (1 to 3) */ u8 num_planes; - /** @cpp: Number of bytes per pixel (per plane) */ - u8 cpp[3]; + union { + /** + * @cpp: + * + * Number of bytes per pixel (per plane), this is aliased with + * @char_per_block. It is deprecated in favour of using the + * triplet @char_per_block, @block_w, @block_h for better + * describing the pixel format. + */ + u8 cpp[3]; + + /** + * @char_per_block: + * + * Number of bytes per block (per plane), where blocks are + * defined as a rectangle of pixels which are stored next to + * each other in a byte aligned memory region. Together with + * @block_w and @block_h this is used to properly describe tiles + * in tiled formats or to describe groups of pixels in packed + * formats for which the memory needed for a single pixel is not + * byte aligned. + * + * @cpp has been kept for historical reasons because there are + * a lot of places in drivers where it's used. In drm core for + * generic code paths the preferred way is to use + * @char_per_block, drm_format_info_block_width() and + * drm_format_info_block_height() which allows handling both + * block and non-block formats in the same way. + * + * For formats that are intended to be used only with non-linear + * modifiers both @cpp and @char_per_block must be 0 in the + * generic format table. Drivers could supply accurate + * information from their drm_mode_config.get_format_info hook + * if they want the core to be validating the pitch. + */ + u8 char_per_block[3]; + }; + + /** + * @block_w: + * + * Block width in pixels, this is intended to be accessed through + * drm_format_info_block_width() + */ + u8 block_w[3]; + + /** + * @block_h: + * + * Block height in pixels, this is intended to be accessed through + * drm_format_info_block_height() + */ + u8 block_h[3]; /** @hsub: Horizontal chroma subsampling factor */ u8 hsub; @@ -106,6 +157,12 @@ int drm_format_horz_chroma_subsampling(uint32_t format); int drm_format_vert_chroma_subsampling(uint32_t format); int drm_format_plane_width(int width, uint32_t format, int plane); int drm_format_plane_height(int height, uint32_t format, int plane); +unsigned int drm_format_info_block_width(const struct drm_format_info *info, + int plane); +unsigned int drm_format_info_block_height(const struct drm_format_info *info, + int plane); +uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, + int plane, unsigned int buffer_width); const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf); #endif /* __DRM_FOURCC_H__ */ -- cgit v1.2.3 From 9aefed1f74989eebb430fd0b0bbc3f87da33d0ec Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Thu, 1 Nov 2018 15:11:32 +0000 Subject: drm: Add macro to export functions only when CONFIG_DRM_DEBUG_SELFTEST is enabled If we want to be able to write drmselftests for non-static core functions that are not intended to be used by drivers we need this functions to be exported. This adds a macro that is tied of CONFIG_DRM_DEBUG_SELFTEST, and uses that to export drm_internal_framebuffer_create, in order for subsequent patches to be able to test it. Reviewed-by: Daniel Vetter Signed-off-by: Alexandru Gheorghe Link: https://patchwork.freedesktop.org/patch/msgid/20181101151051.1509-7-alexandru-cosmin.gheorghe@arm.com --- drivers/gpu/drm/drm_framebuffer.c | 1 + include/drm/drmP.h | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 167c1c4544af..fcaea8f50513 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -323,6 +323,7 @@ drm_internal_framebuffer_create(struct drm_device *dev, return fb; } +EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create); /** * drm_mode_addfb2 - add an FB to the graphics configuration diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 05350424a4d3..514beb2d483a 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -110,4 +110,10 @@ static inline bool drm_can_sleep(void) return true; } +#if defined(CONFIG_DRM_DEBUG_SELFTEST_MODULE) +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) EXPORT_SYMBOL(x) +#else +#define EXPORT_SYMBOL_FOR_TESTS_ONLY(x) +#endif + #endif -- cgit v1.2.3 From 078b7de41249b989a574339078696663e095cf37 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 2 Nov 2018 14:25:42 +0100 Subject: drm/file: Uncompact the feature flags This essentially undoes commit 39868bd7668bd47308b1dfd97c212757caee764f Author: Chris Wilson Date: Tue Oct 29 08:55:58 2013 +0000 drm: Compact booleans within struct drm_file We do lockless access to these flags everywhere, and it's kinda not a great idea to mix lockless and bitfields. Aside from that gcc isn't generating great code for these. If this ever becomes an issue size-wise, I think we need atomic_t here and atomic bitflag ops. Cc: Chris Wilson Cc: David Herrmann Cc: Dave Airlie Acked-by: Chris Wilson Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181102132543.16486-2-daniel.vetter@ffwll.ch --- include/drm/drm_file.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include/drm') diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 26485acc51d7..84ac79219e4c 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -164,14 +164,14 @@ struct drm_file { * See also the :ref:`section on primary nodes and authentication * `. */ - unsigned authenticated :1; + bool authenticated; /** * @stereo_allowed: * * True when the client has asked us to expose stereo 3D mode flags. */ - unsigned stereo_allowed :1; + bool stereo_allowed; /** * @universal_planes: @@ -179,10 +179,10 @@ struct drm_file { * True if client understands CRTC primary planes and cursor planes * in the plane list. Automatically set when @atomic is set. */ - unsigned universal_planes:1; + bool universal_planes; /** @atomic: True if client understands atomic properties. */ - unsigned atomic:1; + bool atomic; /** * @aspect_ratio_allowed: @@ -190,14 +190,14 @@ struct drm_file { * True, if client can handle picture aspect ratios, and has requested * to pass this information along with the mode. */ - unsigned aspect_ratio_allowed:1; + bool aspect_ratio_allowed; /** * @writeback_connectors: * * True if client understands writeback connectors */ - unsigned writeback_connectors:1; + bool writeback_connectors; /** * @is_master: @@ -208,7 +208,7 @@ struct drm_file { * See also the :ref:`section on primary nodes and authentication * `. */ - unsigned is_master:1; + bool is_master; /** * @master: -- cgit v1.2.3 From e7afb623b4fb82089c9a50c733c740522b8220bc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Oct 2018 20:34:52 +0200 Subject: drm: Add drm_any_plane_has_format() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a function to check whether there is at least one plane that supports a specific format and modifier combination. Drivers can use this to reject unsupported formats/modifiers in .fb_create(). v2: Accept anyformat if the driver doesn't do planes (Eric) s/planes_have_format/any_plane_has_format/ (Eric) Check the modifier as well since we already have a function that does both v3: Don't do the check in the core since we may not know the modifier yet, instead export the function and let drivers call it themselves Cc: Eric Anholt Cc: Dhinakaran Pandiyan Signed-off-by: Ville Syrjälä Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20181029183453.28541-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_plane.c | 23 +++++++++++++++++++++++ include/drm/drm_mode_config.h | 6 ++++++ include/drm/drm_plane.h | 2 ++ 3 files changed, 31 insertions(+) (limited to 'include/drm') diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 1fa98bd12003..679455e36829 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -636,6 +636,29 @@ static int __setplane_check(struct drm_plane *plane, return 0; } +/** + * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination + * @dev: DRM device + * @format: pixel format (DRM_FORMAT_*) + * @modifier: data layout modifier + * + * Returns: + * Whether at least one plane supports the specified format and modifier combination. + */ +bool drm_any_plane_has_format(struct drm_device *dev, + u32 format, u64 modifier) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) { + if (drm_plane_check_pixel_format(plane, format, modifier) == 0) + return true; + } + + return false; +} +EXPORT_SYMBOL(drm_any_plane_has_format); + /* * __setplane_internal - setplane handler for internal callers * diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index d643d268693e..5dbeabdbaf91 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -52,6 +52,12 @@ struct drm_mode_config_funcs { * requested metadata, but most of that is left to the driver. See * &struct drm_mode_fb_cmd2 for details. * + * To validate the pixel format and modifier drivers can use + * drm_any_plane_has_format() to make sure at least one plane supports + * the requested values. Note that the driver must first determine the + * actual modifier used if the request doesn't have it specified, + * ie. when (@mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0. + * * If the parameters are deemed valid and the backing storage objects in * the underlying memory manager all exist, then the driver allocates * a new &drm_framebuffer structure, subclassed to contain diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 0a0834bef8bd..3701f56c3362 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -798,5 +798,7 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) +bool drm_any_plane_has_format(struct drm_device *dev, + u32 format, u64 modifier); #endif -- cgit v1.2.3