Re: [PATCH v5 3/4] drm/bridge: Add an ->atomic_check() hook
Hi! Dne četrtek, 19. december 2019 ob 11:11:50 CET je Neil Armstrong napisal(a): > From: Boris Brezillon > > So that bridge drivers have a way to check/reject an atomic operation. > The drm_atomic_bridge_chain_check() (which is just a wrapper around > the ->atomic_check() hook) is called in place of > drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented, > the core falls back on ->mode_fixup(), so the behavior should stay > the same for existing bridge drivers). > > Signed-off-by: Boris Brezillon > Reviewed-by: Neil Armstrong > Reviewed-by: Laurent Pinchart > Signed-off-by: Neil Armstrong > --- Reviewed by: Jernej Skrabec Best regards, Jernej > Changes in v5: > * None > > Changes in v4: > * Add R-bs > > Changes in v3: > * None > > Changes in v2: > * Clarify the fact that ->atomic_check() is replacing ->mode_fixup() > --- > drivers/gpu/drm/drm_atomic_helper.c | 12 +++--- > drivers/gpu/drm/drm_bridge.c| 62 + > include/drm/drm_bridge.h| 29 +- > 3 files changed, 96 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c > b/drivers/gpu/drm/drm_atomic_helper.c index b3e1aedd9d7a..44536b421d65 > 100644 > --- a/drivers/gpu/drm/drm_atomic_helper.c > +++ b/drivers/gpu/drm/drm_atomic_helper.c > @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) > funcs = encoder->helper_private; > > bridge = drm_bridge_chain_get_first_bridge(encoder); > - ret = drm_bridge_chain_mode_fixup(bridge, > - _crtc_state->mode, > - _crtc_state- >adjusted_mode); > - if (!ret) { > - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); > - return -EINVAL; > + ret = drm_atomic_bridge_chain_check(bridge, > + new_crtc_state, > + new_conn_state); > + if (ret) { > + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); > + return ret; > } > > if (funcs && funcs->atomic_check) { > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c > index 6bdc4ab789c9..442804598f60 100644 > --- a/drivers/gpu/drm/drm_bridge.c > +++ b/drivers/gpu/drm/drm_bridge.c > @@ -609,6 +609,68 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge > *bridge, } > EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); > > +static int drm_atomic_bridge_check(struct drm_bridge *bridge, > +struct drm_crtc_state *crtc_state, > +struct drm_connector_state *conn_state) > +{ > + if (bridge->funcs->atomic_check) { > + struct drm_bridge_state *bridge_state; > + int ret; > + > + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, > + bridge); > + if (WARN_ON(!bridge_state)) > + return -EINVAL; > + > + ret = bridge->funcs->atomic_check(bridge, bridge_state, > + crtc_state, conn_state); > + if (ret) > + return ret; > + } else if (bridge->funcs->mode_fixup) { > + if (!bridge->funcs->mode_fixup(bridge, _state->mode, > +_state- >adjusted_mode)) > + return -EINVAL; > + } > + > + return 0; > +} > + > +/** > + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain > + * @bridge: bridge control structure > + * @crtc_state: new CRTC state > + * @conn_state: new connector state > + * > + * Calls _bridge_funcs.atomic_check() (falls back on > + * _bridge_funcs.mode_fixup()) op for all the bridges in the encoder > chain, + * starting from the last bridge to the first. These are called > before calling + * _encoder_helper_funcs.atomic_check() > + * > + * RETURNS: > + * 0 on success, a negative error code on failure > + */ > +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, > + struct drm_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > +{ > + struct drm_encoder *encoder = bridge->encoder; > + struct drm_bridge *iter; > + > + list_for_each_entry_reverse(iter, >bridge_chain, chain_node) { > + int ret; > + > + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); > + if (ret) > + return ret; > + > + if (iter == bridge) > + break; > + } > + > + return 0; > +} > +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); > + > /** > * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper > *
[PATCH v5 3/4] drm/bridge: Add an ->atomic_check() hook
From: Boris Brezillon So that bridge drivers have a way to check/reject an atomic operation. The drm_atomic_bridge_chain_check() (which is just a wrapper around the ->atomic_check() hook) is called in place of drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented, the core falls back on ->mode_fixup(), so the behavior should stay the same for existing bridge drivers). Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong --- Changes in v5: * None Changes in v4: * Add R-bs Changes in v3: * None Changes in v2: * Clarify the fact that ->atomic_check() is replacing ->mode_fixup() --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++--- drivers/gpu/drm/drm_bridge.c| 62 + include/drm/drm_bridge.h| 29 +- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b3e1aedd9d7a..44536b421d65 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_bridge_chain_mode_fixup(bridge, - _crtc_state->mode, - _crtc_state->adjusted_mode); - if (!ret) { - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); - return -EINVAL; + ret = drm_atomic_bridge_chain_check(bridge, + new_crtc_state, + new_conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); + return ret; } if (funcs && funcs->atomic_check) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 6bdc4ab789c9..442804598f60 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -609,6 +609,68 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +static int drm_atomic_bridge_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + if (bridge->funcs->atomic_check) { + struct drm_bridge_state *bridge_state; + int ret; + + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + bridge); + if (WARN_ON(!bridge_state)) + return -EINVAL; + + ret = bridge->funcs->atomic_check(bridge, bridge_state, + crtc_state, conn_state); + if (ret) + return ret; + } else if (bridge->funcs->mode_fixup) { + if (!bridge->funcs->mode_fixup(bridge, _state->mode, + _state->adjusted_mode)) + return -EINVAL; + } + + return 0; +} + +/** + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain + * @bridge: bridge control structure + * @crtc_state: new CRTC state + * @conn_state: new connector state + * + * Calls _bridge_funcs.atomic_check() (falls back on + * _bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, + * starting from the last bridge to the first. These are called before calling + * _encoder_helper_funcs.atomic_check() + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge *iter; + + list_for_each_entry_reverse(iter, >bridge_chain, chain_node) { + int ret; + + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); + if (ret) + return ret; + + if (iter == bridge) + break; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); + /** * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper * @bridge: the bridge this state refers to diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 0331e330635b..269f0d1da339 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -128,7 +128,9 @@ struct drm_bridge_funcs { * this function passes all other callbacks