blob: 7393764aed33edb6807c79746f3975ba4f13fdd8 [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
Clarence Ipe78efb72016-06-24 18:35:21 -040024#define SHARP_STRENGTH_DEFAULT 32
25#define SHARP_EDGE_THR_DEFAULT 112
26#define SHARP_SMOOTH_THR_DEFAULT 8
27#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040028
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 */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070045 uint32_t nformats;
46 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040047
48 struct sde_hw_pipe *pipe_hw;
49 struct sde_hw_pipe_cfg pipe_cfg;
50 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040051 struct sde_hw_sharp_cfg sharp_cfg;
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
Clarence Ipe78efb72016-06-24 18:35:21 -040060static void _sde_plane_set_scanout(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040061 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
Clarence Ipe78efb72016-06-24 18:35:21 -040084static void _sde_plane_setup_scaler(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040085 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 */
Clarence Ipe78efb72016-06-24 18:35:21 -040090 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040091 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -040092 phase_steps[SDE_SSPP_COMP_1_2] =
93 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
94 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
95 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040096
97 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -040098 if (fmt->is_yuv || src != dst) {
99 filter[SDE_SSPP_COMP_3] =
100 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
101 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400102
Clarence Ipe78efb72016-06-24 18:35:21 -0400103 if (fmt->is_yuv) {
104 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
105 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
106 } else {
107 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
108 filter[SDE_SSPP_COMP_1_2] =
109 SDE_MDP_SCALE_FILTER_NEAREST;
110 }
111 } else {
112 /* disable scaler */
113 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
114 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
115 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400116 }
117}
118
Clarence Ipe78efb72016-06-24 18:35:21 -0400119static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400120 uint32_t src, uint32_t dst, uint32_t decimated_src,
121 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400122 int *out_edge2, enum sde_hw_filter *filter,
123 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
124 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400125{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400126 int64_t edge1, edge2, caf;
127 uint32_t src_work;
128 int i, tmp;
129
Clarence Ipe78efb72016-06-24 18:35:21 -0400130 if (plane && phase_steps && out_src && out_edge1 &&
131 out_edge2 && filter && fmt) {
132 /* handle CAF for YUV formats */
133 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400134 caf = PHASE_STEP_UNIT_SCALE;
135 else
136 caf = 0;
137
138 for (i = 0; i < SDE_MAX_PLANES; i++) {
139 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400140 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400141 src_work /= chroma_subsampling;
142 if (post_compare)
143 src = src_work;
144 if (!(fmt->is_yuv) && (src == dst)) {
145 /* unity */
146 edge1 = 0;
147 edge2 = 0;
148 } else if (dst >= src) {
149 /* upscale */
150 edge1 = (1 << PHASE_RESIDUAL);
151 edge1 -= caf;
152 edge2 = (1 << PHASE_RESIDUAL);
153 edge2 += (dst - 1) * *(phase_steps + i);
154 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
155 edge2 += caf;
156 edge2 = -(edge2);
157 } else {
158 /* downscale */
159 edge1 = 0;
160 edge2 = (dst - 1) * *(phase_steps + i);
161 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
162 edge2 += *(phase_steps + i);
163 edge2 = -(edge2);
164 }
165
166 /* only enable CAF for luma plane */
167 caf = 0;
168
169 /* populate output arrays */
170 *(out_src + i) = src_work;
171
172 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400173 if (edge1 >= 0) {
174 tmp = (uint32_t)edge1;
175 tmp >>= PHASE_STEP_SHIFT;
176 *(out_edge1 + i) = -tmp;
177 } else {
178 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400179 *(out_edge1 + i) =
180 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
181 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400182 }
183 if (edge2 >= 0) {
184 tmp = (uint32_t)edge2;
185 tmp >>= PHASE_STEP_SHIFT;
186 *(out_edge2 + i) = -tmp;
187 } else {
188 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400189 *(out_edge2 + i) =
190 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
191 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400192 }
193 }
194 }
195}
196
Clarence Ipe78efb72016-06-24 18:35:21 -0400197static void _sde_plane_setup_csc(struct sde_plane *psde,
198 struct sde_plane_state *pstate,
199 struct sde_mdp_format_params *fmt)
200{
201 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
202 {
203 0x0254, 0x0000, 0x0331,
204 0x0254, 0xff37, 0xfe60,
205 0x0254, 0x0409, 0x0000,
206 },
207 { 0xfff0, 0xff80, 0xff80,},
208 { 0x0, 0x0, 0x0,},
209 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
210 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
211 };
212
213 static const struct sde_csc_cfg sde_csc_NOP = {
214 {
215 0x0200, 0x0000, 0x0000,
216 0x0000, 0x0200, 0x0000,
217 0x0000, 0x0000, 0x0200,
218 },
219 { 0x0, 0x0, 0x0,},
220 { 0x0, 0x0, 0x0,},
221 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
222 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
223 };
224
225 if (!psde->pipe_hw->ops.setup_csc)
226 return;
227
228 if (fmt->is_yuv)
229 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
230 (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L);
231 else
232 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
233 (struct sde_csc_cfg *)&sde_csc_NOP);
234}
235
236static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700237 struct drm_crtc *crtc, struct drm_framebuffer *fb,
238 int crtc_x, int crtc_y,
239 unsigned int crtc_w, unsigned int crtc_h,
240 uint32_t src_x, uint32_t src_y,
241 uint32_t src_w, uint32_t src_h)
242{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400243 struct sde_plane *psde = to_sde_plane(plane);
244 struct sde_plane_state *pstate;
245 const struct mdp_format *format;
246 uint32_t nplanes, pix_format, tmp;
247 int i;
248 struct sde_mdp_format_params *fmt;
249 struct sde_hw_pixel_ext *pe;
250 int ret = 0;
251
252 SDE_PLANE_DEBUG_START();
253 nplanes = drm_format_num_planes(fb->pixel_format);
254
255 pstate = to_sde_plane_state(plane->state);
256
257 format = to_mdp_format(msm_framebuffer_format(fb));
258 pix_format = format->base.pixel_format;
259
260 /* src values are in Q16 fixed point, convert to integer */
261 src_x = src_x >> 16;
262 src_y = src_y >> 16;
263 src_w = src_w >> 16;
264 src_h = src_h >> 16;
265
266 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->name,
267 fb->base.id, src_x, src_y, src_w, src_h,
268 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
269
270 /* update format configuration */
271 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
272
273 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400274 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400275 psde->pipe_cfg.src.width = fb->width;
276 psde->pipe_cfg.src.height = fb->height;
277 psde->pipe_cfg.src.num_planes = nplanes;
278
Clarence Ipe78efb72016-06-24 18:35:21 -0400279 _sde_plane_set_scanout(plane, &psde->pipe_cfg, fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400280
281 psde->pipe_cfg.src_rect.x = src_x;
282 psde->pipe_cfg.src_rect.y = src_y;
283 psde->pipe_cfg.src_rect.w = src_w;
284 psde->pipe_cfg.src_rect.h = src_h;
285
286 psde->pipe_cfg.dst_rect.x = crtc_x;
287 psde->pipe_cfg.dst_rect.y = crtc_y;
288 psde->pipe_cfg.dst_rect.w = crtc_w;
289 psde->pipe_cfg.dst_rect.h = crtc_h;
290
291 psde->pipe_cfg.horz_decimation = 0;
292 psde->pipe_cfg.vert_decimation = 0;
293
294 /* get sde pixel format definition */
295 fmt = psde->pipe_cfg.src.format;
296
297 /* update pixel extensions */
298 pe = &(psde->pixel_ext);
299 if (!pe->enable_pxl_ext) {
300 uint32_t chroma_subsample_h, chroma_subsample_v;
301
302 chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 :
303 drm_format_horz_chroma_subsampling(pix_format);
304 chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 :
305 drm_format_vert_chroma_subsampling(pix_format);
306
307 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
308
309 /* calculate phase steps */
Clarence Ipe78efb72016-06-24 18:35:21 -0400310 _sde_plane_setup_scaler(plane, src_w, crtc_w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400311 pe->phase_step_x,
312 pe->horz_filter, fmt, chroma_subsample_h);
Clarence Ipe78efb72016-06-24 18:35:21 -0400313 _sde_plane_setup_scaler(plane, src_h, crtc_h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400314 pe->phase_step_y,
315 pe->vert_filter, fmt, chroma_subsample_v);
316
317 /* calculate left/right/top/bottom pixel extentions */
318 tmp = DECIMATED_DIMENSION(src_w,
319 psde->pipe_cfg.horz_decimation);
320 if (fmt->is_yuv)
321 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400322 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400323 pe->phase_step_x,
324 pe->roi_w,
325 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400326 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400327 chroma_subsample_h, 0);
328
329 tmp = DECIMATED_DIMENSION(src_h,
330 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400331 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400332 pe->phase_step_y,
333 pe->roi_h,
334 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400335 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400336 chroma_subsample_v, 1);
337
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400338 for (i = 0; i < SDE_MAX_PLANES; i++) {
339 if (pe->num_ext_pxls_left[i] >= 0)
340 pe->left_rpt[i] =
341 pe->num_ext_pxls_left[i];
342 else
343 pe->left_ftch[i] =
344 pe->num_ext_pxls_left[i];
345
346 if (pe->num_ext_pxls_right[i] >= 0)
347 pe->right_rpt[i] =
348 pe->num_ext_pxls_right[i];
349 else
350 pe->right_ftch[i] =
351 pe->num_ext_pxls_right[i];
352
353 if (pe->num_ext_pxls_top[i] >= 0)
354 pe->top_rpt[i] =
355 pe->num_ext_pxls_top[i];
356 else
357 pe->top_ftch[i] =
358 pe->num_ext_pxls_top[i];
359
360 if (pe->num_ext_pxls_btm[i] >= 0)
361 pe->btm_rpt[i] =
362 pe->num_ext_pxls_btm[i];
363 else
364 pe->btm_ftch[i] =
365 pe->num_ext_pxls_btm[i];
366 }
367 }
368
369 if (psde->pipe_hw->ops.setup_sourceformat)
370 psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw,
Clarence Ipe78efb72016-06-24 18:35:21 -0400371 &psde->pipe_cfg, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400372 if (psde->pipe_hw->ops.setup_rects)
373 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
374 &psde->pipe_cfg, &psde->pixel_ext);
375
Clarence Ipe78efb72016-06-24 18:35:21 -0400376 /* update sharpening */
377 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
378 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
379 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
380 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
381
382 if (psde->pipe_hw->ops.setup_sharpening)
383 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
384 &psde->sharp_cfg);
385
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400386 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400387 if (fmt->is_yuv)
388 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400389
390 SDE_PLANE_DEBUG_END();
391 return ret;
392}
393
394static int sde_plane_prepare_fb(struct drm_plane *plane,
395 const struct drm_plane_state *new_state)
396{
397 struct drm_framebuffer *fb = new_state->fb;
398 struct sde_plane *psde = to_sde_plane(plane);
399
400 if (!new_state->fb)
401 return 0;
402
403 SDE_PLANE_DEBUG_START();
404 SDE_PLANE_DEBUG_END();
405 DBG("%s: prepare: FB[%u]", psde->name, fb->base.id);
406 return msm_framebuffer_prepare(fb, psde->mmu_id);
407}
408
409static void sde_plane_cleanup_fb(struct drm_plane *plane,
410 const struct drm_plane_state *old_state)
411{
412 struct drm_framebuffer *fb = old_state->fb;
413 struct sde_plane *psde = to_sde_plane(plane);
414
415 if (!fb)
416 return;
417
418 SDE_PLANE_DEBUG_START();
419 SDE_PLANE_DEBUG_END();
420 DBG("%s: cleanup: FB[%u]", psde->name, fb->base.id);
421 msm_framebuffer_cleanup(fb, psde->mmu_id);
422}
423
424static int sde_plane_atomic_check(struct drm_plane *plane,
425 struct drm_plane_state *state)
426{
427 struct sde_plane *psde = to_sde_plane(plane);
428 struct drm_plane_state *old_state = plane->state;
429 const struct mdp_format *format;
430
431 SDE_PLANE_DEBUG_START();
432 SDE_PLANE_DEBUG_END();
433 DBG("%s: check (%d -> %d)", psde->name,
434 sde_plane_enabled(old_state), sde_plane_enabled(state));
435
436 if (sde_plane_enabled(state)) {
437 /* CIFIX: don't use mdp format? */
438 format = to_mdp_format(msm_framebuffer_format(state->fb));
439 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400440 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400441 !(psde->features & BIT(SDE_SSPP_CSC)))) {
442 dev_err(plane->dev->dev,
443 "Pipe doesn't support YUV\n");
444
445 return -EINVAL;
446 }
447
Clarence Ipe78efb72016-06-24 18:35:21 -0400448 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400449 (((state->src_w >> 16) != state->crtc_w) ||
450 ((state->src_h >> 16) != state->crtc_h))) {
451 dev_err(plane->dev->dev,
452 "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
453 state->src_w >> 16, state->src_h >> 16,
454 state->crtc_w, state->crtc_h);
455
456 return -EINVAL;
457 }
458 }
459
460 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
461 /* we cannot change SMP block configuration during scanout: */
462 bool full_modeset = false;
463
464 if (state->fb->pixel_format != old_state->fb->pixel_format) {
465 DBG("%s: pixel_format change!", psde->name);
466 full_modeset = true;
467 }
468 if (state->src_w != old_state->src_w) {
469 DBG("%s: src_w change!", psde->name);
470 full_modeset = true;
471 }
472 if (to_sde_plane_state(old_state)->pending) {
473 DBG("%s: still pending!", psde->name);
474 full_modeset = true;
475 }
476 if (full_modeset) {
477 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400478 drm_atomic_get_crtc_state(state->state,
479 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400480 crtc_state->mode_changed = true;
481 to_sde_plane_state(state)->mode_changed = true;
482 }
483 } else {
484 to_sde_plane_state(state)->mode_changed = true;
485 }
486
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700487 return 0;
488}
489
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400490static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400491 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700492{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400493 struct sde_plane *sde_plane = to_sde_plane(plane);
494 struct drm_plane_state *state = plane->state;
495
496 DBG("%s: update", sde_plane->name);
497
498 SDE_PLANE_DEBUG_START();
499 if (!sde_plane_enabled(state)) {
500 to_sde_plane_state(state)->pending = true;
501 } else if (to_sde_plane_state(state)->mode_changed) {
502 int ret;
503
504 to_sde_plane_state(state)->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400505 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400506 state->crtc, state->fb,
507 state->crtc_x, state->crtc_y,
508 state->crtc_w, state->crtc_h,
509 state->src_x, state->src_y,
510 state->src_w, state->src_h);
511 /* atomic_check should have ensured that this doesn't fail */
512 WARN_ON(ret < 0);
513 } else {
Clarence Ipe78efb72016-06-24 18:35:21 -0400514 _sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400515 }
516 SDE_PLANE_DEBUG_END();
517}
518
Clarence Ipe78efb72016-06-24 18:35:21 -0400519static void _sde_plane_install_range_property(struct drm_plane *plane,
520 struct drm_device *dev, const char *name,
521 uint64_t min, uint64_t max, uint64_t init,
522 struct drm_property **prop)
523{
524 if (plane && dev && name && prop) {
525 /* only create the property once */
526 if (*prop == 0) {
527 *prop = drm_property_create_range(dev,
528 0 /* flags */, name, min, max);
529 if (*prop == 0)
530 dev_warn(dev->dev,
531 "Create property %s failed\n", name);
532 }
533
534 /* always attach property, if created */
535 if (*prop)
536 drm_object_attach_property(&plane->base, *prop, init);
537 }
538}
539
540static void _sde_plane_install_blob_property(struct drm_plane *plane,
541 struct drm_device *dev, const char *name,
542 struct drm_property **prop)
543{
544}
545
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400546/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400547static void _sde_plane_install_properties(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400548 struct drm_mode_object *obj)
549{
550 struct drm_device *dev = plane->dev;
551 struct msm_drm_private *dev_priv = dev->dev_private;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400552
553 SDE_PLANE_DEBUG_START();
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400554
Clarence Ipe78efb72016-06-24 18:35:21 -0400555 /* range/enum properties */
556 _sde_plane_install_range_property(plane, dev, "zpos", 1, 255, 1,
557 &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400558
Clarence Ipe78efb72016-06-24 18:35:21 -0400559 /* blob properties */
560 _sde_plane_install_blob_property(plane, dev, "pixext",
561 &(dev_priv->plane_property[PLANE_PROP_PIXEXT]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400562
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400563 SDE_PLANE_DEBUG_END();
564}
565
566static int sde_plane_atomic_set_property(struct drm_plane *plane,
567 struct drm_plane_state *state, struct drm_property *property,
568 uint64_t val)
569{
570 struct drm_device *dev = plane->dev;
571 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400572 struct drm_property_blob *blob, **prop_blob;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400574 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400575
576 SDE_PLANE_DEBUG_START();
577
578 pstate = to_sde_plane_state(state);
579
Clarence Ipe78efb72016-06-24 18:35:21 -0400580 for (idx = 0; idx < PLANE_PROP_COUNT && ret; ++idx) {
581 if (dev_priv->plane_property[idx] == property) {
582 DBG("Set property %d <= %d", idx, (int)val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400583
Clarence Ipe78efb72016-06-24 18:35:21 -0400584 /* FUTURE: Add special handling here */
585 if (property->flags & DRM_MODE_PROP_BLOB) {
586 blob = drm_property_lookup_blob(dev,
587 (uint32_t)val);
588 if (!blob) {
589 dev_err(dev->dev, "Blob not found\n");
590 val = 0;
591 } else {
592 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400593
Clarence Ipe78efb72016-06-24 18:35:21 -0400594 /* save blobs for later */
595 prop_blob =
596 &pstate->property_blobs[idx -
597 PLANE_PROP_FIRSTBLOB];
598 /* need to clear previous reference */
599 if (*prop_blob)
600 drm_property_unreference_blob(
601 *prop_blob);
602 *prop_blob = blob;
603 }
604 }
605 pstate->property_values[idx] = val;
606 ret = 0;
607 }
608 }
609
610 if (ret == -EINVAL)
611 dev_err(dev->dev, "Invalid property set\n");
612
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400613 SDE_PLANE_DEBUG_END();
614 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400615}
616
617static int sde_plane_set_property(struct drm_plane *plane,
618 struct drm_property *property, uint64_t val)
619{
620 int rc;
621
622 SDE_PLANE_DEBUG_START();
623 rc = sde_plane_atomic_set_property(plane, plane->state, property,
624 val);
625 SDE_PLANE_DEBUG_END();
626 return rc;
627}
628
629static int sde_plane_atomic_get_property(struct drm_plane *plane,
630 const struct drm_plane_state *state,
631 struct drm_property *property, uint64_t *val)
632{
633 struct drm_device *dev = plane->dev;
634 struct sde_plane_state *pstate;
635 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400636 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400637
638 SDE_PLANE_DEBUG_START();
Clarence Ipe78efb72016-06-24 18:35:21 -0400639
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400640 pstate = to_sde_plane_state(state);
641
Clarence Ipe78efb72016-06-24 18:35:21 -0400642 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
643 if (dev_priv->plane_property[idx] == property) {
644 *val = pstate->property_values[idx];
645 DBG("Get property %d %lld", idx, *val);
646 ret = 0;
647 break;
648 }
649 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400650
Clarence Ipe78efb72016-06-24 18:35:21 -0400651 if (ret == -EINVAL)
652 dev_err(dev->dev, "Invalid property get\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400653
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400654 SDE_PLANE_DEBUG_END();
Clarence Ipe78efb72016-06-24 18:35:21 -0400655
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400656 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700657}
658
659static void sde_plane_destroy(struct drm_plane *plane)
660{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400661 struct sde_plane *psde = to_sde_plane(plane);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700662
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400663 SDE_PLANE_DEBUG_START();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700664
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400665 if (psde->pipe_hw)
666 sde_hw_sspp_destroy(psde->pipe_hw);
667
668 drm_plane_helper_disable(plane);
Clarence Ipe78efb72016-06-24 18:35:21 -0400669
670 /* this will destroy the states as well */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700671 drm_plane_cleanup(plane);
672
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400673 kfree(psde);
674
675 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700676}
677
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400678static void sde_plane_destroy_state(struct drm_plane *plane,
679 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700680{
Clarence Ipe78efb72016-06-24 18:35:21 -0400681 struct sde_plane_state *pstate;
682 int i;
683
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400684 SDE_PLANE_DEBUG_START();
Clarence Ipe78efb72016-06-24 18:35:21 -0400685
686 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400687 if (state->fb)
688 drm_framebuffer_unreference(state->fb);
689
Clarence Ipe78efb72016-06-24 18:35:21 -0400690 pstate = to_sde_plane_state(state);
691
692 /* remove ref count for blobs */
693 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
694 if (pstate->property_blobs[i])
695 drm_property_unreference_blob(
696 pstate->property_blobs[i]);
697
698 kfree(pstate);
699
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400700 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700701}
702
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400703static struct drm_plane_state *
704sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700705{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400706 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400707 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400708
709 if (WARN_ON(!plane->state))
710 return NULL;
711
712 SDE_PLANE_DEBUG_START();
713 pstate = kmemdup(to_sde_plane_state(plane->state),
714 sizeof(*pstate), GFP_KERNEL);
Clarence Ipe78efb72016-06-24 18:35:21 -0400715 if (pstate) {
716 /* add ref count for frame buffer */
717 if (pstate->base.fb)
718 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400719
Clarence Ipe78efb72016-06-24 18:35:21 -0400720 /* add ref count for blobs */
721 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
722 if (pstate->property_blobs[i])
723 drm_property_reference_blob(
724 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400725
Clarence Ipe78efb72016-06-24 18:35:21 -0400726 pstate->mode_changed = false;
727 pstate->pending = false;
728 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400729 SDE_PLANE_DEBUG_END();
730
Clarence Ipe78efb72016-06-24 18:35:21 -0400731 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400732}
733
734static void sde_plane_reset(struct drm_plane *plane)
735{
736 struct sde_plane_state *pstate;
737
738 SDE_PLANE_DEBUG_START();
739 if (plane->state && plane->state->fb)
740 drm_framebuffer_unreference(plane->state->fb);
741
742 kfree(to_sde_plane_state(plane->state));
743 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
744
745 memset(pstate, 0, sizeof(struct sde_plane_state));
746
747 /* assign default blend parameters */
Clarence Ipe78efb72016-06-24 18:35:21 -0400748 pstate->property_values[PLANE_PROP_ALPHA] = 255;
749 pstate->property_values[PLANE_PROP_PREMULTIPLIED] = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400750
751 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
Clarence Ipe78efb72016-06-24 18:35:21 -0400752 pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400753 else
Clarence Ipe78efb72016-06-24 18:35:21 -0400754 pstate->property_values[PLANE_PROP_ZPOS] =
755 STAGE0 + drm_plane_index(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400756
757 pstate->base.plane = plane;
758
759 plane->state = &pstate->base;
760 SDE_PLANE_DEBUG_END();
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700761}
762
763static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400764 .update_plane = drm_atomic_helper_update_plane,
765 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700766 .destroy = sde_plane_destroy,
767 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400768 .atomic_set_property = sde_plane_atomic_set_property,
769 .atomic_get_property = sde_plane_atomic_get_property,
770 .reset = sde_plane_reset,
771 .atomic_duplicate_state = sde_plane_duplicate_state,
772 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700773};
774
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400775static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
776 .prepare_fb = sde_plane_prepare_fb,
777 .cleanup_fb = sde_plane_cleanup_fb,
778 .atomic_check = sde_plane_atomic_check,
779 .atomic_update = sde_plane_atomic_update,
780};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700781
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400782enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700783{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400784 struct sde_plane *sde_plane = to_sde_plane(plane);
785
786 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700787}
788
789/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -0400790struct drm_plane *sde_plane_init(struct drm_device *dev,
791 uint32_t pipe, bool private_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700792{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400793 static const char tmp_name[] = "---";
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700794 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400795 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400796 struct msm_drm_private *priv;
797 struct sde_kms *kms;
798 struct sde_mdss_cfg *sde_cat;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700799 int ret;
800 enum drm_plane_type type;
801
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400802 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -0400803 if (!priv) {
804 DRM_ERROR("[%u]Private data is NULL\n", pipe);
805 goto exit;
806 }
807
808 if (!priv->kms) {
809 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
810 goto exit;
811 }
812 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400813
814 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
815 if (!psde) {
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700816 ret = -ENOMEM;
817 goto fail;
818 }
819
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400820 memset(psde, 0, sizeof(*psde));
821
822 plane = &psde->base;
823
824 psde->pipe = pipe;
825 psde->name = tmp_name;
826
827 if (kms) {
828 /* mmu id for buffer mapping */
829 psde->mmu_id = kms->mmu_id;
830
831 /* check catalog for features mask */
832 sde_cat = kms->catalog;
833 if (sde_cat)
834 psde->features = sde_cat->sspp[pipe].features;
835 }
836 psde->nformats = mdp_get_formats(psde->formats,
837 ARRAY_SIZE(psde->formats),
838 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -0400839 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700840
841 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400842 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
843 psde->formats, psde->nformats,
844 type);
845 if (ret)
846 goto fail;
847
848 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700849
Clarence Ipe78efb72016-06-24 18:35:21 -0400850 _sde_plane_install_properties(plane, &plane->base);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700851
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400852 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
853 if (IS_ERR(psde->pipe_hw)) {
854 ret = PTR_ERR(psde->pipe_hw);
855 psde->pipe_hw = NULL;
856 goto fail;
857 }
858
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400859 pr_err("%s: Successfully created plane\n", __func__);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700860 return plane;
861
862fail:
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400863 pr_err("%s: Plane creation failed\n", __func__);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700864 if (plane)
865 sde_plane_destroy(plane);
Ben Chan78647cd2016-06-26 22:02:47 -0400866exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700867 return ERR_PTR(ret);
868}