blob: 5dd60d6a40a0f11156a42db19e702668e0b01543 [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
Clarence Ipcb410d42016-06-26 22:52:33 -040095int sde_plane_wait_sync_fence(struct drm_plane *plane)
Clarence Ipae4e60c2016-06-26 22:44:04 -040096{
97 struct sde_plane_state *pstate;
Clarence Ipcb410d42016-06-26 22:52:33 -040098 void *sync_fence;
99 long wait_ms;
100 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400101
102 if (!plane) {
103 DRM_ERROR("Invalid plane\n");
104 } else if (!plane->state) {
105 DRM_ERROR("Invalid plane state\n");
106 } else {
107 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -0400108 sync_fence = pstate->sync_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400109
Clarence Ipcb410d42016-06-26 22:52:33 -0400110 if (sync_fence) {
111 wait_ms = (long)sde_plane_get_property(pstate,
112 PLANE_PROP_SYNC_FENCE_TIMEOUT);
113
114 DBG("%s", to_sde_plane(plane)->pipe_name);
115 ret = sde_sync_wait(sync_fence, wait_ms);
116 if (!ret)
117 DBG("signaled");
118 else if (ret == -ETIME)
119 DRM_ERROR("timeout\n");
120 else
121 DRM_ERROR("error %d\n", ret);
122 } else {
123 ret = 0;
124 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400125 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400126 return ret;
127}
128
Clarence Ipe78efb72016-06-24 18:35:21 -0400129static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400130 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400131 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
132{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400133 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400134 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400135 int i;
136
Clarence Ipae4e60c2016-06-26 22:44:04 -0400137 if (!plane || !pstate || !pipe_cfg || !fb)
138 return;
139
140 psde = to_sde_plane(plane);
141
142 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400143 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400144 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400145 BIT(SDE_DRM_DEINTERLACE))
146 shift = 1;
147 else
148 shift = 0;
149
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400150 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
151 while (i) {
152 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400153 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400154 }
155
156 /* address */
157 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
158 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
159 psde->mmu_id, i);
160
161 /* hw driver */
162 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
163 }
164}
165
Clarence Ipcb410d42016-06-26 22:52:33 -0400166static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400167 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
168 struct sde_hw_scaler3_cfg *scale_cfg,
169 struct sde_mdp_format_params *fmt,
170 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
171{
172}
173
Clarence Ipcb410d42016-06-26 22:52:33 -0400174/**
175 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
176 * @psde: Pointer to SDE plane object
177 * @src: Source size
178 * @dst: Destination size
179 * @phase_steps: Pointer to output array for phase steps
180 * @filter: Pointer to output array for filter type
181 * @fmt: Pointer to format definition
182 * @chroma_subsampling: Subsampling amount for chroma channel
183 *
184 * Returns: 0 on success
185 */
186static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400187 uint32_t src, uint32_t dst, uint32_t *phase_steps,
188 enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
189 uint32_t chroma_subsampling)
190{
Clarence Ipcb410d42016-06-26 22:52:33 -0400191 if (!psde || !phase_steps || !filter || !fmt) {
192 DRM_ERROR("Invalid arguments\n");
193 return -EINVAL;
194 }
195
Clarence Ip4c1d9772016-06-26 09:35:38 -0400196 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400197 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400198 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400199 phase_steps[SDE_SSPP_COMP_1_2] =
200 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
201 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
202 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400203
204 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400205 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400206 filter[SDE_SSPP_COMP_3] =
207 (src <= dst) ? SDE_MDP_SCALE_FILTER_BIL :
208 SDE_MDP_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400209
Clarence Ipdbde9832016-06-26 09:48:36 -0400210 if (SDE_FORMAT_IS_YUV(fmt)) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400211 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_CA;
212 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
213 } else {
214 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
215 filter[SDE_SSPP_COMP_1_2] =
216 SDE_MDP_SCALE_FILTER_NEAREST;
217 }
218 } else {
219 /* disable scaler */
Clarence Ipcb410d42016-06-26 22:52:33 -0400220 DBG("Disable scaler");
Clarence Ipe78efb72016-06-24 18:35:21 -0400221 filter[SDE_SSPP_COMP_0] = SDE_MDP_SCALE_FILTER_MAX;
222 filter[SDE_SSPP_COMP_1_2] = SDE_MDP_SCALE_FILTER_MAX;
223 filter[SDE_SSPP_COMP_3] = SDE_MDP_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400224 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400225 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400226}
227
Clarence Ipcb410d42016-06-26 22:52:33 -0400228/**
229 * _sde_plane_setup_pixel_ext - determine default pixel extension values
230 * @psde: Pointer to SDE plane object
231 * @src: Source size
232 * @dst: Destination size
233 * @decimated_src: Source size after decimation, if any
234 * @phase_steps: Pointer to output array for phase steps
235 * @out_src: Output array for pixel extension values
236 * @out_edge1: Output array for pixel extension first edge
237 * @out_edge2: Output array for pixel extension second edge
238 * @filter: Pointer to array for filter type
239 * @fmt: Pointer to format definition
240 * @chroma_subsampling: Subsampling amount for chroma channel
241 * @post_compare: Whether to chroma subsampled source size for comparisions
242 */
243static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400244 uint32_t src, uint32_t dst, uint32_t decimated_src,
245 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400246 int *out_edge2, enum sde_hw_filter *filter,
247 struct sde_mdp_format_params *fmt, uint32_t chroma_subsampling,
248 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400249{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400250 int64_t edge1, edge2, caf;
251 uint32_t src_work;
252 int i, tmp;
253
Clarence Ipcb410d42016-06-26 22:52:33 -0400254 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400255 out_edge2 && filter && fmt) {
256 /* handle CAF for YUV formats */
Clarence Ipdbde9832016-06-26 09:48:36 -0400257 if (SDE_FORMAT_IS_YUV(fmt) &&
258 *filter == SDE_MDP_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400259 caf = PHASE_STEP_UNIT_SCALE;
260 else
261 caf = 0;
262
263 for (i = 0; i < SDE_MAX_PLANES; i++) {
264 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400265 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400266 src_work /= chroma_subsampling;
267 if (post_compare)
268 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400269 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400270 /* unity */
271 edge1 = 0;
272 edge2 = 0;
273 } else if (dst >= src) {
274 /* upscale */
275 edge1 = (1 << PHASE_RESIDUAL);
276 edge1 -= caf;
277 edge2 = (1 << PHASE_RESIDUAL);
278 edge2 += (dst - 1) * *(phase_steps + i);
279 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
280 edge2 += caf;
281 edge2 = -(edge2);
282 } else {
283 /* downscale */
284 edge1 = 0;
285 edge2 = (dst - 1) * *(phase_steps + i);
286 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
287 edge2 += *(phase_steps + i);
288 edge2 = -(edge2);
289 }
290
291 /* only enable CAF for luma plane */
292 caf = 0;
293
294 /* populate output arrays */
295 *(out_src + i) = src_work;
296
297 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400298 if (edge1 >= 0) {
299 tmp = (uint32_t)edge1;
300 tmp >>= PHASE_STEP_SHIFT;
301 *(out_edge1 + i) = -tmp;
302 } else {
303 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400304 *(out_edge1 + i) =
305 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
306 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400307 }
308 if (edge2 >= 0) {
309 tmp = (uint32_t)edge2;
310 tmp >>= PHASE_STEP_SHIFT;
311 *(out_edge2 + i) = -tmp;
312 } else {
313 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400314 *(out_edge2 + i) =
315 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
316 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400317 }
318 }
319 }
320}
321
Clarence Ip5e2a9222016-06-26 22:38:24 -0400322static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
323 enum msm_mdp_plane_property property, size_t *byte_len)
324{
325 struct drm_property_blob *blob;
326 size_t len = 0;
327 void *ret = 0;
328
Clarence Ip4c1d9772016-06-26 09:35:38 -0400329 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
330 DRM_ERROR("Invalid argument(s)\n");
331 } else {
332 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400333 if (blob) {
334 len = blob->length;
335 ret = &blob->data;
336 }
337 }
338
339 if (byte_len)
340 *byte_len = len;
341
342 return ret;
343}
344
345/**
346 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
347 * sub-structure
348 * @blob_ptr: Pointer to start of incoming blob data
349 * @blob_size: Size of incoming blob data, in bytes
350 * @sub_ptr: Pointer to start of desired sub-structure
351 * @sub_size: Required size of sub-structure, in bytes
352 */
353static int _sde_plane_verify_blob(void *blob_ptr,
354 size_t blob_size,
355 void *sub_ptr,
356 size_t sub_size)
357{
358 /*
359 * Use the blob size provided by drm to check if there are enough
360 * bytes from the start of versioned sub-structures to the end of
361 * blob data:
362 *
363 * e.g.,
364 * blob_ptr --> struct blob_data {
365 * uint32_t version;
366 * sub_ptr --> struct blob_data_v1 v1;
367 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
368 * blob_ptr + blob_size --> };
369 *
370 * It's important to check the actual number of bytes from the start
371 * of the sub-structure to the end of the blob data, and not just rely
372 * on something like,
373 *
374 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
375 *
376 * This is because the start of the sub-structure can vary based on
377 * how the compiler pads the overall structure.
378 */
379 if (blob_ptr && sub_ptr)
380 /* return zero if end of blob >= end of sub-struct */
381 return ((unsigned char *)blob_ptr + blob_size) <
382 ((unsigned char *)sub_ptr + sub_size);
383 return -EINVAL;
384}
385
Clarence Ipe78efb72016-06-24 18:35:21 -0400386static void _sde_plane_setup_csc(struct sde_plane *psde,
387 struct sde_plane_state *pstate,
388 struct sde_mdp_format_params *fmt)
389{
390 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
391 {
Clarence Ip373f8592016-05-26 00:58:42 -0400392 /* S15.16 format */
393 0x00012A00, 0x00000000, 0x00019880,
394 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
395 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400396 },
Clarence Ip373f8592016-05-26 00:58:42 -0400397 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400398 { 0xfff0, 0xff80, 0xff80,},
399 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400400 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400401 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400402 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400403 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400404 static const struct sde_csc_cfg sde_csc_NOP = {
405 {
Clarence Ip373f8592016-05-26 00:58:42 -0400406 /* identity matrix, S15.16 format */
407 0x10000, 0x00000, 0x00000,
408 0x00000, 0x10000, 0x00000,
409 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400410 },
Clarence Ip373f8592016-05-26 00:58:42 -0400411 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400412 { 0x0, 0x0, 0x0,},
413 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400414 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400415 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
416 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
417 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400418 struct sde_drm_csc *csc = NULL;
419 size_t csc_size = 0;
420 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400421
422 if (!psde->pipe_hw->ops.setup_csc)
423 return;
424
Clarence Ip5e2a9222016-06-26 22:38:24 -0400425 /* check for user space override */
426 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
427 if (csc) {
428 struct sde_csc_cfg cfg;
429 int i;
430
431 /* user space override */
432 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
433 switch (csc->version) {
434 case SDE_DRM_CSC_V1:
435 if (!_sde_plane_verify_blob(csc,
436 csc_size,
437 &csc->v1,
438 sizeof(struct sde_drm_csc_v1))) {
439 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
440 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400441 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400442 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
443 cfg.csc_pre_bv[i] =
444 csc->v1.pre_bias[i];
445 cfg.csc_post_bv[i] =
446 csc->v1.post_bias[i];
447 }
448 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
449 cfg.csc_pre_lv[i] =
450 csc->v1.pre_clamp[i];
451 cfg.csc_post_lv[i] =
452 csc->v1.post_clamp[i];
453 }
454 user_blob = true;
455 }
456 break;
457 default:
458 break;
459 }
460
461 if (!user_blob)
462 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
463 else
464 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
465 (struct sde_csc_cfg *)&cfg);
466 }
467
468 if (user_blob) {
469 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400470 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400471 /* revert to kernel default */
Clarence Ipdbde9832016-06-26 09:48:36 -0400472 } else if (SDE_FORMAT_IS_YUV(fmt)) {
Clarence Ip373f8592016-05-26 00:58:42 -0400473 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400474 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400475 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400476 }
Clarence Ip373f8592016-05-26 00:58:42 -0400477
478 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400479}
480
Clarence Ipcb410d42016-06-26 22:52:33 -0400481static void _sde_plane_setup_scaler(struct sde_plane *psde,
482 struct sde_mdp_format_params *fmt,
483 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700484{
Clarence Ipcb410d42016-06-26 22:52:33 -0400485 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400486 struct sde_drm_scaler *sc_u = NULL;
487 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400488 size_t sc_u_size = 0;
489 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
490 uint32_t tmp;
491 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400492
Clarence Ipcb410d42016-06-26 22:52:33 -0400493 if (!psde || !fmt)
494 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400495
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400496 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400497 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400498
Clarence Ip5e2a9222016-06-26 22:38:24 -0400499 /* get scaler config from user space */
500 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
501 if (sc_u) {
502 switch (sc_u->version) {
503 case SDE_DRM_SCALER_V1:
504 if (!_sde_plane_verify_blob(sc_u,
505 sc_u_size,
506 &sc_u->v1,
507 sizeof(*sc_u1)))
508 sc_u1 = &sc_u->v1;
509 break;
510 default:
511 DBG("Unrecognized scaler blob v%lld", sc_u->version);
512 break;
513 }
514 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400515
Clarence Ip04ec67d2016-05-26 01:16:15 -0400516 /* decimation */
517 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
518 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
519 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400520 } else {
521 psde->pipe_cfg.horz_decimation = 0;
522 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400523 }
524
525 /* don't chroma subsample if decimating */
526 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Clarence Ipcb410d42016-06-26 22:52:33 -0400527 drm_format_horz_chroma_subsampling(fmt->format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400528 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Clarence Ipcb410d42016-06-26 22:52:33 -0400529 drm_format_vert_chroma_subsampling(fmt->format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400530
Clarence Ip5e2a9222016-06-26 22:38:24 -0400531 /* update scaler */
532 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
533 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Clarence Ipcb410d42016-06-26 22:52:33 -0400534 DBG("SCALER3 blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400535 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400536 _sde_plane_setup_scaler3(psde,
537 psde->pipe_cfg.src_rect.w,
538 psde->pipe_cfg.src_rect.h,
539 psde->pipe_cfg.dst_rect.w,
540 psde->pipe_cfg.dst_rect.h,
541 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400542 chroma_subsmpl_h, chroma_subsmpl_v);
543 } else {
544 /* always calculate basic scaler config */
545 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
546 /* populate from user space */
547 for (i = 0; i < SDE_MAX_PLANES; i++) {
548 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
549 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
550 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
551 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400552
Clarence Ip5e2a9222016-06-26 22:38:24 -0400553 pe->horz_filter[i] = sc_u1->horz_filter[i];
554 pe->vert_filter[i] = sc_u1->vert_filter[i];
555 }
556 } else {
557 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400558 _sde_plane_setup_scaler2(psde,
559 psde->pipe_cfg.src_rect.w,
560 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400561 pe->phase_step_x,
562 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400563 _sde_plane_setup_scaler2(psde,
564 psde->pipe_cfg.src_rect.h,
565 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400566 pe->phase_step_y,
567 pe->vert_filter, fmt, chroma_subsmpl_v);
568 }
569 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400570
Clarence Ip5e2a9222016-06-26 22:38:24 -0400571 /* update pixel extensions */
572 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
573 /* populate from user space */
Clarence Ipcb410d42016-06-26 22:52:33 -0400574 DBG("PIXEXT blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400575 for (i = 0; i < SDE_MAX_PLANES; i++) {
576 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
577 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
578 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
579 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
580 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
581 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
582 pe->roi_w[i] = sc_u1->lr.roi[i];
583
584 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
585 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
586 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
587 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
588 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
589 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
590 pe->roi_h[i] = sc_u1->tb.roi[i];
591 }
592 } else {
593 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400594 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400595 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400596 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400597 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400598 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
599 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400600 pe->phase_step_x,
601 pe->roi_w,
602 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400603 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400604 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400605
Clarence Ipcb410d42016-06-26 22:52:33 -0400606 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400607 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400608 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
609 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400610 pe->phase_step_y,
611 pe->roi_h,
612 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400613 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400614 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400615
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400616 for (i = 0; i < SDE_MAX_PLANES; i++) {
617 if (pe->num_ext_pxls_left[i] >= 0)
618 pe->left_rpt[i] =
619 pe->num_ext_pxls_left[i];
620 else
621 pe->left_ftch[i] =
622 pe->num_ext_pxls_left[i];
623
624 if (pe->num_ext_pxls_right[i] >= 0)
625 pe->right_rpt[i] =
626 pe->num_ext_pxls_right[i];
627 else
628 pe->right_ftch[i] =
629 pe->num_ext_pxls_right[i];
630
631 if (pe->num_ext_pxls_top[i] >= 0)
632 pe->top_rpt[i] =
633 pe->num_ext_pxls_top[i];
634 else
635 pe->top_ftch[i] =
636 pe->num_ext_pxls_top[i];
637
638 if (pe->num_ext_pxls_btm[i] >= 0)
639 pe->btm_rpt[i] =
640 pe->num_ext_pxls_btm[i];
641 else
642 pe->btm_ftch[i] =
643 pe->num_ext_pxls_btm[i];
644 }
645 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400646}
647
648int sde_plane_color_fill(struct drm_plane *plane,
649 uint32_t color, uint32_t alpha)
650{
651 struct sde_plane *psde;
652 struct sde_mdp_format_params *fmt;
653
654 if (!plane) {
655 DRM_ERROR("Invalid plane\n");
656 return -EINVAL;
657 }
658
659 psde = to_sde_plane(plane);
660 if (!psde->pipe_hw) {
661 DRM_ERROR("Invalid plane h/w pointer\n");
662 return -EINVAL;
663 }
664
665 /*
666 * select fill format to match user property expectation,
667 * h/w only supports RGB variants
668 */
669 fmt = sde_mdp_get_format_params(DRM_FORMAT_ABGR8888, 0);
670
671 /* update sspp */
672 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
673 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
674 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
675
676 /* override scaler/decimation if solid fill */
677 psde->pipe_cfg.src_rect.x = 0;
678 psde->pipe_cfg.src_rect.y = 0;
679 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
680 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
681
682 _sde_plane_setup_scaler(psde, fmt, 0);
683
684 if (psde->pipe_hw->ops.setup_format)
685 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
686 fmt, SDE_SSPP_SOLID_FILL);
687
688 if (psde->pipe_hw->ops.setup_rects)
689 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
690 &psde->pipe_cfg, &psde->pixel_ext);
691 }
692
693 return 0;
694}
695
696static int _sde_plane_mode_set(struct drm_plane *plane,
697 struct drm_crtc *crtc, struct drm_framebuffer *fb,
698 int crtc_x, int crtc_y,
699 unsigned int crtc_w, unsigned int crtc_h,
700 uint32_t src_x, uint32_t src_y,
701 uint32_t src_w, uint32_t src_h)
702{
703 struct sde_plane *psde;
704 struct sde_plane_state *pstate;
705 const struct mdp_format *format;
706 uint32_t nplanes, tmp;
707 uint32_t src_flags;
708 struct sde_mdp_format_params *fmt;
709
710 DBG("");
711
712 if (!plane || !plane->state) {
713 DRM_ERROR("Invalid plane/state\n");
714 return -EINVAL;
715 }
716 if (!crtc || !fb) {
717 DRM_ERROR("Invalid crtc/fb\n");
718 return -EINVAL;
719 }
720
721 psde = to_sde_plane(plane);
722 pstate = to_sde_plane_state(plane->state);
723 nplanes = drm_format_num_planes(fb->pixel_format);
724
725 format = to_mdp_format(msm_framebuffer_format(fb));
726 tmp = format->base.pixel_format;
727
728 /* src values are in Q16 fixed point, convert to integer */
729 src_x = src_x >> 16;
730 src_y = src_y >> 16;
731 src_w = src_w >> 16;
732 src_h = src_h >> 16;
733
734 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
735 fb->base.id, src_x, src_y, src_w, src_h,
736 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
737
738 /* update format configuration */
739 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
740 src_flags = 0;
741
742 psde->pipe_cfg.src.format = sde_mdp_get_format_params(tmp,
743 fb->modifier[0]);
744 psde->pipe_cfg.src.width = fb->width;
745 psde->pipe_cfg.src.height = fb->height;
746 psde->pipe_cfg.src.num_planes = nplanes;
747
748 /* flags */
749 DBG("Flags 0x%llX, rotation 0x%llX",
750 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
751 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
752 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
753 BIT(DRM_REFLECT_X))
754 src_flags |= SDE_SSPP_FLIP_LR;
755 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
756 BIT(DRM_REFLECT_Y))
757 src_flags |= SDE_SSPP_FLIP_UD;
758 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
759 BIT(SDE_DRM_DEINTERLACE)) {
760 src_h /= 2;
761 src_y = DIV_ROUND_UP(src_y, 2);
762 src_y &= ~0x1;
763 }
764
765 psde->pipe_cfg.src_rect.x = src_x;
766 psde->pipe_cfg.src_rect.y = src_y;
767 psde->pipe_cfg.src_rect.w = src_w;
768 psde->pipe_cfg.src_rect.h = src_h;
769
770 psde->pipe_cfg.dst_rect.x = crtc_x;
771 psde->pipe_cfg.dst_rect.y = crtc_y;
772 psde->pipe_cfg.dst_rect.w = crtc_w;
773 psde->pipe_cfg.dst_rect.h = crtc_h;
774
775 /* get sde pixel format definition */
776 fmt = psde->pipe_cfg.src.format;
777
778 /* check for color fill */
779 tmp = (uint32_t)sde_plane_get_property(pstate, PLANE_PROP_COLOR_FILL);
780 if (tmp & BIT(31)) {
781 /* force 100% alpha, stop other processing */
782 return sde_plane_color_fill(plane, tmp, 0xFF);
783 }
784
785 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
786
787 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400788
Clarence Ip4c1d9772016-06-26 09:35:38 -0400789 if (psde->pipe_hw->ops.setup_format)
790 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -0400791 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400792 if (psde->pipe_hw->ops.setup_rects)
793 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
794 &psde->pipe_cfg, &psde->pixel_ext);
795
Clarence Ipe78efb72016-06-24 18:35:21 -0400796 /* update sharpening */
797 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
798 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
799 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
800 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
801
802 if (psde->pipe_hw->ops.setup_sharpening)
803 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
804 &psde->sharp_cfg);
805
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400806 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400807 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400808 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400809
Clarence Ip5e2a9222016-06-26 22:38:24 -0400810 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400811}
812
813static int sde_plane_prepare_fb(struct drm_plane *plane,
814 const struct drm_plane_state *new_state)
815{
816 struct drm_framebuffer *fb = new_state->fb;
817 struct sde_plane *psde = to_sde_plane(plane);
818
819 if (!new_state->fb)
820 return 0;
821
Clarence Ipae4e60c2016-06-26 22:44:04 -0400822 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400823 return msm_framebuffer_prepare(fb, psde->mmu_id);
824}
825
826static void sde_plane_cleanup_fb(struct drm_plane *plane,
827 const struct drm_plane_state *old_state)
828{
829 struct drm_framebuffer *fb = old_state->fb;
830 struct sde_plane *psde = to_sde_plane(plane);
831
832 if (!fb)
833 return;
834
Clarence Ipae4e60c2016-06-26 22:44:04 -0400835 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400836 msm_framebuffer_cleanup(fb, psde->mmu_id);
837}
838
Clarence Ipdbde9832016-06-26 09:48:36 -0400839static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
840 struct sde_plane_state *pstate,
841 struct drm_framebuffer *fb)
842{
843 return 0;
844}
845
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400846static int sde_plane_atomic_check(struct drm_plane *plane,
847 struct drm_plane_state *state)
848{
Clarence Ipdbde9832016-06-26 09:48:36 -0400849 struct sde_plane *psde;
850 struct sde_plane_state *pstate;
851 struct drm_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400852 const struct mdp_format *format;
Clarence Ipdbde9832016-06-26 09:48:36 -0400853 struct sde_mdp_format_params *fmt;
854 size_t sc_u_size = 0;
855 struct sde_drm_scaler *sc_u = NULL;
856 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400857
Clarence Ipdbde9832016-06-26 09:48:36 -0400858 uint32_t src_x, src_y;
859 uint32_t src_w, src_h;
860 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
861 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
862 uint32_t upscale_max, downscale_max;
863
864 DBG();
865
866 if (!plane || !state) {
867 DRM_ERROR("Invalid plane/state\n");
868 ret = -EINVAL;
869 goto exit;
870 }
871
872 psde = to_sde_plane(plane);
873 pstate = to_sde_plane_state(state);
874 old_state = plane->state;
875
876 if (!psde->pipe_sblk) {
877 DRM_ERROR("Invalid plane catalog\n");
878 ret = -EINVAL;
879 goto exit;
880 }
881
882 /* get decimation config from user space */
883 deci_w = 0;
884 deci_h = 0;
885 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
886 if (sc_u) {
887 switch (sc_u->version) {
888 case SDE_DRM_SCALER_V1:
889 if (!_sde_plane_verify_blob(sc_u,
890 sc_u_size,
891 &sc_u->v1,
892 sizeof(struct sde_drm_scaler_v1))) {
893 deci_w = sc_u->v1.horz_decimate;
894 deci_h = sc_u->v1.vert_decimate;
895 }
896 break;
897 default:
898 DBG("Unrecognized scaler blob v%lld", sc_u->version);
899 break;
900 }
901 }
902
903 /* src values are in Q16 fixed point, convert to integer */
904 src_x = state->src_x >> 16;
905 src_y = state->src_y >> 16;
906 src_w = state->src_w >> 16;
907 src_h = state->src_h >> 16;
908
909 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
910 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
911
912 src_max_x = 0xFFFF;
913 src_max_y = 0xFFFF;
914 src_max_w = 0x3FFF;
915 src_max_h = 0x3FFF;
916 upscale_max = psde->pipe_sblk->maxupscale;
917 downscale_max = psde->pipe_sblk->maxdwnscale;
918
919 /*
920 * Including checks from mdss
921 * - mdss_mdp_overlay_req_check()
922 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400923 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400924 sde_plane_enabled(old_state), sde_plane_enabled(state));
925
926 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400927 /* determine SDE format definition. State's fb is valid here. */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400928 format = to_mdp_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400929 fmt = sde_mdp_get_format_params(format->base.pixel_format,
930 0 /* modifier */);
931
932 /* don't check for other errors after first failure */
933 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400934 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400935 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400936 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400937 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400938
Clarence Ipdbde9832016-06-26 09:48:36 -0400939 /* verify source size/region */
940 } else if (!src_w || !src_h ||
941 (src_w > src_max_w) || (src_h > src_max_h) ||
942 (src_x > src_max_x) || (src_y > src_max_y) ||
943 (src_x + src_w > src_max_x) ||
944 (src_y + src_h > src_max_y)) {
945 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
946 src_x, src_y, src_x + src_w,
947 src_y + src_h);
948 ret = -EINVAL;
949
950 /* require even source for YUV */
951 } else if (SDE_FORMAT_IS_YUV(fmt) &&
952 ((src_x & 0x1) || (src_y & 0x1) ||
953 (src_w & 0x1) || (src_h & 0x1))) {
954 DRM_ERROR("Invalid odd src res/pos for YUV\n");
955 ret = -EINVAL;
956
957 /* verify scaler requirements */
958 } else if (!(psde->features & SDE_SSPP_SCALER) &&
959 ((src_w != state->crtc_w) ||
960 (src_h != state->crtc_h))) {
961 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
962 src_w, src_h, state->crtc_w,
963 state->crtc_h);
964 ret = -EINVAL;
965
966 /* check decimated source width */
967 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
968 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
969 src_w, src_deci_w,
970 psde->pipe_sblk->maxlinewidth);
971 ret = -EINVAL;
972
973 /* check max scaler capability */
974 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
975 ((src_deci_h * upscale_max) < state->crtc_h) ||
976 ((state->crtc_w * downscale_max) < src_deci_w) ||
977 ((state->crtc_h * downscale_max) < src_deci_h)) {
978 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
979 src_deci_w, src_deci_h,
980 state->crtc_w, state->crtc_h);
981 ret = -EINVAL;
982
983 /* check frame buffer */
984 } else if (_sde_plane_atomic_check_fb(
985 psde, pstate, state->fb)) {
986 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400987 }
988
Clarence Ipdbde9832016-06-26 09:48:36 -0400989 /* check decimation (and bwc/fetch mode) */
990 if (!ret && (deci_w || deci_h)) {
991 if (SDE_FORMAT_IS_UBWC(fmt)) {
992 DRM_ERROR("No decimation with BWC\n");
993 ret = -EINVAL;
994 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
995 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
996 DRM_ERROR("Too much decimation requested\n");
997 ret = -EINVAL;
998 } else if (fmt->fetch_mode != SDE_MDP_FETCH_LINEAR) {
999 DRM_ERROR("Decimation requires linear fetch\n");
1000 ret = -EINVAL;
1001 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001002 }
1003 }
1004
Clarence Ipdbde9832016-06-26 09:48:36 -04001005 if (!ret) {
1006 if (sde_plane_enabled(state) &&
1007 sde_plane_enabled(old_state)) {
1008 bool full_modeset = false;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001009
Clarence Ipdbde9832016-06-26 09:48:36 -04001010 if (state->fb->pixel_format !=
1011 old_state->fb->pixel_format) {
1012 DBG("%s: format change!", psde->pipe_name);
1013 full_modeset = true;
1014 }
1015 if (state->src_w != old_state->src_w ||
1016 state->src_h != old_state->src_h) {
1017 DBG("%s: src_w change!", psde->pipe_name);
1018 full_modeset = true;
1019 }
1020 if (to_sde_plane_state(old_state)->pending) {
1021 DBG("%s: still pending!", psde->pipe_name);
1022 full_modeset = true;
1023 }
Lloyd Atkinson66358902016-03-23 11:58:23 -04001024 if (full_modeset)
Clarence Ipdbde9832016-06-26 09:48:36 -04001025 to_sde_plane_state(state)->mode_changed = true;
Lloyd Atkinson66358902016-03-23 11:58:23 -04001026
Clarence Ipdbde9832016-06-26 09:48:36 -04001027 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001028 to_sde_plane_state(state)->mode_changed = true;
1029 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001030 }
1031
Clarence Ipdbde9832016-06-26 09:48:36 -04001032exit:
1033 return ret;
1034}
1035
1036void sde_plane_complete_flip(struct drm_plane *plane)
1037{
1038 if (plane && plane->state)
1039 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001040}
1041
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001042static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001043 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001044{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001045 struct sde_plane *sde_plane;
1046 struct drm_plane_state *state;
1047 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001048
Clarence Ip5e2a9222016-06-26 22:38:24 -04001049 if (!plane || !plane->state) {
1050 DRM_ERROR("Invalid plane/state\n");
1051 return;
1052 }
1053
1054 sde_plane = to_sde_plane(plane);
1055 state = plane->state;
1056 pstate = to_sde_plane_state(state);
1057
Clarence Ipae4e60c2016-06-26 22:44:04 -04001058 DBG("%s: update", sde_plane->pipe_name);
1059
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001060 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001061 pstate->pending = true;
1062 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001063 int ret;
1064
Clarence Ip5e2a9222016-06-26 22:38:24 -04001065 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001066 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001067 state->crtc, state->fb,
1068 state->crtc_x, state->crtc_y,
1069 state->crtc_w, state->crtc_h,
1070 state->src_x, state->src_y,
1071 state->src_w, state->src_h);
1072 /* atomic_check should have ensured that this doesn't fail */
1073 WARN_ON(ret < 0);
1074 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001075 _sde_plane_set_scanout(plane, pstate,
1076 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001077 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001078}
1079
Clarence Ipae4e60c2016-06-26 22:44:04 -04001080static inline struct drm_property **_sde_plane_get_property_entry(
1081 struct drm_device *dev, enum msm_mdp_plane_property property)
1082{
1083 struct msm_drm_private *priv;
1084
1085 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
1086 return NULL;
1087
1088 priv = dev->dev_private;
1089
1090 return &(priv->plane_property[property]);
1091}
1092
Clarence Ipe78efb72016-06-24 18:35:21 -04001093static void _sde_plane_install_range_property(struct drm_plane *plane,
1094 struct drm_device *dev, const char *name,
1095 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001096 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001097{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001098 struct drm_property **prop;
1099
1100 prop = _sde_plane_get_property_entry(dev, property);
1101 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -04001102 /* only create the property once */
1103 if (*prop == 0) {
1104 *prop = drm_property_create_range(dev,
1105 0 /* flags */, name, min, max);
1106 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001107 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -04001108 }
1109
Clarence Ipae4e60c2016-06-26 22:44:04 -04001110 /* save init value for later */
1111 to_sde_plane(plane)->property_defaults[property] = init;
1112
Clarence Ipe78efb72016-06-24 18:35:21 -04001113 /* always attach property, if created */
1114 if (*prop)
1115 drm_object_attach_property(&plane->base, *prop, init);
1116 }
1117}
1118
Clarence Ip5e2a9222016-06-26 22:38:24 -04001119static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001120 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001121{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001122 struct sde_plane *psde;
1123 struct drm_property **prop;
1124
1125 prop = _sde_plane_get_property_entry(dev, property);
1126 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001127 /* only create the property once */
1128 if (*prop == 0) {
1129 *prop = drm_mode_create_rotation_property(dev,
1130 BIT(DRM_REFLECT_X) |
1131 BIT(DRM_REFLECT_Y));
1132 if (*prop == 0)
1133 DRM_ERROR("Create rotation property failed\n");
1134 }
1135
Clarence Ipae4e60c2016-06-26 22:44:04 -04001136 /* save init value for later */
1137 psde = to_sde_plane(plane);
1138 psde->property_defaults[property] = 0;
1139
Clarence Ip5e2a9222016-06-26 22:38:24 -04001140 /* always attach property, if created */
1141 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001142 drm_object_attach_property(&plane->base, *prop,
1143 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001144 }
1145}
1146
1147static void _sde_plane_install_enum_property(struct drm_plane *plane,
1148 struct drm_device *dev, const char *name, int is_bitmask,
1149 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001150 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001151{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001152 struct sde_plane *psde;
1153 struct drm_property **prop;
1154
1155 prop = _sde_plane_get_property_entry(dev, property);
1156 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001157 /* only create the property once */
1158 if (*prop == 0) {
1159 /* 'bitmask' is a special type of 'enum' */
1160 if (is_bitmask)
1161 *prop = drm_property_create_bitmask(dev,
1162 DRM_MODE_PROP_BITMASK, name,
1163 values, num_values, -1);
1164 else
1165 *prop = drm_property_create_enum(dev,
1166 DRM_MODE_PROP_ENUM, name,
1167 values, num_values);
1168 if (*prop == 0)
1169 DRM_ERROR("Create %s property failed\n", name);
1170 }
1171
Clarence Ipae4e60c2016-06-26 22:44:04 -04001172 /* save init value for later */
1173 psde = to_sde_plane(plane);
1174 psde->property_defaults[property] = 0;
1175
Clarence Ip5e2a9222016-06-26 22:38:24 -04001176 /* always attach property, if created */
1177 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001178 drm_object_attach_property(&plane->base, *prop,
1179 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001180 }
1181}
1182
Clarence Ipe78efb72016-06-24 18:35:21 -04001183static void _sde_plane_install_blob_property(struct drm_plane *plane,
1184 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001185 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001186{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001187 struct sde_plane *psde;
1188 struct drm_property **prop;
1189
1190 prop = _sde_plane_get_property_entry(dev, property);
1191 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001192 /* only create the property once */
1193 if (*prop == 0) {
1194 /* use 'create' for blob property place holder */
1195 *prop = drm_property_create(dev,
1196 DRM_MODE_PROP_BLOB, name, 0);
1197 if (*prop == 0)
1198 DRM_ERROR("Create %s property failed\n", name);
1199 }
1200
Clarence Ipae4e60c2016-06-26 22:44:04 -04001201 /* save init value for later */
1202 psde = to_sde_plane(plane);
1203 psde->property_defaults[property] = 0;
1204
Clarence Ip5e2a9222016-06-26 22:38:24 -04001205 /* always attach property, if created */
1206 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001207 drm_object_attach_property(&plane->base, *prop,
1208 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001209 }
Clarence Ipe78efb72016-06-24 18:35:21 -04001210}
1211
Clarence Ip4c1d9772016-06-26 09:35:38 -04001212static int _sde_plane_get_property_index(struct drm_plane *plane,
1213 struct drm_property *property)
1214{
1215 struct drm_property **prop_array;
1216 int idx = PLANE_PROP_COUNT;
1217
1218 if (!plane) {
1219 DRM_ERROR("Invalid plane\n");
1220 } else if (!plane->dev || !plane->dev->dev_private) {
1221 /* don't access dev_private if !dev */
1222 DRM_ERROR("Invalid device\n");
1223 } else if (!property) {
1224 DRM_ERROR("Incoming property is NULL\n");
1225 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001226 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001227 if (!prop_array)
1228 /* should never hit this */
1229 DRM_ERROR("Invalid property array\n");
1230
1231 /* linear search is okay */
1232 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
1233 if (prop_array[idx] == property)
1234 break;
1235 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001236
1237 if (idx == PLANE_PROP_COUNT)
1238 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001239 }
1240
1241 return idx;
1242}
1243
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001244/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -04001245static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001246 struct drm_mode_object *obj,
1247 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001248{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001249 static const struct drm_prop_enum_list e_blend_op[] = {
1250 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1251 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1252 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1253 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1254 };
1255 static const struct drm_prop_enum_list e_src_config[] = {
1256 {SDE_DRM_DEINTERLACE, "deinterlace"}
1257 };
1258 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001259 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001260
Clarence Ip4ce59322016-06-26 22:27:51 -04001261 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001262
Clarence Ipcb410d42016-06-26 22:52:33 -04001263 if (!psde || !psde->pipe_hw || !psde->pipe_sblk || !catalog) {
1264 DRM_ERROR("Catalog or h/w driver definition error\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001265 return;
1266 }
1267
1268 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001269 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
1270 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1271 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1272 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001273
Clarence Ip5e2a9222016-06-26 22:38:24 -04001274 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001275 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001276
Clarence Ipcb410d42016-06-26 22:52:33 -04001277 if (psde->pipe_hw->ops.setup_solidfill)
1278 _sde_plane_install_range_property(plane, dev, "color_fill",
1279 0, 0xFFFFFFFF, 0,
1280 PLANE_PROP_COLOR_FILL);
1281
Clarence Ipae4e60c2016-06-26 22:44:04 -04001282 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
1283 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001284
Clarence Ipcb410d42016-06-26 22:52:33 -04001285 _sde_plane_install_range_property(plane, dev, "sync_fence_timeout",
1286 0, ~0, 10000,
1287 PLANE_PROP_SYNC_FENCE_TIMEOUT);
1288
Clarence Ip5e2a9222016-06-26 22:38:24 -04001289 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001290 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001291
Clarence Ip04ec67d2016-05-26 01:16:15 -04001292 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001293 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1294 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001295 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001296 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1297 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001298 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001299
Clarence Ipe78efb72016-06-24 18:35:21 -04001300 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001301 if (psde->features & SDE_SSPP_SCALER)
1302 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001303 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001304 if (psde->features & BIT(SDE_SSPP_CSC))
1305 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001306 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001307}
1308
1309static int sde_plane_atomic_set_property(struct drm_plane *plane,
1310 struct drm_plane_state *state, struct drm_property *property,
1311 uint64_t val)
1312{
Clarence Ip730e7192016-06-26 22:45:09 -04001313 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001314 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001315 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001316 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001317
Clarence Ip4c1d9772016-06-26 09:35:38 -04001318 idx = _sde_plane_get_property_index(plane, property);
1319 if (!state) {
1320 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001321 } else if (idx >= PLANE_PROP_COUNT) {
1322 DRM_ERROR("Invalid property\n");
1323 } else {
1324 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001325 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001326
Lloyd Atkinson0fda6c52016-02-04 15:09:43 -05001327 DBG("%s: pipe %d, prop %s, val %d", psde->pipe_name,
1328 sde_plane_pipe(plane),
1329 property->name, (int)val);
Clarence Ip730e7192016-06-26 22:45:09 -04001330
Clarence Ipae4e60c2016-06-26 22:44:04 -04001331 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001332 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1333 (idx < PLANE_PROP_BLOBCOUNT)) {
1334 /* DRM lookup also takes a reference */
1335 blob = drm_property_lookup_blob(plane->dev,
1336 (uint32_t)val);
1337 if (!blob) {
1338 DRM_ERROR("Blob not found\n");
1339 val = 0;
1340 } else {
1341 DBG("Blob %u saved", blob->base.id);
1342 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001343
Clarence Ip4c1d9772016-06-26 09:35:38 -04001344 /* save blobs for later */
1345 pr_blob = &pstate->property_blobs[idx];
1346 /* need to clear previous reference */
1347 if (*pr_blob)
1348 drm_property_unreference_blob(*pr_blob);
1349 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001350 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001351 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1352 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001353 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001354 pstate->property_values[idx] = val;
1355 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001356 }
1357
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001358 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001359}
1360
1361static int sde_plane_set_property(struct drm_plane *plane,
1362 struct drm_property *property, uint64_t val)
1363{
Clarence Ip4ce59322016-06-26 22:27:51 -04001364 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001365
1366 if (!plane)
1367 return -EINVAL;
1368
Clarence Ipae4e60c2016-06-26 22:44:04 -04001369 return sde_plane_atomic_set_property(plane,
1370 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001371}
1372
1373static int sde_plane_atomic_get_property(struct drm_plane *plane,
1374 const struct drm_plane_state *state,
1375 struct drm_property *property, uint64_t *val)
1376{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001377 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001378 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001379
Clarence Ip4c1d9772016-06-26 09:35:38 -04001380 idx = _sde_plane_get_property_index(plane, property);
1381 if (!state) {
1382 DRM_ERROR("Invalid state\n");
1383 } else if (!val) {
1384 DRM_ERROR("Value pointer is NULL\n");
1385 } else if (idx < PLANE_PROP_COUNT) {
1386 pstate = to_sde_plane_state(state);
1387
1388 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001389 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001390 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001391 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001392
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001393 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001394}
1395
Clarence Ip730e7192016-06-26 22:45:09 -04001396static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
1397{
1398 struct sde_plane *psde;
1399 struct sde_plane_state *pstate;
1400
1401 if (!plane)
1402 return NULL;
1403
1404 psde = to_sde_plane(plane);
1405 pstate = NULL;
1406
1407 mutex_lock(&psde->lock);
1408 if (psde->state_cache_size)
1409 pstate = psde->state_cache[--(psde->state_cache_size)];
1410 mutex_unlock(&psde->lock);
1411
1412 if (!pstate)
1413 pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
1414
1415 return pstate;
1416}
1417
1418static void sde_plane_free_state(struct drm_plane *plane,
1419 struct sde_plane_state *pstate)
1420{
1421 struct sde_plane *psde;
1422
1423 if (!plane || !pstate)
1424 return;
1425
1426 psde = to_sde_plane(plane);
1427
1428 mutex_lock(&psde->lock);
1429 if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
1430 psde->state_cache[(psde->state_cache_size)++] = pstate;
1431 mutex_unlock(&psde->lock);
1432 } else {
1433 mutex_unlock(&psde->lock);
1434 kfree(pstate);
1435 }
1436}
1437
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001438static void sde_plane_destroy(struct drm_plane *plane)
1439{
Clarence Ip4ce59322016-06-26 22:27:51 -04001440 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001441
Clarence Ip4ce59322016-06-26 22:27:51 -04001442 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001443
Clarence Ip4ce59322016-06-26 22:27:51 -04001444 if (plane) {
1445 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001446
Clarence Ip4ce59322016-06-26 22:27:51 -04001447 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001448
Clarence Ip730e7192016-06-26 22:45:09 -04001449 mutex_destroy(&psde->lock);
1450
Clarence Ip4ce59322016-06-26 22:27:51 -04001451 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001452
Clarence Ip4ce59322016-06-26 22:27:51 -04001453 /* this will destroy the states as well */
1454 drm_plane_cleanup(plane);
1455
Clarence Ip4c1d9772016-06-26 09:35:38 -04001456 if (psde->pipe_hw)
1457 sde_hw_sspp_destroy(psde->pipe_hw);
1458
Clarence Ip730e7192016-06-26 22:45:09 -04001459 /* free state cache */
1460 while (psde->state_cache_size > 0)
1461 kfree(psde->state_cache[--(psde->state_cache_size)]);
1462
Clarence Ip4ce59322016-06-26 22:27:51 -04001463 kfree(psde);
1464 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001465}
1466
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001467static void sde_plane_destroy_state(struct drm_plane *plane,
1468 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001469{
Clarence Ipe78efb72016-06-24 18:35:21 -04001470 struct sde_plane_state *pstate;
1471 int i;
1472
Clarence Ipae4e60c2016-06-26 22:44:04 -04001473 if (!plane || !state) {
1474 DRM_ERROR("Invalid plane/state\n");
1475 return;
1476 }
1477
Clarence Ip730e7192016-06-26 22:45:09 -04001478 pstate = to_sde_plane_state(state);
1479
1480 DBG("");
1481
Clarence Ipe78efb72016-06-24 18:35:21 -04001482 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001483 if (state->fb)
1484 drm_framebuffer_unreference(state->fb);
1485
Clarence Ipae4e60c2016-06-26 22:44:04 -04001486 /* remove ref count for fence */
1487 if (pstate->sync_fence)
1488 sde_sync_put(pstate->sync_fence);
1489
Clarence Ipe78efb72016-06-24 18:35:21 -04001490 /* remove ref count for blobs */
1491 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1492 if (pstate->property_blobs[i])
1493 drm_property_unreference_blob(
1494 pstate->property_blobs[i]);
Clarence Ip730e7192016-06-26 22:45:09 -04001495 sde_plane_free_state(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001496}
1497
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001498static struct drm_plane_state *
1499sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001500{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001501 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001502 struct sde_plane_state *old_state;
Clarence Ipe78efb72016-06-24 18:35:21 -04001503 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001504
Clarence Ip730e7192016-06-26 22:45:09 -04001505 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001506 return NULL;
1507
Clarence Ip730e7192016-06-26 22:45:09 -04001508 old_state = to_sde_plane_state(plane->state);
1509 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001510
1511 DBG("");
1512
Clarence Ip730e7192016-06-26 22:45:09 -04001513 if (!pstate)
1514 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001515
Clarence Ip730e7192016-06-26 22:45:09 -04001516 memcpy(pstate, old_state, sizeof(*pstate));
Clarence Ipae4e60c2016-06-26 22:44:04 -04001517
Clarence Ip730e7192016-06-26 22:45:09 -04001518 /* add ref count for frame buffer */
1519 if (pstate->base.fb)
1520 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001521
Clarence Ip730e7192016-06-26 22:45:09 -04001522 /* add ref count for fence */
1523 if (pstate->sync_fence) {
1524 pstate->sync_fence = 0;
1525 _sde_plane_update_sync_fence(plane, pstate, pstate->
1526 property_values[PLANE_PROP_SYNC_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001527 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001528
Clarence Ip730e7192016-06-26 22:45:09 -04001529 /* add ref count for blobs */
1530 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1531 if (pstate->property_blobs[i])
1532 drm_property_reference_blob(
1533 pstate->property_blobs[i]);
1534
1535 pstate->mode_changed = false;
1536 pstate->pending = false;
1537
1538 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001539}
1540
1541static void sde_plane_reset(struct drm_plane *plane)
1542{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001543 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001544 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001545 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001546
Clarence Ipae4e60c2016-06-26 22:44:04 -04001547 if (!plane) {
1548 DRM_ERROR("Invalid plane\n");
1549 return;
1550 }
1551
Clarence Ip730e7192016-06-26 22:45:09 -04001552 psde = to_sde_plane(plane);
1553 DBG("%s", psde->pipe_name);
1554
Clarence Ipae4e60c2016-06-26 22:44:04 -04001555 /* remove previous state, if present */
1556 if (plane->state)
1557 sde_plane_destroy_state(plane, plane->state);
1558 plane->state = 0;
1559
Clarence Ip730e7192016-06-26 22:45:09 -04001560 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001561 if (!pstate) {
Clarence Ip730e7192016-06-26 22:45:09 -04001562 DRM_ERROR("Failed to (re)allocate plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001563 return;
1564 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001565
Clarence Ip730e7192016-06-26 22:45:09 -04001566 memset(pstate, 0, sizeof(*pstate));
1567
Clarence Ipae4e60c2016-06-26 22:44:04 -04001568 /* assign default property values */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001569 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1570 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001571
1572 pstate->base.plane = plane;
1573
1574 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001575}
1576
1577static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001578 .update_plane = drm_atomic_helper_update_plane,
1579 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001580 .destroy = sde_plane_destroy,
1581 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001582 .atomic_set_property = sde_plane_atomic_set_property,
1583 .atomic_get_property = sde_plane_atomic_get_property,
1584 .reset = sde_plane_reset,
1585 .atomic_duplicate_state = sde_plane_duplicate_state,
1586 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001587};
1588
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001589static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1590 .prepare_fb = sde_plane_prepare_fb,
1591 .cleanup_fb = sde_plane_cleanup_fb,
1592 .atomic_check = sde_plane_atomic_check,
1593 .atomic_update = sde_plane_atomic_update,
1594};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001595
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001596enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001597{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001598 struct sde_plane *sde_plane = to_sde_plane(plane);
1599
1600 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001601}
1602
Clarence Ip4ce59322016-06-26 22:27:51 -04001603static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1604{
1605 const struct sde_sspp_sub_blks *sblk = 0;
1606 const struct sde_sspp_cfg *cfg = 0;
1607
1608 if (psde && psde->pipe_hw)
1609 cfg = psde->pipe_hw->cap;
1610 if (cfg)
1611 sblk = cfg->sblk;
1612
1613 if (kms && sblk) {
1614 /* create overall sub-directory for the pipe */
1615 psde->debugfs_root =
1616 debugfs_create_dir(psde->pipe_name,
1617 sde_debugfs_get_root(kms));
1618 if (psde->debugfs_root) {
1619 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001620 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001621 psde->debugfs_root, &psde->features);
1622
1623 /* add register dump support */
1624 sde_debugfs_setup_regset32(&psde->debugfs_src,
1625 sblk->src_blk.base + cfg->base,
1626 sblk->src_blk.len,
1627 kms->mmio);
1628 sde_debugfs_create_regset32("src_blk", 0444,
1629 psde->debugfs_root, &psde->debugfs_src);
1630
1631 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1632 sblk->scaler_blk.base + cfg->base,
1633 sblk->scaler_blk.len,
1634 kms->mmio);
1635 sde_debugfs_create_regset32("scaler_blk", 0444,
1636 psde->debugfs_root,
1637 &psde->debugfs_scaler);
1638
1639 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1640 sblk->csc_blk.base + cfg->base,
1641 sblk->csc_blk.len,
1642 kms->mmio);
1643 sde_debugfs_create_regset32("csc_blk", 0444,
1644 psde->debugfs_root, &psde->debugfs_csc);
1645 }
1646 }
1647}
1648
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001649/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001650struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001651 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001652{
1653 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001654 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001655 struct msm_drm_private *priv;
1656 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001657 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001658 int ret = -EINVAL;
1659
1660 if (!dev) {
1661 DRM_ERROR("[%u]Device is NULL\n", pipe);
1662 goto exit;
1663 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001664
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001665 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001666 if (!priv) {
1667 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1668 goto exit;
1669 }
1670
1671 if (!priv->kms) {
1672 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1673 goto exit;
1674 }
1675 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001676
Clarence Ip4c1d9772016-06-26 09:35:38 -04001677 if (!kms->catalog) {
1678 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1679 goto exit;
1680 }
1681
Clarence Ip4ce59322016-06-26 22:27:51 -04001682 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001683 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1684 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001685 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001686 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001687 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001688 }
1689
Clarence Ip4c1d9772016-06-26 09:35:38 -04001690 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001691 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001692 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001693 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001694
Clarence Ip4c1d9772016-06-26 09:35:38 -04001695 /* initialize underlying h/w driver */
1696 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1697 if (IS_ERR(psde->pipe_hw)) {
1698 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1699 ret = PTR_ERR(psde->pipe_hw);
1700 goto clean_plane;
1701 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1702 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1703 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001704 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001705
1706 /* cache features mask for later */
1707 psde->features = psde->pipe_hw->cap->features;
1708 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1709
1710 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001711 psde->nformats = mdp_get_formats(psde->formats,
1712 ARRAY_SIZE(psde->formats),
1713 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001714 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001715
Clarence Ip4c1d9772016-06-26 09:35:38 -04001716 if (!psde->nformats) {
1717 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1718 goto clean_sspp;
1719 }
1720
1721 if (psde->features & BIT(SDE_SSPP_CURSOR))
1722 type = DRM_PLANE_TYPE_CURSOR;
1723 else if (primary_plane)
1724 type = DRM_PLANE_TYPE_PRIMARY;
1725 else
1726 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001727 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1728 psde->formats, psde->nformats,
1729 type);
1730 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001731 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001732
Clarence Ip4c1d9772016-06-26 09:35:38 -04001733 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001734 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001735
Clarence Ip4c1d9772016-06-26 09:35:38 -04001736 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001737
Clarence Ip4ce59322016-06-26 22:27:51 -04001738 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001739 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001740
Clarence Ip730e7192016-06-26 22:45:09 -04001741 mutex_init(&psde->lock);
1742
Clarence Ip4ce59322016-06-26 22:27:51 -04001743 _sde_plane_init_debugfs(psde, kms);
1744
Clarence Ip4c1d9772016-06-26 09:35:38 -04001745 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001746 return plane;
1747
Clarence Ip4c1d9772016-06-26 09:35:38 -04001748clean_sspp:
1749 if (psde && psde->pipe_hw)
1750 sde_hw_sspp_destroy(psde->pipe_hw);
1751clean_plane:
1752 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001753exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001754 return ERR_PTR(ret);
1755}