1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
4 * Author: Rob Clark <rob.clark@linaro.org>
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
11 #include "omap_dmm_tiler.h"
18 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
21 struct drm_plane base
;
22 enum omap_plane_id id
;
26 static int omap_plane_prepare_fb(struct drm_plane
*plane
,
27 struct drm_plane_state
*new_state
)
32 return omap_framebuffer_pin(new_state
->fb
);
35 static void omap_plane_cleanup_fb(struct drm_plane
*plane
,
36 struct drm_plane_state
*old_state
)
39 omap_framebuffer_unpin(old_state
->fb
);
42 static void omap_plane_atomic_update(struct drm_plane
*plane
,
43 struct drm_plane_state
*old_state
)
45 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
46 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
47 struct drm_plane_state
*state
= plane
->state
;
48 struct omap_overlay_info info
;
51 DBG("%s, crtc=%p fb=%p", omap_plane
->name
, state
->crtc
, state
->fb
);
53 memset(&info
, 0, sizeof(info
));
54 info
.rotation_type
= OMAP_DSS_ROT_NONE
;
55 info
.rotation
= DRM_MODE_ROTATE_0
;
56 info
.global_alpha
= state
->alpha
>> 8;
57 info
.zorder
= state
->normalized_zpos
;
58 if (state
->pixel_blend_mode
== DRM_MODE_BLEND_PREMULTI
)
59 info
.pre_mult_alpha
= 1;
61 info
.pre_mult_alpha
= 0;
64 omap_framebuffer_update_scanout(state
->fb
, state
, &info
);
66 DBG("%dx%d -> %dx%d (%d)", info
.width
, info
.height
,
67 info
.out_width
, info
.out_height
,
69 DBG("%d,%d %pad %pad", info
.pos_x
, info
.pos_y
,
70 &info
.paddr
, &info
.p_uv_addr
);
72 /* and finally, update omapdss: */
73 ret
= priv
->dispc_ops
->ovl_setup(priv
->dispc
, omap_plane
->id
, &info
,
74 omap_crtc_timings(state
->crtc
), false,
75 omap_crtc_channel(state
->crtc
));
77 dev_err(plane
->dev
->dev
, "Failed to setup plane %s\n",
79 priv
->dispc_ops
->ovl_enable(priv
->dispc
, omap_plane
->id
, false);
83 priv
->dispc_ops
->ovl_enable(priv
->dispc
, omap_plane
->id
, true);
86 static void omap_plane_atomic_disable(struct drm_plane
*plane
,
87 struct drm_plane_state
*old_state
)
89 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
90 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
92 plane
->state
->rotation
= DRM_MODE_ROTATE_0
;
93 plane
->state
->zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
96 priv
->dispc_ops
->ovl_enable(priv
->dispc
, omap_plane
->id
, false);
99 static int omap_plane_atomic_check(struct drm_plane
*plane
,
100 struct drm_plane_state
*state
)
102 struct drm_crtc_state
*crtc_state
;
107 /* crtc should only be NULL when disabling (i.e., !state->fb) */
108 if (WARN_ON(!state
->crtc
))
111 crtc_state
= drm_atomic_get_existing_crtc_state(state
->state
, state
->crtc
);
112 /* we should have a crtc state if the plane is attached to a crtc */
113 if (WARN_ON(!crtc_state
))
116 if (!crtc_state
->enable
)
119 if (state
->crtc_x
< 0 || state
->crtc_y
< 0)
122 if (state
->crtc_x
+ state
->crtc_w
> crtc_state
->adjusted_mode
.hdisplay
)
125 if (state
->crtc_y
+ state
->crtc_h
> crtc_state
->adjusted_mode
.vdisplay
)
128 if (state
->rotation
!= DRM_MODE_ROTATE_0
&&
129 !omap_framebuffer_supports_rotation(state
->fb
))
135 static const struct drm_plane_helper_funcs omap_plane_helper_funcs
= {
136 .prepare_fb
= omap_plane_prepare_fb
,
137 .cleanup_fb
= omap_plane_cleanup_fb
,
138 .atomic_check
= omap_plane_atomic_check
,
139 .atomic_update
= omap_plane_atomic_update
,
140 .atomic_disable
= omap_plane_atomic_disable
,
143 static void omap_plane_destroy(struct drm_plane
*plane
)
145 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
147 DBG("%s", omap_plane
->name
);
149 drm_plane_cleanup(plane
);
154 /* helper to install properties which are common to planes and crtcs */
155 void omap_plane_install_properties(struct drm_plane
*plane
,
156 struct drm_mode_object
*obj
)
158 struct drm_device
*dev
= plane
->dev
;
159 struct omap_drm_private
*priv
= dev
->dev_private
;
162 if (!plane
->rotation_property
)
163 drm_plane_create_rotation_property(plane
,
165 DRM_MODE_ROTATE_0
| DRM_MODE_ROTATE_90
|
166 DRM_MODE_ROTATE_180
| DRM_MODE_ROTATE_270
|
167 DRM_MODE_REFLECT_X
| DRM_MODE_REFLECT_Y
);
169 /* Attach the rotation property also to the crtc object */
170 if (plane
->rotation_property
&& obj
!= &plane
->base
)
171 drm_object_attach_property(obj
, plane
->rotation_property
,
175 drm_object_attach_property(obj
, priv
->zorder_prop
, 0);
178 static void omap_plane_reset(struct drm_plane
*plane
)
180 struct omap_plane
*omap_plane
= to_omap_plane(plane
);
182 drm_atomic_helper_plane_reset(plane
);
187 * Set the zpos default depending on whether we are a primary or overlay
190 plane
->state
->zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
191 ? 0 : omap_plane
->id
;
194 static int omap_plane_atomic_set_property(struct drm_plane
*plane
,
195 struct drm_plane_state
*state
,
196 struct drm_property
*property
,
199 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
201 if (property
== priv
->zorder_prop
)
209 static int omap_plane_atomic_get_property(struct drm_plane
*plane
,
210 const struct drm_plane_state
*state
,
211 struct drm_property
*property
,
214 struct omap_drm_private
*priv
= plane
->dev
->dev_private
;
216 if (property
== priv
->zorder_prop
)
224 static const struct drm_plane_funcs omap_plane_funcs
= {
225 .update_plane
= drm_atomic_helper_update_plane
,
226 .disable_plane
= drm_atomic_helper_disable_plane
,
227 .reset
= omap_plane_reset
,
228 .destroy
= omap_plane_destroy
,
229 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
230 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
231 .atomic_set_property
= omap_plane_atomic_set_property
,
232 .atomic_get_property
= omap_plane_atomic_get_property
,
235 static const char *plane_id_to_name
[] = {
236 [OMAP_DSS_GFX
] = "gfx",
237 [OMAP_DSS_VIDEO1
] = "vid1",
238 [OMAP_DSS_VIDEO2
] = "vid2",
239 [OMAP_DSS_VIDEO3
] = "vid3",
242 static const enum omap_plane_id plane_idx_to_id
[] = {
249 /* initialize plane */
250 struct drm_plane
*omap_plane_init(struct drm_device
*dev
,
251 int idx
, enum drm_plane_type type
,
254 struct omap_drm_private
*priv
= dev
->dev_private
;
255 unsigned int num_planes
= priv
->dispc_ops
->get_num_ovls(priv
->dispc
);
256 struct drm_plane
*plane
;
257 struct omap_plane
*omap_plane
;
258 enum omap_plane_id id
;
263 if (WARN_ON(idx
>= ARRAY_SIZE(plane_idx_to_id
)))
264 return ERR_PTR(-EINVAL
);
266 id
= plane_idx_to_id
[idx
];
268 DBG("%s: type=%d", plane_id_to_name
[id
], type
);
270 omap_plane
= kzalloc(sizeof(*omap_plane
), GFP_KERNEL
);
272 return ERR_PTR(-ENOMEM
);
274 formats
= priv
->dispc_ops
->ovl_get_color_modes(priv
->dispc
, id
);
275 for (nformats
= 0; formats
[nformats
]; ++nformats
)
278 omap_plane
->name
= plane_id_to_name
[id
];
280 plane
= &omap_plane
->base
;
282 ret
= drm_universal_plane_init(dev
, plane
, possible_crtcs
,
283 &omap_plane_funcs
, formats
,
284 nformats
, NULL
, type
, NULL
);
288 drm_plane_helper_add(plane
, &omap_plane_helper_funcs
);
290 omap_plane_install_properties(plane
, &plane
->base
);
291 drm_plane_create_zpos_property(plane
, 0, 0, num_planes
- 1);
292 drm_plane_create_alpha_property(plane
);
293 drm_plane_create_blend_mode_property(plane
, BIT(DRM_MODE_BLEND_PREMULTI
) |
294 BIT(DRM_MODE_BLEND_COVERAGE
));
299 dev_err(dev
->dev
, "%s(): could not create plane: %s\n",
300 __func__
, plane_id_to_name
[id
]);