1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 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 | Right 12 * -----|------ 13 * LM0 | LM1 14 * LM2 | LM5 15 * 16 */ 17 static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 }; 18 19 static 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 38 int 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 a 58 * mixer already assigned to this CRTC, it means this call is 59 * a request to get an additional right mixer. Assume that the 60 * existing mixer is the 'left' one, and try to see if we can 61 * 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 can 86 * switch the CRTC from Normal mode to Source Split mode 87 * without requiring a full modeset if we had already 88 * assigned this CRTC a pair-able LM. 89 * 90 * TODO: There will be assignment sequences which would 91 * result in the CRTC requiring a full modeset, even 92 * if we have the LM resources to prevent it. For a platform 93 * with a few displays, we don't run out of pair-able LMs 94 * so easily. For now, ignore the possibility of requiring 95 * 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 119 int 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 143 void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer) 144 { 145 kfree(mixer); 146 } 147 148 static const char * const mixer_names[] = { 149 "LM0", "LM1", "LM2", "LM3", "LM4", "LM5", 150 }; 151 152 struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm) 153 { 154 struct mdp5_hw_mixer *mixer; 155 156 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 157 if (!mixer) 158 return ERR_PTR(-ENOMEM); 159 160 mixer->name = mixer_names[lm->id]; 161 mixer->lm = lm->id; 162 mixer->caps = lm->caps; 163 mixer->pp = lm->pp; 164 mixer->dspp = lm->dspp; 165 mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id); 166 167 return mixer; 168 } 169