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
;
34 #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base)
36 static void mdp4_plane_set_scanout(struct drm_plane
*plane
,
37 struct drm_framebuffer
*fb
);
38 static int mdp4_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 struct mdp4_kms
*get_kms(struct drm_plane
*plane
)
47 struct msm_drm_private
*priv
= plane
->dev
->dev_private
;
48 return to_mdp4_kms(to_mdp_kms(priv
->kms
));
51 static void mdp4_plane_destroy(struct drm_plane
*plane
)
53 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
55 drm_plane_helper_disable(plane
);
56 drm_plane_cleanup(plane
);
61 /* helper to install properties which are common to planes and crtcs */
62 void mdp4_plane_install_properties(struct drm_plane
*plane
,
63 struct drm_mode_object
*obj
)
68 int mdp4_plane_set_property(struct drm_plane
*plane
,
69 struct drm_property
*property
, uint64_t val
)
75 static const struct drm_plane_funcs mdp4_plane_funcs
= {
76 .update_plane
= drm_atomic_helper_update_plane
,
77 .disable_plane
= drm_atomic_helper_disable_plane
,
78 .destroy
= mdp4_plane_destroy
,
79 .set_property
= mdp4_plane_set_property
,
80 .reset
= drm_atomic_helper_plane_reset
,
81 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
82 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
85 static int mdp4_plane_prepare_fb(struct drm_plane
*plane
,
86 struct drm_framebuffer
*fb
)
88 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
89 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
91 DBG("%s: prepare: FB[%u]", mdp4_plane
->name
, fb
->base
.id
);
92 return msm_framebuffer_prepare(fb
, mdp4_kms
->id
);
95 static void mdp4_plane_cleanup_fb(struct drm_plane
*plane
,
96 struct drm_framebuffer
*fb
)
98 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
99 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
101 DBG("%s: cleanup: FB[%u]", mdp4_plane
->name
, fb
->base
.id
);
102 msm_framebuffer_cleanup(fb
, mdp4_kms
->id
);
106 static int mdp4_plane_atomic_check(struct drm_plane
*plane
,
107 struct drm_plane_state
*state
)
112 static void mdp4_plane_atomic_update(struct drm_plane
*plane
,
113 struct drm_plane_state
*old_state
)
115 struct drm_plane_state
*state
= plane
->state
;
118 ret
= mdp4_plane_mode_set(plane
,
119 state
->crtc
, state
->fb
,
120 state
->crtc_x
, state
->crtc_y
,
121 state
->crtc_w
, state
->crtc_h
,
122 state
->src_x
, state
->src_y
,
123 state
->src_w
, state
->src_h
);
124 /* atomic_check should have ensured that this doesn't fail */
128 static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs
= {
129 .prepare_fb
= mdp4_plane_prepare_fb
,
130 .cleanup_fb
= mdp4_plane_cleanup_fb
,
131 .atomic_check
= mdp4_plane_atomic_check
,
132 .atomic_update
= mdp4_plane_atomic_update
,
135 static void mdp4_plane_set_scanout(struct drm_plane
*plane
,
136 struct drm_framebuffer
*fb
)
138 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
139 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
140 enum mdp4_pipe pipe
= mdp4_plane
->pipe
;
142 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_STRIDE_A(pipe
),
143 MDP4_PIPE_SRC_STRIDE_A_P0(fb
->pitches
[0]) |
144 MDP4_PIPE_SRC_STRIDE_A_P1(fb
->pitches
[1]));
146 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_STRIDE_B(pipe
),
147 MDP4_PIPE_SRC_STRIDE_B_P2(fb
->pitches
[2]) |
148 MDP4_PIPE_SRC_STRIDE_B_P3(fb
->pitches
[3]));
150 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP0_BASE(pipe
),
151 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 0));
152 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP1_BASE(pipe
),
153 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 1));
154 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP2_BASE(pipe
),
155 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 2));
156 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRCP3_BASE(pipe
),
157 msm_framebuffer_iova(fb
, mdp4_kms
->id
, 3));
162 static void mdp4_write_csc_config(struct mdp4_kms
*mdp4_kms
,
163 enum mdp4_pipe pipe
, struct csc_cfg
*csc
)
167 for (i
= 0; i
< ARRAY_SIZE(csc
->matrix
); i
++) {
168 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_MV(pipe
, i
),
172 for (i
= 0; i
< ARRAY_SIZE(csc
->post_bias
) ; i
++) {
173 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_PRE_BV(pipe
, i
),
176 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_POST_BV(pipe
, i
),
180 for (i
= 0; i
< ARRAY_SIZE(csc
->post_clamp
) ; i
++) {
181 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_PRE_LV(pipe
, i
),
184 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_CSC_POST_LV(pipe
, i
),
189 #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
191 static int mdp4_plane_mode_set(struct drm_plane
*plane
,
192 struct drm_crtc
*crtc
, struct drm_framebuffer
*fb
,
193 int crtc_x
, int crtc_y
,
194 unsigned int crtc_w
, unsigned int crtc_h
,
195 uint32_t src_x
, uint32_t src_y
,
196 uint32_t src_w
, uint32_t src_h
)
198 struct drm_device
*dev
= plane
->dev
;
199 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
200 struct mdp4_kms
*mdp4_kms
= get_kms(plane
);
201 enum mdp4_pipe pipe
= mdp4_plane
->pipe
;
202 const struct mdp_format
*format
;
203 uint32_t op_mode
= 0;
204 uint32_t phasex_step
= MDP4_VG_PHASE_STEP_DEFAULT
;
205 uint32_t phasey_step
= MDP4_VG_PHASE_STEP_DEFAULT
;
208 DBG("%s: disabled!", mdp4_plane
->name
);
212 /* src values are in Q16 fixed point, convert to integer: */
218 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane
->name
,
219 fb
->base
.id
, src_x
, src_y
, src_w
, src_h
,
220 crtc
->base
.id
, crtc_x
, crtc_y
, crtc_w
, crtc_h
);
222 format
= to_mdp_format(msm_framebuffer_format(fb
));
224 if (src_w
> (crtc_w
* DOWN_SCALE_MAX
)) {
225 dev_err(dev
->dev
, "Width down scaling exceeds limits!\n");
229 if (src_h
> (crtc_h
* DOWN_SCALE_MAX
)) {
230 dev_err(dev
->dev
, "Height down scaling exceeds limits!\n");
234 if (crtc_w
> (src_w
* UP_SCALE_MAX
)) {
235 dev_err(dev
->dev
, "Width up scaling exceeds limits!\n");
239 if (crtc_h
> (src_h
* UP_SCALE_MAX
)) {
240 dev_err(dev
->dev
, "Height up scaling exceeds limits!\n");
244 if (src_w
!= crtc_w
) {
245 uint32_t sel_unit
= SCALE_FIR
;
246 op_mode
|= MDP4_PIPE_OP_MODE_SCALEX_EN
;
248 if (MDP_FORMAT_IS_YUV(format
)) {
250 sel_unit
= SCALE_PIXEL_RPT
;
251 else if (crtc_w
<= (src_w
/ 4))
252 sel_unit
= SCALE_MN_PHASE
;
254 op_mode
|= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit
);
255 phasex_step
= mult_frac(MDP4_VG_PHASE_STEP_DEFAULT
,
260 if (src_h
!= crtc_h
) {
261 uint32_t sel_unit
= SCALE_FIR
;
262 op_mode
|= MDP4_PIPE_OP_MODE_SCALEY_EN
;
264 if (MDP_FORMAT_IS_YUV(format
)) {
267 sel_unit
= SCALE_PIXEL_RPT
;
268 else if (crtc_h
<= (src_h
/ 4))
269 sel_unit
= SCALE_MN_PHASE
;
271 op_mode
|= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit
);
272 phasey_step
= mult_frac(MDP4_VG_PHASE_STEP_DEFAULT
,
277 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_SIZE(pipe
),
278 MDP4_PIPE_SRC_SIZE_WIDTH(src_w
) |
279 MDP4_PIPE_SRC_SIZE_HEIGHT(src_h
));
281 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_XY(pipe
),
282 MDP4_PIPE_SRC_XY_X(src_x
) |
283 MDP4_PIPE_SRC_XY_Y(src_y
));
285 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_DST_SIZE(pipe
),
286 MDP4_PIPE_DST_SIZE_WIDTH(crtc_w
) |
287 MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h
));
289 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_DST_XY(pipe
),
290 MDP4_PIPE_DST_XY_X(crtc_x
) |
291 MDP4_PIPE_DST_XY_Y(crtc_y
));
293 mdp4_plane_set_scanout(plane
, fb
);
295 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_FORMAT(pipe
),
296 MDP4_PIPE_SRC_FORMAT_A_BPC(format
->bpc_a
) |
297 MDP4_PIPE_SRC_FORMAT_R_BPC(format
->bpc_r
) |
298 MDP4_PIPE_SRC_FORMAT_G_BPC(format
->bpc_g
) |
299 MDP4_PIPE_SRC_FORMAT_B_BPC(format
->bpc_b
) |
300 COND(format
->alpha_enable
, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE
) |
301 MDP4_PIPE_SRC_FORMAT_CPP(format
->cpp
- 1) |
302 MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format
->unpack_count
- 1) |
303 MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format
->fetch_type
) |
304 MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format
->chroma_sample
) |
305 COND(format
->unpack_tight
, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT
));
307 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_SRC_UNPACK(pipe
),
308 MDP4_PIPE_SRC_UNPACK_ELEM0(format
->unpack
[0]) |
309 MDP4_PIPE_SRC_UNPACK_ELEM1(format
->unpack
[1]) |
310 MDP4_PIPE_SRC_UNPACK_ELEM2(format
->unpack
[2]) |
311 MDP4_PIPE_SRC_UNPACK_ELEM3(format
->unpack
[3]));
313 if (MDP_FORMAT_IS_YUV(format
)) {
314 struct csc_cfg
*csc
= mdp_get_default_csc_cfg(CSC_YUV2RGB
);
316 op_mode
|= MDP4_PIPE_OP_MODE_SRC_YCBCR
;
317 op_mode
|= MDP4_PIPE_OP_MODE_CSC_EN
;
318 mdp4_write_csc_config(mdp4_kms
, pipe
, csc
);
321 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_OP_MODE(pipe
), op_mode
);
322 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_PHASEX_STEP(pipe
), phasex_step
);
323 mdp4_write(mdp4_kms
, REG_MDP4_PIPE_PHASEY_STEP(pipe
), phasey_step
);
328 static const char *pipe_names
[] = {
330 "RGB1", "RGB2", "RGB3",
334 enum mdp4_pipe
mdp4_plane_pipe(struct drm_plane
*plane
)
336 struct mdp4_plane
*mdp4_plane
= to_mdp4_plane(plane
);
337 return mdp4_plane
->pipe
;
340 /* initialize plane */
341 struct drm_plane
*mdp4_plane_init(struct drm_device
*dev
,
342 enum mdp4_pipe pipe_id
, bool private_plane
)
344 struct drm_plane
*plane
= NULL
;
345 struct mdp4_plane
*mdp4_plane
;
347 enum drm_plane_type type
;
349 mdp4_plane
= kzalloc(sizeof(*mdp4_plane
), GFP_KERNEL
);
355 plane
= &mdp4_plane
->base
;
357 mdp4_plane
->pipe
= pipe_id
;
358 mdp4_plane
->name
= pipe_names
[pipe_id
];
360 mdp4_plane
->nformats
= mdp4_get_formats(pipe_id
, mdp4_plane
->formats
,
361 ARRAY_SIZE(mdp4_plane
->formats
));
363 type
= private_plane
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
364 ret
= drm_universal_plane_init(dev
, plane
, 0xff, &mdp4_plane_funcs
,
365 mdp4_plane
->formats
, mdp4_plane
->nformats
, type
);
369 drm_plane_helper_add(plane
, &mdp4_plane_helper_funcs
);
371 mdp4_plane_install_properties(plane
, &plane
->base
);
377 mdp4_plane_destroy(plane
);