2014-11-05 07:14:14 +08: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 19:09:47 +08:00
|
|
|
#include <drm/drm_crtc.h>
|
2016-08-13 04:48:39 +08:00
|
|
|
#include <drm/drm_modeset_helper_vtables.h>
|
|
|
|
#include <drm/drm_modeset_helper.h>
|
2018-09-05 21:57:05 +08:00
|
|
|
#include <drm/drm_util.h>
|
2014-11-25 19:09:47 +08:00
|
|
|
|
2015-08-26 03:35:58 +08:00
|
|
|
struct drm_atomic_state;
|
2017-07-12 23:51:02 +08:00
|
|
|
struct drm_private_obj;
|
|
|
|
struct drm_private_state;
|
2015-08-26 03:35:58 +08:00
|
|
|
|
2014-11-26 23:57:41 +08:00
|
|
|
int drm_atomic_helper_check_modeset(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
2017-11-02 04:16:19 +08:00
|
|
|
int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state,
|
|
|
|
const struct drm_crtc_state *crtc_state,
|
|
|
|
int min_scale,
|
|
|
|
int max_scale,
|
|
|
|
bool can_position,
|
|
|
|
bool can_update_disabled);
|
2014-11-26 23:57:41 +08:00
|
|
|
int drm_atomic_helper_check_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
2014-11-05 07:14:14 +08:00
|
|
|
int drm_atomic_helper_check(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
drm/atomic-helper: nonblocking commit support
Design ideas:
- split up the actual commit into different phases, and have
completions for each of them. This will be useful for the future
when we want to interleave phases much more aggressively, for e.g.
queue depth > 1. For not it's just a minimal optimization compared
to current common nonblocking implementation patterns from drivers,
which all stall for the entire commit to complete, including vblank
waits and cleanups.
- Extract a separate atomic_commit_hw hook since that's the part most
drivers will need to overwrite, hopefully allowing even more shared
code.
- Enforce EBUSY seamntics by attaching one of the completions to the
flip_done vblank event. Side benefit of forcing atomic drivers using
these helpers to implement event handlign at least semi-correct. I'm
evil that way ;-)
- Ridiculously modular, as usual.
- The main tracking unit for a commit stays struct drm_atomic_state,
and the ownership rules for that are unchanged. Ownership still
gets transferred to the driver (and subsequently to the worker) on
successful commits. What is added is a small, per-crtc, refcounted
structure to track pending commits called struct drm_crtc_commit.
No actual state is attached to that though, it's purely for ordering
and waiting.
- Dependencies are implicitly handled by assuming that any CRTC part
of &drm_atomic_state is a dependency, and that the current commit
must wait for any commits to complete on those CRTC. This way
drivers can easily add more depencies using
drm_atomic_get_crtc_state(), which is very natural since in most
case a dependency exists iff there's some bit of state that needs to
be cross checked.
Removing depencies is not possible, drivers simply need to be
careful to not include every CRTC in a commit if that's not
necessary. Which is a good idea anyway, since that also avoids
ww_mutex lock contention.
- Queue depth > 1 sees some prep work in this patch by adding a stall
paramater to drm_atomic_helper_swap_states(). To be able to push
commits entirely free-standing and in a deeper queue through the
back-end the driver must not access any obj->state pointers. This
means we need to track the old state in drm_atomic_state (much
easier with the consolidated arrays), and pass them all explicitly
to driver backends (this will be serious amounts of churn).
Once that's done stall can be set to false in swap_states.
v2: Dont ask for flip_done signalling when the CRTC is off and stays
off: Drivers don't handle events in that case. Instead complete right
away. This way future commits don't need to have special-case logic,
but can keep blocking for the flip_done completion.
v3: Tons of fixes:
- Stall for preceeding commit for real, not the current one by
accident.
- Add WARN_ON in case drivers don't fire the drm event.
- Don't double-free drm events.
v4: Make legacy cursor not stall.
v5: Extend the helper hook to cover the entire commit tail. Some
drivers need special code for cleanup and vblank waiting, this makes
it a bit more useful. Inspired by the rockchip driver.
v6: Add WARN_ON to catch drivers who forget to send out the
drm event.
v7: Fixup the stalls in swap_state for real!!
v8:
- Fixup trailing whitespace, spotted by Maarten.
- Actually wait for flip_done in cleanup_done, like the comment says
we should do. Thanks a lot for Tomeu for helping with debugging this
on.
v9: Now with awesome kerneldoc!
v10: Split out drm_crtc_commit tracking infrastructure.
v:
- Add missing static (Gustavo).
- Split out the sync functions, only do the actual nonblocking
logic in this patch (Maarten).
Cc: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Tested-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Tomeu Vizoso <tomeu.vizoso@gmail.com>
Cc: Daniel Stone <daniels@collabora.com>
Tested-by: Liviu Dudau <Liviu.Dudau@arm.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Testcase: igt/kms_flip/*
Testcase: igt/kms_cursor*
Testcase: igt/kms*plane*
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465388359-8070-10-git-send-email-daniel.vetter@ffwll.ch
2016-06-08 20:19:02 +08:00
|
|
|
void drm_atomic_helper_commit_tail(struct drm_atomic_state *state);
|
2017-07-20 21:01:16 +08:00
|
|
|
void drm_atomic_helper_commit_tail_rpm(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 23:50:47 +08:00
|
|
|
int drm_atomic_helper_commit(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state,
|
2016-04-26 22:11:34 +08:00
|
|
|
bool nonblock);
|
2017-07-01 02:03:17 +08:00
|
|
|
int drm_atomic_helper_async_check(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
void drm_atomic_helper_async_commit(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 23:50:47 +08:00
|
|
|
|
2016-09-13 03:08:11 +08:00
|
|
|
int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state,
|
|
|
|
bool pre_swap);
|
2016-01-19 18:46:58 +08:00
|
|
|
|
2014-11-12 08:38:59 +08:00
|
|
|
void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
|
|
|
|
2017-06-02 16:32:06 +08:00
|
|
|
void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
|
|
|
|
2015-05-12 21:27:37 +08:00
|
|
|
void
|
|
|
|
drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
|
|
|
|
2015-02-22 19:24:19 +08: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 23:50:47 +08:00
|
|
|
struct drm_atomic_state *old_state);
|
2014-11-05 07:14:14 +08:00
|
|
|
|
|
|
|
int drm_atomic_helper_prepare_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
2016-08-29 17:12:03 +08:00
|
|
|
|
|
|
|
#define DRM_PLANE_COMMIT_ACTIVE_ONLY BIT(0)
|
|
|
|
#define DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET BIT(1)
|
|
|
|
|
2014-11-05 07:14:14 +08:00
|
|
|
void drm_atomic_helper_commit_planes(struct drm_device *dev,
|
2015-09-08 18:02:07 +08:00
|
|
|
struct drm_atomic_state *state,
|
2016-08-29 17:12:03 +08:00
|
|
|
uint32_t flags);
|
2014-11-05 07:14:14 +08:00
|
|
|
void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *old_state);
|
2015-05-19 22:41:01 +08:00
|
|
|
void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state);
|
2016-08-26 15:30:39 +08:00
|
|
|
void
|
|
|
|
drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc_state *old_crtc_state,
|
|
|
|
bool atomic);
|
2014-11-05 07:14:14 +08:00
|
|
|
|
2017-07-11 22:33:13 +08:00
|
|
|
int __must_check drm_atomic_helper_swap_state(struct drm_atomic_state *state,
|
|
|
|
bool stall);
|
2014-11-05 07:14:14 +08:00
|
|
|
|
2016-06-08 23:15:36 +08:00
|
|
|
/* nonblocking commit helpers */
|
|
|
|
int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
|
|
|
|
bool nonblock);
|
|
|
|
void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state);
|
2018-07-03 15:50:19 +08:00
|
|
|
void drm_atomic_helper_fake_vblank(struct drm_atomic_state *state);
|
2016-06-08 23:15:36 +08:00
|
|
|
void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state);
|
|
|
|
void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state);
|
|
|
|
|
2014-07-27 19:46:52 +08: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,
|
2017-03-23 05:50:41 +08:00
|
|
|
uint32_t src_w, uint32_t src_h,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2017-03-23 05:50:43 +08:00
|
|
|
int drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2015-08-26 03:35:58 +08:00
|
|
|
int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *plane_state);
|
2017-03-23 05:50:57 +08:00
|
|
|
int drm_atomic_helper_set_config(struct drm_mode_set *set,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2015-08-26 03:35:58 +08:00
|
|
|
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
|
|
|
|
struct drm_atomic_state *state);
|
2014-07-27 19:46:52 +08:00
|
|
|
|
2015-12-03 00:50:04 +08:00
|
|
|
int drm_atomic_helper_disable_all(struct drm_device *dev,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2017-03-22 00:41:49 +08:00
|
|
|
void drm_atomic_helper_shutdown(struct drm_device *dev);
|
2015-12-03 00:50:04 +08:00
|
|
|
struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev);
|
2017-01-16 17:37:38 +08:00
|
|
|
int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2015-12-03 00:50:04 +08:00
|
|
|
int drm_atomic_helper_resume(struct drm_device *dev,
|
|
|
|
struct drm_atomic_state *state);
|
|
|
|
|
2014-07-28 00:42:37 +08:00
|
|
|
int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
|
|
|
struct drm_pending_vblank_event *event,
|
2017-03-23 05:50:50 +08:00
|
|
|
uint32_t flags,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2017-01-07 04:39:40 +08:00
|
|
|
int drm_atomic_helper_page_flip_target(
|
|
|
|
struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
|
|
|
struct drm_pending_vblank_event *event,
|
|
|
|
uint32_t flags,
|
2017-03-23 05:50:50 +08:00
|
|
|
uint32_t target,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2014-07-28 00:42:37 +08:00
|
|
|
|
2014-11-03 22:56:43 +08:00
|
|
|
/* default implementations for state handling */
|
|
|
|
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
|
2015-01-28 21:54:32 +08:00
|
|
|
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
|
|
|
|
struct drm_crtc_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
struct drm_crtc_state *
|
|
|
|
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
|
2016-05-09 22:34:09 +08:00
|
|
|
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
|
|
|
|
struct drm_crtc_state *state);
|
|
|
|
|
2018-08-05 00:15:21 +08:00
|
|
|
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
void drm_atomic_helper_plane_reset(struct drm_plane *plane);
|
2015-01-28 21:54:32 +08:00
|
|
|
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
struct drm_plane_state *
|
|
|
|
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
|
2016-05-09 22:34:10 +08:00
|
|
|
void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
|
|
|
|
struct drm_plane_state *state);
|
|
|
|
|
2016-01-04 19:53:16 +08:00
|
|
|
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *conn_state);
|
2014-11-03 22:56:43 +08:00
|
|
|
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
|
2015-01-28 21:54:32 +08:00
|
|
|
void
|
|
|
|
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
struct drm_connector_state *
|
|
|
|
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
|
2015-09-08 21:00:45 +08:00
|
|
|
struct drm_atomic_state *
|
|
|
|
drm_atomic_helper_duplicate_state(struct drm_device *dev,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2015-01-28 21:54:32 +08:00
|
|
|
void
|
2016-05-09 22:34:11 +08:00
|
|
|
__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
|
|
|
|
struct drm_connector_state *state);
|
2016-06-07 18:49:30 +08:00
|
|
|
int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
|
|
|
|
u16 *red, u16 *green, u16 *blue,
|
2017-04-03 16:33:01 +08:00
|
|
|
uint32_t size,
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2017-07-12 23:51:02 +08:00
|
|
|
void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
|
|
|
|
struct drm_private_state *state);
|
2014-11-03 22:56:43 +08:00
|
|
|
|
2014-11-26 09:29:46 +08: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
|
2017-01-25 14:26:43 +08:00
|
|
|
* planes which *will* be attached (more useful in code called from
|
|
|
|
* &drm_mode_config_funcs.atomic_check) see
|
2016-06-10 23:03:25 +08:00
|
|
|
* drm_atomic_crtc_state_for_each_plane().
|
2014-11-26 09:29:46 +08:00
|
|
|
*/
|
|
|
|
#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
|
2017-01-25 14:26:43 +08:00
|
|
|
* attached if the specified state is applied. Useful during for example
|
|
|
|
* in code called from &drm_mode_config_funcs.atomic_check operations, to
|
|
|
|
* validate the incoming state.
|
2014-11-26 09:29:46 +08:00
|
|
|
*/
|
|
|
|
#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 19:46:52 +08:00
|
|
|
|
2016-06-02 22:21:44 +08:00
|
|
|
/**
|
|
|
|
* drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state
|
|
|
|
* @plane: the loop cursor
|
|
|
|
* @plane_state: loop cursor for the plane's state, must be const
|
|
|
|
* @crtc_state: the incoming crtc-state
|
|
|
|
*
|
|
|
|
* Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
|
2017-01-25 14:26:43 +08:00
|
|
|
* attached if the specified state is applied. Useful during for example
|
|
|
|
* in code called from &drm_mode_config_funcs.atomic_check operations, to
|
|
|
|
* validate the incoming state.
|
2016-06-02 22:21:44 +08:00
|
|
|
*
|
|
|
|
* Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a
|
|
|
|
* const plane_state. This is useful when a driver just wants to peek at other
|
|
|
|
* active planes on this crtc, but does not need to change it.
|
|
|
|
*/
|
|
|
|
#define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \
|
|
|
|
drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \
|
|
|
|
for_each_if ((plane_state = \
|
|
|
|
__drm_atomic_get_current_plane_state((crtc_state)->state, \
|
|
|
|
plane)))
|
|
|
|
|
2017-02-16 22:47:07 +08: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 19:05:50 +08:00
|
|
|
* drm_atomic_plane_disabling - check whether a plane is being disabled
|
2017-02-16 22:47:07 +08:00
|
|
|
* @old_plane_state: old atomic plane state
|
|
|
|
* @new_plane_state: new atomic plane state
|
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 19:05:50 +08:00
|
|
|
*
|
|
|
|
* 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
|
2017-02-16 22:47:07 +08:00
|
|
|
drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state,
|
|
|
|
struct drm_plane_state *new_plane_state)
|
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 19:05:50 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-02-16 22:47:07 +08:00
|
|
|
WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) ||
|
|
|
|
(new_plane_state->crtc != NULL && new_plane_state->fb == NULL));
|
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 19:05:50 +08:00
|
|
|
|
2017-02-16 22:47:07 +08:00
|
|
|
return old_plane_state->crtc && !new_plane_state->crtc;
|
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 19:05:50 +08:00
|
|
|
}
|
|
|
|
|
2014-11-05 07:14:14 +08:00
|
|
|
#endif /* DRM_ATOMIC_HELPER_H_ */
|