Commit | Line | Data |
---|---|---|
9bbf86fe BG |
1 | /* |
2 | * Copyright (C) STMicroelectronics SA 2014 | |
3 | * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> | |
4 | * Fabien Dessenne <fabien.dessenne@st.com> | |
5 | * for STMicroelectronics. | |
6 | * License terms: GNU General Public License (GPL), version 2 | |
7 | */ | |
8 | ||
de4b00b0 BG |
9 | #include <drm/drmP.h> |
10 | #include <drm/drm_atomic_helper.h> | |
871bcdfe VA |
11 | #include <drm/drm_gem_cma_helper.h> |
12 | #include <drm/drm_fb_cma_helper.h> | |
de4b00b0 BG |
13 | #include <drm/drm_plane_helper.h> |
14 | ||
9bbf86fe BG |
15 | #include "sti_compositor.h" |
16 | #include "sti_drm_drv.h" | |
17 | #include "sti_drm_plane.h" | |
18 | #include "sti_vtg.h" | |
19 | ||
871bcdfe VA |
20 | /* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ |
21 | enum sti_plane_desc sti_plane_default_zorder[] = { | |
9bbf86fe | 22 | STI_GDP_0, |
9bbf86fe | 23 | STI_GDP_1, |
871bcdfe | 24 | STI_HQVDP_0, |
9bbf86fe BG |
25 | STI_GDP_2, |
26 | STI_GDP_3, | |
27 | }; | |
28 | ||
871bcdfe | 29 | const char *sti_plane_to_str(struct sti_plane *plane) |
9bbf86fe | 30 | { |
871bcdfe VA |
31 | switch (plane->desc) { |
32 | case STI_GDP_0: | |
33 | return "GDP0"; | |
34 | case STI_GDP_1: | |
35 | return "GDP1"; | |
36 | case STI_GDP_2: | |
37 | return "GDP2"; | |
38 | case STI_GDP_3: | |
39 | return "GDP3"; | |
40 | case STI_HQVDP_0: | |
41 | return "HQVDP0"; | |
42 | case STI_CURSOR: | |
43 | return "CURSOR"; | |
44 | default: | |
45 | return "<UNKNOWN PLANE>"; | |
46 | } | |
47 | } | |
48 | EXPORT_SYMBOL(sti_plane_to_str); | |
49 | ||
50 | static int sti_plane_prepare(struct sti_plane *plane, | |
51 | struct drm_crtc *crtc, | |
52 | struct drm_framebuffer *fb, | |
53 | struct drm_display_mode *mode, int mixer_id, | |
54 | int dest_x, int dest_y, int dest_w, int dest_h, | |
55 | int src_x, int src_y, int src_w, int src_h) | |
56 | { | |
57 | struct drm_gem_cma_object *cma_obj; | |
58 | unsigned int i; | |
9bbf86fe BG |
59 | int res; |
60 | ||
871bcdfe VA |
61 | if (!plane || !fb || !mode) { |
62 | DRM_ERROR("Null fb, plane or mode\n"); | |
63 | return 1; | |
64 | } | |
9bbf86fe | 65 | |
871bcdfe VA |
66 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); |
67 | if (!cma_obj) { | |
68 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | |
69 | return 1; | |
9bbf86fe BG |
70 | } |
71 | ||
871bcdfe VA |
72 | plane->fb = fb; |
73 | plane->mode = mode; | |
74 | plane->mixer_id = mixer_id; | |
75 | plane->dst_x = dest_x; | |
76 | plane->dst_y = dest_y; | |
77 | plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); | |
78 | plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); | |
79 | plane->src_x = src_x; | |
80 | plane->src_y = src_y; | |
81 | plane->src_w = src_w; | |
82 | plane->src_h = src_h; | |
83 | plane->format = fb->pixel_format; | |
84 | plane->vaddr = cma_obj->vaddr; | |
85 | plane->paddr = cma_obj->paddr; | |
86 | for (i = 0; i < 4; i++) { | |
87 | plane->pitches[i] = fb->pitches[i]; | |
88 | plane->offsets[i] = fb->offsets[i]; | |
9bbf86fe BG |
89 | } |
90 | ||
871bcdfe VA |
91 | DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", |
92 | sti_plane_to_str(plane), | |
93 | plane->mixer_id); | |
94 | DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", | |
95 | sti_plane_to_str(plane), | |
96 | plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, | |
97 | plane->src_w, plane->src_h, plane->src_x, | |
98 | plane->src_y); | |
99 | ||
100 | DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, | |
101 | (char *)&plane->format, (unsigned long)plane->paddr); | |
102 | ||
103 | if (!plane->ops->prepare) { | |
104 | DRM_ERROR("Cannot prepare\n"); | |
105 | return 1; | |
9bbf86fe BG |
106 | } |
107 | ||
871bcdfe | 108 | res = plane->ops->prepare(plane, !plane->enabled); |
9bbf86fe | 109 | if (res) { |
871bcdfe | 110 | DRM_ERROR("Plane prepare failed\n"); |
9bbf86fe BG |
111 | return res; |
112 | } | |
113 | ||
871bcdfe VA |
114 | plane->enabled = true; |
115 | ||
9bbf86fe BG |
116 | return 0; |
117 | } | |
118 | ||
871bcdfe | 119 | static int sti_plane_commit(struct sti_plane *plane) |
9bbf86fe | 120 | { |
871bcdfe VA |
121 | if (!plane) |
122 | return 1; | |
9bbf86fe | 123 | |
871bcdfe VA |
124 | if (!plane->ops->commit) { |
125 | DRM_ERROR("Cannot commit\n"); | |
126 | return 1; | |
9bbf86fe | 127 | } |
9bbf86fe | 128 | |
871bcdfe VA |
129 | return plane->ops->commit(plane); |
130 | } | |
9bbf86fe | 131 | |
871bcdfe VA |
132 | static int sti_plane_disable(struct sti_plane *plane) |
133 | { | |
134 | int res; | |
9bbf86fe | 135 | |
871bcdfe VA |
136 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); |
137 | if (!plane) | |
138 | return 1; | |
9bbf86fe | 139 | |
871bcdfe VA |
140 | if (!plane->enabled) |
141 | return 0; | |
9bbf86fe | 142 | |
871bcdfe VA |
143 | if (!plane->ops->disable) { |
144 | DRM_ERROR("Cannot disable\n"); | |
145 | return 1; | |
146 | } | |
147 | ||
148 | res = plane->ops->disable(plane); | |
149 | if (res) { | |
150 | DRM_ERROR("Plane disable failed\n"); | |
151 | return res; | |
152 | } | |
153 | ||
154 | plane->enabled = false; | |
9bbf86fe BG |
155 | |
156 | return 0; | |
157 | } | |
158 | ||
871bcdfe | 159 | static void sti_drm_plane_destroy(struct drm_plane *drm_plane) |
9bbf86fe BG |
160 | { |
161 | DRM_DEBUG_DRIVER("\n"); | |
162 | ||
871bcdfe VA |
163 | drm_plane_helper_disable(drm_plane); |
164 | drm_plane_cleanup(drm_plane); | |
9bbf86fe BG |
165 | } |
166 | ||
871bcdfe | 167 | static int sti_drm_plane_set_property(struct drm_plane *drm_plane, |
9bbf86fe BG |
168 | struct drm_property *property, |
169 | uint64_t val) | |
170 | { | |
871bcdfe | 171 | struct drm_device *dev = drm_plane->dev; |
9bbf86fe | 172 | struct sti_drm_private *private = dev->dev_private; |
871bcdfe | 173 | struct sti_plane *plane = to_sti_plane(drm_plane); |
9bbf86fe BG |
174 | |
175 | DRM_DEBUG_DRIVER("\n"); | |
176 | ||
177 | if (property == private->plane_zorder_property) { | |
871bcdfe | 178 | plane->zorder = val; |
9bbf86fe BG |
179 | return 0; |
180 | } | |
181 | ||
182 | return -EINVAL; | |
183 | } | |
184 | ||
185 | static struct drm_plane_funcs sti_drm_plane_funcs = { | |
de4b00b0 BG |
186 | .update_plane = drm_atomic_helper_update_plane, |
187 | .disable_plane = drm_atomic_helper_disable_plane, | |
9bbf86fe BG |
188 | .destroy = sti_drm_plane_destroy, |
189 | .set_property = sti_drm_plane_set_property, | |
de4b00b0 BG |
190 | .reset = drm_atomic_helper_plane_reset, |
191 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | |
192 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | |
193 | }; | |
194 | ||
871bcdfe | 195 | static int sti_drm_plane_atomic_check(struct drm_plane *drm_plane, |
de4b00b0 BG |
196 | struct drm_plane_state *state) |
197 | { | |
198 | return 0; | |
199 | } | |
200 | ||
871bcdfe | 201 | static void sti_drm_plane_atomic_update(struct drm_plane *drm_plane, |
de4b00b0 BG |
202 | struct drm_plane_state *oldstate) |
203 | { | |
871bcdfe VA |
204 | struct drm_plane_state *state = drm_plane->state; |
205 | struct sti_plane *plane = to_sti_plane(drm_plane); | |
206 | struct sti_mixer *mixer = to_sti_mixer(state->crtc); | |
207 | int res; | |
208 | ||
209 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", | |
210 | state->crtc->base.id, sti_mixer_to_str(mixer), | |
211 | drm_plane->base.id, sti_plane_to_str(plane)); | |
212 | DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", | |
213 | state->crtc_w, state->crtc_h, | |
214 | state->crtc_x, state->crtc_y); | |
215 | ||
216 | res = sti_mixer_set_plane_depth(mixer, plane); | |
217 | if (res) { | |
218 | DRM_ERROR("Cannot set plane depth\n"); | |
219 | return; | |
220 | } | |
de4b00b0 | 221 | |
871bcdfe VA |
222 | /* src_x are in 16.16 format */ |
223 | res = sti_plane_prepare(plane, state->crtc, state->fb, | |
224 | &state->crtc->mode, mixer->id, | |
225 | state->crtc_x, state->crtc_y, | |
226 | state->crtc_w, state->crtc_h, | |
227 | state->src_x >> 16, state->src_y >> 16, | |
228 | state->src_w >> 16, state->src_h >> 16); | |
229 | if (res) { | |
230 | DRM_ERROR("Plane prepare failed\n"); | |
231 | return; | |
232 | } | |
233 | ||
234 | res = sti_plane_commit(plane); | |
235 | if (res) { | |
236 | DRM_ERROR("Plane commit failed\n"); | |
237 | return; | |
238 | } | |
239 | ||
240 | res = sti_mixer_set_plane_status(mixer, plane, true); | |
241 | if (res) { | |
242 | DRM_ERROR("Cannot enable plane at mixer\n"); | |
243 | return; | |
244 | } | |
de4b00b0 BG |
245 | } |
246 | ||
871bcdfe | 247 | static void sti_drm_plane_atomic_disable(struct drm_plane *drm_plane, |
de4b00b0 BG |
248 | struct drm_plane_state *oldstate) |
249 | { | |
871bcdfe VA |
250 | struct sti_plane *plane = to_sti_plane(drm_plane); |
251 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); | |
252 | int res; | |
253 | ||
254 | if (!drm_plane->crtc) { | |
255 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", | |
256 | drm_plane->base.id); | |
257 | return; | |
258 | } | |
259 | ||
260 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", | |
261 | drm_plane->crtc->base.id, sti_mixer_to_str(mixer), | |
262 | drm_plane->base.id, sti_plane_to_str(plane)); | |
263 | ||
264 | /* Disable plane at mixer level */ | |
265 | res = sti_mixer_set_plane_status(mixer, plane, false); | |
266 | if (res) { | |
267 | DRM_ERROR("Cannot disable plane at mixer\n"); | |
268 | return; | |
269 | } | |
270 | ||
271 | /* Wait a while to be sure that a Vsync event is received */ | |
272 | msleep(WAIT_NEXT_VSYNC_MS); | |
273 | ||
274 | /* Then disable plane itself */ | |
275 | res = sti_plane_disable(plane); | |
276 | if (res) { | |
277 | DRM_ERROR("Plane disable failed\n"); | |
278 | return; | |
279 | } | |
de4b00b0 BG |
280 | } |
281 | ||
282 | static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { | |
de4b00b0 BG |
283 | .atomic_check = sti_drm_plane_atomic_check, |
284 | .atomic_update = sti_drm_plane_atomic_update, | |
285 | .atomic_disable = sti_drm_plane_atomic_disable, | |
9bbf86fe BG |
286 | }; |
287 | ||
871bcdfe | 288 | static void sti_drm_plane_attach_zorder_property(struct drm_plane *drm_plane) |
9bbf86fe | 289 | { |
871bcdfe | 290 | struct drm_device *dev = drm_plane->dev; |
9bbf86fe | 291 | struct sti_drm_private *private = dev->dev_private; |
871bcdfe | 292 | struct sti_plane *plane = to_sti_plane(drm_plane); |
9bbf86fe | 293 | struct drm_property *prop; |
9bbf86fe BG |
294 | |
295 | prop = private->plane_zorder_property; | |
296 | if (!prop) { | |
bf60b29f VA |
297 | prop = drm_property_create_range(dev, 0, "zpos", 1, |
298 | GAM_MIXER_NB_DEPTH_LEVEL); | |
9bbf86fe BG |
299 | if (!prop) |
300 | return; | |
301 | ||
302 | private->plane_zorder_property = prop; | |
303 | } | |
304 | ||
871bcdfe | 305 | drm_object_attach_property(&drm_plane->base, prop, plane->zorder); |
9bbf86fe BG |
306 | } |
307 | ||
308 | struct drm_plane *sti_drm_plane_init(struct drm_device *dev, | |
871bcdfe VA |
309 | struct sti_plane *plane, |
310 | unsigned int possible_crtcs, | |
311 | enum drm_plane_type type) | |
9bbf86fe BG |
312 | { |
313 | int err, i; | |
9bbf86fe | 314 | |
871bcdfe VA |
315 | err = drm_universal_plane_init(dev, &plane->drm_plane, |
316 | possible_crtcs, | |
317 | &sti_drm_plane_funcs, | |
318 | plane->ops->get_formats(plane), | |
319 | plane->ops->get_nb_formats(plane), | |
320 | type); | |
9bbf86fe | 321 | if (err) { |
871bcdfe | 322 | DRM_ERROR("Failed to initialize universal plane\n"); |
9bbf86fe BG |
323 | return NULL; |
324 | } | |
325 | ||
871bcdfe VA |
326 | drm_plane_helper_add(&plane->drm_plane, |
327 | &sti_drm_plane_helpers_funcs); | |
de4b00b0 | 328 | |
871bcdfe VA |
329 | for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) |
330 | if (sti_plane_default_zorder[i] == plane->desc) | |
9bbf86fe BG |
331 | break; |
332 | ||
871bcdfe | 333 | plane->zorder = i + 1; |
9bbf86fe BG |
334 | |
335 | if (type == DRM_PLANE_TYPE_OVERLAY) | |
871bcdfe | 336 | sti_drm_plane_attach_zorder_property(&plane->drm_plane); |
9bbf86fe | 337 | |
871bcdfe VA |
338 | DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", |
339 | plane->drm_plane.base.id, | |
340 | sti_plane_to_str(plane), plane->zorder); | |
9bbf86fe | 341 | |
871bcdfe | 342 | return &plane->drm_plane; |
9bbf86fe | 343 | } |
4e0cd681 | 344 | EXPORT_SYMBOL(sti_drm_plane_init); |