blob: be0181a4c2ca017014a8dd2c2fae1ed387c07978 [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 Ipae4e60c2016-06-26 22:44:04 -040015#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040016#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040017#include "sde_hw_sspp.h"
18
19#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
20#define PHASE_STEP_SHIFT 21
21#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
22#define PHASE_RESIDUAL 15
23
Clarence Ipe78efb72016-06-24 18:35:21 -040024#define SHARP_STRENGTH_DEFAULT 32
25#define SHARP_EDGE_THR_DEFAULT 112
26#define SHARP_SMOOTH_THR_DEFAULT 8
27#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040028
Clarence Ip5e2a9222016-06-26 22:38:24 -040029#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070030
31struct sde_plane {
32 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040033
34 int mmu_id;
35
36 enum sde_sspp pipe;
37 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070038 uint32_t nformats;
39 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040040
41 struct sde_hw_pipe *pipe_hw;
42 struct sde_hw_pipe_cfg pipe_cfg;
43 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040044 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040045 struct sde_hw_scaler3_cfg scaler3_cfg;
Clarence Ip4ce59322016-06-26 22:27:51 -040046
Clarence Ip373f8592016-05-26 00:58:42 -040047 struct sde_csc_cfg csc_cfg;
48 struct sde_csc_cfg *csc_ptr;
49
Clarence Ip4c1d9772016-06-26 09:35:38 -040050 const struct sde_sspp_sub_blks *pipe_sblk;
51
Clarence Ip5e2a9222016-06-26 22:38:24 -040052 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040053
Clarence Ipae4e60c2016-06-26 22:44:04 -040054 /* cache property default values (for reset) */
55 uint64_t property_defaults[PLANE_PROP_COUNT];
56
Clarence Ip4ce59322016-06-26 22:27:51 -040057 /* debugfs related stuff */
58 struct dentry *debugfs_root;
59 struct sde_debugfs_regset32 debugfs_src;
60 struct sde_debugfs_regset32 debugfs_scaler;
61 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070062};
63#define to_sde_plane(x) container_of(x, struct sde_plane, base)
64
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040065static bool sde_plane_enabled(struct drm_plane_state *state)
66{
67 return state->fb && state->crtc;
68}
69
Clarence Ipae4e60c2016-06-26 22:44:04 -040070/* helper to update a state's sync fence pointer from the property */
71static void _sde_plane_update_sync_fence(struct drm_plane *plane,
72 struct sde_plane_state *pstate, uint64_t fd)
73{
74 if (!plane || !pstate)
75 return;
76
77 /* clear previous reference */
78 if (pstate->sync_fence)
79 sde_sync_put(pstate->sync_fence);
80
81 /* get fence pointer for later */
82 pstate->sync_fence = sde_sync_get(fd);
83
84 DBG("0x%llX", fd);
85}
86
87void *sde_plane_get_sync_fence(struct drm_plane *plane)
88{
89 struct sde_plane_state *pstate;
90 void *ret = NULL;
91
92 if (!plane) {
93 DRM_ERROR("Invalid plane\n");
94 } else if (!plane->state) {
95 DRM_ERROR("Invalid plane state\n");
96 } else {
97 pstate = to_sde_plane_state(plane->state);
98 ret = pstate->sync_fence;
99
100 DBG("%s", to_sde_plane(plane)->pipe_name);
101 }
102
103 return ret;
104}
105
Clarence Ipe78efb72016-06-24 18:35:21 -0400106static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400107 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400108 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
109{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400110 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400111 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400112 int i;
113
Clarence Ipae4e60c2016-06-26 22:44:04 -0400114 if (!plane || !pstate || !pipe_cfg || !fb)
115 return;
116
117 psde = to_sde_plane(plane);
118
119 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400120 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400121 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400122 BIT(SDE_DRM_DEINTERLACE))
123 shift = 1;
124 else
125 shift = 0;
126
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400127 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
128 while (i) {
129 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400130 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400131 }
132
133 /* address */
134 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
135 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
136 psde->mmu_id, i);
137
138 /* hw driver */
139 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
140 }
141}
142
Clarence Ip5e2a9222016-06-26 22:38:24 -0400143static void _sde_plane_setup_scaler3(struct drm_plane *plane,
144 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
145 struct sde_hw_scaler3_cfg *scale_cfg,
146 struct sde_mdp_format_params *fmt,
147 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
148{
149}
150
151static void _sde_plane_setup_scaler2(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400152 uint32_t src, uint32_t dst, uint32_t *phase_steps,
153 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
154 uint32_t chroma_subsampling)
155{
Clarence Ip4c1d9772016-06-26 09:35:38 -0400156 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400157 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400158 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400159 phase_steps[SDE_SSPP_COMP_1_2] =
160 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
161 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
162 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400163
164 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -0400165 if (fmt->is_yuv || src != dst) {
166 filter[SDE_SSPP_COMP_3] =
167 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
168 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400169
Clarence Ipe78efb72016-06-24 18:35:21 -0400170 if (fmt->is_yuv) {
171 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
172 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
173 } else {
174 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
175 filter[SDE_SSPP_COMP_1_2] =
176 SDE_MDP_SCALE_FILTER_NEAREST;
177 }
178 } else {
179 /* disable scaler */
180 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
181 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
182 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400183 }
184}
185
Clarence Ipe78efb72016-06-24 18:35:21 -0400186static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400187 uint32_t src, uint32_t dst, uint32_t decimated_src,
188 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400189 int *out_edge2, enum sde_hw_filter *filter,
190 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
191 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400192{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400193 int64_t edge1, edge2, caf;
194 uint32_t src_work;
195 int i, tmp;
196
Clarence Ipe78efb72016-06-24 18:35:21 -0400197 if (plane && phase_steps && out_src && out_edge1 &&
198 out_edge2 && filter && fmt) {
199 /* handle CAF for YUV formats */
200 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400201 caf = PHASE_STEP_UNIT_SCALE;
202 else
203 caf = 0;
204
205 for (i = 0; i < SDE_MAX_PLANES; i++) {
206 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400207 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400208 src_work /= chroma_subsampling;
209 if (post_compare)
210 src = src_work;
211 if (!(fmt->is_yuv) && (src == dst)) {
212 /* unity */
213 edge1 = 0;
214 edge2 = 0;
215 } else if (dst >= src) {
216 /* upscale */
217 edge1 = (1 << PHASE_RESIDUAL);
218 edge1 -= caf;
219 edge2 = (1 << PHASE_RESIDUAL);
220 edge2 += (dst - 1) * *(phase_steps + i);
221 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
222 edge2 += caf;
223 edge2 = -(edge2);
224 } else {
225 /* downscale */
226 edge1 = 0;
227 edge2 = (dst - 1) * *(phase_steps + i);
228 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
229 edge2 += *(phase_steps + i);
230 edge2 = -(edge2);
231 }
232
233 /* only enable CAF for luma plane */
234 caf = 0;
235
236 /* populate output arrays */
237 *(out_src + i) = src_work;
238
239 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400240 if (edge1 >= 0) {
241 tmp = (uint32_t)edge1;
242 tmp >>= PHASE_STEP_SHIFT;
243 *(out_edge1 + i) = -tmp;
244 } else {
245 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400246 *(out_edge1 + i) =
247 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
248 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400249 }
250 if (edge2 >= 0) {
251 tmp = (uint32_t)edge2;
252 tmp >>= PHASE_STEP_SHIFT;
253 *(out_edge2 + i) = -tmp;
254 } else {
255 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400256 *(out_edge2 + i) =
257 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
258 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400259 }
260 }
261 }
262}
263
Clarence Ip5e2a9222016-06-26 22:38:24 -0400264static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
265 enum msm_mdp_plane_property property, size_t *byte_len)
266{
267 struct drm_property_blob *blob;
268 size_t len = 0;
269 void *ret = 0;
270
Clarence Ip4c1d9772016-06-26 09:35:38 -0400271 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
272 DRM_ERROR("Invalid argument(s)\n");
273 } else {
274 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400275 if (blob) {
276 len = blob->length;
277 ret = &blob->data;
278 }
279 }
280
281 if (byte_len)
282 *byte_len = len;
283
284 return ret;
285}
286
287/**
288 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
289 * sub-structure
290 * @blob_ptr: Pointer to start of incoming blob data
291 * @blob_size: Size of incoming blob data, in bytes
292 * @sub_ptr: Pointer to start of desired sub-structure
293 * @sub_size: Required size of sub-structure, in bytes
294 */
295static int _sde_plane_verify_blob(void *blob_ptr,
296 size_t blob_size,
297 void *sub_ptr,
298 size_t sub_size)
299{
300 /*
301 * Use the blob size provided by drm to check if there are enough
302 * bytes from the start of versioned sub-structures to the end of
303 * blob data:
304 *
305 * e.g.,
306 * blob_ptr --> struct blob_data {
307 * uint32_t version;
308 * sub_ptr --> struct blob_data_v1 v1;
309 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
310 * blob_ptr + blob_size --> };
311 *
312 * It's important to check the actual number of bytes from the start
313 * of the sub-structure to the end of the blob data, and not just rely
314 * on something like,
315 *
316 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
317 *
318 * This is because the start of the sub-structure can vary based on
319 * how the compiler pads the overall structure.
320 */
321 if (blob_ptr && sub_ptr)
322 /* return zero if end of blob >= end of sub-struct */
323 return ((unsigned char *)blob_ptr + blob_size) <
324 ((unsigned char *)sub_ptr + sub_size);
325 return -EINVAL;
326}
327
Clarence Ipe78efb72016-06-24 18:35:21 -0400328static void _sde_plane_setup_csc(struct sde_plane *psde,
329 struct sde_plane_state *pstate,
330 struct sde_mdp_format_params *fmt)
331{
332 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
333 {
Clarence Ip373f8592016-05-26 00:58:42 -0400334 /* S15.16 format */
335 0x00012A00, 0x00000000, 0x00019880,
336 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
337 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400338 },
Clarence Ip373f8592016-05-26 00:58:42 -0400339 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400340 { 0xfff0, 0xff80, 0xff80,},
341 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400342 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400343 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400344 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400345 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400346 static const struct sde_csc_cfg sde_csc_NOP = {
347 {
Clarence Ip373f8592016-05-26 00:58:42 -0400348 /* identity matrix, S15.16 format */
349 0x10000, 0x00000, 0x00000,
350 0x00000, 0x10000, 0x00000,
351 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400352 },
Clarence Ip373f8592016-05-26 00:58:42 -0400353 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400354 { 0x0, 0x0, 0x0,},
355 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400356 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400357 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
358 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
359 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400360 struct sde_drm_csc *csc = NULL;
361 size_t csc_size = 0;
362 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400363
364 if (!psde->pipe_hw->ops.setup_csc)
365 return;
366
Clarence Ip5e2a9222016-06-26 22:38:24 -0400367 /* check for user space override */
368 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
369 if (csc) {
370 struct sde_csc_cfg cfg;
371 int i;
372
373 /* user space override */
374 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
375 switch (csc->version) {
376 case SDE_DRM_CSC_V1:
377 if (!_sde_plane_verify_blob(csc,
378 csc_size,
379 &csc->v1,
380 sizeof(struct sde_drm_csc_v1))) {
381 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
382 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400383 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400384 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
385 cfg.csc_pre_bv[i] =
386 csc->v1.pre_bias[i];
387 cfg.csc_post_bv[i] =
388 csc->v1.post_bias[i];
389 }
390 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
391 cfg.csc_pre_lv[i] =
392 csc->v1.pre_clamp[i];
393 cfg.csc_post_lv[i] =
394 csc->v1.post_clamp[i];
395 }
396 user_blob = true;
397 }
398 break;
399 default:
400 break;
401 }
402
403 if (!user_blob)
404 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
405 else
406 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
407 (struct sde_csc_cfg *)&cfg);
408 }
409
410 if (user_blob) {
411 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400412 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400413 /* revert to kernel default */
414 } else if (fmt->is_yuv) {
Clarence Ip373f8592016-05-26 00:58:42 -0400415 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400416 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400417 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400418 }
Clarence Ip373f8592016-05-26 00:58:42 -0400419
420 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400421}
422
423static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700424 struct drm_crtc *crtc, struct drm_framebuffer *fb,
425 int crtc_x, int crtc_y,
426 unsigned int crtc_w, unsigned int crtc_h,
427 uint32_t src_x, uint32_t src_y,
428 uint32_t src_w, uint32_t src_h)
429{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400430 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400431 struct sde_plane_state *pstate;
432 const struct mdp_format *format;
433 uint32_t nplanes, pix_format, tmp;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400434 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
435 uint32_t src_fmt_flags;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400436 int i;
437 struct sde_mdp_format_params *fmt;
438 struct sde_hw_pixel_ext *pe;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400439 size_t sc_u_size = 0;
440 struct sde_drm_scaler *sc_u = NULL;
441 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400442
Clarence Ip4ce59322016-06-26 22:27:51 -0400443 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400444
Clarence Ip5e2a9222016-06-26 22:38:24 -0400445 if (!plane || !plane->state) {
446 DRM_ERROR("Invalid plane/state\n");
447 return -EINVAL;
448 }
449 if (!crtc || !fb) {
450 DRM_ERROR("Invalid crtc/fb\n");
451 return -EINVAL;
452 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400453
Clarence Ip5e2a9222016-06-26 22:38:24 -0400454 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400455 pstate = to_sde_plane_state(plane->state);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400456 nplanes = drm_format_num_planes(fb->pixel_format);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400457
458 format = to_mdp_format(msm_framebuffer_format(fb));
459 pix_format = format->base.pixel_format;
460
461 /* src values are in Q16 fixed point, convert to integer */
462 src_x = src_x >> 16;
463 src_y = src_y >> 16;
464 src_w = src_w >> 16;
465 src_h = src_h >> 16;
466
Clarence Ip4ce59322016-06-26 22:27:51 -0400467 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400468 fb->base.id, src_x, src_y, src_w, src_h,
469 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
470
471 /* update format configuration */
472 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400473 src_fmt_flags = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400474
475 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400476 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400477 psde->pipe_cfg.src.width = fb->width;
478 psde->pipe_cfg.src.height = fb->height;
479 psde->pipe_cfg.src.num_planes = nplanes;
480
Clarence Ip5e2a9222016-06-26 22:38:24 -0400481 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
482
Clarence Ip5e2a9222016-06-26 22:38:24 -0400483 /* flags */
484 DBG("Flags 0x%llX, rotation 0x%llX",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400485 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
486 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
487 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400488 BIT(DRM_REFLECT_X))
489 src_fmt_flags |= SDE_SSPP_FLIP_LR;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400490 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400491 BIT(DRM_REFLECT_Y))
492 src_fmt_flags |= SDE_SSPP_FLIP_UD;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400493 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400494 BIT(SDE_DRM_DEINTERLACE)) {
495 src_h /= 2;
496 src_y = DIV_ROUND_UP(src_y, 2);
497 src_y &= ~0x1;
498 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400499
500 psde->pipe_cfg.src_rect.x = src_x;
501 psde->pipe_cfg.src_rect.y = src_y;
502 psde->pipe_cfg.src_rect.w = src_w;
503 psde->pipe_cfg.src_rect.h = src_h;
504
505 psde->pipe_cfg.dst_rect.x = crtc_x;
506 psde->pipe_cfg.dst_rect.y = crtc_y;
507 psde->pipe_cfg.dst_rect.w = crtc_w;
508 psde->pipe_cfg.dst_rect.h = crtc_h;
509
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400510 /* get sde pixel format definition */
511 fmt = psde->pipe_cfg.src.format;
512
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400513 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400514 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400515
Clarence Ip5e2a9222016-06-26 22:38:24 -0400516 /* get scaler config from user space */
517 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
518 if (sc_u) {
519 switch (sc_u->version) {
520 case SDE_DRM_SCALER_V1:
521 if (!_sde_plane_verify_blob(sc_u,
522 sc_u_size,
523 &sc_u->v1,
524 sizeof(*sc_u1)))
525 sc_u1 = &sc_u->v1;
526 break;
527 default:
528 DBG("Unrecognized scaler blob v%lld", sc_u->version);
529 break;
530 }
531 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400532
Clarence Ip04ec67d2016-05-26 01:16:15 -0400533 /* decimation */
534 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
535 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
536 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
537 }
538
539 /* don't chroma subsample if decimating */
540 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
541 drm_format_horz_chroma_subsampling(pix_format);
542 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
543 drm_format_vert_chroma_subsampling(pix_format);
544
Clarence Ip5e2a9222016-06-26 22:38:24 -0400545 /* update scaler */
546 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
547 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
548 DBG("QSEED3 blob detected");
549 else
550 _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
551 crtc_h, &psde->scaler3_cfg, fmt,
552 chroma_subsmpl_h, chroma_subsmpl_v);
553 } else {
554 /* always calculate basic scaler config */
555 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
556 /* populate from user space */
557 for (i = 0; i < SDE_MAX_PLANES; i++) {
558 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
559 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
560 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
561 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400562
Clarence Ip5e2a9222016-06-26 22:38:24 -0400563 pe->horz_filter[i] = sc_u1->horz_filter[i];
564 pe->vert_filter[i] = sc_u1->vert_filter[i];
565 }
566 } else {
567 /* calculate phase steps */
568 _sde_plane_setup_scaler2(plane, src_w, crtc_w,
569 pe->phase_step_x,
570 pe->horz_filter, fmt, chroma_subsmpl_h);
571 _sde_plane_setup_scaler2(plane, src_h, crtc_h,
572 pe->phase_step_y,
573 pe->vert_filter, fmt, chroma_subsmpl_v);
574 }
575 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400576
Clarence Ip5e2a9222016-06-26 22:38:24 -0400577 /* update pixel extensions */
578 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
579 /* populate from user space */
580 for (i = 0; i < SDE_MAX_PLANES; i++) {
581 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
582 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
583 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
584 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
585 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
586 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
587 pe->roi_w[i] = sc_u1->lr.roi[i];
588
589 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
590 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
591 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
592 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
593 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
594 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
595 pe->roi_h[i] = sc_u1->tb.roi[i];
596 }
597 } else {
598 /* calculate left/right/top/bottom pixel extensions */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400599 tmp = DECIMATED_DIMENSION(src_w,
600 psde->pipe_cfg.horz_decimation);
601 if (fmt->is_yuv)
602 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400603 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400604 pe->phase_step_x,
605 pe->roi_w,
606 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400607 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400608 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400609
610 tmp = DECIMATED_DIMENSION(src_h,
611 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400612 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400613 pe->phase_step_y,
614 pe->roi_h,
615 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400616 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400617 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400618
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400619 for (i = 0; i < SDE_MAX_PLANES; i++) {
620 if (pe->num_ext_pxls_left[i] >= 0)
621 pe->left_rpt[i] =
622 pe->num_ext_pxls_left[i];
623 else
624 pe->left_ftch[i] =
625 pe->num_ext_pxls_left[i];
626
627 if (pe->num_ext_pxls_right[i] >= 0)
628 pe->right_rpt[i] =
629 pe->num_ext_pxls_right[i];
630 else
631 pe->right_ftch[i] =
632 pe->num_ext_pxls_right[i];
633
634 if (pe->num_ext_pxls_top[i] >= 0)
635 pe->top_rpt[i] =
636 pe->num_ext_pxls_top[i];
637 else
638 pe->top_ftch[i] =
639 pe->num_ext_pxls_top[i];
640
641 if (pe->num_ext_pxls_btm[i] >= 0)
642 pe->btm_rpt[i] =
643 pe->num_ext_pxls_btm[i];
644 else
645 pe->btm_ftch[i] =
646 pe->num_ext_pxls_btm[i];
647 }
648 }
649
Clarence Ip4c1d9772016-06-26 09:35:38 -0400650 if (psde->pipe_hw->ops.setup_format)
651 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400652 &psde->pipe_cfg, src_fmt_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400653 if (psde->pipe_hw->ops.setup_rects)
654 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
655 &psde->pipe_cfg, &psde->pixel_ext);
656
Clarence Ipe78efb72016-06-24 18:35:21 -0400657 /* update sharpening */
658 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
659 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
660 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
661 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
662
663 if (psde->pipe_hw->ops.setup_sharpening)
664 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
665 &psde->sharp_cfg);
666
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400667 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400668 if (fmt->is_yuv)
669 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400670
Clarence Ip5e2a9222016-06-26 22:38:24 -0400671 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400672}
673
674static int sde_plane_prepare_fb(struct drm_plane *plane,
675 const struct drm_plane_state *new_state)
676{
677 struct drm_framebuffer *fb = new_state->fb;
678 struct sde_plane *psde = to_sde_plane(plane);
679
680 if (!new_state->fb)
681 return 0;
682
Clarence Ipae4e60c2016-06-26 22:44:04 -0400683 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400684 return msm_framebuffer_prepare(fb, psde->mmu_id);
685}
686
687static void sde_plane_cleanup_fb(struct drm_plane *plane,
688 const struct drm_plane_state *old_state)
689{
690 struct drm_framebuffer *fb = old_state->fb;
691 struct sde_plane *psde = to_sde_plane(plane);
692
693 if (!fb)
694 return;
695
Clarence Ipae4e60c2016-06-26 22:44:04 -0400696 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400697 msm_framebuffer_cleanup(fb, psde->mmu_id);
698}
699
700static int sde_plane_atomic_check(struct drm_plane *plane,
701 struct drm_plane_state *state)
702{
703 struct sde_plane *psde = to_sde_plane(plane);
704 struct drm_plane_state *old_state = plane->state;
705 const struct mdp_format *format;
706
Clarence Ip4ce59322016-06-26 22:27:51 -0400707 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400708 sde_plane_enabled(old_state), sde_plane_enabled(state));
709
710 if (sde_plane_enabled(state)) {
711 /* CIFIX: don't use mdp format? */
712 format = to_mdp_format(msm_framebuffer_format(state->fb));
713 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400714 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400715 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400716 DRM_ERROR("Pipe doesn't support YUV\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400717
718 return -EINVAL;
719 }
720
Clarence Ipe78efb72016-06-24 18:35:21 -0400721 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400722 (((state->src_w >> 16) != state->crtc_w) ||
723 ((state->src_h >> 16) != state->crtc_h))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400724 DRM_ERROR(
725 "Unsupported Pipe scaling (%dx%d -> %dx%d)\n",
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400726 state->src_w >> 16, state->src_h >> 16,
727 state->crtc_w, state->crtc_h);
728
729 return -EINVAL;
730 }
731 }
732
733 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
734 /* we cannot change SMP block configuration during scanout: */
735 bool full_modeset = false;
736
737 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400738 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400739 full_modeset = true;
740 }
741 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400742 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400743 full_modeset = true;
744 }
745 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400746 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400747 full_modeset = true;
748 }
749 if (full_modeset) {
750 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400751 drm_atomic_get_crtc_state(state->state,
752 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400753 crtc_state->mode_changed = true;
754 to_sde_plane_state(state)->mode_changed = true;
755 }
756 } else {
757 to_sde_plane_state(state)->mode_changed = true;
758 }
759
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700760 return 0;
761}
762
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400763static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400764 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700765{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400766 struct sde_plane *sde_plane;
767 struct drm_plane_state *state;
768 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400769
Clarence Ip5e2a9222016-06-26 22:38:24 -0400770 if (!plane || !plane->state) {
771 DRM_ERROR("Invalid plane/state\n");
772 return;
773 }
774
775 sde_plane = to_sde_plane(plane);
776 state = plane->state;
777 pstate = to_sde_plane_state(state);
778
Clarence Ipae4e60c2016-06-26 22:44:04 -0400779 DBG("%s: update", sde_plane->pipe_name);
780
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400781 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400782 pstate->pending = true;
783 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400784 int ret;
785
Clarence Ip5e2a9222016-06-26 22:38:24 -0400786 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400787 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400788 state->crtc, state->fb,
789 state->crtc_x, state->crtc_y,
790 state->crtc_w, state->crtc_h,
791 state->src_x, state->src_y,
792 state->src_w, state->src_h);
793 /* atomic_check should have ensured that this doesn't fail */
794 WARN_ON(ret < 0);
795 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400796 _sde_plane_set_scanout(plane, pstate,
797 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400798 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400799}
800
Clarence Ipae4e60c2016-06-26 22:44:04 -0400801static inline struct drm_property **_sde_plane_get_property_entry(
802 struct drm_device *dev, enum msm_mdp_plane_property property)
803{
804 struct msm_drm_private *priv;
805
806 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
807 return NULL;
808
809 priv = dev->dev_private;
810
811 return &(priv->plane_property[property]);
812}
813
Clarence Ipe78efb72016-06-24 18:35:21 -0400814static void _sde_plane_install_range_property(struct drm_plane *plane,
815 struct drm_device *dev, const char *name,
816 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400817 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -0400818{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400819 struct drm_property **prop;
820
821 prop = _sde_plane_get_property_entry(dev, property);
822 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400823 /* only create the property once */
824 if (*prop == 0) {
825 *prop = drm_property_create_range(dev,
826 0 /* flags */, name, min, max);
827 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400828 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400829 }
830
Clarence Ipae4e60c2016-06-26 22:44:04 -0400831 /* save init value for later */
832 to_sde_plane(plane)->property_defaults[property] = init;
833
Clarence Ipe78efb72016-06-24 18:35:21 -0400834 /* always attach property, if created */
835 if (*prop)
836 drm_object_attach_property(&plane->base, *prop, init);
837 }
838}
839
Clarence Ip5e2a9222016-06-26 22:38:24 -0400840static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400841 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400842{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400843 struct sde_plane *psde;
844 struct drm_property **prop;
845
846 prop = _sde_plane_get_property_entry(dev, property);
847 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400848 /* only create the property once */
849 if (*prop == 0) {
850 *prop = drm_mode_create_rotation_property(dev,
851 BIT(DRM_REFLECT_X) |
852 BIT(DRM_REFLECT_Y));
853 if (*prop == 0)
854 DRM_ERROR("Create rotation property failed\n");
855 }
856
Clarence Ipae4e60c2016-06-26 22:44:04 -0400857 /* save init value for later */
858 psde = to_sde_plane(plane);
859 psde->property_defaults[property] = 0;
860
Clarence Ip5e2a9222016-06-26 22:38:24 -0400861 /* always attach property, if created */
862 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400863 drm_object_attach_property(&plane->base, *prop,
864 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400865 }
866}
867
868static void _sde_plane_install_enum_property(struct drm_plane *plane,
869 struct drm_device *dev, const char *name, int is_bitmask,
870 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400871 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400872{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400873 struct sde_plane *psde;
874 struct drm_property **prop;
875
876 prop = _sde_plane_get_property_entry(dev, property);
877 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400878 /* only create the property once */
879 if (*prop == 0) {
880 /* 'bitmask' is a special type of 'enum' */
881 if (is_bitmask)
882 *prop = drm_property_create_bitmask(dev,
883 DRM_MODE_PROP_BITMASK, name,
884 values, num_values, -1);
885 else
886 *prop = drm_property_create_enum(dev,
887 DRM_MODE_PROP_ENUM, name,
888 values, num_values);
889 if (*prop == 0)
890 DRM_ERROR("Create %s property failed\n", name);
891 }
892
Clarence Ipae4e60c2016-06-26 22:44:04 -0400893 /* save init value for later */
894 psde = to_sde_plane(plane);
895 psde->property_defaults[property] = 0;
896
Clarence Ip5e2a9222016-06-26 22:38:24 -0400897 /* always attach property, if created */
898 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400899 drm_object_attach_property(&plane->base, *prop,
900 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400901 }
902}
903
Clarence Ipe78efb72016-06-24 18:35:21 -0400904static void _sde_plane_install_blob_property(struct drm_plane *plane,
905 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400906 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -0400907{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400908 struct sde_plane *psde;
909 struct drm_property **prop;
910
911 prop = _sde_plane_get_property_entry(dev, property);
912 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400913 /* only create the property once */
914 if (*prop == 0) {
915 /* use 'create' for blob property place holder */
916 *prop = drm_property_create(dev,
917 DRM_MODE_PROP_BLOB, name, 0);
918 if (*prop == 0)
919 DRM_ERROR("Create %s property failed\n", name);
920 }
921
Clarence Ipae4e60c2016-06-26 22:44:04 -0400922 /* save init value for later */
923 psde = to_sde_plane(plane);
924 psde->property_defaults[property] = 0;
925
Clarence Ip5e2a9222016-06-26 22:38:24 -0400926 /* always attach property, if created */
927 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400928 drm_object_attach_property(&plane->base, *prop,
929 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400930 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400931}
932
Clarence Ip4c1d9772016-06-26 09:35:38 -0400933static int _sde_plane_get_property_index(struct drm_plane *plane,
934 struct drm_property *property)
935{
936 struct drm_property **prop_array;
937 int idx = PLANE_PROP_COUNT;
938
939 if (!plane) {
940 DRM_ERROR("Invalid plane\n");
941 } else if (!plane->dev || !plane->dev->dev_private) {
942 /* don't access dev_private if !dev */
943 DRM_ERROR("Invalid device\n");
944 } else if (!property) {
945 DRM_ERROR("Incoming property is NULL\n");
946 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -0400947 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -0400948 if (!prop_array)
949 /* should never hit this */
950 DRM_ERROR("Invalid property array\n");
951
952 /* linear search is okay */
953 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
954 if (prop_array[idx] == property)
955 break;
956 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400957
958 if (idx == PLANE_PROP_COUNT)
959 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -0400960 }
961
962 return idx;
963}
964
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400965/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400966static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -0400967 struct drm_mode_object *obj,
968 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400969{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400970 static const struct drm_prop_enum_list e_blend_op[] = {
971 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
972 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
973 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
974 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
975 };
976 static const struct drm_prop_enum_list e_src_config[] = {
977 {SDE_DRM_DEINTERLACE, "deinterlace"}
978 };
979 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400980 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400981
Clarence Ip4ce59322016-06-26 22:27:51 -0400982 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400983
Clarence Ip4c1d9772016-06-26 09:35:38 -0400984 if (!psde || !psde->pipe_sblk || !catalog) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400985 DRM_ERROR("Failed to identify catalog definition\n");
986 return;
987 }
988
989 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -0400990 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
991 plane->type == DRM_PLANE_TYPE_PRIMARY ?
992 STAGE_BASE : STAGE0 + drm_plane_index(plane),
993 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400994
Clarence Ip5e2a9222016-06-26 22:38:24 -0400995 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400996 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400997
Clarence Ipae4e60c2016-06-26 22:44:04 -0400998 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
999 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001000
1001 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001002 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001003
Clarence Ip04ec67d2016-05-26 01:16:15 -04001004 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001005 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1006 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001007 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001008 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1009 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001010 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001011
Clarence Ipe78efb72016-06-24 18:35:21 -04001012 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001013 if (psde->features & SDE_SSPP_SCALER)
1014 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001015 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001016 if (psde->features & BIT(SDE_SSPP_CSC))
1017 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001018 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001019}
1020
1021static int sde_plane_atomic_set_property(struct drm_plane *plane,
1022 struct drm_plane_state *state, struct drm_property *property,
1023 uint64_t val)
1024{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001025 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001026 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001027 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001028
Clarence Ip4ce59322016-06-26 22:27:51 -04001029 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001030
Clarence Ip4c1d9772016-06-26 09:35:38 -04001031 idx = _sde_plane_get_property_index(plane, property);
1032 if (!state) {
1033 DRM_ERROR("Invalid state\n");
1034 } else if (idx < PLANE_PROP_COUNT) {
1035 DBG("Set property %d <= %d", idx, (int)val);
1036 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001037
Clarence Ipae4e60c2016-06-26 22:44:04 -04001038 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001039 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1040 (idx < PLANE_PROP_BLOBCOUNT)) {
1041 /* DRM lookup also takes a reference */
1042 blob = drm_property_lookup_blob(plane->dev,
1043 (uint32_t)val);
1044 if (!blob) {
1045 DRM_ERROR("Blob not found\n");
1046 val = 0;
1047 } else {
1048 DBG("Blob %u saved", blob->base.id);
1049 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001050
Clarence Ip4c1d9772016-06-26 09:35:38 -04001051 /* save blobs for later */
1052 pr_blob = &pstate->property_blobs[idx];
1053 /* need to clear previous reference */
1054 if (*pr_blob)
1055 drm_property_unreference_blob(*pr_blob);
1056 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001057 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001058 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1059 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001060 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001061 pstate->property_values[idx] = val;
1062 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001063 }
1064
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001065 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001066}
1067
1068static int sde_plane_set_property(struct drm_plane *plane,
1069 struct drm_property *property, uint64_t val)
1070{
Clarence Ip4ce59322016-06-26 22:27:51 -04001071 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001072
1073 if (!plane)
1074 return -EINVAL;
1075
Clarence Ipae4e60c2016-06-26 22:44:04 -04001076 return sde_plane_atomic_set_property(plane,
1077 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001078}
1079
1080static int sde_plane_atomic_get_property(struct drm_plane *plane,
1081 const struct drm_plane_state *state,
1082 struct drm_property *property, uint64_t *val)
1083{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001084 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001085 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001086
Clarence Ip4c1d9772016-06-26 09:35:38 -04001087 idx = _sde_plane_get_property_index(plane, property);
1088 if (!state) {
1089 DRM_ERROR("Invalid state\n");
1090 } else if (!val) {
1091 DRM_ERROR("Value pointer is NULL\n");
1092 } else if (idx < PLANE_PROP_COUNT) {
1093 pstate = to_sde_plane_state(state);
1094
1095 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001096 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001097 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001098 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001099
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001100 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001101}
1102
1103static void sde_plane_destroy(struct drm_plane *plane)
1104{
Clarence Ip4ce59322016-06-26 22:27:51 -04001105 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001106
Clarence Ip4ce59322016-06-26 22:27:51 -04001107 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001108
Clarence Ip4ce59322016-06-26 22:27:51 -04001109 if (plane) {
1110 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001111
Clarence Ip4ce59322016-06-26 22:27:51 -04001112 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001113
Clarence Ip4ce59322016-06-26 22:27:51 -04001114 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001115
Clarence Ip4ce59322016-06-26 22:27:51 -04001116 /* this will destroy the states as well */
1117 drm_plane_cleanup(plane);
1118
Clarence Ip4c1d9772016-06-26 09:35:38 -04001119 if (psde->pipe_hw)
1120 sde_hw_sspp_destroy(psde->pipe_hw);
1121
Clarence Ip4ce59322016-06-26 22:27:51 -04001122 kfree(psde);
1123 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001124}
1125
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001126static void sde_plane_destroy_state(struct drm_plane *plane,
1127 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001128{
Clarence Ipe78efb72016-06-24 18:35:21 -04001129 struct sde_plane_state *pstate;
1130 int i;
1131
Clarence Ip4ce59322016-06-26 22:27:51 -04001132 DBG("");
Clarence Ipe78efb72016-06-24 18:35:21 -04001133
Clarence Ipae4e60c2016-06-26 22:44:04 -04001134 if (!plane || !state) {
1135 DRM_ERROR("Invalid plane/state\n");
1136 return;
1137 }
1138
Clarence Ipe78efb72016-06-24 18:35:21 -04001139 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001140 if (state->fb)
1141 drm_framebuffer_unreference(state->fb);
1142
Clarence Ipe78efb72016-06-24 18:35:21 -04001143 pstate = to_sde_plane_state(state);
1144
Clarence Ipae4e60c2016-06-26 22:44:04 -04001145 /* remove ref count for fence */
1146 if (pstate->sync_fence)
1147 sde_sync_put(pstate->sync_fence);
1148
Clarence Ipe78efb72016-06-24 18:35:21 -04001149 /* remove ref count for blobs */
1150 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1151 if (pstate->property_blobs[i])
1152 drm_property_unreference_blob(
1153 pstate->property_blobs[i]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001154 kfree(pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001155}
1156
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001157static struct drm_plane_state *
1158sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001159{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001160 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001161 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001162
1163 if (WARN_ON(!plane->state))
1164 return NULL;
1165
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001166 pstate = kmemdup(to_sde_plane_state(plane->state),
1167 sizeof(*pstate), GFP_KERNEL);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001168
1169 DBG("");
1170
Clarence Ipe78efb72016-06-24 18:35:21 -04001171 if (pstate) {
1172 /* add ref count for frame buffer */
1173 if (pstate->base.fb)
1174 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001175
Clarence Ipae4e60c2016-06-26 22:44:04 -04001176 /* add ref count for fence */
1177 if (pstate->sync_fence) {
1178 pstate->sync_fence = 0;
1179 _sde_plane_update_sync_fence(plane, pstate, pstate->
1180 property_values[PLANE_PROP_SYNC_FENCE]);
1181 }
1182
Clarence Ipe78efb72016-06-24 18:35:21 -04001183 /* add ref count for blobs */
1184 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1185 if (pstate->property_blobs[i])
1186 drm_property_reference_blob(
1187 pstate->property_blobs[i]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001188
Clarence Ipe78efb72016-06-24 18:35:21 -04001189 pstate->mode_changed = false;
1190 pstate->pending = false;
1191 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001192
Clarence Ipe78efb72016-06-24 18:35:21 -04001193 return pstate ? &pstate->base : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001194}
1195
1196static void sde_plane_reset(struct drm_plane *plane)
1197{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001198 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001199 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001200 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001201
Clarence Ip4ce59322016-06-26 22:27:51 -04001202 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001203
Clarence Ipae4e60c2016-06-26 22:44:04 -04001204 if (!plane) {
1205 DRM_ERROR("Invalid plane\n");
1206 return;
1207 }
1208
1209 /* remove previous state, if present */
1210 if (plane->state)
1211 sde_plane_destroy_state(plane, plane->state);
1212 plane->state = 0;
1213
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001214 pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001215 if (!pstate) {
1216 DRM_ERROR("Failed to re-allocate plane state\n");
1217 return;
1218 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001219
Clarence Ipae4e60c2016-06-26 22:44:04 -04001220 /* assign default property values */
1221 psde = to_sde_plane(plane);
1222 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1223 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001224
1225 pstate->base.plane = plane;
1226
1227 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001228}
1229
1230static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001231 .update_plane = drm_atomic_helper_update_plane,
1232 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001233 .destroy = sde_plane_destroy,
1234 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001235 .atomic_set_property = sde_plane_atomic_set_property,
1236 .atomic_get_property = sde_plane_atomic_get_property,
1237 .reset = sde_plane_reset,
1238 .atomic_duplicate_state = sde_plane_duplicate_state,
1239 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001240};
1241
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001242static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1243 .prepare_fb = sde_plane_prepare_fb,
1244 .cleanup_fb = sde_plane_cleanup_fb,
1245 .atomic_check = sde_plane_atomic_check,
1246 .atomic_update = sde_plane_atomic_update,
1247};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001248
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001249enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001250{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001251 struct sde_plane *sde_plane = to_sde_plane(plane);
1252
1253 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001254}
1255
Clarence Ip4ce59322016-06-26 22:27:51 -04001256static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1257{
1258 const struct sde_sspp_sub_blks *sblk = 0;
1259 const struct sde_sspp_cfg *cfg = 0;
1260
1261 if (psde && psde->pipe_hw)
1262 cfg = psde->pipe_hw->cap;
1263 if (cfg)
1264 sblk = cfg->sblk;
1265
1266 if (kms && sblk) {
1267 /* create overall sub-directory for the pipe */
1268 psde->debugfs_root =
1269 debugfs_create_dir(psde->pipe_name,
1270 sde_debugfs_get_root(kms));
1271 if (psde->debugfs_root) {
1272 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001273 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001274 psde->debugfs_root, &psde->features);
1275
1276 /* add register dump support */
1277 sde_debugfs_setup_regset32(&psde->debugfs_src,
1278 sblk->src_blk.base + cfg->base,
1279 sblk->src_blk.len,
1280 kms->mmio);
1281 sde_debugfs_create_regset32("src_blk", 0444,
1282 psde->debugfs_root, &psde->debugfs_src);
1283
1284 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1285 sblk->scaler_blk.base + cfg->base,
1286 sblk->scaler_blk.len,
1287 kms->mmio);
1288 sde_debugfs_create_regset32("scaler_blk", 0444,
1289 psde->debugfs_root,
1290 &psde->debugfs_scaler);
1291
1292 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1293 sblk->csc_blk.base + cfg->base,
1294 sblk->csc_blk.len,
1295 kms->mmio);
1296 sde_debugfs_create_regset32("csc_blk", 0444,
1297 psde->debugfs_root, &psde->debugfs_csc);
1298 }
1299 }
1300}
1301
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001302/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001303struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001304 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001305{
1306 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001307 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001308 struct msm_drm_private *priv;
1309 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001310 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001311 int ret = -EINVAL;
1312
1313 if (!dev) {
1314 DRM_ERROR("[%u]Device is NULL\n", pipe);
1315 goto exit;
1316 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001317
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001318 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001319 if (!priv) {
1320 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1321 goto exit;
1322 }
1323
1324 if (!priv->kms) {
1325 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1326 goto exit;
1327 }
1328 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001329
Clarence Ip4c1d9772016-06-26 09:35:38 -04001330 if (!kms->catalog) {
1331 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1332 goto exit;
1333 }
1334
Clarence Ip4ce59322016-06-26 22:27:51 -04001335 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001336 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1337 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001338 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001339 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001340 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001341 }
1342
Clarence Ip4c1d9772016-06-26 09:35:38 -04001343 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001344 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001345 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001346 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001347
Clarence Ip4c1d9772016-06-26 09:35:38 -04001348 /* initialize underlying h/w driver */
1349 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1350 if (IS_ERR(psde->pipe_hw)) {
1351 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1352 ret = PTR_ERR(psde->pipe_hw);
1353 goto clean_plane;
1354 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1355 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1356 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001357 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001358
1359 /* cache features mask for later */
1360 psde->features = psde->pipe_hw->cap->features;
1361 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1362
1363 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001364 psde->nformats = mdp_get_formats(psde->formats,
1365 ARRAY_SIZE(psde->formats),
1366 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001367 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001368
Clarence Ip4c1d9772016-06-26 09:35:38 -04001369 if (!psde->nformats) {
1370 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1371 goto clean_sspp;
1372 }
1373
1374 if (psde->features & BIT(SDE_SSPP_CURSOR))
1375 type = DRM_PLANE_TYPE_CURSOR;
1376 else if (primary_plane)
1377 type = DRM_PLANE_TYPE_PRIMARY;
1378 else
1379 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001380 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1381 psde->formats, psde->nformats,
1382 type);
1383 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001384 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001385
Clarence Ip4c1d9772016-06-26 09:35:38 -04001386 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001387 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001388
Clarence Ip4c1d9772016-06-26 09:35:38 -04001389 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001390
Clarence Ip4ce59322016-06-26 22:27:51 -04001391 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001392 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001393
1394 _sde_plane_init_debugfs(psde, kms);
1395
Clarence Ip4c1d9772016-06-26 09:35:38 -04001396 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001397 return plane;
1398
Clarence Ip4c1d9772016-06-26 09:35:38 -04001399clean_sspp:
1400 if (psde && psde->pipe_hw)
1401 sde_hw_sspp_destroy(psde->pipe_hw);
1402clean_plane:
1403 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001404exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001405 return ERR_PTR(ret);
1406}