1 // SPDX-License-Identifier: GPL-2.0
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
10 #include <drm/drm_print.h>
11 #include "komeda_dev.h"
12 #include "komeda_kms.h"
13 #include "komeda_framebuffer.h"
16 komeda_plane_init_data_flow(struct drm_plane_state
*st
,
17 struct komeda_crtc_state
*kcrtc_st
,
18 struct komeda_data_flow_cfg
*dflow
)
20 struct komeda_plane
*kplane
= to_kplane(st
->plane
);
21 struct drm_framebuffer
*fb
= st
->fb
;
22 const struct komeda_format_caps
*caps
= to_kfb(fb
)->format_caps
;
23 struct komeda_pipeline
*pipe
= kplane
->layer
->base
.pipeline
;
25 memset(dflow
, 0, sizeof(*dflow
));
27 dflow
->blending_zorder
= st
->normalized_zpos
;
28 if (pipe
== to_kcrtc(st
->crtc
)->master
)
29 dflow
->blending_zorder
-= kcrtc_st
->max_slave_zorder
;
30 if (dflow
->blending_zorder
< 0) {
31 DRM_DEBUG_ATOMIC("%s zorder:%d < max_slave_zorder: %d.\n",
32 st
->plane
->name
, st
->normalized_zpos
,
33 kcrtc_st
->max_slave_zorder
);
37 dflow
->pixel_blend_mode
= st
->pixel_blend_mode
;
38 dflow
->layer_alpha
= st
->alpha
>> 8;
40 dflow
->out_x
= st
->crtc_x
;
41 dflow
->out_y
= st
->crtc_y
;
42 dflow
->out_w
= st
->crtc_w
;
43 dflow
->out_h
= st
->crtc_h
;
45 dflow
->in_x
= st
->src_x
>> 16;
46 dflow
->in_y
= st
->src_y
>> 16;
47 dflow
->in_w
= st
->src_w
>> 16;
48 dflow
->in_h
= st
->src_h
>> 16;
50 dflow
->rot
= drm_rotation_simplify(st
->rotation
, caps
->supported_rots
);
51 if (!has_bits(dflow
->rot
, caps
->supported_rots
)) {
52 DRM_DEBUG_ATOMIC("rotation(0x%x) isn't supported by %s.\n",
54 komeda_get_format_name(caps
->fourcc
,
59 komeda_complete_data_flow_cfg(kplane
->layer
, dflow
, fb
);
65 * komeda_plane_atomic_check - build input data flow
67 * @state: the plane state object
70 * Zero for success or -errno
73 komeda_plane_atomic_check(struct drm_plane
*plane
,
74 struct drm_plane_state
*state
)
76 struct komeda_plane
*kplane
= to_kplane(plane
);
77 struct komeda_plane_state
*kplane_st
= to_kplane_st(state
);
78 struct komeda_layer
*layer
= kplane
->layer
;
79 struct drm_crtc_state
*crtc_st
;
80 struct komeda_crtc_state
*kcrtc_st
;
81 struct komeda_data_flow_cfg dflow
;
84 if (!state
->crtc
|| !state
->fb
)
87 crtc_st
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
88 if (IS_ERR(crtc_st
) || !crtc_st
->enable
) {
89 DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
93 /* crtc is inactive, skip the resource assignment */
97 kcrtc_st
= to_kcrtc_st(crtc_st
);
99 err
= komeda_plane_init_data_flow(state
, kcrtc_st
, &dflow
);
104 err
= komeda_build_layer_split_data_flow(layer
,
105 kplane_st
, kcrtc_st
, &dflow
);
107 err
= komeda_build_layer_data_flow(layer
,
108 kplane_st
, kcrtc_st
, &dflow
);
113 /* plane doesn't represent a real HW, so there is no HW update for plane.
114 * komeda handles all the HW update in crtc->atomic_flush
117 komeda_plane_atomic_update(struct drm_plane
*plane
,
118 struct drm_plane_state
*old_state
)
122 static const struct drm_plane_helper_funcs komeda_plane_helper_funcs
= {
123 .atomic_check
= komeda_plane_atomic_check
,
124 .atomic_update
= komeda_plane_atomic_update
,
127 static void komeda_plane_destroy(struct drm_plane
*plane
)
129 drm_plane_cleanup(plane
);
131 kfree(to_kplane(plane
));
134 static void komeda_plane_reset(struct drm_plane
*plane
)
136 struct komeda_plane_state
*state
;
137 struct komeda_plane
*kplane
= to_kplane(plane
);
140 __drm_atomic_helper_plane_destroy_state(plane
->state
);
145 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
147 state
->base
.rotation
= DRM_MODE_ROTATE_0
;
148 state
->base
.pixel_blend_mode
= DRM_MODE_BLEND_PREMULTI
;
149 state
->base
.alpha
= DRM_BLEND_ALPHA_OPAQUE
;
150 state
->base
.zpos
= kplane
->layer
->base
.id
;
151 state
->base
.color_encoding
= DRM_COLOR_YCBCR_BT601
;
152 state
->base
.color_range
= DRM_COLOR_YCBCR_LIMITED_RANGE
;
153 plane
->state
= &state
->base
;
154 plane
->state
->plane
= plane
;
158 static struct drm_plane_state
*
159 komeda_plane_atomic_duplicate_state(struct drm_plane
*plane
)
161 struct komeda_plane_state
*new;
163 if (WARN_ON(!plane
->state
))
166 new = kzalloc(sizeof(*new), GFP_KERNEL
);
170 __drm_atomic_helper_plane_duplicate_state(plane
, &new->base
);
176 komeda_plane_atomic_destroy_state(struct drm_plane
*plane
,
177 struct drm_plane_state
*state
)
179 __drm_atomic_helper_plane_destroy_state(state
);
180 kfree(to_kplane_st(state
));
184 komeda_plane_format_mod_supported(struct drm_plane
*plane
,
185 u32 format
, u64 modifier
)
187 struct komeda_dev
*mdev
= plane
->dev
->dev_private
;
188 struct komeda_plane
*kplane
= to_kplane(plane
);
189 u32 layer_type
= kplane
->layer
->layer_type
;
191 return komeda_format_mod_supported(&mdev
->fmt_tbl
, layer_type
,
192 format
, modifier
, 0);
195 static const struct drm_plane_funcs komeda_plane_funcs
= {
196 .update_plane
= drm_atomic_helper_update_plane
,
197 .disable_plane
= drm_atomic_helper_disable_plane
,
198 .destroy
= komeda_plane_destroy
,
199 .reset
= komeda_plane_reset
,
200 .atomic_duplicate_state
= komeda_plane_atomic_duplicate_state
,
201 .atomic_destroy_state
= komeda_plane_atomic_destroy_state
,
202 .format_mod_supported
= komeda_plane_format_mod_supported
,
205 /* for komeda, which is pipeline can be share between crtcs */
206 static u32
get_possible_crtcs(struct komeda_kms_dev
*kms
,
207 struct komeda_pipeline
*pipe
)
209 struct komeda_crtc
*crtc
;
210 u32 possible_crtcs
= 0;
213 for (i
= 0; i
< kms
->n_crtcs
; i
++) {
214 crtc
= &kms
->crtcs
[i
];
216 if ((pipe
== crtc
->master
) || (pipe
== crtc
->slave
))
217 possible_crtcs
|= BIT(i
);
220 return possible_crtcs
;
224 komeda_set_crtc_plane_mask(struct komeda_kms_dev
*kms
,
225 struct komeda_pipeline
*pipe
,
226 struct drm_plane
*plane
)
228 struct komeda_crtc
*kcrtc
;
231 for (i
= 0; i
< kms
->n_crtcs
; i
++) {
232 kcrtc
= &kms
->crtcs
[i
];
234 if (pipe
== kcrtc
->slave
)
235 kcrtc
->slave_planes
|= BIT(drm_plane_index(plane
));
239 /* use Layer0 as primary */
240 static u32
get_plane_type(struct komeda_kms_dev
*kms
,
241 struct komeda_component
*c
)
243 bool is_primary
= (c
->id
== KOMEDA_COMPONENT_LAYER0
);
245 return is_primary
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY
;
248 static int komeda_plane_add(struct komeda_kms_dev
*kms
,
249 struct komeda_layer
*layer
)
251 struct komeda_dev
*mdev
= kms
->base
.dev_private
;
252 struct komeda_component
*c
= &layer
->base
;
253 struct komeda_plane
*kplane
;
254 struct drm_plane
*plane
;
255 u32
*formats
, n_formats
= 0;
258 kplane
= kzalloc(sizeof(*kplane
), GFP_KERNEL
);
262 plane
= &kplane
->base
;
263 kplane
->layer
= layer
;
265 formats
= komeda_get_layer_fourcc_list(&mdev
->fmt_tbl
,
266 layer
->layer_type
, &n_formats
);
268 err
= drm_universal_plane_init(&kms
->base
, plane
,
269 get_possible_crtcs(kms
, c
->pipeline
),
271 formats
, n_formats
, komeda_supported_modifiers
,
272 get_plane_type(kms
, c
),
275 komeda_put_fourcc_list(formats
);
280 drm_plane_helper_add(plane
, &komeda_plane_helper_funcs
);
282 err
= drm_plane_create_rotation_property(plane
, DRM_MODE_ROTATE_0
,
283 layer
->supported_rots
);
287 err
= drm_plane_create_alpha_property(plane
);
291 err
= drm_plane_create_blend_mode_property(plane
,
292 BIT(DRM_MODE_BLEND_PIXEL_NONE
) |
293 BIT(DRM_MODE_BLEND_PREMULTI
) |
294 BIT(DRM_MODE_BLEND_COVERAGE
));
298 err
= drm_plane_create_color_properties(plane
,
299 BIT(DRM_COLOR_YCBCR_BT601
) |
300 BIT(DRM_COLOR_YCBCR_BT709
) |
301 BIT(DRM_COLOR_YCBCR_BT2020
),
302 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE
) |
303 BIT(DRM_COLOR_YCBCR_FULL_RANGE
),
304 DRM_COLOR_YCBCR_BT601
,
305 DRM_COLOR_YCBCR_LIMITED_RANGE
);
309 err
= drm_plane_create_zpos_property(plane
, layer
->base
.id
, 0, 8);
313 komeda_set_crtc_plane_mask(kms
, c
->pipeline
, plane
);
317 komeda_plane_destroy(plane
);
321 int komeda_kms_add_planes(struct komeda_kms_dev
*kms
, struct komeda_dev
*mdev
)
323 struct komeda_pipeline
*pipe
;
326 for (i
= 0; i
< mdev
->n_pipelines
; i
++) {
327 pipe
= mdev
->pipelines
[i
];
329 for (j
= 0; j
< pipe
->n_layers
; j
++) {
330 err
= komeda_plane_add(kms
, pipe
->layers
[j
]);