blob: 395967eb92b1d4357327901154155e1975bae9bd [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 */
Clarence Ip4ce59322016-06-26 22:27:51 -040012#include <linux/debugfs.h>
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070013#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
Clarence Ip4ce59322016-06-26 22:27:51 -040029#define SDE_PIPE_NAME_SIZE 8
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070030
31struct sde_plane {
32 struct drm_plane base;
33 const char *name;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040034
35 int mmu_id;
36
37 enum sde_sspp pipe;
38 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070039 uint32_t nformats;
40 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040041
42 struct sde_hw_pipe *pipe_hw;
43 struct sde_hw_pipe_cfg pipe_cfg;
44 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040045 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip4ce59322016-06-26 22:27:51 -040046
47 char pipe_name[SDE_PIPE_NAME_SIZE];
48
49 /* debugfs related stuff */
50 struct dentry *debugfs_root;
51 struct sde_debugfs_regset32 debugfs_src;
52 struct sde_debugfs_regset32 debugfs_scaler;
53 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070054};
55#define to_sde_plane(x) container_of(x, struct sde_plane, base)
56
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040057static bool sde_plane_enabled(struct drm_plane_state *state)
58{
59 return state->fb && state->crtc;
60}
61
Clarence Ipe78efb72016-06-24 18:35:21 -040062static void _sde_plane_set_scanout(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040063 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
64{
65 struct sde_plane *psde = to_sde_plane(plane);
66 int i;
67
68 if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
69 /* stride */
70 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
71 while (i) {
72 --i;
73 pipe_cfg->src.ystride[i] = fb->pitches[i];
74 }
75
76 /* address */
77 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
78 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
79 psde->mmu_id, i);
80
81 /* hw driver */
82 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
83 }
84}
85
Clarence Ipe78efb72016-06-24 18:35:21 -040086static void _sde_plane_setup_scaler(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040087 uint32_t src, uint32_t dst, uint32_t *phase_steps,
88 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
89 uint32_t chroma_subsampling)
90{
91 /* calcualte phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -040092 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040093 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -040094 phase_steps[SDE_SSPP_COMP_1_2] =
95 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
96 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
97 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040098
99 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -0400100 if (fmt->is_yuv || src != dst) {
101 filter[SDE_SSPP_COMP_3] =
102 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
103 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400104
Clarence Ipe78efb72016-06-24 18:35:21 -0400105 if (fmt->is_yuv) {
106 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
107 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
108 } else {
109 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
110 filter[SDE_SSPP_COMP_1_2] =
111 SDE_MDP_SCALE_FILTER_NEAREST;
112 }
113 } else {
114 /* disable scaler */
115 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
116 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
117 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400118 }
119}
120
Clarence Ipe78efb72016-06-24 18:35:21 -0400121static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400122 uint32_t src, uint32_t dst, uint32_t decimated_src,
123 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400124 int *out_edge2, enum sde_hw_filter *filter,
125 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
126 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400127{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400128 int64_t edge1, edge2, caf;
129 uint32_t src_work;
130 int i, tmp;
131
Clarence Ipe78efb72016-06-24 18:35:21 -0400132 if (plane && phase_steps && out_src && out_edge1 &&
133 out_edge2 && filter && fmt) {
134 /* handle CAF for YUV formats */
135 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400136 caf = PHASE_STEP_UNIT_SCALE;
137 else
138 caf = 0;
139
140 for (i = 0; i < SDE_MAX_PLANES; i++) {
141 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400142 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400143 src_work /= chroma_subsampling;
144 if (post_compare)
145 src = src_work;
146 if (!(fmt->is_yuv) && (src == dst)) {
147 /* unity */
148 edge1 = 0;
149 edge2 = 0;
150 } else if (dst >= src) {
151 /* upscale */
152 edge1 = (1 << PHASE_RESIDUAL);
153 edge1 -= caf;
154 edge2 = (1 << PHASE_RESIDUAL);
155 edge2 += (dst - 1) * *(phase_steps + i);
156 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
157 edge2 += caf;
158 edge2 = -(edge2);
159 } else {
160 /* downscale */
161 edge1 = 0;
162 edge2 = (dst - 1) * *(phase_steps + i);
163 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
164 edge2 += *(phase_steps + i);
165 edge2 = -(edge2);
166 }
167
168 /* only enable CAF for luma plane */
169 caf = 0;
170
171 /* populate output arrays */
172 *(out_src + i) = src_work;
173
174 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400175 if (edge1 >= 0) {
176 tmp = (uint32_t)edge1;
177 tmp >>= PHASE_STEP_SHIFT;
178 *(out_edge1 + i) = -tmp;
179 } else {
180 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400181 *(out_edge1 + i) =
182 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
183 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400184 }
185 if (edge2 >= 0) {
186 tmp = (uint32_t)edge2;
187 tmp >>= PHASE_STEP_SHIFT;
188 *(out_edge2 + i) = -tmp;
189 } else {
190 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400191 *(out_edge2 + i) =
192 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
193 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400194 }
195 }
196 }
197}
198
Clarence Ipe78efb72016-06-24 18:35:21 -0400199static void _sde_plane_setup_csc(struct sde_plane *psde,
200 struct sde_plane_state *pstate,
201 struct sde_mdp_format_params *fmt)
202{
203 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
204 {
205 0x0254, 0x0000, 0x0331,
206 0x0254, 0xff37, 0xfe60,
207 0x0254, 0x0409, 0x0000,
208 },
209 { 0xfff0, 0xff80, 0xff80,},
210 { 0x0, 0x0, 0x0,},
211 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
212 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
213 };
214
215 static const struct sde_csc_cfg sde_csc_NOP = {
216 {
217 0x0200, 0x0000, 0x0000,
218 0x0000, 0x0200, 0x0000,
219 0x0000, 0x0000, 0x0200,
220 },
221 { 0x0, 0x0, 0x0,},
222 { 0x0, 0x0, 0x0,},
223 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
224 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
225 };
226
227 if (!psde->pipe_hw->ops.setup_csc)
228 return;
229
230 if (fmt->is_yuv)
231 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
232 (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L);
233 else
234 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
235 (struct sde_csc_cfg *)&sde_csc_NOP);
236}
237
238static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700239 struct drm_crtc *crtc, struct drm_framebuffer *fb,
240 int crtc_x, int crtc_y,
241 unsigned int crtc_w, unsigned int crtc_h,
242 uint32_t src_x, uint32_t src_y,
243 uint32_t src_w, uint32_t src_h)
244{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400245 struct sde_plane *psde = to_sde_plane(plane);
246 struct sde_plane_state *pstate;
247 const struct mdp_format *format;
248 uint32_t nplanes, pix_format, tmp;
249 int i;
250 struct sde_mdp_format_params *fmt;
251 struct sde_hw_pixel_ext *pe;
252 int ret = 0;
253
Clarence Ip4ce59322016-06-26 22:27:51 -0400254 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400255 nplanes = drm_format_num_planes(fb->pixel_format);
256
257 pstate = to_sde_plane_state(plane->state);
258
259 format = to_mdp_format(msm_framebuffer_format(fb));
260 pix_format = format->base.pixel_format;
261
262 /* src values are in Q16 fixed point, convert to integer */
263 src_x = src_x >> 16;
264 src_y = src_y >> 16;
265 src_w = src_w >> 16;
266 src_h = src_h >> 16;
267
Clarence Ip4ce59322016-06-26 22:27:51 -0400268 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400269 fb->base.id, src_x, src_y, src_w, src_h,
270 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
271
272 /* update format configuration */
273 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
274
275 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400276 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400277 psde->pipe_cfg.src.width = fb->width;
278 psde->pipe_cfg.src.height = fb->height;
279 psde->pipe_cfg.src.num_planes = nplanes;
280
Clarence Ipe78efb72016-06-24 18:35:21 -0400281 _sde_plane_set_scanout(plane, &psde->pipe_cfg, fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400282
283 psde->pipe_cfg.src_rect.x = src_x;
284 psde->pipe_cfg.src_rect.y = src_y;
285 psde->pipe_cfg.src_rect.w = src_w;
286 psde->pipe_cfg.src_rect.h = src_h;
287
288 psde->pipe_cfg.dst_rect.x = crtc_x;
289 psde->pipe_cfg.dst_rect.y = crtc_y;
290 psde->pipe_cfg.dst_rect.w = crtc_w;
291 psde->pipe_cfg.dst_rect.h = crtc_h;
292
293 psde->pipe_cfg.horz_decimation = 0;
294 psde->pipe_cfg.vert_decimation = 0;
295
296 /* get sde pixel format definition */
297 fmt = psde->pipe_cfg.src.format;
298
299 /* update pixel extensions */
300 pe = &(psde->pixel_ext);
301 if (!pe->enable_pxl_ext) {
302 uint32_t chroma_subsample_h, chroma_subsample_v;
303
304 chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 :
305 drm_format_horz_chroma_subsampling(pix_format);
306 chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 :
307 drm_format_vert_chroma_subsampling(pix_format);
308
309 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
310
311 /* calculate phase steps */
Clarence Ipe78efb72016-06-24 18:35:21 -0400312 _sde_plane_setup_scaler(plane, src_w, crtc_w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400313 pe->phase_step_x,
314 pe->horz_filter, fmt, chroma_subsample_h);
Clarence Ipe78efb72016-06-24 18:35:21 -0400315 _sde_plane_setup_scaler(plane, src_h, crtc_h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400316 pe->phase_step_y,
317 pe->vert_filter, fmt, chroma_subsample_v);
318
319 /* calculate left/right/top/bottom pixel extentions */
320 tmp = DECIMATED_DIMENSION(src_w,
321 psde->pipe_cfg.horz_decimation);
322 if (fmt->is_yuv)
323 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400324 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400325 pe->phase_step_x,
326 pe->roi_w,
327 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400328 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400329 chroma_subsample_h, 0);
330
331 tmp = DECIMATED_DIMENSION(src_h,
332 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400333 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400334 pe->phase_step_y,
335 pe->roi_h,
336 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400337 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400338 chroma_subsample_v, 1);
339
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400340 for (i = 0; i < SDE_MAX_PLANES; i++) {
341 if (pe->num_ext_pxls_left[i] >= 0)
342 pe->left_rpt[i] =
343 pe->num_ext_pxls_left[i];
344 else
345 pe->left_ftch[i] =
346 pe->num_ext_pxls_left[i];
347
348 if (pe->num_ext_pxls_right[i] >= 0)
349 pe->right_rpt[i] =
350 pe->num_ext_pxls_right[i];
351 else
352 pe->right_ftch[i] =
353 pe->num_ext_pxls_right[i];
354
355 if (pe->num_ext_pxls_top[i] >= 0)
356 pe->top_rpt[i] =
357 pe->num_ext_pxls_top[i];
358 else
359 pe->top_ftch[i] =
360 pe->num_ext_pxls_top[i];
361
362 if (pe->num_ext_pxls_btm[i] >= 0)
363 pe->btm_rpt[i] =
364 pe->num_ext_pxls_btm[i];
365 else
366 pe->btm_ftch[i] =
367 pe->num_ext_pxls_btm[i];
368 }
369 }
370
371 if (psde->pipe_hw->ops.setup_sourceformat)
372 psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw,
Clarence Ipe78efb72016-06-24 18:35:21 -0400373 &psde->pipe_cfg, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400374 if (psde->pipe_hw->ops.setup_rects)
375 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
376 &psde->pipe_cfg, &psde->pixel_ext);
377
Clarence Ipe78efb72016-06-24 18:35:21 -0400378 /* update sharpening */
379 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
380 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
381 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
382 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
383
384 if (psde->pipe_hw->ops.setup_sharpening)
385 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
386 &psde->sharp_cfg);
387
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400388 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400389 if (fmt->is_yuv)
390 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400391
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400392 return ret;
393}
394
395static int sde_plane_prepare_fb(struct drm_plane *plane,
396 const struct drm_plane_state *new_state)
397{
398 struct drm_framebuffer *fb = new_state->fb;
399 struct sde_plane *psde = to_sde_plane(plane);
400
401 if (!new_state->fb)
402 return 0;
403
Clarence Ip4ce59322016-06-26 22:27:51 -0400404 DBG("%s: prepare: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400405 return msm_framebuffer_prepare(fb, psde->mmu_id);
406}
407
408static void sde_plane_cleanup_fb(struct drm_plane *plane,
409 const struct drm_plane_state *old_state)
410{
411 struct drm_framebuffer *fb = old_state->fb;
412 struct sde_plane *psde = to_sde_plane(plane);
413
414 if (!fb)
415 return;
416
Clarence Ip4ce59322016-06-26 22:27:51 -0400417 DBG("%s: cleanup: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400418 msm_framebuffer_cleanup(fb, psde->mmu_id);
419}
420
421static int sde_plane_atomic_check(struct drm_plane *plane,
422 struct drm_plane_state *state)
423{
424 struct sde_plane *psde = to_sde_plane(plane);
425 struct drm_plane_state *old_state = plane->state;
426 const struct mdp_format *format;
427
Clarence Ip4ce59322016-06-26 22:27:51 -0400428 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400429 sde_plane_enabled(old_state), sde_plane_enabled(state));
430
431 if (sde_plane_enabled(state)) {
432 /* CIFIX: don't use mdp format? */
433 format = to_mdp_format(msm_framebuffer_format(state->fb));
434 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400435 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400436 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400437 DRM_ERROR("Pipe doesn't support YUV\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400438
439 return -EINVAL;
440 }
441
Clarence Ipe78efb72016-06-24 18:35:21 -0400442 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400443 (((state->src_w >> 16) != state->crtc_w) ||
444 ((state->src_h >> 16) != state->crtc_h))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400445 DRM_ERROR(
446 "Unsupported Pipe scaling (%dx%d -> %dx%d)\n",
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400447 state->src_w >> 16, state->src_h >> 16,
448 state->crtc_w, state->crtc_h);
449
450 return -EINVAL;
451 }
452 }
453
454 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
455 /* we cannot change SMP block configuration during scanout: */
456 bool full_modeset = false;
457
458 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400459 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400460 full_modeset = true;
461 }
462 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400463 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400464 full_modeset = true;
465 }
466 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400467 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400468 full_modeset = true;
469 }
470 if (full_modeset) {
471 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400472 drm_atomic_get_crtc_state(state->state,
473 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400474 crtc_state->mode_changed = true;
475 to_sde_plane_state(state)->mode_changed = true;
476 }
477 } else {
478 to_sde_plane_state(state)->mode_changed = true;
479 }
480
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700481 return 0;
482}
483
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400484static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400485 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700486{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400487 struct sde_plane *sde_plane = to_sde_plane(plane);
488 struct drm_plane_state *state = plane->state;
489
Clarence Ip4ce59322016-06-26 22:27:51 -0400490 DBG("%s: update", sde_plane->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400491
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400492 if (!sde_plane_enabled(state)) {
493 to_sde_plane_state(state)->pending = true;
494 } else if (to_sde_plane_state(state)->mode_changed) {
495 int ret;
496
497 to_sde_plane_state(state)->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400498 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400499 state->crtc, state->fb,
500 state->crtc_x, state->crtc_y,
501 state->crtc_w, state->crtc_h,
502 state->src_x, state->src_y,
503 state->src_w, state->src_h);
504 /* atomic_check should have ensured that this doesn't fail */
505 WARN_ON(ret < 0);
506 } else {
Clarence Ipe78efb72016-06-24 18:35:21 -0400507 _sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400508 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400509}
510
Clarence Ipe78efb72016-06-24 18:35:21 -0400511static void _sde_plane_install_range_property(struct drm_plane *plane,
512 struct drm_device *dev, const char *name,
513 uint64_t min, uint64_t max, uint64_t init,
514 struct drm_property **prop)
515{
516 if (plane && dev && name && prop) {
517 /* only create the property once */
518 if (*prop == 0) {
519 *prop = drm_property_create_range(dev,
520 0 /* flags */, name, min, max);
521 if (*prop == 0)
Clarence Ip4ce59322016-06-26 22:27:51 -0400522 DRM_ERROR("Create property %s failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400523 }
524
525 /* always attach property, if created */
526 if (*prop)
527 drm_object_attach_property(&plane->base, *prop, init);
528 }
529}
530
531static void _sde_plane_install_blob_property(struct drm_plane *plane,
532 struct drm_device *dev, const char *name,
533 struct drm_property **prop)
534{
535}
536
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400537/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400538static void _sde_plane_install_properties(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400539 struct drm_mode_object *obj)
540{
541 struct drm_device *dev = plane->dev;
542 struct msm_drm_private *dev_priv = dev->dev_private;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400543
Clarence Ip4ce59322016-06-26 22:27:51 -0400544 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400545
Clarence Ipe78efb72016-06-24 18:35:21 -0400546 /* range/enum properties */
547 _sde_plane_install_range_property(plane, dev, "zpos", 1, 255, 1,
548 &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400549
Clarence Ipe78efb72016-06-24 18:35:21 -0400550 /* blob properties */
551 _sde_plane_install_blob_property(plane, dev, "pixext",
552 &(dev_priv->plane_property[PLANE_PROP_PIXEXT]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400553}
554
555static int sde_plane_atomic_set_property(struct drm_plane *plane,
556 struct drm_plane_state *state, struct drm_property *property,
557 uint64_t val)
558{
559 struct drm_device *dev = plane->dev;
560 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400561 struct drm_property_blob *blob, **prop_blob;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400562 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400563 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400564
Clarence Ip4ce59322016-06-26 22:27:51 -0400565 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400566
567 pstate = to_sde_plane_state(state);
568
Clarence Ipe78efb72016-06-24 18:35:21 -0400569 for (idx = 0; idx < PLANE_PROP_COUNT && ret; ++idx) {
570 if (dev_priv->plane_property[idx] == property) {
571 DBG("Set property %d <= %d", idx, (int)val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400572
Clarence Ipe78efb72016-06-24 18:35:21 -0400573 /* FUTURE: Add special handling here */
574 if (property->flags & DRM_MODE_PROP_BLOB) {
575 blob = drm_property_lookup_blob(dev,
576 (uint32_t)val);
577 if (!blob) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400578 DRM_ERROR("Blob not found\n");
Clarence Ipe78efb72016-06-24 18:35:21 -0400579 val = 0;
580 } else {
581 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400582
Clarence Ipe78efb72016-06-24 18:35:21 -0400583 /* save blobs for later */
584 prop_blob =
585 &pstate->property_blobs[idx -
586 PLANE_PROP_FIRSTBLOB];
587 /* need to clear previous reference */
588 if (*prop_blob)
589 drm_property_unreference_blob(
590 *prop_blob);
591 *prop_blob = blob;
592 }
593 }
594 pstate->property_values[idx] = val;
595 ret = 0;
596 }
597 }
598
599 if (ret == -EINVAL)
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400600 DRM_ERROR("Invalid property set\n");
Clarence Ipe78efb72016-06-24 18:35:21 -0400601
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400602 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400603}
604
605static int sde_plane_set_property(struct drm_plane *plane,
606 struct drm_property *property, uint64_t val)
607{
608 int rc;
609
Clarence Ip4ce59322016-06-26 22:27:51 -0400610 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400611 rc = sde_plane_atomic_set_property(plane, plane->state, property,
612 val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400613 return rc;
614}
615
616static int sde_plane_atomic_get_property(struct drm_plane *plane,
617 const struct drm_plane_state *state,
618 struct drm_property *property, uint64_t *val)
619{
620 struct drm_device *dev = plane->dev;
621 struct sde_plane_state *pstate;
622 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400623 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400624
Clarence Ip4ce59322016-06-26 22:27:51 -0400625 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -0400626
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400627 pstate = to_sde_plane_state(state);
628
Clarence Ipe78efb72016-06-24 18:35:21 -0400629 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
630 if (dev_priv->plane_property[idx] == property) {
631 *val = pstate->property_values[idx];
632 DBG("Get property %d %lld", idx, *val);
633 ret = 0;
634 break;
635 }
636 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400637
Clarence Ipe78efb72016-06-24 18:35:21 -0400638 if (ret == -EINVAL)
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400639 DRM_ERROR("Invalid property get\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400640
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400641 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700642}
643
644static void sde_plane_destroy(struct drm_plane *plane)
645{
Clarence Ip4ce59322016-06-26 22:27:51 -0400646 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700647
Clarence Ip4ce59322016-06-26 22:27:51 -0400648 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700649
Clarence Ip4ce59322016-06-26 22:27:51 -0400650 if (plane) {
651 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400652
Clarence Ip4ce59322016-06-26 22:27:51 -0400653 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -0400654
Clarence Ip4ce59322016-06-26 22:27:51 -0400655 if (psde->pipe_hw)
656 sde_hw_sspp_destroy(psde->pipe_hw);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700657
Clarence Ip4ce59322016-06-26 22:27:51 -0400658 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400659
Clarence Ip4ce59322016-06-26 22:27:51 -0400660 /* this will destroy the states as well */
661 drm_plane_cleanup(plane);
662
663 kfree(psde);
664 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700665}
666
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400667static void sde_plane_destroy_state(struct drm_plane *plane,
668 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700669{
Clarence Ipe78efb72016-06-24 18:35:21 -0400670 struct sde_plane_state *pstate;
671 int i;
672
Clarence Ip4ce59322016-06-26 22:27:51 -0400673 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -0400674
675 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400676 if (state->fb)
677 drm_framebuffer_unreference(state->fb);
678
Clarence Ipe78efb72016-06-24 18:35:21 -0400679 pstate = to_sde_plane_state(state);
680
681 /* remove ref count for blobs */
682 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
683 if (pstate->property_blobs[i])
684 drm_property_unreference_blob(
685 pstate->property_blobs[i]);
686
687 kfree(pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700688}
689
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400690static struct drm_plane_state *
691sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700692{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400693 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400694 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400695
696 if (WARN_ON(!plane->state))
697 return NULL;
698
Clarence Ip4ce59322016-06-26 22:27:51 -0400699 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400700 pstate = kmemdup(to_sde_plane_state(plane->state),
701 sizeof(*pstate), GFP_KERNEL);
Clarence Ipe78efb72016-06-24 18:35:21 -0400702 if (pstate) {
703 /* add ref count for frame buffer */
704 if (pstate->base.fb)
705 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400706
Clarence Ipe78efb72016-06-24 18:35:21 -0400707 /* add ref count for blobs */
708 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
709 if (pstate->property_blobs[i])
710 drm_property_reference_blob(
711 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400712
Clarence Ipe78efb72016-06-24 18:35:21 -0400713 pstate->mode_changed = false;
714 pstate->pending = false;
715 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400716
Clarence Ipe78efb72016-06-24 18:35:21 -0400717 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400718}
719
720static void sde_plane_reset(struct drm_plane *plane)
721{
722 struct sde_plane_state *pstate;
723
Clarence Ip4ce59322016-06-26 22:27:51 -0400724 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400725 if (plane->state && plane->state->fb)
726 drm_framebuffer_unreference(plane->state->fb);
727
728 kfree(to_sde_plane_state(plane->state));
729 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
730
731 memset(pstate, 0, sizeof(struct sde_plane_state));
732
733 /* assign default blend parameters */
Clarence Ipe78efb72016-06-24 18:35:21 -0400734 pstate->property_values[PLANE_PROP_ALPHA] = 255;
735 pstate->property_values[PLANE_PROP_PREMULTIPLIED] = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400736
737 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
Clarence Ipe78efb72016-06-24 18:35:21 -0400738 pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400739 else
Clarence Ipe78efb72016-06-24 18:35:21 -0400740 pstate->property_values[PLANE_PROP_ZPOS] =
741 STAGE0 + drm_plane_index(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400742
743 pstate->base.plane = plane;
744
745 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700746}
747
748static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400749 .update_plane = drm_atomic_helper_update_plane,
750 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700751 .destroy = sde_plane_destroy,
752 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400753 .atomic_set_property = sde_plane_atomic_set_property,
754 .atomic_get_property = sde_plane_atomic_get_property,
755 .reset = sde_plane_reset,
756 .atomic_duplicate_state = sde_plane_duplicate_state,
757 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700758};
759
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400760static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
761 .prepare_fb = sde_plane_prepare_fb,
762 .cleanup_fb = sde_plane_cleanup_fb,
763 .atomic_check = sde_plane_atomic_check,
764 .atomic_update = sde_plane_atomic_update,
765};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700766
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400767enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700768{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400769 struct sde_plane *sde_plane = to_sde_plane(plane);
770
771 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700772}
773
Clarence Ip4ce59322016-06-26 22:27:51 -0400774static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
775{
776 const struct sde_sspp_sub_blks *sblk = 0;
777 const struct sde_sspp_cfg *cfg = 0;
778
779 if (psde && psde->pipe_hw)
780 cfg = psde->pipe_hw->cap;
781 if (cfg)
782 sblk = cfg->sblk;
783
784 if (kms && sblk) {
785 /* create overall sub-directory for the pipe */
786 psde->debugfs_root =
787 debugfs_create_dir(psde->pipe_name,
788 sde_debugfs_get_root(kms));
789 if (psde->debugfs_root) {
790 /* don't error check these */
791 debugfs_create_x32("features", 0444,
792 psde->debugfs_root, &psde->features);
793
794 /* add register dump support */
795 sde_debugfs_setup_regset32(&psde->debugfs_src,
796 sblk->src_blk.base + cfg->base,
797 sblk->src_blk.len,
798 kms->mmio);
799 sde_debugfs_create_regset32("src_blk", 0444,
800 psde->debugfs_root, &psde->debugfs_src);
801
802 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
803 sblk->scaler_blk.base + cfg->base,
804 sblk->scaler_blk.len,
805 kms->mmio);
806 sde_debugfs_create_regset32("scaler_blk", 0444,
807 psde->debugfs_root,
808 &psde->debugfs_scaler);
809
810 sde_debugfs_setup_regset32(&psde->debugfs_csc,
811 sblk->csc_blk.base + cfg->base,
812 sblk->csc_blk.len,
813 kms->mmio);
814 sde_debugfs_create_regset32("csc_blk", 0444,
815 psde->debugfs_root, &psde->debugfs_csc);
816 }
817 }
818}
819
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700820/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -0400821struct drm_plane *sde_plane_init(struct drm_device *dev,
822 uint32_t pipe, bool private_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700823{
824 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400825 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400826 struct msm_drm_private *priv;
827 struct sde_kms *kms;
828 struct sde_mdss_cfg *sde_cat;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700829 int ret;
830 enum drm_plane_type type;
831
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400832 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -0400833 if (!priv) {
834 DRM_ERROR("[%u]Private data is NULL\n", pipe);
835 goto exit;
836 }
837
838 if (!priv->kms) {
839 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
840 goto exit;
841 }
842 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400843
Clarence Ip4ce59322016-06-26 22:27:51 -0400844 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400845 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
846 if (!psde) {
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700847 ret = -ENOMEM;
848 goto fail;
849 }
850
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400851 plane = &psde->base;
852
853 psde->pipe = pipe;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400854
855 if (kms) {
856 /* mmu id for buffer mapping */
857 psde->mmu_id = kms->mmu_id;
858
859 /* check catalog for features mask */
860 sde_cat = kms->catalog;
861 if (sde_cat)
862 psde->features = sde_cat->sspp[pipe].features;
863 }
864 psde->nformats = mdp_get_formats(psde->formats,
865 ARRAY_SIZE(psde->formats),
866 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -0400867 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700868
869 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400870 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
871 psde->formats, psde->nformats,
872 type);
873 if (ret)
874 goto fail;
875
876 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700877
Clarence Ipe78efb72016-06-24 18:35:21 -0400878 _sde_plane_install_properties(plane, &plane->base);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700879
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400880 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
881 if (IS_ERR(psde->pipe_hw)) {
882 ret = PTR_ERR(psde->pipe_hw);
883 psde->pipe_hw = NULL;
884 goto fail;
885 }
886
Clarence Ip4ce59322016-06-26 22:27:51 -0400887 /* save user friendly pipe name for later */
888 snprintf(psde->pipe_name, SDE_PIPE_NAME_SIZE, "pipe%u", pipe);
889
890 _sde_plane_init_debugfs(psde, kms);
891
892 DRM_INFO("Successfully created plane for %s\n", psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700893 return plane;
894
895fail:
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400896 DRM_ERROR("Plane creation failed\n");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700897 if (plane)
898 sde_plane_destroy(plane);
Ben Chan78647cd2016-06-26 22:02:47 -0400899exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700900 return ERR_PTR(ret);
901}