blob: 6dbf34687f0af98e3133b2ef66765fecac33dcfd [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)))) {
437 dev_err(plane->dev->dev,
438 "Pipe doesn't support YUV\n");
439
440 return -EINVAL;
441 }
442
Clarence Ipe78efb72016-06-24 18:35:21 -0400443 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400444 (((state->src_w >> 16) != state->crtc_w) ||
445 ((state->src_h >> 16) != state->crtc_h))) {
446 dev_err(plane->dev->dev,
447 "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
448 state->src_w >> 16, state->src_h >> 16,
449 state->crtc_w, state->crtc_h);
450
451 return -EINVAL;
452 }
453 }
454
455 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
456 /* we cannot change SMP block configuration during scanout: */
457 bool full_modeset = false;
458
459 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400460 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400461 full_modeset = true;
462 }
463 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400464 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400465 full_modeset = true;
466 }
467 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400468 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400469 full_modeset = true;
470 }
471 if (full_modeset) {
472 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400473 drm_atomic_get_crtc_state(state->state,
474 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400475 crtc_state->mode_changed = true;
476 to_sde_plane_state(state)->mode_changed = true;
477 }
478 } else {
479 to_sde_plane_state(state)->mode_changed = true;
480 }
481
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700482 return 0;
483}
484
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400485static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400486 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700487{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400488 struct sde_plane *sde_plane = to_sde_plane(plane);
489 struct drm_plane_state *state = plane->state;
490
Clarence Ip4ce59322016-06-26 22:27:51 -0400491 DBG("%s: update", sde_plane->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400492
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400493 if (!sde_plane_enabled(state)) {
494 to_sde_plane_state(state)->pending = true;
495 } else if (to_sde_plane_state(state)->mode_changed) {
496 int ret;
497
498 to_sde_plane_state(state)->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400499 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400500 state->crtc, state->fb,
501 state->crtc_x, state->crtc_y,
502 state->crtc_w, state->crtc_h,
503 state->src_x, state->src_y,
504 state->src_w, state->src_h);
505 /* atomic_check should have ensured that this doesn't fail */
506 WARN_ON(ret < 0);
507 } else {
Clarence Ipe78efb72016-06-24 18:35:21 -0400508 _sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400509 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400510}
511
Clarence Ipe78efb72016-06-24 18:35:21 -0400512static void _sde_plane_install_range_property(struct drm_plane *plane,
513 struct drm_device *dev, const char *name,
514 uint64_t min, uint64_t max, uint64_t init,
515 struct drm_property **prop)
516{
517 if (plane && dev && name && prop) {
518 /* only create the property once */
519 if (*prop == 0) {
520 *prop = drm_property_create_range(dev,
521 0 /* flags */, name, min, max);
522 if (*prop == 0)
Clarence Ip4ce59322016-06-26 22:27:51 -0400523 DRM_ERROR("Create property %s failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400524 }
525
526 /* always attach property, if created */
527 if (*prop)
528 drm_object_attach_property(&plane->base, *prop, init);
529 }
530}
531
532static void _sde_plane_install_blob_property(struct drm_plane *plane,
533 struct drm_device *dev, const char *name,
534 struct drm_property **prop)
535{
536}
537
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400538/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400539static void _sde_plane_install_properties(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400540 struct drm_mode_object *obj)
541{
542 struct drm_device *dev = plane->dev;
543 struct msm_drm_private *dev_priv = dev->dev_private;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400544
Clarence Ip4ce59322016-06-26 22:27:51 -0400545 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400546
Clarence Ipe78efb72016-06-24 18:35:21 -0400547 /* range/enum properties */
548 _sde_plane_install_range_property(plane, dev, "zpos", 1, 255, 1,
549 &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400550
Clarence Ipe78efb72016-06-24 18:35:21 -0400551 /* blob properties */
552 _sde_plane_install_blob_property(plane, dev, "pixext",
553 &(dev_priv->plane_property[PLANE_PROP_PIXEXT]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400554}
555
556static int sde_plane_atomic_set_property(struct drm_plane *plane,
557 struct drm_plane_state *state, struct drm_property *property,
558 uint64_t val)
559{
560 struct drm_device *dev = plane->dev;
561 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400562 struct drm_property_blob *blob, **prop_blob;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400563 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400564 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400565
Clarence Ip4ce59322016-06-26 22:27:51 -0400566 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400567
568 pstate = to_sde_plane_state(state);
569
Clarence Ipe78efb72016-06-24 18:35:21 -0400570 for (idx = 0; idx < PLANE_PROP_COUNT && ret; ++idx) {
571 if (dev_priv->plane_property[idx] == property) {
572 DBG("Set property %d <= %d", idx, (int)val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573
Clarence Ipe78efb72016-06-24 18:35:21 -0400574 /* FUTURE: Add special handling here */
575 if (property->flags & DRM_MODE_PROP_BLOB) {
576 blob = drm_property_lookup_blob(dev,
577 (uint32_t)val);
578 if (!blob) {
579 dev_err(dev->dev, "Blob not found\n");
580 val = 0;
581 } else {
582 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400583
Clarence Ipe78efb72016-06-24 18:35:21 -0400584 /* save blobs for later */
585 prop_blob =
586 &pstate->property_blobs[idx -
587 PLANE_PROP_FIRSTBLOB];
588 /* need to clear previous reference */
589 if (*prop_blob)
590 drm_property_unreference_blob(
591 *prop_blob);
592 *prop_blob = blob;
593 }
594 }
595 pstate->property_values[idx] = val;
596 ret = 0;
597 }
598 }
599
600 if (ret == -EINVAL)
601 dev_err(dev->dev, "Invalid property set\n");
602
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400603 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400604}
605
606static int sde_plane_set_property(struct drm_plane *plane,
607 struct drm_property *property, uint64_t val)
608{
609 int rc;
610
Clarence Ip4ce59322016-06-26 22:27:51 -0400611 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400612 rc = sde_plane_atomic_set_property(plane, plane->state, property,
613 val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400614 return rc;
615}
616
617static int sde_plane_atomic_get_property(struct drm_plane *plane,
618 const struct drm_plane_state *state,
619 struct drm_property *property, uint64_t *val)
620{
621 struct drm_device *dev = plane->dev;
622 struct sde_plane_state *pstate;
623 struct msm_drm_private *dev_priv = dev->dev_private;
Clarence Ipe78efb72016-06-24 18:35:21 -0400624 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400625
Clarence Ip4ce59322016-06-26 22:27:51 -0400626 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -0400627
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400628 pstate = to_sde_plane_state(state);
629
Clarence Ipe78efb72016-06-24 18:35:21 -0400630 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
631 if (dev_priv->plane_property[idx] == property) {
632 *val = pstate->property_values[idx];
633 DBG("Get property %d %lld", idx, *val);
634 ret = 0;
635 break;
636 }
637 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400638
Clarence Ipe78efb72016-06-24 18:35:21 -0400639 if (ret == -EINVAL)
640 dev_err(dev->dev, "Invalid property get\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400641
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400642 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700643}
644
645static void sde_plane_destroy(struct drm_plane *plane)
646{
Clarence Ip4ce59322016-06-26 22:27:51 -0400647 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700648
Clarence Ip4ce59322016-06-26 22:27:51 -0400649 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700650
Clarence Ip4ce59322016-06-26 22:27:51 -0400651 if (plane) {
652 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400653
Clarence Ip4ce59322016-06-26 22:27:51 -0400654 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -0400655
Clarence Ip4ce59322016-06-26 22:27:51 -0400656 if (psde->pipe_hw)
657 sde_hw_sspp_destroy(psde->pipe_hw);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700658
Clarence Ip4ce59322016-06-26 22:27:51 -0400659 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400660
Clarence Ip4ce59322016-06-26 22:27:51 -0400661 /* this will destroy the states as well */
662 drm_plane_cleanup(plane);
663
664 kfree(psde);
665 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700666}
667
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400668static void sde_plane_destroy_state(struct drm_plane *plane,
669 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700670{
Clarence Ipe78efb72016-06-24 18:35:21 -0400671 struct sde_plane_state *pstate;
672 int i;
673
Clarence Ip4ce59322016-06-26 22:27:51 -0400674 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -0400675
676 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400677 if (state->fb)
678 drm_framebuffer_unreference(state->fb);
679
Clarence Ipe78efb72016-06-24 18:35:21 -0400680 pstate = to_sde_plane_state(state);
681
682 /* remove ref count for blobs */
683 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
684 if (pstate->property_blobs[i])
685 drm_property_unreference_blob(
686 pstate->property_blobs[i]);
687
688 kfree(pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700689}
690
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400691static struct drm_plane_state *
692sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700693{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400694 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400695 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400696
697 if (WARN_ON(!plane->state))
698 return NULL;
699
Clarence Ip4ce59322016-06-26 22:27:51 -0400700 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400701 pstate = kmemdup(to_sde_plane_state(plane->state),
702 sizeof(*pstate), GFP_KERNEL);
Clarence Ipe78efb72016-06-24 18:35:21 -0400703 if (pstate) {
704 /* add ref count for frame buffer */
705 if (pstate->base.fb)
706 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400707
Clarence Ipe78efb72016-06-24 18:35:21 -0400708 /* add ref count for blobs */
709 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
710 if (pstate->property_blobs[i])
711 drm_property_reference_blob(
712 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400713
Clarence Ipe78efb72016-06-24 18:35:21 -0400714 pstate->mode_changed = false;
715 pstate->pending = false;
716 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400717
Clarence Ipe78efb72016-06-24 18:35:21 -0400718 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400719}
720
721static void sde_plane_reset(struct drm_plane *plane)
722{
723 struct sde_plane_state *pstate;
724
Clarence Ip4ce59322016-06-26 22:27:51 -0400725 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400726 if (plane->state && plane->state->fb)
727 drm_framebuffer_unreference(plane->state->fb);
728
729 kfree(to_sde_plane_state(plane->state));
730 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
731
732 memset(pstate, 0, sizeof(struct sde_plane_state));
733
734 /* assign default blend parameters */
Clarence Ipe78efb72016-06-24 18:35:21 -0400735 pstate->property_values[PLANE_PROP_ALPHA] = 255;
736 pstate->property_values[PLANE_PROP_PREMULTIPLIED] = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400737
738 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
Clarence Ipe78efb72016-06-24 18:35:21 -0400739 pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400740 else
Clarence Ipe78efb72016-06-24 18:35:21 -0400741 pstate->property_values[PLANE_PROP_ZPOS] =
742 STAGE0 + drm_plane_index(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400743
744 pstate->base.plane = plane;
745
746 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700747}
748
749static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400750 .update_plane = drm_atomic_helper_update_plane,
751 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700752 .destroy = sde_plane_destroy,
753 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400754 .atomic_set_property = sde_plane_atomic_set_property,
755 .atomic_get_property = sde_plane_atomic_get_property,
756 .reset = sde_plane_reset,
757 .atomic_duplicate_state = sde_plane_duplicate_state,
758 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700759};
760
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400761static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
762 .prepare_fb = sde_plane_prepare_fb,
763 .cleanup_fb = sde_plane_cleanup_fb,
764 .atomic_check = sde_plane_atomic_check,
765 .atomic_update = sde_plane_atomic_update,
766};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700767
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400768enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700769{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400770 struct sde_plane *sde_plane = to_sde_plane(plane);
771
772 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700773}
774
Clarence Ip4ce59322016-06-26 22:27:51 -0400775static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
776{
777 const struct sde_sspp_sub_blks *sblk = 0;
778 const struct sde_sspp_cfg *cfg = 0;
779
780 if (psde && psde->pipe_hw)
781 cfg = psde->pipe_hw->cap;
782 if (cfg)
783 sblk = cfg->sblk;
784
785 if (kms && sblk) {
786 /* create overall sub-directory for the pipe */
787 psde->debugfs_root =
788 debugfs_create_dir(psde->pipe_name,
789 sde_debugfs_get_root(kms));
790 if (psde->debugfs_root) {
791 /* don't error check these */
792 debugfs_create_x32("features", 0444,
793 psde->debugfs_root, &psde->features);
794
795 /* add register dump support */
796 sde_debugfs_setup_regset32(&psde->debugfs_src,
797 sblk->src_blk.base + cfg->base,
798 sblk->src_blk.len,
799 kms->mmio);
800 sde_debugfs_create_regset32("src_blk", 0444,
801 psde->debugfs_root, &psde->debugfs_src);
802
803 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
804 sblk->scaler_blk.base + cfg->base,
805 sblk->scaler_blk.len,
806 kms->mmio);
807 sde_debugfs_create_regset32("scaler_blk", 0444,
808 psde->debugfs_root,
809 &psde->debugfs_scaler);
810
811 sde_debugfs_setup_regset32(&psde->debugfs_csc,
812 sblk->csc_blk.base + cfg->base,
813 sblk->csc_blk.len,
814 kms->mmio);
815 sde_debugfs_create_regset32("csc_blk", 0444,
816 psde->debugfs_root, &psde->debugfs_csc);
817 }
818 }
819}
820
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700821/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -0400822struct drm_plane *sde_plane_init(struct drm_device *dev,
823 uint32_t pipe, bool private_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700824{
825 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400826 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400827 struct msm_drm_private *priv;
828 struct sde_kms *kms;
829 struct sde_mdss_cfg *sde_cat;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700830 int ret;
831 enum drm_plane_type type;
832
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400833 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -0400834 if (!priv) {
835 DRM_ERROR("[%u]Private data is NULL\n", pipe);
836 goto exit;
837 }
838
839 if (!priv->kms) {
840 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
841 goto exit;
842 }
843 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400844
Clarence Ip4ce59322016-06-26 22:27:51 -0400845 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400846 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
847 if (!psde) {
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700848 ret = -ENOMEM;
849 goto fail;
850 }
851
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400852 plane = &psde->base;
853
854 psde->pipe = pipe;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400855
856 if (kms) {
857 /* mmu id for buffer mapping */
858 psde->mmu_id = kms->mmu_id;
859
860 /* check catalog for features mask */
861 sde_cat = kms->catalog;
862 if (sde_cat)
863 psde->features = sde_cat->sspp[pipe].features;
864 }
865 psde->nformats = mdp_get_formats(psde->formats,
866 ARRAY_SIZE(psde->formats),
867 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -0400868 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700869
870 type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400871 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
872 psde->formats, psde->nformats,
873 type);
874 if (ret)
875 goto fail;
876
877 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700878
Clarence Ipe78efb72016-06-24 18:35:21 -0400879 _sde_plane_install_properties(plane, &plane->base);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700880
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400881 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
882 if (IS_ERR(psde->pipe_hw)) {
883 ret = PTR_ERR(psde->pipe_hw);
884 psde->pipe_hw = NULL;
885 goto fail;
886 }
887
Clarence Ip4ce59322016-06-26 22:27:51 -0400888 /* save user friendly pipe name for later */
889 snprintf(psde->pipe_name, SDE_PIPE_NAME_SIZE, "pipe%u", pipe);
890
891 _sde_plane_init_debugfs(psde, kms);
892
893 DRM_INFO("Successfully created plane for %s\n", psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700894 return plane;
895
896fail:
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400897 pr_err("%s: Plane creation failed\n", __func__);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700898 if (plane)
899 sde_plane_destroy(plane);
Ben Chan78647cd2016-06-26 22:02:47 -0400900exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700901 return ERR_PTR(ret);
902}