drm/tegra: hub: Use private object for global state
authorThierry Reding <treding@nvidia.com>
Tue, 28 Nov 2017 10:20:40 +0000 (11:20 +0100)
committerThierry Reding <treding@nvidia.com>
Fri, 16 Mar 2018 23:03:36 +0000 (00:03 +0100)
Rather than subclass the global atomic state to store the hub display
clock and rate, create a private object and store this data in its
state.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/hub.c
drivers/gpu/drm/tegra/hub.h

index dfa787e..464495b 100644 (file)
@@ -1736,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
        drm_crtc_vblank_on(crtc);
 }
 
-static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
-                                  struct drm_crtc_state *state)
-{
-       struct tegra_atomic_state *s = to_tegra_atomic_state(state->state);
-       struct tegra_dc_state *tegra = to_dc_state(state);
-
-       /*
-        * The display hub display clock needs to be fed by the display clock
-        * with the highest frequency to ensure proper functioning of all the
-        * displays.
-        *
-        * Note that this isn't used before Tegra186, but it doesn't hurt and
-        * conditionalizing it would make the code less clean.
-        */
-       if (state->active) {
-               if (!s->clk_disp || tegra->pclk > s->rate) {
-                       s->dc = to_tegra_dc(crtc);
-                       s->clk_disp = s->dc->clk;
-                       s->rate = tegra->pclk;
-               }
-       }
-
-       return 0;
-}
-
 static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_crtc_state)
 {
@@ -1797,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
-       .atomic_check = tegra_crtc_atomic_check,
        .atomic_begin = tegra_crtc_atomic_begin,
        .atomic_flush = tegra_crtc_atomic_flush,
        .atomic_enable = tegra_crtc_atomic_enable,
index d50bddb..e20e013 100644 (file)
@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm,
        if (err < 0)
                return err;
 
+       err = tegra_display_hub_atomic_check(drm, state);
+       if (err < 0)
+               return err;
+
        err = drm_atomic_normalize_zpos(drm, state);
        if (err < 0)
                return err;
@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm,
        return 0;
 }
 
-static struct drm_atomic_state *
-tegra_atomic_state_alloc(struct drm_device *drm)
-{
-       struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
-
-       if (!state || drm_atomic_state_init(drm, &state->base) < 0) {
-               kfree(state);
-               return NULL;
-       }
-
-       return &state->base;
-}
-
-static void tegra_atomic_state_clear(struct drm_atomic_state *state)
-{
-       struct tegra_atomic_state *tegra = to_tegra_atomic_state(state);
-
-       drm_atomic_state_default_clear(state);
-       tegra->clk_disp = NULL;
-       tegra->dc = NULL;
-       tegra->rate = 0;
-}
-
-static void tegra_atomic_state_free(struct drm_atomic_state *state)
-{
-       drm_atomic_state_default_release(state);
-       kfree(state);
-}
-
 static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
        .fb_create = tegra_fb_create,
 #ifdef CONFIG_DRM_FBDEV_EMULATION
@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
 #endif
        .atomic_check = tegra_atomic_check,
        .atomic_commit = drm_atomic_helper_commit,
-       .atomic_state_alloc = tegra_atomic_state_alloc,
-       .atomic_state_clear = tegra_atomic_state_clear,
-       .atomic_state_free = tegra_atomic_state_free,
 };
 
 static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state)
index 73b661c..4f41aae 100644 (file)
@@ -42,20 +42,6 @@ struct tegra_fbdev {
 };
 #endif
 
-struct tegra_atomic_state {
-       struct drm_atomic_state base;
-
-       struct clk *clk_disp;
-       struct tegra_dc *dc;
-       unsigned long rate;
-};
-
-static inline struct tegra_atomic_state *
-to_tegra_atomic_state(struct drm_atomic_state *state)
-{
-       return container_of(state, struct tegra_atomic_state, base);
-}
-
 struct tegra_drm {
        struct drm_device *drm;
 
index 094324d..9a3f23d 100644 (file)
@@ -573,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
        return p;
 }
 
