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 */
37 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
39 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
40 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
41 int crtc_x
, int crtc_y
,
42 unsigned int crtc_w
, unsigned int crtc_h
,
43 uint32_t src_x
, uint32_t src_y
,
44 uint32_t src_w
, uint32_t src_h
);
45 static void set_scanout_locked(struct drm_plane
*plane
,
46 struct drm_framebuffer
*fb
);
48 static struct mdp5_kms
*get_kms(struct drm_plane
*plane
)
50 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
51 return to_mdp5_kms(to_mdp_kms(priv
->kms
));
54 static bool plane_enabled(struct drm_plane_state
*state
)
56 return state
->fb
&& state
->crtc
;
59 static int mdp5_plane_disable(struct drm_plane
*plane
)
61 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
62 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
63 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
65 DBG("%s: disable", mdp5_plane
->name
);
68 /* Release the memory we requested earlier from the SMP: */
69 mdp5_smp_release(mdp5_kms
->smp
, pipe
);
75 static void mdp5_plane_destroy(struct drm_plane
*plane
)
77 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
79 drm_plane_helper_disable(plane
);
80 drm_plane_cleanup(plane
);
85 /* helper to install properties which are common to planes and crtcs */
86 void mdp5_plane_install_properties(struct drm_plane
*plane
,
87 struct drm_mode_object
*obj
)
92 int mdp5_plane_set_property(struct drm_plane
*plane
,
93 struct drm_property
*property
, uint64_t val
)
99 static void mdp5_plane_reset(struct drm_plane
*plane
)
101 struct mdp5_plane_state
*mdp5_state
;
103 if (plane
->state
&& plane
->state
->fb
)
104 drm_framebuffer_unreference(plane
->state
->fb
);
106 kfree(to_mdp5_plane_state(plane
->state
));
107 mdp5_state
= kzalloc(sizeof(*mdp5_state
), GFP_KERNEL
);
109 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
) {
110 mdp5_state
->zpos
= 0;
112 mdp5_state
->zpos
= 1 + drm_plane_index(plane
);
114 mdp5_state
->base
.plane
= plane
;
116 plane
->state
= &mdp5_state
->base
;
119 static struct drm_plane_state
*
120 mdp5_plane_duplicate_state(struct drm_plane
*plane
)
122 struct mdp5_plane_state
*mdp5_state
;
124 if (WARN_ON(!plane
->state
))
127 mdp5_state
= kmemdup(to_mdp5_plane_state(plane
->state
),
128 sizeof(*mdp5_state
), GFP_KERNEL
);
130 if (mdp5_state
&& mdp5_state
->base
.fb
)
131 drm_framebuffer_reference(mdp5_state
->base
.fb
);
133 mdp5_state
->mode_changed
= false;
134 mdp5_state
->pending
= false;
136 return &mdp5_state
->base
;
139 static void mdp5_plane_destroy_state(struct drm_plane
*plane
,
140 struct drm_plane_state
*state
)
143 drm_framebuffer_unreference(state
->fb
);
145 kfree(to_mdp5_plane_state(state
));
148 static const struct drm_plane_funcs mdp5_plane_funcs
= {
149 .update_plane
= drm_atomic_helper_update_plane
,
150 .disable_plane
= drm_atomic_helper_disable_plane
,
151 .destroy
= mdp5_plane_destroy
,
152 .set_property
= mdp5_plane_set_property
,
153 .reset
= mdp5_plane_reset
,
154 .atomic_duplicate_state
= mdp5_plane_duplicate_state
,
155 .atomic_destroy_state
= mdp5_plane_destroy_state
,
158 static int mdp5_plane_prepare_fb(struct drm_plane
*plane
,
159 struct drm_framebuffer
*fb
,
160 const struct drm_plane_state
*new_state
)
162 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
163 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
165 DBG("%s: prepare: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
166 return msm_framebuffer_prepare(fb
, mdp5_kms
->id
);
169 static void mdp5_plane_cleanup_fb(struct drm_plane
*plane
,
170 struct drm_framebuffer
*fb
,
171 const struct drm_plane_state
*old_state
)
173 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
174 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
176 DBG("%s: cleanup: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
177 msm_framebuffer_cleanup(fb
, mdp5_kms
->id
);
180 static int mdp5_plane_atomic_check(struct drm_plane
*plane
,
181 struct drm_plane_state
*state
)
183 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
184 struct drm_plane_state
*old_state
= plane
->state
;
186 DBG("%s: check (%d -> %d)", mdp5_plane
->name
,
187 plane_enabled(old_state
), plane_enabled(state
));
189 if (plane_enabled(state
) && plane_enabled(old_state
)) {
190 /* we cannot change SMP block configuration during scanout: */
191 bool full_modeset
= false;
192 if (state
->fb
->pixel_format
!= old_state
->fb
->pixel_format
) {
193 DBG("%s: pixel_format change!", mdp5_plane
->name
);
196 if (state
->src_w
!= old_state
->src_w
) {
197 DBG("%s: src_w change!", mdp5_plane
->name
);
200 if (to_mdp5_plane_state(old_state
)->pending
) {
201 DBG("%s: still pending!", mdp5_plane
->name
);
205 struct drm_crtc_state
*crtc_state
=
206 drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
207 crtc_state
->mode_changed
= true;
208 to_mdp5_plane_state(state
)->mode_changed
= true;
211 to_mdp5_plane_state(state
)->mode_changed
= true;
217 static void mdp5_plane_atomic_update(struct drm_plane
*plane
,
218 struct drm_plane_state
*old_state
)
220 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
221 struct drm_plane_state
*state
= plane
->state
;
223 DBG("%s: update", mdp5_plane
->name
);
225 if (!plane_enabled(state
)) {
226 to_mdp5_plane_state(state
)->pending
= true;
227 mdp5_plane_disable(plane
);
228 } else if (to_mdp5_plane_state(state
)->mode_changed
) {
230 to_mdp5_plane_state(state
)->pending
= true;
231 ret
= mdp5_plane_mode_set(plane
,
232 state
->crtc
, state
->fb
,
233 state
->crtc_x
, state
->crtc_y
,
234 state
->crtc_w
, state
->crtc_h
,
235 state
->src_x
, state
->src_y
,
236 state
->src_w
, state
->src_h
);
237 /* atomic_check should have ensured that this doesn't fail */
241 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
242 set_scanout_locked(plane
, state
->fb
);
243 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
247 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs
= {
248 .prepare_fb
= mdp5_plane_prepare_fb
,
249 .cleanup_fb
= mdp5_plane_cleanup_fb
,
250 .atomic_check
= mdp5_plane_atomic_check
,
251 .atomic_update
= mdp5_plane_atomic_update
,
254 static void set_scanout_locked(struct drm_plane
*plane
,
255 struct drm_framebuffer
*fb
)
257 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
258 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
259 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
261 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_A(pipe
),
262 MDP5_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
263 MDP5_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
265 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_B(pipe
),
266 MDP5_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
267 MDP5_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
269 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC0_ADDR(pipe
),
270 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 0));
271 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC1_ADDR(pipe
),
272 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 1));
273 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC2_ADDR(pipe
),
274 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 2));
275 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC3_ADDR(pipe
),
276 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 3));
281 /* Note: mdp5_plane->pipe_lock must be locked */
282 static void csc_disable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
)
284 uint32_t value
= mdp5_read(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
)) &
285 ~MDP5_PIPE_OP_MODE_CSC_1_EN
;
287 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), value
);
290 /* Note: mdp5_plane->pipe_lock must be locked */
291 static void csc_enable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
,
294 uint32_t i
, mode
= 0; /* RGB, no CSC */
300 if ((csc
->type
== CSC_YUV2RGB
) || (CSC_YUV2YUV
== csc
->type
))
301 mode
|= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV
);
302 if ((csc
->type
== CSC_RGB2YUV
) || (CSC_YUV2YUV
== csc
->type
))
303 mode
|= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV
);
304 mode
|= MDP5_PIPE_OP_MODE_CSC_1_EN
;
305 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), mode
);
307 matrix
= csc
->matrix
;
308 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe
),
309 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix
[0]) |
310 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix
[1]));
311 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe
),
312 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix
[2]) |
313 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix
[3]));
314 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe
),
315 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix
[4]) |
316 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix
[5]));
317 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe
),
318 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix
[6]) |
319 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix
[7]));
320 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe
),
321 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix
[8]));
323 for (i
= 0; i
< ARRAY_SIZE(csc
->pre_bias
); i
++) {
324 uint32_t *pre_clamp
= csc
->pre_clamp
;
325 uint32_t *post_clamp
= csc
->post_clamp
;
327 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe
, i
),
328 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp
[2*i
+1]) |
329 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp
[2*i
]));
331 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe
, i
),
332 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp
[2*i
+1]) |
333 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp
[2*i
]));
335 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe
, i
),
336 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc
->pre_bias
[i
]));
338 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe
, i
),
339 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc
->post_bias
[i
]));
343 #define PHASE_STEP_SHIFT 21
344 #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
346 static int calc_phase_step(uint32_t src
, uint32_t dst
, uint32_t *out_phase
)
350 if (src
== 0 || dst
== 0)
354 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
355 * where 2^21 represents the unity "1" in fixed-point hardware design.
356 * This leaves 5 bits for the integer part (downscale case):
357 * -> maximum downscale ratio = 0b1_1111 = 31
359 if (src
> (dst
* DOWN_SCALE_RATIO_MAX
))
362 unit
= 1 << PHASE_STEP_SHIFT
;
363 *out_phase
= mult_frac(unit
, src
, dst
);
368 static int calc_scalex_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
369 uint32_t phasex_steps
[2])
371 uint32_t phasex_step
;
375 ret
= calc_phase_step(src
, dest
, &phasex_step
);
379 hsub
= drm_format_horz_chroma_subsampling(pixel_format
);
381 phasex_steps
[0] = phasex_step
;
382 phasex_steps
[1] = phasex_step
/ hsub
;
387 static int calc_scaley_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
388 uint32_t phasey_steps
[2])
390 uint32_t phasey_step
;
394 ret
= calc_phase_step(src
, dest
, &phasey_step
);
398 vsub
= drm_format_vert_chroma_subsampling(pixel_format
);
400 phasey_steps
[0] = phasey_step
;
401 phasey_steps
[1] = phasey_step
/ vsub
;
406 static uint32_t get_scalex_config(uint32_t src
, uint32_t dest
)
410 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
412 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN
|
413 MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter
) |
414 MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter
) |
415 MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter
);
418 static uint32_t get_scaley_config(uint32_t src
, uint32_t dest
)
422 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
424 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN
|
425 MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter
) |
426 MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter
) |
427 MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter
);
430 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
431 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
432 int crtc_x
, int crtc_y
,
433 unsigned int crtc_w
, unsigned int crtc_h
,
434 uint32_t src_x
, uint32_t src_y
,
435 uint32_t src_w
, uint32_t src_h
)
437 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
438 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
439 struct device
*dev
= mdp5_kms
->dev
->dev
;
440 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
441 const struct mdp_format
*format
;
442 uint32_t nplanes
, config
= 0;
443 /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
444 uint32_t phasex_step
[2] = {0,}, phasey_step
[2] = {0,};
445 uint32_t hdecm
= 0, vdecm
= 0;
450 nplanes
= drm_format_num_planes(fb
->pixel_format
);
452 /* bad formats should already be rejected: */
453 if (WARN_ON(nplanes
> pipe2nclients(pipe
)))
456 format
= to_mdp_format(msm_framebuffer_format(fb
));
457 pix_format
= format
->base
.pixel_format
;
459 /* src values are in Q16 fixed point, convert to integer: */
465 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane
->name
,
466 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
467 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
469 /* Request some memory from the SMP: */
470 ret
= mdp5_smp_request(mdp5_kms
->smp
,
471 mdp5_plane
->pipe
, fb
->pixel_format
, src_w
);
476 * Currently we update the hw for allocations/requests immediately,
477 * but once atomic modeset/pageflip is in place, the allocation
478 * would move into atomic->check_plane_state(), while updating the
479 * hw would remain here:
481 mdp5_smp_configure(mdp5_kms
->smp
, pipe
);
483 /* SCALE is used to both scale and up-sample chroma components */
485 if ((src_w
!= crtc_w
) || MDP_FORMAT_IS_YUV(format
)) {
486 /* TODO calc hdecm */
487 ret
= calc_scalex_steps(pix_format
, src_w
, crtc_w
, phasex_step
);
489 dev_err(dev
, "X scaling (%d -> %d) failed: %d\n",
493 config
|= get_scalex_config(src_w
, crtc_w
);
496 if ((src_h
!= crtc_h
) || MDP_FORMAT_IS_YUV(format
)) {
497 /* TODO calc vdecm */
498 ret
= calc_scaley_steps(pix_format
, src_h
, crtc_h
, phasey_step
);
500 dev_err(dev
, "Y scaling (%d -> %d) failed: %d\n",
504 config
|= get_scaley_config(src_h
, crtc_h
);
507 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
509 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe
),
510 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb
->width
) |
511 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb
->height
));
513 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_SIZE(pipe
),
514 MDP5_PIPE_SRC_SIZE_WIDTH(src_w
) |
515 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h
));
517 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_XY(pipe
),
518 MDP5_PIPE_SRC_XY_X(src_x
) |
519 MDP5_PIPE_SRC_XY_Y(src_y
));
521 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_SIZE(pipe
),
522 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w
) |
523 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h
));
525 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_XY(pipe
),
526 MDP5_PIPE_OUT_XY_X(crtc_x
) |
527 MDP5_PIPE_OUT_XY_Y(crtc_y
));
529 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_FORMAT(pipe
),
530 MDP5_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
531 MDP5_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
532 MDP5_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
533 MDP5_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
534 COND(format
->alpha_enable
, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
535 MDP5_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
536 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
537 COND(format
->unpack_tight
, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT
) |
538 MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format
->fetch_type
) |
539 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
));
541 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_UNPACK(pipe
),
542 MDP5_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
543 MDP5_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
544 MDP5_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
545 MDP5_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
547 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_OP_MODE(pipe
),
548 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS
));
550 /* not using secure mode: */
551 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe
), 0);
553 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe
),
555 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe
),
557 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe
),
559 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe
),
561 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_DECIMATION(pipe
),
562 MDP5_PIPE_DECIMATION_VERT(vdecm
) |
563 MDP5_PIPE_DECIMATION_HORZ(hdecm
));
564 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CONFIG(pipe
), config
);
566 if (MDP_FORMAT_IS_YUV(format
))
567 csc_enable(mdp5_kms
, pipe
,
568 mdp_get_default_csc_cfg(CSC_YUV2RGB
));
570 csc_disable(mdp5_kms
, pipe
);
572 set_scanout_locked(plane
, fb
);
574 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
579 void mdp5_plane_complete_flip(struct drm_plane
*plane
)
581 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
582 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
583 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
585 DBG("%s: complete flip", mdp5_plane
->name
);
587 mdp5_smp_commit(mdp5_kms
->smp
, pipe
);
589 to_mdp5_plane_state(plane
->state
)->pending
= false;
592 enum mdp5_pipe
mdp5_plane_pipe(struct drm_plane
*plane
)
594 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
595 return mdp5_plane
->pipe
;
598 uint32_t mdp5_plane_get_flush(struct drm_plane
*plane
)
600 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
602 return mdp5_plane
->flush_mask
;
605 /* initialize plane */
606 struct drm_plane
*mdp5_plane_init(struct drm_device
*dev
,
607 enum mdp5_pipe pipe
, bool private_plane
, uint32_t reg_offset
)
609 struct drm_plane
*plane
= NULL
;
610 struct mdp5_plane
*mdp5_plane
;
612 enum drm_plane_type type
;
614 mdp5_plane
= kzalloc(sizeof(*mdp5_plane
), GFP_KERNEL
);
620 plane
= &mdp5_plane
->base
;
622 mdp5_plane
->pipe
= pipe
;
623 mdp5_plane
->name
= pipe2name(pipe
);
625 mdp5_plane
->nformats
= mdp5_get_formats(pipe
, mdp5_plane
->formats
,
626 ARRAY_SIZE(mdp5_plane
->formats
));
628 mdp5_plane
->flush_mask
= mdp_ctl_flush_mask_pipe(pipe
);
629 mdp5_plane
->reg_offset
= reg_offset
;
630 spin_lock_init(&mdp5_plane
->pipe_lock
);
632 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
633 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp5_plane_funcs
,
634 mdp5_plane
->formats
, mdp5_plane
->nformats
,
639 drm_plane_helper_add(plane
, &mdp5_plane_helper_funcs
);
641 mdp5_plane_install_properties(plane
, &plane
->base
);
647 mdp5_plane_destroy(plane
);