blob: 8817a3b8ad8e2a95ec682513128a42ee2ef6a1ca [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>
Clarence Ip5e2a9222016-06-26 22:38:24 -040013#include <uapi/drm/sde_drm.h>
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070014#include "sde_kms.h"
Clarence Ipc475b082016-06-26 09:27:23 -040015#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040016#include "sde_hw_sspp.h"
17
18#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
19#define PHASE_STEP_SHIFT 21
20#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
21#define PHASE_RESIDUAL 15
22
Clarence Ipe78efb72016-06-24 18:35:21 -040023#define SHARP_STRENGTH_DEFAULT 32
24#define SHARP_EDGE_THR_DEFAULT 112
25#define SHARP_SMOOTH_THR_DEFAULT 8
26#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040027
Clarence Ip5e2a9222016-06-26 22:38:24 -040028#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070029
30struct sde_plane {
31 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040032
33 int mmu_id;
34
35 enum sde_sspp pipe;
36 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070037 uint32_t nformats;
38 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040039
40 struct sde_hw_pipe *pipe_hw;
41 struct sde_hw_pipe_cfg pipe_cfg;
42 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040043 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040044 struct sde_hw_scaler3_cfg scaler3_cfg;
Clarence Ip4ce59322016-06-26 22:27:51 -040045
Clarence Ip4c1d9772016-06-26 09:35:38 -040046 const struct sde_sspp_sub_blks *pipe_sblk;
47
Clarence Ip5e2a9222016-06-26 22:38:24 -040048 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040049
50 /* debugfs related stuff */
51 struct dentry *debugfs_root;
52 struct sde_debugfs_regset32 debugfs_src;
53 struct sde_debugfs_regset32 debugfs_scaler;
54 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070055};
56#define to_sde_plane(x) container_of(x, struct sde_plane, base)
57
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040058static bool sde_plane_enabled(struct drm_plane_state *state)
59{
60 return state->fb && state->crtc;
61}
62
Clarence Ipe78efb72016-06-24 18:35:21 -040063static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -040064 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040065 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
66{
67 struct sde_plane *psde = to_sde_plane(plane);
Clarence Ip5e2a9222016-06-26 22:38:24 -040068 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040069 int i;
70
71 if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
72 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -040073 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -040074 BIT(SDE_DRM_DEINTERLACE))
75 shift = 1;
76 else
77 shift = 0;
78
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040079 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
80 while (i) {
81 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -040082 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040083 }
84
85 /* address */
86 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
87 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
88 psde->mmu_id, i);
89
90 /* hw driver */
91 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
92 }
93}
94
Clarence Ip5e2a9222016-06-26 22:38:24 -040095static void _sde_plane_setup_scaler3(struct drm_plane *plane,
96 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
97 struct sde_hw_scaler3_cfg *scale_cfg,
98 struct sde_mdp_format_params *fmt,
99 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
100{
101}
102
103static void _sde_plane_setup_scaler2(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400104 uint32_t src, uint32_t dst, uint32_t *phase_steps,
105 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
106 uint32_t chroma_subsampling)
107{
Clarence Ip4c1d9772016-06-26 09:35:38 -0400108 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400109 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400110 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400111 phase_steps[SDE_SSPP_COMP_1_2] =
112 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
113 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
114 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400115
116 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -0400117 if (fmt->is_yuv || src != dst) {
118 filter[SDE_SSPP_COMP_3] =
119 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
120 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400121
Clarence Ipe78efb72016-06-24 18:35:21 -0400122 if (fmt->is_yuv) {
123 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
124 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
125 } else {
126 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
127 filter[SDE_SSPP_COMP_1_2] =
128 SDE_MDP_SCALE_FILTER_NEAREST;
129 }
130 } else {
131 /* disable scaler */
132 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
133 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
134 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400135 }
136}
137
Clarence Ipe78efb72016-06-24 18:35:21 -0400138static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400139 uint32_t src, uint32_t dst, uint32_t decimated_src,
140 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400141 int *out_edge2, enum sde_hw_filter *filter,
142 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
143 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400144{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400145 int64_t edge1, edge2, caf;
146 uint32_t src_work;
147 int i, tmp;
148
Clarence Ipe78efb72016-06-24 18:35:21 -0400149 if (plane && phase_steps && out_src && out_edge1 &&
150 out_edge2 && filter && fmt) {
151 /* handle CAF for YUV formats */
152 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400153 caf = PHASE_STEP_UNIT_SCALE;
154 else
155 caf = 0;
156
157 for (i = 0; i < SDE_MAX_PLANES; i++) {
158 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400159 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400160 src_work /= chroma_subsampling;
161 if (post_compare)
162 src = src_work;
163 if (!(fmt->is_yuv) && (src == dst)) {
164 /* unity */
165 edge1 = 0;
166 edge2 = 0;
167 } else if (dst >= src) {
168 /* upscale */
169 edge1 = (1 << PHASE_RESIDUAL);
170 edge1 -= caf;
171 edge2 = (1 << PHASE_RESIDUAL);
172 edge2 += (dst - 1) * *(phase_steps + i);
173 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
174 edge2 += caf;
175 edge2 = -(edge2);
176 } else {
177 /* downscale */
178 edge1 = 0;
179 edge2 = (dst - 1) * *(phase_steps + i);
180 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
181 edge2 += *(phase_steps + i);
182 edge2 = -(edge2);
183 }
184
185 /* only enable CAF for luma plane */
186 caf = 0;
187
188 /* populate output arrays */
189 *(out_src + i) = src_work;
190
191 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400192 if (edge1 >= 0) {
193 tmp = (uint32_t)edge1;
194 tmp >>= PHASE_STEP_SHIFT;
195 *(out_edge1 + i) = -tmp;
196 } else {
197 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400198 *(out_edge1 + i) =
199 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
200 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400201 }
202 if (edge2 >= 0) {
203 tmp = (uint32_t)edge2;
204 tmp >>= PHASE_STEP_SHIFT;
205 *(out_edge2 + i) = -tmp;
206 } else {
207 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400208 *(out_edge2 + i) =
209 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
210 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400211 }
212 }
213 }
214}
215
Clarence Ip5e2a9222016-06-26 22:38:24 -0400216static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
217 enum msm_mdp_plane_property property, size_t *byte_len)
218{
219 struct drm_property_blob *blob;
220 size_t len = 0;
221 void *ret = 0;
222
Clarence Ip4c1d9772016-06-26 09:35:38 -0400223 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
224 DRM_ERROR("Invalid argument(s)\n");
225 } else {
226 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400227 if (blob) {
228 len = blob->length;
229 ret = &blob->data;
230 }
231 }
232
233 if (byte_len)
234 *byte_len = len;
235
236 return ret;
237}
238
239/**
240 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
241 * sub-structure
242 * @blob_ptr: Pointer to start of incoming blob data
243 * @blob_size: Size of incoming blob data, in bytes
244 * @sub_ptr: Pointer to start of desired sub-structure
245 * @sub_size: Required size of sub-structure, in bytes
246 */
247static int _sde_plane_verify_blob(void *blob_ptr,
248 size_t blob_size,
249 void *sub_ptr,
250 size_t sub_size)
251{
252 /*
253 * Use the blob size provided by drm to check if there are enough
254 * bytes from the start of versioned sub-structures to the end of
255 * blob data:
256 *
257 * e.g.,
258 * blob_ptr --> struct blob_data {
259 * uint32_t version;
260 * sub_ptr --> struct blob_data_v1 v1;
261 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
262 * blob_ptr + blob_size --> };
263 *
264 * It's important to check the actual number of bytes from the start
265 * of the sub-structure to the end of the blob data, and not just rely
266 * on something like,
267 *
268 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
269 *
270 * This is because the start of the sub-structure can vary based on
271 * how the compiler pads the overall structure.
272 */
273 if (blob_ptr && sub_ptr)
274 /* return zero if end of blob >= end of sub-struct */
275 return ((unsigned char *)blob_ptr + blob_size) <
276 ((unsigned char *)sub_ptr + sub_size);
277 return -EINVAL;
278}
279
Clarence Ipe78efb72016-06-24 18:35:21 -0400280static void _sde_plane_setup_csc(struct sde_plane *psde,
281 struct sde_plane_state *pstate,
282 struct sde_mdp_format_params *fmt)
283{
284 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
285 {
286 0x0254, 0x0000, 0x0331,
287 0x0254, 0xff37, 0xfe60,
288 0x0254, 0x0409, 0x0000,
289 },
290 { 0xfff0, 0xff80, 0xff80,},
291 { 0x0, 0x0, 0x0,},
292 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
293 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
294 };
295
296 static const struct sde_csc_cfg sde_csc_NOP = {
297 {
298 0x0200, 0x0000, 0x0000,
299 0x0000, 0x0200, 0x0000,
300 0x0000, 0x0000, 0x0200,
301 },
302 { 0x0, 0x0, 0x0,},
303 { 0x0, 0x0, 0x0,},
304 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
305 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
306 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400307 struct sde_drm_csc *csc = NULL;
308 size_t csc_size = 0;
309 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400310
311 if (!psde->pipe_hw->ops.setup_csc)
312 return;
313
Clarence Ip5e2a9222016-06-26 22:38:24 -0400314 /* check for user space override */
315 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
316 if (csc) {
317 struct sde_csc_cfg cfg;
318 int i;
319
320 /* user space override */
321 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
322 switch (csc->version) {
323 case SDE_DRM_CSC_V1:
324 if (!_sde_plane_verify_blob(csc,
325 csc_size,
326 &csc->v1,
327 sizeof(struct sde_drm_csc_v1))) {
328 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
329 cfg.csc_mv[i] =
330 csc->v1.ctm_coeff[i] >> 23;
331 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
332 cfg.csc_pre_bv[i] =
333 csc->v1.pre_bias[i];
334 cfg.csc_post_bv[i] =
335 csc->v1.post_bias[i];
336 }
337 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
338 cfg.csc_pre_lv[i] =
339 csc->v1.pre_clamp[i];
340 cfg.csc_post_lv[i] =
341 csc->v1.post_clamp[i];
342 }
343 user_blob = true;
344 }
345 break;
346 default:
347 break;
348 }
349
350 if (!user_blob)
351 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
352 else
353 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
354 (struct sde_csc_cfg *)&cfg);
355 }
356
357 if (user_blob) {
358 DBG("User blobs override for CSC");
359 /* revert to kernel default */
360 } else if (fmt->is_yuv) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400361 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
362 (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400363 } else {
Clarence Ipe78efb72016-06-24 18:35:21 -0400364 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
365 (struct sde_csc_cfg *)&sde_csc_NOP);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400366 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400367}
368
369static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700370 struct drm_crtc *crtc, struct drm_framebuffer *fb,
371 int crtc_x, int crtc_y,
372 unsigned int crtc_w, unsigned int crtc_h,
373 uint32_t src_x, uint32_t src_y,
374 uint32_t src_w, uint32_t src_h)
375{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400376 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400377 struct sde_plane_state *pstate;
378 const struct mdp_format *format;
379 uint32_t nplanes, pix_format, tmp;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400380 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
381 uint32_t src_fmt_flags;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400382 int i;
383 struct sde_mdp_format_params *fmt;
384 struct sde_hw_pixel_ext *pe;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400385 size_t sc_u_size = 0;
386 struct sde_drm_scaler *sc_u = NULL;
387 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400388
Clarence Ip4ce59322016-06-26 22:27:51 -0400389 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400390
Clarence Ip5e2a9222016-06-26 22:38:24 -0400391 if (!plane || !plane->state) {
392 DRM_ERROR("Invalid plane/state\n");
393 return -EINVAL;
394 }
395 if (!crtc || !fb) {
396 DRM_ERROR("Invalid crtc/fb\n");
397 return -EINVAL;
398 }
399 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400400 pstate = to_sde_plane_state(plane->state);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400401 nplanes = drm_format_num_planes(fb->pixel_format);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400402
403 format = to_mdp_format(msm_framebuffer_format(fb));
404 pix_format = format->base.pixel_format;
405
406 /* src values are in Q16 fixed point, convert to integer */
407 src_x = src_x >> 16;
408 src_y = src_y >> 16;
409 src_w = src_w >> 16;
410 src_h = src_h >> 16;
411
Clarence Ip4ce59322016-06-26 22:27:51 -0400412 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400413 fb->base.id, src_x, src_y, src_w, src_h,
414 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
415
416 /* update format configuration */
417 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400418 src_fmt_flags = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400419
420 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400421 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400422 psde->pipe_cfg.src.width = fb->width;
423 psde->pipe_cfg.src.height = fb->height;
424 psde->pipe_cfg.src.num_planes = nplanes;
425
Clarence Ip5e2a9222016-06-26 22:38:24 -0400426 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
427
428 /* decimation */
429 psde->pipe_cfg.horz_decimation =
Clarence Ip4c1d9772016-06-26 09:35:38 -0400430 sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400431 psde->pipe_cfg.vert_decimation =
Clarence Ip4c1d9772016-06-26 09:35:38 -0400432 sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400433
434 /* flags */
435 DBG("Flags 0x%llX, rotation 0x%llX",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400436 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
437 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
438 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400439 BIT(DRM_REFLECT_X))
440 src_fmt_flags |= SDE_SSPP_FLIP_LR;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400441 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400442 BIT(DRM_REFLECT_Y))
443 src_fmt_flags |= SDE_SSPP_FLIP_UD;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400444 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400445 BIT(SDE_DRM_DEINTERLACE)) {
446 src_h /= 2;
447 src_y = DIV_ROUND_UP(src_y, 2);
448 src_y &= ~0x1;
449 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400450
451 psde->pipe_cfg.src_rect.x = src_x;
452 psde->pipe_cfg.src_rect.y = src_y;
453 psde->pipe_cfg.src_rect.w = src_w;
454 psde->pipe_cfg.src_rect.h = src_h;
455
456 psde->pipe_cfg.dst_rect.x = crtc_x;
457 psde->pipe_cfg.dst_rect.y = crtc_y;
458 psde->pipe_cfg.dst_rect.w = crtc_w;
459 psde->pipe_cfg.dst_rect.h = crtc_h;
460
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400461 /* get sde pixel format definition */
462 fmt = psde->pipe_cfg.src.format;
463
Clarence Ip5e2a9222016-06-26 22:38:24 -0400464 /* don't chroma subsample if decimating */
465 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
466 drm_format_horz_chroma_subsampling(pix_format);
467 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
468 drm_format_vert_chroma_subsampling(pix_format);
469
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400470 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400471 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400472
Clarence Ip5e2a9222016-06-26 22:38:24 -0400473 /* get scaler config from user space */
474 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
475 if (sc_u) {
476 switch (sc_u->version) {
477 case SDE_DRM_SCALER_V1:
478 if (!_sde_plane_verify_blob(sc_u,
479 sc_u_size,
480 &sc_u->v1,
481 sizeof(*sc_u1)))
482 sc_u1 = &sc_u->v1;
483 break;
484 default:
485 DBG("Unrecognized scaler blob v%lld", sc_u->version);
486 break;
487 }
488 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400489
Clarence Ip5e2a9222016-06-26 22:38:24 -0400490 /* update scaler */
491 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
492 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
493 DBG("QSEED3 blob detected");
494 else
495 _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
496 crtc_h, &psde->scaler3_cfg, fmt,
497 chroma_subsmpl_h, chroma_subsmpl_v);
498 } else {
499 /* always calculate basic scaler config */
500 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
501 /* populate from user space */
502 for (i = 0; i < SDE_MAX_PLANES; i++) {
503 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
504 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
505 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
506 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400507
Clarence Ip5e2a9222016-06-26 22:38:24 -0400508 pe->horz_filter[i] = sc_u1->horz_filter[i];
509 pe->vert_filter[i] = sc_u1->vert_filter[i];
510 }
511 } else {
512 /* calculate phase steps */
513 _sde_plane_setup_scaler2(plane, src_w, crtc_w,
514 pe->phase_step_x,
515 pe->horz_filter, fmt, chroma_subsmpl_h);
516 _sde_plane_setup_scaler2(plane, src_h, crtc_h,
517 pe->phase_step_y,
518 pe->vert_filter, fmt, chroma_subsmpl_v);
519 }
520 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400521
Clarence Ip5e2a9222016-06-26 22:38:24 -0400522 /* update pixel extensions */
523 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
524 /* populate from user space */
525 for (i = 0; i < SDE_MAX_PLANES; i++) {
526 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
527 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
528 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
529 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
530 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
531 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
532 pe->roi_w[i] = sc_u1->lr.roi[i];
533
534 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
535 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
536 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
537 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
538 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
539 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
540 pe->roi_h[i] = sc_u1->tb.roi[i];
541 }
542 } else {
543 /* calculate left/right/top/bottom pixel extensions */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400544 tmp = DECIMATED_DIMENSION(src_w,
545 psde->pipe_cfg.horz_decimation);
546 if (fmt->is_yuv)
547 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400548 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400549 pe->phase_step_x,
550 pe->roi_w,
551 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400552 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400553 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400554
555 tmp = DECIMATED_DIMENSION(src_h,
556 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400557 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400558 pe->phase_step_y,
559 pe->roi_h,
560 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400561 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400562 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400563
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400564 for (i = 0; i < SDE_MAX_PLANES; i++) {
565 if (pe->num_ext_pxls_left[i] >= 0)
566 pe->left_rpt[i] =
567 pe->num_ext_pxls_left[i];
568 else
569 pe->left_ftch[i] =
570 pe->num_ext_pxls_left[i];
571
572 if (pe->num_ext_pxls_right[i] >= 0)
573 pe->right_rpt[i] =
574 pe->num_ext_pxls_right[i];
575 else
576 pe->right_ftch[i] =
577 pe->num_ext_pxls_right[i];
578
579 if (pe->num_ext_pxls_top[i] >= 0)
580 pe->top_rpt[i] =
581 pe->num_ext_pxls_top[i];
582 else
583 pe->top_ftch[i] =
584 pe->num_ext_pxls_top[i];
585
586 if (pe->num_ext_pxls_btm[i] >= 0)
587 pe->btm_rpt[i] =
588 pe->num_ext_pxls_btm[i];
589 else
590 pe->btm_ftch[i] =
591 pe->num_ext_pxls_btm[i];
592 }
593 }
594
Clarence Ip4c1d9772016-06-26 09:35:38 -0400595 if (psde->pipe_hw->ops.setup_format)
596 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400597 &psde->pipe_cfg, src_fmt_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400598 if (psde->pipe_hw->ops.setup_rects)
599 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
600 &psde->pipe_cfg, &psde->pixel_ext);
601
Clarence Ipe78efb72016-06-24 18:35:21 -0400602 /* update sharpening */
603 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
604 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
605 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
606 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
607
608 if (psde->pipe_hw->ops.setup_sharpening)
609 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
610 &psde->sharp_cfg);
611
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400612 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400613 if (fmt->is_yuv)
614 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400615
Clarence Ip5e2a9222016-06-26 22:38:24 -0400616 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400617}
618
619static int sde_plane_prepare_fb(struct drm_plane *plane,
620 const struct drm_plane_state *new_state)
621{
622 struct drm_framebuffer *fb = new_state->fb;
623 struct sde_plane *psde = to_sde_plane(plane);
624
625 if (!new_state->fb)
626 return 0;
627
Clarence Ip4ce59322016-06-26 22:27:51 -0400628 DBG("%s: prepare: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400629 return msm_framebuffer_prepare(fb, psde->mmu_id);
630}
631
632static void sde_plane_cleanup_fb(struct drm_plane *plane,
633 const struct drm_plane_state *old_state)
634{
635 struct drm_framebuffer *fb = old_state->fb;
636 struct sde_plane *psde = to_sde_plane(plane);
637
638 if (!fb)
639 return;
640
Clarence Ip4ce59322016-06-26 22:27:51 -0400641 DBG("%s: cleanup: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400642 msm_framebuffer_cleanup(fb, psde->mmu_id);
643}
644
645static int sde_plane_atomic_check(struct drm_plane *plane,
646 struct drm_plane_state *state)
647{
648 struct sde_plane *psde = to_sde_plane(plane);
649 struct drm_plane_state *old_state = plane->state;
650 const struct mdp_format *format;
651
Clarence Ip4ce59322016-06-26 22:27:51 -0400652 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400653 sde_plane_enabled(old_state), sde_plane_enabled(state));
654
655 if (sde_plane_enabled(state)) {
656 /* CIFIX: don't use mdp format? */
657 format = to_mdp_format(msm_framebuffer_format(state->fb));
658 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400659 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400660 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400661 DRM_ERROR("Pipe doesn't support YUV\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400662
663 return -EINVAL;
664 }
665
Clarence Ipe78efb72016-06-24 18:35:21 -0400666 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400667 (((state->src_w >> 16) != state->crtc_w) ||
668 ((state->src_h >> 16) != state->crtc_h))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400669 DRM_ERROR(
670 "Unsupported Pipe scaling (%dx%d -> %dx%d)\n",
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400671 state->src_w >> 16, state->src_h >> 16,
672 state->crtc_w, state->crtc_h);
673
674 return -EINVAL;
675 }
676 }
677
678 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
679 /* we cannot change SMP block configuration during scanout: */
680 bool full_modeset = false;
681
682 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400683 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400684 full_modeset = true;
685 }
686 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400687 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400688 full_modeset = true;
689 }
690 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400691 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400692 full_modeset = true;
693 }
694 if (full_modeset) {
695 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400696 drm_atomic_get_crtc_state(state->state,
697 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400698 crtc_state->mode_changed = true;
699 to_sde_plane_state(state)->mode_changed = true;
700 }
701 } else {
702 to_sde_plane_state(state)->mode_changed = true;
703 }
704
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700705 return 0;
706}
707
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400708static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400709 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700710{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400711 struct sde_plane *sde_plane;
712 struct drm_plane_state *state;
713 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400714
Clarence Ip4ce59322016-06-26 22:27:51 -0400715 DBG("%s: update", sde_plane->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400716
Clarence Ip5e2a9222016-06-26 22:38:24 -0400717 if (!plane || !plane->state) {
718 DRM_ERROR("Invalid plane/state\n");
719 return;
720 }
721
722 sde_plane = to_sde_plane(plane);
723 state = plane->state;
724 pstate = to_sde_plane_state(state);
725
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400726 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400727 pstate->pending = true;
728 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400729 int ret;
730
Clarence Ip5e2a9222016-06-26 22:38:24 -0400731 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400732 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400733 state->crtc, state->fb,
734 state->crtc_x, state->crtc_y,
735 state->crtc_w, state->crtc_h,
736 state->src_x, state->src_y,
737 state->src_w, state->src_h);
738 /* atomic_check should have ensured that this doesn't fail */
739 WARN_ON(ret < 0);
740 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400741 _sde_plane_set_scanout(plane, pstate,
742 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400743 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400744}
745
Clarence Ipe78efb72016-06-24 18:35:21 -0400746static void _sde_plane_install_range_property(struct drm_plane *plane,
747 struct drm_device *dev, const char *name,
748 uint64_t min, uint64_t max, uint64_t init,
749 struct drm_property **prop)
750{
751 if (plane && dev && name && prop) {
752 /* only create the property once */
753 if (*prop == 0) {
754 *prop = drm_property_create_range(dev,
755 0 /* flags */, name, min, max);
756 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400757 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400758 }
759
760 /* always attach property, if created */
761 if (*prop)
762 drm_object_attach_property(&plane->base, *prop, init);
763 }
764}
765
Clarence Ip5e2a9222016-06-26 22:38:24 -0400766static void _sde_plane_install_rotation_property(struct drm_plane *plane,
767 struct drm_device *dev, struct drm_property **prop)
768{
769 if (plane && dev && prop) {
770 /* only create the property once */
771 if (*prop == 0) {
772 *prop = drm_mode_create_rotation_property(dev,
773 BIT(DRM_REFLECT_X) |
774 BIT(DRM_REFLECT_Y));
775 if (*prop == 0)
776 DRM_ERROR("Create rotation property failed\n");
777 }
778
779 /* always attach property, if created */
780 if (*prop)
781 drm_object_attach_property(&plane->base, *prop, 0);
782 }
783}
784
785static void _sde_plane_install_enum_property(struct drm_plane *plane,
786 struct drm_device *dev, const char *name, int is_bitmask,
787 const struct drm_prop_enum_list *values, int num_values,
788 struct drm_property **prop)
789{
790 if (plane && dev && name && prop && values && num_values) {
791 /* only create the property once */
792 if (*prop == 0) {
793 /* 'bitmask' is a special type of 'enum' */
794 if (is_bitmask)
795 *prop = drm_property_create_bitmask(dev,
796 DRM_MODE_PROP_BITMASK, name,
797 values, num_values, -1);
798 else
799 *prop = drm_property_create_enum(dev,
800 DRM_MODE_PROP_ENUM, name,
801 values, num_values);
802 if (*prop == 0)
803 DRM_ERROR("Create %s property failed\n", name);
804 }
805
806 /* always attach property, if created */
807 if (*prop)
808 drm_object_attach_property(&plane->base, *prop, 0);
809 }
810}
811
Clarence Ipe78efb72016-06-24 18:35:21 -0400812static void _sde_plane_install_blob_property(struct drm_plane *plane,
813 struct drm_device *dev, const char *name,
814 struct drm_property **prop)
815{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400816 if (plane && dev && name && prop) {
817 /* only create the property once */
818 if (*prop == 0) {
819 /* use 'create' for blob property place holder */
820 *prop = drm_property_create(dev,
821 DRM_MODE_PROP_BLOB, name, 0);
822 if (*prop == 0)
823 DRM_ERROR("Create %s property failed\n", name);
824 }
825
826 /* always attach property, if created */
827 if (*prop)
828 drm_object_attach_property(&plane->base, *prop, 0);
829 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400830}
831
Clarence Ip4c1d9772016-06-26 09:35:38 -0400832static int _sde_plane_get_property_index(struct drm_plane *plane,
833 struct drm_property *property)
834{
835 struct drm_property **prop_array;
836 int idx = PLANE_PROP_COUNT;
837
838 if (!plane) {
839 DRM_ERROR("Invalid plane\n");
840 } else if (!plane->dev || !plane->dev->dev_private) {
841 /* don't access dev_private if !dev */
842 DRM_ERROR("Invalid device\n");
843 } else if (!property) {
844 DRM_ERROR("Incoming property is NULL\n");
845 } else {
846 prop_array = ((struct msm_drm_private *)
847 (plane->dev->dev_private))->plane_property;
848 if (!prop_array)
849 /* should never hit this */
850 DRM_ERROR("Invalid property array\n");
851
852 /* linear search is okay */
853 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
854 if (prop_array[idx] == property)
855 break;
856 }
857 }
858
859 return idx;
860}
861
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400862/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400863static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -0400864 struct drm_mode_object *obj,
865 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400866{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400867 static const struct drm_prop_enum_list e_blend_op[] = {
868 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
869 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
870 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
871 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
872 };
873 static const struct drm_prop_enum_list e_src_config[] = {
874 {SDE_DRM_DEINTERLACE, "deinterlace"}
875 };
876 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400877 struct drm_device *dev = plane->dev;
878 struct msm_drm_private *dev_priv = dev->dev_private;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400879
Clarence Ip4ce59322016-06-26 22:27:51 -0400880 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400881
Clarence Ip4c1d9772016-06-26 09:35:38 -0400882 if (!psde || !psde->pipe_sblk || !catalog) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400883 DRM_ERROR("Failed to identify catalog definition\n");
884 return;
885 }
886
887 /* range properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400888 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255, 1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400889 &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400890
Clarence Ip5e2a9222016-06-26 22:38:24 -0400891 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
892 &(dev_priv->plane_property[PLANE_PROP_ALPHA]));
893
Clarence Ip4c1d9772016-06-26 09:35:38 -0400894 /* max range of first pipe will be used */
Clarence Ip5e2a9222016-06-26 22:38:24 -0400895 _sde_plane_install_range_property(plane, dev, "h_decimate",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400896 0, psde->pipe_sblk->maxhdeciexp, 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400897 &(dev_priv->plane_property[PLANE_PROP_H_DECIMATE]));
898
Clarence Ip4c1d9772016-06-26 09:35:38 -0400899 /* max range of first pipe will be used */
Clarence Ip5e2a9222016-06-26 22:38:24 -0400900 _sde_plane_install_range_property(plane, dev, "v_decimate",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400901 0, psde->pipe_sblk->maxvdeciexp, 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400902 &(dev_priv->plane_property[PLANE_PROP_V_DECIMATE]));
903
904 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, 0,
905 &(dev_priv->plane_property[PLANE_PROP_SYNC_FENCE]));
906
907 /* standard properties */
908 _sde_plane_install_rotation_property(plane, dev,
909 &(dev_priv->plane_property[PLANE_PROP_ROTATION]));
910
911 /* enum/bitmask properties */
912 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
913 e_blend_op, ARRAY_SIZE(e_blend_op),
914 &(dev_priv->plane_property[PLANE_PROP_BLEND_OP]));
915 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
916 e_src_config, ARRAY_SIZE(e_src_config),
917 &(dev_priv->plane_property[PLANE_PROP_SRC_CONFIG]));
918
Clarence Ipe78efb72016-06-24 18:35:21 -0400919 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400920 if (psde->features & SDE_SSPP_SCALER)
921 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ip5e2a9222016-06-26 22:38:24 -0400922 &(dev_priv->plane_property[PLANE_PROP_SCALER]));
Clarence Ip4c1d9772016-06-26 09:35:38 -0400923 if (psde->features & BIT(SDE_SSPP_CSC))
924 _sde_plane_install_blob_property(plane, dev, "csc",
925 &(dev_priv->plane_property[PLANE_PROP_CSC]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400926}
927
928static int sde_plane_atomic_set_property(struct drm_plane *plane,
929 struct drm_plane_state *state, struct drm_property *property,
930 uint64_t val)
931{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400932 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400933 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -0400934 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400935
Clarence Ip4ce59322016-06-26 22:27:51 -0400936 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400937
Clarence Ip4c1d9772016-06-26 09:35:38 -0400938 idx = _sde_plane_get_property_index(plane, property);
939 if (!state) {
940 DRM_ERROR("Invalid state\n");
941 } else if (idx < PLANE_PROP_COUNT) {
942 DBG("Set property %d <= %d", idx, (int)val);
943 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400944
Clarence Ip4c1d9772016-06-26 09:35:38 -0400945 /* extra handling for incoming blob properties */
946 if ((property->flags & DRM_MODE_PROP_BLOB) &&
947 (idx < PLANE_PROP_BLOBCOUNT)) {
948 /* DRM lookup also takes a reference */
949 blob = drm_property_lookup_blob(plane->dev,
950 (uint32_t)val);
951 if (!blob) {
952 DRM_ERROR("Blob not found\n");
953 val = 0;
954 } else {
955 DBG("Blob %u saved", blob->base.id);
956 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400957
Clarence Ip4c1d9772016-06-26 09:35:38 -0400958 /* save blobs for later */
959 pr_blob = &pstate->property_blobs[idx];
960 /* need to clear previous reference */
961 if (*pr_blob)
962 drm_property_unreference_blob(*pr_blob);
963 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -0400964 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400965 }
Clarence Ip4c1d9772016-06-26 09:35:38 -0400966 pstate->property_values[idx] = val;
967 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -0400968 }
969
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400970 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400971}
972
973static int sde_plane_set_property(struct drm_plane *plane,
974 struct drm_property *property, uint64_t val)
975{
976 int rc;
977
Clarence Ip4ce59322016-06-26 22:27:51 -0400978 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -0400979
980 if (!plane)
981 return -EINVAL;
982
Clarence Ip5e2a9222016-06-26 22:38:24 -0400983 rc = sde_plane_atomic_set_property(plane, plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400984 return rc;
985}
986
987static int sde_plane_atomic_get_property(struct drm_plane *plane,
988 const struct drm_plane_state *state,
989 struct drm_property *property, uint64_t *val)
990{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400991 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -0400992 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400993
Clarence Ip4ce59322016-06-26 22:27:51 -0400994 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400995
Clarence Ip4c1d9772016-06-26 09:35:38 -0400996 idx = _sde_plane_get_property_index(plane, property);
997 if (!state) {
998 DRM_ERROR("Invalid state\n");
999 } else if (!val) {
1000 DRM_ERROR("Value pointer is NULL\n");
1001 } else if (idx < PLANE_PROP_COUNT) {
1002 pstate = to_sde_plane_state(state);
1003
1004 *val = pstate->property_values[idx];
1005 DBG("Get property %d %lld", idx, *val);
1006 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001007 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001008
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001009 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001010}
1011
1012static void sde_plane_destroy(struct drm_plane *plane)
1013{
Clarence Ip4ce59322016-06-26 22:27:51 -04001014 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001015
Clarence Ip4ce59322016-06-26 22:27:51 -04001016 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001017
Clarence Ip4ce59322016-06-26 22:27:51 -04001018 if (plane) {
1019 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001020
Clarence Ip4ce59322016-06-26 22:27:51 -04001021 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001022
Clarence Ip4ce59322016-06-26 22:27:51 -04001023 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001024
Clarence Ip4ce59322016-06-26 22:27:51 -04001025 /* this will destroy the states as well */
1026 drm_plane_cleanup(plane);
1027
Clarence Ip4c1d9772016-06-26 09:35:38 -04001028 if (psde->pipe_hw)
1029 sde_hw_sspp_destroy(psde->pipe_hw);
1030
Clarence Ip4ce59322016-06-26 22:27:51 -04001031 kfree(psde);
1032 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001033}
1034
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001035static void sde_plane_destroy_state(struct drm_plane *plane,
1036 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001037{
Clarence Ipe78efb72016-06-24 18:35:21 -04001038 struct sde_plane_state *pstate;
1039 int i;
1040
Clarence Ip4ce59322016-06-26 22:27:51 -04001041 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -04001042
1043 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001044 if (state->fb)
1045 drm_framebuffer_unreference(state->fb);
1046
Clarence Ipe78efb72016-06-24 18:35:21 -04001047 pstate = to_sde_plane_state(state);
1048
1049 /* remove ref count for blobs */
1050 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1051 if (pstate->property_blobs[i])
1052 drm_property_unreference_blob(
1053 pstate->property_blobs[i]);
1054
1055 kfree(pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001056}
1057
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001058static struct drm_plane_state *
1059sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001060{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001061 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001062 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001063
1064 if (WARN_ON(!plane->state))
1065 return NULL;
1066
Clarence Ip4ce59322016-06-26 22:27:51 -04001067 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001068 pstate = kmemdup(to_sde_plane_state(plane->state),
1069 sizeof(*pstate), GFP_KERNEL);
Clarence Ipe78efb72016-06-24 18:35:21 -04001070 if (pstate) {
1071 /* add ref count for frame buffer */
1072 if (pstate->base.fb)
1073 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001074
Clarence Ipe78efb72016-06-24 18:35:21 -04001075 /* add ref count for blobs */
1076 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1077 if (pstate->property_blobs[i])
1078 drm_property_reference_blob(
1079 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001080
Clarence Ipe78efb72016-06-24 18:35:21 -04001081 pstate->mode_changed = false;
1082 pstate->pending = false;
1083 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001084
Clarence Ipe78efb72016-06-24 18:35:21 -04001085 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001086}
1087
1088static void sde_plane_reset(struct drm_plane *plane)
1089{
1090 struct sde_plane_state *pstate;
1091
Clarence Ip4ce59322016-06-26 22:27:51 -04001092 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001093 if (plane->state && plane->state->fb)
1094 drm_framebuffer_unreference(plane->state->fb);
1095
1096 kfree(to_sde_plane_state(plane->state));
1097 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
1098
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001099 /* assign default blend parameters */
Clarence Ipe78efb72016-06-24 18:35:21 -04001100 pstate->property_values[PLANE_PROP_ALPHA] = 255;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001101
1102 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
Clarence Ipe78efb72016-06-24 18:35:21 -04001103 pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001104 else
Clarence Ipe78efb72016-06-24 18:35:21 -04001105 pstate->property_values[PLANE_PROP_ZPOS] =
1106 STAGE0 + drm_plane_index(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001107
1108 pstate->base.plane = plane;
1109
1110 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001111}
1112
1113static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001114 .update_plane = drm_atomic_helper_update_plane,
1115 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001116 .destroy = sde_plane_destroy,
1117 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001118 .atomic_set_property = sde_plane_atomic_set_property,
1119 .atomic_get_property = sde_plane_atomic_get_property,
1120 .reset = sde_plane_reset,
1121 .atomic_duplicate_state = sde_plane_duplicate_state,
1122 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001123};
1124
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001125static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1126 .prepare_fb = sde_plane_prepare_fb,
1127 .cleanup_fb = sde_plane_cleanup_fb,
1128 .atomic_check = sde_plane_atomic_check,
1129 .atomic_update = sde_plane_atomic_update,
1130};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001131
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001132enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001133{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001134 struct sde_plane *sde_plane = to_sde_plane(plane);
1135
1136 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001137}
1138
Clarence Ip4ce59322016-06-26 22:27:51 -04001139static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1140{
1141 const struct sde_sspp_sub_blks *sblk = 0;
1142 const struct sde_sspp_cfg *cfg = 0;
1143
1144 if (psde && psde->pipe_hw)
1145 cfg = psde->pipe_hw->cap;
1146 if (cfg)
1147 sblk = cfg->sblk;
1148
1149 if (kms && sblk) {
1150 /* create overall sub-directory for the pipe */
1151 psde->debugfs_root =
1152 debugfs_create_dir(psde->pipe_name,
1153 sde_debugfs_get_root(kms));
1154 if (psde->debugfs_root) {
1155 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001156 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001157 psde->debugfs_root, &psde->features);
1158
1159 /* add register dump support */
1160 sde_debugfs_setup_regset32(&psde->debugfs_src,
1161 sblk->src_blk.base + cfg->base,
1162 sblk->src_blk.len,
1163 kms->mmio);
1164 sde_debugfs_create_regset32("src_blk", 0444,
1165 psde->debugfs_root, &psde->debugfs_src);
1166
1167 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1168 sblk->scaler_blk.base + cfg->base,
1169 sblk->scaler_blk.len,
1170 kms->mmio);
1171 sde_debugfs_create_regset32("scaler_blk", 0444,
1172 psde->debugfs_root,
1173 &psde->debugfs_scaler);
1174
1175 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1176 sblk->csc_blk.base + cfg->base,
1177 sblk->csc_blk.len,
1178 kms->mmio);
1179 sde_debugfs_create_regset32("csc_blk", 0444,
1180 psde->debugfs_root, &psde->debugfs_csc);
1181 }
1182 }
1183}
1184
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001185/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001186struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001187 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001188{
1189 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001190 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001191 struct msm_drm_private *priv;
1192 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001193 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001194 int ret = -EINVAL;
1195
1196 if (!dev) {
1197 DRM_ERROR("[%u]Device is NULL\n", pipe);
1198 goto exit;
1199 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001200
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001201 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001202 if (!priv) {
1203 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1204 goto exit;
1205 }
1206
1207 if (!priv->kms) {
1208 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1209 goto exit;
1210 }
1211 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001212
Clarence Ip4c1d9772016-06-26 09:35:38 -04001213 if (!kms->catalog) {
1214 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1215 goto exit;
1216 }
1217
Clarence Ip4ce59322016-06-26 22:27:51 -04001218 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001219 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1220 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001221 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001222 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001223 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001224 }
1225
Clarence Ip4c1d9772016-06-26 09:35:38 -04001226 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001227 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001228 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001229 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001230
Clarence Ip4c1d9772016-06-26 09:35:38 -04001231 /* initialize underlying h/w driver */
1232 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1233 if (IS_ERR(psde->pipe_hw)) {
1234 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1235 ret = PTR_ERR(psde->pipe_hw);
1236 goto clean_plane;
1237 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1238 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1239 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001240 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001241
1242 /* cache features mask for later */
1243 psde->features = psde->pipe_hw->cap->features;
1244 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1245
1246 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001247 psde->nformats = mdp_get_formats(psde->formats,
1248 ARRAY_SIZE(psde->formats),
1249 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001250 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001251
Clarence Ip4c1d9772016-06-26 09:35:38 -04001252 if (!psde->nformats) {
1253 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1254 goto clean_sspp;
1255 }
1256
1257 if (psde->features & BIT(SDE_SSPP_CURSOR))
1258 type = DRM_PLANE_TYPE_CURSOR;
1259 else if (primary_plane)
1260 type = DRM_PLANE_TYPE_PRIMARY;
1261 else
1262 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001263 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1264 psde->formats, psde->nformats,
1265 type);
1266 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001267 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001268
Clarence Ip4c1d9772016-06-26 09:35:38 -04001269 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001270 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001271
Clarence Ip4c1d9772016-06-26 09:35:38 -04001272 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001273
Clarence Ip4ce59322016-06-26 22:27:51 -04001274 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001275 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001276
1277 _sde_plane_init_debugfs(psde, kms);
1278
Clarence Ip4c1d9772016-06-26 09:35:38 -04001279 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001280 return plane;
1281
Clarence Ip4c1d9772016-06-26 09:35:38 -04001282clean_sspp:
1283 if (psde && psde->pipe_hw)
1284 sde_hw_sspp_destroy(psde->pipe_hw);
1285clean_plane:
1286 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001287exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001288 return ERR_PTR(ret);
1289}