blob: 09db61b63db42865fc581b1721b55fbea7eef7a3 [file] [log] [blame]
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include "sde_kms.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040014#include "sde_hwio.h"
15#include "sde_hw_mdp_ctl.h"
16#include "sde_mdp_formats.h"
17#include "sde_hw_sspp.h"
18
19#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
20#define PHASE_STEP_SHIFT 21
21#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
22#define PHASE_RESIDUAL 15
23
24#define SDE_PLANE_FEATURE_SCALER \
25 (BIT(SDE_SSPP_SCALAR_QSEED2)| \
26 BIT(SDE_SSPP_SCALAR_QSEED3)| \
27 BIT(SDE_SSPP_SCALAR_RGB))
28
29#ifndef SDE_PLANE_DEBUG_START
30#define SDE_PLANE_DEBUG_START()
31#endif
32
33#ifndef SDE_PLANE_DEBUG_END
34#define SDE_PLANE_DEBUG_END()
35#endif
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070036
37struct sde_plane {
38 struct drm_plane base;
39 const char *name;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040040
41 int mmu_id;
42
43 enum sde_sspp pipe;
44 uint32_t features; /* capabilities from catalog */
45 uint32_t flush_mask; /* used to commit pipe registers */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070046 uint32_t nformats;
47 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040048
49 struct sde_hw_pipe *pipe_hw;
50 struct sde_hw_pipe_cfg pipe_cfg;
51 struct sde_hw_pixel_ext pixel_ext;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070052};
53#define to_sde_plane(x) container_of(x, struct sde_plane, base)
54
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040055static bool sde_plane_enabled(struct drm_plane_state *state)
56{
57 return state->fb && state->crtc;
58}
59
60static void sde_plane_set_scanout(struct drm_plane *plane,
61 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
62{
63 struct sde_plane *psde = to_sde_plane(plane);
64 int i;
65
66 if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
67 /* stride */
68 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
69 while (i) {
70 --i;
71 pipe_cfg->src.ystride[i] = fb->pitches[i];
72 }
73
74 /* address */
75 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
76 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
77 psde->mmu_id, i);
78
79 /* hw driver */
80 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
81 }
82}
83
84static void sde_plane_scale_helper(struct drm_plane *plane,
85 uint32_t src, uint32_t dst, uint32_t *phase_steps,
86 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
87 uint32_t chroma_subsampling)
88{
89 /* calcualte phase steps, leave init phase as zero */
90 phase_steps[SDE_SSPP_COMP_LUMA] =
91 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
92 phase_steps[SDE_SSPP_COMP_CHROMA] =
93 phase_steps[SDE_SSPP_COMP_LUMA] / chroma_subsampling;
94
95 /* calculate scaler config, if necessary */
96 if (src != dst) {
97 filter[SDE_SSPP_COMP_ALPHA] = (src < dst) ?
98 SDE_MDP_SCALE_FILTER_BIL :
99 SDE_MDP_SCALE_FILTER_PCMN;
100
101 if (fmt->is_yuv)
102 filter[SDE_SSPP_COMP_LUMA] = SDE_MDP_SCALE_FILTER_CA;
103 else
104 filter[SDE_SSPP_COMP_LUMA] =
105 filter[SDE_SSPP_COMP_ALPHA];
106 }
107}
108
109/* CIFIX: clean up fmt/subsampling params once we're using fourcc formats */
110static void _sde_plane_pixel_ext_helper(struct drm_plane *plane,
111 uint32_t src, uint32_t dst, uint32_t decimated_src,
112 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
113 int *out_edge2, struct sde_mdp_format_params *fmt,
114 uint32_t chroma_subsampling, bool post_compare)
115{
116 /* CIFIX: adapted from mdss_mdp_pipe_calc_pixel_extn() */
117 int64_t edge1, edge2, caf;
118 uint32_t src_work;
119 int i, tmp;
120
121 if (plane && phase_steps && out_src && out_edge1 && out_edge2 && fmt) {
122 /* enable CAF for YUV formats */
123 if (fmt->is_yuv)
124 caf = PHASE_STEP_UNIT_SCALE;
125 else
126 caf = 0;
127
128 for (i = 0; i < SDE_MAX_PLANES; i++) {
129 src_work = decimated_src;
130 if (i == 1 || i == 2)
131 src_work /= chroma_subsampling;
132 if (post_compare)
133 src = src_work;
134 if (!(fmt->is_yuv) && (src == dst)) {
135 /* unity */
136 edge1 = 0;
137 edge2 = 0;
138 } else if (dst >= src) {
139 /* upscale */
140 edge1 = (1 << PHASE_RESIDUAL);
141 edge1 -= caf;
142 edge2 = (1 << PHASE_RESIDUAL);
143 edge2 += (dst - 1) * *(phase_steps + i);
144 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
145 edge2 += caf;
146 edge2 = -(edge2);
147 } else {
148 /* downscale */
149 edge1 = 0;
150 edge2 = (dst - 1) * *(phase_steps + i);
151 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
152 edge2 += *(phase_steps + i);
153 edge2 = -(edge2);
154 }
155
156 /* only enable CAF for luma plane */
157 caf = 0;
158
159 /* populate output arrays */
160 *(out_src + i) = src_work;
161
162 /* edge updates taken from __pxl_extn_helper */
163 /* CIFIX: why are we casting first to uint32_t? */
164 if (edge1 >= 0) {
165 tmp = (uint32_t)edge1;
166 tmp >>= PHASE_STEP_SHIFT;
167 *(out_edge1 + i) = -tmp;
168 } else {
169 tmp = (uint32_t)(-edge1);
170 *(out_edge1 + i) = (tmp + PHASE_STEP_UNIT_SCALE
171 - 1) >> PHASE_STEP_SHIFT;
172 }
173 if (edge2 >= 0) {
174 tmp = (uint32_t)edge2;
175 tmp >>= PHASE_STEP_SHIFT;
176 *(out_edge2 + i) = -tmp;
177 } else {
178 tmp = (uint32_t)(-edge2);
179 *(out_edge2 + i) = (tmp + PHASE_STEP_UNIT_SCALE
180 - 1) >> PHASE_STEP_SHIFT;
181 }
182 }
183 }
184}
185
186static int sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700187 struct drm_crtc *crtc, struct drm_framebuffer *fb,
188 int crtc_x, int crtc_y,
189 unsigned int crtc_w, unsigned int crtc_h,
190 uint32_t src_x, uint32_t src_y,
191 uint32_t src_w, uint32_t src_h)
192{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400193 struct sde_plane *psde = to_sde_plane(plane);
194 struct sde_plane_state *pstate;
195 const struct mdp_format *format;
196 uint32_t nplanes, pix_format, tmp;
197 int i;
198 struct sde_mdp_format_params *fmt;
199 struct sde_hw_pixel_ext *pe;
200 int ret = 0;
201
202 SDE_PLANE_DEBUG_START();
203 nplanes = drm_format_num_planes(fb->pixel_format);
204
205 pstate = to_sde_plane_state(plane->state);
206
207 format = to_mdp_format(msm_framebuffer_format(fb));
208 pix_format = format->base.pixel_format;
209
210 /* src values are in Q16 fixed point, convert to integer */
211 src_x = src_x >> 16;
212 src_y = src_y >> 16;
213 src_w = src_w >> 16;
214 src_h = src_h >> 16;
215
216 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->name,
217 fb->base.id, src_x, src_y, src_w, src_h,
218 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
219
220 /* update format configuration */
221 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
222
223 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
224 0/* CIFIX: fmt_modifier */);
225 psde->pipe_cfg.src.width = fb->width;
226 psde->pipe_cfg.src.height = fb->height;
227 psde->pipe_cfg.src.num_planes = nplanes;
228
229 sde_plane_set_scanout(plane, &psde->pipe_cfg, fb);
230
231 psde->pipe_cfg.src_rect.x = src_x;
232 psde->pipe_cfg.src_rect.y = src_y;
233 psde->pipe_cfg.src_rect.w = src_w;
234 psde->pipe_cfg.src_rect.h = src_h;
235
236 psde->pipe_cfg.dst_rect.x = crtc_x;
237 psde->pipe_cfg.dst_rect.y = crtc_y;
238 psde->pipe_cfg.dst_rect.w = crtc_w;
239 psde->pipe_cfg.dst_rect.h = crtc_h;
240
241 psde->pipe_cfg.horz_decimation = 0;
242 psde->pipe_cfg.vert_decimation = 0;
243
244 /* get sde pixel format definition */
245 fmt = psde->pipe_cfg.src.format;
246
247 /* update pixel extensions */
248 pe = &(psde->pixel_ext);
249 if (!pe->enable_pxl_ext) {
250 uint32_t chroma_subsample_h, chroma_subsample_v;
251
252 chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 :
253 drm_format_horz_chroma_subsampling(pix_format);
254 chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 :
255 drm_format_vert_chroma_subsampling(pix_format);
256
257 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
258
259 /* calculate phase steps */
260 sde_plane_scale_helper(plane, src_w, crtc_w,
261 pe->phase_step_x,
262 pe->horz_filter, fmt, chroma_subsample_h);
263 sde_plane_scale_helper(plane, src_h, crtc_h,
264 pe->phase_step_y,
265 pe->vert_filter, fmt, chroma_subsample_v);
266
267 /* calculate left/right/top/bottom pixel extentions */
268 tmp = DECIMATED_DIMENSION(src_w,
269 psde->pipe_cfg.horz_decimation);
270 if (fmt->is_yuv)
271 tmp &= ~0x1;
272 _sde_plane_pixel_ext_helper(plane, src_w, crtc_w, tmp,
273 pe->phase_step_x,
274 pe->roi_w,
275 pe->num_ext_pxls_left,
276 pe->num_ext_pxls_right, fmt,
277 chroma_subsample_h, 0);
278
279 tmp = DECIMATED_DIMENSION(src_h,
280 psde->pipe_cfg.vert_decimation);
281 _sde_plane_pixel_ext_helper(plane, src_h, crtc_h, tmp,
282 pe->phase_step_y,
283 pe->roi_h,
284 pe->num_ext_pxls_top,
285 pe->num_ext_pxls_btm, fmt,
286 chroma_subsample_v, 1);
287
288 /* CIFIX: port "Single pixel rgb scale adjustment"? */
289
290 for (i = 0; i < SDE_MAX_PLANES; i++) {
291 if (pe->num_ext_pxls_left[i] >= 0)
292 pe->left_rpt[i] =
293 pe->num_ext_pxls_left[i];
294 else
295 pe->left_ftch[i] =
296 pe->num_ext_pxls_left[i];
297
298 if (pe->num_ext_pxls_right[i] >= 0)
299 pe->right_rpt[i] =
300 pe->num_ext_pxls_right[i];
301 else
302 pe->right_ftch[i] =
303 pe->num_ext_pxls_right[i];
304
305 if (pe->num_ext_pxls_top[i] >= 0)
306 pe->top_rpt[i] =
307 pe->num_ext_pxls_top[i];
308 else
309 pe->top_ftch[i] =
310 pe->num_ext_pxls_top[i];
311
312 if (pe->num_ext_pxls_btm[i] >= 0)
313 pe->btm_rpt[i] =
314 pe->num_ext_pxls_btm[i];
315 else
316 pe->btm_ftch[i] =
317 pe->num_ext_pxls_btm[i];
318 }
319 }
320
321 if (psde->pipe_hw->ops.setup_sourceformat)
322 psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw,
323 &psde->pipe_cfg, 0 /* CIFIX: flags */);
324 if (psde->pipe_hw->ops.setup_rects)
325 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
326 &psde->pipe_cfg, &psde->pixel_ext);
327
328 /* update csc */
329
330 SDE_PLANE_DEBUG_END();
331 return ret;
332}
333
334static int sde_plane_prepare_fb(struct drm_plane *plane,
335 const struct drm_plane_state *new_state)
336{
337 struct drm_framebuffer *fb = new_state->fb;
338 struct sde_plane *psde = to_sde_plane(plane);
339
340 if (!new_state->fb)
341 return 0;
342
343 SDE_PLANE_DEBUG_START();
344 SDE_PLANE_DEBUG_END();
345 DBG("%s: prepare: FB[%u]", psde->name, fb->base.id);
346 return msm_framebuffer_prepare(fb, psde->mmu_id);
347}
348
349static void sde_plane_cleanup_fb(struct drm_plane *plane,
350 const struct drm_plane_state *old_state)
351{
352 struct drm_framebuffer *fb = old_state->fb;
353 struct sde_plane *psde = to_sde_plane(plane);
354
355 if (!fb)
356 return;
357
358 SDE_PLANE_DEBUG_START();
359 SDE_PLANE_DEBUG_END();
360 DBG("%s: cleanup: FB[%u]", psde->name, fb->base.id);
361 msm_framebuffer_cleanup(fb, psde->mmu_id);
362}
363
364static int sde_plane_atomic_check(struct drm_plane *plane,
365 struct drm_plane_state *state)
366{
367 struct sde_plane *psde = to_sde_plane(plane);
368 struct drm_plane_state *old_state = plane->state;
369 const struct mdp_format *format;
370
371 SDE_PLANE_DEBUG_START();
372 SDE_PLANE_DEBUG_END();
373 DBG("%s: check (%d -> %d)", psde->name,
374 sde_plane_enabled(old_state), sde_plane_enabled(state));
375
376 if (sde_plane_enabled(state)) {
377 /* CIFIX: don't use mdp format? */
378 format = to_mdp_format(msm_framebuffer_format(state->fb));
379 if (MDP_FORMAT_IS_YUV(format) &&
380 (!(psde->features & SDE_PLANE_FEATURE_SCALER) ||
381 !(psde->features & BIT(SDE_SSPP_CSC)))) {
382 dev_err(plane->dev->dev,
383 "Pipe doesn't support YUV\n");
384
385 return -EINVAL;
386 }
387
388 if (!(psde->features & SDE_PLANE_FEATURE_SCALER) &&
389 (((state->src_w >> 16) != state->crtc_w) ||
390 ((state->src_h >> 16) != state->crtc_h))) {
391 dev_err(plane->dev->dev,
392 "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
393 state->src_w >> 16, state->src_h >> 16,
394 state->crtc_w, state->crtc_h);
395
396 return -EINVAL;
397 }
398 }
399
400 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
401 /* we cannot change SMP block configuration during scanout: */
402 bool full_modeset = false;
403
404 if (state->fb->pixel_format != old_state->fb->pixel_format) {
405 DBG("%s: pixel_format change!", psde->name);
406 full_modeset = true;
407 }
408 if (state->src_w != old_state->src_w) {
409 DBG("%s: src_w change!", psde->name);
410 full_modeset = true;
411 }
412 if (to_sde_plane_state(old_state)->pending) {
413 DBG("%s: still pending!", psde->name);
414 full_modeset = true;
415 }
416 if (full_modeset) {
417 struct drm_crtc_state *crtc_state =
418 drm_atomic_get_crtc_state(state->state,
419 state->crtc);
420 crtc_state->mode_changed = true;
421 to_sde_plane_state(state)->mode_changed = true;
422 }
423 } else {
424 to_sde_plane_state(state)->mode_changed = true;
425 }
426
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700427 return 0;
428}
429
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400430static void sde_plane_atomic_update(struct drm_plane *plane,
431 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700432{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400433 struct sde_plane *sde_plane = to_sde_plane(plane);
434 struct drm_plane_state *state = plane->state;
435
436 DBG("%s: update", sde_plane->name);
437
438 SDE_PLANE_DEBUG_START();
439 if (!sde_plane_enabled(state)) {
440 to_sde_plane_state(state)->pending = true;
441 } else if (to_sde_plane_state(state)->mode_changed) {
442 int ret;
443
444 to_sde_plane_state(state)->pending = true;
445 ret = sde_plane_mode_set(plane,
446 state->crtc, state->fb,
447 state->crtc_x, state->crtc_y,
448 state->crtc_w, state->crtc_h,
449 state->src_x, state->src_y,
450 state->src_w, state->src_h);
451 /* atomic_check should have ensured that this doesn't fail */
452 WARN_ON(ret < 0);
453 } else {
454 sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb);
455 }
456 SDE_PLANE_DEBUG_END();
457}
458
459/* helper to install properties which are common to planes and crtcs */
460static void sde_plane_install_properties(struct drm_plane *plane,
461 struct drm_mode_object *obj)
462{
463 struct drm_device *dev = plane->dev;
464 struct msm_drm_private *dev_priv = dev->dev_private;
465 struct drm_property *prop;
466
467 SDE_PLANE_DEBUG_START();
468#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) {}
469
470#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
471 INSTALL_PROPERTY(name, NAME, init_val, \
472 create_range, min, max)
473
474#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
475 INSTALL_PROPERTY(name, NAME, init_val, \
476 create_enum, name##_prop_enum_list, \
477 ARRAY_SIZE(name##_prop_enum_list))
478
479 INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
480
481#undef INSTALL_RANGE_PROPERTY
482#undef INSTALL_ENUM_PROPERTY
483#undef INSTALL_PROPERTY
484 SDE_PLANE_DEBUG_END();
485}
486
487static int sde_plane_atomic_set_property(struct drm_plane *plane,
488 struct drm_plane_state *state, struct drm_property *property,
489 uint64_t val)
490{
491 struct drm_device *dev = plane->dev;
492 struct sde_plane_state *pstate;
493 struct msm_drm_private *dev_priv = dev->dev_private;
494 int ret = 0;
495
496 SDE_PLANE_DEBUG_START();
497
498 pstate = to_sde_plane_state(state);
499
500#define SET_PROPERTY(name, NAME, type) do { \
501 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
502 pstate->name = (type)val; \
503 DBG("Set property %s %d", #name, (type)val); \
504 goto done; \
505 } \
506 } while (0)
507
508 SET_PROPERTY(zpos, ZPOS, uint8_t);
509
510 dev_err(dev->dev, "Invalid property\n");
511 ret = -EINVAL;
512done:
513 SDE_PLANE_DEBUG_END();
514 return ret;
515#undef SET_PROPERTY
516}
517
518static int sde_plane_set_property(struct drm_plane *plane,
519 struct drm_property *property, uint64_t val)
520{
521 int rc;
522
523 SDE_PLANE_DEBUG_START();
524 rc = sde_plane_atomic_set_property(plane, plane->state, property,
525 val);
526 SDE_PLANE_DEBUG_END();
527 return rc;
528}
529
530static int sde_plane_atomic_get_property(struct drm_plane *plane,
531 const struct drm_plane_state *state,
532 struct drm_property *property, uint64_t *val)
533{
534 struct drm_device *dev = plane->dev;
535 struct sde_plane_state *pstate;
536 struct msm_drm_private *dev_priv = dev->dev_private;
537 int ret = 0;
538
539 SDE_PLANE_DEBUG_START();
540 pstate = to_sde_plane_state(state);
541
542#define GET_PROPERTY(name, NAME, type) do { \
543 if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
544 *val = pstate->name; \
545 DBG("Get property %s %lld", #name, *val); \
546 goto done; \
547 } \
548 } while (0)
549
550 GET_PROPERTY(zpos, ZPOS, uint8_t);
551
552 dev_err(dev->dev, "Invalid property\n");
553 ret = -EINVAL;
554done:
555 SDE_PLANE_DEBUG_END();
556 return ret;
557#undef SET_PROPERTY
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700558}
559
560static void sde_plane_destroy(struct drm_plane *plane)
561{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400562 struct sde_plane *psde = to_sde_plane(plane);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700563
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400564 SDE_PLANE_DEBUG_START();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700565
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400566 if (psde->pipe_hw)
567 sde_hw_sspp_destroy(psde->pipe_hw);
568
569 drm_plane_helper_disable(plane);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700570 drm_plane_cleanup(plane);
571
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400572 kfree(psde);
573
574 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700575}
576
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400577static void sde_plane_destroy_state(struct drm_plane *plane,
578 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700579{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400580 SDE_PLANE_DEBUG_START();
581 if (state->fb)
582 drm_framebuffer_unreference(state->fb);
583
584 kfree(to_sde_plane_state(state));
585 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700586}
587
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400588static struct drm_plane_state *
589sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700590{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400591 struct sde_plane_state *pstate;
592
593 if (WARN_ON(!plane->state))
594 return NULL;
595
596 SDE_PLANE_DEBUG_START();
597 pstate = kmemdup(to_sde_plane_state(plane->state),
598 sizeof(*pstate), GFP_KERNEL);
599
600 if (pstate && pstate->base.fb)
601 drm_framebuffer_reference(pstate->base.fb);
602
603 pstate->mode_changed = false;
604 pstate->pending = false;
605 SDE_PLANE_DEBUG_END();
606
607 return &pstate->base;
608}
609
610static void sde_plane_reset(struct drm_plane *plane)
611{
612 struct sde_plane_state *pstate;
613
614 SDE_PLANE_DEBUG_START();
615 if (plane->state && plane->state->fb)
616 drm_framebuffer_unreference(plane->state->fb);
617
618 kfree(to_sde_plane_state(plane->state));
619 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
620
621 memset(pstate, 0, sizeof(struct sde_plane_state));
622
623 /* assign default blend parameters */
624 pstate->alpha = 255;
625 pstate->premultiplied = 0;
626
627 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
628 pstate->zpos = STAGE_BASE;
629 else
630 pstate->zpos = STAGE0 + drm_plane_index(plane);
631
632 pstate->base.plane = plane;
633
634 plane->state = &pstate->base;
635 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700636}
637
638static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400639 .update_plane = drm_atomic_helper_update_plane,
640 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700641 .destroy = sde_plane_destroy,
642 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400643 .atomic_set_property = sde_plane_atomic_set_property,
644 .atomic_get_property = sde_plane_atomic_get_property,
645 .reset = sde_plane_reset,
646 .atomic_duplicate_state = sde_plane_duplicate_state,
647 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700648};
649
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400650static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
651 .prepare_fb = sde_plane_prepare_fb,
652 .cleanup_fb = sde_plane_cleanup_fb,
653 .atomic_check = sde_plane_atomic_check,
654 .atomic_update = sde_plane_atomic_update,
655};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700656
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400657enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700658{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400659 struct sde_plane *sde_plane = to_sde_plane(plane);
660
661 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700662}
663
664/* initialize plane */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400665struct drm_plane *sde_plane_init(struct drm_device *dev, uint32_t pipe,
666 bool private_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700667{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400668 static const char tmp_name[] = "---";
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700669 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400670 struct sde_plane *psde;
671 struct sde_hw_ctl *sde_ctl;
672 struct msm_drm_private *priv;
673 struct sde_kms *kms;
674 struct sde_mdss_cfg *sde_cat;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700675 int ret;
676 enum drm_plane_type type;
677
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400678 priv = dev->dev_private;
679 kms = to_sde_kms(to_mdp_kms(priv->kms));
680
681 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
682 if (!psde) {
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700683 ret = -ENOMEM;
684 goto fail;
685 }
686
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400687 memset(psde, 0, sizeof(*psde));
688
689 plane = &psde->base;
690
691 psde->pipe = pipe;
692 psde->name = tmp_name;
693
694 if (kms) {
695 /* mmu id for buffer mapping */
696 psde->mmu_id = kms->mmu_id;
697
698 /* check catalog for features mask */
699 sde_cat = kms->catalog;
700 if (sde_cat)
701 psde->features = sde_cat->sspp[pipe].features;
702 }
703 psde->nformats = mdp_get_formats(psde->formats,
704 ARRAY_SIZE(psde->formats),
705 !(psde->features & BIT(SDE_SSPP_CSC)) ||
706 !(psde->features & SDE_PLANE_FEATURE_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700707
708 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400709 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
710 psde->formats, psde->nformats,
711 type);
712 if (ret)
713 goto fail;
714
715 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700716
717 sde_plane_install_properties(plane, &plane->base);
718
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400719 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
720 if (IS_ERR(psde->pipe_hw)) {
721 ret = PTR_ERR(psde->pipe_hw);
722 psde->pipe_hw = NULL;
723 goto fail;
724 }
725
726 /* cache flush mask for later */
727 sde_ctl = sde_hw_ctl_init(CTL_0, kms->mmio, sde_cat);
728 if (!IS_ERR(sde_ctl)) {
729 if (sde_ctl->ops.get_bitmask_sspp)
730 sde_ctl->ops.get_bitmask_sspp(sde_ctl,
731 &psde->flush_mask, pipe);
732 sde_hw_ctl_destroy(sde_ctl);
733 }
734
735 pr_err("%s: Successfully created plane\n", __func__);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700736 return plane;
737
738fail:
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400739 pr_err("%s: Plane creation failed\n", __func__);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700740 if (plane)
741 sde_plane_destroy(plane);
742
743 return ERR_PTR(ret);
744}