diff options
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h | 9 |
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__ */ |