summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c31
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c1
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h1
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c55
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h9
5 files changed, 97 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 12dc94854410..9cfad3defa61 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -367,6 +367,30 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
mdp5_crtc->enabled = true;
}
+int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
+ struct drm_crtc_state *new_crtc_state)
+{
+ struct mdp5_crtc_state *mdp5_cstate =
+ to_mdp5_crtc_state(new_crtc_state);
+ struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
+ bool new_mixer = false;
+
+ new_mixer = !pipeline->mixer;
+
+ if (new_mixer) {
+ struct mdp5_hw_mixer *old_mixer = pipeline->mixer;
+
+ pipeline->mixer = mdp5_mixer_assign(new_crtc_state->state, crtc,
+ MDP_LM_CAP_DISPLAY);
+ if (IS_ERR(pipeline->mixer))
+ return PTR_ERR(pipeline->mixer);
+
+ mdp5_mixer_release(new_crtc_state->state, old_mixer);
+ }
+
+ return 0;
+}
+
struct plane_state {
struct drm_plane *plane;
struct mdp5_plane_state *state;
@@ -399,6 +423,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
const struct drm_plane_state *pstate;
bool cursor_plane = false;
int cnt = 0, base = 0, i;
+ int ret;
DBG("%s: check", crtc->name);
@@ -412,6 +437,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
cursor_plane = true;
}
+ ret = mdp5_crtc_setup_pipeline(crtc, state);
+ if (ret) {
+ dev_err(dev->dev, "couldn't assign mixers %d\n", ret);
+ return ret;
+ }
+
/* assign a stage based on sorted zpos property */
sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 9d855ee0c0a4..880c7d4208ec 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -93,6 +93,7 @@ struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s)
/* Copy state: */
new_state->hwpipe = mdp5_kms->state->hwpipe;
+ new_state->hwmixer = mdp5_kms->state->hwmixer;
if (mdp5_kms->smp)
new_state->smp = mdp5_kms->state->smp;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 84b28936613d..35f3c30a6d4a 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -90,6 +90,7 @@ struct mdp5_kms {
*/
struct mdp5_state {
struct mdp5_hw_pipe_state hwpipe;
+ struct mdp5_hw_mixer_state hwmixer;
struct mdp5_smp_state smp;
};
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c
index 032dc0a9638f..6f353c4886e4 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c
@@ -16,6 +16,61 @@
#include "mdp5_kms.h"
+struct mdp5_hw_mixer *mdp5_mixer_assign(struct drm_atomic_state *s,
+ struct drm_crtc *crtc, uint32_t caps)
+{
+ struct msm_drm_private *priv = s->dev->dev_private;
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
+ struct mdp5_state *state = mdp5_get_state(s);
+ struct mdp5_hw_mixer_state *new_state;
+ struct mdp5_hw_mixer *mixer = NULL;
+ int i;
+
+ if (IS_ERR(state))
+ return ERR_CAST(state);
+
+ new_state = &state->hwmixer;
+
+ for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
+ struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i];
+
+ /* skip if already in-use */
+ if (new_state->hwmixer_to_crtc[cur->idx])
+ continue;
+
+ /* skip if doesn't support some required caps: */
+ if (caps & ~cur->caps)
+ continue;
+
+ if (!mixer)
+ mixer = cur;
+ }
+
+ if (!mixer)
+ return ERR_PTR(-ENOMEM);
+
+ new_state->hwmixer_to_crtc[mixer->idx] = crtc;
+
+ return mixer;
+}
+
+void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
+{
+ struct mdp5_state *state = mdp5_get_state(s);
+ struct mdp5_hw_mixer_state *new_state = &state->hwmixer;
+
+ if (!mixer)
+ return;
+
+ if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))
+ return;
+
+ DBG("%s: release from crtc %s", mixer->name,
+ new_state->hwmixer_to_crtc[mixer->idx]->name);
+
+ new_state->hwmixer_to_crtc[mixer->idx] = NULL;
+}
+
void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer)
{
kfree(mixer);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h
index 08d2173703bf..18ed933ae574 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h
@@ -31,7 +31,16 @@ struct mdp5_hw_mixer {
uint32_t flush_mask; /* used to commit LM registers */
};
+/* global atomic state of assignment between CRTCs and Layer Mixers: */
+struct mdp5_hw_mixer_state {
+ struct drm_crtc *hwmixer_to_crtc[8];
+};
+
struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm);
void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm);
+struct mdp5_hw_mixer *mdp5_mixer_assign(struct drm_atomic_state *s,
+ struct drm_crtc *crtc, uint32_t caps);
+void mdp5_mixer_release(struct drm_atomic_state *s,
+ struct mdp5_hw_mixer *mixer);
#endif /* __MDP5_LM_H__ */