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 static void mdp5_plane_install_properties(struct drm_plane
*plane
,
69 struct drm_mode_object
*obj
)
71 struct drm_device
*dev
= plane
->dev
;
72 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
73 struct drm_property
*prop
;
75 #define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
76 prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
78 prop = drm_property_##fnc(dev, 0, #name, \
82 "Create property %s failed\n", \
86 dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
88 drm_object_attach_property(&plane->base, prop, init_val); \
91 #define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
92 INSTALL_PROPERTY(name, NAME, init_val, \
93 create_range, min, max)
95 #define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
96 INSTALL_PROPERTY(name, NAME, init_val, \
97 create_enum, name##_prop_enum_list, \
98 ARRAY_SIZE(name##_prop_enum_list))
100 INSTALL_RANGE_PROPERTY(zpos
, ZPOS
, 1, 255, 1);
102 #undef INSTALL_RANGE_PROPERTY
103 #undef INSTALL_ENUM_PROPERTY
104 #undef INSTALL_PROPERTY
107 static int mdp5_plane_atomic_set_property(struct drm_plane
*plane
,
108 struct drm_plane_state
*state
, struct drm_property
*property
,
111 struct drm_device
*dev
= plane
->dev
;
112 struct mdp5_plane_state
*pstate
;
113 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
116 pstate
= to_mdp5_plane_state(state
);
118 #define SET_PROPERTY(name, NAME, type) do { \
119 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
120 pstate->name = (type)val; \
121 DBG("Set property %s %d", #name, (type)val); \
126 SET_PROPERTY(zpos
, ZPOS
, uint8_t);
128 dev_err(dev
->dev
, "Invalid property\n");
135 static int mdp5_plane_set_property(struct drm_plane
*plane
,
136 struct drm_property
*property
, uint64_t val
)
138 return mdp5_plane_atomic_set_property(plane
, plane
->state
, property
,
142 static int mdp5_plane_atomic_get_property(struct drm_plane
*plane
,
143 const struct drm_plane_state
*state
,
144 struct drm_property
*property
, uint64_t *val
)
146 struct drm_device
*dev
= plane
->dev
;
147 struct mdp5_plane_state
*pstate
;
148 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
151 pstate
= to_mdp5_plane_state(state
);
153 #define GET_PROPERTY(name, NAME, type) do { \
154 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
155 *val = pstate->name; \
156 DBG("Get property %s %lld", #name, *val); \
161 GET_PROPERTY(zpos
, ZPOS
, uint8_t);
163 dev_err(dev
->dev
, "Invalid property\n");
170 static void mdp5_plane_reset(struct drm_plane
*plane
)
172 struct mdp5_plane_state
*mdp5_state
;
174 if (plane
->state
&& plane
->state
->fb
)
175 drm_framebuffer_unreference(plane
->state
->fb
);
177 kfree(to_mdp5_plane_state(plane
->state
));
178 mdp5_state
= kzalloc(sizeof(*mdp5_state
), GFP_KERNEL
);
180 /* assign default blend parameters */
181 mdp5_state
->alpha
= 255;
182 mdp5_state
->premultiplied
= 0;
184 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
)
185 mdp5_state
->zpos
= STAGE_BASE
;
187 mdp5_state
->zpos
= STAGE0
+ drm_plane_index(plane
);
189 mdp5_state
->base
.plane
= plane
;
191 plane
->state
= &mdp5_state
->base
;
194 static struct drm_plane_state
*
195 mdp5_plane_duplicate_state(struct drm_plane
*plane
)
197 struct mdp5_plane_state
*mdp5_state
;
199 if (WARN_ON(!plane
->state
))
202 mdp5_state
= kmemdup(to_mdp5_plane_state(plane
->state
),
203 sizeof(*mdp5_state
), GFP_KERNEL
);
205 if (mdp5_state
&& mdp5_state
->base
.fb
)
206 drm_framebuffer_reference(mdp5_state
->base
.fb
);
208 mdp5_state
->mode_changed
= false;
209 mdp5_state
->pending
= false;
211 return &mdp5_state
->base
;
214 static void mdp5_plane_destroy_state(struct drm_plane
*plane
,
215 struct drm_plane_state
*state
)
218 drm_framebuffer_unreference(state
->fb
);
220 kfree(to_mdp5_plane_state(state
));
223 static const struct drm_plane_funcs mdp5_plane_funcs
= {
224 .update_plane
= drm_atomic_helper_update_plane
,
225 .disable_plane
= drm_atomic_helper_disable_plane
,
226 .destroy
= mdp5_plane_destroy
,
227 .set_property
= mdp5_plane_set_property
,
228 .atomic_set_property
= mdp5_plane_atomic_set_property
,
229 .atomic_get_property
= mdp5_plane_atomic_get_property
,
230 .reset
= mdp5_plane_reset
,
231 .atomic_duplicate_state
= mdp5_plane_duplicate_state
,
232 .atomic_destroy_state
= mdp5_plane_destroy_state
,
235 static int mdp5_plane_prepare_fb(struct drm_plane
*plane
,
236 struct drm_framebuffer
*fb
,
237 const struct drm_plane_state
*new_state
)
239 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
240 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
242 DBG("%s: prepare: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
243 return msm_framebuffer_prepare(fb
, mdp5_kms
->id
);
246 static void mdp5_plane_cleanup_fb(struct drm_plane
*plane
,
247 struct drm_framebuffer
*fb
,
248 const struct drm_plane_state
*old_state
)
250 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
251 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
253 DBG("%s: cleanup: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
254 msm_framebuffer_cleanup(fb
, mdp5_kms
->id
);
257 static int mdp5_plane_atomic_check(struct drm_plane
*plane
,
258 struct drm_plane_state
*state
)
260 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
261 struct drm_plane_state
*old_state
= plane
->state
;
263 DBG("%s: check (%d -> %d)", mdp5_plane
->name
,
264 plane_enabled(old_state
), plane_enabled(state
));
266 if (plane_enabled(state
) && plane_enabled(old_state
)) {
267 /* we cannot change SMP block configuration during scanout: */
268 bool full_modeset
= false;
269 if (state
->fb
->pixel_format
!= old_state
->fb
->pixel_format
) {
270 DBG("%s: pixel_format change!", mdp5_plane
->name
);
273 if (state
->src_w
!= old_state
->src_w
) {
274 DBG("%s: src_w change!", mdp5_plane
->name
);
277 if (to_mdp5_plane_state(old_state
)->pending
) {
278 DBG("%s: still pending!", mdp5_plane
->name
);
282 struct drm_crtc_state
*crtc_state
=
283 drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
284 crtc_state
->mode_changed
= true;
285 to_mdp5_plane_state(state
)->mode_changed
= true;
288 to_mdp5_plane_state(state
)->mode_changed
= true;
294 static void mdp5_plane_atomic_update(struct drm_plane
*plane
,
295 struct drm_plane_state
*old_state
)
297 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
298 struct drm_plane_state
*state
= plane
->state
;
300 DBG("%s: update", mdp5_plane
->name
);
302 if (!plane_enabled(state
)) {
303 to_mdp5_plane_state(state
)->pending
= true;
304 } else if (to_mdp5_plane_state(state
)->mode_changed
) {
306 to_mdp5_plane_state(state
)->pending
= true;
307 ret
= mdp5_plane_mode_set(plane
,
308 state
->crtc
, state
->fb
,
309 state
->crtc_x
, state
->crtc_y
,
310 state
->crtc_w
, state
->crtc_h
,
311 state
->src_x
, state
->src_y
,
312 state
->src_w
, state
->src_h
);
313 /* atomic_check should have ensured that this doesn't fail */
317 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
318 set_scanout_locked(plane
, state
->fb
);
319 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
323 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs
= {
324 .prepare_fb
= mdp5_plane_prepare_fb
,
325 .cleanup_fb
= mdp5_plane_cleanup_fb
,
326 .atomic_check
= mdp5_plane_atomic_check
,
327 .atomic_update
= mdp5_plane_atomic_update
,
330 static void set_scanout_locked(struct drm_plane
*plane
,
331 struct drm_framebuffer
*fb
)
333 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
334 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
335 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
337 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_A(pipe
),
338 MDP5_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
339 MDP5_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
341 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_B(pipe
),
342 MDP5_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
343 MDP5_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
345 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC0_ADDR(pipe
),
346 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 0));
347 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC1_ADDR(pipe
),
348 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 1));
349 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC2_ADDR(pipe
),
350 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 2));
351 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC3_ADDR(pipe
),
352 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 3));
357 /* Note: mdp5_plane->pipe_lock must be locked */
358 static void csc_disable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
)
360 uint32_t value
= mdp5_read(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
)) &
361 ~MDP5_PIPE_OP_MODE_CSC_1_EN
;
363 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), value
);
366 /* Note: mdp5_plane->pipe_lock must be locked */
367 static void csc_enable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
,
370 uint32_t i
, mode
= 0; /* RGB, no CSC */
376 if ((csc
->type
== CSC_YUV2RGB
) || (CSC_YUV2YUV
== csc
->type
))
377 mode
|= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV
);
378 if ((csc
->type
== CSC_RGB2YUV
) || (CSC_YUV2YUV
== csc
->type
))
379 mode
|= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV
);
380 mode
|= MDP5_PIPE_OP_MODE_CSC_1_EN
;
381 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), mode
);
383 matrix
= csc
->matrix
;
384 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe
),
385 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix
[0]) |
386 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix
[1]));
387 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe
),
388 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix
[2]) |
389 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix
[3]));
390 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe
),
391 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix
[4]) |
392 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix
[5]));
393 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe
),
394 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix
[6]) |
395 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix
[7]));
396 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe
),
397 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix
[8]));
399 for (i
= 0; i
< ARRAY_SIZE(csc
->pre_bias
); i
++) {
400 uint32_t *pre_clamp
= csc
->pre_clamp
;
401 uint32_t *post_clamp
= csc
->post_clamp
;
403 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe
, i
),
404 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp
[2*i
+1]) |
405 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp
[2*i
]));
407 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe
, i
),
408 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp
[2*i
+1]) |
409 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp
[2*i
]));
411 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe
, i
),
412 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc
->pre_bias
[i
]));
414 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe
, i
),
415 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc
->post_bias
[i
]));
419 #define PHASE_STEP_SHIFT 21
420 #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
422 static int calc_phase_step(uint32_t src
, uint32_t dst
, uint32_t *out_phase
)
426 if (src
== 0 || dst
== 0)
430 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
431 * where 2^21 represents the unity "1" in fixed-point hardware design.
432 * This leaves 5 bits for the integer part (downscale case):
433 * -> maximum downscale ratio = 0b1_1111 = 31
435 if (src
> (dst
* DOWN_SCALE_RATIO_MAX
))
438 unit
= 1 << PHASE_STEP_SHIFT
;
439 *out_phase
= mult_frac(unit
, src
, dst
);
444 static int calc_scalex_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
445 uint32_t phasex_steps
[2])
447 uint32_t phasex_step
;
451 ret
= calc_phase_step(src
, dest
, &phasex_step
);
455 hsub
= drm_format_horz_chroma_subsampling(pixel_format
);
457 phasex_steps
[0] = phasex_step
;
458 phasex_steps
[1] = phasex_step
/ hsub
;
463 static int calc_scaley_steps(uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
464 uint32_t phasey_steps
[2])
466 uint32_t phasey_step
;
470 ret
= calc_phase_step(src
, dest
, &phasey_step
);
474 vsub
= drm_format_vert_chroma_subsampling(pixel_format
);
476 phasey_steps
[0] = phasey_step
;
477 phasey_steps
[1] = phasey_step
/ vsub
;
482 static uint32_t get_scalex_config(uint32_t src
, uint32_t dest
)
486 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
488 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN
|
489 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(filter
) |
490 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(filter
) |
491 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(filter
);
494 static uint32_t get_scaley_config(uint32_t src
, uint32_t dest
)
498 filter
= (src
<= dest
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
500 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN
|
501 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(filter
) |
502 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(filter
) |
503 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(filter
);
506 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
507 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
508 int crtc_x
, int crtc_y
,
509 unsigned int crtc_w
, unsigned int crtc_h
,
510 uint32_t src_x
, uint32_t src_y
,
511 uint32_t src_w
, uint32_t src_h
)
513 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
514 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
515 struct device
*dev
= mdp5_kms
->dev
->dev
;
516 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
517 const struct mdp_format
*format
;
518 uint32_t nplanes
, config
= 0;
519 /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
520 uint32_t phasex_step
[2] = {0,}, phasey_step
[2] = {0,};
521 uint32_t hdecm
= 0, vdecm
= 0;
526 nplanes
= drm_format_num_planes(fb
->pixel_format
);
528 /* bad formats should already be rejected: */
529 if (WARN_ON(nplanes
> pipe2nclients(pipe
)))
532 format
= to_mdp_format(msm_framebuffer_format(fb
));
533 pix_format
= format
->base
.pixel_format
;
535 /* src values are in Q16 fixed point, convert to integer: */
541 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane
->name
,
542 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
543 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
545 /* Request some memory from the SMP: */
546 ret
= mdp5_smp_request(mdp5_kms
->smp
,
547 mdp5_plane
->pipe
, fb
->pixel_format
, src_w
);
552 * Currently we update the hw for allocations/requests immediately,
553 * but once atomic modeset/pageflip is in place, the allocation
554 * would move into atomic->check_plane_state(), while updating the
555 * hw would remain here:
557 mdp5_smp_configure(mdp5_kms
->smp
, pipe
);
559 /* SCALE is used to both scale and up-sample chroma components */
561 if ((src_w
!= crtc_w
) || MDP_FORMAT_IS_YUV(format
)) {
562 /* TODO calc hdecm */
563 ret
= calc_scalex_steps(pix_format
, src_w
, crtc_w
, phasex_step
);
565 dev_err(dev
, "X scaling (%d -> %d) failed: %d\n",
569 config
|= get_scalex_config(src_w
, crtc_w
);
572 if ((src_h
!= crtc_h
) || MDP_FORMAT_IS_YUV(format
)) {
573 /* TODO calc vdecm */
574 ret
= calc_scaley_steps(pix_format
, src_h
, crtc_h
, phasey_step
);
576 dev_err(dev
, "Y scaling (%d -> %d) failed: %d\n",
580 config
|= get_scaley_config(src_h
, crtc_h
);
583 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
585 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe
),
586 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb
->width
) |
587 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb
->height
));
589 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_SIZE(pipe
),
590 MDP5_PIPE_SRC_SIZE_WIDTH(src_w
) |
591 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h
));
593 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_XY(pipe
),
594 MDP5_PIPE_SRC_XY_X(src_x
) |
595 MDP5_PIPE_SRC_XY_Y(src_y
));
597 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_SIZE(pipe
),
598 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w
) |
599 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h
));
601 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_XY(pipe
),
602 MDP5_PIPE_OUT_XY_X(crtc_x
) |
603 MDP5_PIPE_OUT_XY_Y(crtc_y
));
605 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_FORMAT(pipe
),
606 MDP5_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
607 MDP5_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
608 MDP5_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
609 MDP5_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
610 COND(format
->alpha_enable
, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
611 MDP5_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
612 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
613 COND(format
->unpack_tight
, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT
) |
614 MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format
->fetch_type
) |
615 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
));
617 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_UNPACK(pipe
),
618 MDP5_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
619 MDP5_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
620 MDP5_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
621 MDP5_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
623 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_OP_MODE(pipe
),
624 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS
));
626 /* not using secure mode: */
627 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe
), 0);
629 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe
),
631 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe
),
633 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe
),
635 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe
),
637 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_DECIMATION(pipe
),
638 MDP5_PIPE_DECIMATION_VERT(vdecm
) |
639 MDP5_PIPE_DECIMATION_HORZ(hdecm
));
640 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CONFIG(pipe
), config
);
642 if (MDP_FORMAT_IS_YUV(format
))
643 csc_enable(mdp5_kms
, pipe
,
644 mdp_get_default_csc_cfg(CSC_YUV2RGB
));
646 csc_disable(mdp5_kms
, pipe
);
648 set_scanout_locked(plane
, fb
);
650 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
655 void mdp5_plane_complete_flip(struct drm_plane
*plane
)
657 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
658 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
659 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
661 DBG("%s: complete flip", mdp5_plane
->name
);
663 mdp5_smp_commit(mdp5_kms
->smp
, pipe
);
665 to_mdp5_plane_state(plane
->state
)->pending
= false;
668 enum mdp5_pipe
mdp5_plane_pipe(struct drm_plane
*plane
)
670 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
671 return mdp5_plane
->pipe
;
674 uint32_t mdp5_plane_get_flush(struct drm_plane
*plane
)
676 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
678 return mdp5_plane
->flush_mask
;
681 /* called after vsync in thread context */
682 void mdp5_plane_complete_commit(struct drm_plane
*plane
,
683 struct drm_plane_state
*state
)
685 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
686 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
687 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
689 if (!plane_enabled(plane
->state
)) {
690 DBG("%s: free SMP", mdp5_plane
->name
);
691 mdp5_smp_release(mdp5_kms
->smp
, pipe
);
695 /* initialize plane */
696 struct drm_plane
*mdp5_plane_init(struct drm_device
*dev
,
697 enum mdp5_pipe pipe
, bool private_plane
, uint32_t reg_offset
)
699 struct drm_plane
*plane
= NULL
;
700 struct mdp5_plane
*mdp5_plane
;
702 enum drm_plane_type type
;
704 mdp5_plane
= kzalloc(sizeof(*mdp5_plane
), GFP_KERNEL
);
710 plane
= &mdp5_plane
->base
;
712 mdp5_plane
->pipe
= pipe
;
713 mdp5_plane
->name
= pipe2name(pipe
);
715 mdp5_plane
->nformats
= mdp5_get_formats(pipe
, mdp5_plane
->formats
,
716 ARRAY_SIZE(mdp5_plane
->formats
));
718 mdp5_plane
->flush_mask
= mdp_ctl_flush_mask_pipe(pipe
);
719 mdp5_plane
->reg_offset
= reg_offset
;
720 spin_lock_init(&mdp5_plane
->pipe_lock
);
722 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
723 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp5_plane_funcs
,
724 mdp5_plane
->formats
, mdp5_plane
->nformats
,
729 drm_plane_helper_add(plane
, &mdp5_plane_helper_funcs
);
731 mdp5_plane_install_properties(plane
, &plane
->base
);
737 mdp5_plane_destroy(plane
);