]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/gpu/drm/drm_bridge.c
Revert "drm/bridge: Add the necessary bits to support bus format negotiation"
[linux.git] / drivers / gpu / drm / drm_bridge.c
index b6517b4fa3d1b384d7ec2c3205961dc91c7721b0..8e4b799150b0e29d8806dc7aaab7acd5efd6a5a9 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 
+#include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_encoder.h>
 
@@ -89,6 +90,74 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
+static struct drm_bridge_state *
+drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge)
+{
+       struct drm_bridge_state *new;
+
+       if (WARN_ON(!bridge->base.state))
+               return NULL;
+
+       new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (new)
+               __drm_atomic_helper_bridge_duplicate_state(bridge, new);
+
+       return new;
+}
+
+static struct drm_private_state *
+drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
+{
+       struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+       struct drm_bridge_state *state;
+
+       if (bridge->funcs->atomic_duplicate_state)
+               state = bridge->funcs->atomic_duplicate_state(bridge);
+       else
+               state = drm_atomic_default_bridge_duplicate_state(bridge);
+
+       return state ? &state->base : NULL;
+}
+
+static void
+drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge,
+                                       struct drm_bridge_state *state)
+{
+       /* Just a simple kfree() for now */
+       kfree(state);
+}
+
+static void
+drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
+                                    struct drm_private_state *s)
+{
+       struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
+       struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+
+       if (bridge->funcs->atomic_destroy_state)
+               bridge->funcs->atomic_destroy_state(bridge, state);
+       else
+               drm_atomic_default_bridge_destroy_state(bridge, state);
+}
+
+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
+       .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
+       .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+};
+
+static struct drm_bridge_state *
+drm_atomic_default_bridge_reset(struct drm_bridge *bridge)
+{
+       struct drm_bridge_state *bridge_state;
+
+       bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL);
+       if (!bridge_state)
+               return ERR_PTR(-ENOMEM);
+
+       __drm_atomic_helper_bridge_reset(bridge, bridge_state);
+       return bridge_state;
+}
+
 /**
  * drm_bridge_attach - attach the bridge to an encoder's chain
  *
@@ -114,6 +183,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
                      struct drm_bridge *previous)
 {
+       struct drm_bridge_state *state;
        int ret;
 
        if (!encoder || !bridge)
@@ -135,15 +205,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
 
        if (bridge->funcs->attach) {
                ret = bridge->funcs->attach(bridge);
-               if (ret < 0) {
-                       list_del(&bridge->chain_node);
-                       bridge->dev = NULL;
-                       bridge->encoder = NULL;
-                       return ret;
-               }
+               if (ret < 0)
+                       goto err_reset_bridge;
        }
 
+       if (bridge->funcs->atomic_reset)
+               state = bridge->funcs->atomic_reset(bridge);
+       else
+               state = drm_atomic_default_bridge_reset(bridge);
+
+       if (IS_ERR(state)) {
+               ret = PTR_ERR(state);
+               goto err_detach_bridge;
+       }
+
+       drm_atomic_private_obj_init(bridge->dev, &bridge->base,
+                                   &state->base,
+                                   &drm_bridge_priv_state_funcs);
+
        return 0;
+
+err_detach_bridge:
+       if (bridge->funcs->detach)
+               bridge->funcs->detach(bridge);
+
+err_reset_bridge:
+       bridge->dev = NULL;
+       bridge->encoder = NULL;
+       list_del(&bridge->chain_node);
+       return ret;
 }
 EXPORT_SYMBOL(drm_bridge_attach);
 
@@ -155,6 +245,8 @@ void drm_bridge_detach(struct drm_bridge *bridge)
        if (WARN_ON(!bridge->dev))
                return;
 
+       drm_atomic_private_obj_fini(&bridge->base);
+
        if (bridge->funcs->detach)
                bridge->funcs->detach(bridge);
 
@@ -389,7 +481,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable);
 /**
  * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
  * @bridge: bridge control structure
- * @state: atomic state being committed
+ * @old_state: old atomic state
  *
  * Calls &drm_bridge_funcs.atomic_disable (falls back on
  * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
@@ -399,7 +491,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable);
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
-                                    struct drm_atomic_state *state)
+                                    struct drm_atomic_state *old_state)
 {
        struct drm_encoder *encoder;
        struct drm_bridge *iter;
@@ -409,10 +501,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        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)
+               if (iter->funcs->atomic_disable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               iter);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       iter->funcs->atomic_disable(iter, old_bridge_state);
+               } else if (iter->funcs->disable) {
                        iter->funcs->disable(iter);
+               }
 
                if (iter == bridge)
                        break;
@@ -424,7 +525,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
  * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
  *                                       in the encoder chain
  * @bridge: bridge control structure
- * @state: atomic state being committed
+ * @old_state: old atomic state
  *
  * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
  * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
@@ -434,7 +535,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
-                                         struct drm_atomic_state *state)
+                                         struct drm_atomic_state *old_state)
 {
        struct drm_encoder *encoder;
 
@@ -443,10 +544,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        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)
+               if (bridge->funcs->atomic_post_disable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               bridge);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       bridge->funcs->atomic_post_disable(bridge,
+                                                          old_bridge_state);
+               } else if (bridge->funcs->post_disable) {
                        bridge->funcs->post_disable(bridge);
+               }
        }
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
@@ -455,7 +566,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
  * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
  *                                     the encoder chain
  * @bridge: bridge control structure
- * @state: atomic state being committed
+ * @old_state: old atomic state
  *
  * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
  * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
@@ -465,7 +576,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
-                                       struct drm_atomic_state *state)
+                                       struct drm_atomic_state *old_state)
 {
        struct drm_encoder *encoder;
        struct drm_bridge *iter;
@@ -475,10 +586,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        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)
+               if (iter->funcs->atomic_pre_enable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               iter);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       iter->funcs->atomic_pre_enable(iter, old_bridge_state);
+               } else if (iter->funcs->pre_enable) {
                        iter->funcs->pre_enable(iter);
+               }
 
                if (iter == bridge)
                        break;
@@ -489,7 +609,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
 /**
  * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
  * @bridge: bridge control structure
- * @state: atomic state being committed
+ * @old_state: old atomic state
  *
  * Calls &drm_bridge_funcs.atomic_enable (falls back on
  * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
@@ -499,7 +619,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
-                                   struct drm_atomic_state *state)
+                                   struct drm_atomic_state *old_state)
 {
        struct drm_encoder *encoder;
 
@@ -508,14 +628,120 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
 
        encoder = bridge->encoder;
        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)
+               if (bridge->funcs->atomic_enable) {
+                       struct drm_bridge_state *old_bridge_state;
+
+                       old_bridge_state =
+                               drm_atomic_get_old_bridge_state(old_state,
+                                                               bridge);
+                       if (WARN_ON(!old_bridge_state))
+                               return;
+
+                       bridge->funcs->atomic_enable(bridge, old_bridge_state);
+               } else if (bridge->funcs->enable) {
                        bridge->funcs->enable(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, &crtc_state->mode,
+                                              &crtc_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 &drm_bridge_funcs.atomic_check() (falls back on
+ * &drm_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
+ * &drm_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, &encoder->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_reset() - Initialize a bridge state to its
+ *                                     default
+ * @bridge: the bridge this state is refers to
+ * @state: bridge state to initialize
+ *
+ * Initialize the bridge state to default values. This is meant to be* called
+ * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the
+ * bridge state.
+ */
+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
+                                     struct drm_bridge_state *state)
+{
+       memset(state, 0, sizeof(*state));
+       state->bridge = bridge;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
+
+/**
+ * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state
+ * @bridge: bridge object
+ * @state: atomic bridge state
+ *
+ * Copies atomic state from a bridge's current state and resets inferred values.
+ * This is useful for drivers that subclass the bridge state.
+ */
+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
+                                               struct drm_bridge_state *state)
+{
+       __drm_atomic_helper_private_obj_duplicate_state(&bridge->base,
+                                                       &state->base);
+       state->bridge = bridge;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state);
+
 #ifdef CONFIG_OF
 /**
  * of_drm_find_bridge - find the bridge corresponding to the device node in