1 /* 2 * Copyright (C) 2017 The Linux Foundation. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 17 #include "mdp5_kms.h" 18 19 /* 20 * As of now, there are only 2 combinations possible for source split: 21 * 22 * Left | Right 23 * -----|------ 24 * LM0 | LM1 25 * LM2 | LM5 26 * 27 */ 28 static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 }; 29 30 static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm) 31 { 32 int i; 33 int pair_lm; 34 35 pair_lm = lm_right_pair[lm]; 36 if (pair_lm < 0) 37 return -EINVAL; 38 39 for (i = 0; i < mdp5_kms->num_hwmixers; i++) { 40 struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i]; 41 42 if (mixer->lm == pair_lm) 43 return mixer->idx; 44 } 45 46 return -1; 47 } 48 49 int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, 50 uint32_t caps, struct mdp5_hw_mixer **mixer, 51 struct mdp5_hw_mixer **r_mixer) 52 { 53 struct msm_drm_private *priv = s->dev->dev_private; 54 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); 55 struct mdp5_global_state *global_state = mdp5_get_global_state(s); 56 struct mdp5_hw_mixer_state *new_state; 57 int i; 58 59 if (IS_ERR(global_state)) 60 return PTR_ERR(global_state); 61 62 new_state = &global_state->hwmixer; 63 64 for (i = 0; i < mdp5_kms->num_hwmixers; i++) { 65 struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i]; 66 67 /* 68 * skip if already in-use by a different CRTC. If there is a 69 * mixer already assigned to this CRTC, it means this call is 70 * a request to get an additional right mixer. Assume that the 71 * existing mixer is the 'left' one, and try to see if we can 72 * get its corresponding 'right' pair. 73 */ 74 if (new_state->hwmixer_to_crtc[cur->idx] && 75 new_state->hwmixer_to_crtc[cur->idx] != crtc) 76 continue; 77 78 /* skip if doesn't support some required caps: */ 79 if (caps & ~cur->caps) 80 continue; 81 82 if (r_mixer) { 83 int pair_idx; 84 85 pair_idx = get_right_pair_idx(mdp5_kms, cur->lm); 86 if (pair_idx < 0) 87 return -EINVAL; 88 89 if (new_state->hwmixer_to_crtc[pair_idx]) 90 continue; 91 92 *r_mixer = mdp5_kms->hwmixers[pair_idx]; 93 } 94 95 /* 96 * prefer a pair-able LM over an unpairable one. We can 97 * switch the CRTC from Normal mode to Source Split mode 98 * without requiring a full modeset if we had already 99 * assigned this CRTC a pair-able LM. 100 * 101 * TODO: There will be assignment sequences which would 102 * result in the CRTC requiring a full modeset, even 103 * if we have the LM resources to prevent it. For a platform 104 * with a few displays, we don't run out of pair-able LMs 105 * so easily. For now, ignore the possibility of requiring 106 * a full modeset. 107 */ 108 if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR) 109 *mixer = cur; 110 } 111 112 if (!(*mixer)) 113 return -ENOMEM; 114 115 if (r_mixer && !(*r_mixer)) 116 return -ENOMEM; 117 118 DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name); 119 120 new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc; 121 if (r_mixer) { 122 DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm, 123 crtc->name); 124 new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc; 125 } 126 127 return 0; 128 } 129 130 void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) 131 { 132 struct mdp5_global_state *global_state = mdp5_get_global_state(s); 133 struct mdp5_hw_mixer_state *new_state = &global_state->hwmixer; 134 135 if (!mixer) 136 return; 137 138 if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx])) 139 return; 140 141 DBG("%s: release from crtc %s", mixer->name, 142 new_state->hwmixer_to_crtc[mixer->idx]->name); 143 144 new_state->hwmixer_to_crtc[mixer->idx] = NULL; 145 } 146 147 void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer) 148 { 149 kfree(mixer); 150 } 151 152 static const char * const mixer_names[] = { 153 "LM0", "LM1", "LM2", "LM3", "LM4", "LM5", 154 }; 155 156 struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm) 157 { 158 struct mdp5_hw_mixer *mixer; 159 160 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 161 if (!mixer) 162 return ERR_PTR(-ENOMEM); 163 164 mixer->name = mixer_names[lm->id]; 165 mixer->lm = lm->id; 166 mixer->caps = lm->caps; 167 mixer->pp = lm->pp; 168 mixer->dspp = lm->dspp; 169 mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id); 170 171 return mixer; 172 } 173