2014-11-05 02:14:14 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Red Hat
|
|
|
|
* Copyright (C) 2014 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 <robdclark@gmail.com>
|
|
|
|
* Daniel Vetter <daniel.vetter@ffwll.ch>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef DRM_ATOMIC_HELPER_H_
|
|
|
|
#define DRM_ATOMIC_HELPER_H_
|
|
|
|
|
2014-11-25 14:09:47 +03:00
|
|
|
#include <drm/drm_crtc.h>
|
|
|
|
|
2015-08-25 22:35:58 +03:00
|
|
|
struct drm_atomic_state;
|
|
|
|
|
2014-11-26 18:57:41 +03:00
|
|
|
int drm_atomic_helper_check_modeset(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
int drm_atomic_helper_check_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
2014-11-05 02:14:14 +03:00
|
|
|
int drm_atomic_helper_check(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
drm: Atomic crtc/connector updates using crtc/plane helper interfaces
So this is finally the integration of the crtc and plane helper
interfaces into the atomic helper functions.
In the check function we now have a few steps:
- First we update the output routing and figure out which crtcs need a
full mode set. Suitable encoders are selected using ->best_encoder,
with the same semantics as the crtc helpers of implicitly disabling
all connectors currently using the encoder.
- Then we pull all other connectors into the state update which feed
from a crtc which changes. This must be done do catch mode changes
and similar updates - atomic updates are differences on top of the
current state.
- Then we call all the various ->mode_fixup to compute the adjusted
mode. Note that here we have a slight semantic difference compared
to the crtc helpers: We have not yet updated the encoder->crtc link
when calling the encoder's ->mode_fixup function. But that's a
requirement when converting to atomic since we want to prepare the
entire state completely contained with the over drm_atomic_state
structure. So this must be carefully checked when converting drivers
over to atomic helpers.
- Finally we do call the atomic_check functions on planes and crtcs.
The commit function is also quite a beast:
- The only step that can fail is done first, namely pinning the
framebuffers. After that we cross the point of no return, an async
commit would push all that into the worker thread.
- The disabling of encoders and connectors is a bit tricky, since
depending upon the final state we need to select different crtc
helper functions.
- Software tracking is a bit clarified compared to the crtc helpers:
We commit the software state before starting to touch the hardware,
like crtc helpers. But since we just swap them we still have the old
state (i.e. the current hw state) around, which is really handy to
write simple disable functions. So no more
drm_crtc_helper_disable_all_unused_functions kind of fun because
we're leaving unused crtcs/encoders behind. Everything gets shut
down in-order now, which is one of the key differences of the i915
helpers compared to crtc helpers and a really nice additional
guarantee.
- Like with the plane helpers the atomic commit function waits for one
vblank to pass before calling the framebuffer cleanup function.
Compared to Rob's helper approach there's a bunch of upsides:
- All the interfaces which can fail are called in the ->check hook
(i.e. ->best_match and the various ->mode_fixup hooks). This means
that drivers can just reuse those functions and don't need to move
everything into ->atomic_check callbacks. If drivers have no need
for additional constraint checking beyong their existing crtc
helper callbacks they don't need to do anything.
- The actual commit operation is properly stage: First we prepare
framebuffers, which can potentially still fail (due to memory
exhausting). This is important for the async case, where this must
be done synchronously to correctly return errors.
- The output configuration changes (done with crtc helper functions)
and the plane update (using atomic plane helpers) are correctly
interleaved: First we shut down any crtcs that need changing, then
we update planes and finally we enable everything again. Hardware
without GO bits must be more careful with ordering, which this
sequence enables.
- Also for hardware with shared output resources (like display PLLs)
we first must shut down the old configuration before we can enable
the new one. Otherwise we can hit an impossible intermediate state
where there's not enough PLLs (which is the point behind atomic
updates).
v2:
- Ensure that users of ->check update crtc_state->enable correctly.
- Update the legacy state in crtc/plane structures. Eventually we want
to remove that, but for now the drm core still expects this (especially
the plane->fb pointer).
v3: A few changes for better async handling:
- Reorder the software side state commit so that it happens all before
we touch the hardware. This way async support becomes very easy
since we can punt all the actual hw touching to a worker thread. And
as long as we synchronize with that thread (flushing or cancelling,
depending upon what the driver can handle) before we commit the next
software state there's no need for any locking in the worker thread
at all. Which greatly simplifies things.
And as long as we synchronize with all relevant threads we can have
a lot of them (e.g. per-crtc for per-crtc updates) running in
parallel.
- Expose pre/post plane commit steps separately. We need to expose the
actual hw commit step anyway for drivers to be able to implement
asynchronous commit workers. But if we expose pre/post and plane
commit steps individually we allow drivers to selectively use atomic
helpers.
- I've forgotten to call encoder/bridge ->mode_set functions, fix
this.
v4: Add debug output and fix a mixup between current and new state
that resulted in crtcs not getting updated correctly. And in an
Oops ...
v5:
- Be kind to driver writers in the vblank wait functions.. if thing
aren't working yet, and vblank irq will never come, then let's not
block forever.. especially under console-lock.
- Correctly clear connector_state->best_encoder when disabling.
Spotted while trying to understand a report from Rob Clark.
- Only steal encoder if it actually changed, otherwise hilarity ensues
if we steal from the current connector and so set the ->crtc pointer
unexpectedly to NULL. Reported by Rob Clark.
- Bail out in disable_outputs if an output currently doesn't have a
best_encoder - this means it's already disabled.
v6: Fixupe kerneldoc as reported by Paulo. And also fix up kerneldoc
in drm_crtc.h.
v7: Take ownership of the atomic state and clean it up with
drm_atomic_state_free().
v8 Various improvements all over:
- Polish code comments and kerneldoc.
- Improve debug output to make sure all failure cases are logged.
- Treat enabled crtc with no connectors as invalid input from userspace.
- Don't ignore the return value from mode_fixup().
v9:
- Improve debug output for crtc_state->mode_changed.
v10:
- Fixup the vblank waiting code to properly balance the vblank_get/put
calls.
- Better comments when checking/computing crtc->mode_changed
v11: Fixup the encoder stealing logic: We can't look at encoder->crtc
since that's not in the atomic state structures and might be updated
asynchronously in and async commit. Instead we need to inspect all the
connector states and check whether the encoder is currently in used
and if so, on which crtc.
v12: Review from Sean:
- A few spelling fixes.
- Flatten control flow indent by converting if blocks to early
continue/return in 2 places.
- Capture connectors_for_crtc return value in int num_connectors
instead of bool has_connectors and do an explicit int->bool
conversion with !!. I think the helper is more useful for drivers if
it returns the number of connectors (e.g. to detect cloning
configurations), so decided to keep that return value.
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-09-16 19:50:47 +04:00
|
|
|
int drm_atomic_helper_commit(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state,
|
|
|
|
bool async);
|
|
|
|
|
2014-11-12 03:38:59 +03:00
|
|
|
void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
|
|
|
|
2015-05-12 16:27:37 +03:00
|
|
|
void
|
|
|
|
drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
|
|
|
|
2015-02-22 14:24:19 +03:00
|
|
|
void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
|
drm: Atomic crtc/connector updates using crtc/plane helper interfaces
So this is finally the integration of the crtc and plane helper
interfaces into the atomic helper functions.
In the check function we now have a few steps:
- First we update the output routing and figure out which crtcs need a
full mode set. Suitable encoders are selected using ->best_encoder,
with the same semantics as the crtc helpers of implicitly disabling
all connectors currently using the encoder.
- Then we pull all other connectors into the state update which feed
from a crtc which changes. This must be done do catch mode changes
and similar updates - atomic updates are differences on top of the
current state.
- Then we call all the various ->mode_fixup to compute the adjusted
mode. Note that here we have a slight semantic difference compared
to the crtc helpers: We have not yet updated the encoder->crtc link
when calling the encoder's ->mode_fixup function. But that's a
requirement when converting to atomic since we want to prepare the
entire state completely contained with the over drm_atomic_state
structure. So this must be carefully checked when converting drivers
over to atomic helpers.
- Finally we do call the atomic_check functions on planes and crtcs.
The commit function is also quite a beast:
- The only step that can fail is done first, namely pinning the
framebuffers. After that we cross the point of no return, an async
commit would push all that into the worker thread.
- The disabling of encoders and connectors is a bit tricky, since
depending upon the final state we need to select different crtc
helper functions.
- Software tracking is a bit clarified compared to the crtc helpers:
We commit the software state before starting to touch the hardware,
like crtc helpers. But since we just swap them we still have the old
state (i.e. the current hw state) around, which is really handy to
write simple disable functions. So no more
drm_crtc_helper_disable_all_unused_functions kind of fun because
we're leaving unused crtcs/encoders behind. Everything gets shut
down in-order now, which is one of the key differences of the i915
helpers compared to crtc helpers and a really nice additional
guarantee.
- Like with the plane helpers the atomic commit function waits for one
vblank to pass before calling the framebuffer cleanup function.
Compared to Rob's helper approach there's a bunch of upsides:
- All the interfaces which can fail are called in the ->check hook
(i.e. ->best_match and the various ->mode_fixup hooks). This means
that drivers can just reuse those functions and don't need to move
everything into ->atomic_check callbacks. If drivers have no need
for additional constraint checking beyong their existing crtc
helper callbacks they don't need to do anything.
- The actual commit operation is properly stage: First we prepare
framebuffers, which can potentially still fail (due to memory
exhausting). This is important for the async case, where this must
be done synchronously to correctly return errors.
- The output configuration changes (done with crtc helper functions)
and the plane update (using atomic plane helpers) are correctly
interleaved: First we shut down any crtcs that need changing, then
we update planes and finally we enable everything again. Hardware
without GO bits must be more careful with ordering, which this
sequence enables.
- Also for hardware with shared output resources (like display PLLs)
we first must shut down the old configuration before we can enable
the new one. Otherwise we can hit an impossible intermediate state
where there's not enough PLLs (which is the point behind atomic
updates).
v2:
- Ensure that users of ->check update crtc_state->enable correctly.
- Update the legacy state in crtc/plane structures. Eventually we want
to remove that, but for now the drm core still expects this (especially
the plane->fb pointer).
v3: A few changes for better async handling:
- Reorder the software side state commit so that it happens all before
we touch the hardware. This way async support becomes very easy
since we can punt all the actual hw touching to a worker thread. And
as long as we synchronize with that thread (flushing or cancelling,
depending upon what the driver can handle) before we commit the next
software state there's no need for any locking in the worker thread
at all. Which greatly simplifies things.
And as long as we synchronize with all relevant threads we can have
a lot of them (e.g. per-crtc for per-crtc updates) running in
parallel.
- Expose pre/post plane commit steps separately. We need to expose the
actual hw commit step anyway for drivers to be able to implement
asynchronous commit workers. But if we expose pre/post and plane
commit steps individually we allow drivers to selectively use atomic
helpers.
- I've forgotten to call encoder/bridge ->mode_set functions, fix
this.
v4: Add debug output and fix a mixup between current and new state
that resulted in crtcs not getting updated correctly. And in an
Oops ...
v5:
- Be kind to driver writers in the vblank wait functions.. if thing
aren't working yet, and vblank irq will never come, then let's not
block forever.. especially under console-lock.
- Correctly clear connector_state->best_encoder when disabling.
Spotted while trying to understand a report from Rob Clark.
- Only steal encoder if it actually changed, otherwise hilarity ensues
if we steal from the current connector and so set the ->crtc pointer
unexpectedly to NULL. Reported by Rob Clark.
- Bail out in disable_outputs if an output currently doesn't have a
best_encoder - this means it's already disabled.
v6: Fixupe kerneldoc as reported by Paulo. And also fix up kerneldoc
in drm_crtc.h.
v7: Take ownership of the atomic state and clean it up with
drm_atomic_state_free().
v8 Various improvements all over:
- Polish code comments and kerneldoc.
- Improve debug output to make sure all failure cases are logged.
- Treat enabled crtc with no connectors as invalid input from userspace.
- Don't ignore the return value from mode_fixup().
v9:
- Improve debug output for crtc_state->mode_changed.
v10:
- Fixup the vblank waiting code to properly balance the vblank_get/put
calls.
- Better comments when checking/computing crtc->mode_changed
v11: Fixup the encoder stealing logic: We can't look at encoder->crtc
since that's not in the atomic state structures and might be updated
asynchronously in and async commit. Instead we need to inspect all the
connector states and check whether the encoder is currently in used
and if so, on which crtc.
v12: Review from Sean:
- A few spelling fixes.
- Flatten control flow indent by converting if blocks to early
continue/return in 2 places.
- Capture connectors_for_crtc return value in int num_connectors
instead of bool has_connectors and do an explicit int->bool
conversion with !!. I think the helper is more useful for drivers if
it returns the number of connectors (e.g. to detect cloning
configurations), so decided to keep that return value.
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-09-16 19:50:47 +04:00
|
|
|
struct drm_atomic_state *old_state);
|
2014-11-05 02:14:14 +03:00
|
|
|
|
|
|
|
int drm_atomic_helper_prepare_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
void drm_atomic_helper_commit_planes(struct drm_device *dev,
|
2015-09-08 13:02:07 +03:00
|
|
|
struct drm_atomic_state *state,
|
|
|
|
bool active_only);
|
2014-11-05 02:14:14 +03:00
|
|
|
void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
2015-05-19 17:41:01 +03:00
|
|
|
void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
|
2015-11-27 17:14:01 +03:00
|
|
|
void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc,
|
|
|
|
bool atomic);
|
2014-11-05 02:14:14 +03:00
|
|
|
|
|
|
|
void drm_atomic_helper_swap_state(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
|
2014-07-27 15:46:52 +04:00
|
|
|
/* implementations for legacy interfaces */
|
|
|
|
int drm_atomic_helper_update_plane(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);
|
|
|
|
int drm_atomic_helper_disable_plane(struct drm_plane *plane);
|
2015-08-25 22:35:58 +03:00
|
|
|
int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *plane_state);
|
2014-07-27 15:46:52 +04:00
|
|
|
int drm_atomic_helper_set_config(struct drm_mode_set *set);
|
2015-08-25 22:35:58 +03:00
|
|
|
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
|
|
|
|
struct drm_atomic_state *state);
|
2014-07-27 15:46:52 +04:00
|
|
|
|
2015-12-02 19:50:04 +03:00
|
|
|
int drm_atomic_helper_disable_all(struct drm_device *dev,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
|
|
|
struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev);
|
|
|
|
int drm_atomic_helper_resume(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
|
2014-07-27 15:46:52 +04:00
|
|
|
int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc,
|
|
|
|
struct drm_property *property,
|
|
|
|
uint64_t val);
|
|
|
|
int drm_atomic_helper_plane_set_property(struct drm_plane *plane,
|
|
|
|
struct drm_property *property,
|
|
|
|
uint64_t val);
|
|
|
|
int drm_atomic_helper_connector_set_property(struct drm_connector *connector,
|
|
|
|
struct drm_property *property,
|
|
|
|
uint64_t val);
|
2014-07-27 20:42:37 +04:00
|
|
|
int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
|
|
|
struct drm_pending_vblank_event *event,
|
|
|
|
uint32_t flags);
|
2015-07-21 12:34:55 +03:00
|
|
|
int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
|
|
|
|
int mode);
|
2014-07-27 20:42:37 +04:00
|
|
|
|
2014-11-03 17:56:43 +03:00
|
|
|
/* default implementations for state handling */
|
|
|
|
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
|
2015-01-28 16:54:32 +03:00
|
|
|
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
|
|
|
|
struct drm_crtc_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
struct drm_crtc_state *
|
|
|
|
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
|
2015-01-28 16:54:32 +03:00
|
|
|
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
|
|
|
|
struct drm_crtc_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
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);
|
2015-01-28 16:54:32 +03:00
|
|
|
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
struct drm_plane_state *
|
|
|
|
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
|
2015-01-28 16:54:32 +03:00
|
|
|
void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
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);
|
2015-01-28 16:54:32 +03:00
|
|
|
void
|
|
|
|
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
struct drm_connector_state *
|
|
|
|
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
|
2015-09-08 16:00:45 +03:00
|
|
|
struct drm_atomic_state *
|
|
|
|
drm_atomic_helper_duplicate_state(struct drm_device *dev,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2015-01-28 16:54:32 +03:00
|
|
|
void
|
|
|
|
__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state);
|
2014-11-03 17:56:43 +03:00
|
|
|
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state);
|
|
|
|
|
2014-11-26 04:29:46 +03:00
|
|
|
/**
|
|
|
|
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
|
|
|
|
* @plane: the loop cursor
|
|
|
|
* @crtc: the crtc whose planes are iterated
|
|
|
|
*
|
|
|
|
* This iterates over the current state, useful (for example) when applying
|
|
|
|
* atomic state after it has been checked and swapped. To iterate over the
|
|
|
|
* planes which *will* be attached (for ->atomic_check()) see
|
|
|
|
* drm_crtc_for_each_pending_plane()
|
|
|
|
*/
|
|
|
|
#define drm_atomic_crtc_for_each_plane(plane, crtc) \
|
|
|
|
drm_for_each_plane_mask(plane, (crtc)->dev, (crtc)->state->plane_mask)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state
|
|
|
|
* @plane: the loop cursor
|
|
|
|
* @crtc_state: the incoming crtc-state
|
|
|
|
*
|
|
|
|
* Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
|
|
|
|
* attached if the specified state is applied. Useful during (for example)
|
|
|
|
* ->atomic_check() operations, to validate the incoming state
|
|
|
|
*/
|
|
|
|
#define drm_atomic_crtc_state_for_each_plane(plane, crtc_state) \
|
|
|
|
drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask)
|
2014-07-27 15:46:52 +04:00
|
|
|
|
drm/plane: Add optional ->atomic_disable() callback
In order to prevent drivers from having to perform the same checks over
and over again, add an optional ->atomic_disable callback which the core
calls under the right circumstances.
v2: pass old state and detect edges to avoid calling ->atomic_disable on
already disabled planes, remove redundant comment (Daniel Vetter)
v3: rename helper to drm_atomic_plane_disabling() to clarify that it is
checking for transitions, move helper to drm_atomic_helper.h, clarify
check for !old_state and its relation to transitional helpers
Here's an extract from some discussion rationalizing the behaviour (for
a full version, see the reference below):
> > Hm, thinking about this some more this will result in a slight difference
> > in behaviour, at least when drivers just use the helper ->reset functions
> > but don't disable everything:
> > - With transitional helpers we assume we know nothing and call
> > ->atomic_disable.
> > - With atomic old_state->crtc == NULL in the same situation right after
> > boot-up, but we asssume the plane is really off and _dont_ call
> > ->atomic_disable.
> >
> > Should we instead check for (old_state && old_state->crtc) and state that
> > drivers need to make sure they don't have stuff hanging around?
>
> I don't think we can check for old_state because otherwise this will
> always return false, whereas we really want it to force-disable planes
> that could be on (lacking any more accurate information). For
> transitional helpers anyway.
>
> For the atomic helpers, old_state will never be NULL, but I'd assume
> that the driver would reconstruct the current state in ->reset().
By the way, the reason for why old_state can be NULL with transitional
helpers is the ordering of the steps in the atomic transition. Currently
the Tegra patches do this (based on your blog post and the Exynos proto-
type):
1) atomic conversion, phase 1:
- implement ->atomic_{check,update,disable}()
- use drm_plane_helper_{update,disable}()
2) atomic conversion, phase 2:
- call drm_mode_config_reset() from ->load()
- implement ->reset()
That's only a partial list of what's done in these steps, but that's the
only relevant pieces for why old_state is NULL.
What happens is that without ->reset() implemented there won't be any
initial state, hence plane->state (the old_state here) will be NULL the
first time atomic state is applied.
We could of course reorder the sequence such that drivers are required
to hook up ->reset() before they can (or at the same as they) hook up
the transitional helpers. We could add an appropriate WARN_ON to this
helper to make that more obvious.
However, that will not solve the problem because it only gets rid of the
special case. We still don't know whether old_state->crtc == NULL is the
current state or just the initial default.
So no matter which way we do this, I don't see a way to get away without
requiring specific semantics from drivers. They would be that:
- drivers recreate the correct state in ->reset() so that
old_state->crtc != NULL if the plane is really enabled
or
- drivers have to ensure that the real state in fact mirrors the
initial default as encoded in the state (plane disabled)
References: http://lists.freedesktop.org/archives/dri-devel/2015-January/075578.html
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Signed-off-by: Thierry Reding <treding@nvidia.com>
2014-11-20 14:05:50 +03:00
|
|
|
/*
|
|
|
|
* drm_atomic_plane_disabling - check whether a plane is being disabled
|
|
|
|
* @plane: plane object
|
|
|
|
* @old_state: previous atomic state
|
|
|
|
*
|
|
|
|
* Checks the atomic state of a plane to determine whether it's being disabled
|
|
|
|
* or not. This also WARNs if it detects an invalid state (both CRTC and FB
|
|
|
|
* need to either both be NULL or both be non-NULL).
|
|
|
|
*
|
|
|
|
* RETURNS:
|
|
|
|
* True if the plane is being disabled, false otherwise.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
drm_atomic_plane_disabling(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *old_state)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* When disabling a plane, CRTC and FB should always be NULL together.
|
|
|
|
* Anything else should be considered a bug in the atomic core, so we
|
|
|
|
* gently warn about it.
|
|
|
|
*/
|
|
|
|
WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) ||
|
|
|
|
(plane->state->crtc != NULL && plane->state->fb == NULL));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When using the transitional helpers, old_state may be NULL. If so,
|
|
|
|
* we know nothing about the current state and have to assume that it
|
|
|
|
* might be enabled.
|
|
|
|
*
|
|
|
|
* When using the atomic helpers, old_state won't be NULL. Therefore
|
|
|
|
* this check assumes that either the driver will have reconstructed
|
|
|
|
* the correct state in ->reset() or that the driver will have taken
|
|
|
|
* appropriate measures to disable all planes.
|
|
|
|
*/
|
|
|
|
return (!old_state || old_state->crtc) && !plane->state->crtc;
|
|
|
|
}
|
|
|
|
|
2014-11-05 02:14:14 +03:00
|
|
|
#endif /* DRM_ATOMIC_HELPER_H_ */
|