2 * Copyright (C) 2014-2015 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 */
31 uint32_t flush_mask
; /* used to commit pipe registers */
36 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
38 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
39 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
40 int crtc_x
, int crtc_y
,
41 unsigned int crtc_w
, unsigned int crtc_h
,
42 uint32_t src_x
, uint32_t src_y
,
43 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 void mdp5_plane_destroy(struct drm_plane
*plane
)
61 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
63 drm_plane_helper_disable(plane
);
64 drm_plane_cleanup(plane
);
69 static void mdp5_plane_install_rotation_property(struct drm_device
*dev
,
70 struct drm_plane
*plane
)
72 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
74 if (!(mdp5_plane
->caps
& MDP_PIPE_CAP_HFLIP
) &&
75 !(mdp5_plane
->caps
& MDP_PIPE_CAP_VFLIP
))
78 if (!dev
->mode_config
.rotation_property
)
79 dev
->mode_config
.rotation_property
=
80 drm_mode_create_rotation_property(dev
,
81 BIT(DRM_REFLECT_X
) | BIT(DRM_REFLECT_Y
));
83 if (dev
->mode_config
.rotation_property
)
84 drm_object_attach_property(&plane
->base
,
85 dev
->mode_config
.rotation_property
,
89 /* helper to install properties which are common to planes and crtcs */
90 static void mdp5_plane_install_properties(struct drm_plane
*plane
,
91 struct drm_mode_object
*obj
)
93 struct drm_device
*dev
= plane
->dev
;
94 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
95 struct drm_property
*prop
;
97 #define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
98 prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
100 prop = drm_property_##fnc(dev, 0, #name, \
104 "Create property %s failed\n", \
108 dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
110 drm_object_attach_property(&plane->base, prop, init_val); \
113 #define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
114 INSTALL_PROPERTY(name, NAME, init_val, \
115 create_range, min, max)
117 #define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
118 INSTALL_PROPERTY(name, NAME, init_val, \
119 create_enum, name##_prop_enum_list, \
120 ARRAY_SIZE(name##_prop_enum_list))
122 INSTALL_RANGE_PROPERTY(zpos
, ZPOS
, 1, 255, 1);
124 mdp5_plane_install_rotation_property(dev
, plane
);
126 #undef INSTALL_RANGE_PROPERTY
127 #undef INSTALL_ENUM_PROPERTY
128 #undef INSTALL_PROPERTY
131 static int mdp5_plane_atomic_set_property(struct drm_plane
*plane
,
132 struct drm_plane_state
*state
, struct drm_property
*property
,
135 struct drm_device
*dev
= plane
->dev
;
136 struct mdp5_plane_state
*pstate
;
137 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
140 pstate
= to_mdp5_plane_state(state
);
142 #define SET_PROPERTY(name, NAME, type) do { \
143 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
144 pstate->name = (type)val; \
145 DBG("Set property %s %d", #name, (type)val); \
150 SET_PROPERTY(zpos
, ZPOS
, uint8_t);
152 dev_err(dev
->dev
, "Invalid property\n");
159 static int mdp5_plane_atomic_get_property(struct drm_plane
*plane
,
160 const struct drm_plane_state
*state
,
161 struct drm_property
*property
, uint64_t *val
)
163 struct drm_device
*dev
= plane
->dev
;
164 struct mdp5_plane_state
*pstate
;
165 struct msm_drm_private
*dev_priv
= dev
->dev_private
;
168 pstate
= to_mdp5_plane_state(state
);
170 #define GET_PROPERTY(name, NAME, type) do { \
171 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
172 *val = pstate->name; \
173 DBG("Get property %s %lld", #name, *val); \
178 GET_PROPERTY(zpos
, ZPOS
, uint8_t);
180 dev_err(dev
->dev
, "Invalid property\n");
187 static void mdp5_plane_reset(struct drm_plane
*plane
)
189 struct mdp5_plane_state
*mdp5_state
;
191 if (plane
->state
&& plane
->state
->fb
)
192 drm_framebuffer_unreference(plane
->state
->fb
);
194 kfree(to_mdp5_plane_state(plane
->state
));
195 mdp5_state
= kzalloc(sizeof(*mdp5_state
), GFP_KERNEL
);
197 /* assign default blend parameters */
198 mdp5_state
->alpha
= 255;
199 mdp5_state
->premultiplied
= 0;
201 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
)
202 mdp5_state
->zpos
= STAGE_BASE
;
204 mdp5_state
->zpos
= STAGE0
+ drm_plane_index(plane
);
206 mdp5_state
->base
.plane
= plane
;
208 plane
->state
= &mdp5_state
->base
;
211 static struct drm_plane_state
*
212 mdp5_plane_duplicate_state(struct drm_plane
*plane
)
214 struct mdp5_plane_state
*mdp5_state
;
216 if (WARN_ON(!plane
->state
))
219 mdp5_state
= kmemdup(to_mdp5_plane_state(plane
->state
),
220 sizeof(*mdp5_state
), GFP_KERNEL
);
222 if (mdp5_state
&& mdp5_state
->base
.fb
)
223 drm_framebuffer_reference(mdp5_state
->base
.fb
);
225 mdp5_state
->mode_changed
= false;
226 mdp5_state
->pending
= false;
228 return &mdp5_state
->base
;
231 static void mdp5_plane_destroy_state(struct drm_plane
*plane
,
232 struct drm_plane_state
*state
)
235 drm_framebuffer_unreference(state
->fb
);
237 kfree(to_mdp5_plane_state(state
));
240 static const struct drm_plane_funcs mdp5_plane_funcs
= {
241 .update_plane
= drm_atomic_helper_update_plane
,
242 .disable_plane
= drm_atomic_helper_disable_plane
,
243 .destroy
= mdp5_plane_destroy
,
244 .set_property
= drm_atomic_helper_plane_set_property
,
245 .atomic_set_property
= mdp5_plane_atomic_set_property
,
246 .atomic_get_property
= mdp5_plane_atomic_get_property
,
247 .reset
= mdp5_plane_reset
,
248 .atomic_duplicate_state
= mdp5_plane_duplicate_state
,
249 .atomic_destroy_state
= mdp5_plane_destroy_state
,
252 static int mdp5_plane_prepare_fb(struct drm_plane
*plane
,
253 const struct drm_plane_state
*new_state
)
255 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
256 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
257 struct drm_framebuffer
*fb
= new_state
->fb
;
262 DBG("%s: prepare: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
263 return msm_framebuffer_prepare(fb
, mdp5_kms
->id
);
266 static void mdp5_plane_cleanup_fb(struct drm_plane
*plane
,
267 const struct drm_plane_state
*old_state
)
269 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
270 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
271 struct drm_framebuffer
*fb
= old_state
->fb
;
276 DBG("%s: cleanup: FB[%u]", mdp5_plane
->name
, fb
->base
.id
);
277 msm_framebuffer_cleanup(fb
, mdp5_kms
->id
);
280 static int mdp5_plane_atomic_check(struct drm_plane
*plane
,
281 struct drm_plane_state
*state
)
283 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
284 struct drm_plane_state
*old_state
= plane
->state
;
285 const struct mdp_format
*format
;
288 DBG("%s: check (%d -> %d)", mdp5_plane
->name
,
289 plane_enabled(old_state
), plane_enabled(state
));
291 if (plane_enabled(state
)) {
292 format
= to_mdp_format(msm_framebuffer_format(state
->fb
));
293 if (MDP_FORMAT_IS_YUV(format
) &&
294 !pipe_supports_yuv(mdp5_plane
->caps
)) {
295 dev_err(plane
->dev
->dev
,
296 "Pipe doesn't support YUV\n");
301 if (!(mdp5_plane
->caps
& MDP_PIPE_CAP_SCALE
) &&
302 (((state
->src_w
>> 16) != state
->crtc_w
) ||
303 ((state
->src_h
>> 16) != state
->crtc_h
))) {
304 dev_err(plane
->dev
->dev
,
305 "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
306 state
->src_w
>> 16, state
->src_h
>> 16,
307 state
->crtc_w
, state
->crtc_h
);
312 hflip
= !!(state
->rotation
& BIT(DRM_REFLECT_X
));
313 vflip
= !!(state
->rotation
& BIT(DRM_REFLECT_Y
));
314 if ((vflip
&& !(mdp5_plane
->caps
& MDP_PIPE_CAP_VFLIP
)) ||
315 (hflip
&& !(mdp5_plane
->caps
& MDP_PIPE_CAP_HFLIP
))) {
316 dev_err(plane
->dev
->dev
,
317 "Pipe doesn't support flip\n");
323 if (plane_enabled(state
) && plane_enabled(old_state
)) {
324 /* we cannot change SMP block configuration during scanout: */
325 bool full_modeset
= false;
326 if (state
->fb
->pixel_format
!= old_state
->fb
->pixel_format
) {
327 DBG("%s: pixel_format change!", mdp5_plane
->name
);
330 if (state
->src_w
!= old_state
->src_w
) {
331 DBG("%s: src_w change!", mdp5_plane
->name
);
334 if (to_mdp5_plane_state(old_state
)->pending
) {
335 DBG("%s: still pending!", mdp5_plane
->name
);
339 struct drm_crtc_state
*crtc_state
=
340 drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
341 crtc_state
->mode_changed
= true;
342 to_mdp5_plane_state(state
)->mode_changed
= true;
345 to_mdp5_plane_state(state
)->mode_changed
= true;
351 static void mdp5_plane_atomic_update(struct drm_plane
*plane
,
352 struct drm_plane_state
*old_state
)
354 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
355 struct drm_plane_state
*state
= plane
->state
;
357 DBG("%s: update", mdp5_plane
->name
);
359 if (!plane_enabled(state
)) {
360 to_mdp5_plane_state(state
)->pending
= true;
361 } else if (to_mdp5_plane_state(state
)->mode_changed
) {
363 to_mdp5_plane_state(state
)->pending
= true;
364 ret
= mdp5_plane_mode_set(plane
,
365 state
->crtc
, state
->fb
,
366 state
->crtc_x
, state
->crtc_y
,
367 state
->crtc_w
, state
->crtc_h
,
368 state
->src_x
, state
->src_y
,
369 state
->src_w
, state
->src_h
);
370 /* atomic_check should have ensured that this doesn't fail */
374 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
375 set_scanout_locked(plane
, state
->fb
);
376 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
380 static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs
= {
381 .prepare_fb
= mdp5_plane_prepare_fb
,
382 .cleanup_fb
= mdp5_plane_cleanup_fb
,
383 .atomic_check
= mdp5_plane_atomic_check
,
384 .atomic_update
= mdp5_plane_atomic_update
,
387 static void set_scanout_locked(struct drm_plane
*plane
,
388 struct drm_framebuffer
*fb
)
390 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
391 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
392 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
394 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_A(pipe
),
395 MDP5_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
396 MDP5_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
398 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_STRIDE_B(pipe
),
399 MDP5_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
400 MDP5_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
402 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC0_ADDR(pipe
),
403 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 0));
404 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC1_ADDR(pipe
),
405 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 1));
406 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC2_ADDR(pipe
),
407 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 2));
408 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC3_ADDR(pipe
),
409 msm_framebuffer_iova(fb
, mdp5_kms
->id
, 3));
414 /* Note: mdp5_plane->pipe_lock must be locked */
415 static void csc_disable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
)
417 uint32_t value
= mdp5_read(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
)) &
418 ~MDP5_PIPE_OP_MODE_CSC_1_EN
;
420 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), value
);
423 /* Note: mdp5_plane->pipe_lock must be locked */
424 static void csc_enable(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
,
427 uint32_t i
, mode
= 0; /* RGB, no CSC */
433 if ((csc
->type
== CSC_YUV2RGB
) || (CSC_YUV2YUV
== csc
->type
))
434 mode
|= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV
);
435 if ((csc
->type
== CSC_RGB2YUV
) || (CSC_YUV2YUV
== csc
->type
))
436 mode
|= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV
);
437 mode
|= MDP5_PIPE_OP_MODE_CSC_1_EN
;
438 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OP_MODE(pipe
), mode
);
440 matrix
= csc
->matrix
;
441 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe
),
442 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix
[0]) |
443 MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix
[1]));
444 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe
),
445 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix
[2]) |
446 MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix
[3]));
447 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe
),
448 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix
[4]) |
449 MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix
[5]));
450 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe
),
451 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix
[6]) |
452 MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix
[7]));
453 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe
),
454 MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix
[8]));
456 for (i
= 0; i
< ARRAY_SIZE(csc
->pre_bias
); i
++) {
457 uint32_t *pre_clamp
= csc
->pre_clamp
;
458 uint32_t *post_clamp
= csc
->post_clamp
;
460 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe
, i
),
461 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp
[2*i
+1]) |
462 MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp
[2*i
]));
464 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe
, i
),
465 MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp
[2*i
+1]) |
466 MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp
[2*i
]));
468 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe
, i
),
469 MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc
->pre_bias
[i
]));
471 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe
, i
),
472 MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc
->post_bias
[i
]));
476 #define PHASE_STEP_SHIFT 21
477 #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
479 static int calc_phase_step(uint32_t src
, uint32_t dst
, uint32_t *out_phase
)
483 if (src
== 0 || dst
== 0)
487 * PHASE_STEP_X/Y is coded on 26 bits (25:0),
488 * where 2^21 represents the unity "1" in fixed-point hardware design.
489 * This leaves 5 bits for the integer part (downscale case):
490 * -> maximum downscale ratio = 0b1_1111 = 31
492 if (src
> (dst
* DOWN_SCALE_RATIO_MAX
))
495 unit
= 1 << PHASE_STEP_SHIFT
;
496 *out_phase
= mult_frac(unit
, src
, dst
);
501 static int calc_scalex_steps(struct drm_plane
*plane
,
502 uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
503 uint32_t phasex_steps
[COMP_MAX
])
505 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
506 struct device
*dev
= mdp5_kms
->dev
->dev
;
507 uint32_t phasex_step
;
511 ret
= calc_phase_step(src
, dest
, &phasex_step
);
513 dev_err(dev
, "X scaling (%d->%d) failed: %d\n", src
, dest
, ret
);
517 hsub
= drm_format_horz_chroma_subsampling(pixel_format
);
519 phasex_steps
[COMP_0
] = phasex_step
;
520 phasex_steps
[COMP_3
] = phasex_step
;
521 phasex_steps
[COMP_1_2
] = phasex_step
/ hsub
;
526 static int calc_scaley_steps(struct drm_plane
*plane
,
527 uint32_t pixel_format
, uint32_t src
, uint32_t dest
,
528 uint32_t phasey_steps
[COMP_MAX
])
530 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
531 struct device
*dev
= mdp5_kms
->dev
->dev
;
532 uint32_t phasey_step
;
536 ret
= calc_phase_step(src
, dest
, &phasey_step
);
538 dev_err(dev
, "Y scaling (%d->%d) failed: %d\n", src
, dest
, ret
);
542 vsub
= drm_format_vert_chroma_subsampling(pixel_format
);
544 phasey_steps
[COMP_0
] = phasey_step
;
545 phasey_steps
[COMP_3
] = phasey_step
;
546 phasey_steps
[COMP_1_2
] = phasey_step
/ vsub
;
551 static uint32_t get_scale_config(const struct mdp_format
*format
,
552 uint32_t src
, uint32_t dst
, bool horz
)
554 bool scaling
= format
->is_yuv
? true : (src
!= dst
);
555 uint32_t sub
, pix_fmt
= format
->base
.pixel_format
;
556 uint32_t ya_filter
, uv_filter
;
557 bool yuv
= format
->is_yuv
;
563 sub
= horz
? drm_format_horz_chroma_subsampling(pix_fmt
) :
564 drm_format_vert_chroma_subsampling(pix_fmt
);
565 uv_filter
= ((src
/ sub
) <= dst
) ?
566 SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
568 ya_filter
= (src
<= dst
) ? SCALE_FILTER_BIL
: SCALE_FILTER_PCMN
;
571 return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN
|
572 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter
) |
573 MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter
) |
574 COND(yuv
, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter
));
576 return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN
|
577 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter
) |
578 MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter
) |
579 COND(yuv
, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter
));
582 static void calc_pixel_ext(const struct mdp_format
*format
,
583 uint32_t src
, uint32_t dst
, uint32_t phase_step
[2],
584 int pix_ext_edge1
[COMP_MAX
], int pix_ext_edge2
[COMP_MAX
],
587 bool scaling
= format
->is_yuv
? true : (src
!= dst
);
592 * We assume here that:
593 * 1. PCMN filter is used for downscale
594 * 2. bilinear filter is used for upscale
595 * 3. we are in a single pipe configuration
598 for (i
= 0; i
< COMP_MAX
; i
++) {
599 pix_ext_edge1
[i
] = 0;
600 pix_ext_edge2
[i
] = scaling
? 1 : 0;
604 static void mdp5_write_pixel_ext(struct mdp5_kms
*mdp5_kms
, enum mdp5_pipe pipe
,
605 const struct mdp_format
*format
,
606 uint32_t src_w
, int pe_left
[COMP_MAX
], int pe_right
[COMP_MAX
],
607 uint32_t src_h
, int pe_top
[COMP_MAX
], int pe_bottom
[COMP_MAX
])
609 uint32_t pix_fmt
= format
->base
.pixel_format
;
610 uint32_t lr
, tb
, req
;
613 for (i
= 0; i
< COMP_MAX
; i
++) {
614 uint32_t roi_w
= src_w
;
615 uint32_t roi_h
= src_h
;
617 if (format
->is_yuv
&& i
== COMP_1_2
) {
618 roi_w
/= drm_format_horz_chroma_subsampling(pix_fmt
);
619 roi_h
/= drm_format_vert_chroma_subsampling(pix_fmt
);
622 lr
= (pe_left
[i
] >= 0) ?
623 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left
[i
]) :
624 MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left
[i
]);
626 lr
|= (pe_right
[i
] >= 0) ?
627 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right
[i
]) :
628 MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right
[i
]);
630 tb
= (pe_top
[i
] >= 0) ?
631 MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top
[i
]) :
632 MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top
[i
]);
634 tb
|= (pe_bottom
[i
] >= 0) ?
635 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom
[i
]) :
636 MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom
[i
]);
638 req
= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w
+
639 pe_left
[i
] + pe_right
[i
]);
641 req
|= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h
+
642 pe_top
[i
] + pe_bottom
[i
]);
644 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe
, i
), lr
);
645 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe
, i
), tb
);
646 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe
, i
), req
);
648 DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i
,
649 FIELD(lr
, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT
),
650 FIELD(lr
, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT
),
651 FIELD(lr
, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF
),
652 FIELD(lr
, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF
),
653 FIELD(req
, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT
));
655 DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i
,
656 FIELD(tb
, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT
),
657 FIELD(tb
, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT
),
658 FIELD(tb
, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF
),
659 FIELD(tb
, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF
),
660 FIELD(req
, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM
));
665 static int mdp5_plane_mode_set(struct drm_plane
*plane
,
666 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
667 int crtc_x
, int crtc_y
,
668 unsigned int crtc_w
, unsigned int crtc_h
,
669 uint32_t src_x
, uint32_t src_y
,
670 uint32_t src_w
, uint32_t src_h
)
672 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
673 struct drm_plane_state
*pstate
= plane
->state
;
674 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
675 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
676 const struct mdp_format
*format
;
677 uint32_t nplanes
, config
= 0;
678 uint32_t phasex_step
[COMP_MAX
] = {0,}, phasey_step
[COMP_MAX
] = {0,};
679 bool pe
= mdp5_plane
->caps
& MDP_PIPE_CAP_SW_PIX_EXT
;
680 int pe_left
[COMP_MAX
], pe_right
[COMP_MAX
];
681 int pe_top
[COMP_MAX
], pe_bottom
[COMP_MAX
];
682 uint32_t hdecm
= 0, vdecm
= 0;
688 nplanes
= drm_format_num_planes(fb
->pixel_format
);
690 /* bad formats should already be rejected: */
691 if (WARN_ON(nplanes
> pipe2nclients(pipe
)))
694 format
= to_mdp_format(msm_framebuffer_format(fb
));
695 pix_format
= format
->base
.pixel_format
;
697 /* src values are in Q16 fixed point, convert to integer: */
703 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane
->name
,
704 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
705 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
707 /* Request some memory from the SMP: */
709 ret
= mdp5_smp_request(mdp5_kms
->smp
,
710 mdp5_plane
->pipe
, format
, src_w
, false);
716 * Currently we update the hw for allocations/requests immediately,
717 * but once atomic modeset/pageflip is in place, the allocation
718 * would move into atomic->check_plane_state(), while updating the
719 * hw would remain here:
722 mdp5_smp_configure(mdp5_kms
->smp
, pipe
);
724 ret
= calc_scalex_steps(plane
, pix_format
, src_w
, crtc_w
, phasex_step
);
728 ret
= calc_scaley_steps(plane
, pix_format
, src_h
, crtc_h
, phasey_step
);
732 if (mdp5_plane
->caps
& MDP_PIPE_CAP_SW_PIX_EXT
) {
733 calc_pixel_ext(format
, src_w
, crtc_w
, phasex_step
,
734 pe_left
, pe_right
, true);
735 calc_pixel_ext(format
, src_h
, crtc_h
, phasey_step
,
736 pe_top
, pe_bottom
, false);
739 /* TODO calc hdecm, vdecm */
741 /* SCALE is used to both scale and up-sample chroma components */
742 config
|= get_scale_config(format
, src_w
, crtc_w
, true);
743 config
|= get_scale_config(format
, src_h
, crtc_h
, false);
744 DBG("scale config = %x", config
);
746 hflip
= !!(pstate
->rotation
& BIT(DRM_REFLECT_X
));
747 vflip
= !!(pstate
->rotation
& BIT(DRM_REFLECT_Y
));
749 spin_lock_irqsave(&mdp5_plane
->pipe_lock
, flags
);
751 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe
),
752 MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb
->width
) |
753 MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb
->height
));
755 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_SIZE(pipe
),
756 MDP5_PIPE_SRC_SIZE_WIDTH(src_w
) |
757 MDP5_PIPE_SRC_SIZE_HEIGHT(src_h
));
759 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_XY(pipe
),
760 MDP5_PIPE_SRC_XY_X(src_x
) |
761 MDP5_PIPE_SRC_XY_Y(src_y
));
763 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_SIZE(pipe
),
764 MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w
) |
765 MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h
));
767 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_OUT_XY(pipe
),
768 MDP5_PIPE_OUT_XY_X(crtc_x
) |
769 MDP5_PIPE_OUT_XY_Y(crtc_y
));
771 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_FORMAT(pipe
),
772 MDP5_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
773 MDP5_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
774 MDP5_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
775 MDP5_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
776 COND(format
->alpha_enable
, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
777 MDP5_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
778 MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
779 COND(format
->unpack_tight
, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT
) |
780 MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format
->fetch_type
) |
781 MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
));
783 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_UNPACK(pipe
),
784 MDP5_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
785 MDP5_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
786 MDP5_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
787 MDP5_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
789 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_OP_MODE(pipe
),
790 (hflip
? MDP5_PIPE_SRC_OP_MODE_FLIP_LR
: 0) |
791 (vflip
? MDP5_PIPE_SRC_OP_MODE_FLIP_UD
: 0) |
792 COND(pe
, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE
) |
793 MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS
));
795 /* not using secure mode: */
796 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe
), 0);
798 if (mdp5_plane
->caps
& MDP_PIPE_CAP_SW_PIX_EXT
)
799 mdp5_write_pixel_ext(mdp5_kms
, pipe
, format
,
800 src_w
, pe_left
, pe_right
,
801 src_h
, pe_top
, pe_bottom
);
803 if (mdp5_plane
->caps
& MDP_PIPE_CAP_SCALE
) {
804 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe
),
805 phasex_step
[COMP_0
]);
806 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe
),
807 phasey_step
[COMP_0
]);
808 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe
),
809 phasex_step
[COMP_1_2
]);
810 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe
),
811 phasey_step
[COMP_1_2
]);
812 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_DECIMATION(pipe
),
813 MDP5_PIPE_DECIMATION_VERT(vdecm
) |
814 MDP5_PIPE_DECIMATION_HORZ(hdecm
));
815 mdp5_write(mdp5_kms
, REG_MDP5_PIPE_SCALE_CONFIG(pipe
), config
);
818 if (mdp5_plane
->caps
& MDP_PIPE_CAP_CSC
) {
819 if (MDP_FORMAT_IS_YUV(format
))
820 csc_enable(mdp5_kms
, pipe
,
821 mdp_get_default_csc_cfg(CSC_YUV2RGB
));
823 csc_disable(mdp5_kms
, pipe
);
826 set_scanout_locked(plane
, fb
);
828 spin_unlock_irqrestore(&mdp5_plane
->pipe_lock
, flags
);
833 void mdp5_plane_complete_flip(struct drm_plane
*plane
)
835 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
836 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
837 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
839 DBG("%s: complete flip", mdp5_plane
->name
);
842 mdp5_smp_commit(mdp5_kms
->smp
, pipe
);
844 to_mdp5_plane_state(plane
->state
)->pending
= false;
847 enum mdp5_pipe
mdp5_plane_pipe(struct drm_plane
*plane
)
849 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
850 return mdp5_plane
->pipe
;
853 uint32_t mdp5_plane_get_flush(struct drm_plane
*plane
)
855 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
857 return mdp5_plane
->flush_mask
;
860 /* called after vsync in thread context */
861 void mdp5_plane_complete_commit(struct drm_plane
*plane
,
862 struct drm_plane_state
*state
)
864 struct mdp5_kms
*mdp5_kms
= get_kms(plane
);
865 struct mdp5_plane
*mdp5_plane
= to_mdp5_plane(plane
);
866 enum mdp5_pipe pipe
= mdp5_plane
->pipe
;
868 if (!plane_enabled(plane
->state
) && mdp5_kms
->smp
) {
869 DBG("%s: free SMP", mdp5_plane
->name
);
870 mdp5_smp_release(mdp5_kms
->smp
, pipe
);
874 /* initialize plane */
875 struct drm_plane
*mdp5_plane_init(struct drm_device
*dev
,
876 enum mdp5_pipe pipe
, bool private_plane
, uint32_t reg_offset
,
879 struct drm_plane
*plane
= NULL
;
880 struct mdp5_plane
*mdp5_plane
;
882 enum drm_plane_type type
;
884 mdp5_plane
= kzalloc(sizeof(*mdp5_plane
), GFP_KERNEL
);
890 plane
= &mdp5_plane
->base
;
892 mdp5_plane
->pipe
= pipe
;
893 mdp5_plane
->name
= pipe2name(pipe
);
894 mdp5_plane
->caps
= caps
;
896 mdp5_plane
->nformats
= mdp_get_formats(mdp5_plane
->formats
,
897 ARRAY_SIZE(mdp5_plane
->formats
),
898 !pipe_supports_yuv(mdp5_plane
->caps
));
900 mdp5_plane
->flush_mask
= mdp_ctl_flush_mask_pipe(pipe
);
901 mdp5_plane
->reg_offset
= reg_offset
;
902 spin_lock_init(&mdp5_plane
->pipe_lock
);
904 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
905 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp5_plane_funcs
,
906 mdp5_plane
->formats
, mdp5_plane
->nformats
,
911 drm_plane_helper_add(plane
, &mdp5_plane_helper_funcs
);
913 mdp5_plane_install_properties(plane
, &plane
->base
);
919 mdp5_plane_destroy(plane
);