blob: 1681bbf3168bac5b398ea5982b24b04fc7a31eff [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 Ip373f8592016-05-26 00:58:42 -040046 struct sde_csc_cfg csc_cfg;
47 struct sde_csc_cfg *csc_ptr;
48
Clarence Ip4c1d9772016-06-26 09:35:38 -040049 const struct sde_sspp_sub_blks *pipe_sblk;
50
Clarence Ip5e2a9222016-06-26 22:38:24 -040051 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040052
53 /* debugfs related stuff */
54 struct dentry *debugfs_root;
55 struct sde_debugfs_regset32 debugfs_src;
56 struct sde_debugfs_regset32 debugfs_scaler;
57 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070058};
59#define to_sde_plane(x) container_of(x, struct sde_plane, base)
60
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040061static bool sde_plane_enabled(struct drm_plane_state *state)
62{
63 return state->fb && state->crtc;
64}
65
Clarence Ipe78efb72016-06-24 18:35:21 -040066static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -040067 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040068 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
69{
70 struct sde_plane *psde = to_sde_plane(plane);
Clarence Ip5e2a9222016-06-26 22:38:24 -040071 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040072 int i;
73
74 if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
75 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -040076 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -040077 BIT(SDE_DRM_DEINTERLACE))
78 shift = 1;
79 else
80 shift = 0;
81
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040082 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
83 while (i) {
84 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -040085 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040086 }
87
88 /* address */
89 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
90 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
91 psde->mmu_id, i);
92
93 /* hw driver */
94 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
95 }
96}
97
Clarence Ip5e2a9222016-06-26 22:38:24 -040098static void _sde_plane_setup_scaler3(struct drm_plane *plane,
99 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
100 struct sde_hw_scaler3_cfg *scale_cfg,
101 struct sde_mdp_format_params *fmt,
102 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
103{
104}
105
106static void _sde_plane_setup_scaler2(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400107 uint32_t src, uint32_t dst, uint32_t *phase_steps,
108 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
109 uint32_t chroma_subsampling)
110{
Clarence Ip4c1d9772016-06-26 09:35:38 -0400111 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400112 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400113 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400114 phase_steps[SDE_SSPP_COMP_1_2] =
115 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
116 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
117 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400118
119 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -0400120 if (fmt->is_yuv || src != dst) {
121 filter[SDE_SSPP_COMP_3] =
122 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
123 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400124
Clarence Ipe78efb72016-06-24 18:35:21 -0400125 if (fmt->is_yuv) {
126 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
127 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
128 } else {
129 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
130 filter[SDE_SSPP_COMP_1_2] =
131 SDE_MDP_SCALE_FILTER_NEAREST;
132 }
133 } else {
134 /* disable scaler */
135 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
136 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
137 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400138 }
139}
140
Clarence Ipe78efb72016-06-24 18:35:21 -0400141static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400142 uint32_t src, uint32_t dst, uint32_t decimated_src,
143 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400144 int *out_edge2, enum sde_hw_filter *filter,
145 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
146 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400147{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400148 int64_t edge1, edge2, caf;
149 uint32_t src_work;
150 int i, tmp;
151
Clarence Ipe78efb72016-06-24 18:35:21 -0400152 if (plane && phase_steps && out_src && out_edge1 &&
153 out_edge2 && filter && fmt) {
154 /* handle CAF for YUV formats */
155 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400156 caf = PHASE_STEP_UNIT_SCALE;
157 else
158 caf = 0;
159
160 for (i = 0; i < SDE_MAX_PLANES; i++) {
161 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400162 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400163 src_work /= chroma_subsampling;
164 if (post_compare)
165 src = src_work;
166 if (!(fmt->is_yuv) && (src == dst)) {
167 /* unity */
168 edge1 = 0;
169 edge2 = 0;
170 } else if (dst >= src) {
171 /* upscale */
172 edge1 = (1 << PHASE_RESIDUAL);
173 edge1 -= caf;
174 edge2 = (1 << PHASE_RESIDUAL);
175 edge2 += (dst - 1) * *(phase_steps + i);
176 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
177 edge2 += caf;
178 edge2 = -(edge2);
179 } else {
180 /* downscale */
181 edge1 = 0;
182 edge2 = (dst - 1) * *(phase_steps + i);
183 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
184 edge2 += *(phase_steps + i);
185 edge2 = -(edge2);
186 }
187
188 /* only enable CAF for luma plane */
189 caf = 0;
190
191 /* populate output arrays */
192 *(out_src + i) = src_work;
193
194 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400195 if (edge1 >= 0) {
196 tmp = (uint32_t)edge1;
197 tmp >>= PHASE_STEP_SHIFT;
198 *(out_edge1 + i) = -tmp;
199 } else {
200 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400201 *(out_edge1 + i) =
202 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
203 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400204 }
205 if (edge2 >= 0) {
206 tmp = (uint32_t)edge2;
207 tmp >>= PHASE_STEP_SHIFT;
208 *(out_edge2 + i) = -tmp;
209 } else {
210 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400211 *(out_edge2 + i) =
212 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
213 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400214 }
215 }
216 }
217}
218
Clarence Ip5e2a9222016-06-26 22:38:24 -0400219static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
220 enum msm_mdp_plane_property property, size_t *byte_len)
221{
222 struct drm_property_blob *blob;
223 size_t len = 0;
224 void *ret = 0;
225
Clarence Ip4c1d9772016-06-26 09:35:38 -0400226 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
227 DRM_ERROR("Invalid argument(s)\n");
228 } else {
229 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400230 if (blob) {
231 len = blob->length;
232 ret = &blob->data;
233 }
234 }
235
236 if (byte_len)
237 *byte_len = len;
238
239 return ret;
240}
241
242/**
243 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
244 * sub-structure
245 * @blob_ptr: Pointer to start of incoming blob data
246 * @blob_size: Size of incoming blob data, in bytes
247 * @sub_ptr: Pointer to start of desired sub-structure
248 * @sub_size: Required size of sub-structure, in bytes
249 */
250static int _sde_plane_verify_blob(void *blob_ptr,
251 size_t blob_size,
252 void *sub_ptr,
253 size_t sub_size)
254{
255 /*
256 * Use the blob size provided by drm to check if there are enough
257 * bytes from the start of versioned sub-structures to the end of
258 * blob data:
259 *
260 * e.g.,
261 * blob_ptr --> struct blob_data {
262 * uint32_t version;
263 * sub_ptr --> struct blob_data_v1 v1;
264 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
265 * blob_ptr + blob_size --> };
266 *
267 * It's important to check the actual number of bytes from the start
268 * of the sub-structure to the end of the blob data, and not just rely
269 * on something like,
270 *
271 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
272 *
273 * This is because the start of the sub-structure can vary based on
274 * how the compiler pads the overall structure.
275 */
276 if (blob_ptr && sub_ptr)
277 /* return zero if end of blob >= end of sub-struct */
278 return ((unsigned char *)blob_ptr + blob_size) <
279 ((unsigned char *)sub_ptr + sub_size);
280 return -EINVAL;
281}
282
Clarence Ipe78efb72016-06-24 18:35:21 -0400283static void _sde_plane_setup_csc(struct sde_plane *psde,
284 struct sde_plane_state *pstate,
285 struct sde_mdp_format_params *fmt)
286{
287 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
288 {
Clarence Ip373f8592016-05-26 00:58:42 -0400289 /* S15.16 format */
290 0x00012A00, 0x00000000, 0x00019880,
291 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
292 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400293 },
Clarence Ip373f8592016-05-26 00:58:42 -0400294 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400295 { 0xfff0, 0xff80, 0xff80,},
296 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400297 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400298 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400299 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400300 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400301 static const struct sde_csc_cfg sde_csc_NOP = {
302 {
Clarence Ip373f8592016-05-26 00:58:42 -0400303 /* identity matrix, S15.16 format */
304 0x10000, 0x00000, 0x00000,
305 0x00000, 0x10000, 0x00000,
306 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400307 },
Clarence Ip373f8592016-05-26 00:58:42 -0400308 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400309 { 0x0, 0x0, 0x0,},
310 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400311 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400312 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
313 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
314 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400315 struct sde_drm_csc *csc = NULL;
316 size_t csc_size = 0;
317 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400318
319 if (!psde->pipe_hw->ops.setup_csc)
320 return;
321
Clarence Ip5e2a9222016-06-26 22:38:24 -0400322 /* check for user space override */
323 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
324 if (csc) {
325 struct sde_csc_cfg cfg;
326 int i;
327
328 /* user space override */
329 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
330 switch (csc->version) {
331 case SDE_DRM_CSC_V1:
332 if (!_sde_plane_verify_blob(csc,
333 csc_size,
334 &csc->v1,
335 sizeof(struct sde_drm_csc_v1))) {
336 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
337 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400338 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400339 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
340 cfg.csc_pre_bv[i] =
341 csc->v1.pre_bias[i];
342 cfg.csc_post_bv[i] =
343 csc->v1.post_bias[i];
344 }
345 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
346 cfg.csc_pre_lv[i] =
347 csc->v1.pre_clamp[i];
348 cfg.csc_post_lv[i] =
349 csc->v1.post_clamp[i];
350 }
351 user_blob = true;
352 }
353 break;
354 default:
355 break;
356 }
357
358 if (!user_blob)
359 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
360 else
361 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
362 (struct sde_csc_cfg *)&cfg);
363 }
364
365 if (user_blob) {
366 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400367 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400368 /* revert to kernel default */
369 } else if (fmt->is_yuv) {
Clarence Ip373f8592016-05-26 00:58:42 -0400370 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400371 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400372 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400373 }
Clarence Ip373f8592016-05-26 00:58:42 -0400374
375 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400376}
377
378static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700379 struct drm_crtc *crtc, struct drm_framebuffer *fb,
380 int crtc_x, int crtc_y,
381 unsigned int crtc_w, unsigned int crtc_h,
382 uint32_t src_x, uint32_t src_y,
383 uint32_t src_w, uint32_t src_h)
384{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400385 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400386 struct sde_plane_state *pstate;
387 const struct mdp_format *format;
388 uint32_t nplanes, pix_format, tmp;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400389 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
390 uint32_t src_fmt_flags;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400391 int i;
392 struct sde_mdp_format_params *fmt;
393 struct sde_hw_pixel_ext *pe;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400394 size_t sc_u_size = 0;
395 struct sde_drm_scaler *sc_u = NULL;
396 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400397
Clarence Ip4ce59322016-06-26 22:27:51 -0400398 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400399
Clarence Ip5e2a9222016-06-26 22:38:24 -0400400 if (!plane || !plane->state) {
401 DRM_ERROR("Invalid plane/state\n");
402 return -EINVAL;
403 }
404 if (!crtc || !fb) {
405 DRM_ERROR("Invalid crtc/fb\n");
406 return -EINVAL;
407 }
408 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400409 pstate = to_sde_plane_state(plane->state);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400410 nplanes = drm_format_num_planes(fb->pixel_format);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400411
412 format = to_mdp_format(msm_framebuffer_format(fb));
413 pix_format = format->base.pixel_format;
414
415 /* src values are in Q16 fixed point, convert to integer */
416 src_x = src_x >> 16;
417 src_y = src_y >> 16;
418 src_w = src_w >> 16;
419 src_h = src_h >> 16;
420
Clarence Ip4ce59322016-06-26 22:27:51 -0400421 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400422 fb->base.id, src_x, src_y, src_w, src_h,
423 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
424
425 /* update format configuration */
426 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400427 src_fmt_flags = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400428
429 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400430 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400431 psde->pipe_cfg.src.width = fb->width;
432 psde->pipe_cfg.src.height = fb->height;
433 psde->pipe_cfg.src.num_planes = nplanes;
434
Clarence Ip5e2a9222016-06-26 22:38:24 -0400435 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
436
437 /* decimation */
438 psde->pipe_cfg.horz_decimation =
Clarence Ip4c1d9772016-06-26 09:35:38 -0400439 sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400440 psde->pipe_cfg.vert_decimation =
Clarence Ip4c1d9772016-06-26 09:35:38 -0400441 sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400442
443 /* flags */
444 DBG("Flags 0x%llX, rotation 0x%llX",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400445 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
446 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
447 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400448 BIT(DRM_REFLECT_X))
449 src_fmt_flags |= SDE_SSPP_FLIP_LR;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400450 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400451 BIT(DRM_REFLECT_Y))
452 src_fmt_flags |= SDE_SSPP_FLIP_UD;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400453 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400454 BIT(SDE_DRM_DEINTERLACE)) {
455 src_h /= 2;
456 src_y = DIV_ROUND_UP(src_y, 2);
457 src_y &= ~0x1;
458 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400459
460 psde->pipe_cfg.src_rect.x = src_x;
461 psde->pipe_cfg.src_rect.y = src_y;
462 psde->pipe_cfg.src_rect.w = src_w;
463 psde->pipe_cfg.src_rect.h = src_h;
464
465 psde->pipe_cfg.dst_rect.x = crtc_x;
466 psde->pipe_cfg.dst_rect.y = crtc_y;
467 psde->pipe_cfg.dst_rect.w = crtc_w;
468 psde->pipe_cfg.dst_rect.h = crtc_h;
469
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400470 /* get sde pixel format definition */
471 fmt = psde->pipe_cfg.src.format;
472
Clarence Ip5e2a9222016-06-26 22:38:24 -0400473 /* don't chroma subsample if decimating */
474 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
475 drm_format_horz_chroma_subsampling(pix_format);
476 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
477 drm_format_vert_chroma_subsampling(pix_format);
478
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400479 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400480 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400481
Clarence Ip5e2a9222016-06-26 22:38:24 -0400482 /* get scaler config from user space */
483 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
484 if (sc_u) {
485 switch (sc_u->version) {
486 case SDE_DRM_SCALER_V1:
487 if (!_sde_plane_verify_blob(sc_u,
488 sc_u_size,
489 &sc_u->v1,
490 sizeof(*sc_u1)))
491 sc_u1 = &sc_u->v1;
492 break;
493 default:
494 DBG("Unrecognized scaler blob v%lld", sc_u->version);
495 break;
496 }
497 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400498
Clarence Ip5e2a9222016-06-26 22:38:24 -0400499 /* update scaler */
500 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
501 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
502 DBG("QSEED3 blob detected");
503 else
504 _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
505 crtc_h, &psde->scaler3_cfg, fmt,
506 chroma_subsmpl_h, chroma_subsmpl_v);
507 } else {
508 /* always calculate basic scaler config */
509 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
510 /* populate from user space */
511 for (i = 0; i < SDE_MAX_PLANES; i++) {
512 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
513 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
514 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
515 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400516
Clarence Ip5e2a9222016-06-26 22:38:24 -0400517 pe->horz_filter[i] = sc_u1->horz_filter[i];
518 pe->vert_filter[i] = sc_u1->vert_filter[i];
519 }
520 } else {
521 /* calculate phase steps */
522 _sde_plane_setup_scaler2(plane, src_w, crtc_w,
523 pe->phase_step_x,
524 pe->horz_filter, fmt, chroma_subsmpl_h);
525 _sde_plane_setup_scaler2(plane, src_h, crtc_h,
526 pe->phase_step_y,
527 pe->vert_filter, fmt, chroma_subsmpl_v);
528 }
529 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400530
Clarence Ip5e2a9222016-06-26 22:38:24 -0400531 /* update pixel extensions */
532 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
533 /* populate from user space */
534 for (i = 0; i < SDE_MAX_PLANES; i++) {
535 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
536 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
537 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
538 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
539 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
540 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
541 pe->roi_w[i] = sc_u1->lr.roi[i];
542
543 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
544 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
545 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
546 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
547 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
548 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
549 pe->roi_h[i] = sc_u1->tb.roi[i];
550 }
551 } else {
552 /* calculate left/right/top/bottom pixel extensions */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400553 tmp = DECIMATED_DIMENSION(src_w,
554 psde->pipe_cfg.horz_decimation);
555 if (fmt->is_yuv)
556 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400557 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400558 pe->phase_step_x,
559 pe->roi_w,
560 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400561 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400562 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400563
564 tmp = DECIMATED_DIMENSION(src_h,
565 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400566 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400567 pe->phase_step_y,
568 pe->roi_h,
569 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400570 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400571 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400572
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 for (i = 0; i < SDE_MAX_PLANES; i++) {
574 if (pe->num_ext_pxls_left[i] >= 0)
575 pe->left_rpt[i] =
576 pe->num_ext_pxls_left[i];
577 else
578 pe->left_ftch[i] =
579 pe->num_ext_pxls_left[i];
580
581 if (pe->num_ext_pxls_right[i] >= 0)
582 pe->right_rpt[i] =
583 pe->num_ext_pxls_right[i];
584 else
585 pe->right_ftch[i] =
586 pe->num_ext_pxls_right[i];
587
588 if (pe->num_ext_pxls_top[i] >= 0)
589 pe->top_rpt[i] =
590 pe->num_ext_pxls_top[i];
591 else
592 pe->top_ftch[i] =
593 pe->num_ext_pxls_top[i];
594
595 if (pe->num_ext_pxls_btm[i] >= 0)
596 pe->btm_rpt[i] =
597 pe->num_ext_pxls_btm[i];
598 else
599 pe->btm_ftch[i] =
600 pe->num_ext_pxls_btm[i];
601 }
602 }
603
Clarence Ip4c1d9772016-06-26 09:35:38 -0400604 if (psde->pipe_hw->ops.setup_format)
605 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400606 &psde->pipe_cfg, src_fmt_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400607 if (psde->pipe_hw->ops.setup_rects)
608 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
609 &psde->pipe_cfg, &psde->pixel_ext);
610
Clarence Ipe78efb72016-06-24 18:35:21 -0400611 /* update sharpening */
612 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
613 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
614 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
615 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
616
617 if (psde->pipe_hw->ops.setup_sharpening)
618 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
619 &psde->sharp_cfg);
620
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400621 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400622 if (fmt->is_yuv)
623 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400624
Clarence Ip5e2a9222016-06-26 22:38:24 -0400625 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400626}
627
628static int sde_plane_prepare_fb(struct drm_plane *plane,
629 const struct drm_plane_state *new_state)
630{
631 struct drm_framebuffer *fb = new_state->fb;
632 struct sde_plane *psde = to_sde_plane(plane);
633
634 if (!new_state->fb)
635 return 0;
636
Clarence Ip4ce59322016-06-26 22:27:51 -0400637 DBG("%s: prepare: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400638 return msm_framebuffer_prepare(fb, psde->mmu_id);
639}
640
641static void sde_plane_cleanup_fb(struct drm_plane *plane,
642 const struct drm_plane_state *old_state)
643{
644 struct drm_framebuffer *fb = old_state->fb;
645 struct sde_plane *psde = to_sde_plane(plane);
646
647 if (!fb)
648 return;
649
Clarence Ip4ce59322016-06-26 22:27:51 -0400650 DBG("%s: cleanup: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400651 msm_framebuffer_cleanup(fb, psde->mmu_id);
652}
653
654static int sde_plane_atomic_check(struct drm_plane *plane,
655 struct drm_plane_state *state)
656{
657 struct sde_plane *psde = to_sde_plane(plane);
658 struct drm_plane_state *old_state = plane->state;
659 const struct mdp_format *format;
660
Clarence Ip4ce59322016-06-26 22:27:51 -0400661 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400662 sde_plane_enabled(old_state), sde_plane_enabled(state));
663
664 if (sde_plane_enabled(state)) {
665 /* CIFIX: don't use mdp format? */
666 format = to_mdp_format(msm_framebuffer_format(state->fb));
667 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400668 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400669 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400670 DRM_ERROR("Pipe doesn't support YUV\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400671
672 return -EINVAL;
673 }
674
Clarence Ipe78efb72016-06-24 18:35:21 -0400675 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400676 (((state->src_w >> 16) != state->crtc_w) ||
677 ((state->src_h >> 16) != state->crtc_h))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400678 DRM_ERROR(
679 "Unsupported Pipe scaling (%dx%d -> %dx%d)\n",
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400680 state->src_w >> 16, state->src_h >> 16,
681 state->crtc_w, state->crtc_h);
682
683 return -EINVAL;
684 }
685 }
686
687 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
688 /* we cannot change SMP block configuration during scanout: */
689 bool full_modeset = false;
690
691 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400692 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400693 full_modeset = true;
694 }
695 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400696 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400697 full_modeset = true;
698 }
699 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400700 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400701 full_modeset = true;
702 }
703 if (full_modeset) {
704 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400705 drm_atomic_get_crtc_state(state->state,
706 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400707 crtc_state->mode_changed = true;
708 to_sde_plane_state(state)->mode_changed = true;
709 }
710 } else {
711 to_sde_plane_state(state)->mode_changed = true;
712 }
713
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700714 return 0;
715}
716
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400717static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400718 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700719{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400720 struct sde_plane *sde_plane;
721 struct drm_plane_state *state;
722 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400723
Clarence Ip4ce59322016-06-26 22:27:51 -0400724 DBG("%s: update", sde_plane->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400725
Clarence Ip5e2a9222016-06-26 22:38:24 -0400726 if (!plane || !plane->state) {
727 DRM_ERROR("Invalid plane/state\n");
728 return;
729 }
730
731 sde_plane = to_sde_plane(plane);
732 state = plane->state;
733 pstate = to_sde_plane_state(state);
734
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400735 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400736 pstate->pending = true;
737 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400738 int ret;
739
Clarence Ip5e2a9222016-06-26 22:38:24 -0400740 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400741 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400742 state->crtc, state->fb,
743 state->crtc_x, state->crtc_y,
744 state->crtc_w, state->crtc_h,
745 state->src_x, state->src_y,
746 state->src_w, state->src_h);
747 /* atomic_check should have ensured that this doesn't fail */
748 WARN_ON(ret < 0);
749 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400750 _sde_plane_set_scanout(plane, pstate,
751 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400752 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400753}
754
Clarence Ipe78efb72016-06-24 18:35:21 -0400755static void _sde_plane_install_range_property(struct drm_plane *plane,
756 struct drm_device *dev, const char *name,
757 uint64_t min, uint64_t max, uint64_t init,
758 struct drm_property **prop)
759{
760 if (plane && dev && name && prop) {
761 /* only create the property once */
762 if (*prop == 0) {
763 *prop = drm_property_create_range(dev,
764 0 /* flags */, name, min, max);
765 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400766 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400767 }
768
769 /* always attach property, if created */
770 if (*prop)
771 drm_object_attach_property(&plane->base, *prop, init);
772 }
773}
774
Clarence Ip5e2a9222016-06-26 22:38:24 -0400775static void _sde_plane_install_rotation_property(struct drm_plane *plane,
776 struct drm_device *dev, struct drm_property **prop)
777{
778 if (plane && dev && prop) {
779 /* only create the property once */
780 if (*prop == 0) {
781 *prop = drm_mode_create_rotation_property(dev,
782 BIT(DRM_REFLECT_X) |
783 BIT(DRM_REFLECT_Y));
784 if (*prop == 0)
785 DRM_ERROR("Create rotation property failed\n");
786 }
787
788 /* always attach property, if created */
789 if (*prop)
790 drm_object_attach_property(&plane->base, *prop, 0);
791 }
792}
793
794static void _sde_plane_install_enum_property(struct drm_plane *plane,
795 struct drm_device *dev, const char *name, int is_bitmask,
796 const struct drm_prop_enum_list *values, int num_values,
797 struct drm_property **prop)
798{
799 if (plane && dev && name && prop && values && num_values) {
800 /* only create the property once */
801 if (*prop == 0) {
802 /* 'bitmask' is a special type of 'enum' */
803 if (is_bitmask)
804 *prop = drm_property_create_bitmask(dev,
805 DRM_MODE_PROP_BITMASK, name,
806 values, num_values, -1);
807 else
808 *prop = drm_property_create_enum(dev,
809 DRM_MODE_PROP_ENUM, name,
810 values, num_values);
811 if (*prop == 0)
812 DRM_ERROR("Create %s property failed\n", name);
813 }
814
815 /* always attach property, if created */
816 if (*prop)
817 drm_object_attach_property(&plane->base, *prop, 0);
818 }
819}
820
Clarence Ipe78efb72016-06-24 18:35:21 -0400821static void _sde_plane_install_blob_property(struct drm_plane *plane,
822 struct drm_device *dev, const char *name,
823 struct drm_property **prop)
824{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400825 if (plane && dev && name && prop) {
826 /* only create the property once */
827 if (*prop == 0) {
828 /* use 'create' for blob property place holder */
829 *prop = drm_property_create(dev,
830 DRM_MODE_PROP_BLOB, name, 0);
831 if (*prop == 0)
832 DRM_ERROR("Create %s property failed\n", name);
833 }
834
835 /* always attach property, if created */
836 if (*prop)
837 drm_object_attach_property(&plane->base, *prop, 0);
838 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400839}
840
Clarence Ip4c1d9772016-06-26 09:35:38 -0400841static int _sde_plane_get_property_index(struct drm_plane *plane,
842 struct drm_property *property)
843{
844 struct drm_property **prop_array;
845 int idx = PLANE_PROP_COUNT;
846
847 if (!plane) {
848 DRM_ERROR("Invalid plane\n");
849 } else if (!plane->dev || !plane->dev->dev_private) {
850 /* don't access dev_private if !dev */
851 DRM_ERROR("Invalid device\n");
852 } else if (!property) {
853 DRM_ERROR("Incoming property is NULL\n");
854 } else {
855 prop_array = ((struct msm_drm_private *)
856 (plane->dev->dev_private))->plane_property;
857 if (!prop_array)
858 /* should never hit this */
859 DRM_ERROR("Invalid property array\n");
860
861 /* linear search is okay */
862 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
863 if (prop_array[idx] == property)
864 break;
865 }
866 }
867
868 return idx;
869}
870
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400871/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400872static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -0400873 struct drm_mode_object *obj,
874 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400875{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400876 static const struct drm_prop_enum_list e_blend_op[] = {
877 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
878 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
879 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
880 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
881 };
882 static const struct drm_prop_enum_list e_src_config[] = {
883 {SDE_DRM_DEINTERLACE, "deinterlace"}
884 };
885 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400886 struct drm_device *dev = plane->dev;
887 struct msm_drm_private *dev_priv = dev->dev_private;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400888
Clarence Ip4ce59322016-06-26 22:27:51 -0400889 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400890
Clarence Ip4c1d9772016-06-26 09:35:38 -0400891 if (!psde || !psde->pipe_sblk || !catalog) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400892 DRM_ERROR("Failed to identify catalog definition\n");
893 return;
894 }
895
896 /* range properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400897 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255, 1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400898 &(dev_priv->plane_property[PLANE_PROP_ZPOS]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400899
Clarence Ip5e2a9222016-06-26 22:38:24 -0400900 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
901 &(dev_priv->plane_property[PLANE_PROP_ALPHA]));
902
Clarence Ip4c1d9772016-06-26 09:35:38 -0400903 /* max range of first pipe will be used */
Clarence Ip5e2a9222016-06-26 22:38:24 -0400904 _sde_plane_install_range_property(plane, dev, "h_decimate",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400905 0, psde->pipe_sblk->maxhdeciexp, 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400906 &(dev_priv->plane_property[PLANE_PROP_H_DECIMATE]));
907
Clarence Ip4c1d9772016-06-26 09:35:38 -0400908 /* max range of first pipe will be used */
Clarence Ip5e2a9222016-06-26 22:38:24 -0400909 _sde_plane_install_range_property(plane, dev, "v_decimate",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400910 0, psde->pipe_sblk->maxvdeciexp, 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400911 &(dev_priv->plane_property[PLANE_PROP_V_DECIMATE]));
912
913 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, 0,
914 &(dev_priv->plane_property[PLANE_PROP_SYNC_FENCE]));
915
916 /* standard properties */
917 _sde_plane_install_rotation_property(plane, dev,
918 &(dev_priv->plane_property[PLANE_PROP_ROTATION]));
919
920 /* enum/bitmask properties */
921 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
922 e_blend_op, ARRAY_SIZE(e_blend_op),
923 &(dev_priv->plane_property[PLANE_PROP_BLEND_OP]));
924 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
925 e_src_config, ARRAY_SIZE(e_src_config),
926 &(dev_priv->plane_property[PLANE_PROP_SRC_CONFIG]));
927
Clarence Ipe78efb72016-06-24 18:35:21 -0400928 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400929 if (psde->features & SDE_SSPP_SCALER)
930 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ip5e2a9222016-06-26 22:38:24 -0400931 &(dev_priv->plane_property[PLANE_PROP_SCALER]));
Clarence Ip4c1d9772016-06-26 09:35:38 -0400932 if (psde->features & BIT(SDE_SSPP_CSC))
933 _sde_plane_install_blob_property(plane, dev, "csc",
934 &(dev_priv->plane_property[PLANE_PROP_CSC]));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400935}
936
937static int sde_plane_atomic_set_property(struct drm_plane *plane,
938 struct drm_plane_state *state, struct drm_property *property,
939 uint64_t val)
940{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400941 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400942 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -0400943 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400944
Clarence Ip4ce59322016-06-26 22:27:51 -0400945 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400946
Clarence Ip4c1d9772016-06-26 09:35:38 -0400947 idx = _sde_plane_get_property_index(plane, property);
948 if (!state) {
949 DRM_ERROR("Invalid state\n");
950 } else if (idx < PLANE_PROP_COUNT) {
951 DBG("Set property %d <= %d", idx, (int)val);
952 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400953
Clarence Ip4c1d9772016-06-26 09:35:38 -0400954 /* extra handling for incoming blob properties */
955 if ((property->flags & DRM_MODE_PROP_BLOB) &&
956 (idx < PLANE_PROP_BLOBCOUNT)) {
957 /* DRM lookup also takes a reference */
958 blob = drm_property_lookup_blob(plane->dev,
959 (uint32_t)val);
960 if (!blob) {
961 DRM_ERROR("Blob not found\n");
962 val = 0;
963 } else {
964 DBG("Blob %u saved", blob->base.id);
965 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400966
Clarence Ip4c1d9772016-06-26 09:35:38 -0400967 /* save blobs for later */
968 pr_blob = &pstate->property_blobs[idx];
969 /* need to clear previous reference */
970 if (*pr_blob)
971 drm_property_unreference_blob(*pr_blob);
972 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -0400973 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400974 }
Clarence Ip4c1d9772016-06-26 09:35:38 -0400975 pstate->property_values[idx] = val;
976 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -0400977 }
978
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400979 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400980}
981
982static int sde_plane_set_property(struct drm_plane *plane,
983 struct drm_property *property, uint64_t val)
984{
985 int rc;
986
Clarence Ip4ce59322016-06-26 22:27:51 -0400987 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -0400988
989 if (!plane)
990 return -EINVAL;
991
Clarence Ip5e2a9222016-06-26 22:38:24 -0400992 rc = sde_plane_atomic_set_property(plane, plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400993 return rc;
994}
995
996static int sde_plane_atomic_get_property(struct drm_plane *plane,
997 const struct drm_plane_state *state,
998 struct drm_property *property, uint64_t *val)
999{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001000 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001001 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001002
Clarence Ip4ce59322016-06-26 22:27:51 -04001003 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001004
Clarence Ip4c1d9772016-06-26 09:35:38 -04001005 idx = _sde_plane_get_property_index(plane, property);
1006 if (!state) {
1007 DRM_ERROR("Invalid state\n");
1008 } else if (!val) {
1009 DRM_ERROR("Value pointer is NULL\n");
1010 } else if (idx < PLANE_PROP_COUNT) {
1011 pstate = to_sde_plane_state(state);
1012
1013 *val = pstate->property_values[idx];
1014 DBG("Get property %d %lld", idx, *val);
1015 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001016 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001017
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001018 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001019}
1020
1021static void sde_plane_destroy(struct drm_plane *plane)
1022{
Clarence Ip4ce59322016-06-26 22:27:51 -04001023 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001024
Clarence Ip4ce59322016-06-26 22:27:51 -04001025 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001026
Clarence Ip4ce59322016-06-26 22:27:51 -04001027 if (plane) {
1028 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001029
Clarence Ip4ce59322016-06-26 22:27:51 -04001030 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001031
Clarence Ip4ce59322016-06-26 22:27:51 -04001032 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001033
Clarence Ip4ce59322016-06-26 22:27:51 -04001034 /* this will destroy the states as well */
1035 drm_plane_cleanup(plane);
1036
Clarence Ip4c1d9772016-06-26 09:35:38 -04001037 if (psde->pipe_hw)
1038 sde_hw_sspp_destroy(psde->pipe_hw);
1039
Clarence Ip4ce59322016-06-26 22:27:51 -04001040 kfree(psde);
1041 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001042}
1043
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001044static void sde_plane_destroy_state(struct drm_plane *plane,
1045 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001046{
Clarence Ipe78efb72016-06-24 18:35:21 -04001047 struct sde_plane_state *pstate;
1048 int i;
1049
Clarence Ip4ce59322016-06-26 22:27:51 -04001050 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -04001051
1052 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001053 if (state->fb)
1054 drm_framebuffer_unreference(state->fb);
1055
Clarence Ipe78efb72016-06-24 18:35:21 -04001056 pstate = to_sde_plane_state(state);
1057
1058 /* remove ref count for blobs */
1059 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1060 if (pstate->property_blobs[i])
1061 drm_property_unreference_blob(
1062 pstate->property_blobs[i]);
1063
1064 kfree(pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001065}
1066
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001067static struct drm_plane_state *
1068sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001069{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001070 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001071 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001072
1073 if (WARN_ON(!plane->state))
1074 return NULL;
1075
Clarence Ip4ce59322016-06-26 22:27:51 -04001076 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001077 pstate = kmemdup(to_sde_plane_state(plane->state),
1078 sizeof(*pstate), GFP_KERNEL);
Clarence Ipe78efb72016-06-24 18:35:21 -04001079 if (pstate) {
1080 /* add ref count for frame buffer */
1081 if (pstate->base.fb)
1082 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001083
Clarence Ipe78efb72016-06-24 18:35:21 -04001084 /* add ref count for blobs */
1085 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1086 if (pstate->property_blobs[i])
1087 drm_property_reference_blob(
1088 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001089
Clarence Ipe78efb72016-06-24 18:35:21 -04001090 pstate->mode_changed = false;
1091 pstate->pending = false;
1092 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001093
Clarence Ipe78efb72016-06-24 18:35:21 -04001094 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001095}
1096
1097static void sde_plane_reset(struct drm_plane *plane)
1098{
1099 struct sde_plane_state *pstate;
1100
Clarence Ip4ce59322016-06-26 22:27:51 -04001101 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001102 if (plane->state && plane->state->fb)
1103 drm_framebuffer_unreference(plane->state->fb);
1104
1105 kfree(to_sde_plane_state(plane->state));
1106 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
1107
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001108 /* assign default blend parameters */
Clarence Ipe78efb72016-06-24 18:35:21 -04001109 pstate->property_values[PLANE_PROP_ALPHA] = 255;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001110
1111 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
Clarence Ipe78efb72016-06-24 18:35:21 -04001112 pstate->property_values[PLANE_PROP_ZPOS] = STAGE_BASE;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001113 else
Clarence Ipe78efb72016-06-24 18:35:21 -04001114 pstate->property_values[PLANE_PROP_ZPOS] =
1115 STAGE0 + drm_plane_index(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001116
1117 pstate->base.plane = plane;
1118
1119 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001120}
1121
1122static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001123 .update_plane = drm_atomic_helper_update_plane,
1124 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001125 .destroy = sde_plane_destroy,
1126 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001127 .atomic_set_property = sde_plane_atomic_set_property,
1128 .atomic_get_property = sde_plane_atomic_get_property,
1129 .reset = sde_plane_reset,
1130 .atomic_duplicate_state = sde_plane_duplicate_state,
1131 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001132};
1133
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001134static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1135 .prepare_fb = sde_plane_prepare_fb,
1136 .cleanup_fb = sde_plane_cleanup_fb,
1137 .atomic_check = sde_plane_atomic_check,
1138 .atomic_update = sde_plane_atomic_update,
1139};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001140
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001141enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001142{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001143 struct sde_plane *sde_plane = to_sde_plane(plane);
1144
1145 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001146}
1147
Clarence Ip4ce59322016-06-26 22:27:51 -04001148static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1149{
1150 const struct sde_sspp_sub_blks *sblk = 0;
1151 const struct sde_sspp_cfg *cfg = 0;
1152
1153 if (psde && psde->pipe_hw)
1154 cfg = psde->pipe_hw->cap;
1155 if (cfg)
1156 sblk = cfg->sblk;
1157
1158 if (kms && sblk) {
1159 /* create overall sub-directory for the pipe */
1160 psde->debugfs_root =
1161 debugfs_create_dir(psde->pipe_name,
1162 sde_debugfs_get_root(kms));
1163 if (psde->debugfs_root) {
1164 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001165 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001166 psde->debugfs_root, &psde->features);
1167
1168 /* add register dump support */
1169 sde_debugfs_setup_regset32(&psde->debugfs_src,
1170 sblk->src_blk.base + cfg->base,
1171 sblk->src_blk.len,
1172 kms->mmio);
1173 sde_debugfs_create_regset32("src_blk", 0444,
1174 psde->debugfs_root, &psde->debugfs_src);
1175
1176 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1177 sblk->scaler_blk.base + cfg->base,
1178 sblk->scaler_blk.len,
1179 kms->mmio);
1180 sde_debugfs_create_regset32("scaler_blk", 0444,
1181 psde->debugfs_root,
1182 &psde->debugfs_scaler);
1183
1184 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1185 sblk->csc_blk.base + cfg->base,
1186 sblk->csc_blk.len,
1187 kms->mmio);
1188 sde_debugfs_create_regset32("csc_blk", 0444,
1189 psde->debugfs_root, &psde->debugfs_csc);
1190 }
1191 }
1192}
1193
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001194/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001195struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001196 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001197{
1198 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001199 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001200 struct msm_drm_private *priv;
1201 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001202 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001203 int ret = -EINVAL;
1204
1205 if (!dev) {
1206 DRM_ERROR("[%u]Device is NULL\n", pipe);
1207 goto exit;
1208 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001209
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001210 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001211 if (!priv) {
1212 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1213 goto exit;
1214 }
1215
1216 if (!priv->kms) {
1217 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1218 goto exit;
1219 }
1220 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001221
Clarence Ip4c1d9772016-06-26 09:35:38 -04001222 if (!kms->catalog) {
1223 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1224 goto exit;
1225 }
1226
Clarence Ip4ce59322016-06-26 22:27:51 -04001227 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001228 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1229 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001230 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001231 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001232 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001233 }
1234
Clarence Ip4c1d9772016-06-26 09:35:38 -04001235 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001236 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001237 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001238 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001239
Clarence Ip4c1d9772016-06-26 09:35:38 -04001240 /* initialize underlying h/w driver */
1241 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1242 if (IS_ERR(psde->pipe_hw)) {
1243 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1244 ret = PTR_ERR(psde->pipe_hw);
1245 goto clean_plane;
1246 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1247 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1248 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001249 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001250
1251 /* cache features mask for later */
1252 psde->features = psde->pipe_hw->cap->features;
1253 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1254
1255 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001256 psde->nformats = mdp_get_formats(psde->formats,
1257 ARRAY_SIZE(psde->formats),
1258 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001259 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001260
Clarence Ip4c1d9772016-06-26 09:35:38 -04001261 if (!psde->nformats) {
1262 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1263 goto clean_sspp;
1264 }
1265
1266 if (psde->features & BIT(SDE_SSPP_CURSOR))
1267 type = DRM_PLANE_TYPE_CURSOR;
1268 else if (primary_plane)
1269 type = DRM_PLANE_TYPE_PRIMARY;
1270 else
1271 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001272 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1273 psde->formats, psde->nformats,
1274 type);
1275 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001276 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001277
Clarence Ip4c1d9772016-06-26 09:35:38 -04001278 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001279 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001280
Clarence Ip4c1d9772016-06-26 09:35:38 -04001281 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001282
Clarence Ip4ce59322016-06-26 22:27:51 -04001283 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001284 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001285
1286 _sde_plane_init_debugfs(psde, kms);
1287
Clarence Ip4c1d9772016-06-26 09:35:38 -04001288 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001289 return plane;
1290
Clarence Ip4c1d9772016-06-26 09:35:38 -04001291clean_sspp:
1292 if (psde && psde->pipe_hw)
1293 sde_hw_sspp_destroy(psde->pipe_hw);
1294clean_plane:
1295 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001296exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001297 return ERR_PTR(ret);
1298}