165 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2017 The Linux Foundation. All rights reserved.4 */5 6#include "mdp5_kms.h"7 8/*9 * As of now, there are only 2 combinations possible for source split:10 *11 * Left | Right12 * -----|------13 * LM0 | LM114 * LM2 | LM515 *16 */17static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 };18 19static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm)20{21 int i;22 int pair_lm;23 24 pair_lm = lm_right_pair[lm];25 if (pair_lm < 0)26 return -EINVAL;27 28 for (i = 0; i < mdp5_kms->num_hwmixers; i++) {29 struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i];30 31 if (mixer->lm == pair_lm)32 return mixer->idx;33 }34 35 return -1;36}37 38int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc,39 uint32_t caps, struct mdp5_hw_mixer **mixer,40 struct mdp5_hw_mixer **r_mixer)41{42 struct msm_drm_private *priv = s->dev->dev_private;43 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));44 struct mdp5_global_state *global_state = mdp5_get_global_state(s);45 struct mdp5_hw_mixer_state *new_state;46 int i;47 48 if (IS_ERR(global_state))49 return PTR_ERR(global_state);50 51 new_state = &global_state->hwmixer;52 53 for (i = 0; i < mdp5_kms->num_hwmixers; i++) {54 struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i];55 56 /*57 * skip if already in-use by a different CRTC. If there is a58 * mixer already assigned to this CRTC, it means this call is59 * a request to get an additional right mixer. Assume that the60 * existing mixer is the 'left' one, and try to see if we can61 * get its corresponding 'right' pair.62 */63 if (new_state->hwmixer_to_crtc[cur->idx] &&64 new_state->hwmixer_to_crtc[cur->idx] != crtc)65 continue;66 67 /* skip if doesn't support some required caps: */68 if (caps & ~cur->caps)69 continue;70 71 if (r_mixer) {72 int pair_idx;73 74 pair_idx = get_right_pair_idx(mdp5_kms, cur->lm);75 if (pair_idx < 0)76 return -EINVAL;77 78 if (new_state->hwmixer_to_crtc[pair_idx])79 continue;80 81 *r_mixer = mdp5_kms->hwmixers[pair_idx];82 }83 84 /*85 * prefer a pair-able LM over an unpairable one. We can86 * switch the CRTC from Normal mode to Source Split mode87 * without requiring a full modeset if we had already88 * assigned this CRTC a pair-able LM.89 *90 * TODO: There will be assignment sequences which would91 * result in the CRTC requiring a full modeset, even92 * if we have the LM resources to prevent it. For a platform93 * with a few displays, we don't run out of pair-able LMs94 * so easily. For now, ignore the possibility of requiring95 * a full modeset.96 */97 if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR)98 *mixer = cur;99 }100 101 if (!(*mixer))102 return -ENOMEM;103 104 if (r_mixer && !(*r_mixer))105 return -ENOMEM;106 107 DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name);108 109 new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc;110 if (r_mixer) {111 DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm,112 crtc->name);113 new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc;114 }115 116 return 0;117}118 119int mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer)120{121 struct mdp5_global_state *global_state = mdp5_get_global_state(s);122 struct mdp5_hw_mixer_state *new_state;123 124 if (!mixer)125 return 0;126 127 if (IS_ERR(global_state))128 return PTR_ERR(global_state);129 130 new_state = &global_state->hwmixer;131 132 if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx]))133 return -EINVAL;134 135 DBG("%s: release from crtc %s", mixer->name,136 new_state->hwmixer_to_crtc[mixer->idx]->name);137 138 new_state->hwmixer_to_crtc[mixer->idx] = NULL;139 140 return 0;141}142 143static const char * const mixer_names[] = {144 "LM0", "LM1", "LM2", "LM3", "LM4", "LM5",145};146 147struct mdp5_hw_mixer *mdp5_mixer_init(struct drm_device *dev,148 const struct mdp5_lm_instance *lm)149{150 struct mdp5_hw_mixer *mixer;151 152 mixer = devm_kzalloc(dev->dev, sizeof(*mixer), GFP_KERNEL);153 if (!mixer)154 return ERR_PTR(-ENOMEM);155 156 mixer->name = mixer_names[lm->id];157 mixer->lm = lm->id;158 mixer->caps = lm->caps;159 mixer->pp = lm->pp;160 mixer->dspp = lm->dspp;161 mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id);162 163 return mixer;164}165