]> Git Repo - J-linux.git/blobdiff - drivers/gpu/drm/vc4/vc4_kms.c
Merge v5.16-rc5 into drm-next
[J-linux.git] / drivers / gpu / drm / vc4 / vc4_kms.c
index b61792d2aa65740db39b49f957dc41eda99c5824..bf3706f97ec7fb7d53451cb71ce441644bd8ed53 100644 (file)
@@ -39,9 +39,11 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
 
 struct vc4_hvs_state {
        struct drm_private_state base;
+       unsigned long core_clock_rate;
 
        struct {
                unsigned in_use: 1;
+               unsigned long fifo_load;
                struct drm_crtc_commit *pending_commit;
        } fifo_state[HVS_NUM_CHANNELS];
 };
@@ -233,6 +235,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
        unsigned int i;
 
        for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
                struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
                u32 dispctrl;
                u32 dsp3_mux;
@@ -253,7 +256,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
                 * TXP IP, and we need to disable the FIFO2 -> pixelvalve1
                 * route.
                 */
-               if (vc4_state->feed_txp)
+               if (vc4_crtc->feeds_txp)
                        dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
                else
                        dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
@@ -338,11 +341,20 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_hvs *hvs = vc4->hvs;
        struct drm_crtc_state *new_crtc_state;
+       struct vc4_hvs_state *new_hvs_state;
        struct drm_crtc *crtc;
        struct vc4_hvs_state *old_hvs_state;
        unsigned int channel;
        int i;
 
+       old_hvs_state = vc4_hvs_get_old_global_state(state);
+       if (WARN_ON(IS_ERR(old_hvs_state)))
+               return;
+
+       new_hvs_state = vc4_hvs_get_new_global_state(state);
+       if (WARN_ON(IS_ERR(new_hvs_state)))
+               return;
+
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
                struct vc4_crtc_state *vc4_crtc_state;
 
@@ -353,9 +365,13 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
                vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
        }
 
-       old_hvs_state = vc4_hvs_get_old_global_state(state);
-       if (IS_ERR(old_hvs_state))
-               return;
+       if (vc4->hvs->hvs5) {
+               unsigned long core_rate = max_t(unsigned long,
+                                               500000000,
+                                               new_hvs_state->core_clock_rate);
+
+               clk_set_min_rate(hvs->core_clk, core_rate);
+       }
 
        for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
                struct drm_crtc_commit *commit;
@@ -376,9 +392,6 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
                old_hvs_state->fifo_state[channel].pending_commit = NULL;
        }
 
-       if (vc4->hvs->hvs5)
-               clk_set_min_rate(hvs->core_clk, 500000000);
-
        drm_atomic_helper_commit_modeset_disables(dev, state);
 
        vc4_ctm_commit(vc4, state);
@@ -400,8 +413,12 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_cleanup_planes(dev, state);
 
-       if (vc4->hvs->hvs5)
-               clk_set_min_rate(hvs->core_clk, 0);
+       if (vc4->hvs->hvs5) {
+               drm_dbg(dev, "Running the core clock at %lu Hz\n",
+                       new_hvs_state->core_clock_rate);
+
+               clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate);
+       }
 }
 
 static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
@@ -553,9 +570,6 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state)
        struct drm_plane *plane;
        int i;
 
-       if (!vc4->load_tracker_available)
-               return 0;
-
        priv_state = drm_atomic_get_private_obj_state(state,
                                                      &vc4->load_tracker);
        if (IS_ERR(priv_state))
@@ -630,9 +644,6 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
 
-       if (!vc4->load_tracker_available)
-               return;
-
        drm_atomic_private_obj_fini(&vc4->load_tracker);
 }
 
@@ -640,9 +651,6 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
 {
        struct vc4_load_tracker_state *load_state;
 
-       if (!vc4->load_tracker_available)
-               return 0;
-
        load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
        if (!load_state)
                return -ENOMEM;
@@ -667,11 +675,13 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
 
        __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
 
-
        for (i = 0; i < HVS_NUM_CHANNELS; i++) {
                state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
+               state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
        }
 
+       state->core_clock_rate = old_state->core_clock_rate;
+
        return &state->base;
 }
 
@@ -826,6 +836,76 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
        return 0;
 }
 
+static int
+vc4_core_clock_atomic_check(struct drm_atomic_state *state)
+{
+       struct vc4_dev *vc4 = to_vc4_dev(state->dev);
+       struct drm_private_state *priv_state;
+       struct vc4_hvs_state *hvs_new_state;
+       struct vc4_load_tracker_state *load_state;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct drm_crtc *crtc;
+       unsigned int num_outputs;
+       unsigned long pixel_rate;
+       unsigned long cob_rate;
+       unsigned int i;
+
+       priv_state = drm_atomic_get_private_obj_state(state,
+                                                     &vc4->load_tracker);
+       if (IS_ERR(priv_state))
+               return PTR_ERR(priv_state);
+
+       load_state = to_vc4_load_tracker_state(priv_state);
+
+       hvs_new_state = vc4_hvs_get_global_state(state);
+       if (IS_ERR(hvs_new_state))
+               return PTR_ERR(hvs_new_state);
+
+       for_each_oldnew_crtc_in_state(state, crtc,
+                                     old_crtc_state,
+                                     new_crtc_state,
+                                     i) {
+               if (old_crtc_state->active) {
+                       struct vc4_crtc_state *old_vc4_state =
+                               to_vc4_crtc_state(old_crtc_state);
+                       unsigned int channel = old_vc4_state->assigned_channel;
+
+                       hvs_new_state->fifo_state[channel].fifo_load = 0;
+               }
+
+               if (new_crtc_state->active) {
+                       struct vc4_crtc_state *new_vc4_state =
+                               to_vc4_crtc_state(new_crtc_state);
+                       unsigned int channel = new_vc4_state->assigned_channel;
+
+                       hvs_new_state->fifo_state[channel].fifo_load =
+                               new_vc4_state->hvs_load;
+               }
+       }
+
+       cob_rate = 0;
+       num_outputs = 0;
+       for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+               if (!hvs_new_state->fifo_state[i].in_use)
+                       continue;
+
+               num_outputs++;
+               cob_rate += hvs_new_state->fifo_state[i].fifo_load;
+       }
+
+       pixel_rate = load_state->hvs_load;
+       if (num_outputs > 1) {
+               pixel_rate = (pixel_rate * 40) / 100;
+       } else {
+               pixel_rate = (pixel_rate * 60) / 100;
+       }
+
+       hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate);
+
+       return 0;
+}
+
+
 static int
 vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
 {
@@ -843,7 +923,11 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
        if (ret)
                return ret;
 
-       return vc4_load_tracker_atomic_check(state);
+       ret = vc4_load_tracker_atomic_check(state);
+       if (ret)
+               return ret;
+
+       return vc4_core_clock_atomic_check(state);
 }
 
 static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = {
@@ -864,9 +948,12 @@ int vc4_kms_load(struct drm_device *dev)
                                              "brcm,bcm2711-vc5");
        int ret;
 
+       /*
+        * The limits enforced by the load tracker aren't relevant for
+        * the BCM2711, but the load tracker computations are used for
+        * the core clock rate calculation.
+        */
        if (!is_vc5) {
-               vc4->load_tracker_available = true;
-
                /* Start with the load tracker enabled. Can be
                 * disabled through the debugfs load_tracker file.
                 */
This page took 0.037178 seconds and 4 git commands to generate.