diff options
Diffstat (limited to 'drivers/gpu/drm/drm_bridge.c')
-rw-r--r-- | drivers/gpu/drm/drm_bridge.c | 96 |
1 files changed, 42 insertions, 54 deletions
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index cee3188adf3d..241a384ebce3 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -27,8 +27,9 @@ #include <linux/mutex.h> #include <drm/drm_atomic_state_helper.h> -#include <drm/drm_debugfs.h> #include <drm/drm_bridge.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_file.h> #include <drm/drm_of.h> @@ -206,6 +207,10 @@ void drm_bridge_add(struct drm_bridge *bridge) { mutex_init(&bridge->hpd_mutex); + if (bridge->ops & DRM_BRIDGE_OP_HDMI) + bridge->ycbcr_420_allowed = !!(bridge->supported_formats & + BIT(HDMI_COLORSPACE_YUV420)); + mutex_lock(&bridge_lock); list_add_tail(&bridge->list, &bridge_list); mutex_unlock(&bridge_lock); @@ -352,13 +357,13 @@ err_reset_bridge: bridge->encoder = NULL; list_del(&bridge->chain_node); -#ifdef CONFIG_OF - DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", - bridge->of_node, encoder->name, ret); -#else - DRM_ERROR("failed to attach bridge to encoder %s: %d\n", - encoder->name, ret); -#endif + if (ret != -EPROBE_DEFER) + DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", + bridge->of_node, encoder->name, ret); + else + dev_err_probe(encoder->dev->dev, -EPROBE_DEFER, + "failed to attach bridge %pOF to encoder %s\n", + bridge->of_node, encoder->name); return ret; } @@ -472,43 +477,6 @@ void drm_bridge_detach(struct drm_bridge *bridge) */ /** - * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the - * encoder chain - * @bridge: bridge control structure - * @mode: desired mode to be set for the bridge - * @adjusted_mode: updated mode that works for this bridge - * - * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the - * encoder chain, starting from the first bridge to the last. - * - * Note: the bridge passed should be the one closest to the encoder - * - * RETURNS: - * true on success, false on failure - */ -bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_encoder *encoder; - - if (!bridge) - return true; - - encoder = bridge->encoder; - list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (!bridge->funcs->mode_fixup) - continue; - - if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode)) - return false; - } - - return true; -} -EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); - -/** * drm_bridge_chain_mode_valid - validate the mode against all bridges in the * encoder chain. * @bridge: bridge control structure @@ -656,6 +624,13 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge, * bridge will be called before the previous one to reverse the @pre_enable * calling direction. * + * Example: + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E + * + * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting + * @post_disable order would be, + * Bridge B, Bridge A, Bridge E, Bridge D, Bridge C. + * * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, @@ -686,11 +661,17 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, */ list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) { - if (next->pre_enable_prev_first) { + if (!next->pre_enable_prev_first) { next = list_prev_entry(next, chain_node); limit = next; break; } + + if (list_is_last(&next->chain_node, + &encoder->bridge_chain)) { + limit = next; + break; + } } /* Call these bridges in reverse order */ @@ -746,6 +727,13 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge, * If a bridge sets @pre_enable_prev_first, then the pre_enable for the * prev bridge will be called before pre_enable of this bridge. * + * Example: + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E + * + * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting + * @pre_enable order would be, + * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B. + * * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, @@ -773,7 +761,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, /* Found first bridge that does NOT * request prev to be enabled first */ - limit = list_prev_entry(next, chain_node); + limit = next; break; } } @@ -1207,26 +1195,26 @@ int drm_bridge_get_modes(struct drm_bridge *bridge, EXPORT_SYMBOL_GPL(drm_bridge_get_modes); /** - * drm_bridge_get_edid - get the EDID data of the connected display + * drm_bridge_edid_read - read the EDID data of the connected display * @bridge: bridge control structure * @connector: the connector to read EDID for * * If the bridge supports output EDID retrieval, as reported by the - * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.get_edid to - * get the EDID and return it. Otherwise return NULL. + * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.edid_read to get + * the EDID and return it. Otherwise return NULL. * * RETURNS: * The retrieved EDID on success, or NULL otherwise. */ -struct edid *drm_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +const struct drm_edid *drm_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { if (!(bridge->ops & DRM_BRIDGE_OP_EDID)) return NULL; - return bridge->funcs->get_edid(bridge, connector); + return bridge->funcs->edid_read(bridge, connector); } -EXPORT_SYMBOL_GPL(drm_bridge_get_edid); +EXPORT_SYMBOL_GPL(drm_bridge_edid_read); /** * drm_bridge_hpd_enable - enable hot plug detection for the bridge |