2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
20 #define DOWN_SCALE_MAX 8
21 #define UP_SCALE_MAX 8
24 struct drm_plane base
;
35 #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base)
37 /* MDP format helper functions */
39 enum mdp4_frame_format
mdp4_get_frame_format(struct drm_framebuffer
*fb
)
43 if (fb
->modifier
== DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
)
46 if (fb
->pixel_format
== DRM_FORMAT_NV12
&& is_tile
)
47 return FRAME_TILE_YCBCR_420
;
52 static void mdp4_plane_set_scanout(struct drm_plane
*plane
,
53 struct drm_framebuffer
*fb
);
54 static int mdp4_plane_mode_set(struct drm_plane
*plane
,
55 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
56 int crtc_x
, int crtc_y
,
57 unsigned int crtc_w
, unsigned int crtc_h
,
58 uint32_t src_x
, uint32_t src_y
,
59 uint32_t src_w
, uint32_t src_h
);
61 static struct mdp4_kms
*get_kms(struct drm_plane
*plane
)
63 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
64 return to_mdp4_kms(to_mdp_kms(priv
->kms
));
67 static void mdp4_plane_destroy(struct drm_plane
*plane
)
69 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
71 drm_plane_helper_disable(plane
);
72 drm_plane_cleanup(plane
);
77 /* helper to install properties which are common to planes and crtcs */
78 static void mdp4_plane_install_properties(struct drm_plane
*plane
,
79 struct drm_mode_object
*obj
)
84 static int mdp4_plane_set_property(struct drm_plane
*plane
,
85 struct drm_property
*property
, uint64_t val
)
91 static const struct drm_plane_funcs mdp4_plane_funcs
= {
92 .update_plane
= drm_atomic_helper_update_plane
,
93 .disable_plane
= drm_atomic_helper_disable_plane
,
94 .destroy
= mdp4_plane_destroy
,
95 .set_property
= mdp4_plane_set_property
,
96 .reset
= drm_atomic_helper_plane_reset
,
97 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
98 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
101 static int mdp4_plane_prepare_fb(struct drm_plane
*plane
,
102 struct drm_plane_state
*new_state
)
104 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
105 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
106 struct drm_framebuffer
*fb
= new_state
->fb
;
111 DBG("%s: prepare: FB[%u]", mdp4_plane
->name
, fb
->base
.id
);
112 return msm_framebuffer_prepare(fb
, mdp4_kms
->id
);
115 static void mdp4_plane_cleanup_fb(struct drm_plane
*plane
,
116 struct drm_plane_state
*old_state
)
118 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
119 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
120 struct drm_framebuffer
*fb
= old_state
->fb
;
125 DBG("%s: cleanup: FB[%u]", mdp4_plane
->name
, fb
->base
.id
);
126 msm_framebuffer_cleanup(fb
, mdp4_kms
->id
);
130 static int mdp4_plane_atomic_check(struct drm_plane
*plane
,
131 struct drm_plane_state
*state
)
136 static void mdp4_plane_atomic_update(struct drm_plane
*plane
,
137 struct drm_plane_state
*old_state
)
139 struct drm_plane_state
*state
= plane
->state
;
142 ret
= mdp4_plane_mode_set(plane
,
143 state
->crtc
, state
->fb
,
144 state
->crtc_x
, state
->crtc_y
,
145 state
->crtc_w
, state
->crtc_h
,
146 state
->src_x
, state
->src_y
,
147 state
->src_w
, state
->src_h
);
148 /* atomic_check should have ensured that this doesn't fail */
152 static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs
= {
153 .prepare_fb
= mdp4_plane_prepare_fb
,
154 .cleanup_fb
= mdp4_plane_cleanup_fb
,
155 .atomic_check
= mdp4_plane_atomic_check
,
156 .atomic_update
= mdp4_plane_atomic_update
,
159 static void mdp4_plane_set_scanout(struct drm_plane
*plane
,
160 struct drm_framebuffer
*fb
)
162 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
163 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
164 enum mdp4_pipe pipe
= mdp4_plane
->pipe
;
166 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_STRIDE_A(pipe
),
167 MDP4_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
168 MDP4_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
170 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_STRIDE_B(pipe
),
171 MDP4_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
172 MDP4_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
174 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP0_BASE(pipe
),
175 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 0));
176 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP1_BASE(pipe
),
177 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 1));
178 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP2_BASE(pipe
),
179 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 2));
180 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP3_BASE(pipe
),
181 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 3));
186 static void mdp4_write_csc_config(struct mdp4_kms
*mdp4_kms
,
187 enum mdp4_pipe pipe
, struct csc_cfg
*csc
)
191 for (i
= 0; i
< ARRAY_SIZE(csc
->matrix
); i
++) {
192 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_MV(pipe
, i
),
196 for (i
= 0; i
< ARRAY_SIZE(csc
->post_bias
) ; i
++) {
197 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_PRE_BV(pipe
, i
),
200 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_POST_BV(pipe
, i
),
204 for (i
= 0; i
< ARRAY_SIZE(csc
->post_clamp
) ; i
++) {
205 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_PRE_LV(pipe
, i
),
208 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_POST_LV(pipe
, i
),
213 #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
215 static int mdp4_plane_mode_set(struct drm_plane
*plane
,
216 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
217 int crtc_x
, int crtc_y
,
218 unsigned int crtc_w
, unsigned int crtc_h
,
219 uint32_t src_x
, uint32_t src_y
,
220 uint32_t src_w
, uint32_t src_h
)
222 struct drm_device
*dev
= plane
->dev
;
223 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
224 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
225 enum mdp4_pipe pipe
= mdp4_plane
->pipe
;
226 const struct mdp_format
*format
;
227 uint32_t op_mode
= 0;
228 uint32_t phasex_step
= MDP4_VG_PHASE_STEP_DEFAULT
;
229 uint32_t phasey_step
= MDP4_VG_PHASE_STEP_DEFAULT
;
230 enum mdp4_frame_format frame_type
;
233 DBG("%s: disabled!", mdp4_plane
->name
);
237 frame_type
= mdp4_get_frame_format(fb
);
239 /* src values are in Q16 fixed point, convert to integer: */
245 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane
->name
,
246 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
247 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
249 format
= to_mdp_format(msm_framebuffer_format(fb
));
251 if (src_w
> (crtc_w
* DOWN_SCALE_MAX
)) {
252 dev_err(dev
->dev
, "Width down scaling exceeds limits!\n");
256 if (src_h
> (crtc_h
* DOWN_SCALE_MAX
)) {
257 dev_err(dev
->dev
, "Height down scaling exceeds limits!\n");
261 if (crtc_w
> (src_w
* UP_SCALE_MAX
)) {
262 dev_err(dev
->dev
, "Width up scaling exceeds limits!\n");
266 if (crtc_h
> (src_h
* UP_SCALE_MAX
)) {
267 dev_err(dev
->dev
, "Height up scaling exceeds limits!\n");
271 if (src_w
!= crtc_w
) {
272 uint32_t sel_unit
= SCALE_FIR
;
273 op_mode
|= MDP4_PIPE_OP_MODE_SCALEX_EN
;
275 if (MDP_FORMAT_IS_YUV(format
)) {
277 sel_unit
= SCALE_PIXEL_RPT
;
278 else if (crtc_w
<= (src_w
/ 4))
279 sel_unit
= SCALE_MN_PHASE
;
281 op_mode
|= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit
);
282 phasex_step
= mult_frac(MDP4_VG_PHASE_STEP_DEFAULT
,
287 if (src_h
!= crtc_h
) {
288 uint32_t sel_unit
= SCALE_FIR
;
289 op_mode
|= MDP4_PIPE_OP_MODE_SCALEY_EN
;
291 if (MDP_FORMAT_IS_YUV(format
)) {
294 sel_unit
= SCALE_PIXEL_RPT
;
295 else if (crtc_h
<= (src_h
/ 4))
296 sel_unit
= SCALE_MN_PHASE
;
298 op_mode
|= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit
);
299 phasey_step
= mult_frac(MDP4_VG_PHASE_STEP_DEFAULT
,
304 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_SIZE(pipe
),
305 MDP4_PIPE_SRC_SIZE_WIDTH(src_w
) |
306 MDP4_PIPE_SRC_SIZE_HEIGHT(src_h
));
308 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_XY(pipe
),
309 MDP4_PIPE_SRC_XY_X(src_x
) |
310 MDP4_PIPE_SRC_XY_Y(src_y
));
312 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_DST_SIZE(pipe
),
313 MDP4_PIPE_DST_SIZE_WIDTH(crtc_w
) |
314 MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h
));
316 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_DST_XY(pipe
),
317 MDP4_PIPE_DST_XY_X(crtc_x
) |
318 MDP4_PIPE_DST_XY_Y(crtc_y
));
320 mdp4_plane_set_scanout(plane
, fb
);
322 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_FORMAT(pipe
),
323 MDP4_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
324 MDP4_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
325 MDP4_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
326 MDP4_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
327 COND(format
->alpha_enable
, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
328 MDP4_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
329 MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
330 MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format
->fetch_type
) |
331 MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
) |
332 MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type
) |
333 COND(format
->unpack_tight
, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT
));
335 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_UNPACK(pipe
),
336 MDP4_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
337 MDP4_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
338 MDP4_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
339 MDP4_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
341 if (MDP_FORMAT_IS_YUV(format
)) {
342 struct csc_cfg
*csc
= mdp_get_default_csc_cfg(CSC_YUV2RGB
);
344 op_mode
|= MDP4_PIPE_OP_MODE_SRC_YCBCR
;
345 op_mode
|= MDP4_PIPE_OP_MODE_CSC_EN
;
346 mdp4_write_csc_config(mdp4_kms
, pipe
, csc
);
349 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_OP_MODE(pipe
), op_mode
);
350 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_PHASEX_STEP(pipe
), phasex_step
);
351 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_PHASEY_STEP(pipe
), phasey_step
);
353 if (frame_type
!= FRAME_LINEAR
)
354 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe
),
355 MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w
) |
356 MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h
));
361 static const char *pipe_names
[] = {
363 "RGB1", "RGB2", "RGB3",
367 enum mdp4_pipe
mdp4_plane_pipe(struct drm_plane
*plane
)
369 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
370 return mdp4_plane
->pipe
;
373 /* initialize plane */
374 struct drm_plane
*mdp4_plane_init(struct drm_device
*dev
,
375 enum mdp4_pipe pipe_id
, bool private_plane
)
377 struct drm_plane
*plane
= NULL
;
378 struct mdp4_plane
*mdp4_plane
;
380 enum drm_plane_type type
;
382 mdp4_plane
= kzalloc(sizeof(*mdp4_plane
), GFP_KERNEL
);
388 plane
= &mdp4_plane
->base
;
390 mdp4_plane
->pipe
= pipe_id
;
391 mdp4_plane
->name
= pipe_names
[pipe_id
];
392 mdp4_plane
->caps
= mdp4_pipe_caps(pipe_id
);
394 mdp4_plane
->nformats
= mdp_get_formats(mdp4_plane
->formats
,
395 ARRAY_SIZE(mdp4_plane
->formats
),
396 !pipe_supports_yuv(mdp4_plane
->caps
));
398 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
399 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp4_plane_funcs
,
400 mdp4_plane
->formats
, mdp4_plane
->nformats
,
405 drm_plane_helper_add(plane
, &mdp4_plane_helper_funcs
);
407 mdp4_plane_install_properties(plane
, &plane
->base
);
413 mdp4_plane_destroy(plane
);