1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
214be3200SRob Clark /*
314be3200SRob Clark * Copyright (C) 2017 The Linux Foundation. All rights reserved.
414be3200SRob Clark */
514be3200SRob Clark
614be3200SRob Clark #include "mdp5_kms.h"
714be3200SRob Clark
814be3200SRob Clark /*
914be3200SRob Clark * As of now, there are only 2 combinations possible for source split:
1014be3200SRob Clark *
1114be3200SRob Clark * Left | Right
1214be3200SRob Clark * -----|------
1314be3200SRob Clark * LM0 | LM1
1414be3200SRob Clark * LM2 | LM5
1514be3200SRob Clark *
1614be3200SRob Clark */
1714be3200SRob Clark static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 };
1814be3200SRob Clark
get_right_pair_idx(struct mdp5_kms * mdp5_kms,int lm)1914be3200SRob Clark static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm)
2014be3200SRob Clark {
2114be3200SRob Clark int i;
2214be3200SRob Clark int pair_lm;
2314be3200SRob Clark
2414be3200SRob Clark pair_lm = lm_right_pair[lm];
2514be3200SRob Clark if (pair_lm < 0)
2614be3200SRob Clark return -EINVAL;
2714be3200SRob Clark
2814be3200SRob Clark for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
2914be3200SRob Clark struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i];
3014be3200SRob Clark
3114be3200SRob Clark if (mixer->lm == pair_lm)
3214be3200SRob Clark return mixer->idx;
3314be3200SRob Clark }
3414be3200SRob Clark
3514be3200SRob Clark return -1;
3614be3200SRob Clark }
3714be3200SRob Clark
mdp5_mixer_assign(struct drm_atomic_state * s,struct drm_crtc * crtc,uint32_t caps,struct mdp5_hw_mixer ** mixer,struct mdp5_hw_mixer ** r_mixer)3814be3200SRob Clark int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,
3914be3200SRob Clark uint32_t caps, struct mdp5_hw_mixer **mixer,
4014be3200SRob Clark struct mdp5_hw_mixer **r_mixer)
4114be3200SRob Clark {
4214be3200SRob Clark struct msm_drm_private *priv = s->dev->dev_private;
4314be3200SRob Clark struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
447907a0d7SArchit Taneja struct mdp5_global_state *global_state = mdp5_get_global_state(s);
4514be3200SRob Clark struct mdp5_hw_mixer_state *new_state;
4614be3200SRob Clark int i;
4714be3200SRob Clark
487907a0d7SArchit Taneja if (IS_ERR(global_state))
497907a0d7SArchit Taneja return PTR_ERR(global_state);
5014be3200SRob Clark
517907a0d7SArchit Taneja new_state = &global_state->hwmixer;
5214be3200SRob Clark
5314be3200SRob Clark for (i = 0; i < mdp5_kms->num_hwmixers; i++) {
5414be3200SRob Clark struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i];
5514be3200SRob Clark
5614be3200SRob Clark /*
5714be3200SRob Clark * skip if already in-use by a different CRTC. If there is a
5814be3200SRob Clark * mixer already assigned to this CRTC, it means this call is
5914be3200SRob Clark * a request to get an additional right mixer. Assume that the
6014be3200SRob Clark * existing mixer is the 'left' one, and try to see if we can
6114be3200SRob Clark * get its corresponding 'right' pair.
6214be3200SRob Clark */
6314be3200SRob Clark if (new_state->hwmixer_to_crtc[cur->idx] &&
6414be3200SRob Clark new_state->hwmixer_to_crtc[cur->idx] != crtc)
6514be3200SRob Clark continue;
6614be3200SRob Clark
6714be3200SRob Clark /* skip if doesn't support some required caps: */
6814be3200SRob Clark if (caps & ~cur->caps)
6914be3200SRob Clark continue;
7014be3200SRob Clark
7114be3200SRob Clark if (r_mixer) {
7214be3200SRob Clark int pair_idx;
7314be3200SRob Clark
7414be3200SRob Clark pair_idx = get_right_pair_idx(mdp5_kms, cur->lm);
7514be3200SRob Clark if (pair_idx < 0)
7614be3200SRob Clark return -EINVAL;
7714be3200SRob Clark
7814be3200SRob Clark if (new_state->hwmixer_to_crtc[pair_idx])
7914be3200SRob Clark continue;
8014be3200SRob Clark
8114be3200SRob Clark *r_mixer = mdp5_kms->hwmixers[pair_idx];
8214be3200SRob Clark }
8314be3200SRob Clark
8414be3200SRob Clark /*
8514be3200SRob Clark * prefer a pair-able LM over an unpairable one. We can
8614be3200SRob Clark * switch the CRTC from Normal mode to Source Split mode
8714be3200SRob Clark * without requiring a full modeset if we had already
8814be3200SRob Clark * assigned this CRTC a pair-able LM.
8914be3200SRob Clark *
9014be3200SRob Clark * TODO: There will be assignment sequences which would
9114be3200SRob Clark * result in the CRTC requiring a full modeset, even
9214be3200SRob Clark * if we have the LM resources to prevent it. For a platform
9314be3200SRob Clark * with a few displays, we don't run out of pair-able LMs
9414be3200SRob Clark * so easily. For now, ignore the possibility of requiring
9514be3200SRob Clark * a full modeset.
9614be3200SRob Clark */
9714be3200SRob Clark if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR)
9814be3200SRob Clark *mixer = cur;
9914be3200SRob Clark }
10014be3200SRob Clark
10114be3200SRob Clark if (!(*mixer))
10214be3200SRob Clark return -ENOMEM;
10314be3200SRob Clark
10414be3200SRob Clark if (r_mixer && !(*r_mixer))
10514be3200SRob Clark return -ENOMEM;
10614be3200SRob Clark
10714be3200SRob Clark DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name);
10814be3200SRob Clark
10914be3200SRob Clark new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc;
11014be3200SRob Clark if (r_mixer) {
11114be3200SRob Clark DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm,
11214be3200SRob Clark crtc->name);
11314be3200SRob Clark new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc;
11414be3200SRob Clark }
11514be3200SRob Clark
11614be3200SRob Clark return 0;
11714be3200SRob Clark }
11814be3200SRob Clark
mdp5_mixer_release(struct drm_atomic_state * s,struct mdp5_hw_mixer * mixer)119*ca75f6f7SJessica Zhang int mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)
12014be3200SRob Clark {
1217907a0d7SArchit Taneja struct mdp5_global_state *global_state = mdp5_get_global_state(s);
122*ca75f6f7SJessica Zhang struct mdp5_hw_mixer_state *new_state;
12314be3200SRob Clark
12414be3200SRob Clark if (!mixer)
125*ca75f6f7SJessica Zhang return 0;
126*ca75f6f7SJessica Zhang
127*ca75f6f7SJessica Zhang if (IS_ERR(global_state))
128*ca75f6f7SJessica Zhang return PTR_ERR(global_state);
129*ca75f6f7SJessica Zhang
130*ca75f6f7SJessica Zhang new_state = &global_state->hwmixer;
13114be3200SRob Clark
13214be3200SRob Clark if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))
133*ca75f6f7SJessica Zhang return -EINVAL;
13414be3200SRob Clark
13514be3200SRob Clark DBG("%s: release from crtc %s", mixer->name,
13614be3200SRob Clark new_state->hwmixer_to_crtc[mixer->idx]->name);
13714be3200SRob Clark
13814be3200SRob Clark new_state->hwmixer_to_crtc[mixer->idx] = NULL;
139*ca75f6f7SJessica Zhang
140*ca75f6f7SJessica Zhang return 0;
14114be3200SRob Clark }
14214be3200SRob Clark
mdp5_mixer_destroy(struct mdp5_hw_mixer * mixer)14314be3200SRob Clark void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer)
14414be3200SRob Clark {
14514be3200SRob Clark kfree(mixer);
14614be3200SRob Clark }
14714be3200SRob Clark
14814be3200SRob Clark static const char * const mixer_names[] = {
14914be3200SRob Clark "LM0", "LM1", "LM2", "LM3", "LM4", "LM5",
15014be3200SRob Clark };
15114be3200SRob Clark
mdp5_mixer_init(const struct mdp5_lm_instance * lm)15214be3200SRob Clark struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm)
15314be3200SRob Clark {
15414be3200SRob Clark struct mdp5_hw_mixer *mixer;
15514be3200SRob Clark
15614be3200SRob Clark mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
15714be3200SRob Clark if (!mixer)
15814be3200SRob Clark return ERR_PTR(-ENOMEM);
15914be3200SRob Clark
16014be3200SRob Clark mixer->name = mixer_names[lm->id];
16114be3200SRob Clark mixer->lm = lm->id;
16214be3200SRob Clark mixer->caps = lm->caps;
16314be3200SRob Clark mixer->pp = lm->pp;
16414be3200SRob Clark mixer->dspp = lm->dspp;
16514be3200SRob Clark mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id);
16614be3200SRob Clark
16714be3200SRob Clark return mixer;
16814be3200SRob Clark }
169