.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. |
---|
3 | 4 | * Copyright (C) 2013 Red Hat |
---|
4 | 5 | * Author: Rob Clark <robdclark@gmail.com> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
8 | | - * the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License along with |
---|
16 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
---|
17 | 6 | */ |
---|
18 | 7 | |
---|
19 | 8 | #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ |
---|
20 | 9 | #include <linux/sort.h> |
---|
21 | 10 | #include <linux/debugfs.h> |
---|
22 | 11 | #include <linux/ktime.h> |
---|
23 | | -#include <drm/drm_mode.h> |
---|
| 12 | +#include <linux/bits.h> |
---|
| 13 | + |
---|
24 | 14 | #include <drm/drm_crtc.h> |
---|
25 | | -#include <drm/drm_crtc_helper.h> |
---|
26 | 15 | #include <drm/drm_flip_work.h> |
---|
| 16 | +#include <drm/drm_mode.h> |
---|
| 17 | +#include <drm/drm_probe_helper.h> |
---|
27 | 18 | #include <drm/drm_rect.h> |
---|
| 19 | +#include <drm/drm_vblank.h> |
---|
28 | 20 | |
---|
29 | 21 | #include "dpu_kms.h" |
---|
30 | 22 | #include "dpu_hw_lm.h" |
---|
31 | 23 | #include "dpu_hw_ctl.h" |
---|
| 24 | +#include "dpu_hw_dspp.h" |
---|
32 | 25 | #include "dpu_crtc.h" |
---|
33 | 26 | #include "dpu_plane.h" |
---|
34 | 27 | #include "dpu_encoder.h" |
---|
35 | 28 | #include "dpu_vbif.h" |
---|
36 | | -#include "dpu_power_handle.h" |
---|
37 | 29 | #include "dpu_core_perf.h" |
---|
38 | 30 | #include "dpu_trace.h" |
---|
39 | 31 | |
---|
.. | .. |
---|
47 | 39 | #define LEFT_MIXER 0 |
---|
48 | 40 | #define RIGHT_MIXER 1 |
---|
49 | 41 | |
---|
50 | | -#define MISR_BUFF_SIZE 256 |
---|
| 42 | +/* timeout in ms waiting for frame done */ |
---|
| 43 | +#define DPU_CRTC_FRAME_DONE_TIMEOUT_MS 60 |
---|
51 | 44 | |
---|
52 | | -static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
---|
| 45 | +#define CONVERT_S3_15(val) \ |
---|
| 46 | + (((((u64)val) & ~BIT_ULL(63)) >> 17) & GENMASK_ULL(17, 0)) |
---|
| 47 | + |
---|
| 48 | +static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) |
---|
53 | 49 | { |
---|
54 | | - struct msm_drm_private *priv; |
---|
55 | | - |
---|
56 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
---|
57 | | - DPU_ERROR("invalid crtc\n"); |
---|
58 | | - return NULL; |
---|
59 | | - } |
---|
60 | | - priv = crtc->dev->dev_private; |
---|
61 | | - if (!priv || !priv->kms) { |
---|
62 | | - DPU_ERROR("invalid kms\n"); |
---|
63 | | - return NULL; |
---|
64 | | - } |
---|
| 50 | + struct msm_drm_private *priv = crtc->dev->dev_private; |
---|
65 | 51 | |
---|
66 | 52 | return to_dpu_kms(priv->kms); |
---|
67 | | -} |
---|
68 | | - |
---|
69 | | -static inline int _dpu_crtc_power_enable(struct dpu_crtc *dpu_crtc, bool enable) |
---|
70 | | -{ |
---|
71 | | - struct drm_crtc *crtc; |
---|
72 | | - struct msm_drm_private *priv; |
---|
73 | | - struct dpu_kms *dpu_kms; |
---|
74 | | - |
---|
75 | | - if (!dpu_crtc) { |
---|
76 | | - DPU_ERROR("invalid dpu crtc\n"); |
---|
77 | | - return -EINVAL; |
---|
78 | | - } |
---|
79 | | - |
---|
80 | | - crtc = &dpu_crtc->base; |
---|
81 | | - if (!crtc->dev || !crtc->dev->dev_private) { |
---|
82 | | - DPU_ERROR("invalid drm device\n"); |
---|
83 | | - return -EINVAL; |
---|
84 | | - } |
---|
85 | | - |
---|
86 | | - priv = crtc->dev->dev_private; |
---|
87 | | - if (!priv->kms) { |
---|
88 | | - DPU_ERROR("invalid kms\n"); |
---|
89 | | - return -EINVAL; |
---|
90 | | - } |
---|
91 | | - |
---|
92 | | - dpu_kms = to_dpu_kms(priv->kms); |
---|
93 | | - |
---|
94 | | - if (enable) |
---|
95 | | - pm_runtime_get_sync(&dpu_kms->pdev->dev); |
---|
96 | | - else |
---|
97 | | - pm_runtime_put_sync(&dpu_kms->pdev->dev); |
---|
98 | | - |
---|
99 | | - return 0; |
---|
100 | | -} |
---|
101 | | - |
---|
102 | | -/** |
---|
103 | | - * _dpu_crtc_rp_to_crtc - get crtc from resource pool object |
---|
104 | | - * @rp: Pointer to resource pool |
---|
105 | | - * return: Pointer to drm crtc if success; null otherwise |
---|
106 | | - */ |
---|
107 | | -static struct drm_crtc *_dpu_crtc_rp_to_crtc(struct dpu_crtc_respool *rp) |
---|
108 | | -{ |
---|
109 | | - if (!rp) |
---|
110 | | - return NULL; |
---|
111 | | - |
---|
112 | | - return container_of(rp, struct dpu_crtc_state, rp)->base.crtc; |
---|
113 | | -} |
---|
114 | | - |
---|
115 | | -/** |
---|
116 | | - * _dpu_crtc_rp_reclaim - reclaim unused, or all if forced, resources in pool |
---|
117 | | - * @rp: Pointer to resource pool |
---|
118 | | - * @force: True to reclaim all resources; otherwise, reclaim only unused ones |
---|
119 | | - * return: None |
---|
120 | | - */ |
---|
121 | | -static void _dpu_crtc_rp_reclaim(struct dpu_crtc_respool *rp, bool force) |
---|
122 | | -{ |
---|
123 | | - struct dpu_crtc_res *res, *next; |
---|
124 | | - struct drm_crtc *crtc; |
---|
125 | | - |
---|
126 | | - crtc = _dpu_crtc_rp_to_crtc(rp); |
---|
127 | | - if (!crtc) { |
---|
128 | | - DPU_ERROR("invalid crtc\n"); |
---|
129 | | - return; |
---|
130 | | - } |
---|
131 | | - |
---|
132 | | - DPU_DEBUG("crtc%d.%u %s\n", crtc->base.id, rp->sequence_id, |
---|
133 | | - force ? "destroy" : "free_unused"); |
---|
134 | | - |
---|
135 | | - list_for_each_entry_safe(res, next, &rp->res_list, list) { |
---|
136 | | - if (!force && !(res->flags & DPU_CRTC_RES_FLAG_FREE)) |
---|
137 | | - continue; |
---|
138 | | - DPU_DEBUG("crtc%d.%u reclaim res:0x%x/0x%llx/%pK/%d\n", |
---|
139 | | - crtc->base.id, rp->sequence_id, |
---|
140 | | - res->type, res->tag, res->val, |
---|
141 | | - atomic_read(&res->refcount)); |
---|
142 | | - list_del(&res->list); |
---|
143 | | - if (res->ops.put) |
---|
144 | | - res->ops.put(res->val); |
---|
145 | | - kfree(res); |
---|
146 | | - } |
---|
147 | | -} |
---|
148 | | - |
---|
149 | | -/** |
---|
150 | | - * _dpu_crtc_rp_free_unused - free unused resource in pool |
---|
151 | | - * @rp: Pointer to resource pool |
---|
152 | | - * return: none |
---|
153 | | - */ |
---|
154 | | -static void _dpu_crtc_rp_free_unused(struct dpu_crtc_respool *rp) |
---|
155 | | -{ |
---|
156 | | - mutex_lock(rp->rp_lock); |
---|
157 | | - _dpu_crtc_rp_reclaim(rp, false); |
---|
158 | | - mutex_unlock(rp->rp_lock); |
---|
159 | | -} |
---|
160 | | - |
---|
161 | | -/** |
---|
162 | | - * _dpu_crtc_rp_destroy - destroy resource pool |
---|
163 | | - * @rp: Pointer to resource pool |
---|
164 | | - * return: None |
---|
165 | | - */ |
---|
166 | | -static void _dpu_crtc_rp_destroy(struct dpu_crtc_respool *rp) |
---|
167 | | -{ |
---|
168 | | - mutex_lock(rp->rp_lock); |
---|
169 | | - list_del_init(&rp->rp_list); |
---|
170 | | - _dpu_crtc_rp_reclaim(rp, true); |
---|
171 | | - mutex_unlock(rp->rp_lock); |
---|
172 | | -} |
---|
173 | | - |
---|
174 | | -/** |
---|
175 | | - * _dpu_crtc_hw_blk_get - get callback for hardware block |
---|
176 | | - * @val: Resource handle |
---|
177 | | - * @type: Resource type |
---|
178 | | - * @tag: Search tag for given resource |
---|
179 | | - * return: Resource handle |
---|
180 | | - */ |
---|
181 | | -static void *_dpu_crtc_hw_blk_get(void *val, u32 type, u64 tag) |
---|
182 | | -{ |
---|
183 | | - DPU_DEBUG("res:%d/0x%llx/%pK\n", type, tag, val); |
---|
184 | | - return dpu_hw_blk_get(val, type, tag); |
---|
185 | | -} |
---|
186 | | - |
---|
187 | | -/** |
---|
188 | | - * _dpu_crtc_hw_blk_put - put callback for hardware block |
---|
189 | | - * @val: Resource handle |
---|
190 | | - * return: None |
---|
191 | | - */ |
---|
192 | | -static void _dpu_crtc_hw_blk_put(void *val) |
---|
193 | | -{ |
---|
194 | | - DPU_DEBUG("res://%pK\n", val); |
---|
195 | | - dpu_hw_blk_put(val); |
---|
196 | | -} |
---|
197 | | - |
---|
198 | | -/** |
---|
199 | | - * _dpu_crtc_rp_duplicate - duplicate resource pool and reset reference count |
---|
200 | | - * @rp: Pointer to original resource pool |
---|
201 | | - * @dup_rp: Pointer to duplicated resource pool |
---|
202 | | - * return: None |
---|
203 | | - */ |
---|
204 | | -static void _dpu_crtc_rp_duplicate(struct dpu_crtc_respool *rp, |
---|
205 | | - struct dpu_crtc_respool *dup_rp) |
---|
206 | | -{ |
---|
207 | | - struct dpu_crtc_res *res, *dup_res; |
---|
208 | | - struct drm_crtc *crtc; |
---|
209 | | - |
---|
210 | | - if (!rp || !dup_rp || !rp->rp_head) { |
---|
211 | | - DPU_ERROR("invalid resource pool\n"); |
---|
212 | | - return; |
---|
213 | | - } |
---|
214 | | - |
---|
215 | | - crtc = _dpu_crtc_rp_to_crtc(rp); |
---|
216 | | - if (!crtc) { |
---|
217 | | - DPU_ERROR("invalid crtc\n"); |
---|
218 | | - return; |
---|
219 | | - } |
---|
220 | | - |
---|
221 | | - DPU_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id); |
---|
222 | | - |
---|
223 | | - mutex_lock(rp->rp_lock); |
---|
224 | | - dup_rp->sequence_id = rp->sequence_id + 1; |
---|
225 | | - INIT_LIST_HEAD(&dup_rp->res_list); |
---|
226 | | - dup_rp->ops = rp->ops; |
---|
227 | | - list_for_each_entry(res, &rp->res_list, list) { |
---|
228 | | - dup_res = kzalloc(sizeof(struct dpu_crtc_res), GFP_KERNEL); |
---|
229 | | - if (!dup_res) { |
---|
230 | | - mutex_unlock(rp->rp_lock); |
---|
231 | | - return; |
---|
232 | | - } |
---|
233 | | - INIT_LIST_HEAD(&dup_res->list); |
---|
234 | | - atomic_set(&dup_res->refcount, 0); |
---|
235 | | - dup_res->type = res->type; |
---|
236 | | - dup_res->tag = res->tag; |
---|
237 | | - dup_res->val = res->val; |
---|
238 | | - dup_res->ops = res->ops; |
---|
239 | | - dup_res->flags = DPU_CRTC_RES_FLAG_FREE; |
---|
240 | | - DPU_DEBUG("crtc%d.%u dup res:0x%x/0x%llx/%pK/%d\n", |
---|
241 | | - crtc->base.id, dup_rp->sequence_id, |
---|
242 | | - dup_res->type, dup_res->tag, dup_res->val, |
---|
243 | | - atomic_read(&dup_res->refcount)); |
---|
244 | | - list_add_tail(&dup_res->list, &dup_rp->res_list); |
---|
245 | | - if (dup_res->ops.get) |
---|
246 | | - dup_res->ops.get(dup_res->val, 0, -1); |
---|
247 | | - } |
---|
248 | | - |
---|
249 | | - dup_rp->rp_lock = rp->rp_lock; |
---|
250 | | - dup_rp->rp_head = rp->rp_head; |
---|
251 | | - INIT_LIST_HEAD(&dup_rp->rp_list); |
---|
252 | | - list_add_tail(&dup_rp->rp_list, rp->rp_head); |
---|
253 | | - mutex_unlock(rp->rp_lock); |
---|
254 | | -} |
---|
255 | | - |
---|
256 | | -/** |
---|
257 | | - * _dpu_crtc_rp_reset - reset resource pool after allocation |
---|
258 | | - * @rp: Pointer to original resource pool |
---|
259 | | - * @rp_lock: Pointer to serialization resource pool lock |
---|
260 | | - * @rp_head: Pointer to crtc resource pool head |
---|
261 | | - * return: None |
---|
262 | | - */ |
---|
263 | | -static void _dpu_crtc_rp_reset(struct dpu_crtc_respool *rp, |
---|
264 | | - struct mutex *rp_lock, struct list_head *rp_head) |
---|
265 | | -{ |
---|
266 | | - if (!rp || !rp_lock || !rp_head) { |
---|
267 | | - DPU_ERROR("invalid resource pool\n"); |
---|
268 | | - return; |
---|
269 | | - } |
---|
270 | | - |
---|
271 | | - mutex_lock(rp_lock); |
---|
272 | | - rp->rp_lock = rp_lock; |
---|
273 | | - rp->rp_head = rp_head; |
---|
274 | | - INIT_LIST_HEAD(&rp->rp_list); |
---|
275 | | - rp->sequence_id = 0; |
---|
276 | | - INIT_LIST_HEAD(&rp->res_list); |
---|
277 | | - rp->ops.get = _dpu_crtc_hw_blk_get; |
---|
278 | | - rp->ops.put = _dpu_crtc_hw_blk_put; |
---|
279 | | - list_add_tail(&rp->rp_list, rp->rp_head); |
---|
280 | | - mutex_unlock(rp_lock); |
---|
281 | 53 | } |
---|
282 | 54 | |
---|
283 | 55 | static void dpu_crtc_destroy(struct drm_crtc *crtc) |
---|
.. | .. |
---|
289 | 61 | if (!crtc) |
---|
290 | 62 | return; |
---|
291 | 63 | |
---|
292 | | - dpu_crtc->phandle = NULL; |
---|
293 | | - |
---|
294 | 64 | drm_crtc_cleanup(crtc); |
---|
295 | | - mutex_destroy(&dpu_crtc->crtc_lock); |
---|
296 | 65 | kfree(dpu_crtc); |
---|
297 | 66 | } |
---|
298 | 67 | |
---|
299 | 68 | static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, |
---|
300 | | - struct dpu_plane_state *pstate) |
---|
| 69 | + struct dpu_plane_state *pstate, struct dpu_format *format) |
---|
301 | 70 | { |
---|
302 | 71 | struct dpu_hw_mixer *lm = mixer->hw_lm; |
---|
| 72 | + uint32_t blend_op; |
---|
| 73 | + struct drm_format_name_buf format_name; |
---|
303 | 74 | |
---|
304 | 75 | /* default to opaque blending */ |
---|
305 | | - lm->ops.setup_blend_config(lm, pstate->stage, 0XFF, 0, |
---|
306 | | - DPU_BLEND_FG_ALPHA_FG_CONST | |
---|
307 | | - DPU_BLEND_BG_ALPHA_BG_CONST); |
---|
| 76 | + blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | |
---|
| 77 | + DPU_BLEND_BG_ALPHA_BG_CONST; |
---|
| 78 | + |
---|
| 79 | + if (format->alpha_enable) { |
---|
| 80 | + /* coverage blending */ |
---|
| 81 | + blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | |
---|
| 82 | + DPU_BLEND_BG_ALPHA_FG_PIXEL | |
---|
| 83 | + DPU_BLEND_BG_INV_ALPHA; |
---|
| 84 | + } |
---|
| 85 | + |
---|
| 86 | + lm->ops.setup_blend_config(lm, pstate->stage, |
---|
| 87 | + 0xFF, 0, blend_op); |
---|
| 88 | + |
---|
| 89 | + DPU_DEBUG("format:%s, alpha_en:%u blend_op:0x%x\n", |
---|
| 90 | + drm_get_format_name(format->base.pixel_format, &format_name), |
---|
| 91 | + format->alpha_enable, blend_op); |
---|
308 | 92 | } |
---|
309 | 93 | |
---|
310 | 94 | static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) |
---|
311 | 95 | { |
---|
312 | | - struct dpu_crtc *dpu_crtc; |
---|
313 | 96 | struct dpu_crtc_state *crtc_state; |
---|
314 | 97 | int lm_idx, lm_horiz_position; |
---|
315 | 98 | |
---|
316 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
317 | 99 | crtc_state = to_dpu_crtc_state(crtc->state); |
---|
318 | 100 | |
---|
319 | 101 | lm_horiz_position = 0; |
---|
320 | | - for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { |
---|
| 102 | + for (lm_idx = 0; lm_idx < crtc_state->num_mixers; lm_idx++) { |
---|
321 | 103 | const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx]; |
---|
322 | | - struct dpu_hw_mixer *hw_lm = dpu_crtc->mixers[lm_idx].hw_lm; |
---|
| 104 | + struct dpu_hw_mixer *hw_lm = crtc_state->mixers[lm_idx].hw_lm; |
---|
323 | 105 | struct dpu_hw_mixer_cfg cfg; |
---|
324 | 106 | |
---|
325 | 107 | if (!lm_roi || !drm_rect_visible(lm_roi)) |
---|
.. | .. |
---|
339 | 121 | struct drm_plane *plane; |
---|
340 | 122 | struct drm_framebuffer *fb; |
---|
341 | 123 | struct drm_plane_state *state; |
---|
342 | | - struct dpu_crtc_state *cstate; |
---|
| 124 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
343 | 125 | struct dpu_plane_state *pstate = NULL; |
---|
344 | 126 | struct dpu_format *format; |
---|
345 | | - struct dpu_hw_ctl *ctl; |
---|
346 | | - struct dpu_hw_mixer *lm; |
---|
347 | | - struct dpu_hw_stage_cfg *stage_cfg; |
---|
| 127 | + struct dpu_hw_ctl *ctl = mixer->lm_ctl; |
---|
| 128 | + struct dpu_hw_stage_cfg *stage_cfg = &dpu_crtc->stage_cfg; |
---|
348 | 129 | |
---|
349 | 130 | u32 flush_mask; |
---|
350 | 131 | uint32_t stage_idx, lm_idx; |
---|
351 | 132 | int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; |
---|
352 | 133 | bool bg_alpha_enable = false; |
---|
353 | | - |
---|
354 | | - if (!dpu_crtc || !mixer) { |
---|
355 | | - DPU_ERROR("invalid dpu_crtc or mixer\n"); |
---|
356 | | - return; |
---|
357 | | - } |
---|
358 | | - |
---|
359 | | - ctl = mixer->hw_ctl; |
---|
360 | | - lm = mixer->hw_lm; |
---|
361 | | - stage_cfg = &dpu_crtc->stage_cfg; |
---|
362 | | - cstate = to_dpu_crtc_state(crtc->state); |
---|
363 | 134 | |
---|
364 | 135 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
---|
365 | 136 | state = plane->state; |
---|
.. | .. |
---|
379 | 150 | state->fb ? state->fb->base.id : -1); |
---|
380 | 151 | |
---|
381 | 152 | format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); |
---|
382 | | - if (!format) { |
---|
383 | | - DPU_ERROR("invalid format\n"); |
---|
384 | | - return; |
---|
385 | | - } |
---|
386 | 153 | |
---|
387 | 154 | if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) |
---|
388 | 155 | bg_alpha_enable = true; |
---|
.. | .. |
---|
400 | 167 | fb ? fb->modifier : 0); |
---|
401 | 168 | |
---|
402 | 169 | /* blend config update */ |
---|
403 | | - for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { |
---|
404 | | - _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate); |
---|
| 170 | + for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) { |
---|
| 171 | + _dpu_crtc_setup_blend_cfg(mixer + lm_idx, |
---|
| 172 | + pstate, format); |
---|
405 | 173 | |
---|
406 | 174 | mixer[lm_idx].flush_mask |= flush_mask; |
---|
407 | 175 | |
---|
.. | .. |
---|
422 | 190 | */ |
---|
423 | 191 | static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) |
---|
424 | 192 | { |
---|
425 | | - struct dpu_crtc *dpu_crtc; |
---|
426 | | - struct dpu_crtc_state *dpu_crtc_state; |
---|
427 | | - struct dpu_crtc_mixer *mixer; |
---|
| 193 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 194 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
| 195 | + struct dpu_crtc_mixer *mixer = cstate->mixers; |
---|
428 | 196 | struct dpu_hw_ctl *ctl; |
---|
429 | 197 | struct dpu_hw_mixer *lm; |
---|
430 | | - |
---|
431 | 198 | int i; |
---|
432 | | - |
---|
433 | | - if (!crtc) |
---|
434 | | - return; |
---|
435 | | - |
---|
436 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
437 | | - dpu_crtc_state = to_dpu_crtc_state(crtc->state); |
---|
438 | | - mixer = dpu_crtc->mixers; |
---|
439 | 199 | |
---|
440 | 200 | DPU_DEBUG("%s\n", dpu_crtc->name); |
---|
441 | 201 | |
---|
442 | | - if (dpu_crtc->num_mixers > CRTC_DUAL_MIXERS) { |
---|
443 | | - DPU_ERROR("invalid number mixers: %d\n", dpu_crtc->num_mixers); |
---|
444 | | - return; |
---|
445 | | - } |
---|
446 | | - |
---|
447 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
---|
448 | | - if (!mixer[i].hw_lm || !mixer[i].hw_ctl) { |
---|
449 | | - DPU_ERROR("invalid lm or ctl assigned to mixer\n"); |
---|
450 | | - return; |
---|
451 | | - } |
---|
| 202 | + for (i = 0; i < cstate->num_mixers; i++) { |
---|
452 | 203 | mixer[i].mixer_op_mode = 0; |
---|
453 | 204 | mixer[i].flush_mask = 0; |
---|
454 | | - if (mixer[i].hw_ctl->ops.clear_all_blendstages) |
---|
455 | | - mixer[i].hw_ctl->ops.clear_all_blendstages( |
---|
456 | | - mixer[i].hw_ctl); |
---|
| 205 | + if (mixer[i].lm_ctl->ops.clear_all_blendstages) |
---|
| 206 | + mixer[i].lm_ctl->ops.clear_all_blendstages( |
---|
| 207 | + mixer[i].lm_ctl); |
---|
457 | 208 | } |
---|
458 | 209 | |
---|
459 | 210 | /* initialize stage cfg */ |
---|
.. | .. |
---|
461 | 212 | |
---|
462 | 213 | _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer); |
---|
463 | 214 | |
---|
464 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
---|
465 | | - ctl = mixer[i].hw_ctl; |
---|
| 215 | + for (i = 0; i < cstate->num_mixers; i++) { |
---|
| 216 | + ctl = mixer[i].lm_ctl; |
---|
466 | 217 | lm = mixer[i].hw_lm; |
---|
467 | 218 | |
---|
468 | 219 | lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); |
---|
.. | .. |
---|
514 | 265 | { |
---|
515 | 266 | struct drm_encoder *encoder; |
---|
516 | 267 | |
---|
517 | | - if (!crtc || !crtc->dev) { |
---|
518 | | - DPU_ERROR("invalid crtc\n"); |
---|
519 | | - return INTF_MODE_NONE; |
---|
520 | | - } |
---|
| 268 | + /* |
---|
| 269 | + * TODO: This function is called from dpu debugfs and as part of atomic |
---|
| 270 | + * check. When called from debugfs, the crtc->mutex must be held to |
---|
| 271 | + * read crtc->state. However reading crtc->state from atomic check isn't |
---|
| 272 | + * allowed (unless you have a good reason, a big comment, and a deep |
---|
| 273 | + * understanding of how the atomic/modeset locks work (<- and this is |
---|
| 274 | + * probably not possible)). So we'll keep the WARN_ON here for now, but |
---|
| 275 | + * really we need to figure out a better way to track our operating mode |
---|
| 276 | + */ |
---|
| 277 | + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); |
---|
521 | 278 | |
---|
522 | | - drm_for_each_encoder(encoder, crtc->dev) |
---|
523 | | - if (encoder->crtc == crtc) |
---|
524 | | - return dpu_encoder_get_intf_mode(encoder); |
---|
| 279 | + /* TODO: Returns the first INTF_MODE, could there be multiple values? */ |
---|
| 280 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
---|
| 281 | + return dpu_encoder_get_intf_mode(encoder); |
---|
525 | 282 | |
---|
526 | 283 | return INTF_MODE_NONE; |
---|
527 | 284 | } |
---|
528 | 285 | |
---|
529 | | -static void dpu_crtc_vblank_cb(void *data) |
---|
| 286 | +void dpu_crtc_vblank_callback(struct drm_crtc *crtc) |
---|
530 | 287 | { |
---|
531 | | - struct drm_crtc *crtc = (struct drm_crtc *)data; |
---|
532 | 288 | struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
533 | 289 | |
---|
534 | 290 | /* keep statistics on vblank callback - with auto reset via debugfs */ |
---|
.. | .. |
---|
536 | 292 | dpu_crtc->vblank_cb_time = ktime_get(); |
---|
537 | 293 | else |
---|
538 | 294 | dpu_crtc->vblank_cb_count++; |
---|
539 | | - _dpu_crtc_complete_flip(crtc); |
---|
540 | 295 | drm_crtc_handle_vblank(crtc); |
---|
541 | 296 | trace_dpu_crtc_vblank_cb(DRMID(crtc)); |
---|
542 | 297 | } |
---|
543 | 298 | |
---|
544 | 299 | static void dpu_crtc_frame_event_work(struct kthread_work *work) |
---|
545 | 300 | { |
---|
546 | | - struct msm_drm_private *priv; |
---|
547 | | - struct dpu_crtc_frame_event *fevent; |
---|
548 | | - struct drm_crtc *crtc; |
---|
549 | | - struct dpu_crtc *dpu_crtc; |
---|
550 | | - struct dpu_kms *dpu_kms; |
---|
| 301 | + struct dpu_crtc_frame_event *fevent = container_of(work, |
---|
| 302 | + struct dpu_crtc_frame_event, work); |
---|
| 303 | + struct drm_crtc *crtc = fevent->crtc; |
---|
| 304 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
551 | 305 | unsigned long flags; |
---|
552 | 306 | bool frame_done = false; |
---|
553 | 307 | |
---|
554 | | - if (!work) { |
---|
555 | | - DPU_ERROR("invalid work handle\n"); |
---|
556 | | - return; |
---|
557 | | - } |
---|
558 | | - |
---|
559 | | - fevent = container_of(work, struct dpu_crtc_frame_event, work); |
---|
560 | | - if (!fevent->crtc || !fevent->crtc->state) { |
---|
561 | | - DPU_ERROR("invalid crtc\n"); |
---|
562 | | - return; |
---|
563 | | - } |
---|
564 | | - |
---|
565 | | - crtc = fevent->crtc; |
---|
566 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
567 | | - |
---|
568 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
---|
569 | | - if (!dpu_kms) { |
---|
570 | | - DPU_ERROR("invalid kms handle\n"); |
---|
571 | | - return; |
---|
572 | | - } |
---|
573 | | - priv = dpu_kms->dev->dev_private; |
---|
574 | 308 | DPU_ATRACE_BEGIN("crtc_frame_event"); |
---|
575 | 309 | |
---|
576 | 310 | DRM_DEBUG_KMS("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, |
---|
.. | .. |
---|
581 | 315 | | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { |
---|
582 | 316 | |
---|
583 | 317 | if (atomic_read(&dpu_crtc->frame_pending) < 1) { |
---|
584 | | - /* this should not happen */ |
---|
585 | | - DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n", |
---|
586 | | - crtc->base.id, |
---|
587 | | - fevent->event, |
---|
588 | | - ktime_to_ns(fevent->ts), |
---|
589 | | - atomic_read(&dpu_crtc->frame_pending)); |
---|
| 318 | + /* ignore vblank when not pending */ |
---|
590 | 319 | } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { |
---|
591 | 320 | /* release bandwidth and other resources */ |
---|
592 | 321 | trace_dpu_crtc_frame_event_done(DRMID(crtc), |
---|
.. | .. |
---|
636 | 365 | unsigned long flags; |
---|
637 | 366 | u32 crtc_id; |
---|
638 | 367 | |
---|
639 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
---|
640 | | - DPU_ERROR("invalid parameters\n"); |
---|
641 | | - return; |
---|
642 | | - } |
---|
643 | | - |
---|
644 | 368 | /* Nothing to do on idle event */ |
---|
645 | 369 | if (event & DPU_ENCODER_FRAME_EVENT_IDLE) |
---|
646 | 370 | return; |
---|
.. | .. |
---|
666 | 390 | fevent->event = event; |
---|
667 | 391 | fevent->crtc = crtc; |
---|
668 | 392 | fevent->ts = ktime_get(); |
---|
669 | | - kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); |
---|
| 393 | + kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); |
---|
670 | 394 | } |
---|
671 | 395 | |
---|
672 | | -void dpu_crtc_complete_commit(struct drm_crtc *crtc, |
---|
673 | | - struct drm_crtc_state *old_state) |
---|
| 396 | +void dpu_crtc_complete_commit(struct drm_crtc *crtc) |
---|
674 | 397 | { |
---|
675 | | - if (!crtc || !crtc->state) { |
---|
676 | | - DPU_ERROR("invalid crtc\n"); |
---|
677 | | - return; |
---|
678 | | - } |
---|
679 | 398 | trace_dpu_crtc_complete_commit(DRMID(crtc)); |
---|
680 | | -} |
---|
681 | | - |
---|
682 | | -static void _dpu_crtc_setup_mixer_for_encoder( |
---|
683 | | - struct drm_crtc *crtc, |
---|
684 | | - struct drm_encoder *enc) |
---|
685 | | -{ |
---|
686 | | - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
687 | | - struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); |
---|
688 | | - struct dpu_rm *rm = &dpu_kms->rm; |
---|
689 | | - struct dpu_crtc_mixer *mixer; |
---|
690 | | - struct dpu_hw_ctl *last_valid_ctl = NULL; |
---|
691 | | - int i; |
---|
692 | | - struct dpu_rm_hw_iter lm_iter, ctl_iter; |
---|
693 | | - |
---|
694 | | - dpu_rm_init_hw_iter(&lm_iter, enc->base.id, DPU_HW_BLK_LM); |
---|
695 | | - dpu_rm_init_hw_iter(&ctl_iter, enc->base.id, DPU_HW_BLK_CTL); |
---|
696 | | - |
---|
697 | | - /* Set up all the mixers and ctls reserved by this encoder */ |
---|
698 | | - for (i = dpu_crtc->num_mixers; i < ARRAY_SIZE(dpu_crtc->mixers); i++) { |
---|
699 | | - mixer = &dpu_crtc->mixers[i]; |
---|
700 | | - |
---|
701 | | - if (!dpu_rm_get_hw(rm, &lm_iter)) |
---|
702 | | - break; |
---|
703 | | - mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; |
---|
704 | | - |
---|
705 | | - /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ |
---|
706 | | - if (!dpu_rm_get_hw(rm, &ctl_iter)) { |
---|
707 | | - DPU_DEBUG("no ctl assigned to lm %d, using previous\n", |
---|
708 | | - mixer->hw_lm->idx - LM_0); |
---|
709 | | - mixer->hw_ctl = last_valid_ctl; |
---|
710 | | - } else { |
---|
711 | | - mixer->hw_ctl = (struct dpu_hw_ctl *)ctl_iter.hw; |
---|
712 | | - last_valid_ctl = mixer->hw_ctl; |
---|
713 | | - } |
---|
714 | | - |
---|
715 | | - /* Shouldn't happen, mixers are always >= ctls */ |
---|
716 | | - if (!mixer->hw_ctl) { |
---|
717 | | - DPU_ERROR("no valid ctls found for lm %d\n", |
---|
718 | | - mixer->hw_lm->idx - LM_0); |
---|
719 | | - return; |
---|
720 | | - } |
---|
721 | | - |
---|
722 | | - mixer->encoder = enc; |
---|
723 | | - |
---|
724 | | - dpu_crtc->num_mixers++; |
---|
725 | | - DPU_DEBUG("setup mixer %d: lm %d\n", |
---|
726 | | - i, mixer->hw_lm->idx - LM_0); |
---|
727 | | - DPU_DEBUG("setup mixer %d: ctl %d\n", |
---|
728 | | - i, mixer->hw_ctl->idx - CTL_0); |
---|
729 | | - } |
---|
730 | | -} |
---|
731 | | - |
---|
732 | | -static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) |
---|
733 | | -{ |
---|
734 | | - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
735 | | - struct drm_encoder *enc; |
---|
736 | | - |
---|
737 | | - dpu_crtc->num_mixers = 0; |
---|
738 | | - dpu_crtc->mixers_swapped = false; |
---|
739 | | - memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); |
---|
740 | | - |
---|
741 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
742 | | - /* Check for mixers on all encoders attached to this crtc */ |
---|
743 | | - list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { |
---|
744 | | - if (enc->crtc != crtc) |
---|
745 | | - continue; |
---|
746 | | - |
---|
747 | | - _dpu_crtc_setup_mixer_for_encoder(crtc, enc); |
---|
748 | | - } |
---|
749 | | - |
---|
750 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
| 399 | + _dpu_crtc_complete_flip(crtc); |
---|
751 | 400 | } |
---|
752 | 401 | |
---|
753 | 402 | static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, |
---|
754 | 403 | struct drm_crtc_state *state) |
---|
755 | 404 | { |
---|
756 | | - struct dpu_crtc *dpu_crtc; |
---|
757 | | - struct dpu_crtc_state *cstate; |
---|
758 | | - struct drm_display_mode *adj_mode; |
---|
759 | | - u32 crtc_split_width; |
---|
| 405 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
---|
| 406 | + struct drm_display_mode *adj_mode = &state->adjusted_mode; |
---|
| 407 | + u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers; |
---|
760 | 408 | int i; |
---|
761 | 409 | |
---|
762 | | - if (!crtc || !state) { |
---|
763 | | - DPU_ERROR("invalid args\n"); |
---|
764 | | - return; |
---|
765 | | - } |
---|
766 | | - |
---|
767 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
768 | | - cstate = to_dpu_crtc_state(state); |
---|
769 | | - |
---|
770 | | - adj_mode = &state->adjusted_mode; |
---|
771 | | - crtc_split_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, adj_mode); |
---|
772 | | - |
---|
773 | | - for (i = 0; i < dpu_crtc->num_mixers; i++) { |
---|
| 410 | + for (i = 0; i < cstate->num_mixers; i++) { |
---|
774 | 411 | struct drm_rect *r = &cstate->lm_bounds[i]; |
---|
775 | 412 | r->x1 = crtc_split_width * i; |
---|
776 | 413 | r->y1 = 0; |
---|
777 | 414 | r->x2 = r->x1 + crtc_split_width; |
---|
778 | | - r->y2 = dpu_crtc_get_mixer_height(dpu_crtc, cstate, adj_mode); |
---|
| 415 | + r->y2 = adj_mode->vdisplay; |
---|
779 | 416 | |
---|
780 | 417 | trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); |
---|
781 | 418 | } |
---|
| 419 | +} |
---|
782 | 420 | |
---|
783 | | - drm_mode_debug_printmodeline(adj_mode); |
---|
| 421 | +static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, |
---|
| 422 | + struct dpu_hw_pcc_cfg *cfg) |
---|
| 423 | +{ |
---|
| 424 | + struct drm_color_ctm *ctm; |
---|
| 425 | + |
---|
| 426 | + memset(cfg, 0, sizeof(struct dpu_hw_pcc_cfg)); |
---|
| 427 | + |
---|
| 428 | + ctm = (struct drm_color_ctm *)state->ctm->data; |
---|
| 429 | + |
---|
| 430 | + if (!ctm) |
---|
| 431 | + return; |
---|
| 432 | + |
---|
| 433 | + cfg->r.r = CONVERT_S3_15(ctm->matrix[0]); |
---|
| 434 | + cfg->g.r = CONVERT_S3_15(ctm->matrix[1]); |
---|
| 435 | + cfg->b.r = CONVERT_S3_15(ctm->matrix[2]); |
---|
| 436 | + |
---|
| 437 | + cfg->r.g = CONVERT_S3_15(ctm->matrix[3]); |
---|
| 438 | + cfg->g.g = CONVERT_S3_15(ctm->matrix[4]); |
---|
| 439 | + cfg->b.g = CONVERT_S3_15(ctm->matrix[5]); |
---|
| 440 | + |
---|
| 441 | + cfg->r.b = CONVERT_S3_15(ctm->matrix[6]); |
---|
| 442 | + cfg->g.b = CONVERT_S3_15(ctm->matrix[7]); |
---|
| 443 | + cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); |
---|
| 444 | +} |
---|
| 445 | + |
---|
| 446 | +static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) |
---|
| 447 | +{ |
---|
| 448 | + struct drm_crtc_state *state = crtc->state; |
---|
| 449 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
| 450 | + struct dpu_crtc_mixer *mixer = cstate->mixers; |
---|
| 451 | + struct dpu_hw_pcc_cfg cfg; |
---|
| 452 | + struct dpu_hw_ctl *ctl; |
---|
| 453 | + struct dpu_hw_dspp *dspp; |
---|
| 454 | + int i; |
---|
| 455 | + |
---|
| 456 | + |
---|
| 457 | + if (!state->color_mgmt_changed) |
---|
| 458 | + return; |
---|
| 459 | + |
---|
| 460 | + for (i = 0; i < cstate->num_mixers; i++) { |
---|
| 461 | + ctl = mixer[i].lm_ctl; |
---|
| 462 | + dspp = mixer[i].hw_dspp; |
---|
| 463 | + |
---|
| 464 | + if (!dspp || !dspp->ops.setup_pcc) |
---|
| 465 | + continue; |
---|
| 466 | + |
---|
| 467 | + if (!state->ctm) { |
---|
| 468 | + dspp->ops.setup_pcc(dspp, NULL); |
---|
| 469 | + } else { |
---|
| 470 | + _dpu_crtc_get_pcc_coeff(state, &cfg); |
---|
| 471 | + dspp->ops.setup_pcc(dspp, &cfg); |
---|
| 472 | + } |
---|
| 473 | + |
---|
| 474 | + mixer[i].flush_mask |= ctl->ops.get_bitmask_dspp(ctl, |
---|
| 475 | + mixer[i].hw_dspp->idx); |
---|
| 476 | + |
---|
| 477 | + /* stage config flush mask */ |
---|
| 478 | + ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); |
---|
| 479 | + |
---|
| 480 | + DPU_DEBUG("lm %d, ctl %d, flush mask 0x%x\n", |
---|
| 481 | + mixer[i].hw_lm->idx - DSPP_0, |
---|
| 482 | + ctl->idx - CTL_0, |
---|
| 483 | + mixer[i].flush_mask); |
---|
| 484 | + } |
---|
784 | 485 | } |
---|
785 | 486 | |
---|
786 | 487 | static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, |
---|
787 | 488 | struct drm_crtc_state *old_state) |
---|
788 | 489 | { |
---|
789 | | - struct dpu_crtc *dpu_crtc; |
---|
| 490 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
790 | 491 | struct drm_encoder *encoder; |
---|
791 | | - struct drm_device *dev; |
---|
792 | | - unsigned long flags; |
---|
793 | | - struct dpu_crtc_smmu_state_data *smmu_state; |
---|
794 | | - |
---|
795 | | - if (!crtc) { |
---|
796 | | - DPU_ERROR("invalid crtc\n"); |
---|
797 | | - return; |
---|
798 | | - } |
---|
799 | 492 | |
---|
800 | 493 | if (!crtc->state->enable) { |
---|
801 | 494 | DPU_DEBUG("crtc%d -> enable %d, skip atomic_begin\n", |
---|
.. | .. |
---|
805 | 498 | |
---|
806 | 499 | DPU_DEBUG("crtc%d\n", crtc->base.id); |
---|
807 | 500 | |
---|
808 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
809 | | - dev = crtc->dev; |
---|
810 | | - smmu_state = &dpu_crtc->smmu_state; |
---|
| 501 | + _dpu_crtc_setup_lm_bounds(crtc, crtc->state); |
---|
811 | 502 | |
---|
812 | | - if (!dpu_crtc->num_mixers) { |
---|
813 | | - _dpu_crtc_setup_mixers(crtc); |
---|
814 | | - _dpu_crtc_setup_lm_bounds(crtc, crtc->state); |
---|
815 | | - } |
---|
816 | | - |
---|
817 | | - if (dpu_crtc->event) { |
---|
818 | | - WARN_ON(dpu_crtc->event); |
---|
819 | | - } else { |
---|
820 | | - spin_lock_irqsave(&dev->event_lock, flags); |
---|
821 | | - dpu_crtc->event = crtc->state->event; |
---|
822 | | - crtc->state->event = NULL; |
---|
823 | | - spin_unlock_irqrestore(&dev->event_lock, flags); |
---|
824 | | - } |
---|
825 | | - |
---|
826 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
---|
827 | | - if (encoder->crtc != crtc) |
---|
828 | | - continue; |
---|
829 | | - |
---|
830 | | - /* encoder will trigger pending mask now */ |
---|
| 503 | + /* encoder will trigger pending mask now */ |
---|
| 504 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
---|
831 | 505 | dpu_encoder_trigger_kickoff_pending(encoder); |
---|
832 | | - } |
---|
833 | 506 | |
---|
834 | 507 | /* |
---|
835 | 508 | * If no mixers have been allocated in dpu_crtc_atomic_check(), |
---|
836 | 509 | * it means we are trying to flush a CRTC whose state is disabled: |
---|
837 | 510 | * nothing else needs to be done. |
---|
838 | 511 | */ |
---|
839 | | - if (unlikely(!dpu_crtc->num_mixers)) |
---|
| 512 | + if (unlikely(!cstate->num_mixers)) |
---|
840 | 513 | return; |
---|
841 | 514 | |
---|
842 | 515 | _dpu_crtc_blend_setup(crtc); |
---|
| 516 | + |
---|
| 517 | + _dpu_crtc_setup_cp_blocks(crtc); |
---|
843 | 518 | |
---|
844 | 519 | /* |
---|
845 | 520 | * PP_DONE irq is only used by command mode for now. |
---|
.. | .. |
---|
857 | 532 | struct drm_device *dev; |
---|
858 | 533 | struct drm_plane *plane; |
---|
859 | 534 | struct msm_drm_private *priv; |
---|
860 | | - struct msm_drm_thread *event_thread; |
---|
861 | 535 | unsigned long flags; |
---|
862 | 536 | struct dpu_crtc_state *cstate; |
---|
863 | | - |
---|
864 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
---|
865 | | - DPU_ERROR("invalid crtc\n"); |
---|
866 | | - return; |
---|
867 | | - } |
---|
868 | 537 | |
---|
869 | 538 | if (!crtc->state->enable) { |
---|
870 | 539 | DPU_DEBUG("crtc%d -> enable %d, skip atomic_flush\n", |
---|
.. | .. |
---|
884 | 553 | return; |
---|
885 | 554 | } |
---|
886 | 555 | |
---|
887 | | - event_thread = &priv->event_thread[crtc->index]; |
---|
888 | | - |
---|
889 | | - if (dpu_crtc->event) { |
---|
890 | | - DPU_DEBUG("already received dpu_crtc->event\n"); |
---|
891 | | - } else { |
---|
892 | | - spin_lock_irqsave(&dev->event_lock, flags); |
---|
893 | | - dpu_crtc->event = crtc->state->event; |
---|
894 | | - crtc->state->event = NULL; |
---|
895 | | - spin_unlock_irqrestore(&dev->event_lock, flags); |
---|
896 | | - } |
---|
| 556 | + WARN_ON(dpu_crtc->event); |
---|
| 557 | + spin_lock_irqsave(&dev->event_lock, flags); |
---|
| 558 | + dpu_crtc->event = crtc->state->event; |
---|
| 559 | + crtc->state->event = NULL; |
---|
| 560 | + spin_unlock_irqrestore(&dev->event_lock, flags); |
---|
897 | 561 | |
---|
898 | 562 | /* |
---|
899 | 563 | * If no mixers has been allocated in dpu_crtc_atomic_check(), |
---|
900 | 564 | * it means we are trying to flush a CRTC whose state is disabled: |
---|
901 | 565 | * nothing else needs to be done. |
---|
902 | 566 | */ |
---|
903 | | - if (unlikely(!dpu_crtc->num_mixers)) |
---|
| 567 | + if (unlikely(!cstate->num_mixers)) |
---|
904 | 568 | return; |
---|
905 | 569 | |
---|
906 | 570 | /* |
---|
.. | .. |
---|
938 | 602 | static void dpu_crtc_destroy_state(struct drm_crtc *crtc, |
---|
939 | 603 | struct drm_crtc_state *state) |
---|
940 | 604 | { |
---|
941 | | - struct dpu_crtc *dpu_crtc; |
---|
942 | | - struct dpu_crtc_state *cstate; |
---|
943 | | - |
---|
944 | | - if (!crtc || !state) { |
---|
945 | | - DPU_ERROR("invalid argument(s)\n"); |
---|
946 | | - return; |
---|
947 | | - } |
---|
948 | | - |
---|
949 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
950 | | - cstate = to_dpu_crtc_state(state); |
---|
| 605 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
---|
951 | 606 | |
---|
952 | 607 | DPU_DEBUG("crtc%d\n", crtc->base.id); |
---|
953 | | - |
---|
954 | | - _dpu_crtc_rp_destroy(&cstate->rp); |
---|
955 | 608 | |
---|
956 | 609 | __drm_atomic_helper_crtc_destroy_state(state); |
---|
957 | 610 | |
---|
.. | .. |
---|
960 | 613 | |
---|
961 | 614 | static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) |
---|
962 | 615 | { |
---|
963 | | - struct dpu_crtc *dpu_crtc; |
---|
| 616 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
964 | 617 | int ret, rc = 0; |
---|
965 | | - |
---|
966 | | - if (!crtc) { |
---|
967 | | - DPU_ERROR("invalid argument\n"); |
---|
968 | | - return -EINVAL; |
---|
969 | | - } |
---|
970 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
971 | 618 | |
---|
972 | 619 | if (!atomic_read(&dpu_crtc->frame_pending)) { |
---|
973 | 620 | DPU_DEBUG("no frames pending\n"); |
---|
.. | .. |
---|
976 | 623 | |
---|
977 | 624 | DPU_ATRACE_BEGIN("frame done completion wait"); |
---|
978 | 625 | ret = wait_for_completion_timeout(&dpu_crtc->frame_done_comp, |
---|
979 | | - msecs_to_jiffies(DPU_FRAME_DONE_TIMEOUT)); |
---|
| 626 | + msecs_to_jiffies(DPU_CRTC_FRAME_DONE_TIMEOUT_MS)); |
---|
980 | 627 | if (!ret) { |
---|
981 | 628 | DRM_ERROR("frame done wait timed out, ret:%d\n", ret); |
---|
982 | 629 | rc = -ETIMEDOUT; |
---|
.. | .. |
---|
989 | 636 | void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) |
---|
990 | 637 | { |
---|
991 | 638 | struct drm_encoder *encoder; |
---|
992 | | - struct drm_device *dev; |
---|
993 | | - struct dpu_crtc *dpu_crtc; |
---|
994 | | - struct msm_drm_private *priv; |
---|
995 | | - struct dpu_kms *dpu_kms; |
---|
996 | | - struct dpu_crtc_state *cstate; |
---|
997 | | - int ret; |
---|
998 | | - |
---|
999 | | - if (!crtc) { |
---|
1000 | | - DPU_ERROR("invalid argument\n"); |
---|
1001 | | - return; |
---|
1002 | | - } |
---|
1003 | | - dev = crtc->dev; |
---|
1004 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1005 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
---|
1006 | | - |
---|
1007 | | - if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev_private) { |
---|
1008 | | - DPU_ERROR("invalid argument\n"); |
---|
1009 | | - return; |
---|
1010 | | - } |
---|
1011 | | - |
---|
1012 | | - priv = dpu_kms->dev->dev_private; |
---|
1013 | | - cstate = to_dpu_crtc_state(crtc->state); |
---|
| 639 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 640 | + struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); |
---|
| 641 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
1014 | 642 | |
---|
1015 | 643 | /* |
---|
1016 | 644 | * If no mixers has been allocated in dpu_crtc_atomic_check(), |
---|
1017 | 645 | * it means we are trying to start a CRTC whose state is disabled: |
---|
1018 | 646 | * nothing else needs to be done. |
---|
1019 | 647 | */ |
---|
1020 | | - if (unlikely(!dpu_crtc->num_mixers)) |
---|
| 648 | + if (unlikely(!cstate->num_mixers)) |
---|
1021 | 649 | return; |
---|
1022 | 650 | |
---|
1023 | 651 | DPU_ATRACE_BEGIN("crtc_commit"); |
---|
1024 | 652 | |
---|
1025 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
---|
1026 | | - struct dpu_encoder_kickoff_params params = { 0 }; |
---|
1027 | | - |
---|
1028 | | - if (encoder->crtc != crtc) |
---|
1029 | | - continue; |
---|
1030 | | - |
---|
1031 | | - /* |
---|
1032 | | - * Encoder will flush/start now, unless it has a tx pending. |
---|
1033 | | - * If so, it may delay and flush at an irq event (e.g. ppdone) |
---|
1034 | | - */ |
---|
1035 | | - dpu_encoder_prepare_for_kickoff(encoder, ¶ms); |
---|
1036 | | - } |
---|
1037 | | - |
---|
1038 | | - /* wait for frame_event_done completion */ |
---|
1039 | | - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); |
---|
1040 | | - ret = _dpu_crtc_wait_for_frame_done(crtc); |
---|
1041 | | - DPU_ATRACE_END("wait_for_frame_done_event"); |
---|
1042 | | - if (ret) { |
---|
1043 | | - DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", |
---|
1044 | | - crtc->base.id, |
---|
1045 | | - atomic_read(&dpu_crtc->frame_pending)); |
---|
1046 | | - goto end; |
---|
1047 | | - } |
---|
| 653 | + /* |
---|
| 654 | + * Encoder will flush/start now, unless it has a tx pending. If so, it |
---|
| 655 | + * may delay and flush at an irq event (e.g. ppdone) |
---|
| 656 | + */ |
---|
| 657 | + drm_for_each_encoder_mask(encoder, crtc->dev, |
---|
| 658 | + crtc->state->encoder_mask) |
---|
| 659 | + dpu_encoder_prepare_for_kickoff(encoder); |
---|
1048 | 660 | |
---|
1049 | 661 | if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { |
---|
1050 | 662 | /* acquire bandwidth and other resources */ |
---|
.. | .. |
---|
1056 | 668 | |
---|
1057 | 669 | dpu_vbif_clear_errors(dpu_kms); |
---|
1058 | 670 | |
---|
1059 | | - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
---|
1060 | | - if (encoder->crtc != crtc) |
---|
1061 | | - continue; |
---|
1062 | | - |
---|
| 671 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
---|
1063 | 672 | dpu_encoder_kickoff(encoder); |
---|
1064 | | - } |
---|
1065 | 673 | |
---|
1066 | | -end: |
---|
1067 | 674 | reinit_completion(&dpu_crtc->frame_done_comp); |
---|
1068 | 675 | DPU_ATRACE_END("crtc_commit"); |
---|
1069 | 676 | } |
---|
1070 | 677 | |
---|
1071 | | -/** |
---|
1072 | | - * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank request |
---|
1073 | | - * @dpu_crtc: Pointer to dpu crtc structure |
---|
1074 | | - * @enable: Whether to enable/disable vblanks |
---|
1075 | | - * |
---|
1076 | | - * @Return: error code |
---|
1077 | | - */ |
---|
1078 | | -static int _dpu_crtc_vblank_enable_no_lock( |
---|
1079 | | - struct dpu_crtc *dpu_crtc, bool enable) |
---|
| 678 | +static void dpu_crtc_reset(struct drm_crtc *crtc) |
---|
1080 | 679 | { |
---|
1081 | | - struct drm_device *dev; |
---|
1082 | | - struct drm_crtc *crtc; |
---|
1083 | | - struct drm_encoder *enc; |
---|
| 680 | + struct dpu_crtc_state *cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); |
---|
1084 | 681 | |
---|
1085 | | - if (!dpu_crtc) { |
---|
1086 | | - DPU_ERROR("invalid crtc\n"); |
---|
1087 | | - return -EINVAL; |
---|
1088 | | - } |
---|
| 682 | + if (crtc->state) |
---|
| 683 | + dpu_crtc_destroy_state(crtc, crtc->state); |
---|
1089 | 684 | |
---|
1090 | | - crtc = &dpu_crtc->base; |
---|
1091 | | - dev = crtc->dev; |
---|
1092 | | - |
---|
1093 | | - if (enable) { |
---|
1094 | | - int ret; |
---|
1095 | | - |
---|
1096 | | - /* drop lock since power crtc cb may try to re-acquire lock */ |
---|
1097 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1098 | | - ret = _dpu_crtc_power_enable(dpu_crtc, true); |
---|
1099 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1100 | | - if (ret) |
---|
1101 | | - return ret; |
---|
1102 | | - |
---|
1103 | | - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { |
---|
1104 | | - if (enc->crtc != crtc) |
---|
1105 | | - continue; |
---|
1106 | | - |
---|
1107 | | - trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), |
---|
1108 | | - DRMID(enc), enable, |
---|
1109 | | - dpu_crtc); |
---|
1110 | | - |
---|
1111 | | - dpu_encoder_register_vblank_callback(enc, |
---|
1112 | | - dpu_crtc_vblank_cb, (void *)crtc); |
---|
1113 | | - } |
---|
1114 | | - } else { |
---|
1115 | | - list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { |
---|
1116 | | - if (enc->crtc != crtc) |
---|
1117 | | - continue; |
---|
1118 | | - |
---|
1119 | | - trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), |
---|
1120 | | - DRMID(enc), enable, |
---|
1121 | | - dpu_crtc); |
---|
1122 | | - |
---|
1123 | | - dpu_encoder_register_vblank_callback(enc, NULL, NULL); |
---|
1124 | | - } |
---|
1125 | | - |
---|
1126 | | - /* drop lock since power crtc cb may try to re-acquire lock */ |
---|
1127 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1128 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
---|
1129 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1130 | | - } |
---|
1131 | | - |
---|
1132 | | - return 0; |
---|
1133 | | -} |
---|
1134 | | - |
---|
1135 | | -/** |
---|
1136 | | - * _dpu_crtc_set_suspend - notify crtc of suspend enable/disable |
---|
1137 | | - * @crtc: Pointer to drm crtc object |
---|
1138 | | - * @enable: true to enable suspend, false to indicate resume |
---|
1139 | | - */ |
---|
1140 | | -static void _dpu_crtc_set_suspend(struct drm_crtc *crtc, bool enable) |
---|
1141 | | -{ |
---|
1142 | | - struct dpu_crtc *dpu_crtc; |
---|
1143 | | - struct msm_drm_private *priv; |
---|
1144 | | - struct dpu_kms *dpu_kms; |
---|
1145 | | - int ret = 0; |
---|
1146 | | - |
---|
1147 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
---|
1148 | | - DPU_ERROR("invalid crtc\n"); |
---|
1149 | | - return; |
---|
1150 | | - } |
---|
1151 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1152 | | - priv = crtc->dev->dev_private; |
---|
1153 | | - |
---|
1154 | | - if (!priv->kms) { |
---|
1155 | | - DPU_ERROR("invalid crtc kms\n"); |
---|
1156 | | - return; |
---|
1157 | | - } |
---|
1158 | | - dpu_kms = to_dpu_kms(priv->kms); |
---|
1159 | | - |
---|
1160 | | - DRM_DEBUG_KMS("crtc%d suspend = %d\n", crtc->base.id, enable); |
---|
1161 | | - |
---|
1162 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1163 | | - |
---|
1164 | | - /* |
---|
1165 | | - * If the vblank is enabled, release a power reference on suspend |
---|
1166 | | - * and take it back during resume (if it is still enabled). |
---|
1167 | | - */ |
---|
1168 | | - trace_dpu_crtc_set_suspend(DRMID(&dpu_crtc->base), enable, dpu_crtc); |
---|
1169 | | - if (dpu_crtc->suspend == enable) |
---|
1170 | | - DPU_DEBUG("crtc%d suspend already set to %d, ignoring update\n", |
---|
1171 | | - crtc->base.id, enable); |
---|
1172 | | - else if (dpu_crtc->enabled && dpu_crtc->vblank_requested) { |
---|
1173 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, !enable); |
---|
1174 | | - if (ret) |
---|
1175 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
---|
1176 | | - dpu_crtc->name, ret); |
---|
1177 | | - } |
---|
1178 | | - |
---|
1179 | | - dpu_crtc->suspend = enable; |
---|
1180 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
| 685 | + if (cstate) |
---|
| 686 | + __drm_atomic_helper_crtc_reset(crtc, &cstate->base); |
---|
| 687 | + else |
---|
| 688 | + __drm_atomic_helper_crtc_reset(crtc, NULL); |
---|
1181 | 689 | } |
---|
1182 | 690 | |
---|
1183 | 691 | /** |
---|
1184 | 692 | * dpu_crtc_duplicate_state - state duplicate hook |
---|
1185 | 693 | * @crtc: Pointer to drm crtc structure |
---|
1186 | | - * @Returns: Pointer to new drm_crtc_state structure |
---|
1187 | 694 | */ |
---|
1188 | 695 | static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) |
---|
1189 | 696 | { |
---|
1190 | | - struct dpu_crtc *dpu_crtc; |
---|
1191 | | - struct dpu_crtc_state *cstate, *old_cstate; |
---|
| 697 | + struct dpu_crtc_state *cstate, *old_cstate = to_dpu_crtc_state(crtc->state); |
---|
1192 | 698 | |
---|
1193 | | - if (!crtc || !crtc->state) { |
---|
1194 | | - DPU_ERROR("invalid argument(s)\n"); |
---|
1195 | | - return NULL; |
---|
1196 | | - } |
---|
1197 | | - |
---|
1198 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1199 | | - old_cstate = to_dpu_crtc_state(crtc->state); |
---|
1200 | 699 | cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); |
---|
1201 | 700 | if (!cstate) { |
---|
1202 | 701 | DPU_ERROR("failed to allocate state\n"); |
---|
.. | .. |
---|
1206 | 705 | /* duplicate base helper */ |
---|
1207 | 706 | __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); |
---|
1208 | 707 | |
---|
1209 | | - _dpu_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); |
---|
1210 | | - |
---|
1211 | 708 | return &cstate->base; |
---|
1212 | 709 | } |
---|
1213 | 710 | |
---|
1214 | | -/** |
---|
1215 | | - * dpu_crtc_reset - reset hook for CRTCs |
---|
1216 | | - * Resets the atomic state for @crtc by freeing the state pointer (which might |
---|
1217 | | - * be NULL, e.g. at driver load time) and allocating a new empty state object. |
---|
1218 | | - * @crtc: Pointer to drm crtc structure |
---|
1219 | | - */ |
---|
1220 | | -static void dpu_crtc_reset(struct drm_crtc *crtc) |
---|
| 711 | +static void dpu_crtc_disable(struct drm_crtc *crtc, |
---|
| 712 | + struct drm_crtc_state *old_crtc_state) |
---|
1221 | 713 | { |
---|
1222 | | - struct dpu_crtc *dpu_crtc; |
---|
1223 | | - struct dpu_crtc_state *cstate; |
---|
1224 | | - |
---|
1225 | | - if (!crtc) { |
---|
1226 | | - DPU_ERROR("invalid crtc\n"); |
---|
1227 | | - return; |
---|
1228 | | - } |
---|
1229 | | - |
---|
1230 | | - /* revert suspend actions, if necessary */ |
---|
1231 | | - if (dpu_kms_is_suspend_state(crtc->dev)) |
---|
1232 | | - _dpu_crtc_set_suspend(crtc, false); |
---|
1233 | | - |
---|
1234 | | - /* remove previous state, if present */ |
---|
1235 | | - if (crtc->state) { |
---|
1236 | | - dpu_crtc_destroy_state(crtc, crtc->state); |
---|
1237 | | - crtc->state = 0; |
---|
1238 | | - } |
---|
1239 | | - |
---|
1240 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1241 | | - cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); |
---|
1242 | | - if (!cstate) { |
---|
1243 | | - DPU_ERROR("failed to allocate state\n"); |
---|
1244 | | - return; |
---|
1245 | | - } |
---|
1246 | | - |
---|
1247 | | - _dpu_crtc_rp_reset(&cstate->rp, &dpu_crtc->rp_lock, |
---|
1248 | | - &dpu_crtc->rp_head); |
---|
1249 | | - |
---|
1250 | | - cstate->base.crtc = crtc; |
---|
1251 | | - crtc->state = &cstate->base; |
---|
1252 | | -} |
---|
1253 | | - |
---|
1254 | | -static void dpu_crtc_handle_power_event(u32 event_type, void *arg) |
---|
1255 | | -{ |
---|
1256 | | - struct drm_crtc *crtc = arg; |
---|
1257 | | - struct dpu_crtc *dpu_crtc; |
---|
| 714 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 715 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); |
---|
1258 | 716 | struct drm_encoder *encoder; |
---|
1259 | | - struct dpu_crtc_mixer *m; |
---|
1260 | | - u32 i, misr_status; |
---|
1261 | | - |
---|
1262 | | - if (!crtc) { |
---|
1263 | | - DPU_ERROR("invalid crtc\n"); |
---|
1264 | | - return; |
---|
1265 | | - } |
---|
1266 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1267 | | - |
---|
1268 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1269 | | - |
---|
1270 | | - trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type); |
---|
1271 | | - |
---|
1272 | | - switch (event_type) { |
---|
1273 | | - case DPU_POWER_EVENT_POST_ENABLE: |
---|
1274 | | - /* restore encoder; crtc will be programmed during commit */ |
---|
1275 | | - drm_for_each_encoder(encoder, crtc->dev) { |
---|
1276 | | - if (encoder->crtc != crtc) |
---|
1277 | | - continue; |
---|
1278 | | - |
---|
1279 | | - dpu_encoder_virt_restore(encoder); |
---|
1280 | | - } |
---|
1281 | | - |
---|
1282 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
---|
1283 | | - m = &dpu_crtc->mixers[i]; |
---|
1284 | | - if (!m->hw_lm || !m->hw_lm->ops.setup_misr || |
---|
1285 | | - !dpu_crtc->misr_enable) |
---|
1286 | | - continue; |
---|
1287 | | - |
---|
1288 | | - m->hw_lm->ops.setup_misr(m->hw_lm, true, |
---|
1289 | | - dpu_crtc->misr_frame_count); |
---|
1290 | | - } |
---|
1291 | | - break; |
---|
1292 | | - case DPU_POWER_EVENT_PRE_DISABLE: |
---|
1293 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
---|
1294 | | - m = &dpu_crtc->mixers[i]; |
---|
1295 | | - if (!m->hw_lm || !m->hw_lm->ops.collect_misr || |
---|
1296 | | - !dpu_crtc->misr_enable) |
---|
1297 | | - continue; |
---|
1298 | | - |
---|
1299 | | - misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); |
---|
1300 | | - dpu_crtc->misr_data[i] = misr_status ? misr_status : |
---|
1301 | | - dpu_crtc->misr_data[i]; |
---|
1302 | | - } |
---|
1303 | | - break; |
---|
1304 | | - case DPU_POWER_EVENT_POST_DISABLE: |
---|
1305 | | - /** |
---|
1306 | | - * Nothing to do. All the planes on the CRTC will be |
---|
1307 | | - * programmed for every frame |
---|
1308 | | - */ |
---|
1309 | | - break; |
---|
1310 | | - default: |
---|
1311 | | - DPU_DEBUG("event:%d not handled\n", event_type); |
---|
1312 | | - break; |
---|
1313 | | - } |
---|
1314 | | - |
---|
1315 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1316 | | -} |
---|
1317 | | - |
---|
1318 | | -static void dpu_crtc_disable(struct drm_crtc *crtc) |
---|
1319 | | -{ |
---|
1320 | | - struct dpu_crtc *dpu_crtc; |
---|
1321 | | - struct dpu_crtc_state *cstate; |
---|
1322 | | - struct drm_display_mode *mode; |
---|
1323 | | - struct drm_encoder *encoder; |
---|
1324 | | - struct msm_drm_private *priv; |
---|
1325 | | - int ret; |
---|
1326 | 717 | unsigned long flags; |
---|
1327 | | - |
---|
1328 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { |
---|
1329 | | - DPU_ERROR("invalid crtc\n"); |
---|
1330 | | - return; |
---|
1331 | | - } |
---|
1332 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1333 | | - cstate = to_dpu_crtc_state(crtc->state); |
---|
1334 | | - mode = &cstate->base.adjusted_mode; |
---|
1335 | | - priv = crtc->dev->dev_private; |
---|
| 718 | + bool release_bandwidth = false; |
---|
1336 | 719 | |
---|
1337 | 720 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); |
---|
1338 | | - |
---|
1339 | | - if (dpu_kms_is_suspend_state(crtc->dev)) |
---|
1340 | | - _dpu_crtc_set_suspend(crtc, true); |
---|
1341 | 721 | |
---|
1342 | 722 | /* Disable/save vblank irq handling */ |
---|
1343 | 723 | drm_crtc_vblank_off(crtc); |
---|
1344 | 724 | |
---|
1345 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
| 725 | + drm_for_each_encoder_mask(encoder, crtc->dev, |
---|
| 726 | + old_crtc_state->encoder_mask) { |
---|
| 727 | + /* in video mode, we hold an extra bandwidth reference |
---|
| 728 | + * as we cannot drop bandwidth at frame-done if any |
---|
| 729 | + * crtc is being used in video mode. |
---|
| 730 | + */ |
---|
| 731 | + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) |
---|
| 732 | + release_bandwidth = true; |
---|
| 733 | + dpu_encoder_assign_crtc(encoder, NULL); |
---|
| 734 | + } |
---|
1346 | 735 | |
---|
1347 | 736 | /* wait for frame_event_done completion */ |
---|
1348 | 737 | if (_dpu_crtc_wait_for_frame_done(crtc)) |
---|
.. | .. |
---|
1351 | 740 | atomic_read(&dpu_crtc->frame_pending)); |
---|
1352 | 741 | |
---|
1353 | 742 | trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); |
---|
1354 | | - if (dpu_crtc->enabled && !dpu_crtc->suspend && |
---|
1355 | | - dpu_crtc->vblank_requested) { |
---|
1356 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, false); |
---|
1357 | | - if (ret) |
---|
1358 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
---|
1359 | | - dpu_crtc->name, ret); |
---|
1360 | | - } |
---|
1361 | 743 | dpu_crtc->enabled = false; |
---|
1362 | 744 | |
---|
1363 | 745 | if (atomic_read(&dpu_crtc->frame_pending)) { |
---|
1364 | 746 | trace_dpu_crtc_disable_frame_pending(DRMID(crtc), |
---|
1365 | 747 | atomic_read(&dpu_crtc->frame_pending)); |
---|
1366 | | - dpu_core_perf_crtc_release_bw(crtc); |
---|
| 748 | + if (release_bandwidth) |
---|
| 749 | + dpu_core_perf_crtc_release_bw(crtc); |
---|
1367 | 750 | atomic_set(&dpu_crtc->frame_pending, 0); |
---|
1368 | 751 | } |
---|
1369 | 752 | |
---|
1370 | 753 | dpu_core_perf_crtc_update(crtc, 0, true); |
---|
1371 | 754 | |
---|
1372 | | - drm_for_each_encoder(encoder, crtc->dev) { |
---|
1373 | | - if (encoder->crtc != crtc) |
---|
1374 | | - continue; |
---|
| 755 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
---|
1375 | 756 | dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); |
---|
1376 | | - } |
---|
1377 | 757 | |
---|
1378 | | - if (dpu_crtc->power_event) |
---|
1379 | | - dpu_power_handle_unregister_event(dpu_crtc->phandle, |
---|
1380 | | - dpu_crtc->power_event); |
---|
1381 | | - |
---|
1382 | | - memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); |
---|
1383 | | - dpu_crtc->num_mixers = 0; |
---|
1384 | | - dpu_crtc->mixers_swapped = false; |
---|
| 758 | + memset(cstate->mixers, 0, sizeof(cstate->mixers)); |
---|
| 759 | + cstate->num_mixers = 0; |
---|
1385 | 760 | |
---|
1386 | 761 | /* disable clk & bw control until clk & bw properties are set */ |
---|
1387 | 762 | cstate->bw_control = false; |
---|
1388 | 763 | cstate->bw_split_vote = false; |
---|
1389 | | - |
---|
1390 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1391 | 764 | |
---|
1392 | 765 | if (crtc->state->event && !crtc->state->active) { |
---|
1393 | 766 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
---|
.. | .. |
---|
1395 | 768 | crtc->state->event = NULL; |
---|
1396 | 769 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
---|
1397 | 770 | } |
---|
| 771 | + |
---|
| 772 | + pm_runtime_put_sync(crtc->dev->dev); |
---|
1398 | 773 | } |
---|
1399 | 774 | |
---|
1400 | 775 | static void dpu_crtc_enable(struct drm_crtc *crtc, |
---|
1401 | 776 | struct drm_crtc_state *old_crtc_state) |
---|
1402 | 777 | { |
---|
1403 | | - struct dpu_crtc *dpu_crtc; |
---|
| 778 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
1404 | 779 | struct drm_encoder *encoder; |
---|
1405 | | - struct msm_drm_private *priv; |
---|
1406 | | - int ret; |
---|
| 780 | + bool request_bandwidth = false; |
---|
1407 | 781 | |
---|
1408 | | - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { |
---|
1409 | | - DPU_ERROR("invalid crtc\n"); |
---|
1410 | | - return; |
---|
1411 | | - } |
---|
1412 | | - priv = crtc->dev->dev_private; |
---|
| 782 | + pm_runtime_get_sync(crtc->dev->dev); |
---|
1413 | 783 | |
---|
1414 | 784 | DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); |
---|
1415 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1416 | 785 | |
---|
1417 | | - drm_for_each_encoder(encoder, crtc->dev) { |
---|
1418 | | - if (encoder->crtc != crtc) |
---|
1419 | | - continue; |
---|
| 786 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { |
---|
| 787 | + /* in video mode, we hold an extra bandwidth reference |
---|
| 788 | + * as we cannot drop bandwidth at frame-done if any |
---|
| 789 | + * crtc is being used in video mode. |
---|
| 790 | + */ |
---|
| 791 | + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) |
---|
| 792 | + request_bandwidth = true; |
---|
1420 | 793 | dpu_encoder_register_frame_event_callback(encoder, |
---|
1421 | 794 | dpu_crtc_frame_event_cb, (void *)crtc); |
---|
1422 | 795 | } |
---|
1423 | 796 | |
---|
1424 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
| 797 | + if (request_bandwidth) |
---|
| 798 | + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); |
---|
| 799 | + |
---|
1425 | 800 | trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); |
---|
1426 | | - if (!dpu_crtc->enabled && !dpu_crtc->suspend && |
---|
1427 | | - dpu_crtc->vblank_requested) { |
---|
1428 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, true); |
---|
1429 | | - if (ret) |
---|
1430 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
---|
1431 | | - dpu_crtc->name, ret); |
---|
1432 | | - } |
---|
1433 | 801 | dpu_crtc->enabled = true; |
---|
1434 | 802 | |
---|
1435 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
| 803 | + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) |
---|
| 804 | + dpu_encoder_assign_crtc(encoder, crtc); |
---|
1436 | 805 | |
---|
1437 | 806 | /* Enable/restore vblank irq handling */ |
---|
1438 | 807 | drm_crtc_vblank_on(crtc); |
---|
1439 | | - |
---|
1440 | | - dpu_crtc->power_event = dpu_power_handle_register_event( |
---|
1441 | | - dpu_crtc->phandle, |
---|
1442 | | - DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | |
---|
1443 | | - DPU_POWER_EVENT_PRE_DISABLE, |
---|
1444 | | - dpu_crtc_handle_power_event, crtc, dpu_crtc->name); |
---|
1445 | | - |
---|
1446 | 808 | } |
---|
1447 | 809 | |
---|
1448 | 810 | struct plane_state { |
---|
.. | .. |
---|
1455 | 817 | static int dpu_crtc_atomic_check(struct drm_crtc *crtc, |
---|
1456 | 818 | struct drm_crtc_state *state) |
---|
1457 | 819 | { |
---|
1458 | | - struct dpu_crtc *dpu_crtc; |
---|
| 820 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 821 | + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); |
---|
1459 | 822 | struct plane_state *pstates; |
---|
1460 | | - struct dpu_crtc_state *cstate; |
---|
1461 | 823 | |
---|
1462 | 824 | const struct drm_plane_state *pstate; |
---|
1463 | 825 | struct drm_plane *plane; |
---|
1464 | 826 | struct drm_display_mode *mode; |
---|
1465 | 827 | |
---|
1466 | | - int cnt = 0, rc = 0, mixer_width, i, z_pos; |
---|
| 828 | + int cnt = 0, rc = 0, mixer_width = 0, i, z_pos; |
---|
1467 | 829 | |
---|
1468 | 830 | struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2]; |
---|
1469 | 831 | int multirect_count = 0; |
---|
.. | .. |
---|
1471 | 833 | int left_zpos_cnt = 0, right_zpos_cnt = 0; |
---|
1472 | 834 | struct drm_rect crtc_rect = { 0 }; |
---|
1473 | 835 | |
---|
1474 | | - if (!crtc) { |
---|
1475 | | - DPU_ERROR("invalid crtc\n"); |
---|
1476 | | - return -EINVAL; |
---|
1477 | | - } |
---|
1478 | | - |
---|
1479 | 836 | pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); |
---|
1480 | | - |
---|
1481 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1482 | | - cstate = to_dpu_crtc_state(state); |
---|
| 837 | + if (!pstates) |
---|
| 838 | + return -ENOMEM; |
---|
1483 | 839 | |
---|
1484 | 840 | if (!state->enable || !state->active) { |
---|
1485 | 841 | DPU_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", |
---|
.. | .. |
---|
1496 | 852 | |
---|
1497 | 853 | memset(pipe_staged, 0, sizeof(pipe_staged)); |
---|
1498 | 854 | |
---|
1499 | | - mixer_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); |
---|
| 855 | + if (cstate->num_mixers) { |
---|
| 856 | + mixer_width = mode->hdisplay / cstate->num_mixers; |
---|
1500 | 857 | |
---|
1501 | | - _dpu_crtc_setup_lm_bounds(crtc, state); |
---|
| 858 | + _dpu_crtc_setup_lm_bounds(crtc, state); |
---|
| 859 | + } |
---|
1502 | 860 | |
---|
1503 | 861 | crtc_rect.x2 = mode->hdisplay; |
---|
1504 | 862 | crtc_rect.y2 = mode->vdisplay; |
---|
.. | .. |
---|
1608 | 966 | } |
---|
1609 | 967 | } |
---|
1610 | 968 | |
---|
| 969 | + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); |
---|
| 970 | + |
---|
1611 | 971 | rc = dpu_core_perf_crtc_check(crtc, state); |
---|
1612 | 972 | if (rc) { |
---|
1613 | 973 | DPU_ERROR("crtc%d failed performance check %d\n", |
---|
.. | .. |
---|
1678 | 1038 | } |
---|
1679 | 1039 | |
---|
1680 | 1040 | end: |
---|
1681 | | - _dpu_crtc_rp_free_unused(&cstate->rp); |
---|
1682 | 1041 | kfree(pstates); |
---|
1683 | 1042 | return rc; |
---|
1684 | 1043 | } |
---|
1685 | 1044 | |
---|
1686 | 1045 | int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) |
---|
1687 | 1046 | { |
---|
1688 | | - struct dpu_crtc *dpu_crtc; |
---|
1689 | | - int ret; |
---|
| 1047 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 1048 | + struct drm_encoder *enc; |
---|
1690 | 1049 | |
---|
1691 | | - if (!crtc) { |
---|
1692 | | - DPU_ERROR("invalid crtc\n"); |
---|
1693 | | - return -EINVAL; |
---|
1694 | | - } |
---|
1695 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
1696 | | - |
---|
1697 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1698 | 1050 | trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc); |
---|
1699 | | - if (dpu_crtc->enabled && !dpu_crtc->suspend) { |
---|
1700 | | - ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, en); |
---|
1701 | | - if (ret) |
---|
1702 | | - DPU_ERROR("%s vblank enable failed: %d\n", |
---|
1703 | | - dpu_crtc->name, ret); |
---|
| 1051 | + |
---|
| 1052 | + /* |
---|
| 1053 | + * Normally we would iterate through encoder_mask in crtc state to find |
---|
| 1054 | + * attached encoders. In this case, we might be disabling vblank _after_ |
---|
| 1055 | + * encoder_mask has been cleared. |
---|
| 1056 | + * |
---|
| 1057 | + * Instead, we "assign" a crtc to the encoder in enable and clear it in |
---|
| 1058 | + * disable (which is also after encoder_mask is cleared). So instead of |
---|
| 1059 | + * using encoder mask, we'll ask the encoder to toggle itself iff it's |
---|
| 1060 | + * currently assigned to our crtc. |
---|
| 1061 | + * |
---|
| 1062 | + * Note also that this function cannot be called while crtc is disabled |
---|
| 1063 | + * since we use drm_crtc_vblank_on/off. So we don't need to worry |
---|
| 1064 | + * about the assigned crtcs being inconsistent with the current state |
---|
| 1065 | + * (which means no need to worry about modeset locks). |
---|
| 1066 | + */ |
---|
| 1067 | + list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { |
---|
| 1068 | + trace_dpu_crtc_vblank_enable(DRMID(crtc), DRMID(enc), en, |
---|
| 1069 | + dpu_crtc); |
---|
| 1070 | + |
---|
| 1071 | + dpu_encoder_toggle_vblank_for_crtc(enc, crtc, en); |
---|
1704 | 1072 | } |
---|
1705 | | - dpu_crtc->vblank_requested = en; |
---|
1706 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1707 | 1073 | |
---|
1708 | 1074 | return 0; |
---|
1709 | 1075 | } |
---|
.. | .. |
---|
1724 | 1090 | |
---|
1725 | 1091 | int i, out_width; |
---|
1726 | 1092 | |
---|
1727 | | - if (!s || !s->private) |
---|
1728 | | - return -EINVAL; |
---|
1729 | | - |
---|
1730 | 1093 | dpu_crtc = s->private; |
---|
1731 | 1094 | crtc = &dpu_crtc->base; |
---|
| 1095 | + |
---|
| 1096 | + drm_modeset_lock_all(crtc->dev); |
---|
1732 | 1097 | cstate = to_dpu_crtc_state(crtc->state); |
---|
1733 | 1098 | |
---|
1734 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1735 | 1099 | mode = &crtc->state->adjusted_mode; |
---|
1736 | | - out_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); |
---|
| 1100 | + out_width = mode->hdisplay / cstate->num_mixers; |
---|
1737 | 1101 | |
---|
1738 | 1102 | seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, |
---|
1739 | 1103 | mode->hdisplay, mode->vdisplay); |
---|
1740 | 1104 | |
---|
1741 | 1105 | seq_puts(s, "\n"); |
---|
1742 | 1106 | |
---|
1743 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
---|
1744 | | - m = &dpu_crtc->mixers[i]; |
---|
1745 | | - if (!m->hw_lm) |
---|
1746 | | - seq_printf(s, "\tmixer[%d] has no lm\n", i); |
---|
1747 | | - else if (!m->hw_ctl) |
---|
1748 | | - seq_printf(s, "\tmixer[%d] has no ctl\n", i); |
---|
1749 | | - else |
---|
1750 | | - seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", |
---|
1751 | | - m->hw_lm->idx - LM_0, m->hw_ctl->idx - CTL_0, |
---|
1752 | | - out_width, mode->vdisplay); |
---|
| 1107 | + for (i = 0; i < cstate->num_mixers; ++i) { |
---|
| 1108 | + m = &cstate->mixers[i]; |
---|
| 1109 | + seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", |
---|
| 1110 | + m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0, |
---|
| 1111 | + out_width, mode->vdisplay); |
---|
1753 | 1112 | } |
---|
1754 | 1113 | |
---|
1755 | 1114 | seq_puts(s, "\n"); |
---|
.. | .. |
---|
1818 | 1177 | dpu_crtc->vblank_cb_time = ktime_set(0, 0); |
---|
1819 | 1178 | } |
---|
1820 | 1179 | |
---|
1821 | | - seq_printf(s, "vblank_enable:%d\n", dpu_crtc->vblank_requested); |
---|
1822 | | - |
---|
1823 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
| 1180 | + drm_modeset_unlock_all(crtc->dev); |
---|
1824 | 1181 | |
---|
1825 | 1182 | return 0; |
---|
1826 | 1183 | } |
---|
1827 | 1184 | |
---|
1828 | | -static int _dpu_debugfs_status_open(struct inode *inode, struct file *file) |
---|
1829 | | -{ |
---|
1830 | | - return single_open(file, _dpu_debugfs_status_show, inode->i_private); |
---|
1831 | | -} |
---|
1832 | | - |
---|
1833 | | -static ssize_t _dpu_crtc_misr_setup(struct file *file, |
---|
1834 | | - const char __user *user_buf, size_t count, loff_t *ppos) |
---|
1835 | | -{ |
---|
1836 | | - struct dpu_crtc *dpu_crtc; |
---|
1837 | | - struct dpu_crtc_mixer *m; |
---|
1838 | | - int i = 0, rc; |
---|
1839 | | - char buf[MISR_BUFF_SIZE + 1]; |
---|
1840 | | - u32 frame_count, enable; |
---|
1841 | | - size_t buff_copy; |
---|
1842 | | - |
---|
1843 | | - if (!file || !file->private_data) |
---|
1844 | | - return -EINVAL; |
---|
1845 | | - |
---|
1846 | | - dpu_crtc = file->private_data; |
---|
1847 | | - buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); |
---|
1848 | | - if (copy_from_user(buf, user_buf, buff_copy)) { |
---|
1849 | | - DPU_ERROR("buffer copy failed\n"); |
---|
1850 | | - return -EINVAL; |
---|
1851 | | - } |
---|
1852 | | - |
---|
1853 | | - buf[buff_copy] = 0; /* end of string */ |
---|
1854 | | - |
---|
1855 | | - if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) |
---|
1856 | | - return -EINVAL; |
---|
1857 | | - |
---|
1858 | | - rc = _dpu_crtc_power_enable(dpu_crtc, true); |
---|
1859 | | - if (rc) |
---|
1860 | | - return rc; |
---|
1861 | | - |
---|
1862 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1863 | | - dpu_crtc->misr_enable = enable; |
---|
1864 | | - dpu_crtc->misr_frame_count = frame_count; |
---|
1865 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
---|
1866 | | - dpu_crtc->misr_data[i] = 0; |
---|
1867 | | - m = &dpu_crtc->mixers[i]; |
---|
1868 | | - if (!m->hw_lm || !m->hw_lm->ops.setup_misr) |
---|
1869 | | - continue; |
---|
1870 | | - |
---|
1871 | | - m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count); |
---|
1872 | | - } |
---|
1873 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1874 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
---|
1875 | | - |
---|
1876 | | - return count; |
---|
1877 | | -} |
---|
1878 | | - |
---|
1879 | | -static ssize_t _dpu_crtc_misr_read(struct file *file, |
---|
1880 | | - char __user *user_buff, size_t count, loff_t *ppos) |
---|
1881 | | -{ |
---|
1882 | | - struct dpu_crtc *dpu_crtc; |
---|
1883 | | - struct dpu_crtc_mixer *m; |
---|
1884 | | - int i = 0, rc; |
---|
1885 | | - u32 misr_status; |
---|
1886 | | - ssize_t len = 0; |
---|
1887 | | - char buf[MISR_BUFF_SIZE + 1] = {'\0'}; |
---|
1888 | | - |
---|
1889 | | - if (*ppos) |
---|
1890 | | - return 0; |
---|
1891 | | - |
---|
1892 | | - if (!file || !file->private_data) |
---|
1893 | | - return -EINVAL; |
---|
1894 | | - |
---|
1895 | | - dpu_crtc = file->private_data; |
---|
1896 | | - rc = _dpu_crtc_power_enable(dpu_crtc, true); |
---|
1897 | | - if (rc) |
---|
1898 | | - return rc; |
---|
1899 | | - |
---|
1900 | | - mutex_lock(&dpu_crtc->crtc_lock); |
---|
1901 | | - if (!dpu_crtc->misr_enable) { |
---|
1902 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, |
---|
1903 | | - "disabled\n"); |
---|
1904 | | - goto buff_check; |
---|
1905 | | - } |
---|
1906 | | - |
---|
1907 | | - for (i = 0; i < dpu_crtc->num_mixers; ++i) { |
---|
1908 | | - m = &dpu_crtc->mixers[i]; |
---|
1909 | | - if (!m->hw_lm || !m->hw_lm->ops.collect_misr) |
---|
1910 | | - continue; |
---|
1911 | | - |
---|
1912 | | - misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); |
---|
1913 | | - dpu_crtc->misr_data[i] = misr_status ? misr_status : |
---|
1914 | | - dpu_crtc->misr_data[i]; |
---|
1915 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n", |
---|
1916 | | - m->hw_lm->idx - LM_0); |
---|
1917 | | - len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n", |
---|
1918 | | - dpu_crtc->misr_data[i]); |
---|
1919 | | - } |
---|
1920 | | - |
---|
1921 | | -buff_check: |
---|
1922 | | - if (count <= len) { |
---|
1923 | | - len = 0; |
---|
1924 | | - goto end; |
---|
1925 | | - } |
---|
1926 | | - |
---|
1927 | | - if (copy_to_user(user_buff, buf, len)) { |
---|
1928 | | - len = -EFAULT; |
---|
1929 | | - goto end; |
---|
1930 | | - } |
---|
1931 | | - |
---|
1932 | | - *ppos += len; /* increase offset */ |
---|
1933 | | - |
---|
1934 | | -end: |
---|
1935 | | - mutex_unlock(&dpu_crtc->crtc_lock); |
---|
1936 | | - _dpu_crtc_power_enable(dpu_crtc, false); |
---|
1937 | | - return len; |
---|
1938 | | -} |
---|
1939 | | - |
---|
1940 | | -#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \ |
---|
1941 | | -static int __prefix ## _open(struct inode *inode, struct file *file) \ |
---|
1942 | | -{ \ |
---|
1943 | | - return single_open(file, __prefix ## _show, inode->i_private); \ |
---|
1944 | | -} \ |
---|
1945 | | -static const struct file_operations __prefix ## _fops = { \ |
---|
1946 | | - .owner = THIS_MODULE, \ |
---|
1947 | | - .open = __prefix ## _open, \ |
---|
1948 | | - .release = single_release, \ |
---|
1949 | | - .read = seq_read, \ |
---|
1950 | | - .llseek = seq_lseek, \ |
---|
1951 | | -} |
---|
| 1185 | +DEFINE_SHOW_ATTRIBUTE(_dpu_debugfs_status); |
---|
1952 | 1186 | |
---|
1953 | 1187 | static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) |
---|
1954 | 1188 | { |
---|
1955 | 1189 | struct drm_crtc *crtc = (struct drm_crtc *) s->private; |
---|
1956 | 1190 | struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
1957 | | - struct dpu_crtc_res *res; |
---|
1958 | | - struct dpu_crtc_respool *rp; |
---|
1959 | | - int i; |
---|
1960 | 1191 | |
---|
1961 | 1192 | seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc)); |
---|
1962 | 1193 | seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc)); |
---|
1963 | 1194 | seq_printf(s, "core_clk_rate: %llu\n", |
---|
1964 | 1195 | dpu_crtc->cur_perf.core_clk_rate); |
---|
1965 | | - for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; |
---|
1966 | | - i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { |
---|
1967 | | - seq_printf(s, "bw_ctl[%s]: %llu\n", |
---|
1968 | | - dpu_power_handle_get_dbus_name(i), |
---|
1969 | | - dpu_crtc->cur_perf.bw_ctl[i]); |
---|
1970 | | - seq_printf(s, "max_per_pipe_ib[%s]: %llu\n", |
---|
1971 | | - dpu_power_handle_get_dbus_name(i), |
---|
1972 | | - dpu_crtc->cur_perf.max_per_pipe_ib[i]); |
---|
1973 | | - } |
---|
1974 | | - |
---|
1975 | | - mutex_lock(&dpu_crtc->rp_lock); |
---|
1976 | | - list_for_each_entry(rp, &dpu_crtc->rp_head, rp_list) { |
---|
1977 | | - seq_printf(s, "rp.%d: ", rp->sequence_id); |
---|
1978 | | - list_for_each_entry(res, &rp->res_list, list) |
---|
1979 | | - seq_printf(s, "0x%x/0x%llx/%pK/%d ", |
---|
1980 | | - res->type, res->tag, res->val, |
---|
1981 | | - atomic_read(&res->refcount)); |
---|
1982 | | - seq_puts(s, "\n"); |
---|
1983 | | - } |
---|
1984 | | - mutex_unlock(&dpu_crtc->rp_lock); |
---|
| 1196 | + seq_printf(s, "bw_ctl: %llu\n", dpu_crtc->cur_perf.bw_ctl); |
---|
| 1197 | + seq_printf(s, "max_per_pipe_ib: %llu\n", |
---|
| 1198 | + dpu_crtc->cur_perf.max_per_pipe_ib); |
---|
1985 | 1199 | |
---|
1986 | 1200 | return 0; |
---|
1987 | 1201 | } |
---|
1988 | | -DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_crtc_debugfs_state); |
---|
| 1202 | +DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); |
---|
1989 | 1203 | |
---|
1990 | 1204 | static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) |
---|
1991 | 1205 | { |
---|
1992 | | - struct dpu_crtc *dpu_crtc; |
---|
1993 | | - struct dpu_kms *dpu_kms; |
---|
1994 | | - |
---|
1995 | | - static const struct file_operations debugfs_status_fops = { |
---|
1996 | | - .open = _dpu_debugfs_status_open, |
---|
1997 | | - .read = seq_read, |
---|
1998 | | - .llseek = seq_lseek, |
---|
1999 | | - .release = single_release, |
---|
2000 | | - }; |
---|
2001 | | - static const struct file_operations debugfs_misr_fops = { |
---|
2002 | | - .open = simple_open, |
---|
2003 | | - .read = _dpu_crtc_misr_read, |
---|
2004 | | - .write = _dpu_crtc_misr_setup, |
---|
2005 | | - }; |
---|
2006 | | - |
---|
2007 | | - if (!crtc) |
---|
2008 | | - return -EINVAL; |
---|
2009 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
2010 | | - |
---|
2011 | | - dpu_kms = _dpu_crtc_get_kms(crtc); |
---|
2012 | | - if (!dpu_kms) |
---|
2013 | | - return -EINVAL; |
---|
| 1206 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
2014 | 1207 | |
---|
2015 | 1208 | dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name, |
---|
2016 | 1209 | crtc->dev->primary->debugfs_root); |
---|
2017 | | - if (!dpu_crtc->debugfs_root) |
---|
2018 | | - return -ENOMEM; |
---|
2019 | 1210 | |
---|
2020 | | - /* don't error check these */ |
---|
2021 | 1211 | debugfs_create_file("status", 0400, |
---|
2022 | 1212 | dpu_crtc->debugfs_root, |
---|
2023 | | - dpu_crtc, &debugfs_status_fops); |
---|
| 1213 | + dpu_crtc, &_dpu_debugfs_status_fops); |
---|
2024 | 1214 | debugfs_create_file("state", 0600, |
---|
2025 | 1215 | dpu_crtc->debugfs_root, |
---|
2026 | 1216 | &dpu_crtc->base, |
---|
2027 | 1217 | &dpu_crtc_debugfs_state_fops); |
---|
2028 | | - debugfs_create_file("misr_data", 0600, dpu_crtc->debugfs_root, |
---|
2029 | | - dpu_crtc, &debugfs_misr_fops); |
---|
2030 | 1218 | |
---|
2031 | 1219 | return 0; |
---|
2032 | | -} |
---|
2033 | | - |
---|
2034 | | -static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) |
---|
2035 | | -{ |
---|
2036 | | - struct dpu_crtc *dpu_crtc; |
---|
2037 | | - |
---|
2038 | | - if (!crtc) |
---|
2039 | | - return; |
---|
2040 | | - dpu_crtc = to_dpu_crtc(crtc); |
---|
2041 | | - debugfs_remove_recursive(dpu_crtc->debugfs_root); |
---|
2042 | 1220 | } |
---|
2043 | 1221 | #else |
---|
2044 | 1222 | static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) |
---|
2045 | 1223 | { |
---|
2046 | 1224 | return 0; |
---|
2047 | | -} |
---|
2048 | | - |
---|
2049 | | -static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) |
---|
2050 | | -{ |
---|
2051 | 1225 | } |
---|
2052 | 1226 | #endif /* CONFIG_DEBUG_FS */ |
---|
2053 | 1227 | |
---|
.. | .. |
---|
2058 | 1232 | |
---|
2059 | 1233 | static void dpu_crtc_early_unregister(struct drm_crtc *crtc) |
---|
2060 | 1234 | { |
---|
2061 | | - _dpu_crtc_destroy_debugfs(crtc); |
---|
| 1235 | + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); |
---|
| 1236 | + |
---|
| 1237 | + debugfs_remove_recursive(dpu_crtc->debugfs_root); |
---|
2062 | 1238 | } |
---|
2063 | 1239 | |
---|
2064 | 1240 | static const struct drm_crtc_funcs dpu_crtc_funcs = { |
---|
.. | .. |
---|
2070 | 1246 | .atomic_destroy_state = dpu_crtc_destroy_state, |
---|
2071 | 1247 | .late_register = dpu_crtc_late_register, |
---|
2072 | 1248 | .early_unregister = dpu_crtc_early_unregister, |
---|
| 1249 | + .enable_vblank = msm_crtc_enable_vblank, |
---|
| 1250 | + .disable_vblank = msm_crtc_disable_vblank, |
---|
2073 | 1251 | }; |
---|
2074 | 1252 | |
---|
2075 | 1253 | static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { |
---|
2076 | | - .disable = dpu_crtc_disable, |
---|
| 1254 | + .atomic_disable = dpu_crtc_disable, |
---|
2077 | 1255 | .atomic_enable = dpu_crtc_enable, |
---|
2078 | 1256 | .atomic_check = dpu_crtc_atomic_check, |
---|
2079 | 1257 | .atomic_begin = dpu_crtc_atomic_begin, |
---|
.. | .. |
---|
2081 | 1259 | }; |
---|
2082 | 1260 | |
---|
2083 | 1261 | /* initialize crtc */ |
---|
2084 | | -struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) |
---|
| 1262 | +struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, |
---|
| 1263 | + struct drm_plane *cursor) |
---|
2085 | 1264 | { |
---|
| 1265 | + struct msm_drm_private *priv = dev->dev_private; |
---|
| 1266 | + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); |
---|
2086 | 1267 | struct drm_crtc *crtc = NULL; |
---|
2087 | 1268 | struct dpu_crtc *dpu_crtc = NULL; |
---|
2088 | | - struct msm_drm_private *priv = NULL; |
---|
2089 | | - struct dpu_kms *kms = NULL; |
---|
2090 | 1269 | int i; |
---|
2091 | | - |
---|
2092 | | - priv = dev->dev_private; |
---|
2093 | | - kms = to_dpu_kms(priv->kms); |
---|
2094 | 1270 | |
---|
2095 | 1271 | dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); |
---|
2096 | 1272 | if (!dpu_crtc) |
---|
.. | .. |
---|
2099 | 1275 | crtc = &dpu_crtc->base; |
---|
2100 | 1276 | crtc->dev = dev; |
---|
2101 | 1277 | |
---|
2102 | | - mutex_init(&dpu_crtc->crtc_lock); |
---|
2103 | 1278 | spin_lock_init(&dpu_crtc->spin_lock); |
---|
2104 | 1279 | atomic_set(&dpu_crtc->frame_pending, 0); |
---|
2105 | | - |
---|
2106 | | - mutex_init(&dpu_crtc->rp_lock); |
---|
2107 | | - INIT_LIST_HEAD(&dpu_crtc->rp_head); |
---|
2108 | 1280 | |
---|
2109 | 1281 | init_completion(&dpu_crtc->frame_done_comp); |
---|
2110 | 1282 | |
---|
.. | .. |
---|
2118 | 1290 | dpu_crtc_frame_event_work); |
---|
2119 | 1291 | } |
---|
2120 | 1292 | |
---|
2121 | | - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &dpu_crtc_funcs, |
---|
| 1293 | + drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, |
---|
2122 | 1294 | NULL); |
---|
2123 | 1295 | |
---|
2124 | 1296 | drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); |
---|
| 1297 | + |
---|
| 1298 | + if (dpu_kms->catalog->dspp_count) |
---|
| 1299 | + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); |
---|
2125 | 1300 | |
---|
2126 | 1301 | /* save user friendly CRTC name for later */ |
---|
2127 | 1302 | snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); |
---|
2128 | 1303 | |
---|
2129 | 1304 | /* initialize event handling */ |
---|
2130 | 1305 | spin_lock_init(&dpu_crtc->event_lock); |
---|
2131 | | - |
---|
2132 | | - dpu_crtc->phandle = &kms->phandle; |
---|
2133 | 1306 | |
---|
2134 | 1307 | DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); |
---|
2135 | 1308 | return crtc; |
---|