]>
Commit | Line | Data |
---|---|---|
caab277b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
6803c606 AT |
2 | /* |
3 | * Copyright (C) 2017 The Linux Foundation. All rights reserved. | |
6803c606 AT |
4 | */ |
5 | ||
6 | #include "mdp5_kms.h" | |
7 | ||
8480adac AT |
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) | |
894558ec AT |
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)); | |
7907a0d7 | 44 | struct mdp5_global_state *global_state = mdp5_get_global_state(s); |
894558ec | 45 | struct mdp5_hw_mixer_state *new_state; |
894558ec AT |
46 | int i; |
47 | ||
7907a0d7 AT |
48 | if (IS_ERR(global_state)) |
49 | return PTR_ERR(global_state); | |
894558ec | 50 | |
7907a0d7 | 51 | new_state = &global_state->hwmixer; |
894558ec AT |
52 | |
53 | for (i = 0; i < mdp5_kms->num_hwmixers; i++) { | |
54 | struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i]; | |
55 | ||
8480adac AT |
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) | |
894558ec AT |
65 | continue; |
66 | ||
67 | /* skip if doesn't support some required caps: */ | |
68 | if (caps & ~cur->caps) | |
69 | continue; | |
70 | ||
8480adac AT |
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; | |
894558ec AT |
99 | } |
100 | ||
8480adac AT |
101 | if (!(*mixer)) |
102 | return -ENOMEM; | |
894558ec | 103 | |
8480adac AT |
104 | if (r_mixer && !(*r_mixer)) |
105 | return -ENOMEM; | |
894558ec | 106 | |
8480adac AT |
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; | |
894558ec AT |
117 | } |
118 | ||
119 | void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) | |
120 | { | |
7907a0d7 AT |
121 | struct mdp5_global_state *global_state = mdp5_get_global_state(s); |
122 | struct mdp5_hw_mixer_state *new_state = &global_state->hwmixer; | |
894558ec AT |
123 | |
124 | if (!mixer) | |
125 | return; | |
126 | ||
127 | if (WARN_ON(!new_state->hwmixer_to_crtc[mixer->idx])) | |
128 | return; | |
129 | ||
130 | DBG("%s: release from crtc %s", mixer->name, | |
131 | new_state->hwmixer_to_crtc[mixer->idx]->name); | |
132 | ||
133 | new_state->hwmixer_to_crtc[mixer->idx] = NULL; | |
134 | } | |
135 | ||
6803c606 AT |
136 | void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer) |
137 | { | |
138 | kfree(mixer); | |
139 | } | |
140 | ||
141 | static const char * const mixer_names[] = { | |
142 | "LM0", "LM1", "LM2", "LM3", "LM4", "LM5", | |
143 | }; | |
144 | ||
145 | struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm) | |
146 | { | |
147 | struct mdp5_hw_mixer *mixer; | |
148 | ||
149 | mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); | |
150 | if (!mixer) | |
151 | return ERR_PTR(-ENOMEM); | |
152 | ||
153 | mixer->name = mixer_names[lm->id]; | |
154 | mixer->lm = lm->id; | |
155 | mixer->caps = lm->caps; | |
156 | mixer->pp = lm->pp; | |
157 | mixer->dspp = lm->dspp; | |
158 | mixer->flush_mask = mdp_ctl_flush_mask_lm(lm->id); | |
159 | ||
160 | return mixer; | |
161 | } |