drm/tegra: dc: Store clock setup in atomic state
authorThierry Reding <treding@nvidia.com>
Mon, 8 Dec 2014 15:14:45 +0000 (16:14 +0100)
committerThierry Reding <treding@nvidia.com>
Tue, 27 Jan 2015 09:14:52 +0000 (10:14 +0100)
This allows the clock setup to be separated from the clock programming
and better matches the expectations of the atomic modesetting where no
code paths must fail during modeset.

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

index 4fb9048b2f65e1ad401b88aeb0abedecf5427311..b905a4e2bdf9dd1aa54b1513735e24e3178070d3 100644 (file)
@@ -41,6 +41,22 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
        return container_of(plane, struct tegra_plane, base);
 }
 
+struct tegra_dc_state {
+       struct drm_crtc_state base;
+
+       struct clk *clk;
+       unsigned long pclk;
+       unsigned int div;
+};
+
+static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
+{
+       if (state)
+               return container_of(state, struct tegra_dc_state, base);
+
+       return NULL;
+}
+
 static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
 {
        u32 value = WIN_A_ACT_REQ << index;
@@ -1004,13 +1020,48 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
        drm_crtc_cleanup(crtc);
 }
 
+static void tegra_crtc_reset(struct drm_crtc *crtc)
+{
+       struct tegra_dc_state *state;
+
+       kfree(crtc->state);
+       crtc->state = NULL;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               crtc->state = &state->base;
+}
+
+static struct drm_crtc_state *
+tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+       struct tegra_dc_state *state = to_dc_state(crtc->state);
+       struct tegra_dc_state *copy;
+
+       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       if (!copy)
+               return NULL;
+
+       copy->base.mode_changed = false;
+       copy->base.planes_changed = false;
+       copy->base.event = NULL;
+
+       return &copy->base;
+}
+
+static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state)
+{
+       kfree(state);
+}
+
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
        .page_flip = tegra_dc_page_flip,
        .set_config = drm_crtc_helper_set_config,
        .destroy = tegra_dc_destroy,
-       .reset = drm_atomic_helper_crtc_reset,
-       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       .reset = tegra_crtc_reset,
+       .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,
+       .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
 };
 
 static void tegra_dc_stop(struct tegra_dc *dc)
@@ -1148,6 +1199,20 @@ int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
        return 0;
 }
 
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+                              struct drm_crtc_state *crtc_state,
+                              struct clk *clk, unsigned long pclk,
+                              unsigned int div)
+{
+       struct tegra_dc_state *state = to_dc_state(crtc_state);
+
+       state->clk = clk;
+       state->pclk = pclk;
+       state->div = div;
+
+       return 0;
+}
+
 static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
        struct drm_display_mode *mode = &crtc->state->adjusted_mode;
index bf1c47ec46b6a8db05cb603439711c8daeb2bece..3db719de312f5bd44a8cde1b7820a5b33bda2c13 100644 (file)
@@ -180,6 +180,10 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
 void tegra_dc_commit(struct tegra_dc *dc);
 int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
                         unsigned long pclk, unsigned int div);
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+                              struct drm_crtc_state *crtc_state,
+                              struct clk *clk, unsigned long pclk,
+                              unsigned int div);
 
 struct tegra_output {
        struct device_node *of_node;