2 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
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.
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
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/>.
22 struct drm_plane base
;
27 spinlock_t pipe_lock
; /* protect REG_MDP5_PIPE_* registers */
30 uint32_t flush_mask
; /* used to commit pipe registers */
35 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
37 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
38 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
39 int crtc_x
, int crtc_y
,
40 unsigned int crtc_w
, unsigned int crtc_h
,
41 uint32_t src_x
, uint32_t src_y
,
42 uint32_t src_w
, uint32_t src_h
);
43 static void set_scanout_locked(struct drm_plane
*plane
,
44 struct drm_framebuffer
*fb
);
46 static struct mdp5_kms
*get_kms(struct drm_plane
*plane
)
48 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
49 return to_mdp5_kms(to_mdp_kms(priv
->kms
));
52 static bool plane_enabled(struct drm_plane_state
*state
)
54 return state
->fb
&& state
->crtc
;
57 static void mdp5_plane_destroy(struct drm_plane
*plane
)
59 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
61 drm_plane_helper_disable(plane
);
62 drm_plane_cleanup(plane
);
67 /* helper to install properties which are common to planes and crtcs */
68 void mdp5_plane_install_properties(struct drm_plane
*plane
,
69 struct drm_mode_object
*obj
)
74 int mdp5_plane_set_property(struct drm_plane
*plane
,
75 struct drm_property
*property
, uint64_t val
)
81 static void mdp5_plane_reset(struct drm_plane
*plane
)
83 struct mdp5_plane_state
*mdp5_state
;
85 if (plane
->state
&& plane
->state
->fb
)
86 drm_framebuffer_unreference(plane
->state
->fb
);
88 kfree(to_mdp5_plane_state(plane
->state
));
89 mdp5_state
= kzalloc(sizeof(*mdp5_state
), GFP_KERNEL
);
91 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
) {
94 mdp5_state
->zpos
= 1 + drm_plane_index(plane
);
96 mdp5_state
->base
.plane
= plane
;
98 plane
->state
= &mdp5_state
->base
;
101 static struct drm_plane_state
*
102 mdp5_plane_duplicate_state(struct drm_plane
*plane
)
104 struct mdp5_plane_state
*mdp5_state
;
106 if (WARN_ON(!plane
->state
))
109 mdp5_state
= kmemdup(to_mdp5_plane_state(plane
->state
),
110 sizeof(*mdp5_state
), GFP_KERNEL
);
112 if (mdp5_state
&& mdp5_state
->base
.fb
)
113 drm_framebuffer_reference(mdp5_state
->base
.fb
);
115 mdp5_state
->mode_changed
= false;
116 mdp5_state
->pending
= false;
118 return &mdp5_state
->base
;
121 static void mdp5_plane_destroy_state(struct drm_plane
*plane
,
122 struct drm_plane_state
*state
)
125 drm_framebuffer_unreference(state
->fb
);
127 kfree(to_mdp5_plane_state(state
));
130 static const struct drm_plane_funcs mdp5_plane_funcs
= {
131 .update_plane
= drm_atomic_helper_update_plane
,
132 .disable_plane
= drm_atomic_helper_disable_plane
,
133 .destroy
= mdp5_plane_destroy
,
134 .set_property
= mdp5_plane_set_property
,
135 .reset
= mdp5_plane_reset
,
136 .atomic_duplicate_state
= mdp5_plane_duplicate_state
,
137 .atomic_destroy_state
= mdp5_plane_destroy_state
,
140 static int mdp5_plane_prepare_fb(struct drm_plane
*plane
,
141 struct drm_framebuffer
*fb
,
142 const struct drm_plane_state
*new_state
)
144 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
145 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
147 DBG("%s: prepare: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
148 return msm_framebuffer_prepare(fb
, mdp5_kms
->id
);
151 static void mdp5_plane_cleanup_fb(struct drm_plane
*plane
,
152 struct drm_framebuffer
*fb
,
153 const struct drm_plane_state
*old_state
)
155 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
156 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
158 DBG("%s: cleanup: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
159 msm_framebuffer_cleanup(fb
, mdp5_kms
->id
);
162 static int mdp5_plane_atomic_check(struct drm_plane
*plane
,
163 struct drm_plane_state
*state
)
165 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
166 struct drm_plane_state
*old_state
= plane
->state
;
168 DBG("%s: check (%d -> %d)", mdp5_plane
->name
,
169 plane_enabled(old_state
), plane_enabled(state
));
171 if (plane_enabled(state
) && plane_enabled(old_state
)) {
172 /* we cannot change SMP block configuration during scanout: */
173 bool full_modeset
= false;
174 if (state
->fb
->pixel_format
!= old_state
->fb
->pixel_format
) {
175 DBG("%s: pixel_format change!", mdp5_plane
->name
);
178 if (state
->src_w
!= old_state
->src_w
) {
179 DBG("%s: src_w change!", mdp5_plane
->name
);
182 if (to_mdp5_plane_state(old_state
)->pending
) {
183 DBG("%s: still pending!", mdp5_plane
->name
);
187 struct drm_crtc_state
*crtc_state
=
188 drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
189 crtc_state
->mode_changed
= true;
190 to_mdp5_plane_state(state
)->mode_changed
= true;
193 to_mdp5_plane_state(state
)->mode_changed
= true;
199 static void mdp5_plane_atomic_update(struct drm_plane
*plane
,
200 struct drm_plane_state
*old_state
)
202 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
203 struct drm_plane_state
*state
= plane
->state
;
205 DBG("%s: update", mdp5_plane
->name
);
207 if (!plane_enabled(state
)) {
208 to_mdp5_plane_state(state
)->pending
= true;
209 } else if (to_mdp5_plane_state(state
)->mode_changed
) {
211 to_mdp5_plane_state(state
)->pending
= true;
212 ret
= mdp5_plane_mode_set(plane
,
213 state
->crtc
, state
->fb
,
214 state
->crtc_x
, state
->crtc_y
,
215 state
->crtc_w
, state
->crtc_h
,
216 state
->src_x
, state
->src_y
,
217 state
->src_w
, state
->src_h
);
218 /* atomic_check should have ensured that this doesn't fail */
222 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
223 set_scanout_locked(plane
, state
->fb
);
224 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
228 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs
= {
229 .prepare_fb
= mdp5_plane_prepare_fb
,
230 .cleanup_fb
= mdp5_plane_cleanup_fb
,
231 .atomic_check
= mdp5_plane_atomic_check
,
232 .atomic_update
= mdp5_plane_atomic_update
,
235 static void set_scanout_locked(struct drm_plane
*plane
,
236 struct drm_framebuffer
*fb
)
238 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
239 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
240 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
242 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_A(pipe
),
243 MDP5_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
244 MDP5_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
246 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_B(pipe
),
247 MDP5_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
248 MDP5_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
250 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC0_ADDR(pipe
),
251 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 0));
252 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC1_ADDR(pipe
),
253 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 1));
254 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC2_ADDR(pipe
),
255 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 2));
256 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC3_ADDR(pipe
),
257 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 3));
262 /* Note: mdp5_plane->pipe_lock must be locked */
263 static void csc_disable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
)
265 uint32_t value
= mdp5_read(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
)) &
266 ~MDP5_PIPE_OP_MODE_CSC_1_EN
;
268 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), value
);
271 /* Note: mdp5_plane->pipe_lock must be locked */
272 static void csc_enable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
,
275 uint32_t i
, mode
= 0; /* RGB, no CSC */
281 if ((csc
->type
== CSC_YUV2RGB
) || (CSC_YUV2YUV
== csc
->type
))
282 mode
|= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV
);
283 if ((csc
->type
== CSC_RGB2YUV
) || (CSC_YUV2YUV
== csc
->type
))
284 mode
|= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV
);
285 mode
|= MDP5_PIPE_OP_MODE_CSC_1_EN
;
286 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), mode
);
288 matrix
= csc
->matrix
;
289 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe
),
290 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix
[0]) |
291 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix
[1]));
292 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe
),
293 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix
[2]) |
294 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix
[3]));
295 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe
),
296 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix
[4]) |
297 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix
[5]));
298 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe
),
299 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix
[6]) |
300 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix
[7]));
301 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe
),
302 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix
[8]));
304 for (i
= 0; i
< ARRAY_SIZE(csc
->pre_bias
); i
++) {
305 uint32_t *pre_clamp
= csc
->pre_clamp
;
306 uint32_t *post_clamp
= csc
->post_clamp
;
308 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe
, i
),
309 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp
[2*i
+1]) |
310 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp
[2*i
]));
312 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe
, i
),
313 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp
[2*i
+1]) |
314 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp
[2*i
]));
316 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe
, i
),
317 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc
->pre_bias
[i
]));
319 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe
, i
),
320 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc
->post_bias
[i
]));
324 #define PHASE_STEP_SHIFT 21
325 #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
327 static int calc_phase_step(uint32_t src
, uint32_t dst
, uint32_t *out_phase
)
331 if (src
== 0 || dst
== 0)
335 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
336 * where 2^21 represents the unity "1" in fixed-point hardware design.
337 * This leaves 5 bits for the integer part (downscale case):
338 * -> maximum downscale ratio = 0b1_1111 = 31
340 if (src
> (dst
* DOWN_SCALE_RATIO_MAX
))
343 unit
= 1 << PHASE_STEP_SHIFT
;
344 *out_phase
= mult_frac(unit
, src
, dst
);
349 static int calc_scalex_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
350 uint32_t phasex_steps
[2])
352 uint32_t phasex_step
;
356 ret
= calc_phase_step(src
, dest
, &phasex_step
);
360 hsub
= drm_format_horz_chroma_subsampling(pixel_format
);
362 phasex_steps
[0] = phasex_step
;
363 phasex_steps
[1] = phasex_step
/ hsub
;
368 static int calc_scaley_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
369 uint32_t phasey_steps
[2])
371 uint32_t phasey_step
;
375 ret
= calc_phase_step(src
, dest
, &phasey_step
);
379 vsub
= drm_format_vert_chroma_subsampling(pixel_format
);
381 phasey_steps
[0] = phasey_step
;
382 phasey_steps
[1] = phasey_step
/ vsub
;
387 static uint32_t get_scalex_config(uint32_t src
, uint32_t dest
)
391 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
393 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN
|
394 MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter
) |
395 MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter
) |
396 MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter
);
399 static uint32_t get_scaley_config(uint32_t src
, uint32_t dest
)
403 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
405 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN
|
406 MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter
) |
407 MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter
) |
408 MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter
);
411 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
412 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
413 int crtc_x
, int crtc_y
,
414 unsigned int crtc_w
, unsigned int crtc_h
,
415 uint32_t src_x
, uint32_t src_y
,
416 uint32_t src_w
, uint32_t src_h
)
418 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
419 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
420 struct device
*dev
= mdp5_kms
->dev
->dev
;
421 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
422 const struct mdp_format
*format
;
423 uint32_t nplanes
, config
= 0;
424 /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
425 uint32_t phasex_step
[2] = {0,}, phasey_step
[2] = {0,};
426 uint32_t hdecm
= 0, vdecm
= 0;
431 nplanes
= drm_format_num_planes(fb
->pixel_format
);
433 /* bad formats should already be rejected: */
434 if (WARN_ON(nplanes
> pipe2nclients(pipe
)))
437 format
= to_mdp_format(msm_framebuffer_format(fb
));
438 pix_format
= format
->base
.pixel_format
;
440 /* src values are in Q16 fixed point, convert to integer: */
446 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane
->name
,
447 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
448 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
450 /* Request some memory from the SMP: */
451 ret
= mdp5_smp_request(mdp5_kms
->smp
,
452 mdp5_plane
->pipe
, fb
->pixel_format
, src_w
);
457 * Currently we update the hw for allocations/requests immediately,
458 * but once atomic modeset/pageflip is in place, the allocation
459 * would move into atomic->check_plane_state(), while updating the
460 * hw would remain here:
462 mdp5_smp_configure(mdp5_kms
->smp
, pipe
);
464 /* SCALE is used to both scale and up-sample chroma components */
466 if ((src_w
!= crtc_w
) || MDP_FORMAT_IS_YUV(format
)) {
467 /* TODO calc hdecm */
468 ret
= calc_scalex_steps(pix_format
, src_w
, crtc_w
, phasex_step
);
470 dev_err(dev
, "X scaling (%d -> %d) failed: %d\n",
474 config
|= get_scalex_config(src_w
, crtc_w
);
477 if ((src_h
!= crtc_h
) || MDP_FORMAT_IS_YUV(format
)) {
478 /* TODO calc vdecm */
479 ret
= calc_scaley_steps(pix_format
, src_h
, crtc_h
, phasey_step
);
481 dev_err(dev
, "Y scaling (%d -> %d) failed: %d\n",
485 config
|= get_scaley_config(src_h
, crtc_h
);
488 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
490 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe
),
491 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb
->width
) |
492 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb
->height
));
494 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_SIZE(pipe
),
495 MDP5_PIPE_SRC_SIZE_WIDTH(src_w
) |
496 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h
));
498 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_XY(pipe
),
499 MDP5_PIPE_SRC_XY_X(src_x
) |
500 MDP5_PIPE_SRC_XY_Y(src_y
));
502 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_SIZE(pipe
),
503 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w
) |
504 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h
));
506 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_XY(pipe
),
507 MDP5_PIPE_OUT_XY_X(crtc_x
) |
508 MDP5_PIPE_OUT_XY_Y(crtc_y
));
510 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_FORMAT(pipe
),
511 MDP5_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
512 MDP5_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
513 MDP5_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
514 MDP5_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
515 COND(format
->alpha_enable
, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
516 MDP5_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
517 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
518 COND(format
->unpack_tight
, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT
) |
519 MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format
->fetch_type
) |
520 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
));
522 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_UNPACK(pipe
),
523 MDP5_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
524 MDP5_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
525 MDP5_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
526 MDP5_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
528 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_OP_MODE(pipe
),
529 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS
));
531 /* not using secure mode: */
532 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe
), 0);
534 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe
),
536 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe
),
538 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe
),
540 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe
),
542 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_DECIMATION(pipe
),
543 MDP5_PIPE_DECIMATION_VERT(vdecm
) |
544 MDP5_PIPE_DECIMATION_HORZ(hdecm
));
545 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CONFIG(pipe
), config
);
547 if (MDP_FORMAT_IS_YUV(format
))
548 csc_enable(mdp5_kms
, pipe
,
549 mdp_get_default_csc_cfg(CSC_YUV2RGB
));
551 csc_disable(mdp5_kms
, pipe
);
553 set_scanout_locked(plane
, fb
);
555 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
560 void mdp5_plane_complete_flip(struct drm_plane
*plane
)
562 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
563 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
564 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
566 DBG("%s: complete flip", mdp5_plane
->name
);
568 mdp5_smp_commit(mdp5_kms
->smp
, pipe
);
570 to_mdp5_plane_state(plane
->state
)->pending
= false;
573 enum mdp5_pipe
mdp5_plane_pipe(struct drm_plane
*plane
)
575 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
576 return mdp5_plane
->pipe
;
579 uint32_t mdp5_plane_get_flush(struct drm_plane
*plane
)
581 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
583 return mdp5_plane
->flush_mask
;
586 /* called after vsync in thread context */
587 void mdp5_plane_complete_commit(struct drm_plane
*plane
,
588 struct drm_plane_state
*state
)
590 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
591 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
592 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
594 if (!plane_enabled(plane
->state
)) {
595 DBG("%s: free SMP", mdp5_plane
->name
);
596 mdp5_smp_release(mdp5_kms
->smp
, pipe
);
600 /* initialize plane */
601 struct drm_plane
*mdp5_plane_init(struct drm_device
*dev
,
602 enum mdp5_pipe pipe
, bool private_plane
, uint32_t reg_offset
)
604 struct drm_plane
*plane
= NULL
;
605 struct mdp5_plane
*mdp5_plane
;
607 enum drm_plane_type type
;
609 mdp5_plane
= kzalloc(sizeof(*mdp5_plane
), GFP_KERNEL
);
615 plane
= &mdp5_plane
->base
;
617 mdp5_plane
->pipe
= pipe
;
618 mdp5_plane
->name
= pipe2name(pipe
);
620 mdp5_plane
->nformats
= mdp5_get_formats(pipe
, mdp5_plane
->formats
,
621 ARRAY_SIZE(mdp5_plane
->formats
));
623 mdp5_plane
->flush_mask
= mdp_ctl_flush_mask_pipe(pipe
);
624 mdp5_plane
->reg_offset
= reg_offset
;
625 spin_lock_init(&mdp5_plane
->pipe_lock
);
627 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
628 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp5_plane_funcs
,
629 mdp5_plane
->formats
, mdp5_plane
->nformats
,
634 drm_plane_helper_add(plane
, &mdp5_plane_helper_funcs
);
636 mdp5_plane_install_properties(plane
, &plane
->base
);
642 mdp5_plane_destroy(plane
);