@@ -55,7 +55,7 @@
* just provide additional hooks to get the desired output at the end of the
* encoder chain.
*
- * Bridges can also be chained up using the &drm_bridge.next pointer.
+ * Bridges can also be chained up using the &drm_bridge.chain_node field.
*
* Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
*/
@@ -114,6 +114,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
struct drm_bridge *previous)
{
+ LIST_HEAD(tmp_list);
int ret;
if (!encoder || !bridge)
@@ -127,6 +128,7 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
bridge->dev = encoder->dev;
bridge->encoder = encoder;
+ list_add_tail(&bridge->chain_node, &tmp_list);
if (bridge->funcs->attach) {
ret = bridge->funcs->attach(bridge);
@@ -137,10 +139,12 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
}
}
- if (previous)
- previous->next = bridge;
- else if (bridge != &encoder->bridge)
- encoder->bridge.next = bridge;
+ if (bridge == &encoder->bridge)
+ list_splice(&tmp_list, &encoder->bridge_chain);
+ else if (!previous)
+ list_splice(&tmp_list, &encoder->bridge.chain_node);
+ else
+ list_splice(&tmp_list, &previous->chain_node);
return 0;
}
@@ -157,6 +161,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)
if (bridge->funcs->detach)
bridge->funcs->detach(bridge);
+ list_del(&bridge->chain_node);
bridge->dev = NULL;
}
@@ -170,7 +175,10 @@ void drm_bridge_detach(struct drm_bridge *bridge)
struct drm_bridge *
drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
{
- return bridge->next;
+ if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain))
+ return NULL;
+
+ return list_next_entry(bridge, chain_node);
}
EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
@@ -204,18 +212,17 @@ bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- bool ret = true;
+ struct drm_encoder *encoder = bridge->encoder;
- if (!bridge)
- return true;
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (!bridge->funcs->mode_fixup)
+ continue;
- if (bridge->funcs->mode_fixup)
- ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode);
+ if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode))
+ return false;
+ }
- ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode,
- adjusted_mode);
-
- return ret;
+ return true;
}
EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
@@ -238,18 +245,20 @@ enum drm_mode_status
drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
- enum drm_mode_status ret = MODE_OK;
+ struct drm_encoder *encoder = bridge->encoder;
- if (!bridge)
- return ret;
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ enum drm_mode_status ret;
+
+ if (!bridge->funcs->mode_valid)
+ continue;
- if (bridge->funcs->mode_valid)
ret = bridge->funcs->mode_valid(bridge, mode);
+ if (ret != MODE_OK)
+ return ret;
+ }
- if (ret != MODE_OK)
- return ret;
-
- return drm_bridge_chain_mode_valid(bridge->next, mode);
+ return MODE_OK;
}
EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
@@ -265,13 +274,16 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
*/
void drm_bridge_chain_disable(struct drm_bridge *bridge)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_bridge *iter;
- drm_bridge_chain_disable(bridge->next);
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+ if (iter->funcs->disable)
+ iter->funcs->disable(iter);
- if (bridge->funcs->disable)
- bridge->funcs->disable(bridge);
+ if (iter == bridge)
+ break;
+ }
}
EXPORT_SYMBOL(drm_bridge_chain_disable);
@@ -288,13 +300,12 @@ EXPORT_SYMBOL(drm_bridge_chain_disable);
*/
void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
- if (bridge->funcs->post_disable)
- bridge->funcs->post_disable(bridge);
-
- drm_bridge_chain_post_disable(bridge->next);
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (bridge->funcs->post_disable)
+ bridge->funcs->post_disable(bridge);
+ }
}
EXPORT_SYMBOL(drm_bridge_chain_post_disable);
@@ -314,13 +325,12 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
- if (bridge->funcs->mode_set)
- bridge->funcs->mode_set(bridge, mode, adjusted_mode);
-
- drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode);
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (bridge->funcs->mode_set)
+ bridge->funcs->mode_set(bridge, mode, adjusted_mode);
+ }
}
EXPORT_SYMBOL(drm_bridge_chain_mode_set);
@@ -337,13 +347,13 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set);
*/
void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_bridge *iter;
- drm_bridge_chain_pre_enable(bridge->next);
-
- if (bridge->funcs->pre_enable)
- bridge->funcs->pre_enable(bridge);
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+ if (iter->funcs->pre_enable)
+ iter->funcs->pre_enable(iter);
+ }
}
EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
@@ -359,13 +369,12 @@ EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
*/
void drm_bridge_chain_enable(struct drm_bridge *bridge)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
- if (bridge->funcs->enable)
- bridge->funcs->enable(bridge);
-
- drm_bridge_chain_enable(bridge->next);
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (bridge->funcs->enable)
+ bridge->funcs->enable(bridge);
+ }
}
EXPORT_SYMBOL(drm_bridge_chain_enable);
@@ -384,15 +393,18 @@ EXPORT_SYMBOL(drm_bridge_chain_enable);
void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_bridge *iter;
- drm_atomic_bridge_chain_disable(bridge->next, state);
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+ if (iter->funcs->atomic_disable)
+ iter->funcs->atomic_disable(iter, state);
+ else if (iter->funcs->disable)
+ iter->funcs->disable(iter);
- if (bridge->funcs->atomic_disable)
- bridge->funcs->atomic_disable(bridge, state);
- else if (bridge->funcs->disable)
- bridge->funcs->disable(bridge);
+ if (iter == bridge)
+ break;
+ }
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
@@ -412,15 +424,14 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
- if (bridge->funcs->atomic_post_disable)
- bridge->funcs->atomic_post_disable(bridge, state);
- else if (bridge->funcs->post_disable)
- bridge->funcs->post_disable(bridge);
-
- drm_atomic_bridge_chain_post_disable(bridge->next, state);
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (bridge->funcs->atomic_post_disable)
+ bridge->funcs->atomic_post_disable(bridge, state);
+ else if (bridge->funcs->post_disable)
+ bridge->funcs->post_disable(bridge);
+ }
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
@@ -440,15 +451,18 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_bridge *iter;
- drm_atomic_bridge_chain_pre_enable(bridge->next, state);
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+ if (iter->funcs->atomic_pre_enable)
+ iter->funcs->atomic_pre_enable(iter, state);
+ else if (iter->funcs->pre_enable)
+ iter->funcs->pre_enable(iter);
- if (bridge->funcs->atomic_pre_enable)
- bridge->funcs->atomic_pre_enable(bridge, state);
- else if (bridge->funcs->pre_enable)
- bridge->funcs->pre_enable(bridge);
+ if (iter == bridge)
+ break;
+ }
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
@@ -467,15 +481,14 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
{
- if (!bridge)
- return;
+ struct drm_encoder *encoder = bridge->encoder;
- if (bridge->funcs->atomic_enable)
- bridge->funcs->atomic_enable(bridge, state);
- else if (bridge->funcs->enable)
- bridge->funcs->enable(bridge);
-
- drm_atomic_bridge_chain_enable(bridge->next, state);
+ list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ if (bridge->funcs->atomic_enable)
+ bridge->funcs->atomic_enable(bridge, state);
+ else if (bridge->funcs->enable)
+ bridge->funcs->enable(bridge);
+ }
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
@@ -143,6 +143,7 @@ int drm_encoder_init(struct drm_device *dev,
goto out_put;
}
+ INIT_LIST_HEAD(&encoder->bridge_chain);
if (!encoder->bridge.funcs)
encoder->bridge.funcs = &dummy_bridge_funcs;
@@ -177,10 +178,9 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
* the indices on the drm_encoder after us in the encoder_list.
*/
- for (bridge = &encoder->bridge; bridge; bridge = next) {
- next = bridge->next;
+ list_for_each_entry_safe(bridge, next, &encoder->bridge_chain,
+ chain_node)
drm_bridge_detach(bridge);
- }
drm_mode_object_unregister(dev, &encoder->base);
kfree(encoder->name);
@@ -383,8 +383,8 @@ struct drm_bridge {
struct drm_device *dev;
/** @encoder: encoder to which this bridge is connected */
struct drm_encoder *encoder;
- /** @next: the next bridge in the encoder chain */
- struct drm_bridge *next;
+ /** @chain_node: used to form a bridge chain */
+ struct list_head chain_node;
#ifdef CONFIG_OF
/** @of_node: device node pointer to the bridge */
struct device_node *of_node;
@@ -173,6 +173,13 @@ struct drm_encoder {
*/
struct drm_crtc *crtc;
+ /**
+ * @bridge_chain: Bridges attached to this encoder. The first entry of
+ * this list is always &drm_encoder.bridge. It may be followed by other
+ * bridge entities.
+ */
+ struct list_head bridge_chain;
+
/**
* @bridge: Bridge representing our encoder. Other bridges might be
* linked to this dummy bridge element to form an encoder chain.
So that each element in the chain can easily access its predecessor. This will be needed to support bus format negotiation between elements of the bridge chain. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> --- Changes in v2: * Adjust things to the "dummy encoder bridge" change (patch 2 in this series) --- drivers/gpu/drm/drm_bridge.c | 177 ++++++++++++++++++---------------- drivers/gpu/drm/drm_encoder.c | 6 +- include/drm/drm_bridge.h | 4 +- include/drm/drm_encoder.h | 7 ++ 4 files changed, 107 insertions(+), 87 deletions(-)