blob: 666653263f4094ae028ef9856b09ba297e15e564 [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{
Clarence Ipdbde9832016-06-26 09:48:36 -040075 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040076}
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 Ipdbde9832016-06-26 09:48:36 -0400173 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400174 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 Ipdbde9832016-06-26 09:48:36 -0400178 if (SDE_FORMAT_IS_YUV(fmt)) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400179 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 */
Clarence Ipdbde9832016-06-26 09:48:36 -0400208 if (SDE_FORMAT_IS_YUV(fmt) &&
209 *filter == SDE_MDP_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400210 caf = PHASE_STEP_UNIT_SCALE;
211 else
212 caf = 0;
213
214 for (i = 0; i < SDE_MAX_PLANES; i++) {
215 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400216 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400217 src_work /= chroma_subsampling;
218 if (post_compare)
219 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400220 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400221 /* unity */
222 edge1 = 0;
223 edge2 = 0;
224 } else if (dst >= src) {
225 /* upscale */
226 edge1 = (1 << PHASE_RESIDUAL);
227 edge1 -= caf;
228 edge2 = (1 << PHASE_RESIDUAL);
229 edge2 += (dst - 1) * *(phase_steps + i);
230 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
231 edge2 += caf;
232 edge2 = -(edge2);
233 } else {
234 /* downscale */
235 edge1 = 0;
236 edge2 = (dst - 1) * *(phase_steps + i);
237 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
238 edge2 += *(phase_steps + i);
239 edge2 = -(edge2);
240 }
241
242 /* only enable CAF for luma plane */
243 caf = 0;
244
245 /* populate output arrays */
246 *(out_src + i) = src_work;
247
248 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400249 if (edge1 >= 0) {
250 tmp = (uint32_t)edge1;
251 tmp >>= PHASE_STEP_SHIFT;
252 *(out_edge1 + i) = -tmp;
253 } else {
254 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400255 *(out_edge1 + i) =
256 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
257 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400258 }
259 if (edge2 >= 0) {
260 tmp = (uint32_t)edge2;
261 tmp >>= PHASE_STEP_SHIFT;
262 *(out_edge2 + i) = -tmp;
263 } else {
264 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400265 *(out_edge2 + i) =
266 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
267 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400268 }
269 }
270 }
271}
272
Clarence Ip5e2a9222016-06-26 22:38:24 -0400273static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
274 enum msm_mdp_plane_property property, size_t *byte_len)
275{
276 struct drm_property_blob *blob;
277 size_t len = 0;
278 void *ret = 0;
279
Clarence Ip4c1d9772016-06-26 09:35:38 -0400280 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
281 DRM_ERROR("Invalid argument(s)\n");
282 } else {
283 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400284 if (blob) {
285 len = blob->length;
286 ret = &blob->data;
287 }
288 }
289
290 if (byte_len)
291 *byte_len = len;
292
293 return ret;
294}
295
296/**
297 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
298 * sub-structure
299 * @blob_ptr: Pointer to start of incoming blob data
300 * @blob_size: Size of incoming blob data, in bytes
301 * @sub_ptr: Pointer to start of desired sub-structure
302 * @sub_size: Required size of sub-structure, in bytes
303 */
304static int _sde_plane_verify_blob(void *blob_ptr,
305 size_t blob_size,
306 void *sub_ptr,
307 size_t sub_size)
308{
309 /*
310 * Use the blob size provided by drm to check if there are enough
311 * bytes from the start of versioned sub-structures to the end of
312 * blob data:
313 *
314 * e.g.,
315 * blob_ptr --> struct blob_data {
316 * uint32_t version;
317 * sub_ptr --> struct blob_data_v1 v1;
318 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
319 * blob_ptr + blob_size --> };
320 *
321 * It's important to check the actual number of bytes from the start
322 * of the sub-structure to the end of the blob data, and not just rely
323 * on something like,
324 *
325 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
326 *
327 * This is because the start of the sub-structure can vary based on
328 * how the compiler pads the overall structure.
329 */
330 if (blob_ptr && sub_ptr)
331 /* return zero if end of blob >= end of sub-struct */
332 return ((unsigned char *)blob_ptr + blob_size) <
333 ((unsigned char *)sub_ptr + sub_size);
334 return -EINVAL;
335}
336
Clarence Ipe78efb72016-06-24 18:35:21 -0400337static void _sde_plane_setup_csc(struct sde_plane *psde,
338 struct sde_plane_state *pstate,
339 struct sde_mdp_format_params *fmt)
340{
341 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
342 {
Clarence Ip373f8592016-05-26 00:58:42 -0400343 /* S15.16 format */
344 0x00012A00, 0x00000000, 0x00019880,
345 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
346 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400347 },
Clarence Ip373f8592016-05-26 00:58:42 -0400348 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400349 { 0xfff0, 0xff80, 0xff80,},
350 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400351 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400352 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400353 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400354 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400355 static const struct sde_csc_cfg sde_csc_NOP = {
356 {
Clarence Ip373f8592016-05-26 00:58:42 -0400357 /* identity matrix, S15.16 format */
358 0x10000, 0x00000, 0x00000,
359 0x00000, 0x10000, 0x00000,
360 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400361 },
Clarence Ip373f8592016-05-26 00:58:42 -0400362 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400363 { 0x0, 0x0, 0x0,},
364 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400365 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400366 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
367 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
368 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400369 struct sde_drm_csc *csc = NULL;
370 size_t csc_size = 0;
371 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400372
373 if (!psde->pipe_hw->ops.setup_csc)
374 return;
375
Clarence Ip5e2a9222016-06-26 22:38:24 -0400376 /* check for user space override */
377 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
378 if (csc) {
379 struct sde_csc_cfg cfg;
380 int i;
381
382 /* user space override */
383 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
384 switch (csc->version) {
385 case SDE_DRM_CSC_V1:
386 if (!_sde_plane_verify_blob(csc,
387 csc_size,
388 &csc->v1,
389 sizeof(struct sde_drm_csc_v1))) {
390 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
391 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400392 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400393 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
394 cfg.csc_pre_bv[i] =
395 csc->v1.pre_bias[i];
396 cfg.csc_post_bv[i] =
397 csc->v1.post_bias[i];
398 }
399 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
400 cfg.csc_pre_lv[i] =
401 csc->v1.pre_clamp[i];
402 cfg.csc_post_lv[i] =
403 csc->v1.post_clamp[i];
404 }
405 user_blob = true;
406 }
407 break;
408 default:
409 break;
410 }
411
412 if (!user_blob)
413 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
414 else
415 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
416 (struct sde_csc_cfg *)&cfg);
417 }
418
419 if (user_blob) {
420 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400421 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400422 /* revert to kernel default */
Clarence Ipdbde9832016-06-26 09:48:36 -0400423 } else if (SDE_FORMAT_IS_YUV(fmt)) {
Clarence Ip373f8592016-05-26 00:58:42 -0400424 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400425 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400426 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400427 }
Clarence Ip373f8592016-05-26 00:58:42 -0400428
429 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400430}
431
432static int _sde_plane_mode_set(struct drm_plane *plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700433 struct drm_crtc *crtc, struct drm_framebuffer *fb,
434 int crtc_x, int crtc_y,
435 unsigned int crtc_w, unsigned int crtc_h,
436 uint32_t src_x, uint32_t src_y,
437 uint32_t src_w, uint32_t src_h)
438{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400439 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400440 struct sde_plane_state *pstate;
441 const struct mdp_format *format;
442 uint32_t nplanes, pix_format, tmp;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400443 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
444 uint32_t src_fmt_flags;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400445 int i;
446 struct sde_mdp_format_params *fmt;
447 struct sde_hw_pixel_ext *pe;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400448 size_t sc_u_size = 0;
449 struct sde_drm_scaler *sc_u = NULL;
450 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400451
Clarence Ip4ce59322016-06-26 22:27:51 -0400452 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400453
Clarence Ip5e2a9222016-06-26 22:38:24 -0400454 if (!plane || !plane->state) {
455 DRM_ERROR("Invalid plane/state\n");
456 return -EINVAL;
457 }
458 if (!crtc || !fb) {
459 DRM_ERROR("Invalid crtc/fb\n");
460 return -EINVAL;
461 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400462
Clarence Ip5e2a9222016-06-26 22:38:24 -0400463 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400464 pstate = to_sde_plane_state(plane->state);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400465 nplanes = drm_format_num_planes(fb->pixel_format);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400466
467 format = to_mdp_format(msm_framebuffer_format(fb));
468 pix_format = format->base.pixel_format;
469
470 /* src values are in Q16 fixed point, convert to integer */
471 src_x = src_x >> 16;
472 src_y = src_y >> 16;
473 src_w = src_w >> 16;
474 src_h = src_h >> 16;
475
Clarence Ip4ce59322016-06-26 22:27:51 -0400476 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400477 fb->base.id, src_x, src_y, src_w, src_h,
478 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
479
480 /* update format configuration */
481 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400482 src_fmt_flags = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400483
484 psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
Clarence Ipe78efb72016-06-24 18:35:21 -0400485 fb->modifier[0]);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400486 psde->pipe_cfg.src.width = fb->width;
487 psde->pipe_cfg.src.height = fb->height;
488 psde->pipe_cfg.src.num_planes = nplanes;
489
Clarence Ip5e2a9222016-06-26 22:38:24 -0400490 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
491
Clarence Ip5e2a9222016-06-26 22:38:24 -0400492 /* flags */
493 DBG("Flags 0x%llX, rotation 0x%llX",
Clarence Ip4c1d9772016-06-26 09:35:38 -0400494 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
495 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
496 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400497 BIT(DRM_REFLECT_X))
498 src_fmt_flags |= SDE_SSPP_FLIP_LR;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400499 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400500 BIT(DRM_REFLECT_Y))
501 src_fmt_flags |= SDE_SSPP_FLIP_UD;
Clarence Ip4c1d9772016-06-26 09:35:38 -0400502 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400503 BIT(SDE_DRM_DEINTERLACE)) {
504 src_h /= 2;
505 src_y = DIV_ROUND_UP(src_y, 2);
506 src_y &= ~0x1;
507 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400508
509 psde->pipe_cfg.src_rect.x = src_x;
510 psde->pipe_cfg.src_rect.y = src_y;
511 psde->pipe_cfg.src_rect.w = src_w;
512 psde->pipe_cfg.src_rect.h = src_h;
513
514 psde->pipe_cfg.dst_rect.x = crtc_x;
515 psde->pipe_cfg.dst_rect.y = crtc_y;
516 psde->pipe_cfg.dst_rect.w = crtc_w;
517 psde->pipe_cfg.dst_rect.h = crtc_h;
518
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400519 /* get sde pixel format definition */
520 fmt = psde->pipe_cfg.src.format;
521
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400522 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400523 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400524
Clarence Ip5e2a9222016-06-26 22:38:24 -0400525 /* get scaler config from user space */
526 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
527 if (sc_u) {
528 switch (sc_u->version) {
529 case SDE_DRM_SCALER_V1:
530 if (!_sde_plane_verify_blob(sc_u,
531 sc_u_size,
532 &sc_u->v1,
533 sizeof(*sc_u1)))
534 sc_u1 = &sc_u->v1;
535 break;
536 default:
537 DBG("Unrecognized scaler blob v%lld", sc_u->version);
538 break;
539 }
540 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400541
Clarence Ip04ec67d2016-05-26 01:16:15 -0400542 /* decimation */
543 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
544 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
545 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
546 }
547
548 /* don't chroma subsample if decimating */
549 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
550 drm_format_horz_chroma_subsampling(pix_format);
551 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
552 drm_format_vert_chroma_subsampling(pix_format);
553
Clarence Ip5e2a9222016-06-26 22:38:24 -0400554 /* update scaler */
555 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
556 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
557 DBG("QSEED3 blob detected");
558 else
559 _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
560 crtc_h, &psde->scaler3_cfg, fmt,
561 chroma_subsmpl_h, chroma_subsmpl_v);
562 } else {
563 /* always calculate basic scaler config */
564 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
565 /* populate from user space */
566 for (i = 0; i < SDE_MAX_PLANES; i++) {
567 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
568 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
569 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
570 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400571
Clarence Ip5e2a9222016-06-26 22:38:24 -0400572 pe->horz_filter[i] = sc_u1->horz_filter[i];
573 pe->vert_filter[i] = sc_u1->vert_filter[i];
574 }
575 } else {
576 /* calculate phase steps */
577 _sde_plane_setup_scaler2(plane, src_w, crtc_w,
578 pe->phase_step_x,
579 pe->horz_filter, fmt, chroma_subsmpl_h);
580 _sde_plane_setup_scaler2(plane, src_h, crtc_h,
581 pe->phase_step_y,
582 pe->vert_filter, fmt, chroma_subsmpl_v);
583 }
584 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400585
Clarence Ip5e2a9222016-06-26 22:38:24 -0400586 /* update pixel extensions */
587 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
588 /* populate from user space */
589 for (i = 0; i < SDE_MAX_PLANES; i++) {
590 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
591 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
592 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
593 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
594 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
595 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
596 pe->roi_w[i] = sc_u1->lr.roi[i];
597
598 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
599 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
600 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
601 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
602 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
603 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
604 pe->roi_h[i] = sc_u1->tb.roi[i];
605 }
606 } else {
607 /* calculate left/right/top/bottom pixel extensions */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400608 tmp = DECIMATED_DIMENSION(src_w,
609 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400610 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400611 tmp &= ~0x1;
Clarence Ipe78efb72016-06-24 18:35:21 -0400612 _sde_plane_setup_pixel_ext(plane, src_w, crtc_w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400613 pe->phase_step_x,
614 pe->roi_w,
615 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400616 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400617 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400618
619 tmp = DECIMATED_DIMENSION(src_h,
620 psde->pipe_cfg.vert_decimation);
Clarence Ipe78efb72016-06-24 18:35:21 -0400621 _sde_plane_setup_pixel_ext(plane, src_h, crtc_h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400622 pe->phase_step_y,
623 pe->roi_h,
624 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400625 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400626 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400627
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400628 for (i = 0; i < SDE_MAX_PLANES; i++) {
629 if (pe->num_ext_pxls_left[i] >= 0)
630 pe->left_rpt[i] =
631 pe->num_ext_pxls_left[i];
632 else
633 pe->left_ftch[i] =
634 pe->num_ext_pxls_left[i];
635
636 if (pe->num_ext_pxls_right[i] >= 0)
637 pe->right_rpt[i] =
638 pe->num_ext_pxls_right[i];
639 else
640 pe->right_ftch[i] =
641 pe->num_ext_pxls_right[i];
642
643 if (pe->num_ext_pxls_top[i] >= 0)
644 pe->top_rpt[i] =
645 pe->num_ext_pxls_top[i];
646 else
647 pe->top_ftch[i] =
648 pe->num_ext_pxls_top[i];
649
650 if (pe->num_ext_pxls_btm[i] >= 0)
651 pe->btm_rpt[i] =
652 pe->num_ext_pxls_btm[i];
653 else
654 pe->btm_ftch[i] =
655 pe->num_ext_pxls_btm[i];
656 }
657 }
658
Clarence Ip4c1d9772016-06-26 09:35:38 -0400659 if (psde->pipe_hw->ops.setup_format)
660 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400661 &psde->pipe_cfg, src_fmt_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400662 if (psde->pipe_hw->ops.setup_rects)
663 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
664 &psde->pipe_cfg, &psde->pixel_ext);
665
Clarence Ipe78efb72016-06-24 18:35:21 -0400666 /* update sharpening */
667 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
668 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
669 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
670 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
671
672 if (psde->pipe_hw->ops.setup_sharpening)
673 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
674 &psde->sharp_cfg);
675
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400676 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400677 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400678 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400679
Clarence Ip5e2a9222016-06-26 22:38:24 -0400680 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400681}
682
683static int sde_plane_prepare_fb(struct drm_plane *plane,
684 const struct drm_plane_state *new_state)
685{
686 struct drm_framebuffer *fb = new_state->fb;
687 struct sde_plane *psde = to_sde_plane(plane);
688
689 if (!new_state->fb)
690 return 0;
691
Clarence Ipae4e60c2016-06-26 22:44:04 -0400692 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400693 return msm_framebuffer_prepare(fb, psde->mmu_id);
694}
695
696static void sde_plane_cleanup_fb(struct drm_plane *plane,
697 const struct drm_plane_state *old_state)
698{
699 struct drm_framebuffer *fb = old_state->fb;
700 struct sde_plane *psde = to_sde_plane(plane);
701
702 if (!fb)
703 return;
704
Clarence Ipae4e60c2016-06-26 22:44:04 -0400705 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400706 msm_framebuffer_cleanup(fb, psde->mmu_id);
707}
708
Clarence Ipdbde9832016-06-26 09:48:36 -0400709static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
710 struct sde_plane_state *pstate,
711 struct drm_framebuffer *fb)
712{
713 return 0;
714}
715
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400716static int sde_plane_atomic_check(struct drm_plane *plane,
717 struct drm_plane_state *state)
718{
Clarence Ipdbde9832016-06-26 09:48:36 -0400719 struct sde_plane *psde;
720 struct sde_plane_state *pstate;
721 struct drm_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400722 const struct mdp_format *format;
Clarence Ipdbde9832016-06-26 09:48:36 -0400723 struct sde_mdp_format_params *fmt;
724 size_t sc_u_size = 0;
725 struct sde_drm_scaler *sc_u = NULL;
726 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400727
Clarence Ipdbde9832016-06-26 09:48:36 -0400728 uint32_t src_x, src_y;
729 uint32_t src_w, src_h;
730 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
731 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
732 uint32_t upscale_max, downscale_max;
733
734 DBG();
735
736 if (!plane || !state) {
737 DRM_ERROR("Invalid plane/state\n");
738 ret = -EINVAL;
739 goto exit;
740 }
741
742 psde = to_sde_plane(plane);
743 pstate = to_sde_plane_state(state);
744 old_state = plane->state;
745
746 if (!psde->pipe_sblk) {
747 DRM_ERROR("Invalid plane catalog\n");
748 ret = -EINVAL;
749 goto exit;
750 }
751
752 /* get decimation config from user space */
753 deci_w = 0;
754 deci_h = 0;
755 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
756 if (sc_u) {
757 switch (sc_u->version) {
758 case SDE_DRM_SCALER_V1:
759 if (!_sde_plane_verify_blob(sc_u,
760 sc_u_size,
761 &sc_u->v1,
762 sizeof(struct sde_drm_scaler_v1))) {
763 deci_w = sc_u->v1.horz_decimate;
764 deci_h = sc_u->v1.vert_decimate;
765 }
766 break;
767 default:
768 DBG("Unrecognized scaler blob v%lld", sc_u->version);
769 break;
770 }
771 }
772
773 /* src values are in Q16 fixed point, convert to integer */
774 src_x = state->src_x >> 16;
775 src_y = state->src_y >> 16;
776 src_w = state->src_w >> 16;
777 src_h = state->src_h >> 16;
778
779 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
780 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
781
782 src_max_x = 0xFFFF;
783 src_max_y = 0xFFFF;
784 src_max_w = 0x3FFF;
785 src_max_h = 0x3FFF;
786 upscale_max = psde->pipe_sblk->maxupscale;
787 downscale_max = psde->pipe_sblk->maxdwnscale;
788
789 /*
790 * Including checks from mdss
791 * - mdss_mdp_overlay_req_check()
792 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400793 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400794 sde_plane_enabled(old_state), sde_plane_enabled(state));
795
796 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400797 /* determine SDE format definition. State's fb is valid here. */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400798 format = to_mdp_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400799 fmt = sde_mdp_get_format_params(format->base.pixel_format,
800 0 /* modifier */);
801
802 /* don't check for other errors after first failure */
803 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400804 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400805 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400806 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400807 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400808
Clarence Ipdbde9832016-06-26 09:48:36 -0400809 /* verify source size/region */
810 } else if (!src_w || !src_h ||
811 (src_w > src_max_w) || (src_h > src_max_h) ||
812 (src_x > src_max_x) || (src_y > src_max_y) ||
813 (src_x + src_w > src_max_x) ||
814 (src_y + src_h > src_max_y)) {
815 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
816 src_x, src_y, src_x + src_w,
817 src_y + src_h);
818 ret = -EINVAL;
819
820 /* require even source for YUV */
821 } else if (SDE_FORMAT_IS_YUV(fmt) &&
822 ((src_x & 0x1) || (src_y & 0x1) ||
823 (src_w & 0x1) || (src_h & 0x1))) {
824 DRM_ERROR("Invalid odd src res/pos for YUV\n");
825 ret = -EINVAL;
826
827 /* verify scaler requirements */
828 } else if (!(psde->features & SDE_SSPP_SCALER) &&
829 ((src_w != state->crtc_w) ||
830 (src_h != state->crtc_h))) {
831 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
832 src_w, src_h, state->crtc_w,
833 state->crtc_h);
834 ret = -EINVAL;
835
836 /* check decimated source width */
837 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
838 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
839 src_w, src_deci_w,
840 psde->pipe_sblk->maxlinewidth);
841 ret = -EINVAL;
842
843 /* check max scaler capability */
844 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
845 ((src_deci_h * upscale_max) < state->crtc_h) ||
846 ((state->crtc_w * downscale_max) < src_deci_w) ||
847 ((state->crtc_h * downscale_max) < src_deci_h)) {
848 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
849 src_deci_w, src_deci_h,
850 state->crtc_w, state->crtc_h);
851 ret = -EINVAL;
852
853 /* check frame buffer */
854 } else if (_sde_plane_atomic_check_fb(
855 psde, pstate, state->fb)) {
856 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400857 }
858
Clarence Ipdbde9832016-06-26 09:48:36 -0400859 /* check decimation (and bwc/fetch mode) */
860 if (!ret && (deci_w || deci_h)) {
861 if (SDE_FORMAT_IS_UBWC(fmt)) {
862 DRM_ERROR("No decimation with BWC\n");
863 ret = -EINVAL;
864 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
865 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
866 DRM_ERROR("Too much decimation requested\n");
867 ret = -EINVAL;
868 } else if (fmt->fetch_mode != SDE_MDP_FETCH_LINEAR) {
869 DRM_ERROR("Decimation requires linear fetch\n");
870 ret = -EINVAL;
871 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400872 }
873 }
874
Clarence Ipdbde9832016-06-26 09:48:36 -0400875 if (!ret) {
876 if (sde_plane_enabled(state) &&
877 sde_plane_enabled(old_state)) {
878 bool full_modeset = false;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400879
Clarence Ipdbde9832016-06-26 09:48:36 -0400880 if (state->fb->pixel_format !=
881 old_state->fb->pixel_format) {
882 DBG("%s: format change!", psde->pipe_name);
883 full_modeset = true;
884 }
885 if (state->src_w != old_state->src_w ||
886 state->src_h != old_state->src_h) {
887 DBG("%s: src_w change!", psde->pipe_name);
888 full_modeset = true;
889 }
890 if (to_sde_plane_state(old_state)->pending) {
891 DBG("%s: still pending!", psde->pipe_name);
892 full_modeset = true;
893 }
894 if (full_modeset) {
895 struct drm_crtc_state *crtc_state =
896 drm_atomic_get_crtc_state(state->state,
897 state->crtc);
898 crtc_state->mode_changed = true;
899 to_sde_plane_state(state)->mode_changed = true;
900 }
901 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400902 to_sde_plane_state(state)->mode_changed = true;
903 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400904 }
905
Clarence Ipdbde9832016-06-26 09:48:36 -0400906exit:
907 return ret;
908}
909
910void sde_plane_complete_flip(struct drm_plane *plane)
911{
912 if (plane && plane->state)
913 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700914}
915
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400916static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -0400917 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700918{
Clarence Ip5e2a9222016-06-26 22:38:24 -0400919 struct sde_plane *sde_plane;
920 struct drm_plane_state *state;
921 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400922
Clarence Ip5e2a9222016-06-26 22:38:24 -0400923 if (!plane || !plane->state) {
924 DRM_ERROR("Invalid plane/state\n");
925 return;
926 }
927
928 sde_plane = to_sde_plane(plane);
929 state = plane->state;
930 pstate = to_sde_plane_state(state);
931
Clarence Ipae4e60c2016-06-26 22:44:04 -0400932 DBG("%s: update", sde_plane->pipe_name);
933
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400934 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400935 pstate->pending = true;
936 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400937 int ret;
938
Clarence Ip5e2a9222016-06-26 22:38:24 -0400939 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -0400940 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400941 state->crtc, state->fb,
942 state->crtc_x, state->crtc_y,
943 state->crtc_w, state->crtc_h,
944 state->src_x, state->src_y,
945 state->src_w, state->src_h);
946 /* atomic_check should have ensured that this doesn't fail */
947 WARN_ON(ret < 0);
948 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400949 _sde_plane_set_scanout(plane, pstate,
950 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400951 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400952}
953
Clarence Ipae4e60c2016-06-26 22:44:04 -0400954static inline struct drm_property **_sde_plane_get_property_entry(
955 struct drm_device *dev, enum msm_mdp_plane_property property)
956{
957 struct msm_drm_private *priv;
958
959 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
960 return NULL;
961
962 priv = dev->dev_private;
963
964 return &(priv->plane_property[property]);
965}
966
Clarence Ipe78efb72016-06-24 18:35:21 -0400967static void _sde_plane_install_range_property(struct drm_plane *plane,
968 struct drm_device *dev, const char *name,
969 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400970 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -0400971{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400972 struct drm_property **prop;
973
974 prop = _sde_plane_get_property_entry(dev, property);
975 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400976 /* only create the property once */
977 if (*prop == 0) {
978 *prop = drm_property_create_range(dev,
979 0 /* flags */, name, min, max);
980 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400981 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -0400982 }
983
Clarence Ipae4e60c2016-06-26 22:44:04 -0400984 /* save init value for later */
985 to_sde_plane(plane)->property_defaults[property] = init;
986
Clarence Ipe78efb72016-06-24 18:35:21 -0400987 /* always attach property, if created */
988 if (*prop)
989 drm_object_attach_property(&plane->base, *prop, init);
990 }
991}
992
Clarence Ip5e2a9222016-06-26 22:38:24 -0400993static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400994 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -0400995{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400996 struct sde_plane *psde;
997 struct drm_property **prop;
998
999 prop = _sde_plane_get_property_entry(dev, property);
1000 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001001 /* only create the property once */
1002 if (*prop == 0) {
1003 *prop = drm_mode_create_rotation_property(dev,
1004 BIT(DRM_REFLECT_X) |
1005 BIT(DRM_REFLECT_Y));
1006 if (*prop == 0)
1007 DRM_ERROR("Create rotation property failed\n");
1008 }
1009
Clarence Ipae4e60c2016-06-26 22:44:04 -04001010 /* save init value for later */
1011 psde = to_sde_plane(plane);
1012 psde->property_defaults[property] = 0;
1013
Clarence Ip5e2a9222016-06-26 22:38:24 -04001014 /* always attach property, if created */
1015 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001016 drm_object_attach_property(&plane->base, *prop,
1017 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001018 }
1019}
1020
1021static void _sde_plane_install_enum_property(struct drm_plane *plane,
1022 struct drm_device *dev, const char *name, int is_bitmask,
1023 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001024 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001025{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001026 struct sde_plane *psde;
1027 struct drm_property **prop;
1028
1029 prop = _sde_plane_get_property_entry(dev, property);
1030 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001031 /* only create the property once */
1032 if (*prop == 0) {
1033 /* 'bitmask' is a special type of 'enum' */
1034 if (is_bitmask)
1035 *prop = drm_property_create_bitmask(dev,
1036 DRM_MODE_PROP_BITMASK, name,
1037 values, num_values, -1);
1038 else
1039 *prop = drm_property_create_enum(dev,
1040 DRM_MODE_PROP_ENUM, name,
1041 values, num_values);
1042 if (*prop == 0)
1043 DRM_ERROR("Create %s property failed\n", name);
1044 }
1045
Clarence Ipae4e60c2016-06-26 22:44:04 -04001046 /* save init value for later */
1047 psde = to_sde_plane(plane);
1048 psde->property_defaults[property] = 0;
1049
Clarence Ip5e2a9222016-06-26 22:38:24 -04001050 /* always attach property, if created */
1051 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001052 drm_object_attach_property(&plane->base, *prop,
1053 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001054 }
1055}
1056
Clarence Ipe78efb72016-06-24 18:35:21 -04001057static void _sde_plane_install_blob_property(struct drm_plane *plane,
1058 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001059 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001060{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001061 struct sde_plane *psde;
1062 struct drm_property **prop;
1063
1064 prop = _sde_plane_get_property_entry(dev, property);
1065 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001066 /* only create the property once */
1067 if (*prop == 0) {
1068 /* use 'create' for blob property place holder */
1069 *prop = drm_property_create(dev,
1070 DRM_MODE_PROP_BLOB, name, 0);
1071 if (*prop == 0)
1072 DRM_ERROR("Create %s property failed\n", name);
1073 }
1074
Clarence Ipae4e60c2016-06-26 22:44:04 -04001075 /* save init value for later */
1076 psde = to_sde_plane(plane);
1077 psde->property_defaults[property] = 0;
1078
Clarence Ip5e2a9222016-06-26 22:38:24 -04001079 /* always attach property, if created */
1080 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001081 drm_object_attach_property(&plane->base, *prop,
1082 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001083 }
Clarence Ipe78efb72016-06-24 18:35:21 -04001084}
1085
Clarence Ip4c1d9772016-06-26 09:35:38 -04001086static int _sde_plane_get_property_index(struct drm_plane *plane,
1087 struct drm_property *property)
1088{
1089 struct drm_property **prop_array;
1090 int idx = PLANE_PROP_COUNT;
1091
1092 if (!plane) {
1093 DRM_ERROR("Invalid plane\n");
1094 } else if (!plane->dev || !plane->dev->dev_private) {
1095 /* don't access dev_private if !dev */
1096 DRM_ERROR("Invalid device\n");
1097 } else if (!property) {
1098 DRM_ERROR("Incoming property is NULL\n");
1099 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001100 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001101 if (!prop_array)
1102 /* should never hit this */
1103 DRM_ERROR("Invalid property array\n");
1104
1105 /* linear search is okay */
1106 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
1107 if (prop_array[idx] == property)
1108 break;
1109 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001110
1111 if (idx == PLANE_PROP_COUNT)
1112 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001113 }
1114
1115 return idx;
1116}
1117
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001118/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -04001119static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001120 struct drm_mode_object *obj,
1121 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001122{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001123 static const struct drm_prop_enum_list e_blend_op[] = {
1124 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1125 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1126 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1127 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1128 };
1129 static const struct drm_prop_enum_list e_src_config[] = {
1130 {SDE_DRM_DEINTERLACE, "deinterlace"}
1131 };
1132 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001133 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001134
Clarence Ip4ce59322016-06-26 22:27:51 -04001135 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001136
Clarence Ip4c1d9772016-06-26 09:35:38 -04001137 if (!psde || !psde->pipe_sblk || !catalog) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001138 DRM_ERROR("Failed to identify catalog definition\n");
1139 return;
1140 }
1141
1142 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001143 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
1144 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1145 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1146 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001147
Clarence Ip5e2a9222016-06-26 22:38:24 -04001148 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001149 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001150
Clarence Ipae4e60c2016-06-26 22:44:04 -04001151 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
1152 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001153
1154 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001155 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001156
Clarence Ip04ec67d2016-05-26 01:16:15 -04001157 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001158 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1159 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001160 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001161 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1162 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001163 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001164
Clarence Ipe78efb72016-06-24 18:35:21 -04001165 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001166 if (psde->features & SDE_SSPP_SCALER)
1167 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001168 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001169 if (psde->features & BIT(SDE_SSPP_CSC))
1170 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001171 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001172}
1173
1174static int sde_plane_atomic_set_property(struct drm_plane *plane,
1175 struct drm_plane_state *state, struct drm_property *property,
1176 uint64_t val)
1177{
Clarence Ip730e7192016-06-26 22:45:09 -04001178 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001179 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001180 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001181 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001182
Clarence Ip4c1d9772016-06-26 09:35:38 -04001183 idx = _sde_plane_get_property_index(plane, property);
1184 if (!state) {
1185 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001186 } else if (idx >= PLANE_PROP_COUNT) {
1187 DRM_ERROR("Invalid property\n");
1188 } else {
1189 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001190 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001191
Clarence Ip730e7192016-06-26 22:45:09 -04001192 DBG("%s: %d <= %d", psde->pipe_name, idx, (int)val);
1193
Clarence Ipae4e60c2016-06-26 22:44:04 -04001194 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001195 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1196 (idx < PLANE_PROP_BLOBCOUNT)) {
1197 /* DRM lookup also takes a reference */
1198 blob = drm_property_lookup_blob(plane->dev,
1199 (uint32_t)val);
1200 if (!blob) {
1201 DRM_ERROR("Blob not found\n");
1202 val = 0;
1203 } else {
1204 DBG("Blob %u saved", blob->base.id);
1205 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001206
Clarence Ip4c1d9772016-06-26 09:35:38 -04001207 /* save blobs for later */
1208 pr_blob = &pstate->property_blobs[idx];
1209 /* need to clear previous reference */
1210 if (*pr_blob)
1211 drm_property_unreference_blob(*pr_blob);
1212 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001213 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001214 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1215 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001216 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001217 pstate->property_values[idx] = val;
1218 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001219 }
1220
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001221 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001222}
1223
1224static int sde_plane_set_property(struct drm_plane *plane,
1225 struct drm_property *property, uint64_t val)
1226{
Clarence Ip4ce59322016-06-26 22:27:51 -04001227 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001228
1229 if (!plane)
1230 return -EINVAL;
1231
Clarence Ipae4e60c2016-06-26 22:44:04 -04001232 return sde_plane_atomic_set_property(plane,
1233 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001234}
1235
1236static int sde_plane_atomic_get_property(struct drm_plane *plane,
1237 const struct drm_plane_state *state,
1238 struct drm_property *property, uint64_t *val)
1239{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001240 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001241 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001242
Clarence Ip4c1d9772016-06-26 09:35:38 -04001243 idx = _sde_plane_get_property_index(plane, property);
1244 if (!state) {
1245 DRM_ERROR("Invalid state\n");
1246 } else if (!val) {
1247 DRM_ERROR("Value pointer is NULL\n");
1248 } else if (idx < PLANE_PROP_COUNT) {
1249 pstate = to_sde_plane_state(state);
1250
1251 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001252 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001253 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001254 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001255
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001256 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001257}
1258
Clarence Ip730e7192016-06-26 22:45:09 -04001259static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
1260{
1261 struct sde_plane *psde;
1262 struct sde_plane_state *pstate;
1263
1264 if (!plane)
1265 return NULL;
1266
1267 psde = to_sde_plane(plane);
1268 pstate = NULL;
1269
1270 mutex_lock(&psde->lock);
1271 if (psde->state_cache_size)
1272 pstate = psde->state_cache[--(psde->state_cache_size)];
1273 mutex_unlock(&psde->lock);
1274
1275 if (!pstate)
1276 pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
1277
1278 return pstate;
1279}
1280
1281static void sde_plane_free_state(struct drm_plane *plane,
1282 struct sde_plane_state *pstate)
1283{
1284 struct sde_plane *psde;
1285
1286 if (!plane || !pstate)
1287 return;
1288
1289 psde = to_sde_plane(plane);
1290
1291 mutex_lock(&psde->lock);
1292 if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
1293 psde->state_cache[(psde->state_cache_size)++] = pstate;
1294 mutex_unlock(&psde->lock);
1295 } else {
1296 mutex_unlock(&psde->lock);
1297 kfree(pstate);
1298 }
1299}
1300
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001301static void sde_plane_destroy(struct drm_plane *plane)
1302{
Clarence Ip4ce59322016-06-26 22:27:51 -04001303 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001304
Clarence Ip4ce59322016-06-26 22:27:51 -04001305 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001306
Clarence Ip4ce59322016-06-26 22:27:51 -04001307 if (plane) {
1308 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001309
Clarence Ip4ce59322016-06-26 22:27:51 -04001310 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001311
Clarence Ip730e7192016-06-26 22:45:09 -04001312 mutex_destroy(&psde->lock);
1313
Clarence Ip4ce59322016-06-26 22:27:51 -04001314 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001315
Clarence Ip4ce59322016-06-26 22:27:51 -04001316 /* this will destroy the states as well */
1317 drm_plane_cleanup(plane);
1318
Clarence Ip4c1d9772016-06-26 09:35:38 -04001319 if (psde->pipe_hw)
1320 sde_hw_sspp_destroy(psde->pipe_hw);
1321
Clarence Ip730e7192016-06-26 22:45:09 -04001322 /* free state cache */
1323 while (psde->state_cache_size > 0)
1324 kfree(psde->state_cache[--(psde->state_cache_size)]);
1325
Clarence Ip4ce59322016-06-26 22:27:51 -04001326 kfree(psde);
1327 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001328}
1329
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001330static void sde_plane_destroy_state(struct drm_plane *plane,
1331 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001332{
Clarence Ipe78efb72016-06-24 18:35:21 -04001333 struct sde_plane_state *pstate;
1334 int i;
1335
Clarence Ipae4e60c2016-06-26 22:44:04 -04001336 if (!plane || !state) {
1337 DRM_ERROR("Invalid plane/state\n");
1338 return;
1339 }
1340
Clarence Ip730e7192016-06-26 22:45:09 -04001341 pstate = to_sde_plane_state(state);
1342
1343 DBG("");
1344
Clarence Ipe78efb72016-06-24 18:35:21 -04001345 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001346 if (state->fb)
1347 drm_framebuffer_unreference(state->fb);
1348
Clarence Ipae4e60c2016-06-26 22:44:04 -04001349 /* remove ref count for fence */
1350 if (pstate->sync_fence)
1351 sde_sync_put(pstate->sync_fence);
1352
Clarence Ipe78efb72016-06-24 18:35:21 -04001353 /* remove ref count for blobs */
1354 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1355 if (pstate->property_blobs[i])
1356 drm_property_unreference_blob(
1357 pstate->property_blobs[i]);
Clarence Ip730e7192016-06-26 22:45:09 -04001358 sde_plane_free_state(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001359}
1360
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001361static struct drm_plane_state *
1362sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001363{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001364 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001365 struct sde_plane_state *old_state;
Clarence Ipe78efb72016-06-24 18:35:21 -04001366 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001367
Clarence Ip730e7192016-06-26 22:45:09 -04001368 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001369 return NULL;
1370
Clarence Ip730e7192016-06-26 22:45:09 -04001371 old_state = to_sde_plane_state(plane->state);
1372 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001373
1374 DBG("");
1375
Clarence Ip730e7192016-06-26 22:45:09 -04001376 if (!pstate)
1377 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001378
Clarence Ip730e7192016-06-26 22:45:09 -04001379 memcpy(pstate, old_state, sizeof(*pstate));
Clarence Ipae4e60c2016-06-26 22:44:04 -04001380
Clarence Ip730e7192016-06-26 22:45:09 -04001381 /* add ref count for frame buffer */
1382 if (pstate->base.fb)
1383 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001384
Clarence Ip730e7192016-06-26 22:45:09 -04001385 /* add ref count for fence */
1386 if (pstate->sync_fence) {
1387 pstate->sync_fence = 0;
1388 _sde_plane_update_sync_fence(plane, pstate, pstate->
1389 property_values[PLANE_PROP_SYNC_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001390 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001391
Clarence Ip730e7192016-06-26 22:45:09 -04001392 /* add ref count for blobs */
1393 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1394 if (pstate->property_blobs[i])
1395 drm_property_reference_blob(
1396 pstate->property_blobs[i]);
1397
1398 pstate->mode_changed = false;
1399 pstate->pending = false;
1400
1401 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001402}
1403
1404static void sde_plane_reset(struct drm_plane *plane)
1405{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001406 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001407 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001408 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001409
Clarence Ipae4e60c2016-06-26 22:44:04 -04001410 if (!plane) {
1411 DRM_ERROR("Invalid plane\n");
1412 return;
1413 }
1414
Clarence Ip730e7192016-06-26 22:45:09 -04001415 psde = to_sde_plane(plane);
1416 DBG("%s", psde->pipe_name);
1417
Clarence Ipae4e60c2016-06-26 22:44:04 -04001418 /* remove previous state, if present */
1419 if (plane->state)
1420 sde_plane_destroy_state(plane, plane->state);
1421 plane->state = 0;
1422
Clarence Ip730e7192016-06-26 22:45:09 -04001423 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001424 if (!pstate) {
Clarence Ip730e7192016-06-26 22:45:09 -04001425 DRM_ERROR("Failed to (re)allocate plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001426 return;
1427 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001428
Clarence Ip730e7192016-06-26 22:45:09 -04001429 memset(pstate, 0, sizeof(*pstate));
1430
Clarence Ipae4e60c2016-06-26 22:44:04 -04001431 /* assign default property values */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001432 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1433 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001434
1435 pstate->base.plane = plane;
1436
1437 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001438}
1439
1440static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001441 .update_plane = drm_atomic_helper_update_plane,
1442 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001443 .destroy = sde_plane_destroy,
1444 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001445 .atomic_set_property = sde_plane_atomic_set_property,
1446 .atomic_get_property = sde_plane_atomic_get_property,
1447 .reset = sde_plane_reset,
1448 .atomic_duplicate_state = sde_plane_duplicate_state,
1449 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001450};
1451
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001452static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1453 .prepare_fb = sde_plane_prepare_fb,
1454 .cleanup_fb = sde_plane_cleanup_fb,
1455 .atomic_check = sde_plane_atomic_check,
1456 .atomic_update = sde_plane_atomic_update,
1457};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001458
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001459enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001460{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001461 struct sde_plane *sde_plane = to_sde_plane(plane);
1462
1463 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001464}
1465
Clarence Ip4ce59322016-06-26 22:27:51 -04001466static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1467{
1468 const struct sde_sspp_sub_blks *sblk = 0;
1469 const struct sde_sspp_cfg *cfg = 0;
1470
1471 if (psde && psde->pipe_hw)
1472 cfg = psde->pipe_hw->cap;
1473 if (cfg)
1474 sblk = cfg->sblk;
1475
1476 if (kms && sblk) {
1477 /* create overall sub-directory for the pipe */
1478 psde->debugfs_root =
1479 debugfs_create_dir(psde->pipe_name,
1480 sde_debugfs_get_root(kms));
1481 if (psde->debugfs_root) {
1482 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001483 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001484 psde->debugfs_root, &psde->features);
1485
1486 /* add register dump support */
1487 sde_debugfs_setup_regset32(&psde->debugfs_src,
1488 sblk->src_blk.base + cfg->base,
1489 sblk->src_blk.len,
1490 kms->mmio);
1491 sde_debugfs_create_regset32("src_blk", 0444,
1492 psde->debugfs_root, &psde->debugfs_src);
1493
1494 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1495 sblk->scaler_blk.base + cfg->base,
1496 sblk->scaler_blk.len,
1497 kms->mmio);
1498 sde_debugfs_create_regset32("scaler_blk", 0444,
1499 psde->debugfs_root,
1500 &psde->debugfs_scaler);
1501
1502 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1503 sblk->csc_blk.base + cfg->base,
1504 sblk->csc_blk.len,
1505 kms->mmio);
1506 sde_debugfs_create_regset32("csc_blk", 0444,
1507 psde->debugfs_root, &psde->debugfs_csc);
1508 }
1509 }
1510}
1511
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001512/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001513struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001514 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001515{
1516 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001517 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001518 struct msm_drm_private *priv;
1519 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001520 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001521 int ret = -EINVAL;
1522
1523 if (!dev) {
1524 DRM_ERROR("[%u]Device is NULL\n", pipe);
1525 goto exit;
1526 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001527
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001528 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001529 if (!priv) {
1530 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1531 goto exit;
1532 }
1533
1534 if (!priv->kms) {
1535 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1536 goto exit;
1537 }
1538 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001539
Clarence Ip4c1d9772016-06-26 09:35:38 -04001540 if (!kms->catalog) {
1541 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1542 goto exit;
1543 }
1544
Clarence Ip4ce59322016-06-26 22:27:51 -04001545 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001546 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1547 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001548 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001549 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001550 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001551 }
1552
Clarence Ip4c1d9772016-06-26 09:35:38 -04001553 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001554 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001555 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001556 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001557
Clarence Ip4c1d9772016-06-26 09:35:38 -04001558 /* initialize underlying h/w driver */
1559 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1560 if (IS_ERR(psde->pipe_hw)) {
1561 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1562 ret = PTR_ERR(psde->pipe_hw);
1563 goto clean_plane;
1564 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1565 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1566 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001567 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001568
1569 /* cache features mask for later */
1570 psde->features = psde->pipe_hw->cap->features;
1571 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1572
1573 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001574 psde->nformats = mdp_get_formats(psde->formats,
1575 ARRAY_SIZE(psde->formats),
1576 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001577 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001578
Clarence Ip4c1d9772016-06-26 09:35:38 -04001579 if (!psde->nformats) {
1580 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1581 goto clean_sspp;
1582 }
1583
1584 if (psde->features & BIT(SDE_SSPP_CURSOR))
1585 type = DRM_PLANE_TYPE_CURSOR;
1586 else if (primary_plane)
1587 type = DRM_PLANE_TYPE_PRIMARY;
1588 else
1589 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001590 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1591 psde->formats, psde->nformats,
1592 type);
1593 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001594 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001595
Clarence Ip4c1d9772016-06-26 09:35:38 -04001596 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001597 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001598
Clarence Ip4c1d9772016-06-26 09:35:38 -04001599 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001600
Clarence Ip4ce59322016-06-26 22:27:51 -04001601 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001602 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001603
Clarence Ip730e7192016-06-26 22:45:09 -04001604 mutex_init(&psde->lock);
1605
Clarence Ip4ce59322016-06-26 22:27:51 -04001606 _sde_plane_init_debugfs(psde, kms);
1607
Clarence Ip4c1d9772016-06-26 09:35:38 -04001608 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001609 return plane;
1610
Clarence Ip4c1d9772016-06-26 09:35:38 -04001611clean_sspp:
1612 if (psde && psde->pipe_hw)
1613 sde_hw_sspp_destroy(psde->pipe_hw);
1614clean_plane:
1615 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001616exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001617 return ERR_PTR(ret);
1618}