+static struct drm_private_state *
+tegra_display_hub_duplicate_state(struct drm_private_obj *obj)
+{
+       struct tegra_display_hub_state *state;
+
+       state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+
+       return &state->base;
+}
+
+static void tegra_display_hub_destroy_state(struct drm_private_obj *obj,
+                                           struct drm_private_state *state)
+{
+       struct tegra_display_hub_state *hub_state =
+               to_tegra_display_hub_state(state);
+
+       kfree(hub_state);
+}
+
+static const struct drm_private_state_funcs tegra_display_hub_state_funcs = {
+       .atomic_duplicate_state = tegra_display_hub_duplicate_state,
+       .atomic_destroy_state = tegra_display_hub_destroy_state,
+};
+
+static struct tegra_display_hub_state *
+tegra_display_hub_get_state(struct tegra_display_hub *hub,
+                           struct drm_atomic_state *state)
+{
+       struct drm_device *drm = dev_get_drvdata(hub->client.parent);
+       struct drm_private_state *priv;
+
+       WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex));
+
+       priv = drm_atomic_get_private_obj_state(state, &hub->base);
+       if (IS_ERR(priv))
+               return ERR_CAST(priv);
+
+       return to_tegra_display_hub_state(priv);
+}
+
+int tegra_display_hub_atomic_check(struct drm_device *drm,
+                                  struct drm_atomic_state *state)
+{
+       struct tegra_drm *tegra = drm->dev_private;
+       struct tegra_display_hub_state *hub_state;
+       struct drm_crtc_state *old, *new;
+       struct drm_crtc *crtc;
+       unsigned int i;
+
+       if (!tegra->hub)
+               return 0;
+
+       hub_state = tegra_display_hub_get_state(tegra->hub, state);
+       if (IS_ERR(hub_state))
+               return PTR_ERR(hub_state);
+
+       /*
+        * The display hub display clock needs to be fed by the display clock
+        * with the highest frequency to ensure proper functioning of all the
+        * displays.
+        *
+        * Note that this isn't used before Tegra186, but it doesn't hurt and
+        * conditionalizing it would make the code less clean.
+        */
+       for_each_oldnew_crtc_in_state(state, crtc, old, new, i) {
+               struct tegra_dc_state *dc = to_dc_state(new);
+
+               if (new->active) {
+                       if (!hub_state->clk || dc->pclk > hub_state->rate) {
+                               hub_state->dc = to_tegra_dc(dc->base.crtc);
+                               hub_state->clk = hub_state->dc->clk;
+                               hub_state->rate = dc->pclk;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static void tegra_display_hub_update(struct tegra_dc *dc)
 {
        u32 value;
@@ -598,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc)
 void tegra_display_hub_atomic_commit(struct drm_device *drm,
                                     struct drm_atomic_state *state)
 {
-       struct tegra_atomic_state *s = to_tegra_atomic_state(state);
        struct tegra_drm *tegra = drm->dev_private;
        struct tegra_display_hub *hub = tegra->hub;
+       struct tegra_display_hub_state *hub_state;
        struct device *dev = hub->client.dev;
        int err;
 
-       if (s->clk_disp) {
-               err = clk_set_rate(s->clk_disp, s->rate);
+       hub_state = tegra_display_hub_get_state(hub, state);
+
+       if (hub_state->clk) {
+               err = clk_set_rate(hub_state->clk, hub_state->rate);
                if (err < 0)
                        dev_err(dev, "failed to set rate of %pC to %lu Hz\n",
-                               s->clk_disp, s->rate);
+                               hub_state->clk, hub_state->rate);
 
-               err = clk_set_parent(hub->clk_disp, s->clk_disp);
+               err = clk_set_parent(hub->clk_disp, hub_state->clk);
                if (err < 0)
                        dev_err(dev, "failed to set parent of %pC to %pC: %d\n",
-                               hub->clk_disp, s->clk_disp, err);
+                               hub->clk_disp, hub_state->clk, err);
        }
 
-       if (s->dc)
-               tegra_display_hub_update(s->dc);
+       if (hub_state->dc)
+               tegra_display_hub_update(hub_state->dc);
 }
 
 static int tegra_display_hub_init(struct host1x_client *client)
@@ -625,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client)
        struct tegra_display_hub *hub = to_tegra_display_hub(client);
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = drm->dev_private;
+       struct tegra_display_hub_state *state;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       drm_atomic_private_obj_init(&hub->base, &state->base,
+                                   &tegra_display_hub_state_funcs);
 
        tegra->hub = hub;
 
@@ -636,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client)
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_drm *tegra = drm->dev_private;
 
+       drm_atomic_private_obj_fini(&tegra->hub->base);
        tegra->hub = NULL;
 
        return 0;
index 890a47c..85b8bf4 100644 (file)
@@ -41,6 +41,7 @@ struct tegra_display_hub_soc {
 };
 
 struct tegra_display_hub {
+       struct drm_private_obj base;
        struct host1x_client client;
        struct clk *clk_disp;
        struct clk *clk_dsc;
@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client)
        return container_of(client, struct tegra_display_hub, client);
 }
 
+struct tegra_display_hub_state {
+       struct drm_private_state base;
+
+       struct tegra_dc *dc;
+       unsigned long rate;
+       struct clk *clk;
+};
+
+static inline struct tegra_display_hub_state *
+to_tegra_display_hub_state(struct drm_private_state *priv)
+{
+       return container_of(priv, struct tegra_display_hub_state, base);
+}
+
 struct tegra_dc;
 struct tegra_plane;
 
@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
                                            unsigned int wgrp,
                                            unsigned int index);
 
+int tegra_display_hub_atomic_check(struct drm_device *drm,
+                                  struct drm_atomic_state *state);
 void tegra_display_hub_atomic_commit(struct drm_device *drm,
                                     struct drm_atomic_state *state);