Commit | Line | Data |
---|---|---|
06c0dd96 | 1 | /* |
0deed25b | 2 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. |
06c0dd96 RC |
3 | * Copyright (C) 2013 Red Hat |
4 | * Author: Rob Clark <robdclark@gmail.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License version 2 as published by | |
8 | * the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along with | |
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include "mdp5_kms.h" | |
20 | ||
0deed25b | 21 | #define MAX_PLANE 4 |
06c0dd96 RC |
22 | |
23 | struct mdp5_plane { | |
24 | struct drm_plane base; | |
25 | const char *name; | |
26 | ||
27 | enum mdp5_pipe pipe; | |
28 | ||
0deed25b SV |
29 | spinlock_t pipe_lock; /* protect REG_MDP5_PIPE_* registers */ |
30 | uint32_t reg_offset; | |
31 | ||
32 | uint32_t flush_mask; /* used to commit pipe registers */ | |
33 | ||
06c0dd96 RC |
34 | uint32_t nformats; |
35 | uint32_t formats[32]; | |
36 | ||
37 | bool enabled; | |
38 | }; | |
39 | #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) | |
40 | ||
ed851963 RC |
41 | static int mdp5_plane_mode_set(struct drm_plane *plane, |
42 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | |
43 | int crtc_x, int crtc_y, | |
44 | unsigned int crtc_w, unsigned int crtc_h, | |
45 | uint32_t src_x, uint32_t src_y, | |
46 | uint32_t src_w, uint32_t src_h); | |
47 | static void set_scanout_locked(struct drm_plane *plane, | |
48 | struct drm_framebuffer *fb); | |
49 | ||
06c0dd96 RC |
50 | static struct mdp5_kms *get_kms(struct drm_plane *plane) |
51 | { | |
52 | struct msm_drm_private *priv = plane->dev->dev_private; | |
53 | return to_mdp5_kms(to_mdp_kms(priv->kms)); | |
54 | } | |
55 | ||
ed851963 | 56 | static bool plane_enabled(struct drm_plane_state *state) |
06c0dd96 | 57 | { |
ed851963 | 58 | return state->fb && state->crtc; |
06c0dd96 RC |
59 | } |
60 | ||
61 | static int mdp5_plane_disable(struct drm_plane *plane) | |
62 | { | |
63 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
64 | struct mdp5_kms *mdp5_kms = get_kms(plane); | |
65 | enum mdp5_pipe pipe = mdp5_plane->pipe; | |
06c0dd96 RC |
66 | |
67 | DBG("%s: disable", mdp5_plane->name); | |
68 | ||
bfcdfb0e SV |
69 | if (mdp5_kms) { |
70 | /* Release the memory we requested earlier from the SMP: */ | |
42238da8 | 71 | mdp5_smp_release(mdp5_kms->smp, pipe); |
bfcdfb0e | 72 | } |
06c0dd96 | 73 | |
06c0dd96 RC |
74 | return 0; |
75 | } | |
76 | ||
77 | static void mdp5_plane_destroy(struct drm_plane *plane) | |
78 | { | |
79 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
80 | ||
ed851963 | 81 | drm_plane_helper_disable(plane); |
06c0dd96 RC |
82 | drm_plane_cleanup(plane); |
83 | ||
84 | kfree(mdp5_plane); | |
85 | } | |
86 | ||
87 | /* helper to install properties which are common to planes and crtcs */ | |
88 | void mdp5_plane_install_properties(struct drm_plane *plane, | |
89 | struct drm_mode_object *obj) | |
90 | { | |
91 | // XXX | |
92 | } | |
93 | ||
94 | int mdp5_plane_set_property(struct drm_plane *plane, | |
95 | struct drm_property *property, uint64_t val) | |
96 | { | |
97 | // XXX | |
98 | return -EINVAL; | |
99 | } | |
100 | ||
ed851963 RC |
101 | static void mdp5_plane_reset(struct drm_plane *plane) |
102 | { | |
103 | struct mdp5_plane_state *mdp5_state; | |
104 | ||
105 | if (plane->state && plane->state->fb) | |
106 | drm_framebuffer_unreference(plane->state->fb); | |
107 | ||
108 | kfree(to_mdp5_plane_state(plane->state)); | |
109 | mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL); | |
110 | ||
111 | if (plane->type == DRM_PLANE_TYPE_PRIMARY) { | |
112 | mdp5_state->zpos = 0; | |
113 | } else { | |
114 | mdp5_state->zpos = 1 + drm_plane_index(plane); | |
115 | } | |
116 | ||
117 | plane->state = &mdp5_state->base; | |
118 | } | |
119 | ||
120 | static struct drm_plane_state * | |
121 | mdp5_plane_duplicate_state(struct drm_plane *plane) | |
122 | { | |
123 | struct mdp5_plane_state *mdp5_state; | |
124 | ||
125 | if (WARN_ON(!plane->state)) | |
126 | return NULL; | |
127 | ||
128 | mdp5_state = kmemdup(to_mdp5_plane_state(plane->state), | |
129 | sizeof(*mdp5_state), GFP_KERNEL); | |
130 | ||
131 | if (mdp5_state && mdp5_state->base.fb) | |
132 | drm_framebuffer_reference(mdp5_state->base.fb); | |
133 | ||
134 | mdp5_state->mode_changed = false; | |
135 | mdp5_state->pending = false; | |
136 | ||
137 | return &mdp5_state->base; | |
138 | } | |
139 | ||
140 | static void mdp5_plane_destroy_state(struct drm_plane *plane, | |
141 | struct drm_plane_state *state) | |
142 | { | |
143 | if (state->fb) | |
144 | drm_framebuffer_unreference(state->fb); | |
145 | ||
146 | kfree(to_mdp5_plane_state(state)); | |
147 | } | |
148 | ||
06c0dd96 | 149 | static const struct drm_plane_funcs mdp5_plane_funcs = { |
ed851963 RC |
150 | .update_plane = drm_atomic_helper_update_plane, |
151 | .disable_plane = drm_atomic_helper_disable_plane, | |
06c0dd96 RC |
152 | .destroy = mdp5_plane_destroy, |
153 | .set_property = mdp5_plane_set_property, | |
ed851963 RC |
154 | .reset = mdp5_plane_reset, |
155 | .atomic_duplicate_state = mdp5_plane_duplicate_state, | |
156 | .atomic_destroy_state = mdp5_plane_destroy_state, | |
06c0dd96 RC |
157 | }; |
158 | ||
ed851963 RC |
159 | static int mdp5_plane_prepare_fb(struct drm_plane *plane, |
160 | struct drm_framebuffer *fb) | |
06c0dd96 | 161 | { |
ed851963 | 162 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
06c0dd96 | 163 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
06c0dd96 | 164 | |
ed851963 RC |
165 | DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id); |
166 | return msm_framebuffer_prepare(fb, mdp5_kms->id); | |
0deed25b SV |
167 | } |
168 | ||
ed851963 RC |
169 | static void mdp5_plane_cleanup_fb(struct drm_plane *plane, |
170 | struct drm_framebuffer *fb) | |
0deed25b SV |
171 | { |
172 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
173 | struct mdp5_kms *mdp5_kms = get_kms(plane); | |
0deed25b | 174 | |
ed851963 RC |
175 | DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id); |
176 | msm_framebuffer_cleanup(fb, mdp5_kms->id); | |
177 | } | |
0deed25b | 178 | |
ed851963 RC |
179 | static int mdp5_plane_atomic_check(struct drm_plane *plane, |
180 | struct drm_plane_state *state) | |
181 | { | |
182 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
183 | struct drm_plane_state *old_state = plane->state; | |
184 | ||
185 | DBG("%s: check (%d -> %d)", mdp5_plane->name, | |
186 | plane_enabled(old_state), plane_enabled(state)); | |
187 | ||
188 | if (plane_enabled(state) && plane_enabled(old_state)) { | |
189 | /* we cannot change SMP block configuration during scanout: */ | |
190 | bool full_modeset = false; | |
191 | if (state->fb->pixel_format != old_state->fb->pixel_format) { | |
192 | DBG("%s: pixel_format change!", mdp5_plane->name); | |
193 | full_modeset = true; | |
194 | } | |
195 | if (state->src_w != old_state->src_w) { | |
196 | DBG("%s: src_w change!", mdp5_plane->name); | |
197 | full_modeset = true; | |
198 | } | |
199 | if (to_mdp5_plane_state(old_state)->pending) { | |
200 | DBG("%s: still pending!", mdp5_plane->name); | |
201 | full_modeset = true; | |
202 | } | |
203 | if (full_modeset) { | |
204 | struct drm_crtc_state *crtc_state = | |
205 | drm_atomic_get_crtc_state(state->state, state->crtc); | |
206 | crtc_state->mode_changed = true; | |
207 | to_mdp5_plane_state(state)->mode_changed = true; | |
208 | } | |
209 | } else { | |
210 | to_mdp5_plane_state(state)->mode_changed = true; | |
211 | } | |
06c0dd96 | 212 | |
ed851963 RC |
213 | return 0; |
214 | } | |
215 | ||
f1c37e1a TR |
216 | static void mdp5_plane_atomic_update(struct drm_plane *plane, |
217 | struct drm_plane_state *old_state) | |
ed851963 RC |
218 | { |
219 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
220 | struct drm_plane_state *state = plane->state; | |
221 | ||
222 | DBG("%s: update", mdp5_plane->name); | |
0deed25b | 223 | |
ed851963 RC |
224 | if (!plane_enabled(state)) { |
225 | to_mdp5_plane_state(state)->pending = true; | |
226 | mdp5_plane_disable(plane); | |
227 | } else if (to_mdp5_plane_state(state)->mode_changed) { | |
228 | int ret; | |
229 | to_mdp5_plane_state(state)->pending = true; | |
230 | ret = mdp5_plane_mode_set(plane, | |
231 | state->crtc, state->fb, | |
232 | state->crtc_x, state->crtc_y, | |
233 | state->crtc_w, state->crtc_h, | |
234 | state->src_x, state->src_y, | |
235 | state->src_w, state->src_h); | |
236 | /* atomic_check should have ensured that this doesn't fail */ | |
237 | WARN_ON(ret < 0); | |
238 | } else { | |
239 | unsigned long flags; | |
240 | spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); | |
241 | set_scanout_locked(plane, state->fb); | |
242 | spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); | |
243 | } | |
0deed25b SV |
244 | } |
245 | ||
ed851963 RC |
246 | static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { |
247 | .prepare_fb = mdp5_plane_prepare_fb, | |
248 | .cleanup_fb = mdp5_plane_cleanup_fb, | |
249 | .atomic_check = mdp5_plane_atomic_check, | |
250 | .atomic_update = mdp5_plane_atomic_update, | |
251 | }; | |
252 | ||
253 | static void set_scanout_locked(struct drm_plane *plane, | |
0deed25b SV |
254 | struct drm_framebuffer *fb) |
255 | { | |
256 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
ed851963 RC |
257 | struct mdp5_kms *mdp5_kms = get_kms(plane); |
258 | enum mdp5_pipe pipe = mdp5_plane->pipe; | |
06c0dd96 | 259 | |
ed851963 RC |
260 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), |
261 | MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | | |
262 | MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); | |
0deed25b | 263 | |
ed851963 RC |
264 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), |
265 | MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | | |
266 | MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); | |
267 | ||
268 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), | |
269 | msm_framebuffer_iova(fb, mdp5_kms->id, 0)); | |
270 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), | |
271 | msm_framebuffer_iova(fb, mdp5_kms->id, 1)); | |
272 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), | |
273 | msm_framebuffer_iova(fb, mdp5_kms->id, 2)); | |
274 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), | |
275 | msm_framebuffer_iova(fb, mdp5_kms->id, 4)); | |
06c0dd96 RC |
276 | |
277 | plane->fb = fb; | |
278 | } | |
279 | ||
ed851963 | 280 | static int mdp5_plane_mode_set(struct drm_plane *plane, |
06c0dd96 RC |
281 | struct drm_crtc *crtc, struct drm_framebuffer *fb, |
282 | int crtc_x, int crtc_y, | |
283 | unsigned int crtc_w, unsigned int crtc_h, | |
284 | uint32_t src_x, uint32_t src_y, | |
285 | uint32_t src_w, uint32_t src_h) | |
286 | { | |
287 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
288 | struct mdp5_kms *mdp5_kms = get_kms(plane); | |
289 | enum mdp5_pipe pipe = mdp5_plane->pipe; | |
290 | const struct mdp_format *format; | |
291 | uint32_t nplanes, config = 0; | |
292 | uint32_t phasex_step = 0, phasey_step = 0; | |
293 | uint32_t hdecm = 0, vdecm = 0; | |
0deed25b | 294 | unsigned long flags; |
bfcdfb0e | 295 | int ret; |
06c0dd96 RC |
296 | |
297 | nplanes = drm_format_num_planes(fb->pixel_format); | |
298 | ||
299 | /* bad formats should already be rejected: */ | |
300 | if (WARN_ON(nplanes > pipe2nclients(pipe))) | |
301 | return -EINVAL; | |
302 | ||
303 | /* src values are in Q16 fixed point, convert to integer: */ | |
304 | src_x = src_x >> 16; | |
305 | src_y = src_y >> 16; | |
306 | src_w = src_w >> 16; | |
307 | src_h = src_h >> 16; | |
308 | ||
309 | DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, | |
310 | fb->base.id, src_x, src_y, src_w, src_h, | |
311 | crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); | |
312 | ||
bfcdfb0e | 313 | /* Request some memory from the SMP: */ |
42238da8 | 314 | ret = mdp5_smp_request(mdp5_kms->smp, |
bfcdfb0e SV |
315 | mdp5_plane->pipe, fb->pixel_format, src_w); |
316 | if (ret) | |
317 | return ret; | |
06c0dd96 RC |
318 | |
319 | /* | |
320 | * Currently we update the hw for allocations/requests immediately, | |
321 | * but once atomic modeset/pageflip is in place, the allocation | |
322 | * would move into atomic->check_plane_state(), while updating the | |
323 | * hw would remain here: | |
324 | */ | |
42238da8 | 325 | mdp5_smp_configure(mdp5_kms->smp, pipe); |
06c0dd96 RC |
326 | |
327 | if (src_w != crtc_w) { | |
328 | config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; | |
329 | /* TODO calc phasex_step, hdecm */ | |
330 | } | |
331 | ||
332 | if (src_h != crtc_h) { | |
333 | config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; | |
334 | /* TODO calc phasey_step, vdecm */ | |
335 | } | |
336 | ||
0deed25b SV |
337 | spin_lock_irqsave(&mdp5_plane->pipe_lock, flags); |
338 | ||
06c0dd96 RC |
339 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), |
340 | MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) | | |
341 | MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h)); | |
342 | ||
343 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), | |
344 | MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | | |
345 | MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); | |
346 | ||
347 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), | |
348 | MDP5_PIPE_SRC_XY_X(src_x) | | |
349 | MDP5_PIPE_SRC_XY_Y(src_y)); | |
350 | ||
351 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), | |
352 | MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | | |
353 | MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); | |
354 | ||
355 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), | |
356 | MDP5_PIPE_OUT_XY_X(crtc_x) | | |
357 | MDP5_PIPE_OUT_XY_Y(crtc_y)); | |
358 | ||
06c0dd96 RC |
359 | format = to_mdp_format(msm_framebuffer_format(fb)); |
360 | ||
361 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), | |
362 | MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | | |
363 | MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | | |
364 | MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | | |
365 | MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | | |
366 | COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | | |
367 | MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | | |
368 | MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | | |
369 | COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | | |
370 | MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | | |
371 | MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); | |
372 | ||
373 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), | |
374 | MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | | |
375 | MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | | |
376 | MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | | |
377 | MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); | |
378 | ||
379 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), | |
380 | MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); | |
381 | ||
382 | /* not using secure mode: */ | |
383 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); | |
384 | ||
385 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); | |
386 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); | |
387 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), | |
388 | MDP5_PIPE_DECIMATION_VERT(vdecm) | | |
389 | MDP5_PIPE_DECIMATION_HORZ(hdecm)); | |
390 | mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), | |
391 | MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | | |
392 | MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | | |
393 | MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | | |
394 | MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | | |
395 | MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | | |
396 | MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); | |
397 | ||
ed851963 | 398 | set_scanout_locked(plane, fb); |
0deed25b SV |
399 | |
400 | spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags); | |
401 | ||
0deed25b | 402 | return ret; |
06c0dd96 RC |
403 | } |
404 | ||
405 | void mdp5_plane_complete_flip(struct drm_plane *plane) | |
406 | { | |
407 | struct mdp5_kms *mdp5_kms = get_kms(plane); | |
ed851963 RC |
408 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); |
409 | enum mdp5_pipe pipe = mdp5_plane->pipe; | |
410 | ||
411 | DBG("%s: complete flip", mdp5_plane->name); | |
06c0dd96 | 412 | |
42238da8 | 413 | mdp5_smp_commit(mdp5_kms->smp, pipe); |
ed851963 RC |
414 | |
415 | to_mdp5_plane_state(plane->state)->pending = false; | |
06c0dd96 RC |
416 | } |
417 | ||
418 | enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) | |
419 | { | |
420 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
421 | return mdp5_plane->pipe; | |
422 | } | |
423 | ||
0deed25b SV |
424 | uint32_t mdp5_plane_get_flush(struct drm_plane *plane) |
425 | { | |
426 | struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); | |
427 | ||
428 | return mdp5_plane->flush_mask; | |
429 | } | |
430 | ||
06c0dd96 RC |
431 | /* initialize plane */ |
432 | struct drm_plane *mdp5_plane_init(struct drm_device *dev, | |
0deed25b | 433 | enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset) |
06c0dd96 RC |
434 | { |
435 | struct drm_plane *plane = NULL; | |
436 | struct mdp5_plane *mdp5_plane; | |
437 | int ret; | |
2d82d188 | 438 | enum drm_plane_type type; |
06c0dd96 RC |
439 | |
440 | mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); | |
441 | if (!mdp5_plane) { | |
442 | ret = -ENOMEM; | |
443 | goto fail; | |
444 | } | |
445 | ||
446 | plane = &mdp5_plane->base; | |
447 | ||
448 | mdp5_plane->pipe = pipe; | |
449 | mdp5_plane->name = pipe2name(pipe); | |
450 | ||
451 | mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats, | |
452 | ARRAY_SIZE(mdp5_plane->formats)); | |
453 | ||
0deed25b SV |
454 | mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe); |
455 | mdp5_plane->reg_offset = reg_offset; | |
456 | spin_lock_init(&mdp5_plane->pipe_lock); | |
457 | ||
2d82d188 | 458 | type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; |
ed851963 | 459 | ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, |
2d82d188 MR |
460 | mdp5_plane->formats, mdp5_plane->nformats, |
461 | type); | |
ed851963 RC |
462 | if (ret) |
463 | goto fail; | |
464 | ||
465 | drm_plane_helper_add(plane, &mdp5_plane_helper_funcs); | |
06c0dd96 RC |
466 | |
467 | mdp5_plane_install_properties(plane, &plane->base); | |
468 | ||
469 | return plane; | |
470 | ||
471 | fail: | |
472 | if (plane) | |
473 | mdp5_plane_destroy(plane); | |
474 | ||
475 | return ERR_PTR(ret); | |
476 | } |