blob: 07d4492431f6d11315e687f06978e38d19656453 [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
Clarence Ip730e7192016-06-26 22:45:09 -040031#define SDE_STATE_CACHE_SIZE 2
32
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070033struct sde_plane {
34 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040035
36 int mmu_id;
37
Clarence Ip730e7192016-06-26 22:45:09 -040038 struct mutex lock;
39
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040040 enum sde_sspp pipe;
41 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070042 uint32_t nformats;
43 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040044
45 struct sde_hw_pipe *pipe_hw;
46 struct sde_hw_pipe_cfg pipe_cfg;
47 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040048 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040049 struct sde_hw_scaler3_cfg scaler3_cfg;
Clarence Ip4ce59322016-06-26 22:27:51 -040050
Clarence Ip373f8592016-05-26 00:58:42 -040051 struct sde_csc_cfg csc_cfg;
52 struct sde_csc_cfg *csc_ptr;
53
Clarence Ip4c1d9772016-06-26 09:35:38 -040054 const struct sde_sspp_sub_blks *pipe_sblk;
55
Clarence Ip5e2a9222016-06-26 22:38:24 -040056 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040057
Clarence Ipae4e60c2016-06-26 22:44:04 -040058 /* cache property default values (for reset) */
59 uint64_t property_defaults[PLANE_PROP_COUNT];
60
Clarence Ip730e7192016-06-26 22:45:09 -040061 /* cache for unused plane state structures */
62 struct sde_plane_state *state_cache[SDE_STATE_CACHE_SIZE];
63 int state_cache_size;
64
Clarence Ip4ce59322016-06-26 22:27:51 -040065 /* debugfs related stuff */
66 struct dentry *debugfs_root;
67 struct sde_debugfs_regset32 debugfs_src;
68 struct sde_debugfs_regset32 debugfs_scaler;
69 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070070};
71#define to_sde_plane(x) container_of(x, struct sde_plane, base)
72
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040073static bool sde_plane_enabled(struct drm_plane_state *state)
74{
75 return state->fb && state->crtc;
76}
77
Clarence Ipae4e60c2016-06-26 22:44:04 -040078/* helper to update a state's sync fence pointer from the property */
79static void _sde_plane_update_sync_fence(struct drm_plane *plane,
80 struct sde_plane_state *pstate, uint64_t fd)
81{
82 if (!plane || !pstate)
83 return;
84
85 /* clear previous reference */
86 if (pstate->sync_fence)
87 sde_sync_put(pstate->sync_fence);
88
89 /* get fence pointer for later */
90 pstate->sync_fence = sde_sync_get(fd);
91
92 DBG("0x%llX", fd);
93}
94
95void *sde_plane_get_sync_fence(struct drm_plane *plane)
96{
97 struct sde_plane_state *pstate;
98 void *ret = NULL;
99
100 if (!plane) {
101 DRM_ERROR("Invalid plane\n");
102 } else if (!plane->state) {
103 DRM_ERROR("Invalid plane state\n");
104 } else {
105 pstate = to_sde_plane_state(plane->state);
106 ret = pstate->sync_fence;
107
108 DBG("%s", to_sde_plane(plane)->pipe_name);
109 }
110
111 return ret;
112}
113
Clarence Ipe78efb72016-06-24 18:35:21 -0400114static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400115 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400116 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
117{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400118 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400119 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400120 int i;
121
Clarence Ipae4e60c2016-06-26 22:44:04 -0400122 if (!plane || !pstate || !pipe_cfg || !fb)
123 return;
124
125 psde = to_sde_plane(plane);
126
127 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400128 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400129 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400130 BIT(SDE_DRM_DEINTERLACE))
131 shift = 1;
132 else
133 shift = 0;
134
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400135 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
136 while (i) {
137 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400138 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400139 }
140
141 /* address */
142 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
143 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
144 psde->mmu_id, i);
145
146 /* hw driver */
147 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
148 }
149}
150
Clarence Ip5e2a9222016-06-26 22:38:24 -0400151static void _sde_plane_setup_scaler3(struct drm_plane *plane,
152 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
153 struct sde_hw_scaler3_cfg *scale_cfg,
154 struct sde_mdp_format_params *fmt,
155 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
156{
157}
158
159static void _sde_plane_setup_scaler2(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400160 uint32_t src, uint32_t dst, uint32_t *phase_steps,
161 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
162 uint32_t chroma_subsampling)
163{
Clarence Ip4c1d9772016-06-26 09:35:38 -0400164 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400165 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400166 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400167 phase_steps[SDE_SSPP_COMP_1_2] =
168 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
169 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
170 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400171
172 /* calculate scaler config, if necessary */
Clarence Ipe78efb72016-06-24 18:35:21 -0400173 if (fmt->is_yuv || src != dst) {
174 filter[SDE_SSPP_COMP_3] =
175 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
176 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400177
Clarence Ipe78efb72016-06-24 18:35:21 -0400178 if (fmt->is_yuv) {
179 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
180 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
181 } else {
182 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
183 filter[SDE_SSPP_COMP_1_2] =
184 SDE_MDP_SCALE_FILTER_NEAREST;
185 }
186 } else {
187 /* disable scaler */
188 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
189 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
190 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400191 }
192}
193
Clarence Ipe78efb72016-06-24 18:35:21 -0400194static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400195 uint32_t src, uint32_t dst, uint32_t decimated_src,
196 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400197 int *out_edge2, enum sde_hw_filter *filter,
198 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
199 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400200{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400201 int64_t edge1, edge2, caf;
202 uint32_t src_work;
203 int i, tmp;
204
Clarence Ipe78efb72016-06-24 18:35:21 -0400205 if (plane && phase_steps && out_src && out_edge1 &&
206 out_edge2 && filter && fmt) {
207 /* handle CAF for YUV formats */
208 if (fmt->is_yuv && SDE_MDP_SCALE_FILTER_CA == *filter)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400209 caf = PHASE_STEP_UNIT_SCALE;
210 else
211 caf = 0;
212
213 for (i = 0; i < SDE_MAX_PLANES; i++) {
214 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400215 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400216 src_work /= chroma_subsampling;
217 if (post_compare)
218 src = src_work;
219 if (!(fmt->is_yuv) && (src == dst)) {
220 /* unity */
221 edge1 = 0;
222 edge2 = 0;
223 } else if (dst >= src) {
224 /* upscale */
225 edge1 = (1 << PHASE_RESIDUAL);
226 edge1 -= caf;
227 edge2 = (1 << PHASE_RESIDUAL);
228 edge2 += (dst - 1) * *(phase_steps + i);
229 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
230 edge2 += caf;
231 edge2 = -(edge2);
232 } else {
233 /* downscale */
234 edge1 = 0;
235 edge2 = (dst - 1) * *(phase_steps + i);
236 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
237 edge2 += *(phase_steps + i);
238 edge2 = -(edge2);
239 }
240
241 /* only enable CAF for luma plane */
242 caf = 0;
243
244 /* populate output arrays */
245 *(out_src + i) = src_work;
246
247 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400248 if (edge1 >= 0) {
249 tmp = (uint32_t)edge1;
250 tmp >>= PHASE_STEP_SHIFT;
251 *(out_edge1 + i) = -tmp;
252 } else {
253 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400254 *(out_edge1 + i) =
255 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
256 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400257 }
258 if (edge2 >= 0) {
259 tmp = (uint32_t)edge2;
260 tmp >>= PHASE_STEP_SHIFT;
261 *(out_edge2 + i) = -tmp;
262 } else {
263 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400264 *(out_edge2 + i) =
265 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
266 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400267 }
268 }
269 }
270}
271
Clarence Ip5e2a9222016-06-26 22:38:24 -0400272static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
273 enum msm_mdp_plane_property property, size_t *byte_len)
274{
275 struct drm_property_blob *blob;
276 size_t len = 0;
277 void *ret = 0;
278
Clarence Ip4c1d9772016-06-26 09:35:38 -0400279 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
280 DRM_ERROR("Invalid argument(s)\n");
281 } else {
282 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400283 if (blob) {
284 len = blob->length;
285 ret = &blob->data;
286 }
287 }
288
289 if (byte_len)
290 *byte_len = len;
291
292 return ret;
293}
294
295/**
296 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
297 * sub-structure
298 * @blob_ptr: Pointer to start of incoming blob data
299 * @blob_size: Size of incoming blob data, in bytes
300 * @sub_ptr: Pointer to start of desired sub-structure
301 * @sub_size: Required size of sub-structure, in bytes
302 */
303static int _sde_plane_verify_blob(void *blob_ptr,
304 size_t blob_size,
305 void *sub_ptr,
306 size_t sub_size)
307{
308 /*
309 * Use the blob size provided by drm to check if there are enough
310 * bytes from the start of versioned sub-structures to the end of
311 * blob data:
312 *
313 * e.g.,
314 * blob_ptr --> struct blob_data {
315 * uint32_t version;
316 * sub_ptr --> struct blob_data_v1 v1;
317 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
318 * blob_ptr + blob_size --> };
319 *
320 * It's important to check the actual number of bytes from the start
321 * of the sub-structure to the end of the blob data, and not just rely
322 * on something like,
323 *
324 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
325 *
326 * This is because the start of the sub-structure can vary based on
327 * how the compiler pads the overall structure.
328 */
329 if (blob_ptr && sub_ptr)
330 /* return zero if end of blob >= end of sub-struct */
331 return ((unsigned char *)blob_ptr + blob_size) <
332 ((unsigned char *)sub_ptr + sub_size);
333 return -EINVAL;
334}
335
Clarence Ipe78efb72016-06-24 18:35:21 -0400336static void _sde_plane_setup_csc(struct sde_plane *psde,
337 struct sde_plane_state *pstate,
338 struct sde_mdp_format_params *fmt)
339{
340 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
341 {
Clarence Ip373f8592016-05-26 00:58:42 -0400342 /* S15.16 format */
343 0x00012A00, 0x00000000, 0x00019880,
344 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
345 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400346 },
Clarence Ip373f8592016-05-26 00:58:42 -0400347 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400348 { 0xfff0, 0xff80, 0xff80,},
349 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400350 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400351 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400352 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400353 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400354 static const struct sde_csc_cfg sde_csc_NOP = {
355 {
Clarence Ip373f8592016-05-26 00:58:42 -0400356 /* identity matrix, S15.16 format */
357 0x10000, 0x00000, 0x00000,
358 0x00000, 0x10000, 0x00000,
359 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400360 },
Clarence Ip373f8592016-05-26 00:58:42 -0400361 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400362 { 0x0, 0x0, 0x0,},
363 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400364 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400365 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
366 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
367 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400368 struct sde_drm_csc *csc = NULL;
369 size_t csc_size = 0;
370 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400371
372 if (!psde->pipe_hw->ops.setup_csc)
373 return;
374
Clarence Ip5e2a9222016-06-26 22:38:24 -0400375 /* check for user space override */
376 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
377 if (csc) {
378 struct sde_csc_cfg cfg;
379 int i;
380
381 /* user space override */
382 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
383 switch (csc->version) {
384 case SDE_DRM_CSC_V1:
385 if (!_sde_plane_verify_blob(csc,
386 csc_size,
387 &csc->v1,
388 sizeof(struct sde_drm_csc_v1))) {
389 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
390 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400391 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400392 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
393 cfg.csc_pre_bv[i] =
394 csc->v1.pre_bias[i];
395 cfg.csc_post_bv[i] =
396 csc->v1.post_bias[i];
397 }
398 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
399 cfg.csc_pre_lv[i] =
400 csc->v1.pre_clamp[i];
401 cfg.csc_post_lv[i] =
402 csc->v1.post_clamp[i];
403 }
404 user_blob = true;
405 }
406 break;
407 default:
408 break;
409 }
410
411 if (!user_blob)
412 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
413 else
414 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
415 (struct sde_csc_cfg *)&cfg);
416 }
417
418 if (user_blob) {
419 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400420 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400421 /* revert to kernel default */
422 } else if (fmt->is_yuv) {
Clarence Ip373f8592016-05-26 00:58:42 -0400423 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400424 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400425 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400426 }
Clarence Ip373f8592016-05-26 00:58:42 -0400427
428 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400429}
430
431static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700432 struct drm_crtc *crtc, struct drm_framebuffer *fb,
433 int crtc_x, int crtc_y,
434 unsigned int crtc_w, unsigned int crtc_h,
435 uint32_t src_x, uint32_t src_y,
436 uint32_t src_w, uint32_t src_h)
437{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400438 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400439 struct sde_plane_state *pstate;
440 const struct mdp_format *format;
441 uint32_t nplanes, pix_format, tmp;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400442 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
443 uint32_t src_fmt_flags;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400444 int i;
445 struct sde_mdp_format_params *fmt;
446 struct sde_hw_pixel_ext *pe;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400447 size_t sc_u_size = 0;
448 struct sde_drm_scaler *sc_u = NULL;
449 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400450
Clarence Ip4ce59322016-06-26 22:27:51 -0400451 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400452
Clarence Ip5e2a9222016-06-26 22:38:24 -0400453 if (!plane || !plane->state) {
454 DRM_ERROR("Invalid plane/state\n");
455 return -EINVAL;
456 }
457 if (!crtc || !fb) {
458 DRM_ERROR("Invalid crtc/fb\n");
459 return -EINVAL;
460 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400461
Clarence Ip5e2a9222016-06-26 22:38:24 -0400462 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400463 pstate = to_sde_plane_state(plane->state);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400464 nplanes = drm_format_num_planes(fb->pixel_format);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400465
466 format = to_mdp_format(msm_framebuffer_format(fb));
467 pix_format = format->base.pixel_format;
468
469 /* src values are in Q16 fixed point, convert to integer */
470 src_x = src_x >> 16;
471 src_y = src_y >> 16;
472 src_w = src_w >> 16;
473 src_h = src_h >> 16;
474
Clarence Ip4ce59322016-06-26 22:27:51 -0400475 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400476 fb->base.id, src_x, src_y, src_w, src_h,
477 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
478
479 /* update format configuration */
480 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400481 src_fmt_flags = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400482
483 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400484 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400485 psde->pipe_cfg.src.width = fb->width;
486 psde->pipe_cfg.src.height = fb->height;
487 psde->pipe_cfg.src.num_planes = nplanes;
488
Clarence Ip5e2a9222016-06-26 22:38:24 -0400489 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
490
Clarence Ip5e2a9222016-06-26 22:38:24 -0400491 /* flags */
492 DBG("Flags 0x%llX, rotation 0x%llX",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400493 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
494 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
495 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400496 BIT(DRM_REFLECT_X))
497 src_fmt_flags |= SDE_SSPP_FLIP_LR;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400498 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400499 BIT(DRM_REFLECT_Y))
500 src_fmt_flags |= SDE_SSPP_FLIP_UD;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400501 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400502 BIT(SDE_DRM_DEINTERLACE)) {
503 src_h /= 2;
504 src_y = DIV_ROUND_UP(src_y, 2);
505 src_y &= ~0x1;
506 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400507
508 psde->pipe_cfg.src_rect.x = src_x;
509 psde->pipe_cfg.src_rect.y = src_y;
510 psde->pipe_cfg.src_rect.w = src_w;
511 psde->pipe_cfg.src_rect.h = src_h;
512
513 psde->pipe_cfg.dst_rect.x = crtc_x;
514 psde->pipe_cfg.dst_rect.y = crtc_y;
515 psde->pipe_cfg.dst_rect.w = crtc_w;
516 psde->pipe_cfg.dst_rect.h = crtc_h;
517
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400518 /* get sde pixel format definition */
519 fmt = psde->pipe_cfg.src.format;
520
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400521 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400522 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400523
Clarence Ip5e2a9222016-06-26 22:38:24 -0400524 /* get scaler config from user space */
525 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
526 if (sc_u) {
527 switch (sc_u->version) {
528 case SDE_DRM_SCALER_V1:
529 if (!_sde_plane_verify_blob(sc_u,
530 sc_u_size,
531 &sc_u->v1,
532 sizeof(*sc_u1)))
533 sc_u1 = &sc_u->v1;
534 break;
535 default:
536 DBG("Unrecognized scaler blob v%lld", sc_u->version);
537 break;
538 }
539 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400540
Clarence Ip04ec67d2016-05-26 01:16:15 -0400541 /* decimation */
542 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
543 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
544 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
545 }
546
547 /* don't chroma subsample if decimating */
548 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
549 drm_format_horz_chroma_subsampling(pix_format);
550 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
551 drm_format_vert_chroma_subsampling(pix_format);
552
Clarence Ip5e2a9222016-06-26 22:38:24 -0400553 /* update scaler */
554 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
555 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
556 DBG("QSEED3 blob detected");
557 else
558 _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
559 crtc_h, &psde->scaler3_cfg, fmt,
560 chroma_subsmpl_h, chroma_subsmpl_v);
561 } else {
562 /* always calculate basic scaler config */
563 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
564 /* populate from user space */
565 for (i = 0; i < SDE_MAX_PLANES; i++) {
566 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
567 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
568 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
569 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400570
Clarence Ip5e2a9222016-06-26 22:38:24 -0400571 pe->horz_filter[i] = sc_u1->horz_filter[i];
572 pe->vert_filter[i] = sc_u1->vert_filter[i];
573 }
574 } else {
575 /* calculate phase steps */
576 _sde_plane_setup_scaler2(plane, src_w, crtc_w,
577 pe->phase_step_x,
578 pe->horz_filter, fmt, chroma_subsmpl_h);
579 _sde_plane_setup_scaler2(plane, src_h, crtc_h,
580 pe->phase_step_y,
581 pe->vert_filter, fmt, chroma_subsmpl_v);
582 }
583 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400584
Clarence Ip5e2a9222016-06-26 22:38:24 -0400585 /* update pixel extensions */
586 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
587 /* populate from user space */
588 for (i = 0; i < SDE_MAX_PLANES; i++) {
589 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
590 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
591 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
592 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
593 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
594 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
595 pe->roi_w[i] = sc_u1->lr.roi[i];
596
597 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
598 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
599 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
600 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
601 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
602 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
603 pe->roi_h[i] = sc_u1->tb.roi[i];
604 }
605 } else {
606 /* calculate left/right/top/bottom pixel extensions */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400607 tmp = DECIMATED_DIMENSION(src_w,
608 psde->pipe_cfg.horz_decimation);
609 if (fmt->is_yuv)
610 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400611 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400612 pe->phase_step_x,
613 pe->roi_w,
614 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400615 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400616 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400617
618 tmp = DECIMATED_DIMENSION(src_h,
619 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400620 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400621 pe->phase_step_y,
622 pe->roi_h,
623 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400624 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400625 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400626
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400627 for (i = 0; i < SDE_MAX_PLANES; i++) {
628 if (pe->num_ext_pxls_left[i] >= 0)
629 pe->left_rpt[i] =
630 pe->num_ext_pxls_left[i];
631 else
632 pe->left_ftch[i] =
633 pe->num_ext_pxls_left[i];
634
635 if (pe->num_ext_pxls_right[i] >= 0)
636 pe->right_rpt[i] =
637 pe->num_ext_pxls_right[i];
638 else
639 pe->right_ftch[i] =
640 pe->num_ext_pxls_right[i];
641
642 if (pe->num_ext_pxls_top[i] >= 0)
643 pe->top_rpt[i] =
644 pe->num_ext_pxls_top[i];
645 else
646 pe->top_ftch[i] =
647 pe->num_ext_pxls_top[i];
648
649 if (pe->num_ext_pxls_btm[i] >= 0)
650 pe->btm_rpt[i] =
651 pe->num_ext_pxls_btm[i];
652 else
653 pe->btm_ftch[i] =
654 pe->num_ext_pxls_btm[i];
655 }
656 }
657
Clarence Ip4c1d9772016-06-26 09:35:38 -0400658 if (psde->pipe_hw->ops.setup_format)
659 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400660 &psde->pipe_cfg, src_fmt_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400661 if (psde->pipe_hw->ops.setup_rects)
662 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
663 &psde->pipe_cfg, &psde->pixel_ext);
664
Clarence Ipe78efb72016-06-24 18:35:21 -0400665 /* update sharpening */
666 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
667 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
668 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
669 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
670
671 if (psde->pipe_hw->ops.setup_sharpening)
672 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
673 &psde->sharp_cfg);
674
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400675 /* update csc */
Clarence Ipe78efb72016-06-24 18:35:21 -0400676 if (fmt->is_yuv)
677 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400678
Clarence Ip5e2a9222016-06-26 22:38:24 -0400679 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400680}
681
682static int sde_plane_prepare_fb(struct drm_plane *plane,
683 const struct drm_plane_state *new_state)
684{
685 struct drm_framebuffer *fb = new_state->fb;
686 struct sde_plane *psde = to_sde_plane(plane);
687
688 if (!new_state->fb)
689 return 0;
690
Clarence Ipae4e60c2016-06-26 22:44:04 -0400691 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400692 return msm_framebuffer_prepare(fb, psde->mmu_id);
693}
694
695static void sde_plane_cleanup_fb(struct drm_plane *plane,
696 const struct drm_plane_state *old_state)
697{
698 struct drm_framebuffer *fb = old_state->fb;
699 struct sde_plane *psde = to_sde_plane(plane);
700
701 if (!fb)
702 return;
703
Clarence Ipae4e60c2016-06-26 22:44:04 -0400704 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400705 msm_framebuffer_cleanup(fb, psde->mmu_id);
706}
707
708static int sde_plane_atomic_check(struct drm_plane *plane,
709 struct drm_plane_state *state)
710{
711 struct sde_plane *psde = to_sde_plane(plane);
712 struct drm_plane_state *old_state = plane->state;
713 const struct mdp_format *format;
714
Clarence Ip4ce59322016-06-26 22:27:51 -0400715 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400716 sde_plane_enabled(old_state), sde_plane_enabled(state));
717
718 if (sde_plane_enabled(state)) {
719 /* CIFIX: don't use mdp format? */
720 format = to_mdp_format(msm_framebuffer_format(state->fb));
721 if (MDP_FORMAT_IS_YUV(format) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400722 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400723 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400724 DRM_ERROR("Pipe doesn't support YUV\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400725
726 return -EINVAL;
727 }
728
Clarence Ipe78efb72016-06-24 18:35:21 -0400729 if (!(psde->features & SDE_SSPP_SCALER) &&
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400730 (((state->src_w >> 16) != state->crtc_w) ||
731 ((state->src_h >> 16) != state->crtc_h))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400732 DRM_ERROR(
733 "Unsupported Pipe scaling (%dx%d -> %dx%d)\n",
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400734 state->src_w >> 16, state->src_h >> 16,
735 state->crtc_w, state->crtc_h);
736
737 return -EINVAL;
738 }
739 }
740
741 if (sde_plane_enabled(state) && sde_plane_enabled(old_state)) {
742 /* we cannot change SMP block configuration during scanout: */
743 bool full_modeset = false;
744
745 if (state->fb->pixel_format != old_state->fb->pixel_format) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400746 DBG("%s: pixel_format change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400747 full_modeset = true;
748 }
749 if (state->src_w != old_state->src_w) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400750 DBG("%s: src_w change!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400751 full_modeset = true;
752 }
753 if (to_sde_plane_state(old_state)->pending) {
Clarence Ip4ce59322016-06-26 22:27:51 -0400754 DBG("%s: still pending!", psde->pipe_name);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400755 full_modeset = true;
756 }
757 if (full_modeset) {
758 struct drm_crtc_state *crtc_state =
Clarence Ipe78efb72016-06-24 18:35:21 -0400759 drm_atomic_get_crtc_state(state->state,
760 state->crtc);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400761 crtc_state->mode_changed = true;
762 to_sde_plane_state(state)->mode_changed = true;
763 }
764 } else {
765 to_sde_plane_state(state)->mode_changed = true;
766 }
767
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700768 return 0;
769}
770
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400771static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400772 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700773{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400774 struct sde_plane *sde_plane;
775 struct drm_plane_state *state;
776 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400777
Clarence Ip5e2a9222016-06-26 22:38:24 -0400778 if (!plane || !plane->state) {
779 DRM_ERROR("Invalid plane/state\n");
780 return;
781 }
782
783 sde_plane = to_sde_plane(plane);
784 state = plane->state;
785 pstate = to_sde_plane_state(state);
786
Clarence Ipae4e60c2016-06-26 22:44:04 -0400787 DBG("%s: update", sde_plane->pipe_name);
788
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400789 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400790 pstate->pending = true;
791 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400792 int ret;
793
Clarence Ip5e2a9222016-06-26 22:38:24 -0400794 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400795 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400796 state->crtc, state->fb,
797 state->crtc_x, state->crtc_y,
798 state->crtc_w, state->crtc_h,
799 state->src_x, state->src_y,
800 state->src_w, state->src_h);
801 /* atomic_check should have ensured that this doesn't fail */
802 WARN_ON(ret < 0);
803 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400804 _sde_plane_set_scanout(plane, pstate,
805 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400806 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400807}
808
Clarence Ipae4e60c2016-06-26 22:44:04 -0400809static inline struct drm_property **_sde_plane_get_property_entry(
810 struct drm_device *dev, enum msm_mdp_plane_property property)
811{
812 struct msm_drm_private *priv;
813
814 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
815 return NULL;
816
817 priv = dev->dev_private;
818
819 return &(priv->plane_property[property]);
820}
821
Clarence Ipe78efb72016-06-24 18:35:21 -0400822static void _sde_plane_install_range_property(struct drm_plane *plane,
823 struct drm_device *dev, const char *name,
824 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400825 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -0400826{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400827 struct drm_property **prop;
828
829 prop = _sde_plane_get_property_entry(dev, property);
830 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400831 /* only create the property once */
832 if (*prop == 0) {
833 *prop = drm_property_create_range(dev,
834 0 /* flags */, name, min, max);
835 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400836 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400837 }
838
Clarence Ipae4e60c2016-06-26 22:44:04 -0400839 /* save init value for later */
840 to_sde_plane(plane)->property_defaults[property] = init;
841
Clarence Ipe78efb72016-06-24 18:35:21 -0400842 /* always attach property, if created */
843 if (*prop)
844 drm_object_attach_property(&plane->base, *prop, init);
845 }
846}
847
Clarence Ip5e2a9222016-06-26 22:38:24 -0400848static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400849 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400850{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400851 struct sde_plane *psde;
852 struct drm_property **prop;
853
854 prop = _sde_plane_get_property_entry(dev, property);
855 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400856 /* only create the property once */
857 if (*prop == 0) {
858 *prop = drm_mode_create_rotation_property(dev,
859 BIT(DRM_REFLECT_X) |
860 BIT(DRM_REFLECT_Y));
861 if (*prop == 0)
862 DRM_ERROR("Create rotation property failed\n");
863 }
864
Clarence Ipae4e60c2016-06-26 22:44:04 -0400865 /* save init value for later */
866 psde = to_sde_plane(plane);
867 psde->property_defaults[property] = 0;
868
Clarence Ip5e2a9222016-06-26 22:38:24 -0400869 /* always attach property, if created */
870 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400871 drm_object_attach_property(&plane->base, *prop,
872 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400873 }
874}
875
876static void _sde_plane_install_enum_property(struct drm_plane *plane,
877 struct drm_device *dev, const char *name, int is_bitmask,
878 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400879 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400880{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400881 struct sde_plane *psde;
882 struct drm_property **prop;
883
884 prop = _sde_plane_get_property_entry(dev, property);
885 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400886 /* only create the property once */
887 if (*prop == 0) {
888 /* 'bitmask' is a special type of 'enum' */
889 if (is_bitmask)
890 *prop = drm_property_create_bitmask(dev,
891 DRM_MODE_PROP_BITMASK, name,
892 values, num_values, -1);
893 else
894 *prop = drm_property_create_enum(dev,
895 DRM_MODE_PROP_ENUM, name,
896 values, num_values);
897 if (*prop == 0)
898 DRM_ERROR("Create %s property failed\n", name);
899 }
900
Clarence Ipae4e60c2016-06-26 22:44:04 -0400901 /* save init value for later */
902 psde = to_sde_plane(plane);
903 psde->property_defaults[property] = 0;
904
Clarence Ip5e2a9222016-06-26 22:38:24 -0400905 /* always attach property, if created */
906 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400907 drm_object_attach_property(&plane->base, *prop,
908 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400909 }
910}
911
Clarence Ipe78efb72016-06-24 18:35:21 -0400912static void _sde_plane_install_blob_property(struct drm_plane *plane,
913 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400914 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -0400915{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400916 struct sde_plane *psde;
917 struct drm_property **prop;
918
919 prop = _sde_plane_get_property_entry(dev, property);
920 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400921 /* only create the property once */
922 if (*prop == 0) {
923 /* use 'create' for blob property place holder */
924 *prop = drm_property_create(dev,
925 DRM_MODE_PROP_BLOB, name, 0);
926 if (*prop == 0)
927 DRM_ERROR("Create %s property failed\n", name);
928 }
929
Clarence Ipae4e60c2016-06-26 22:44:04 -0400930 /* save init value for later */
931 psde = to_sde_plane(plane);
932 psde->property_defaults[property] = 0;
933
Clarence Ip5e2a9222016-06-26 22:38:24 -0400934 /* always attach property, if created */
935 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400936 drm_object_attach_property(&plane->base, *prop,
937 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400938 }
Clarence Ipe78efb72016-06-24 18:35:21 -0400939}
940
Clarence Ip4c1d9772016-06-26 09:35:38 -0400941static int _sde_plane_get_property_index(struct drm_plane *plane,
942 struct drm_property *property)
943{
944 struct drm_property **prop_array;
945 int idx = PLANE_PROP_COUNT;
946
947 if (!plane) {
948 DRM_ERROR("Invalid plane\n");
949 } else if (!plane->dev || !plane->dev->dev_private) {
950 /* don't access dev_private if !dev */
951 DRM_ERROR("Invalid device\n");
952 } else if (!property) {
953 DRM_ERROR("Incoming property is NULL\n");
954 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -0400955 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -0400956 if (!prop_array)
957 /* should never hit this */
958 DRM_ERROR("Invalid property array\n");
959
960 /* linear search is okay */
961 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
962 if (prop_array[idx] == property)
963 break;
964 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400965
966 if (idx == PLANE_PROP_COUNT)
967 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -0400968 }
969
970 return idx;
971}
972
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400973/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -0400974static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -0400975 struct drm_mode_object *obj,
976 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400977{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400978 static const struct drm_prop_enum_list e_blend_op[] = {
979 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
980 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
981 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
982 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
983 };
984 static const struct drm_prop_enum_list e_src_config[] = {
985 {SDE_DRM_DEINTERLACE, "deinterlace"}
986 };
987 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400988 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400989
Clarence Ip4ce59322016-06-26 22:27:51 -0400990 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400991
Clarence Ip4c1d9772016-06-26 09:35:38 -0400992 if (!psde || !psde->pipe_sblk || !catalog) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400993 DRM_ERROR("Failed to identify catalog definition\n");
994 return;
995 }
996
997 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -0400998 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
999 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1000 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1001 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001002
Clarence Ip5e2a9222016-06-26 22:38:24 -04001003 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001004 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001005
Clarence Ipae4e60c2016-06-26 22:44:04 -04001006 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
1007 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001008
1009 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001010 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001011
Clarence Ip04ec67d2016-05-26 01:16:15 -04001012 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001013 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1014 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001015 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001016 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1017 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001018 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001019
Clarence Ipe78efb72016-06-24 18:35:21 -04001020 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001021 if (psde->features & SDE_SSPP_SCALER)
1022 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001023 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001024 if (psde->features & BIT(SDE_SSPP_CSC))
1025 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001026 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001027}
1028
1029static int sde_plane_atomic_set_property(struct drm_plane *plane,
1030 struct drm_plane_state *state, struct drm_property *property,
1031 uint64_t val)
1032{
Clarence Ip730e7192016-06-26 22:45:09 -04001033 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001034 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001035 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001036 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001037
Clarence Ip4c1d9772016-06-26 09:35:38 -04001038 idx = _sde_plane_get_property_index(plane, property);
1039 if (!state) {
1040 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001041 } else if (idx >= PLANE_PROP_COUNT) {
1042 DRM_ERROR("Invalid property\n");
1043 } else {
1044 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001045 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001046
Clarence Ip730e7192016-06-26 22:45:09 -04001047 DBG("%s: %d <= %d", psde->pipe_name, idx, (int)val);
1048
Clarence Ipae4e60c2016-06-26 22:44:04 -04001049 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001050 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1051 (idx < PLANE_PROP_BLOBCOUNT)) {
1052 /* DRM lookup also takes a reference */
1053 blob = drm_property_lookup_blob(plane->dev,
1054 (uint32_t)val);
1055 if (!blob) {
1056 DRM_ERROR("Blob not found\n");
1057 val = 0;
1058 } else {
1059 DBG("Blob %u saved", blob->base.id);
1060 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001061
Clarence Ip4c1d9772016-06-26 09:35:38 -04001062 /* save blobs for later */
1063 pr_blob = &pstate->property_blobs[idx];
1064 /* need to clear previous reference */
1065 if (*pr_blob)
1066 drm_property_unreference_blob(*pr_blob);
1067 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001068 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001069 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1070 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001071 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001072 pstate->property_values[idx] = val;
1073 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001074 }
1075
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001076 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001077}
1078
1079static int sde_plane_set_property(struct drm_plane *plane,
1080 struct drm_property *property, uint64_t val)
1081{
Clarence Ip4ce59322016-06-26 22:27:51 -04001082 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001083
1084 if (!plane)
1085 return -EINVAL;
1086
Clarence Ipae4e60c2016-06-26 22:44:04 -04001087 return sde_plane_atomic_set_property(plane,
1088 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001089}
1090
1091static int sde_plane_atomic_get_property(struct drm_plane *plane,
1092 const struct drm_plane_state *state,
1093 struct drm_property *property, uint64_t *val)
1094{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001095 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001096 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001097
Clarence Ip4c1d9772016-06-26 09:35:38 -04001098 idx = _sde_plane_get_property_index(plane, property);
1099 if (!state) {
1100 DRM_ERROR("Invalid state\n");
1101 } else if (!val) {
1102 DRM_ERROR("Value pointer is NULL\n");
1103 } else if (idx < PLANE_PROP_COUNT) {
1104 pstate = to_sde_plane_state(state);
1105
1106 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001107 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001108 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001109 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001110
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001111 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001112}
1113
Clarence Ip730e7192016-06-26 22:45:09 -04001114static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
1115{
1116 struct sde_plane *psde;
1117 struct sde_plane_state *pstate;
1118
1119 if (!plane)
1120 return NULL;
1121
1122 psde = to_sde_plane(plane);
1123 pstate = NULL;
1124
1125 mutex_lock(&psde->lock);
1126 if (psde->state_cache_size)
1127 pstate = psde->state_cache[--(psde->state_cache_size)];
1128 mutex_unlock(&psde->lock);
1129
1130 if (!pstate)
1131 pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
1132
1133 return pstate;
1134}
1135
1136static void sde_plane_free_state(struct drm_plane *plane,
1137 struct sde_plane_state *pstate)
1138{
1139 struct sde_plane *psde;
1140
1141 if (!plane || !pstate)
1142 return;
1143
1144 psde = to_sde_plane(plane);
1145
1146 mutex_lock(&psde->lock);
1147 if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
1148 psde->state_cache[(psde->state_cache_size)++] = pstate;
1149 mutex_unlock(&psde->lock);
1150 } else {
1151 mutex_unlock(&psde->lock);
1152 kfree(pstate);
1153 }
1154}
1155
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001156static void sde_plane_destroy(struct drm_plane *plane)
1157{
Clarence Ip4ce59322016-06-26 22:27:51 -04001158 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001159
Clarence Ip4ce59322016-06-26 22:27:51 -04001160 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001161
Clarence Ip4ce59322016-06-26 22:27:51 -04001162 if (plane) {
1163 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001164
Clarence Ip4ce59322016-06-26 22:27:51 -04001165 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001166
Clarence Ip730e7192016-06-26 22:45:09 -04001167 mutex_destroy(&psde->lock);
1168
Clarence Ip4ce59322016-06-26 22:27:51 -04001169 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001170
Clarence Ip4ce59322016-06-26 22:27:51 -04001171 /* this will destroy the states as well */
1172 drm_plane_cleanup(plane);
1173
Clarence Ip4c1d9772016-06-26 09:35:38 -04001174 if (psde->pipe_hw)
1175 sde_hw_sspp_destroy(psde->pipe_hw);
1176
Clarence Ip730e7192016-06-26 22:45:09 -04001177 /* free state cache */
1178 while (psde->state_cache_size > 0)
1179 kfree(psde->state_cache[--(psde->state_cache_size)]);
1180
Clarence Ip4ce59322016-06-26 22:27:51 -04001181 kfree(psde);
1182 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001183}
1184
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001185static void sde_plane_destroy_state(struct drm_plane *plane,
1186 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001187{
Clarence Ipe78efb72016-06-24 18:35:21 -04001188 struct sde_plane_state *pstate;
1189 int i;
1190
Clarence Ipae4e60c2016-06-26 22:44:04 -04001191 if (!plane || !state) {
1192 DRM_ERROR("Invalid plane/state\n");
1193 return;
1194 }
1195
Clarence Ip730e7192016-06-26 22:45:09 -04001196 pstate = to_sde_plane_state(state);
1197
1198 DBG("");
1199
Clarence Ipe78efb72016-06-24 18:35:21 -04001200 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001201 if (state->fb)
1202 drm_framebuffer_unreference(state->fb);
1203
Clarence Ipae4e60c2016-06-26 22:44:04 -04001204 /* remove ref count for fence */
1205 if (pstate->sync_fence)
1206 sde_sync_put(pstate->sync_fence);
1207
Clarence Ipe78efb72016-06-24 18:35:21 -04001208 /* remove ref count for blobs */
1209 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1210 if (pstate->property_blobs[i])
1211 drm_property_unreference_blob(
1212 pstate->property_blobs[i]);
Clarence Ip730e7192016-06-26 22:45:09 -04001213 sde_plane_free_state(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001214}
1215
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001216static struct drm_plane_state *
1217sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001218{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001219 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001220 struct sde_plane_state *old_state;
Clarence Ipe78efb72016-06-24 18:35:21 -04001221 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001222
Clarence Ip730e7192016-06-26 22:45:09 -04001223 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001224 return NULL;
1225
Clarence Ip730e7192016-06-26 22:45:09 -04001226 old_state = to_sde_plane_state(plane->state);
1227 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001228
1229 DBG("");
1230
Clarence Ip730e7192016-06-26 22:45:09 -04001231 if (!pstate)
1232 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001233
Clarence Ip730e7192016-06-26 22:45:09 -04001234 memcpy(pstate, old_state, sizeof(*pstate));
Clarence Ipae4e60c2016-06-26 22:44:04 -04001235
Clarence Ip730e7192016-06-26 22:45:09 -04001236 /* add ref count for frame buffer */
1237 if (pstate->base.fb)
1238 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001239
Clarence Ip730e7192016-06-26 22:45:09 -04001240 /* add ref count for fence */
1241 if (pstate->sync_fence) {
1242 pstate->sync_fence = 0;
1243 _sde_plane_update_sync_fence(plane, pstate, pstate->
1244 property_values[PLANE_PROP_SYNC_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001245 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001246
Clarence Ip730e7192016-06-26 22:45:09 -04001247 /* add ref count for blobs */
1248 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1249 if (pstate->property_blobs[i])
1250 drm_property_reference_blob(
1251 pstate->property_blobs[i]);
1252
1253 pstate->mode_changed = false;
1254 pstate->pending = false;
1255
1256 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001257}
1258
1259static void sde_plane_reset(struct drm_plane *plane)
1260{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001261 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001262 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001263 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001264
Clarence Ipae4e60c2016-06-26 22:44:04 -04001265 if (!plane) {
1266 DRM_ERROR("Invalid plane\n");
1267 return;
1268 }
1269
Clarence Ip730e7192016-06-26 22:45:09 -04001270 psde = to_sde_plane(plane);
1271 DBG("%s", psde->pipe_name);
1272
Clarence Ipae4e60c2016-06-26 22:44:04 -04001273 /* remove previous state, if present */
1274 if (plane->state)
1275 sde_plane_destroy_state(plane, plane->state);
1276 plane->state = 0;
1277
Clarence Ip730e7192016-06-26 22:45:09 -04001278 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001279 if (!pstate) {
Clarence Ip730e7192016-06-26 22:45:09 -04001280 DRM_ERROR("Failed to (re)allocate plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001281 return;
1282 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001283
Clarence Ip730e7192016-06-26 22:45:09 -04001284 memset(pstate, 0, sizeof(*pstate));
1285
Clarence Ipae4e60c2016-06-26 22:44:04 -04001286 /* assign default property values */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001287 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1288 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001289
1290 pstate->base.plane = plane;
1291
1292 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001293}
1294
1295static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001296 .update_plane = drm_atomic_helper_update_plane,
1297 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001298 .destroy = sde_plane_destroy,
1299 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001300 .atomic_set_property = sde_plane_atomic_set_property,
1301 .atomic_get_property = sde_plane_atomic_get_property,
1302 .reset = sde_plane_reset,
1303 .atomic_duplicate_state = sde_plane_duplicate_state,
1304 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001305};
1306
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001307static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1308 .prepare_fb = sde_plane_prepare_fb,
1309 .cleanup_fb = sde_plane_cleanup_fb,
1310 .atomic_check = sde_plane_atomic_check,
1311 .atomic_update = sde_plane_atomic_update,
1312};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001313
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001314enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001315{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001316 struct sde_plane *sde_plane = to_sde_plane(plane);
1317
1318 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001319}
1320
Clarence Ip4ce59322016-06-26 22:27:51 -04001321static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1322{
1323 const struct sde_sspp_sub_blks *sblk = 0;
1324 const struct sde_sspp_cfg *cfg = 0;
1325
1326 if (psde && psde->pipe_hw)
1327 cfg = psde->pipe_hw->cap;
1328 if (cfg)
1329 sblk = cfg->sblk;
1330
1331 if (kms && sblk) {
1332 /* create overall sub-directory for the pipe */
1333 psde->debugfs_root =
1334 debugfs_create_dir(psde->pipe_name,
1335 sde_debugfs_get_root(kms));
1336 if (psde->debugfs_root) {
1337 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001338 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001339 psde->debugfs_root, &psde->features);
1340
1341 /* add register dump support */
1342 sde_debugfs_setup_regset32(&psde->debugfs_src,
1343 sblk->src_blk.base + cfg->base,
1344 sblk->src_blk.len,
1345 kms->mmio);
1346 sde_debugfs_create_regset32("src_blk", 0444,
1347 psde->debugfs_root, &psde->debugfs_src);
1348
1349 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1350 sblk->scaler_blk.base + cfg->base,
1351 sblk->scaler_blk.len,
1352 kms->mmio);
1353 sde_debugfs_create_regset32("scaler_blk", 0444,
1354 psde->debugfs_root,
1355 &psde->debugfs_scaler);
1356
1357 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1358 sblk->csc_blk.base + cfg->base,
1359 sblk->csc_blk.len,
1360 kms->mmio);
1361 sde_debugfs_create_regset32("csc_blk", 0444,
1362 psde->debugfs_root, &psde->debugfs_csc);
1363 }
1364 }
1365}
1366
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001367/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001368struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001369 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001370{
1371 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001372 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001373 struct msm_drm_private *priv;
1374 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001375 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001376 int ret = -EINVAL;
1377
1378 if (!dev) {
1379 DRM_ERROR("[%u]Device is NULL\n", pipe);
1380 goto exit;
1381 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001382
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001383 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001384 if (!priv) {
1385 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1386 goto exit;
1387 }
1388
1389 if (!priv->kms) {
1390 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1391 goto exit;
1392 }
1393 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001394
Clarence Ip4c1d9772016-06-26 09:35:38 -04001395 if (!kms->catalog) {
1396 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1397 goto exit;
1398 }
1399
Clarence Ip4ce59322016-06-26 22:27:51 -04001400 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001401 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1402 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001403 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001404 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001405 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001406 }
1407
Clarence Ip4c1d9772016-06-26 09:35:38 -04001408 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001409 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001410 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001411 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001412
Clarence Ip4c1d9772016-06-26 09:35:38 -04001413 /* initialize underlying h/w driver */
1414 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1415 if (IS_ERR(psde->pipe_hw)) {
1416 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1417 ret = PTR_ERR(psde->pipe_hw);
1418 goto clean_plane;
1419 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1420 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1421 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001422 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001423
1424 /* cache features mask for later */
1425 psde->features = psde->pipe_hw->cap->features;
1426 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1427
1428 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001429 psde->nformats = mdp_get_formats(psde->formats,
1430 ARRAY_SIZE(psde->formats),
1431 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001432 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001433
Clarence Ip4c1d9772016-06-26 09:35:38 -04001434 if (!psde->nformats) {
1435 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1436 goto clean_sspp;
1437 }
1438
1439 if (psde->features & BIT(SDE_SSPP_CURSOR))
1440 type = DRM_PLANE_TYPE_CURSOR;
1441 else if (primary_plane)
1442 type = DRM_PLANE_TYPE_PRIMARY;
1443 else
1444 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001445 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1446 psde->formats, psde->nformats,
1447 type);
1448 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001449 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001450
Clarence Ip4c1d9772016-06-26 09:35:38 -04001451 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001452 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001453
Clarence Ip4c1d9772016-06-26 09:35:38 -04001454 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001455
Clarence Ip4ce59322016-06-26 22:27:51 -04001456 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001457 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001458
Clarence Ip730e7192016-06-26 22:45:09 -04001459 mutex_init(&psde->lock);
1460
Clarence Ip4ce59322016-06-26 22:27:51 -04001461 _sde_plane_init_debugfs(psde, kms);
1462
Clarence Ip4c1d9772016-06-26 09:35:38 -04001463 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001464 return plane;
1465
Clarence Ip4c1d9772016-06-26 09:35:38 -04001466clean_sspp:
1467 if (psde && psde->pipe_hw)
1468 sde_hw_sspp_destroy(psde->pipe_hw);
1469clean_plane:
1470 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001471exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001472 return ERR_PTR(ret);
1473}